From caf3968e5b443e31a4b958b7c1a96e3e7234fe29 Mon Sep 17 00:00:00 2001 From: Filip Maj Date: Sun, 13 Sep 2015 14:12:41 -0400 Subject: [PATCH] All appearance data seems to be working now. Equip model ids are sent but not set, so body is invisible. Figuring out how to handle this. --- .../FFXIVClassic_Lobby_Server.csproj | 1 + FFXIVClassic_Lobby_Server/PacketProcessor.cs | 13 +--- FFXIVClassic_Lobby_Server/common/Bitfield.cs | 78 +++++++++++++++++++ .../dataobjects/CharaInfo.cs | 53 +++++++++++-- 4 files changed, 131 insertions(+), 14 deletions(-) create mode 100644 FFXIVClassic_Lobby_Server/common/Bitfield.cs diff --git a/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj b/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj index 203bf2dc..e30d33c2 100644 --- a/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj +++ b/FFXIVClassic_Lobby_Server/FFXIVClassic_Lobby_Server.csproj @@ -55,6 +55,7 @@ + diff --git a/FFXIVClassic_Lobby_Server/PacketProcessor.cs b/FFXIVClassic_Lobby_Server/PacketProcessor.cs index d94f1471..6ed7b0ed 100644 --- a/FFXIVClassic_Lobby_Server/PacketProcessor.cs +++ b/FFXIVClassic_Lobby_Server/PacketProcessor.cs @@ -80,7 +80,7 @@ namespace FFXIVClassic_Lobby_Server BasePacket.decryptPacket(client.blowfish, ref packet); - packet.debugPrintPacket(); + //packet.debugPrintPacket(); List subPackets = packet.getSubpackets(); foreach (SubPacket subpacket in subPackets) @@ -157,11 +157,7 @@ namespace FFXIVClassic_Lobby_Server sendWorldList(client, packet); sendImportList(client, packet); sendRetainerList(client, packet); - sendCharacterList(client, packet); - /*BasePacket outgoingPacket = new BasePacket("./packets/getChars_GOOD.bin"); - outgoingPacket.debugPrintPacket(); - BasePacket.encryptPacket(client.blowfish, outgoingPacket); - client.queuePacket(outgoingPacket);*/ + sendCharacterList(client, packet); } @@ -177,7 +173,7 @@ namespace FFXIVClassic_Lobby_Server Log.info(String.Format("{0} => Select character id {1}", client.currentUserId == 0 ? client.getAddress() : "User " + client.currentUserId, characterId)); - String serverIp = "141.117.162.99"; + String serverIp = "141.117.161.40"; ushort port = 54992; BitConverter.GetBytes(port); BasePacket outgoingPacket = new BasePacket("./packets/selectChar.bin"); @@ -309,8 +305,7 @@ namespace FFXIVClassic_Lobby_Server } CharaCreatorPacket charaCreator = new CharaCreatorPacket(charaReq.sequence, code, pid, cid, 1, name, worldName); - BasePacket charaCreatorPacket = BasePacket.createPacket(charaCreator.buildPacket(), true, false); - charaCreatorPacket.debugPrintPacket(); + BasePacket charaCreatorPacket = BasePacket.createPacket(charaCreator.buildPacket(), true, false); BasePacket.encryptPacket(client.blowfish, charaCreatorPacket); client.queuePacket(charaCreatorPacket); diff --git a/FFXIVClassic_Lobby_Server/common/Bitfield.cs b/FFXIVClassic_Lobby_Server/common/Bitfield.cs new file mode 100644 index 00000000..d4e885a0 --- /dev/null +++ b/FFXIVClassic_Lobby_Server/common/Bitfield.cs @@ -0,0 +1,78 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace FFXIVClassic_Lobby_Server.common +{ + [global::System.AttributeUsage(AttributeTargets.Field, AllowMultiple = false)] + sealed class BitfieldLengthAttribute : Attribute + { + uint length; + + public BitfieldLengthAttribute(uint length) + { + this.length = length; + } + + public uint Length { get { return length; } } + } + + static class PrimitiveConversion + { + public static UInt32 ToUInt32(T t) where T : struct + { + UInt32 r = 0; + int offset = 0; + + // For every field suitably attributed with a BitfieldLength + foreach (System.Reflection.FieldInfo f in t.GetType().GetFields()) + { + object[] attrs = f.GetCustomAttributes(typeof(BitfieldLengthAttribute), false); + if (attrs.Length == 1) + { + uint fieldLength = ((BitfieldLengthAttribute)attrs[0]).Length; + + // Calculate a bitmask of the desired length + uint mask = 0; + for (int i = 0; i < fieldLength; i++) + mask |= (UInt32)1 << i; + + r |= ((UInt32)f.GetValue(t) & mask) << offset; + + offset += (int)fieldLength; + } + } + + return r; + } + + public static long ToLong(T t) where T : struct + { + long r = 0; + int offset = 0; + + // For every field suitably attributed with a BitfieldLength + foreach (System.Reflection.FieldInfo f in t.GetType().GetFields()) + { + object[] attrs = f.GetCustomAttributes(typeof(BitfieldLengthAttribute), false); + if (attrs.Length == 1) + { + uint fieldLength = ((BitfieldLengthAttribute)attrs[0]).Length; + + // Calculate a bitmask of the desired length + long mask = 0; + for (int i = 0; i < fieldLength; i++) + mask |= 1 << i; + + r |= ((UInt32)f.GetValue(t) & mask) << offset; + + offset += (int)fieldLength; + } + } + + return r; + } + } +} \ No newline at end of file diff --git a/FFXIVClassic_Lobby_Server/dataobjects/CharaInfo.cs b/FFXIVClassic_Lobby_Server/dataobjects/CharaInfo.cs index 1ebb52e2..5609d829 100644 --- a/FFXIVClassic_Lobby_Server/dataobjects/CharaInfo.cs +++ b/FFXIVClassic_Lobby_Server/dataobjects/CharaInfo.cs @@ -21,10 +21,36 @@ namespace FFXIVClassic_Lobby_Server.dataobjects public ushort eyeColor = 0; public ushort characteristicsColor = 0; + public struct FaceInfo + { + [BitfieldLength(5)] + public uint characteristics; + [BitfieldLength(3)] + public uint characteristicsColor; + [BitfieldLength(6)] + public uint type; + [BitfieldLength(2)] + public uint ears; + [BitfieldLength(2)] + public uint mouth; + [BitfieldLength(2)] + public uint features; + [BitfieldLength(3)] + public uint nose; + [BitfieldLength(3)] + public uint eyeShape; + [BitfieldLength(1)] + public uint irisSize; + [BitfieldLength(3)] + public uint eyebrows; + [BitfieldLength(2)] + public uint unknown; + } + public uint faceType = 0; - public uint faceEyebrow = 0; + public uint faceEyebrows = 0; public uint faceEyeShape = 0; - public uint faceEyeSize = 0; + public uint faceIrisSize = 0; public uint faceNose = 0; public uint faceMouth = 0; public uint faceFeatures = 0; @@ -75,8 +101,8 @@ namespace FFXIVClassic_Lobby_Server.dataobjects reader.ReadUInt32(); - info.faceEyebrow = reader.ReadByte(); - info.faceEyeSize = reader.ReadByte(); + info.faceEyebrows = reader.ReadByte(); + info.faceIrisSize = reader.ReadByte(); info.faceEyeShape = reader.ReadByte(); info.faceNose = reader.ReadByte(); info.faceFeatures = reader.ReadByte(); @@ -119,6 +145,20 @@ namespace FFXIVClassic_Lobby_Server.dataobjects { using (BinaryWriter writer = new BinaryWriter(stream)) { + //Build faceinfo for later + FaceInfo faceInfo = new FaceInfo(); + faceInfo.characteristics = characteristics; + faceInfo.characteristicsColor = characteristicsColor; + faceInfo.type = faceType; + faceInfo.ears = ears; + faceInfo.features = faceFeatures; + faceInfo.eyebrows = faceEyebrows; + faceInfo.eyeShape = faceEyeShape; + faceInfo.irisSize = faceIrisSize; + faceInfo.mouth = faceMouth; + faceInfo.nose = faceNose; + + string location1 = "prv0Inn01\0"; string location2 = "defaultTerritory\0"; @@ -132,7 +172,10 @@ namespace FFXIVClassic_Lobby_Server.dataobjects writer.Write((UInt32)size); uint colorVal = skinColor | (uint)(hairColor << 10) | (uint)(eyeColor << 20); writer.Write((UInt32)colorVal); - writer.Write((UInt32)0x14d00100); //FACE, Figure this out! + + var bitfield = PrimitiveConversion.ToUInt32(faceInfo); + + writer.Write((UInt32)bitfield); //FACE, Figure this out! uint hairVal = hairHighlightColor | (uint)(hairStyle << 10) | (uint)(characteristicsColor << 20); writer.Write((UInt32)hairVal); writer.Write((UInt32)voice);