diff --git a/bungee/pom.xml b/bungee/pom.xml
new file mode 100644
index 0000000..27c7fd3
--- /dev/null
+++ b/bungee/pom.xml
@@ -0,0 +1,79 @@
+
+
+ 4.0.0
+
+
+ me.zimzaza4
+ GeyserUtils
+ 1.0-SNAPSHOT
+
+
+ geyserutils-bungee
+
+
+
+ 1.8
+ UTF-8
+
+
+
+ clean package
+
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+ 3.8.1
+
+ ${java.version}
+ ${java.version}
+
+
+
+ org.apache.maven.plugins
+ maven-shade-plugin
+ 3.2.4
+
+
+ package
+
+ shade
+
+
+ false
+
+
+
+
+
+
+
+ src/main/resources
+ true
+
+
+
+
+
+
+ sonatype
+ https://oss.sonatype.org/content/groups/public/
+
+
+
+
+
+ net.md-5
+ bungeecord-api
+ 1.20-R0.1-SNAPSHOT
+ provided
+
+
+ me.zimzaza4
+ geyserutils-common
+ 1.0-SNAPSHOT
+ compile
+
+
+
diff --git a/bungee/src/main/java/me/zimzaza4/geyserutils/bungee/GeyserUtils.java b/bungee/src/main/java/me/zimzaza4/geyserutils/bungee/GeyserUtils.java
new file mode 100644
index 0000000..e8ad98a
--- /dev/null
+++ b/bungee/src/main/java/me/zimzaza4/geyserutils/bungee/GeyserUtils.java
@@ -0,0 +1,20 @@
+package me.zimzaza4.geyserutils.bungee;
+
+import me.zimzaza4.geyserutils.common.channel.GeyserUtilsChannels;
+import net.md_5.bungee.api.ProxyServer;
+import net.md_5.bungee.api.plugin.Plugin;
+
+public final class GeyserUtils extends Plugin {
+
+ @Override
+ public void onEnable() {
+ ProxyServer.getInstance()
+ .registerChannel(GeyserUtilsChannels.MAIN);
+ // Plugin startup logic
+ }
+
+ @Override
+ public void onDisable() {
+ // Plugin shutdown logic
+ }
+}
diff --git a/bungee/src/main/resources/bungee.yml b/bungee/src/main/resources/bungee.yml
new file mode 100644
index 0000000..7ecaf76
--- /dev/null
+++ b/bungee/src/main/resources/bungee.yml
@@ -0,0 +1,3 @@
+name: GeyserUtils
+version: '${project.version}'
+main: me.zimzaza4.geyserutils.bungee.GeyserUtils
diff --git a/common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomSkinPayloadPacket.java b/common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomSkinPayloadPacket.java
new file mode 100644
index 0000000..02bc2ca
--- /dev/null
+++ b/common/src/main/java/me/zimzaza4/geyserutils/common/packet/CustomSkinPayloadPacket.java
@@ -0,0 +1,14 @@
+package me.zimzaza4.geyserutils.common.packet;
+
+import lombok.Getter;
+import lombok.Setter;
+
+import java.util.ArrayList;
+import java.util.List;
+
+@Setter
+@Getter
+public class CustomSkinPayloadPacket extends CustomPayloadPacket {
+ private int entityId;
+ private String skinId;
+}
diff --git a/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/GeyserUtils.java b/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/GeyserUtils.java
index 3be3689..7443ca3 100644
--- a/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/GeyserUtils.java
+++ b/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/GeyserUtils.java
@@ -5,6 +5,10 @@ import com.github.steveice10.mc.protocol.packet.common.serverbound.ServerboundCu
import com.github.steveice10.packetlib.Session;
import com.github.steveice10.packetlib.event.session.SessionAdapter;
import com.github.steveice10.packetlib.packet.Packet;
+import com.google.gson.Gson;
+import com.google.gson.JsonElement;
+import com.google.gson.JsonParser;
+import it.unimi.dsi.fastutil.bytes.ByteArrays;
import lombok.Getter;
import me.zimzaza4.geyserutils.common.camera.data.CameraPreset;
import me.zimzaza4.geyserutils.common.camera.instruction.ClearInstruction;
@@ -22,26 +26,32 @@ import me.zimzaza4.geyserutils.geyser.form.NpcDialogueForms;
import me.zimzaza4.geyserutils.geyser.form.element.Button;
import me.zimzaza4.geyserutils.geyser.translator.NPCFormResponseTranslator;
import org.cloudburstmc.nbt.NbtMap;
+import org.cloudburstmc.protocol.bedrock.data.skin.ImageData;
+import org.cloudburstmc.protocol.bedrock.data.skin.SerializedSkin;
import org.cloudburstmc.protocol.bedrock.packet.*;
import org.cloudburstmc.protocol.common.DefinitionRegistry;
import org.cloudburstmc.protocol.common.NamedDefinition;
import org.geysermc.event.subscribe.Subscribe;
-import org.geysermc.geyser.GeyserImpl;
-import org.geysermc.geyser.api.bedrock.camera.CameraPerspective;
import org.geysermc.geyser.api.bedrock.camera.CameraShake;
import org.geysermc.geyser.api.event.bedrock.SessionJoinEvent;
import org.geysermc.geyser.api.event.lifecycle.GeyserPostInitializeEvent;
import org.geysermc.geyser.api.extension.Extension;
import org.geysermc.geyser.entity.type.Entity;
+import org.geysermc.geyser.entity.type.player.PlayerEntity;
import org.geysermc.geyser.registry.Registries;
import org.geysermc.geyser.session.GeyserSession;
+import org.geysermc.geyser.skin.SkinManager;
+import org.geysermc.geyser.skin.SkinProvider;
import org.geysermc.geyser.util.DimensionUtils;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Optional;
-import java.util.concurrent.Executors;
-import java.util.concurrent.TimeUnit;
+import javax.imageio.ImageIO;
+import java.awt.image.BufferedImage;
+import java.io.*;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.*;
+
+import static org.geysermc.geyser.skin.SkinManager.buildEntryManually;
public class GeyserUtils implements Extension {
@@ -50,27 +60,63 @@ public class GeyserUtils implements Extension {
@Getter
public static PacketManager packetManager;
+ @Getter
+ public static Map LOADED_SKIN_DATA = new HashMap<>();
+
+ static final SkinProvider.Cape EMPTY_CAPE = new SkinProvider.Cape("", "no-cape", ByteArrays.EMPTY_ARRAY, -1, true);
+
+
@Subscribe
public void onLoad(GeyserPostInitializeEvent event) {
packetManager = new PacketManager();
CameraPreset.load();
Registries.BEDROCK_PACKET_TRANSLATORS.register(NpcRequestPacket.class, new NPCFormResponseTranslator());
-
-
-
+ loadSkins();
}
+
+ public void loadSkins() {
+ LOADED_SKIN_DATA.clear();
+ File folder = this.dataFolder().resolve("skins").toFile();
+ if (!folder.exists()) {
+ folder.mkdirs();
+ }
+ for (File file : folder.listFiles()) {
+ if (file.isDirectory()) {
+ File textureFile = new File(file, "texture.png");
+ File geometryFile = new File(file, "geometry.json");
+
+ try {
+ SkinProvider.Skin skin = new SkinProvider.Skin(null, file.getName(), Files.readAllBytes(textureFile.toPath()), -1, false, false);
+
+ String geoId = "";
+ JsonElement json = new JsonParser().parse(new FileReader(geometryFile));
+ for (JsonElement element : json.getAsJsonObject().get("minecraft:geometry").getAsJsonArray()) {
+ if (element.isJsonObject() && element.getAsJsonObject().has("description")) {
+ geoId = element.getAsJsonObject().get("description").getAsJsonObject().get("identifier").getAsString();
+ break;
+ }
+ }
+ String geoName = "{\"geometry\" :{\"default\" :\"" + geoId + "\"}}";
+ SkinProvider.SkinGeometry geometry = new SkinProvider.SkinGeometry(geoName, Files.readString(geometryFile.toPath()), false);
+ LOADED_SKIN_DATA.put(file.getName(), new SkinProvider.SkinData(skin, EMPTY_CAPE, geometry));
+ this.logger().info("Loaded skin: " + file.getName() + "| geo:" + geoName);
+ } catch (Exception e) {
+ e.printStackTrace();
+ }
+ }
+ }
+ }
+
@Subscribe
public void onSessionJoin(SessionJoinEvent event) {
- System.out.println("JOINED");
if (event.connection() instanceof GeyserSession session) {
- // sendCameraPresets(session);
- System.out.println("2");
session.getDownstream().getSession().addListener(new SessionAdapter() {
@Override
public void packetReceived(Session tcpSession, Packet packet) {
if (packet instanceof ClientboundCustomPayloadPacket payloadPacket) {
- if (payloadPacket.getChannel().equals(GeyserUtilsChannels.MAIN)) {;
+ if (payloadPacket.getChannel().equals(GeyserUtilsChannels.MAIN)) {
+ ;
CustomPayloadPacket customPacket = packetManager.decodePacket(payloadPacket.getData());
if (customPacket instanceof CameraShakeCustomPayloadPacket cameraShakePacket) {
event.connection().shakeCamera(cameraShakePacket.getIntensity(), cameraShakePacket.getDuration(), CameraShake.values()[cameraShakePacket.getType()]);
@@ -141,7 +187,7 @@ public class GeyserUtils implements Extension {
} else if (cameraInstructionPacket.getInstruction() instanceof FadeInstruction instruction) {
session.camera().sendCameraFade(Converter.serializeFadeInstruction(instruction));
- } else if (cameraInstructionPacket.getInstruction() instanceof ClearInstruction){
+ } else if (cameraInstructionPacket.getInstruction() instanceof ClearInstruction) {
session.camera().clearCameraInstructions();
}
@@ -152,6 +198,13 @@ public class GeyserUtils implements Extension {
spawnParticleEffectPacket.setIdentifier(customParticleEffectPacket.getParticle().identifier());
spawnParticleEffectPacket.setMolangVariablesJson(Optional.ofNullable(customParticleEffectPacket.getParticle().molangVariablesJson()));
session.sendUpstreamPacket(spawnParticleEffectPacket);
+ } else if (customPacket instanceof CustomSkinPayloadPacket customSkinPayloadPacket) {
+ if (session.getEntityCache().getEntityByJavaId(customSkinPayloadPacket.getEntityId()) instanceof PlayerEntity player) {
+ SkinProvider.SkinData data = LOADED_SKIN_DATA.get(customSkinPayloadPacket.getSkinId());
+ if (data != null) {
+ sendSkinPacket(session, player, data);
+ }
+ }
}
}
}
@@ -163,32 +216,36 @@ public class GeyserUtils implements Extension {
}
- public static void sendCameraPresets(GeyserSession session) {
- if (session.getUpstream().getCodecHelper().getCameraPresetDefinitions() == null) {
-
- session.getUpstream().getCodecHelper().setCameraPresetDefinitions(new DefinitionRegistry<>() {
- @Override
- public NamedDefinition getDefinition(int i) {
- for (CameraPreset preset : CameraPreset.getPresets().values()) {
- if (preset.getId() == i) {
- return new CameraPresetDefinition(preset.getIdentifier(), i);
- }
- }
-
- return null;
- }
-
- @Override
- public boolean isRegistered(NamedDefinition namedDefinition) {
- return CameraPreset.getPreset(namedDefinition.getIdentifier()) != null;
- }
- });
- }
- CameraPresetsPacket pk = new CameraPresetsPacket();
- for (CameraPreset preset : CameraPreset.getPresets().values()) {
- pk.getPresets().add(Converter.serializeCameraPreset(preset));
+ public static void sendSkinPacket(GeyserSession session, PlayerEntity entity, SkinProvider.SkinData skinData) {
+ SkinProvider.Skin skin = skinData.skin();
+ SkinProvider.Cape cape = skinData.cape();
+ SkinProvider.SkinGeometry geometry = skinData.geometry();
+ if (entity.getUuid().equals(session.getPlayerEntity().getUuid())) {
+ PlayerListPacket.Entry updatedEntry = buildEntryManually(session, entity.getUuid(), entity.getUsername(), entity.getGeyserId(), skin, cape, geometry);
+ PlayerListPacket playerAddPacket = new PlayerListPacket();
+ playerAddPacket.setAction(PlayerListPacket.Action.ADD);
+ playerAddPacket.getEntries().add(updatedEntry);
+ session.sendUpstreamPacket(playerAddPacket);
+ } else {
+ PlayerSkinPacket packet = new PlayerSkinPacket();
+ packet.setUuid(entity.getUuid());
+ packet.setOldSkinName("");
+ packet.setNewSkinName(skin.getTextureUrl());
+ packet.setSkin(getSkin(skin.getTextureUrl(), skin, cape, geometry));
+ packet.setTrustedSkin(true);
+ session.sendUpstreamPacket(packet);
}
- session.sendUpstreamPacket(pk);
+
}
+
+ private static SerializedSkin getSkin(String skinId, SkinProvider.Skin skin, SkinProvider.Cape cape, SkinProvider.SkinGeometry geometry) {
+ try {
+ return SerializedSkin.of(skinId, "", geometry.geometryName(), ImageData.from(ImageIO.read(new ByteArrayInputStream(skin.getSkinData()))), Collections.emptyList(), ImageData.of(cape.capeData()), geometry.geometryData(), "", true, false, false, cape.capeId(), skinId);
+ } catch (IOException e) {
+ throw new RuntimeException(e);
+ }
+ }
+
}
+
diff --git a/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/util/Converter.java b/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/util/Converter.java
index b095cfe..2c13eb0 100644
--- a/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/util/Converter.java
+++ b/geyser/src/main/java/me/zimzaza4/geyserutils/geyser/util/Converter.java
@@ -62,7 +62,6 @@ public class Converter {
public static CameraFade serializeFadeInstruction(FadeInstruction instruction) {
- CameraFadeInstruction cbInstruction = new CameraFadeInstruction();
CameraFade.Builder builder = CameraFade.builder();
if (instruction.getColor() != null) {
builder.color(serializeColor(instruction.getColor()));
diff --git a/spigot/src/main/java/me/zimzaza4/geyserutils/spigot/api/PlayerUtils.java b/spigot/src/main/java/me/zimzaza4/geyserutils/spigot/api/PlayerUtils.java
index b667994..81f11a3 100644
--- a/spigot/src/main/java/me/zimzaza4/geyserutils/spigot/api/PlayerUtils.java
+++ b/spigot/src/main/java/me/zimzaza4/geyserutils/spigot/api/PlayerUtils.java
@@ -3,10 +3,7 @@ package me.zimzaza4.geyserutils.spigot.api;
import me.zimzaza4.geyserutils.common.animation.Animation;
import me.zimzaza4.geyserutils.common.camera.instruction.Instruction;
import me.zimzaza4.geyserutils.common.channel.GeyserUtilsChannels;
-import me.zimzaza4.geyserutils.common.packet.AnimateEntityCustomPayloadPacket;
-import me.zimzaza4.geyserutils.common.packet.CameraInstructionCustomPayloadPacket;
-import me.zimzaza4.geyserutils.common.packet.CameraShakeCustomPayloadPacket;
-import me.zimzaza4.geyserutils.common.packet.CustomParticleEffectPayloadPacket;
+import me.zimzaza4.geyserutils.common.packet.*;
import me.zimzaza4.geyserutils.common.particle.CustomParticle;
import me.zimzaza4.geyserutils.common.util.Pos;
import me.zimzaza4.geyserutils.spigot.GeyserUtils;
@@ -53,6 +50,13 @@ public class PlayerUtils {
packet.setParticle(particle);
packet.setPos(new Pos((float) location.getX(), (float) location.getY(), (float) location.getZ()));
player.sendPluginMessage(GeyserUtils.getInstance(), GeyserUtilsChannels.MAIN, GeyserUtils.getPacketManager().encodePacket(packet));
+ }
+
+ public static void sendCustomSkin(Player player, Entity entity, String skin) {
+ CustomSkinPayloadPacket skinPayloadPacket = new CustomSkinPayloadPacket();
+ skinPayloadPacket.setSkinId(skin);
+ skinPayloadPacket.setEntityId(entity.getEntityId());
+ player.sendPluginMessage(GeyserUtils.getInstance(), GeyserUtilsChannels.MAIN, GeyserUtils.getPacketManager().encodePacket(skinPayloadPacket));
}
}