diff --git a/connector/src/main/java/org/geysermc/connector/entity/Entity.java b/connector/src/main/java/org/geysermc/connector/entity/Entity.java index 612a8e3d..814dedbd 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/Entity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/Entity.java @@ -97,7 +97,7 @@ public class Entity { valid = true; session.getUpstream().sendPacket(addEntityPacket); - GeyserLogger.DEFAULT.debug("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")"); + GeyserLogger.DEFAULT.info("Spawned entity " + entityType + " at location " + position + " with id " + geyserId + " (java id " + entityId + ")"); } public void despawnEntity(GeyserSession session) { @@ -125,11 +125,11 @@ public class Entity { } public void moveAbsolute(Vector3f position, float pitch, float yaw) { - moveAbsolute(position, new Vector3f(pitch, yaw, 0)); + moveAbsolute(position, new Vector3f(pitch, yaw, yaw)); } public void moveAbsolute(Vector3f position, Vector3f rotation) { - if (position.getX() == 0 && position.getX() == 0 && position.getX() == 0 && rotation.getX() == 0 && rotation.getY() == 0) + if (position.getX() == 0 && position.getY() == 0 && position.getZ() == 0 && rotation.getX() == 0 && rotation.getY() == 0) return; this.position = position; diff --git a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java index eee33c17..06b6e7c2 100644 --- a/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java +++ b/connector/src/main/java/org/geysermc/connector/entity/PlayerEntity.java @@ -26,9 +26,7 @@ package org.geysermc.connector.entity; import com.flowpowered.math.vector.Vector3f; -import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; -import com.nukkitx.protocol.bedrock.data.EntityData; -import com.nukkitx.protocol.bedrock.data.EntityDataDictionary; +import com.github.steveice10.mc.auth.data.GameProfile; import com.nukkitx.protocol.bedrock.data.ItemData; import com.nukkitx.protocol.bedrock.packet.AddPlayerPacket; import com.nukkitx.protocol.bedrock.packet.MobArmorEquipmentPacket; @@ -37,14 +35,12 @@ import lombok.Setter; import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; -import java.util.Random; import java.util.UUID; -@Getter -@Setter +@Getter @Setter public class PlayerEntity extends Entity { - private UUID uuid; + private String username; private ItemData hand; @@ -53,10 +49,11 @@ public class PlayerEntity extends Entity { private ItemData leggings; private ItemData boots; - public PlayerEntity(UUID uuid, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { + public PlayerEntity(GameProfile gameProfile, long entityId, long geyserId, EntityType entityType, Vector3f position, Vector3f motion, Vector3f rotation) { super(entityId, geyserId, entityType, position, motion, rotation); - this.uuid = uuid; + uuid = gameProfile.getId(); + username = gameProfile.getName(); } // TODO: Break this into an EquippableEntity class @@ -77,10 +74,10 @@ public class PlayerEntity extends Entity { @Override public void spawnEntity(GeyserSession session) { AddPlayerPacket addPlayerPacket = new AddPlayerPacket(); - addPlayerPacket.setUniqueEntityId(geyserId); + addPlayerPacket.setRuntimeEntityId(geyserId); addPlayerPacket.setUniqueEntityId(geyserId); addPlayerPacket.setUuid(uuid); - addPlayerPacket.setUsername("Player" + new Random().nextInt(1000) + 1); // TODO: Cache player list values and set it here + addPlayerPacket.setUsername(username); addPlayerPacket.setPlatformChatId(""); addPlayerPacket.setPosition(position); addPlayerPacket.setMotion(motion); @@ -92,8 +89,7 @@ public class PlayerEntity extends Entity { addPlayerPacket.setWorldFlags(0); addPlayerPacket.setPlayerPermission(0); addPlayerPacket.setCustomFlags(0); - addPlayerPacket.setDeviceId("WIN10"); // TODO: Find this value - addPlayerPacket.getMetadata().putAll(getMetadata()); + addPlayerPacket.setDeviceId("WIN10"); valid = true; session.getUpstream().sendPacket(addPlayerPacket); diff --git a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java index 1c3930c4..38d466d1 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/GeyserSession.java @@ -29,6 +29,7 @@ import com.flowpowered.math.vector.Vector2f; import com.flowpowered.math.vector.Vector2i; import com.flowpowered.math.vector.Vector3f; import com.flowpowered.math.vector.Vector3i; +import com.github.steveice10.mc.auth.data.GameProfile; import com.github.steveice10.mc.auth.exception.request.RequestException; import com.github.steveice10.mc.protocol.MinecraftProtocol; import com.github.steveice10.packetlib.Client; @@ -103,7 +104,7 @@ public class GeyserSession implements Player { this.scoreboardCache = new ScoreboardCache(this); this.windowCache = new WindowCache(this); - this.playerEntity = new PlayerEntity(UUID.randomUUID(), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)); + this.playerEntity = new PlayerEntity(new GameProfile(UUID.randomUUID(), "Unknown"), 1, 1, EntityType.PLAYER, new Vector3f(0, 0, 0), new Vector3f(0, 0, 0), new Vector3f(0, 0, 0)); this.inventory = new PlayerInventory(); this.javaPacketCache = new DataCache(); @@ -152,6 +153,7 @@ public class GeyserSession implements Player { loggedIn = true; connector.getLogger().info(authenticationData.getName() + " (logged in as: " + protocol.getProfile().getName() + ")" + " has connected to remote java server on address " + remoteServer.getAddress()); playerEntity.setUuid(protocol.getProfile().getId()); + playerEntity.setUsername(protocol.getProfile().getName()); } @Override diff --git a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java index e2bf53c3..8493a2d6 100644 --- a/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java +++ b/connector/src/main/java/org/geysermc/connector/network/session/cache/EntityCache.java @@ -27,10 +27,12 @@ package org.geysermc.connector.network.session.cache; import lombok.Getter; import org.geysermc.connector.entity.Entity; +import org.geysermc.connector.entity.PlayerEntity; import org.geysermc.connector.network.session.GeyserSession; import java.util.HashMap; import java.util.Map; +import java.util.UUID; import java.util.concurrent.atomic.AtomicLong; /** @@ -38,13 +40,12 @@ import java.util.concurrent.atomic.AtomicLong; * for that player (e.g. seeing vanished players from /vanish) */ public class EntityCache { - private GeyserSession session; @Getter - private Map entities = new HashMap(); - - private Map entityIdTranslations = new HashMap(); + private Map entities = new HashMap<>(); + private Map entityIdTranslations = new HashMap<>(); + public Map playerEntities = new HashMap<>(); @Getter private AtomicLong nextEntityId = new AtomicLong(2L); @@ -61,10 +62,9 @@ public class EntityCache { } public void removeEntity(Entity entity) { - if (entity == null) - return; + if (entity == null) return; - entityIdTranslations.remove(entity.getGeyserId()); + entityIdTranslations.remove(entity.getEntityId()); entity.despawnEntity(session); } diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java index e7150acc..558c87e4 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/TranslatorsInit.java @@ -26,29 +26,12 @@ package org.geysermc.connector.network.translators; import com.github.steveice10.mc.protocol.data.game.window.WindowType; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerChatPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerJoinGamePacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerRespawnPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.ServerTitlePacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityAnimationPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityDestroyPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityHeadLookPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityMetadataPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPositionRotationPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityPropertiesPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityRotationPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityTeleportPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.ServerEntityVelocityPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.*; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.*; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerHealthPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerPositionRotationPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.player.ServerPlayerSetExperiencePacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnExpOrbPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnGlobalEntityPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnMobPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnObjectPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPaintingPacket; -import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket; +import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.*; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerDisplayScoreboardPacket; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerScoreboardObjectivePacket; import com.github.steveice10.mc.protocol.packet.ingame.server.scoreboard.ServerUpdateScorePacket; @@ -60,19 +43,9 @@ import com.nukkitx.nbt.CompoundTagBuilder; import com.nukkitx.nbt.NbtUtils; import com.nukkitx.nbt.stream.NBTOutputStream; import com.nukkitx.nbt.tag.CompoundTag; -import com.nukkitx.protocol.bedrock.packet.AnimatePacket; -import com.nukkitx.protocol.bedrock.packet.CommandRequestPacket; -import com.nukkitx.protocol.bedrock.packet.MobEquipmentPacket; -import com.nukkitx.protocol.bedrock.packet.MovePlayerPacket; -import com.nukkitx.protocol.bedrock.packet.PlayerActionPacket; -import com.nukkitx.protocol.bedrock.packet.TextPacket; +import com.nukkitx.protocol.bedrock.packet.*; import lombok.Getter; -import org.geysermc.connector.network.translators.bedrock.BedrockActionTranslator; -import org.geysermc.connector.network.translators.bedrock.BedrockAnimateTranslator; -import org.geysermc.connector.network.translators.bedrock.BedrockCommandRequestTranslator; -import org.geysermc.connector.network.translators.bedrock.BedrockMobEquipmentTranslator; -import org.geysermc.connector.network.translators.bedrock.BedrockMovePlayerTranslator; -import org.geysermc.connector.network.translators.bedrock.BedrockTextTranslator; +import org.geysermc.connector.network.translators.bedrock.*; import org.geysermc.connector.network.translators.block.BlockTranslator; import org.geysermc.connector.network.translators.inventory.GenericInventoryTranslator; import org.geysermc.connector.network.translators.inventory.InventoryTranslator; @@ -80,33 +53,19 @@ import org.geysermc.connector.network.translators.item.ItemTranslator; import org.geysermc.connector.network.translators.java.JavaChatTranslator; import org.geysermc.connector.network.translators.java.JavaJoinGameTranslator; import org.geysermc.connector.network.translators.java.JavaRespawnTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityAnimationTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityDestroyTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityHeadLookTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityMetadataTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityPositionRotationTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityPositionTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityPropertiesTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityRotationTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityTeleportTranslator; -import org.geysermc.connector.network.translators.java.entity.JavaEntityVelocityTranslator; +import org.geysermc.connector.network.translators.java.JavaTitleTranslator; +import org.geysermc.connector.network.translators.java.entity.*; import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerHealthTranslator; import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerPositionRotationTranslator; import org.geysermc.connector.network.translators.java.entity.player.JavaPlayerSetExperienceTranslator; -import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnExpOrbTranslator; -import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnGlobalEntityTranslator; -import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnMobTranslator; -import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnObjectTranslator; -import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPaintingTranslator; -import org.geysermc.connector.network.translators.java.entity.spawn.JavaSpawnPlayerTranslator; +import org.geysermc.connector.network.translators.java.entity.spawn.*; import org.geysermc.connector.network.translators.java.scoreboard.JavaDisplayScoreboardTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaScoreboardObjectiveTranslator; import org.geysermc.connector.network.translators.java.scoreboard.JavaUpdateScoreTranslator; -import org.geysermc.connector.network.translators.java.world.*; import org.geysermc.connector.network.translators.java.window.JavaOpenWindowTranslator; import org.geysermc.connector.network.translators.java.window.JavaSetSlotTranslator; -import org.geysermc.connector.network.translators.java.JavaTitleTranslator; import org.geysermc.connector.network.translators.java.window.JavaWindowItemsTranslator; +import org.geysermc.connector.network.translators.java.world.*; import java.io.ByteArrayOutputStream; import java.io.IOException; @@ -165,6 +124,7 @@ public class TranslatorsInit { Registry.registerJava(ServerSpawnObjectPacket.class, new JavaSpawnObjectTranslator()); Registry.registerJava(ServerSpawnPaintingPacket.class, new JavaSpawnPaintingTranslator()); Registry.registerJava(ServerSpawnPlayerPacket.class, new JavaSpawnPlayerTranslator()); + Registry.registerJava(ServerPlayerListEntryPacket.class, new JavaPlayerListEntryTranslator()); Registry.registerJava(ServerPlayerPositionRotationPacket.class, new JavaPlayerPositionRotationTranslator()); Registry.registerJava(ServerPlayerSetExperiencePacket.class, new JavaPlayerSetExperienceTranslator()); diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java new file mode 100644 index 00000000..43cb57ff --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaPlayerListEntryTranslator.java @@ -0,0 +1,59 @@ +package org.geysermc.connector.network.translators.java.entity.spawn; + +import com.flowpowered.math.vector.Vector3f; +import com.github.steveice10.mc.protocol.data.game.PlayerListEntry; +import com.github.steveice10.mc.protocol.data.game.PlayerListEntryAction; +import com.github.steveice10.mc.protocol.packet.ingame.server.ServerPlayerListEntryPacket; +import com.nukkitx.protocol.bedrock.packet.PlayerListPacket; +import org.geysermc.connector.entity.PlayerEntity; +import org.geysermc.connector.entity.type.EntityType; +import org.geysermc.connector.network.session.GeyserSession; +import org.geysermc.connector.network.translators.PacketTranslator; +import org.geysermc.connector.utils.ProvidedSkin; +import org.geysermc.connector.utils.ProvidedSkinData; + +public class JavaPlayerListEntryTranslator extends PacketTranslator { + private static ProvidedSkinData providedSkinData = ProvidedSkinData.getProvidedSkin("bedrock/skin/model_steve.json"); + private static byte[] providedSkin = new ProvidedSkin("bedrock/skin/skin_steve.png").getSkin(); + + @Override + public void translate(ServerPlayerListEntryPacket packet, GeyserSession session) { + if (packet.getAction() != PlayerListEntryAction.ADD_PLAYER && packet.getAction() != PlayerListEntryAction.REMOVE_PLAYER) return; + + PlayerListPacket translate = new PlayerListPacket(); + translate.setType(packet.getAction() == PlayerListEntryAction.ADD_PLAYER ? PlayerListPacket.Type.ADD : PlayerListPacket.Type.REMOVE); + + for (PlayerListEntry entry : packet.getEntries()) { + PlayerListPacket.Entry entry1 = new PlayerListPacket.Entry(entry.getProfile().getId()); + + if (packet.getAction() == PlayerListEntryAction.ADD_PLAYER) { + long geyserId = session.getEntityCache().getNextEntityId().incrementAndGet(); + + session.getEntityCache().playerEntities.put(entry.getProfile().getId(), new PlayerEntity( + entry.getProfile(), + -1, + geyserId, + EntityType.PLAYER, + Vector3f.ZERO, + Vector3f.ZERO, + Vector3f.ZERO + )); + + entry1.setName(entry.getProfile().getName()); + entry1.setEntityId(geyserId); + entry1.setSkinId(providedSkinData.getSkinId()); + entry1.setSkinData(providedSkin); + entry1.setCapeData(new byte[0]); + entry1.setGeometryName(providedSkinData.getGeometryId()); + entry1.setGeometryData(providedSkinData.getGeometryDataEncoded()); + entry1.setXuid(""); + entry1.setPlatformChatId("WIN10"); + } else { + session.getEntityCache().playerEntities.remove(entry.getProfile().getId()); + } + translate.getEntries().add(entry1); + } + + session.getUpstream().sendPacket(translate); + } +} diff --git a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java index 838dadce..7c0b3cce 100644 --- a/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java +++ b/connector/src/main/java/org/geysermc/connector/network/translators/java/entity/spawn/JavaSpawnPlayerTranslator.java @@ -27,9 +27,8 @@ package org.geysermc.connector.network.translators.java.entity.spawn; import com.flowpowered.math.vector.Vector3f; import com.github.steveice10.mc.protocol.packet.ingame.server.entity.spawn.ServerSpawnPlayerPacket; -import org.geysermc.connector.entity.Entity; +import org.geysermc.api.Geyser; import org.geysermc.connector.entity.PlayerEntity; -import org.geysermc.connector.entity.type.EntityType; import org.geysermc.connector.network.session.GeyserSession; import org.geysermc.connector.network.translators.PacketTranslator; @@ -38,12 +37,17 @@ public class JavaSpawnPlayerTranslator extends PacketTranslator> 16) & 0xFF); + outputStream.write((rgba >> 8) & 0xFF); + outputStream.write(rgba & 0xFF); + outputStream.write((rgba >> 24) & 0xFF); + } + } + image.flush(); + skin = outputStream.toByteArray(); + } finally { + try { + outputStream.close(); + } catch (IOException ignored) {} + } + } catch (IOException e) { + e.printStackTrace(); + } + } +} diff --git a/connector/src/main/java/org/geysermc/connector/utils/ProvidedSkinData.java b/connector/src/main/java/org/geysermc/connector/utils/ProvidedSkinData.java new file mode 100644 index 00000000..9618edcd --- /dev/null +++ b/connector/src/main/java/org/geysermc/connector/utils/ProvidedSkinData.java @@ -0,0 +1,39 @@ +package org.geysermc.connector.utils; + +import com.fasterxml.jackson.core.JsonFactory; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.node.ObjectNode; +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import lombok.Getter; +import org.apache.commons.codec.Charsets; + +import java.util.Base64; + +@Getter +public class ProvidedSkinData { + private static final Gson gson = new GsonBuilder().create(); + private String skinId; + private String skinName; + private String geometryId; + private ObjectNode geometryData; + + public static ProvidedSkinData getProvidedSkin(String skinName) { + try { + ObjectMapper objectMapper = new ObjectMapper(new JsonFactory()); + return objectMapper.readValue(ProvidedSkinData.class.getClassLoader().getResource(skinName), ProvidedSkinData.class); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } + + public String getGeometryDataEncoded() { + try { + return new String(Base64.getEncoder().encode(geometryData.toString().getBytes(Charsets.UTF_8))); + } catch (Exception ex) { + ex.printStackTrace(); + return null; + } + } +} diff --git a/connector/src/main/resources/bedrock/skin/model_steve.json b/connector/src/main/resources/bedrock/skin/model_steve.json new file mode 100644 index 00000000..514308fe --- /dev/null +++ b/connector/src/main/resources/bedrock/skin/model_steve.json @@ -0,0 +1,383 @@ +{ + "skinId" : "c18e65aa-7b21-4637-9b63-8ad63622ef01_Custom", + "skinName" : "skin.Standard.Custom", + "geometryId" : "geometry.humanoid.custom", + "geometryData" : + { + "geometry.humanoid": { + "bones": [ + { + "name": "body", + "pivot": [ 0.0, 24.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 16 ] + } + ] + }, + + { + "name": "waist", + "neverRender": true, + "pivot": [ 0.0, 12.0, 0.0 ] + }, + + { + "name": "head", + "pivot": [ 0.0, 24.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 24.0, -4.0 ], + "size": [ 8, 8, 8 ], + "uv": [ 0, 0 ] + } + ] + }, + + { + "name": "hat", + "pivot": [ 0.0, 24.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 24.0, -4.0 ], + "size": [ 8, 8, 8 ], + "uv": [ 32, 0 ], + "inflate": 0.5 + } + ], + "neverRender": true + }, + + { + "name": "rightArm", + "pivot": [ -5.0, 22.0, 0.0 ], + "cubes": [ + { + "origin": [ -8.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 40, 16 ] + } + ] + }, + + { + "name": "leftArm", + "pivot": [ 5.0, 22.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 40, 16 ] + } + ], + "mirror": true + }, + + { + "name": "rightLeg", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 16 ] + } + ] + }, + + { + "name": "leftLeg", + "pivot": [ 1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 16 ] + } + ], + "mirror": true + } + ] + }, + + "geometry.cape": { + "texturewidth": 64, + "textureheight": 32, + + "bones": [ + { + "name": "cape", + "pivot": [ 0.0, 24.0, -3.0 ], + "cubes": [ + { + "origin": [ -5.0, 8.0, -3.0 ], + "size": [ 10, 16, 1 ], + "uv": [ 0, 0 ] + } + ], + "material": "alpha" + } + ] + }, + "geometry.humanoid.custom:geometry.humanoid": { + "bones": [ + { + "name": "hat", + "neverRender": false, + "material": "alpha", + "pivot": [ 0.0, 24.0, 0.0 ] + }, + { + "name": "leftArm", + "reset": true, + "mirror": false, + "pivot": [ 5.0, 22.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 32, 48 ] + } + ] + }, + + { + "name": "rightArm", + "reset": true, + "pivot": [ -5.0, 22.0, 0.0 ], + "cubes": [ + { + "origin": [ -8.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 40, 16 ] + } + ] + }, + + { + "name": "rightItem", + "pivot": [ -6, 15, 1 ], + "neverRender": true, + "parent": "rightArm" + }, + + { + "name": "leftSleeve", + "pivot": [ 5.0, 22.0, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 48, 48 ], + "inflate": 0.25 + } + ], + "material": "alpha" + }, + + { + "name": "rightSleeve", + "pivot": [ -5.0, 22.0, 0.0 ], + "cubes": [ + { + "origin": [ -8.0, 12.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 40, 32 ], + "inflate": 0.25 + } + ], + "material": "alpha" + }, + + { + "name": "leftLeg", + "reset": true, + "mirror": false, + "pivot": [ 1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 16, 48 ] + } + ] + }, + + { + "name": "leftPants", + "pivot": [ 1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 48 ], + "inflate": 0.25 + } + ], + "pos": [ 1.9, 12, 0 ], + "material": "alpha" + }, + + { + "name": "rightPants", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 32 ], + "inflate": 0.25 + } + ], + "pos": [ -1.9, 12, 0 ], + "material": "alpha" + }, + + { + "name": "jacket", + "pivot": [ 0.0, 24.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 32 ], + "inflate": 0.25 + } + ], + "material": "alpha" + } + ] + }, + "geometry.humanoid.customSlim:geometry.humanoid": { + + "bones": [ + { + "name": "hat", + "neverRender": false, + "material": "alpha" + }, + { + "name": "leftArm", + "reset": true, + "mirror": false, + "pivot": [ 5.0, 21.5, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 11.5, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 32, 48 ] + } + ] + }, + + { + "name": "rightArm", + "reset": true, + "pivot": [ -5.0, 21.5, 0.0 ], + "cubes": [ + { + "origin": [ -7.0, 11.5, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 40, 16 ] + } + ] + }, + + { + "pivot": [ -6, 14.5, 1 ], + "neverRender": true, + "name": "rightItem", + "parent": "rightArm" + }, + + { + "name": "leftSleeve", + "pivot": [ 5.0, 21.5, 0.0 ], + "cubes": [ + { + "origin": [ 4.0, 11.5, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 48, 48 ], + "inflate": 0.25 + } + ], + "material": "alpha" + }, + + { + "name": "rightSleeve", + "pivot": [ -5.0, 21.5, 0.0 ], + "cubes": [ + { + "origin": [ -7.0, 11.5, -2.0 ], + "size": [ 3, 12, 4 ], + "uv": [ 40, 32 ], + "inflate": 0.25 + } + ], + "material": "alpha" + }, + + { + "name": "leftLeg", + "reset": true, + "mirror": false, + "pivot": [ 1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 16, 48 ] + } + ] + }, + + { + "name": "leftPants", + "pivot": [ 1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -0.1, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 48 ], + "inflate": 0.25 + } + ], + "material": "alpha" + }, + + { + "name": "rightPants", + "pivot": [ -1.9, 12.0, 0.0 ], + "cubes": [ + { + "origin": [ -3.9, 0.0, -2.0 ], + "size": [ 4, 12, 4 ], + "uv": [ 0, 32 ], + "inflate": 0.25 + } + ], + "material": "alpha" + }, + + { + "name": "jacket", + "pivot": [ 0.0, 24.0, 0.0 ], + "cubes": [ + { + "origin": [ -4.0, 12.0, -2.0 ], + "size": [ 8, 12, 4 ], + "uv": [ 16, 32 ], + "inflate": 0.25 + } + ], + "material": "alpha" + } + ] + } + + } + +} \ No newline at end of file diff --git a/connector/src/main/resources/bedrock/skin/skin_steve.png b/connector/src/main/resources/bedrock/skin/skin_steve.png new file mode 100644 index 00000000..056f108f Binary files /dev/null and b/connector/src/main/resources/bedrock/skin/skin_steve.png differ