暂存大量修改

This commit is contained in:
Longfeng Qin 2024-11-29 10:01:28 +08:00
parent eadf136dcb
commit 16bb43b1e9
18 changed files with 191 additions and 62 deletions

View File

@ -8,6 +8,9 @@ namespace PSO2SERVER
{ {
private byte[] data; private byte[] data;
// 获取字符串的长度
public int Length => data.Length;
// 从字符串初始化 // 从字符串初始化
public AsciiString(string value) public AsciiString(string value)
{ {
@ -23,7 +26,7 @@ namespace PSO2SERVER
// 从字节数组初始化 // 从字节数组初始化
public AsciiString(byte[] bytes) public AsciiString(byte[] bytes)
{ {
data = bytes; data = bytes ?? throw new ArgumentNullException(nameof(bytes), "字节数组不能为 null");
} }
// 获取 ASCII 字符串,去除尾部的 null 字节 // 获取 ASCII 字符串,去除尾部的 null 字节
@ -67,7 +70,59 @@ namespace PSO2SERVER
return new AsciiString(value); return new AsciiString(value);
} }
// 获取字符串的长度 // 写入固定长度 ASCII 字符串,超出部分截断,空余部分用零填充
public int Length => data.Length; public void WriteFixedLengthASCII(string str, int charCount)
{
// 确保字符串长度不超过规定的 charCount
var writeAmount = Math.Min(str.Length, charCount);
var paddingAmount = charCount - writeAmount;
byte[] byteArray = Encoding.ASCII.GetBytes(str.Substring(0, writeAmount));
// 可能存在的填充
byte[] resultArray = new byte[charCount];
Array.Copy(byteArray, resultArray, byteArray.Length);
// 用零填充剩余部分
if (paddingAmount > 0)
{
for (int i = byteArray.Length; i < charCount; i++)
{
resultArray[i] = 0;
}
}
data = resultArray;
}
// 写入固定长度的 UTF-16 字符串,超出部分截断,空余部分用零填充
public void WriteFixedLengthUtf16(string str, int charCount)
{
var writeAmount = Math.Min(str.Length, charCount);
var paddingAmount = charCount - writeAmount;
byte[] byteArray = Encoding.Unicode.GetBytes(str.Substring(0, writeAmount));
// 可能存在的填充
byte[] resultArray = new byte[charCount * 2]; // UTF-16 每个字符占 2 个字节
Array.Copy(byteArray, resultArray, byteArray.Length);
// 用零填充剩余部分
if (paddingAmount > 0)
{
for (int i = byteArray.Length; i < charCount * 2; i++)
{
resultArray[i] = 0;
}
}
data = resultArray;
}
// 重写 ToString 方法,返回字符串表示
public string GetStringRepresentation()
{
return Encoding.ASCII.GetString(data);
}
} }
} }

View File

@ -712,9 +712,8 @@ namespace PSO2SERVER
}; };
var fakePacket = new CharacterSpawnPacket(fakeChar, new PSOLocation(0f, 1f, 0f, 0f, x, y, z)) var fakePacket = new CharacterSpawnPacket(fakeChar, new PSOLocation(0f, 1f, 0f, 0f, x, y, z), false)
{ {
IsItMe = false
}; };
client.SendPacket(fakePacket); client.SendPacket(fakePacket);

View File

@ -1,6 +1,6 @@
using System; using System;
using System.IO; using System.IO;
using System.Runtime.InteropServices;
using PSO2SERVER.Protocol.Packets; using PSO2SERVER.Protocol.Packets;
namespace PSO2SERVER namespace PSO2SERVER
@ -226,5 +226,32 @@ namespace PSO2SERVER
Writer.WriteLine("\t\t" + DateTime.Now); Writer.WriteLine("\t\t" + DateTime.Now);
Writer.WriteLine("--------------------------------------------------"); Writer.WriteLine("--------------------------------------------------");
} }
// 方法:打印结构体的二进制数据
public static void WriteStructBinary(string text, object obj)
{
var byteArray = StructToByteArray(obj);
WriteHex(text, byteArray);
}
// 将结构体转换为字节数组
public static byte[] StructToByteArray(object obj)
{
int size = Marshal.SizeOf(obj);
byte[] byteArray = new byte[size];
IntPtr ptr = Marshal.AllocHGlobal(size);
try
{
Marshal.StructureToPtr(obj, ptr, false);
Marshal.Copy(ptr, byteArray, 0, size);
}
finally
{
Marshal.FreeHGlobal(ptr);
}
return byteArray;
}
} }
} }

View File

@ -68,8 +68,6 @@ namespace PSO2SERVER.Models
[Flags] [Flags]
public enum ClassTypeField : ushort public enum ClassTypeField : ushort
{ {
Unknown = 0xFF,
None = 0,
Hunter = 1 << 0, Hunter = 1 << 0,
Ranger = 1 << 1, Ranger = 1 << 1,
Force = 1 << 2, Force = 1 << 2,
@ -129,13 +127,13 @@ namespace PSO2SERVER.Models
[StructLayout(LayoutKind.Sequential)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct JobParam public unsafe struct JobParam
{ {
public ClassType mainClass; public ClassType mainClass;//1
public ClassType subClass; public ClassType subClass;//1
public ushort unk2; public ushort unk2;//2
public ClassTypeField enabledClasses; public ClassTypeField enabledClasses;//2
public ushort unk3; public ushort unk3;//2
public Entries entries; //TODO: Make this a fixed array public Entries entries; //TODO: Make this a fixed array 24 * 8
public fixed ushort unk_maxlevel[15]; public fixed ushort unk_maxlevel[15];//30
} }
public enum RunAnimation : ushort public enum RunAnimation : ushort

View File

@ -7,7 +7,7 @@ using static PSO2SERVER.Models.Character;
namespace PSO2SERVER.Models namespace PSO2SERVER.Models
{ {
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct ShortItemId public unsafe struct ShortItemId
{ {
byte ItemType; byte ItemType;
@ -15,7 +15,7 @@ namespace PSO2SERVER.Models
ushort Subid; ushort Subid;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct ItemId public unsafe struct ItemId
{ {
ushort ItemType; ushort ItemType;
@ -51,12 +51,12 @@ namespace PSO2SERVER.Models
//public PSO2ItemNone None; //public PSO2ItemNone None;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemNone public unsafe struct PSO2ItemNone
{ {
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemWeapon public unsafe struct PSO2ItemWeapon
{ {
byte flags; byte flags;
@ -75,7 +75,7 @@ namespace PSO2SERVER.Models
uint unknown6; uint unknown6;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemClothing public unsafe struct PSO2ItemClothing
{ {
ushort flags; ushort flags;
@ -85,7 +85,7 @@ namespace PSO2SERVER.Models
ushort Unk3; ushort Unk3;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemConsumable public unsafe struct PSO2ItemConsumable
{ {
ushort flags; ushort flags;
@ -93,7 +93,7 @@ namespace PSO2SERVER.Models
ushort amount; ushort amount;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemCamo public unsafe struct PSO2ItemCamo
{ {
byte unk1; byte unk1;
@ -103,7 +103,7 @@ namespace PSO2SERVER.Models
byte unk5; byte unk5;
} }
[StructLayout(LayoutKind.Sequential, Pack = 1)] [StructLayout(LayoutKind.Sequential)]
public unsafe struct PSO2ItemUnit public unsafe struct PSO2ItemUnit
{ {
byte flags; byte flags;

View File

@ -117,7 +117,7 @@ namespace PSO2SERVER.Models
NotSet = 0x0000000800000000, NotSet = 0x0000000800000000,
} }
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public unsafe struct QuestDefiniton public unsafe struct QuestDefiniton
{ {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32 - 8)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 32 - 8)]

View File

@ -35,7 +35,7 @@ namespace PSO2SERVER.Protocol.Handlers
//var setPlayerId = new PacketWriter(); //var setPlayerId = new PacketWriter();
//setPlayerId.WriteAccountHeader((uint)context._account.AccountId); //setPlayerId.WriteAccountHeader((uint)context._account.AccountId);
//context.SendPacket(0x06, 0x00, 0, setPlayerId.ToArray()); //context.SendPacket(0x06, 0x00, 0, setPlayerId.ToArray());
context.SendPacket(new SetPlayerIDPacket(context._account.AccountId)); context.SendPacket(new SetAccountIDPacket(context._account.AccountId));
// Spawn Account // Spawn Account
new CharacterSpawn().HandlePacket(context, flags, data, position, size); new CharacterSpawn().HandlePacket(context, flags, data, position, size);

View File

@ -112,11 +112,18 @@ namespace PSO2SERVER.Protocol.Handlers
if (!users.Any()) if (!users.Any())
{ {
// Check if there is an empty field // Check if there is an empty field
if (string.IsNullOrWhiteSpace(Username) || string.IsNullOrWhiteSpace(Password)) if (string.IsNullOrWhiteSpace(Username))
{ {
error = "用户名或密码为空."; error = "Username Empty.";
user = null; user = null;
} }
if (string.IsNullOrWhiteSpace(Password))
{
error = "Password Empty #1.";
user = null;
}
// Check for special characters // Check for special characters
else if (!Regex.IsMatch(Username, "^[a-zA-Z0-9 ]*$", RegexOptions.IgnoreCase)) else if (!Regex.IsMatch(Username, "^[a-zA-Z0-9 ]*$", RegexOptions.IgnoreCase))
{ {
@ -145,20 +152,21 @@ namespace PSO2SERVER.Protocol.Handlers
{ {
user = users.First(); user = users.First();
if (Password != user.Password) //TODO 方便GM测试
{ //if (Password != user.Password)
if (Password == "") //{
{ // if (Password == "")
error = "密码为空."; // {
user = null; // error = "Password Empty #2.";
} // user = null;
else // }
if (!BCrypt.Net.BCrypt.Verify(Password, user.Password)) // else
{ // if (!BCrypt.Net.BCrypt.Verify(Password, user.Password))
error = "密码错误."; // {
user = null; // error = "Wrong Password.";
} // user = null;
} // }
//}
} }
context.SendPacket(new LoginDataPacket("Server AuthList 1", error, (user == null) ? (uint)0 : (uint)user.AccountId)); context.SendPacket(new LoginDataPacket("Server AuthList 1", error, (user == null) ? (uint)0 : (uint)user.AccountId));

View File

@ -35,6 +35,8 @@ namespace PSO2SERVER.Protocol.Handlers
var looks = reader.ReadStruct<Character.LooksParam>(); var looks = reader.ReadStruct<Character.LooksParam>();
var jobs = reader.ReadStruct<Character.JobParam>(); var jobs = reader.ReadStruct<Character.JobParam>();
Logger.WriteStructBinary(info, jobs);
Logger.WriteInternal("[CHR] {0} 创建了名为 {1} 的新角色.", context._account.Username, name); Logger.WriteInternal("[CHR] {0} 创建了名为 {1} 的新角色.", context._account.Username, name);
var newCharacter = new Character var newCharacter = new Character
{ {

View File

@ -8,14 +8,20 @@ namespace PSO2SERVER.Protocol.Handlers
[PacketHandlerAttr(0x11, 0xBC)] [PacketHandlerAttr(0x11, 0xBC)]
class CharacterShipTransferCanceldRequest : PacketHandler class CharacterShipTransferCanceldRequest : PacketHandler
{ {
public uint player_id { get; set; } public struct CharacterShipTransferCanceldRequestPacket
{
public uint player_id { get; set; }
}
CharacterShipTransferCanceldRequestPacket pkt = new CharacterShipTransferCanceldRequestPacket();
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size) public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{ {
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length); var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data); Logger.WriteHex(info, data);
var reader = new PacketReader(data, position, size); var reader = new PacketReader(data, position, size);
player_id = reader.ReadUInt32(); pkt = reader.ReadStruct<CharacterShipTransferCanceldRequestPacket>();
context.SendPacket(new CharacterShipTransferCancelPacket(MoveStatus.Success));// TODO 需要补充完整 context.SendPacket(new CharacterShipTransferCancelPacket(MoveStatus.Success));// TODO 需要补充完整
} }

View File

@ -0,0 +1,31 @@
using System;
using PSO2SERVER.Models;
using PSO2SERVER.Protocol.Packets;
using static PSO2SERVER.Protocol.Handlers.CharacterNewNameRequest;
namespace PSO2SERVER.Protocol.Handlers
{
[PacketHandlerAttr(0x11, 0xDC)]
class CharacterSurvey : PacketHandler
{
public struct CharacterSurveyPacket
{
public uint choice { get; set; }
}
public override void HandlePacket(Client context, byte flags, byte[] data, uint position, uint size)
{
var info = string.Format("[<--] 接收到的数据 (hex): {0} 字节", data.Length);
Logger.WriteHex(info, data);
// 创建一个结构体实例
var packet = new CharacterSurveyPacket();
// 读取数据并填充到结构体中
var reader = new PacketReader(data, position, size);
packet.choice = reader.ReadUInt32();
context.SendPacket(new NoPayloadPacket(0x11, 0xDD));
}
}
}

View File

@ -150,9 +150,9 @@ namespace PSO2SERVER.Protocol
} }
} }
public void WriteAccountHeader(uint id) public void WriteAccountHeader(uint AccountId)
{ {
Write(id); Write(AccountId);
Write((uint) 0); Write((uint) 0);
Write((ushort)ObjectType.Player); Write((ushort)ObjectType.Player);
Write((ushort) 0); Write((ushort) 0);

View File

@ -6,13 +6,13 @@ using System.Text;
namespace PSO2SERVER.Protocol.Packets namespace PSO2SERVER.Protocol.Packets
{ {
public class SetPlayerIDPacket : Packet public class SetAccountIDPacket : Packet
{ {
private readonly int _PlayerId; private readonly int AccountId;
public SetPlayerIDPacket(int PlayerId) public SetAccountIDPacket(int AccountId)
{ {
_PlayerId = PlayerId; this.AccountId = AccountId;
} }
#region implemented abstract members of Packet #region implemented abstract members of Packet
@ -20,7 +20,7 @@ namespace PSO2SERVER.Protocol.Packets
public override byte[] Build() public override byte[] Build()
{ {
var pkt = new PacketWriter(); var pkt = new PacketWriter();
pkt.WriteAccountHeader((uint)_PlayerId); pkt.WriteAccountHeader((uint)AccountId);
return pkt.ToArray(); return pkt.ToArray();
} }

View File

@ -1,4 +1,6 @@
using PSO2SERVER.Models; using PSO2SERVER.Models;
using System.Runtime.InteropServices;
using static PSO2SERVER.Protocol.Packets.CharacterSpawnPacket;
namespace PSO2SERVER.Protocol.Packets namespace PSO2SERVER.Protocol.Packets
{ {
@ -50,19 +52,23 @@ namespace PSO2SERVER.Protocol.Packets
writer.Write((uint)602); // 0x48 writer.Write((uint)602); // 0x48
writer.Write((uint)1); // 0x4C writer.Write((uint)1); // 0x4C
writer.Write((uint)53); // 0x50 writer.Write((uint)53); // 0x50
writer.Write((uint)0); // 0x54 writer.Write((uint)100); // 0x54
writer.Write((uint)(IsItMe ? 47 : 39)); // 0x58 writer.Write((uint)(IsItMe ? CharacterSpawnType.Myself : CharacterSpawnType.Other)); // 0x58
writer.Write((ushort)559); // 0x5C writer.Write((ushort)559); // 0x5C
writer.Write((ushort)306); // 0x5E writer.Write((ushort)306); // 0x5E
writer.Write((uint)_character.Account.AccountId); // player ID copy
writer.Write((uint)0); // "char array ugggghhhhh" according to PolarisLegacy // Character
writer.Write((uint)_character.AccountID); // player ID copy
writer.Write((uint)_character.CharacterID); // "char array ugggghhhhh" according to PolarisLegacy
writer.Write((uint)0); // "voiceParam_unknown4" writer.Write((uint)0); // "voiceParam_unknown4"
writer.Write((uint)0); // "voiceParam_unknown8" writer.Write((uint)0); // "voiceParam_unknown8"
writer.WriteFixedLengthUtf16(_character.Name, 16); writer.WriteFixedLengthUtf16(_character.Name, 16);
writer.Write((uint)0); // 0x90 writer.Write((uint)0); // 0x90
writer.WriteStruct(_character.Looks); writer.WriteStruct(_character.Looks);
writer.WriteStruct(_character.Jobs); writer.WriteStruct(_character.Jobs);
writer.WriteFixedLengthUtf16("", 32); // title? writer.WriteFixedLengthUtf16("", 32); // title?
writer.Write((uint)0); // 0x204 writer.Write((uint)0); // 0x204
writer.Write((uint)0); // gmflag? writer.Write((uint)0); // gmflag?
writer.WriteFixedLengthUtf16(_character.Account.Nickname, 16); // Nickname, maybe not 16 chars? writer.WriteFixedLengthUtf16(_character.Account.Nickname, 16); // Nickname, maybe not 16 chars?

View File

@ -63,7 +63,7 @@ namespace PSO2SERVER.Protocol.Packets
} }
//Size: 308 bytes, confirmed in unpacker //Size: 308 bytes, confirmed in unpacker
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi, Pack = 1)] [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public unsafe struct QuestDifficulty public unsafe struct QuestDifficulty
{ {
[MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)] [MarshalAs(UnmanagedType.ByValTStr, SizeConst = 24)]

View File

@ -54,8 +54,6 @@ namespace PSO2SERVER.Protocol.Packets
writer.Write((uint)ch.AccountID); writer.Write((uint)ch.AccountID);
writer.Write((uint)ch.CharacterID); writer.Write((uint)ch.CharacterID);
//for (var i = 0; i < 0x10; i++)
// writer.Write((byte)0);
writer.Write(ch.Unk1); writer.Write(ch.Unk1);
writer.Write(ch.VoiceType); writer.Write(ch.VoiceType);
writer.Write(ch.Unk2); writer.Write(ch.Unk2);

View File

@ -176,6 +176,7 @@
<Compile Include="Object\ObjectManager.cs" /> <Compile Include="Object\ObjectManager.cs" />
<Compile Include="Protocol\Handlers\0B-QuestHandler\0B-20-AcceptQuest.cs" /> <Compile Include="Protocol\Handlers\0B-QuestHandler\0B-20-AcceptQuest.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-90-CharacterUndeletionRequest.cs" /> <Compile Include="Protocol\Handlers\11-ClientHandler\11-90-CharacterUndeletionRequest.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-DC-CharacterSurvey.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-EB-NicknameCheckRequest - 复制.cs" /> <Compile Include="Protocol\Handlers\11-ClientHandler\11-EB-NicknameCheckRequest - 复制.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-52-CreateCharacterInviteNickname.cs" /> <Compile Include="Protocol\Handlers\11-ClientHandler\11-52-CreateCharacterInviteNickname.cs" />
<Compile Include="Protocol\Handlers\11-ClientHandler\11-C7-CharacterShipInfoRequest.cs" /> <Compile Include="Protocol\Handlers\11-ClientHandler\11-C7-CharacterShipInfoRequest.cs" />
@ -273,7 +274,7 @@
<Compile Include="Protocol\Packets\04-ObjectRelatedPacket\04-81-ActionUpdateServerPacket.cs" /> <Compile Include="Protocol\Packets\04-ObjectRelatedPacket\04-81-ActionUpdateServerPacket.cs" />
<Compile Include="Protocol\Packets\04-ObjectRelatedPacket\04-3B-DespawnPlayerPacket.cs" /> <Compile Include="Protocol\Packets\04-ObjectRelatedPacket\04-3B-DespawnPlayerPacket.cs" />
<Compile Include="Protocol\Packets\06-PlayerStatusPacket\06-05-GainedEXPPacket.cs" /> <Compile Include="Protocol\Packets\06-PlayerStatusPacket\06-05-GainedEXPPacket.cs" />
<Compile Include="Protocol\Packets\06-PlayerStatusPacket\06-00-SetPlayerIDPacket.cs" /> <Compile Include="Protocol\Packets\06-PlayerStatusPacket\06-00-SetAccountIDPacket.cs" />
<Compile Include="Protocol\Packets\08-SpawnPacket\08-09-EventSpawnPacket.cs" /> <Compile Include="Protocol\Packets\08-SpawnPacket\08-09-EventSpawnPacket.cs" />
<Compile Include="Protocol\Packets\08-SpawnPacket\08-0D-EnemySpawnPacket.cs" /> <Compile Include="Protocol\Packets\08-SpawnPacket\08-0D-EnemySpawnPacket.cs" />
<Compile Include="Protocol\Packets\08-SpawnPacket\08-05-TransporterSpawnPacket.cs" /> <Compile Include="Protocol\Packets\08-SpawnPacket\08-05-TransporterSpawnPacket.cs" />

View File

@ -140,10 +140,8 @@ namespace PSO2SERVER.Zone
c.CurrentZone.RemoveClient(c); c.CurrentZone.RemoveClient(c);
} }
//var setPlayerId = new PacketWriter(); // 设置客户端的账户ID
//setPlayerId.WriteAccountHeader((uint)c._account.AccountId); c.SendPacket(new SetAccountIDPacket(c._account.AccountId));
//c.SendPacket(0x06, 0x00, 0, setPlayerId.ToArray());
c.SendPacket(new SetPlayerIDPacket(c._account.AccountId));
// Spawn Character // Spawn Character
c.SendPacket(new CharacterSpawnPacket(c.Character, location)); c.SendPacket(new CharacterSpawnPacket(c.Character, location));