mirror of
https://bitbucket.org/Ioncannon/project-meteor-server.git
synced 2025-04-02 19:42:05 -04:00
Added account and select character packet creators. Fixed wrong field being read for session id. Most of the server is now NOT hardcoded and customizable from the DB. Only hardcoded packet left is the initial handshake.
This commit is contained in:
parent
caf3968e5b
commit
ddf1d2d1a3
@ -26,6 +26,7 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
//Instance Stuff
|
//Instance Stuff
|
||||||
public uint currentUserId = 0;
|
public uint currentUserId = 0;
|
||||||
public uint currentAccount;
|
public uint currentAccount;
|
||||||
|
public string currentSessionToken;
|
||||||
|
|
||||||
//Chara Creation
|
//Chara Creation
|
||||||
public string newCharaName;
|
public string newCharaName;
|
||||||
|
@ -7,10 +7,11 @@ using System.Collections.Generic;
|
|||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
|
using FFXIVClassic_Lobby_Server.common;
|
||||||
|
|
||||||
namespace FFXIVClassic_Lobby_Server
|
namespace FFXIVClassic_Lobby_Server
|
||||||
{
|
{
|
||||||
//charState: 0 - Reserved, 1 - Deleted, 2 - Inactive, 3 - Active
|
//charState: 0 - Reserved, 1 - Inactive, 2 - Active
|
||||||
|
|
||||||
class Database
|
class Database
|
||||||
{
|
{
|
||||||
@ -37,7 +38,7 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
finally
|
finally
|
||||||
{
|
{
|
||||||
conn.Dispose();
|
conn.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return id;
|
return id;
|
||||||
}
|
}
|
||||||
@ -93,6 +94,8 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
{
|
{
|
||||||
conn.Dispose();
|
conn.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.database(String.Format("CID={0} created on 'characters' table.", cid));
|
||||||
}
|
}
|
||||||
|
|
||||||
return alreadyExists;
|
return alreadyExists;
|
||||||
@ -107,7 +110,7 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
conn.Open();
|
conn.Open();
|
||||||
MySqlCommand cmd = new MySqlCommand();
|
MySqlCommand cmd = new MySqlCommand();
|
||||||
cmd.Connection = conn;
|
cmd.Connection = conn;
|
||||||
cmd.CommandText = "UPDATE characters SET state=3, charaInfo=@encodedInfo WHERE userId=@userId AND id=@cid";
|
cmd.CommandText = "UPDATE characters SET state=2, charaInfo=@encodedInfo WHERE userId=@userId AND id=@cid";
|
||||||
cmd.Prepare();
|
cmd.Prepare();
|
||||||
|
|
||||||
cmd.Parameters.AddWithValue("@userId", accountId);
|
cmd.Parameters.AddWithValue("@userId", accountId);
|
||||||
@ -125,6 +128,8 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
{
|
{
|
||||||
conn.Dispose();
|
conn.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.database(String.Format("CID={0} state updated to active(2).", cid));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -167,6 +172,8 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
conn.Dispose();
|
conn.Dispose();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.database(String.Format("CID={0} name updated to \"{1}\".", characterId, newName));
|
||||||
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,6 +203,8 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
conn.Dispose();
|
conn.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Log.database(String.Format("CID={0} deleted.", characterId));
|
||||||
}
|
}
|
||||||
|
|
||||||
public static List<World> getServers()
|
public static List<World> getServers()
|
||||||
|
@ -58,6 +58,7 @@
|
|||||||
<Compile Include="common\Bitfield.cs" />
|
<Compile Include="common\Bitfield.cs" />
|
||||||
<Compile Include="common\Log.cs" />
|
<Compile Include="common\Log.cs" />
|
||||||
<Compile Include="common\STA_INIFile.cs" />
|
<Compile Include="common\STA_INIFile.cs" />
|
||||||
|
<Compile Include="dataobjects\Account.cs" />
|
||||||
<Compile Include="dataobjects\CharaInfo.cs" />
|
<Compile Include="dataobjects\CharaInfo.cs" />
|
||||||
<Compile Include="dataobjects\Retainer.cs" />
|
<Compile Include="dataobjects\Retainer.cs" />
|
||||||
<Compile Include="dataobjects\Character.cs" />
|
<Compile Include="dataobjects\Character.cs" />
|
||||||
@ -74,9 +75,11 @@
|
|||||||
<Compile Include="packets\ErrorPacket.cs" />
|
<Compile Include="packets\ErrorPacket.cs" />
|
||||||
<Compile Include="packets\HardCoded_Packets.cs" />
|
<Compile Include="packets\HardCoded_Packets.cs" />
|
||||||
<Compile Include="packets\PacketStructs.cs" />
|
<Compile Include="packets\PacketStructs.cs" />
|
||||||
|
<Compile Include="packets\SelectCharacterConfirmPacket.cs" />
|
||||||
<Compile Include="packets\SubPacket.cs" />
|
<Compile Include="packets\SubPacket.cs" />
|
||||||
<Compile Include="packets\CharacterListPacket.cs" />
|
<Compile Include="packets\CharacterListPacket.cs" />
|
||||||
<Compile Include="packets\ImportListPacket.cs" />
|
<Compile Include="packets\ImportListPacket.cs" />
|
||||||
|
<Compile Include="packets\AccountListPacket.cs" />
|
||||||
<Compile Include="packets\WorldListPacket.cs" />
|
<Compile Include="packets\WorldListPacket.cs" />
|
||||||
<Compile Include="Program.cs" />
|
<Compile Include="Program.cs" />
|
||||||
<Compile Include="Properties\AssemblyInfo.cs" />
|
<Compile Include="Properties\AssemblyInfo.cs" />
|
||||||
|
@ -84,8 +84,8 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
|
|
||||||
List<SubPacket> subPackets = packet.getSubpackets();
|
List<SubPacket> subPackets = packet.getSubpackets();
|
||||||
foreach (SubPacket subpacket in subPackets)
|
foreach (SubPacket subpacket in subPackets)
|
||||||
{
|
{
|
||||||
|
subpacket.debugPrintSubPacket();
|
||||||
switch (subpacket.header.opcode)
|
switch (subpacket.header.opcode)
|
||||||
{
|
{
|
||||||
case 0x03:
|
case 0x03:
|
||||||
@ -127,27 +127,39 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
|
|
||||||
private void ProcessSessionAcknowledgement(ClientConnection client, SubPacket packet)
|
private void ProcessSessionAcknowledgement(ClientConnection client, SubPacket packet)
|
||||||
{
|
{
|
||||||
PacketStructs.SessionPacket sessionPacket = PacketStructs.toSessionStruct(packet.data);
|
PacketStructs.SessionPacket sessionPacket = PacketStructs.toSessionStruct(packet.data);
|
||||||
String sessionId = sessionPacket.session;
|
|
||||||
String clientVersion = sessionPacket.version;
|
String clientVersion = sessionPacket.version;
|
||||||
|
|
||||||
Log.info(String.Format("Got acknowledgment for secure session."));
|
Log.info(String.Format("Got acknowledgment for secure session."));
|
||||||
Log.info(String.Format("SESSION ID: {0}", sessionId));
|
|
||||||
Log.info(String.Format("CLIENT VERSION: {0}", clientVersion));
|
Log.info(String.Format("CLIENT VERSION: {0}", clientVersion));
|
||||||
|
|
||||||
uint userId = Database.getUserIdFromSession(sessionId);
|
uint userId = Database.getUserIdFromSession(sessionPacket.session);
|
||||||
client.currentUserId = userId;
|
client.currentUserId = userId;
|
||||||
|
client.currentSessionToken = sessionPacket.session; ;
|
||||||
|
|
||||||
if (userId == 0)
|
if (userId == 0)
|
||||||
{
|
{
|
||||||
//client.disconnect();
|
ErrorPacket errorPacket = new ErrorPacket(sessionPacket.sequence, 0, 0, 13001, "Your session has expired, please login again.");
|
||||||
Log.info(String.Format("Invalid session, kicking..."));
|
SubPacket subpacket = errorPacket.buildPacket();
|
||||||
|
BasePacket errorBasePacket = BasePacket.createPacket(subpacket, true, false);
|
||||||
|
BasePacket.encryptPacket(client.blowfish, errorBasePacket);
|
||||||
|
client.queuePacket(errorBasePacket);
|
||||||
|
|
||||||
|
Log.info(String.Format("Invalid session, kicking..."));
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info(String.Format("USER ID: {0}", userId));
|
Log.info(String.Format("USER ID: {0}", userId));
|
||||||
BasePacket outgoingPacket = new BasePacket("./packets/loginAck.bin");
|
|
||||||
BasePacket.encryptPacket(client.blowfish, outgoingPacket);
|
List<Account> accountList = new List<Account>();
|
||||||
client.queuePacket(outgoingPacket);
|
Account defaultAccount = new Account();
|
||||||
|
defaultAccount.id = 1;
|
||||||
|
defaultAccount.name = "FINAL FANTASY XIV";
|
||||||
|
accountList.Add(defaultAccount);
|
||||||
|
AccountListPacket listPacket = new AccountListPacket(1, accountList);
|
||||||
|
BasePacket basePacket = BasePacket.createPacket(listPacket.buildPackets(), true, false);
|
||||||
|
BasePacket.encryptPacket(client.blowfish, basePacket);
|
||||||
|
client.queuePacket(basePacket);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void ProcessGetCharacters(ClientConnection client, SubPacket packet)
|
private void ProcessGetCharacters(ClientConnection client, SubPacket packet)
|
||||||
@ -163,33 +175,29 @@ namespace FFXIVClassic_Lobby_Server
|
|||||||
|
|
||||||
private void ProcessSelectCharacter(ClientConnection client, SubPacket packet)
|
private void ProcessSelectCharacter(ClientConnection client, SubPacket packet)
|
||||||
{
|
{
|
||||||
uint characterId = 0;
|
FFXIVClassic_Lobby_Server.packets.PacketStructs.SelectCharRequestPacket selectCharRequest = PacketStructs.toSelectCharRequestStruct(packet.data);
|
||||||
using (BinaryReader binReader = new BinaryReader(new MemoryStream(packet.data)))
|
|
||||||
|
Log.info(String.Format("{0} => Select character id {1}", client.currentUserId == 0 ? client.getAddress() : "User " + client.currentUserId, selectCharRequest.characterId));
|
||||||
|
|
||||||
|
Character chara = Database.getCharacter(client.currentUserId, selectCharRequest.characterId);
|
||||||
|
World world = null;
|
||||||
|
|
||||||
|
if (chara != null)
|
||||||
|
world = Database.getServer(chara.serverId);
|
||||||
|
|
||||||
|
if (world == null)
|
||||||
{
|
{
|
||||||
binReader.BaseStream.Seek(0x8, SeekOrigin.Begin);
|
ErrorPacket errorPacket = new ErrorPacket(selectCharRequest.sequence, 0, 0, 13001, "World does not exist or is inactive.");
|
||||||
characterId = binReader.ReadUInt32();
|
SubPacket subpacket = errorPacket.buildPacket();
|
||||||
binReader.Close();
|
BasePacket basePacket = BasePacket.createPacket(subpacket, true, false);
|
||||||
|
BasePacket.encryptPacket(client.blowfish, basePacket);
|
||||||
|
client.queuePacket(basePacket);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
Log.info(String.Format("{0} => Select character id {1}", client.currentUserId == 0 ? client.getAddress() : "User " + client.currentUserId, characterId));
|
SelectCharacterConfirmPacket connectCharacter = new SelectCharacterConfirmPacket(selectCharRequest.sequence, selectCharRequest.characterId, client.currentSessionToken, world.address, world.port, selectCharRequest.ticket);
|
||||||
|
|
||||||
String serverIp = "141.117.161.40";
|
|
||||||
ushort port = 54992;
|
|
||||||
BitConverter.GetBytes(port);
|
|
||||||
BasePacket outgoingPacket = new BasePacket("./packets/selectChar.bin");
|
|
||||||
|
|
||||||
//Write Character ID and Server info
|
|
||||||
using (BinaryWriter binWriter = new BinaryWriter(new MemoryStream(outgoingPacket.data)))
|
|
||||||
{
|
|
||||||
binWriter.Seek(0x28, SeekOrigin.Begin);
|
|
||||||
binWriter.Write(characterId);
|
|
||||||
binWriter.Seek(0x78, SeekOrigin.Begin);
|
|
||||||
binWriter.Write(System.Text.Encoding.ASCII.GetBytes(serverIp));
|
|
||||||
binWriter.Seek(0x76, SeekOrigin.Begin);
|
|
||||||
binWriter.Write(port);
|
|
||||||
binWriter.Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
BasePacket outgoingPacket = BasePacket.createPacket(connectCharacter.buildPackets(), true, false);
|
||||||
BasePacket.encryptPacket(client.blowfish, outgoingPacket);
|
BasePacket.encryptPacket(client.blowfish, outgoingPacket);
|
||||||
client.queuePacket(outgoingPacket);
|
client.queuePacket(outgoingPacket);
|
||||||
}
|
}
|
||||||
|
@ -8,11 +8,11 @@ namespace FFXIVClassic_Lobby_Server.common
|
|||||||
|
|
||||||
public class Blowfish
|
public class Blowfish
|
||||||
{
|
{
|
||||||
[DllImport("../../../Debug/Blowfish.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("./Blowfish.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern short initializeBlowfish(byte[] key, short keySize, uint[] P, uint[,] S);
|
private static extern short initializeBlowfish(byte[] key, short keySize, uint[] P, uint[,] S);
|
||||||
[DllImport("../../../Debug/Blowfish.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("./Blowfish.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void blowfish_encipher(ref int xl, ref int xr, uint[] P);
|
private static extern void blowfish_encipher(ref int xl, ref int xr, uint[] P);
|
||||||
[DllImport("../../../Debug/Blowfish.dll", CallingConvention = CallingConvention.Cdecl)]
|
[DllImport("./Blowfish.dll", CallingConvention = CallingConvention.Cdecl)]
|
||||||
private static extern void blowfish_decipher(ref int xl, ref int xr, uint[] P);
|
private static extern void blowfish_decipher(ref int xl, ref int xr, uint[] P);
|
||||||
|
|
||||||
private uint[] P = new uint[16+2];
|
private uint[] P = new uint[16+2];
|
||||||
|
14
FFXIVClassic_Lobby_Server/dataobjects/Account.cs
Normal file
14
FFXIVClassic_Lobby_Server/dataobjects/Account.cs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FFXIVClassic_Lobby_Server.dataobjects
|
||||||
|
{
|
||||||
|
class Account
|
||||||
|
{
|
||||||
|
public UInt32 id;
|
||||||
|
public string name;
|
||||||
|
}
|
||||||
|
}
|
@ -141,6 +141,14 @@ namespace FFXIVClassic_Lobby_Server.dataobjects
|
|||||||
{
|
{
|
||||||
byte[] data;
|
byte[] data;
|
||||||
|
|
||||||
|
mainHand = 79707136;
|
||||||
|
offHand = 32509954;
|
||||||
|
headGear = 43008;
|
||||||
|
bodyGear = 43008;
|
||||||
|
legsGear = 43008;
|
||||||
|
handsGear = 43008;
|
||||||
|
feetGear = 43008;
|
||||||
|
|
||||||
using (MemoryStream stream = new MemoryStream())
|
using (MemoryStream stream = new MemoryStream())
|
||||||
{
|
{
|
||||||
using (BinaryWriter writer = new BinaryWriter(stream))
|
using (BinaryWriter writer = new BinaryWriter(stream))
|
||||||
@ -240,8 +248,6 @@ namespace FFXIVClassic_Lobby_Server.dataobjects
|
|||||||
}
|
}
|
||||||
|
|
||||||
data = stream.GetBuffer();
|
data = stream.GetBuffer();
|
||||||
|
|
||||||
File.WriteAllBytes("./packets/out.bin",data);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_');
|
return Convert.ToBase64String(data).Replace('+', '-').Replace('/', '_');
|
||||||
|
99
FFXIVClassic_Lobby_Server/packets/AccountListPacket.cs
Normal file
99
FFXIVClassic_Lobby_Server/packets/AccountListPacket.cs
Normal file
@ -0,0 +1,99 @@
|
|||||||
|
using FFXIVClassic_Lobby_Server.dataobjects;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FFXIVClassic_Lobby_Server.packets
|
||||||
|
{
|
||||||
|
class AccountListPacket
|
||||||
|
{
|
||||||
|
public const ushort OPCODE = 0x0C;
|
||||||
|
public const ushort MAXPERPACKET = 8;
|
||||||
|
|
||||||
|
private UInt64 sequence;
|
||||||
|
private List<Account> accountList;
|
||||||
|
|
||||||
|
public AccountListPacket(UInt64 sequence, List<Account> accountList)
|
||||||
|
{
|
||||||
|
this.sequence = sequence;
|
||||||
|
this.accountList = accountList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SubPacket> buildPackets()
|
||||||
|
{
|
||||||
|
List<SubPacket> subPackets = new List<SubPacket>();
|
||||||
|
|
||||||
|
int accountCount = 0;
|
||||||
|
int totalCount = 0;
|
||||||
|
|
||||||
|
MemoryStream memStream = null;
|
||||||
|
BinaryWriter binWriter = null;
|
||||||
|
|
||||||
|
foreach (Account account in accountList)
|
||||||
|
{
|
||||||
|
if (totalCount == 0 || accountCount % MAXPERPACKET == 0)
|
||||||
|
{
|
||||||
|
memStream = new MemoryStream(0x280);
|
||||||
|
binWriter = new BinaryWriter(memStream);
|
||||||
|
|
||||||
|
//Write List Info
|
||||||
|
binWriter.Write((UInt64)sequence);
|
||||||
|
byte listTracker = (byte)((MAXPERPACKET * 2) * subPackets.Count);
|
||||||
|
binWriter.Write(accountList.Count - totalCount <= MAXPERPACKET ? (byte)(listTracker + 1) : (byte)(listTracker));
|
||||||
|
binWriter.Write(accountList.Count - totalCount <= MAXPERPACKET ? (UInt32)(accountList.Count - totalCount) : (UInt32)MAXPERPACKET);
|
||||||
|
binWriter.Write((byte)0);
|
||||||
|
binWriter.Write((UInt16)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
//Write Entries
|
||||||
|
binWriter.Write((UInt32)account.id);
|
||||||
|
binWriter.Write((UInt32)0);
|
||||||
|
binWriter.Write(Encoding.ASCII.GetBytes(account.name.PadRight(0x40, '\0')));
|
||||||
|
|
||||||
|
accountCount++;
|
||||||
|
totalCount++;
|
||||||
|
|
||||||
|
//Send this chunk of world list
|
||||||
|
if (accountCount >= MAXPERPACKET)
|
||||||
|
{
|
||||||
|
byte[] data = memStream.GetBuffer();
|
||||||
|
binWriter.Dispose();
|
||||||
|
memStream.Dispose();
|
||||||
|
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data);
|
||||||
|
subPackets.Add(subpacket);
|
||||||
|
accountCount = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
//If there is anything left that was missed or the list is empty
|
||||||
|
if (accountCount > 0 || accountList.Count == 0)
|
||||||
|
{
|
||||||
|
if (accountList.Count == 0)
|
||||||
|
{
|
||||||
|
memStream = new MemoryStream(0x210);
|
||||||
|
binWriter = new BinaryWriter(memStream);
|
||||||
|
|
||||||
|
//Write Empty List Info
|
||||||
|
binWriter.Write((UInt64)sequence);
|
||||||
|
byte listTracker = (byte)((MAXPERPACKET * 2) * subPackets.Count);
|
||||||
|
binWriter.Write(accountList.Count - totalCount <= MAXPERPACKET ? (byte)(listTracker + 1) : (byte)(listTracker));
|
||||||
|
binWriter.Write((UInt32)0);
|
||||||
|
binWriter.Write((byte)0);
|
||||||
|
binWriter.Write((UInt16)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
byte[] data = memStream.GetBuffer();
|
||||||
|
binWriter.Dispose();
|
||||||
|
memStream.Dispose();
|
||||||
|
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data);
|
||||||
|
subPackets.Add(subpacket);
|
||||||
|
}
|
||||||
|
|
||||||
|
return subPackets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -13,13 +13,13 @@ namespace FFXIVClassic_Lobby_Server.packets
|
|||||||
public unsafe struct SessionPacket
|
public unsafe struct SessionPacket
|
||||||
{
|
{
|
||||||
[FieldOffset(0)]
|
[FieldOffset(0)]
|
||||||
public UInt64 sequence;
|
public UInt64 sequence;
|
||||||
|
[FieldOffset(0x10)]
|
||||||
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x40)]
|
||||||
|
public String session;
|
||||||
[FieldOffset(0x50)]
|
[FieldOffset(0x50)]
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
||||||
public String version;
|
public String version;
|
||||||
[FieldOffset(0x70)]
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x20)]
|
|
||||||
public String session;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
@ -37,38 +37,13 @@ namespace FFXIVClassic_Lobby_Server.packets
|
|||||||
public String characterInfoEncoded;
|
public String characterInfoEncoded;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Response Packets
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct ReserveCharaResponse
|
public unsafe struct SelectCharRequestPacket
|
||||||
{
|
{
|
||||||
public UInt64 sequence;
|
public UInt64 sequence;
|
||||||
public uint errorCode;
|
public uint characterId;
|
||||||
public uint statusCode;
|
public uint unknownId;
|
||||||
public uint errorId;
|
public UInt64 ticket;
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x2BB)]
|
|
||||||
public String errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public unsafe struct MakeCharaResponse
|
|
||||||
{
|
|
||||||
public UInt64 sequence;
|
|
||||||
public uint errorCode;
|
|
||||||
public uint statusCode;
|
|
||||||
public uint errorId;
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x2BB)]
|
|
||||||
public String errorMessage;
|
|
||||||
}
|
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
|
||||||
public unsafe struct DeleteCharaResponse
|
|
||||||
{
|
|
||||||
public UInt64 sequence;
|
|
||||||
public uint errorCode;
|
|
||||||
public uint statusCode;
|
|
||||||
public uint errorId;
|
|
||||||
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 0x2BB)]
|
|
||||||
public String errorMessage;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static unsafe CharacterRequestPacket toCharacterRequestStruct(byte[] bytes)
|
public static unsafe CharacterRequestPacket toCharacterRequestStruct(byte[] bytes)
|
||||||
@ -87,6 +62,14 @@ namespace FFXIVClassic_Lobby_Server.packets
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static unsafe SelectCharRequestPacket toSelectCharRequestStruct(byte[] bytes)
|
||||||
|
{
|
||||||
|
fixed (byte* pdata = &bytes[0])
|
||||||
|
{
|
||||||
|
return (SelectCharRequestPacket)Marshal.PtrToStructure(new IntPtr(pdata), typeof(SelectCharRequestPacket));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public static byte[] StructureToByteArray(object obj)
|
public static byte[] StructureToByteArray(object obj)
|
||||||
{
|
{
|
||||||
int len = Marshal.SizeOf(obj);
|
int len = Marshal.SizeOf(obj);
|
||||||
|
@ -0,0 +1,59 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.IO;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace FFXIVClassic_Lobby_Server.packets
|
||||||
|
{
|
||||||
|
class SelectCharacterConfirmPacket
|
||||||
|
{
|
||||||
|
public const ushort OPCODE = 0x0F;
|
||||||
|
|
||||||
|
private UInt64 sequence;
|
||||||
|
private UInt32 characterId;
|
||||||
|
private string sessionToken;
|
||||||
|
private string worldIp;
|
||||||
|
private UInt16 worldPort;
|
||||||
|
private UInt64 selectCharTicket;
|
||||||
|
|
||||||
|
public SelectCharacterConfirmPacket(UInt64 sequence, UInt32 characterId, string sessionToken, string worldIp, ushort worldPort, UInt64 selectCharTicket)
|
||||||
|
{
|
||||||
|
this.sequence = sequence;
|
||||||
|
this.characterId = characterId;
|
||||||
|
this.sessionToken = sessionToken;
|
||||||
|
this.worldIp = worldIp;
|
||||||
|
this.worldPort = worldPort;
|
||||||
|
this.selectCharTicket = selectCharTicket;
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<SubPacket> buildPackets()
|
||||||
|
{
|
||||||
|
List<SubPacket> subPackets = new List<SubPacket>();
|
||||||
|
|
||||||
|
byte[] data;
|
||||||
|
|
||||||
|
using (MemoryStream memStream = new MemoryStream(0x98))
|
||||||
|
{
|
||||||
|
using (BinaryWriter binWriter = new BinaryWriter(memStream))
|
||||||
|
{
|
||||||
|
binWriter.Write((UInt64)sequence);
|
||||||
|
binWriter.Write((UInt32)characterId); //ActorId
|
||||||
|
binWriter.Write((UInt32)characterId); //CharacterId
|
||||||
|
binWriter.Write((UInt32)0);
|
||||||
|
binWriter.Write(Encoding.ASCII.GetBytes(sessionToken.PadRight(0x42, '\0'))); //Session Token
|
||||||
|
binWriter.Write((UInt16)worldPort); //World Port
|
||||||
|
binWriter.Write(Encoding.ASCII.GetBytes(worldIp.PadRight(0x38, '\0'))); //World Hostname/IP
|
||||||
|
binWriter.Write((UInt64)selectCharTicket); //Ticket or Handshake of somekind
|
||||||
|
}
|
||||||
|
data = memStream.GetBuffer();
|
||||||
|
}
|
||||||
|
|
||||||
|
SubPacket subpacket = new SubPacket(OPCODE, 0xe0006868, 0xe0006868, data);
|
||||||
|
subPackets.Add(subpacket);
|
||||||
|
|
||||||
|
return subPackets;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user