Merge pull request #34 from Tim203/master

Some fixes, added playerlist. Player spawning doesn't work yet
This commit is contained in:
Redned 2019-09-16 18:06:03 -05:00 committed by GitHub
commit 610ccbdc62
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 573 additions and 80 deletions

View file

@ -101,8 +101,7 @@ public class Entity {
}
public void despawnEntity(GeyserSession session) {
if (!valid)
return;
if (!valid) return;
RemoveEntityPacket removeEntityPacket = new RemoveEntityPacket();
removeEntityPacket.setUniqueEntityId(geyserId);
@ -129,7 +128,7 @@ public class Entity {
}
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;

View file

@ -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);

View file

@ -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<Packet>();
@ -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

View file

@ -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<Long, Entity> entities = new HashMap<Long, Entity>();
private Map<Long, Long> entityIdTranslations = new HashMap<Long, Long>();
private Map<Long, Entity> entities = new HashMap<>();
private Map<Long, Long> entityIdTranslations = new HashMap<>();
private Map<UUID, PlayerEntity> 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);
}
@ -75,4 +75,16 @@ public class EntityCache {
public Entity getEntityByJavaId(long javaId) {
return entities.get(entityIdTranslations.get(javaId));
}
public void addPlayerEntity(PlayerEntity entity) {
playerEntities.put(entity.getUuid(), entity);
}
public PlayerEntity getPlayerEntity(UUID uuid) {
return playerEntities.get(uuid);
}
public void removePlayerEntity(UUID uuid) {
playerEntities.remove(uuid);
}
}

View file

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

View file

@ -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<ServerPlayerListEntryPacket> {
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().addPlayerEntity(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().removePlayerEntity(entry.getProfile().getId());
}
translate.getEntries().add(entry1);
}
session.getUpstream().sendPacket(translate);
}
}

View file

@ -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<ServerSpawnPlaye
@Override
public void translate(ServerSpawnPlayerPacket packet, GeyserSession session) {
Vector3f position = new Vector3f(packet.getX(), packet.getY(), packet.getZ());
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), 0);
Entity entity = new PlayerEntity(packet.getUUID(), packet.getEntityId(), session.getEntityCache().getNextEntityId().incrementAndGet(),
EntityType.PLAYER, position, new Vector3f(0, 0, 0), rotation);
Vector3f rotation = new Vector3f(packet.getPitch(), packet.getYaw(), packet.getYaw());
if (entity == null)
PlayerEntity entity = session.getEntityCache().getPlayerEntity(packet.getUUID());
if (entity == null) {
Geyser.getLogger().error("Haven't received PlayerListEntry packet before spawning player! We ignore the player");
return;
}
entity.setEntityId(packet.getEntityId());
entity.setPosition(position);
entity.setRotation(rotation);
session.getEntityCache().spawnEntity(entity);
}

View file

@ -0,0 +1,39 @@
package org.geysermc.connector.utils;
import lombok.Getter;
import javax.imageio.ImageIO;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class ProvidedSkin {
@Getter private byte[] skin;
public ProvidedSkin(String internalUrl) {
try {
BufferedImage image = ImageIO.read(ProvidedSkin.class.getClassLoader().getResource(internalUrl));
ByteArrayOutputStream outputStream = new ByteArrayOutputStream(image.getWidth() * 4 + image.getHeight() * 4);
try {
for (int y = 0; y < image.getHeight(); y++) {
for (int x = 0; x < image.getWidth(); x++) {
int rgba = image.getRGB(x, y);
outputStream.write((rgba >> 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();
}
}
}

View file

@ -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;
}
}
}

View file

@ -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"
}
]
}
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB