mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-02 19:42:05 -04:00
Character deletes now delete the character from the DB instead of just changing the state. DB can now get single character. Character list is sent properly as per how 1.0 did it (only 1 'NEW' entry if available). Character info is now loaded from the new character packet and stored. It is also loaded for each character, encoded, and displayed (still testing).
This commit is contained in:
parent
aadca3968d
commit
b717f6aeb1
@ -128,17 +128,31 @@ namespace FFXIVClassic_Lobby_Server
|
||||
}
|
||||
}
|
||||
|
||||
public static void renameCharacter(uint characterId, String newName)
|
||||
public static bool renameCharacter(uint userId, uint characterId, uint serverId, String newName)
|
||||
{
|
||||
using (MySqlConnection conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
|
||||
{
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
|
||||
//Check if exists
|
||||
MySqlCommand cmd = new MySqlCommand("SELECT * FROM characters WHERE name=@name AND serverId=@serverId", conn);
|
||||
cmd.Parameters.AddWithValue("@serverId", serverId);
|
||||
cmd.Parameters.AddWithValue("@name", newName);
|
||||
using (MySqlDataReader Reader = cmd.ExecuteReader())
|
||||
{
|
||||
if (Reader.HasRows)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = "UPDATE characters SET name=@name WHERE id=@cid";
|
||||
cmd.CommandText = "UPDATE characters SET name=@name, doRename=0 WHERE id=@cid AND userId=@uid";
|
||||
cmd.Prepare();
|
||||
cmd.Parameters.AddWithValue("@uid", userId);
|
||||
cmd.Parameters.AddWithValue("@cid", characterId);
|
||||
cmd.Parameters.AddWithValue("@name", newName);
|
||||
cmd.ExecuteNonQuery();
|
||||
@ -152,6 +166,8 @@ namespace FFXIVClassic_Lobby_Server
|
||||
{
|
||||
conn.Dispose();
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -164,7 +180,7 @@ namespace FFXIVClassic_Lobby_Server
|
||||
conn.Open();
|
||||
MySqlCommand cmd = new MySqlCommand();
|
||||
cmd.Connection = conn;
|
||||
cmd.CommandText = "UPDATE characters SET state=1 WHERE id=@cid AND name=@name";
|
||||
cmd.CommandText = "DELETE FROM characters WHERE id=@cid AND name=@name";
|
||||
cmd.Prepare();
|
||||
cmd.Parameters.AddWithValue("@cid", characterId);
|
||||
cmd.Parameters.AddWithValue("@name", name);
|
||||
@ -244,6 +260,29 @@ namespace FFXIVClassic_Lobby_Server
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static Character getCharacter(uint userId, uint charId)
|
||||
{
|
||||
using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
|
||||
{
|
||||
Character chara = null;
|
||||
try
|
||||
{
|
||||
conn.Open();
|
||||
chara = conn.Query<Character>("SELECT * FROM characters WHERE id=@CharaId and userId=@UserId", new { UserId = userId, CharaId = charId }).SingleOrDefault();
|
||||
}
|
||||
catch (MySqlException e)
|
||||
{
|
||||
}
|
||||
finally
|
||||
{
|
||||
conn.Dispose();
|
||||
}
|
||||
|
||||
return chara;
|
||||
}
|
||||
}
|
||||
|
||||
public static List<String> getReservedNames(uint userId)
|
||||
{
|
||||
using (var conn = new MySqlConnection(String.Format("Server={0}; Port={1}; Database={2}; UID={3}; Password={4}", ConfigConstants.DATABASE_HOST, ConfigConstants.DATABASE_PORT, ConfigConstants.DATABASE_NAME, ConfigConstants.DATABASE_USERNAME, ConfigConstants.DATABASE_PASSWORD)))
|
||||
|
@ -157,13 +157,11 @@ namespace FFXIVClassic_Lobby_Server
|
||||
sendWorldList(client, packet);
|
||||
sendImportList(client, packet);
|
||||
sendRetainerList(client, packet);
|
||||
//sendCharacterList(client, packet);
|
||||
|
||||
//BasePacket outgoingPacket = new BasePacket("./packets/getCharsPacket.bin");
|
||||
BasePacket outgoingPacket = new BasePacket("./packets/getChars_GOOD.bin");
|
||||
sendCharacterList(client, packet);
|
||||
/*BasePacket outgoingPacket = new BasePacket("./packets/getChars_GOOD.bin");
|
||||
outgoingPacket.debugPrintPacket();
|
||||
BasePacket.encryptPacket(client.blowfish, outgoingPacket);
|
||||
client.queuePacket(outgoingPacket);
|
||||
|
||||
client.queuePacket(outgoingPacket);*/
|
||||
|
||||
}
|
||||
|
||||
@ -211,9 +209,18 @@ namespace FFXIVClassic_Lobby_Server
|
||||
|
||||
uint pid = 0, cid = 0;
|
||||
|
||||
//Get world from new char instance
|
||||
if (worldId == 0)
|
||||
worldId = client.newCharaWorldId;
|
||||
|
||||
//Check if this character exists, get world from there
|
||||
if (worldId == 0 && charaReq.characterId != 0)
|
||||
{
|
||||
Character chara = Database.getCharacter(client.currentUserId, charaReq.characterId);
|
||||
if (chara != null)
|
||||
worldId = chara.serverId;
|
||||
}
|
||||
|
||||
string worldName = null;
|
||||
World world = Database.getServer(worldId);
|
||||
if (world != null)
|
||||
@ -231,11 +238,13 @@ namespace FFXIVClassic_Lobby_Server
|
||||
return;
|
||||
}
|
||||
|
||||
bool alreadyTaken;
|
||||
|
||||
switch (code)
|
||||
{
|
||||
case 0x01://Reserve
|
||||
|
||||
var alreadyTaken = Database.reserveCharacter(client.currentUserId, slot, worldId, name, out pid, out cid);
|
||||
alreadyTaken = Database.reserveCharacter(client.currentUserId, slot, worldId, name, out pid, out cid);
|
||||
|
||||
if (alreadyTaken)
|
||||
{
|
||||
@ -257,31 +266,45 @@ namespace FFXIVClassic_Lobby_Server
|
||||
client.newCharaName = name;
|
||||
}
|
||||
|
||||
Log.info(String.Format("User {0} => Character reserved \"{1}\"", client.currentUserId, charaReq.characterName));
|
||||
Log.info(String.Format("User {0} => Character reserved \"{1}\"", client.currentUserId, name));
|
||||
break;
|
||||
case 0x02://Make
|
||||
CharaInfo info = new CharaInfo();
|
||||
CharaInfo info = CharaInfo.getFromNewCharRequest(charaReq.characterInfoEncoded);
|
||||
|
||||
Database.makeCharacter(client.currentUserId, client.newCharaCid, info);
|
||||
|
||||
pid = 1;
|
||||
cid = client.newCharaCid;
|
||||
name = client.newCharaName;
|
||||
name = client.newCharaName;
|
||||
|
||||
Log.info(String.Format("User {0} => Character created \"{1}\"", client.currentUserId, charaReq.characterName));
|
||||
Log.info(String.Format("User {0} => Character created \"{1}\"", client.currentUserId, name));
|
||||
break;
|
||||
case 0x03://Rename
|
||||
|
||||
Log.info(String.Format("User {0} => Character renamed \"{1}\"", client.currentUserId, charaReq.characterName));
|
||||
|
||||
alreadyTaken = Database.renameCharacter(client.currentUserId, charaReq.characterId, worldId, charaReq.characterName);
|
||||
|
||||
if (alreadyTaken)
|
||||
{
|
||||
ErrorPacket errorPacket = new ErrorPacket(charaReq.sequence, 1003, 0, 13005, ""); //BDB - Chara Name Used, //1003 - Bad Word
|
||||
SubPacket subpacket = errorPacket.buildPacket();
|
||||
BasePacket basePacket = BasePacket.createPacket(subpacket, true, false);
|
||||
BasePacket.encryptPacket(client.blowfish, basePacket);
|
||||
client.queuePacket(basePacket);
|
||||
|
||||
Log.info(String.Format("User {0} => Error; name taken: \"{1}\"", client.currentUserId, charaReq.characterName));
|
||||
return;
|
||||
}
|
||||
|
||||
Log.info(String.Format("User {0} => Character renamed \"{1}\"", client.currentUserId, name));
|
||||
break;
|
||||
case 0x04://Delete
|
||||
Database.deleteCharacter(charaReq.characterId, charaReq.characterName);
|
||||
|
||||
Log.info(String.Format("User {0} => Character deleted \"{1}\"", client.currentUserId, charaReq.characterName));
|
||||
|
||||
Log.info(String.Format("User {0} => Character deleted \"{1}\"", client.currentUserId, name));
|
||||
break;
|
||||
case 0x06://Rename Retainer
|
||||
|
||||
Log.info(String.Format("User {0} => Retainer renamed \"{1}\"", client.currentUserId, charaReq.characterName));
|
||||
Log.info(String.Format("User {0} => Retainer renamed \"{1}\"", client.currentUserId, name));
|
||||
break;
|
||||
}
|
||||
|
||||
@ -296,7 +319,7 @@ namespace FFXIVClassic_Lobby_Server
|
||||
private void sendWorldList(ClientConnection client, SubPacket packet)
|
||||
{
|
||||
List<World> serverList = Database.getServers();
|
||||
WorldListPacket worldlistPacket = new WorldListPacket(2, serverList);
|
||||
WorldListPacket worldlistPacket = new WorldListPacket(0, serverList);
|
||||
List<SubPacket> subPackets = worldlistPacket.buildPackets();
|
||||
|
||||
BasePacket basePacket = BasePacket.createPacket(subPackets, true, false);
|
||||
@ -309,7 +332,7 @@ namespace FFXIVClassic_Lobby_Server
|
||||
{
|
||||
List<String> names = Database.getReservedNames(client.currentUserId);
|
||||
|
||||
ImportListPacket importListPacket = new ImportListPacket(2, names);
|
||||
ImportListPacket importListPacket = new ImportListPacket(0, names);
|
||||
List<SubPacket> subPackets = importListPacket.buildPackets();
|
||||
BasePacket basePacket = BasePacket.createPacket(subPackets, true, false);
|
||||
BasePacket.encryptPacket(client.blowfish, basePacket);
|
||||
@ -320,7 +343,7 @@ namespace FFXIVClassic_Lobby_Server
|
||||
{
|
||||
List<Retainer> retainers = Database.getRetainers(client.currentUserId);
|
||||
|
||||
RetainerListPacket retainerListPacket = new RetainerListPacket(2, retainers);
|
||||
RetainerListPacket retainerListPacket = new RetainerListPacket(0, retainers);
|
||||
List<SubPacket> subPackets = retainerListPacket.buildPackets();
|
||||
BasePacket basePacket = BasePacket.createPacket(subPackets, true, false);
|
||||
BasePacket.encryptPacket(client.blowfish, basePacket);
|
||||
@ -331,7 +354,10 @@ namespace FFXIVClassic_Lobby_Server
|
||||
{
|
||||
List<Character> characterList = Database.getCharacters(client.currentUserId);
|
||||
|
||||
CharacterListPacket characterlistPacket = new CharacterListPacket(2, characterList, 2);
|
||||
if (characterList.Count > 8)
|
||||
Log.error("Warning, got more than 8 characters. List truncated, check DB for issues.");
|
||||
|
||||
CharacterListPacket characterlistPacket = new CharacterListPacket(0, characterList);
|
||||
List<SubPacket> subPackets = characterlistPacket.buildPackets();
|
||||
BasePacket basePacket = BasePacket.createPacket(subPackets, true, false);
|
||||
BasePacket.encryptPacket(client.blowfish, basePacket);
|
||||
|
@ -3,6 +3,8 @@ using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using FFXIVClassic_Lobby_Server.common;
|
||||
using System.IO;
|
||||
|
||||
namespace FFXIVClassic_Lobby_Server.dataobjects
|
||||
{
|
||||
@ -11,30 +13,33 @@ namespace FFXIVClassic_Lobby_Server.dataobjects
|
||||
public uint tribe = 0;
|
||||
public uint size = 0;
|
||||
public uint voice = 0;
|
||||
public uint skinColor = 0;
|
||||
public ushort skinColor = 0;
|
||||
|
||||
public uint hairStyle = 0;
|
||||
public uint hairColor = 0;
|
||||
public uint eyeColor = 0;
|
||||
public ushort hairStyle = 0;
|
||||
public ushort hairColor = 0;
|
||||
public ushort hairHighlightColor = 0;
|
||||
public ushort eyeColor = 0;
|
||||
public ushort characteristicsColor = 0;
|
||||
|
||||
public uint faceType = 0;
|
||||
public uint faceBrow = 0;
|
||||
public uint faceEye = 0;
|
||||
public uint faceIris = 0;
|
||||
public uint faceEyebrow = 0;
|
||||
public uint faceEyeShape = 0;
|
||||
public uint faceEyeSize = 0;
|
||||
public uint faceNose = 0;
|
||||
public uint faceMouth = 0;
|
||||
public uint faceJaw = 0;
|
||||
public uint faceCheek = 0;
|
||||
public uint faceOption1 = 0;
|
||||
public uint faceOption2 = 0;
|
||||
public uint faceFeatures = 0;
|
||||
public uint characteristics = 0;
|
||||
public uint ears = 0;
|
||||
|
||||
public uint guardian = 0;
|
||||
public uint birthMonth = 0;
|
||||
public uint birthDay = 0;
|
||||
public uint currentClass = 0;
|
||||
public uint currentJob = 0;
|
||||
public uint allegiance = 0;
|
||||
|
||||
public uint weapon1 = 0;
|
||||
public uint weapon2 = 0;
|
||||
public uint mainHand = 0;
|
||||
public uint offHand = 0;
|
||||
|
||||
public uint headGear = 0;
|
||||
public uint bodyGear = 0;
|
||||
@ -46,12 +51,213 @@ namespace FFXIVClassic_Lobby_Server.dataobjects
|
||||
public uint leftEarGear = 0;
|
||||
public uint rightFingerGear = 0;
|
||||
public uint leftFingerGear = 0;
|
||||
|
||||
public byte[] toBytes()
|
||||
|
||||
public uint currentLevel = 1;
|
||||
|
||||
public static CharaInfo getFromNewCharRequest(String encoded)
|
||||
{
|
||||
byte[] bytes = new byte[0x120];
|
||||
return bytes;
|
||||
byte[] data = Convert.FromBase64String(encoded.Replace('-', '+').Replace('_', '/'));
|
||||
CharaInfo info = new CharaInfo();
|
||||
|
||||
using (MemoryStream stream = new MemoryStream(data))
|
||||
{
|
||||
using (BinaryReader reader = new BinaryReader(stream))
|
||||
{
|
||||
uint version = reader.ReadUInt32();
|
||||
uint unknown1 = reader.ReadUInt32();
|
||||
info.tribe = reader.ReadByte();
|
||||
info.size = reader.ReadByte();
|
||||
info.hairStyle = reader.ReadUInt16();
|
||||
info.hairHighlightColor = reader.ReadUInt16();
|
||||
info.faceType = reader.ReadByte();
|
||||
info.characteristics = reader.ReadByte();
|
||||
info.characteristicsColor = reader.ReadByte();
|
||||
|
||||
reader.ReadUInt32();
|
||||
|
||||
info.faceEyebrow = reader.ReadByte();
|
||||
info.faceEyeSize = reader.ReadByte();
|
||||
info.faceEyeShape = reader.ReadByte();
|
||||
info.faceNose = reader.ReadByte();
|
||||
info.faceFeatures = reader.ReadByte();
|
||||
info.faceMouth = reader.ReadByte();
|
||||
info.ears = reader.ReadByte();
|
||||
info.hairColor = reader.ReadUInt16();
|
||||
|
||||
reader.ReadUInt32();
|
||||
|
||||
info.skinColor = reader.ReadUInt16();
|
||||
info.eyeColor = reader.ReadUInt16();
|
||||
|
||||
info.voice = reader.ReadByte();
|
||||
info.guardian = reader.ReadByte();
|
||||
info.birthMonth = reader.ReadByte();
|
||||
info.birthDay = reader.ReadByte();
|
||||
info.currentClass = reader.ReadUInt16();
|
||||
|
||||
reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
reader.ReadUInt32();
|
||||
|
||||
reader.BaseStream.Seek(0x10, SeekOrigin.Current);
|
||||
|
||||
info.allegiance = reader.ReadByte();
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return info;
|
||||
}
|
||||
|
||||
public String buildForCharaList(Character chara)
|
||||
{
|
||||
byte[] data;
|
||||
|
||||
using (MemoryStream stream = new MemoryStream())
|
||||
{
|
||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||
{
|
||||
string location1 = "prv0Inn01";
|
||||
string location2 = "defaultTerritory";
|
||||
|
||||
writer.Write((UInt32)0x000004c0);
|
||||
writer.Write((UInt32)0x232327ea);
|
||||
writer.Write((UInt32)System.Text.Encoding.UTF8.GetBytes(chara.name).Length);
|
||||
writer.Write(System.Text.Encoding.UTF8.GetBytes(chara.name));
|
||||
writer.Write((UInt32)0x1c);
|
||||
writer.Write((UInt32)0x04);
|
||||
writer.Write((UInt32)getTribeModel());
|
||||
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!
|
||||
uint hairVal = hairHighlightColor | (uint)(hairStyle << 10) | (uint)(characteristicsColor << 20);
|
||||
writer.Write((UInt32)hairVal);
|
||||
writer.Write((UInt32)voice);
|
||||
writer.Write((UInt32)mainHand);
|
||||
writer.Write((UInt32)offHand);
|
||||
|
||||
writer.Write((UInt32)0);
|
||||
writer.Write((UInt32)0);
|
||||
writer.Write((UInt32)0);
|
||||
writer.Write((UInt32)0);
|
||||
writer.Write((UInt32)0);
|
||||
|
||||
writer.Write((UInt32)headGear);
|
||||
writer.Write((UInt32)bodyGear);
|
||||
writer.Write((UInt32)legsGear);
|
||||
writer.Write((UInt32)handsGear);
|
||||
writer.Write((UInt32)feetGear);
|
||||
writer.Write((UInt32)waistGear);
|
||||
|
||||
writer.Write((UInt32)0);
|
||||
|
||||
writer.Write((UInt32)rightEarGear);
|
||||
writer.Write((UInt32)leftEarGear);
|
||||
|
||||
writer.Write((UInt32)0);
|
||||
writer.Write((UInt32)0);
|
||||
|
||||
writer.Write((UInt32)rightFingerGear);
|
||||
writer.Write((UInt32)leftFingerGear);
|
||||
|
||||
for (int i = 0; i < 0xC; i++)
|
||||
writer.Write((byte)0);
|
||||
|
||||
writer.Write((UInt32)1);
|
||||
writer.Write((UInt32)1);
|
||||
|
||||
writer.Write((byte)currentClass);
|
||||
writer.Write((UInt16)currentLevel);
|
||||
writer.Write((byte)currentJob);
|
||||
writer.Write((UInt16)1);
|
||||
writer.Write((byte)tribe);
|
||||
|
||||
writer.Write((UInt32)System.Text.Encoding.UTF8.GetBytes(location1).Length);
|
||||
writer.Write(System.Text.Encoding.UTF8.GetBytes(location1));
|
||||
writer.Write((UInt32)System.Text.Encoding.UTF8.GetBytes(location2).Length);
|
||||
writer.Write(System.Text.Encoding.UTF8.GetBytes(location2));
|
||||
|
||||
writer.Write((byte)guardian);
|
||||
writer.Write((byte)birthMonth);
|
||||
writer.Write((byte)birthDay);
|
||||
|
||||
writer.Write((UInt32)4);
|
||||
writer.Write((UInt32)4);
|
||||
|
||||
writer.BaseStream.Seek(0x10, SeekOrigin.Current);
|
||||
|
||||
writer.Write((UInt32)allegiance);
|
||||
writer.Write((UInt32)allegiance);
|
||||
}
|
||||
|
||||
data = stream.GetBuffer();
|
||||
|
||||
File.WriteAllBytes("./packets/out.bin",data);
|
||||
}
|
||||
|
||||
return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_');
|
||||
}
|
||||
|
||||
public static String debug()
|
||||
{
|
||||
byte[] bytes = File.ReadAllBytes("./packets/charaInfo.bin");
|
||||
|
||||
Console.WriteLine(Utils.ByteArrayToHex(bytes));
|
||||
|
||||
return Convert.ToBase64String(bytes).Replace('+', '-').Replace('/', '_');
|
||||
}
|
||||
|
||||
public UInt32 getTribeModel()
|
||||
{
|
||||
switch (tribe)
|
||||
{
|
||||
//Hyur Midlander Male
|
||||
case 0:
|
||||
default:
|
||||
return 1;
|
||||
|
||||
//Hyur Midlander Female
|
||||
case 1:
|
||||
case 2:
|
||||
return 2;
|
||||
|
||||
//Elezen Male
|
||||
case 4:
|
||||
case 6:
|
||||
return 3;
|
||||
|
||||
//Elezen Female
|
||||
case 5:
|
||||
case 7:
|
||||
return 4;
|
||||
|
||||
//Lalafell Male
|
||||
case 8:
|
||||
case 10:
|
||||
return 5;
|
||||
|
||||
//Lalafell Female
|
||||
case 9:
|
||||
case 11:
|
||||
return 6;
|
||||
|
||||
//Miqo'te Female
|
||||
case 12:
|
||||
case 13:
|
||||
return 8;
|
||||
|
||||
//Roegadyn Male
|
||||
case 14:
|
||||
case 15:
|
||||
return 7;
|
||||
|
||||
//Hyur Highlander Male
|
||||
case 3:
|
||||
return 9;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -20,13 +20,7 @@ namespace FFXIVClassic_Lobby_Server
|
||||
public bool doRename;
|
||||
public uint currentZoneId;
|
||||
|
||||
public static String characterToEncoded(CharaInfo chara)
|
||||
{
|
||||
String charaInfo = System.Convert.ToBase64String(chara.toBytes());
|
||||
charaInfo.Replace("+", "-");
|
||||
charaInfo.Replace("/", "_");
|
||||
return charaInfo;
|
||||
}
|
||||
|
||||
|
||||
public static CharaInfo EncodedToCharacter(String charaInfo)
|
||||
{
|
||||
|
@ -1,4 +1,5 @@
|
||||
using FFXIVClassic_Lobby_Server.dataobjects;
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -14,20 +15,20 @@ namespace FFXIVClassic_Lobby_Server.packets
|
||||
public const ushort MAXPERPACKET = 2;
|
||||
|
||||
private ulong sequence;
|
||||
private ushort maxChars;
|
||||
private List<Character> characterList;
|
||||
|
||||
public CharacterListPacket(ulong sequence, List<Character> characterList, ushort maxChars)
|
||||
public CharacterListPacket(ulong sequence, List<Character> characterList)
|
||||
{
|
||||
this.sequence = sequence;
|
||||
this.characterList = characterList;
|
||||
this.maxChars = maxChars;
|
||||
}
|
||||
|
||||
public List<SubPacket> buildPackets()
|
||||
{
|
||||
List<SubPacket> subPackets = new List<SubPacket>();
|
||||
|
||||
int numCharacters = characterList.Count >= 8 ? 8 : characterList.Count + 1;
|
||||
|
||||
int characterCount = 0;
|
||||
int totalCount = 0;
|
||||
|
||||
@ -44,9 +45,8 @@ namespace FFXIVClassic_Lobby_Server.packets
|
||||
//Write List Info
|
||||
binWriter.Write((UInt64)sequence);
|
||||
byte listTracker = (byte)((MAXPERPACKET * 2) * subPackets.Count);
|
||||
binWriter.Write(characterList.Count - totalCount <= MAXPERPACKET ? (byte)(listTracker + 1) : (byte)(listTracker));
|
||||
//binWriter.Write((byte)1);
|
||||
binWriter.Write(maxChars - totalCount <= MAXPERPACKET ? (UInt32)(maxChars - totalCount) : (UInt32)MAXPERPACKET);
|
||||
binWriter.Write(numCharacters - totalCount <= MAXPERPACKET ? (byte)(listTracker + 1) : (byte)(listTracker));
|
||||
binWriter.Write(numCharacters - totalCount <= MAXPERPACKET ? (UInt32)(numCharacters - totalCount) : (UInt32)MAXPERPACKET);
|
||||
binWriter.Write((byte)0);
|
||||
binWriter.Write((UInt16)0);
|
||||
}
|
||||
@ -68,13 +68,16 @@ namespace FFXIVClassic_Lobby_Server.packets
|
||||
options |= 0x02;
|
||||
if (chara.isLegacy)
|
||||
options |= 0x08;
|
||||
|
||||
|
||||
binWriter.Write((byte)options); //Options (0x01: Service Account not active, 0x72: Change Chara Name)
|
||||
binWriter.Write((ushort)0);
|
||||
binWriter.Write((uint)0xF4); //Logged out zone
|
||||
binWriter.Write(Encoding.ASCII.GetBytes(chara.name.PadRight(0x20, '\0'))); //Name
|
||||
binWriter.Write(Encoding.ASCII.GetBytes(worldname.PadRight(0xE, '\0'))); //World Name
|
||||
binWriter.Write("wAQAAOonIyMNAAAAV3Jlbml4IFdyb25nABwAAAAEAAAAAwAAAAMAAAA_8OADAAHQFAAEAAABAAAAABTQCAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAGEgAAAAMQAAQCQAAMAsAACKVAAAAPgCAAAAAAAAAAAAAAAAAAAAAAAAAAAAACQAAAAkAwAAAAAAAAAAANvb1M05AQAABBoAAAEABqoiIuIKAAAAcHJ2MElubjAxABEAAABkZWZhdWx0VGVycml0b3J5AAwJAhcABAAAAAQAAAAAAAAAAAAAAAAAAAAAAAAAAgAAAAIAAAAAAAAAAAAAAAA="); //Appearance Data
|
||||
|
||||
CharaInfo info = JsonConvert.DeserializeObject<CharaInfo>(chara.charaInfo);
|
||||
//binWriter.Write(info.buildForCharaList(chara)); //Appearance Data
|
||||
binWriter.Write(CharaInfo.debug()); //Appearance Data
|
||||
|
||||
characterCount++;
|
||||
totalCount++;
|
||||
@ -90,21 +93,24 @@ namespace FFXIVClassic_Lobby_Server.packets
|
||||
characterCount = 0;
|
||||
}
|
||||
|
||||
//Incase DB came back with more than max
|
||||
if (totalCount >= 8)
|
||||
break;
|
||||
}
|
||||
|
||||
//Keep creating empty slots until done max characters
|
||||
while (maxChars - totalCount > 0)
|
||||
//Add a 'NEW' slot if there is space
|
||||
if (characterList.Count < 8)
|
||||
{
|
||||
if (characterCount % MAXPERPACKET == 0)
|
||||
{
|
||||
memStream = new MemoryStream(0x3D0);
|
||||
memStream = new MemoryStream(0x3B0);
|
||||
binWriter = new BinaryWriter(memStream);
|
||||
|
||||
//Write List Info
|
||||
binWriter.Write((UInt64)sequence);
|
||||
binWriter.Write(maxChars - totalCount <= MAXPERPACKET ? (byte)(maxChars + 1) : (byte)0);
|
||||
//binWriter.Write((byte)1);
|
||||
binWriter.Write(maxChars - totalCount <= MAXPERPACKET ? (UInt32)(maxChars - totalCount) : (UInt32)MAXPERPACKET);
|
||||
byte listTracker = (byte)((MAXPERPACKET * 2) * subPackets.Count);
|
||||
binWriter.Write(numCharacters - totalCount <= MAXPERPACKET ? (byte)(listTracker + 1) : (byte)(listTracker));
|
||||
binWriter.Write(numCharacters - totalCount <= MAXPERPACKET ? (UInt32)(numCharacters-totalCount) : (UInt32)MAXPERPACKET);
|
||||
binWriter.Write((byte)0);
|
||||
binWriter.Write((UInt16)0);
|
||||
}
|
||||
@ -115,7 +121,6 @@ namespace FFXIVClassic_Lobby_Server.packets
|
||||
binWriter.Write((uint)0); //???
|
||||
binWriter.Write((uint)0); //Character Id
|
||||
binWriter.Write((byte)(totalCount)); //Slot
|
||||
|
||||
binWriter.Write((byte)0); //Options (0x01: Service Account not active, 0x72: Change Chara Name)
|
||||
binWriter.Write((ushort)0);
|
||||
binWriter.Write((uint)0); //Logged out zone
|
||||
@ -136,22 +141,8 @@ namespace FFXIVClassic_Lobby_Server.packets
|
||||
}
|
||||
|
||||
//If there is anything left that was missed or the list is empty
|
||||
if (characterCount > 0 || maxChars == 0)
|
||||
{
|
||||
if (maxChars == 0)
|
||||
{
|
||||
memStream = new MemoryStream(0x3D0);
|
||||
binWriter = new BinaryWriter(memStream);
|
||||
|
||||
//Write Empty List Info
|
||||
binWriter.Write((UInt64)sequence);
|
||||
byte listTracker = (byte)((MAXPERPACKET * 2) * subPackets.Count);
|
||||
binWriter.Write(characterList.Count - totalCount <= MAXPERPACKET ? (byte)(listTracker + 1) : (byte)(listTracker));
|
||||
binWriter.Write((UInt32)0);
|
||||
binWriter.Write((byte)0);
|
||||
binWriter.Write((UInt16)0);
|
||||
}
|
||||
|
||||
if (characterCount > 0 || numCharacters == 0)
|
||||
{
|
||||
byte[] data = memStream.GetBuffer();
|
||||
binWriter.Dispose();
|
||||
memStream.Dispose();
|
||||
|
@ -3,18 +3,18 @@
|
||||
|
||||
0x000: Int32;
|
||||
0x004: Int32;
|
||||
0x008:Name Size Int32;
|
||||
0x008:Name Size Int32;
|
||||
0x00C:Name String; Variable size, but in file the name "Wrenix Wrong" is 0xD in size
|
||||
0x019: Int32;
|
||||
0x01D: Int32;
|
||||
0x021:Tribe Model Int32;
|
||||
0x019:Size? Offset? Int32; Must be 0x1c or is crashes....
|
||||
0x01D:Unknown Int32;
|
||||
0x021:Tribe Model Int32;
|
||||
0x025:Size Int32;
|
||||
0x029:Colors Info Int32;
|
||||
0x02D:Face Info Int32;
|
||||
0x031:Hair Model Int32;
|
||||
0x029:Colors Info Int32;
|
||||
0x02D:Face Info Int32;
|
||||
0x031:Hair Style + Highlight Color Int32;
|
||||
0x035:Voice Int32;
|
||||
0x039:MainHand Int32;
|
||||
0x03D:OffHand Int32;
|
||||
0x039:MainHand Int32;
|
||||
0x03D:OffHand Int32;
|
||||
0x041: Int32;
|
||||
0x045: Int32;
|
||||
0x049: Int32;
|
||||
@ -27,29 +27,37 @@
|
||||
0x065:Feet Int32;
|
||||
0x069:Waist Int32;
|
||||
0x06D: Int32;
|
||||
0x071:Right Ear Int32;
|
||||
0x075:Left Ear Int32;
|
||||
0x071:Right Ear Int32;
|
||||
0x075:Left Ear Int32;
|
||||
0x079: Int32;
|
||||
0x07D: Int32;
|
||||
0x081:Right Ring Int32;
|
||||
0x085:Left Ring Int32;
|
||||
0x081:Right Ring Int32;
|
||||
0x085:Left Ring Int32;
|
||||
|
||||
====Zeros/Unknown====
|
||||
|
||||
0x091:ID????? Int32;
|
||||
0x095:Unknown (Must be > 0x00) Int32;
|
||||
0x099:Class Byte;
|
||||
0x09A:Level Short;
|
||||
0x09C:Job Byte;
|
||||
0x09D:Unknown Short;
|
||||
0x09F:Tribe Byte;
|
||||
|
||||
0x0A0: Int32;
|
||||
0x0A4:Location Str Size Int32;
|
||||
0x0A8:Location String String; Variable size, but in file it is prv0Inn01\0, 0x0A in size.
|
||||
0x0A4:Location Str Size Int32;
|
||||
0x0A8:Location String String; Variable size, but in file it is prv0Inn01\0, 0x0A in size.
|
||||
|
||||
0x0B2:Territory Str Size Int32;
|
||||
0x0B6:Territory Str? String; Variable size, but in file it is defaultTerritory\0, 0x11 in size.
|
||||
0x0B2:Territory Str Size Int32;
|
||||
0x0B6:Territory Str? String; Variable size, but in file it is defaultTerritory\0, 0x11 in size.
|
||||
|
||||
0x0C7:Guardian Byte;
|
||||
0x0C8:Birth Month Byte;
|
||||
0x0C9:Birth Day Byte;
|
||||
0x0C7:Guardian Byte;
|
||||
0x0C8:Birth Month Byte;
|
||||
0x0C9:Birth Day Byte;
|
||||
|
||||
0x0CA: Short;
|
||||
0x0CC: Int32;
|
||||
0x0D0: Int32;
|
||||
|
||||
0x0E4: Byte;
|
||||
0x0E8:Allegiance Byte;
|
||||
0x0E8:Allegiance Byte;
|
38
research/encodedCharaMakeInfo.txt
Normal file
38
research/encodedCharaMakeInfo.txt
Normal file
@ -0,0 +1,38 @@
|
||||
===Encoded CharaMake Info=== By Ioncannon
|
||||
-Based on chara info array in Seventh Umbral
|
||||
|
||||
0x00: Unknown... Version? Int32;
|
||||
0x04: Unknown - Weird #1 Int32;
|
||||
0x08: Tribe
|
||||
0x09: Size
|
||||
0x0A: Hair Style Short
|
||||
0x0C: Highlight Hair Color Short;
|
||||
0x0E: Face
|
||||
0x0F: Characteristics
|
||||
0x10: Characteristics Color Short;
|
||||
0x12: Unknown - Weird #2 Int32;
|
||||
0x15: Eyebrows
|
||||
0x16: Eye Size
|
||||
0x17: Eye Shape
|
||||
0x18: Nose
|
||||
0x19: Feature
|
||||
0x1A: Mouth
|
||||
0x1B: Ears
|
||||
0x1C: Hair Color Short;
|
||||
0x1E: Unknown - Weird #3 Int32;
|
||||
0x22: Skin Color Short
|
||||
0x24: Eye Color Short;
|
||||
0x26: Voice
|
||||
0x27: Guardian
|
||||
0x28: Month
|
||||
0x29: Day
|
||||
0x2A: Start Class Short;
|
||||
0x2C: Unknown Int32;
|
||||
0x30: Unknown Int32;
|
||||
0x34: Unknown Int32;
|
||||
|
||||
0x38: 0x10 bytes of 0s
|
||||
|
||||
0x48: Start Nation
|
||||
|
||||
0x49: 0xC bytes of 0s
|
Loading…
Reference in New Issue
Block a user