修正部分数据包结构
This commit is contained in:
parent
6f9d732941
commit
8e6f344974
@ -110,11 +110,42 @@ namespace PSO2SERVER.Database
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public string Unk4 { get; set; }
|
public byte[] Unk4 { get; set; } = new byte[152];
|
||||||
|
|
||||||
public virtual Account Account { get; set; }
|
public virtual Account Account { get; set; }
|
||||||
|
|
||||||
public byte[] fulldata { get; set; }
|
public byte[] fulldata { get; set; }
|
||||||
|
|
||||||
|
public byte[] BuildCharacterByteArray()
|
||||||
|
{
|
||||||
|
PacketWriter writer = new PacketWriter();
|
||||||
|
|
||||||
|
// 序列化字段:CharacterID, AccountID, Unk1, VoiceType, Unk2, VoicePitch
|
||||||
|
writer.Write((uint)CharacterID);
|
||||||
|
writer.Write((uint)AccountID);
|
||||||
|
writer.Write((uint)Unk1);
|
||||||
|
writer.Write((uint)VoiceType);
|
||||||
|
writer.Write((ushort)Unk2);
|
||||||
|
writer.Write(VoicePitch);
|
||||||
|
|
||||||
|
// 序列化 Name (假设固定长度字符串16个字节,UTF-16 编码)
|
||||||
|
writer.WriteFixedLengthUtf16(Name, 0x10);
|
||||||
|
|
||||||
|
// 序列化 Looks
|
||||||
|
writer.WriteStruct(Looks);
|
||||||
|
|
||||||
|
// 序列化 Unk3
|
||||||
|
writer.Write((uint)Unk3);
|
||||||
|
|
||||||
|
// 序列化 Jobs
|
||||||
|
writer.WriteStruct(Jobs);
|
||||||
|
|
||||||
|
// 序列化 Unk4
|
||||||
|
writer.Write(Unk4);
|
||||||
|
|
||||||
|
// 最后返回字节流
|
||||||
|
return writer.ToArray();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class NPC
|
public class NPC
|
||||||
|
@ -9,26 +9,26 @@ namespace PSO2SERVER.Models
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct ShortItemId
|
public unsafe struct ShortItemId
|
||||||
{
|
{
|
||||||
byte ItemType;
|
public byte ItemType;
|
||||||
byte Id;
|
public byte Id;
|
||||||
ushort Subid;
|
public ushort Subid;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct ItemId
|
public unsafe struct ItemId
|
||||||
{
|
{
|
||||||
ushort ItemType;
|
public ushort ItemType;
|
||||||
ushort Id;
|
public ushort Id;
|
||||||
ushort Unk3;
|
public ushort Unk3;
|
||||||
ushort Subid;
|
public ushort Subid;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public struct PSO2Items
|
public struct PSO2Items
|
||||||
{
|
{
|
||||||
long guid;
|
public ulong uuid;
|
||||||
ItemId id;
|
public ItemId id;
|
||||||
Items data;
|
public Items data;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Explicit)]
|
[StructLayout(LayoutKind.Explicit)]
|
||||||
@ -58,73 +58,73 @@ namespace PSO2SERVER.Models
|
|||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct PSO2ItemWeapon
|
public unsafe struct PSO2ItemWeapon
|
||||||
{
|
{
|
||||||
byte flags;
|
public byte flags;
|
||||||
byte element;
|
public byte element;
|
||||||
byte force;
|
public byte force;
|
||||||
byte grind;
|
public byte grind;
|
||||||
byte grindPercent;
|
public byte grindPercent;
|
||||||
byte unknown1;
|
public byte unknown1;
|
||||||
short unknown2;
|
public short unknown2;
|
||||||
fixed short affixes[8];
|
public fixed short affixes[8];
|
||||||
uint potential;
|
public uint potential;
|
||||||
byte extend;
|
public byte extend;
|
||||||
byte unknown3;
|
public byte unknown3;
|
||||||
ushort unknown4;
|
public ushort unknown4;
|
||||||
uint unknown5;
|
public uint unknown5;
|
||||||
uint unknown6;
|
public uint unknown6;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct PSO2ItemClothing
|
public unsafe struct PSO2ItemClothing
|
||||||
{
|
{
|
||||||
ushort flags;
|
public ushort flags;
|
||||||
fixed byte unk1[0x14];
|
public fixed byte unk1[0x14];
|
||||||
public HSVColor Color;
|
public HSVColor Color;
|
||||||
fixed byte unk2[0xA];
|
public fixed byte unk2[0xA];
|
||||||
ushort Unk3;
|
public ushort Unk3;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct PSO2ItemConsumable
|
public unsafe struct PSO2ItemConsumable
|
||||||
{
|
{
|
||||||
ushort flags;
|
public ushort flags;
|
||||||
fixed byte unk1[0x24];
|
public fixed byte unk1[0x24];
|
||||||
ushort amount;
|
public ushort amount;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct PSO2ItemCamo
|
public unsafe struct PSO2ItemCamo
|
||||||
{
|
{
|
||||||
byte unk1;
|
public byte unk1;
|
||||||
byte unk2;
|
public byte unk2;
|
||||||
byte unk3;
|
public byte unk3;
|
||||||
fixed byte unk4[0x24];
|
public fixed byte unk4[0x24];
|
||||||
byte unk5;
|
public byte unk5;
|
||||||
}
|
}
|
||||||
|
|
||||||
[StructLayout(LayoutKind.Sequential)]
|
[StructLayout(LayoutKind.Sequential)]
|
||||||
public unsafe struct PSO2ItemUnit
|
public unsafe struct PSO2ItemUnit
|
||||||
{
|
{
|
||||||
byte flags;
|
public byte flags;
|
||||||
byte EnhLevel;
|
public byte EnhLevel;
|
||||||
byte EnhPercent;
|
public byte EnhPercent;
|
||||||
byte Unk1;
|
public byte Unk1;
|
||||||
|
|
||||||
// 使用 fixed 数组来存储附加信息
|
// 使用 fixed 数组来存储附加信息
|
||||||
fixed ushort Affixes[8]; // Item affix IDs (0 to 4095)
|
public fixed ushort Affixes[8]; // Item affix IDs (0 to 4095)
|
||||||
|
|
||||||
fixed byte unk4[0x7];
|
public fixed byte unk4[0x7];
|
||||||
uint Potential;
|
public uint Potential;
|
||||||
|
|
||||||
// 使用 fixed 数组来存储未知字段
|
// 使用 fixed 数组来存储未知字段
|
||||||
fixed byte Unk2[4];
|
public fixed byte Unk2[4];
|
||||||
|
|
||||||
uint Unk3;
|
public uint Unk3;
|
||||||
ushort Unk4;
|
public ushort Unk4;
|
||||||
ushort Unk5;
|
public ushort Unk5;
|
||||||
|
|
||||||
// 提供访问固定数组的属性
|
// 提供访问固定数组的属性
|
||||||
Span<ushort> AffixSpan
|
public Span<ushort> AffixSpan
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
@ -148,8 +148,8 @@ namespace PSO2SERVER.Models
|
|||||||
public TimeSpan EndDate; // 对应 Rust 的 Duration
|
public TimeSpan EndDate; // 对应 Rust 的 Duration
|
||||||
|
|
||||||
/// Campaign title (固定长度 0x3E).
|
/// Campaign title (固定长度 0x3E).
|
||||||
private const int TitleLength = 0x3E;
|
public const int TitleLength = 0x3E;
|
||||||
private byte[] titleBytes;
|
public byte[] titleBytes;
|
||||||
|
|
||||||
public string Title
|
public string Title
|
||||||
{
|
{
|
||||||
@ -163,8 +163,8 @@ namespace PSO2SERVER.Models
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Campaign conditions (固定长度 0x102).
|
/// Campaign conditions (固定长度 0x102).
|
||||||
private const int ConditionsLength = 0x102;
|
public const int ConditionsLength = 0x102;
|
||||||
private byte[] conditionsBytes;
|
public byte[] conditionsBytes;
|
||||||
|
|
||||||
public string Conditions
|
public string Conditions
|
||||||
{
|
{
|
||||||
@ -243,8 +243,8 @@ namespace PSO2SERVER.Models
|
|||||||
|
|
||||||
MemoryStream stream;
|
MemoryStream stream;
|
||||||
//TODO
|
//TODO
|
||||||
ItemTypes type = ItemTypes.Consumable;
|
public ItemTypes type = ItemTypes.Consumable;
|
||||||
byte[] data = new byte[Size];
|
public byte[] data = new byte[Size];
|
||||||
|
|
||||||
public override string ToString()
|
public override string ToString()
|
||||||
{
|
{
|
||||||
|
100
Server/Models/Time.cs
Normal file
100
Server/Models/Time.cs
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
using System.Threading.Tasks;
|
||||||
|
|
||||||
|
namespace PSO2SERVER.Models
|
||||||
|
{
|
||||||
|
public struct Duration : IEquatable<Duration>, IComparable<Duration>
|
||||||
|
{
|
||||||
|
// The number of seconds in the duration
|
||||||
|
public long Seconds { get; }
|
||||||
|
|
||||||
|
// The number of nanoseconds, should always be between 0 and 999,999,999
|
||||||
|
public int Nanoseconds { get; }
|
||||||
|
|
||||||
|
// Constructor to initialize a Duration with seconds and nanoseconds
|
||||||
|
public Duration(long seconds, int nanoseconds)
|
||||||
|
{
|
||||||
|
if (nanoseconds < 0 || nanoseconds >= 1_000_000_000)
|
||||||
|
{
|
||||||
|
throw new ArgumentOutOfRangeException(nameof(nanoseconds), "Nanoseconds must be between 0 and 999,999,999.");
|
||||||
|
}
|
||||||
|
|
||||||
|
Seconds = seconds;
|
||||||
|
Nanoseconds = nanoseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// A default zero-length duration
|
||||||
|
public static Duration Zero => new Duration(0, 0);
|
||||||
|
|
||||||
|
// Adds two durations together
|
||||||
|
public static Duration operator +(Duration left, Duration right)
|
||||||
|
{
|
||||||
|
long totalSeconds = left.Seconds + right.Seconds;
|
||||||
|
int totalNanoseconds = left.Nanoseconds + right.Nanoseconds;
|
||||||
|
|
||||||
|
// Handle carry over for nanoseconds
|
||||||
|
if (totalNanoseconds >= 1_000_000_000)
|
||||||
|
{
|
||||||
|
totalSeconds++;
|
||||||
|
totalNanoseconds -= 1_000_000_000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Duration(totalSeconds, totalNanoseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Subtracts one duration from another
|
||||||
|
public static Duration operator -(Duration left, Duration right)
|
||||||
|
{
|
||||||
|
long totalSeconds = left.Seconds - right.Seconds;
|
||||||
|
int totalNanoseconds = left.Nanoseconds - right.Nanoseconds;
|
||||||
|
|
||||||
|
// Handle borrow for nanoseconds
|
||||||
|
if (totalNanoseconds < 0)
|
||||||
|
{
|
||||||
|
totalSeconds--;
|
||||||
|
totalNanoseconds += 1_000_000_000;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Duration(totalSeconds, totalNanoseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Compare two durations
|
||||||
|
public int CompareTo(Duration other)
|
||||||
|
{
|
||||||
|
if (Seconds < other.Seconds) return -1;
|
||||||
|
if (Seconds > other.Seconds) return 1;
|
||||||
|
|
||||||
|
return Nanoseconds.CompareTo(other.Nanoseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check if two durations are equal
|
||||||
|
public bool Equals(Duration other)
|
||||||
|
{
|
||||||
|
return Seconds == other.Seconds && Nanoseconds == other.Nanoseconds;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Override ToString() for custom string representation
|
||||||
|
public override string ToString()
|
||||||
|
{
|
||||||
|
return $"{Seconds}s {Nanoseconds}ns";
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static method to create a Duration from milliseconds
|
||||||
|
public static Duration FromMilliseconds(long milliseconds)
|
||||||
|
{
|
||||||
|
long seconds = milliseconds / 1000;
|
||||||
|
int nanoseconds = (int)((milliseconds % 1000) * 1_000_000);
|
||||||
|
return new Duration(seconds, nanoseconds);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Static method to create a Duration from seconds and nanoseconds
|
||||||
|
public static Duration FromSeconds(long seconds, int nanoseconds)
|
||||||
|
{
|
||||||
|
return new Duration(seconds, nanoseconds);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -15,56 +15,53 @@ namespace PSO2SERVER.Protocol.Handlers
|
|||||||
{
|
{
|
||||||
#region implemented abstract members of PacketHandler
|
#region implemented abstract members of PacketHandler
|
||||||
|
|
||||||
public struct CharacterCreatePacket
|
public uint CharacterID { get; set; }
|
||||||
{
|
public uint AccountID { get; set; }
|
||||||
public int CharacterID;
|
public uint Unk1 { get; set; }
|
||||||
public int AccountID;
|
public uint VoiceType { get; set; }
|
||||||
public int Unk1;
|
public ushort Unk2 { get; set; }
|
||||||
public int VoiceType;
|
public short VoicePitch { get; set; }
|
||||||
public short Unk2;
|
public string Name { get; set; }
|
||||||
public short VoicePitch;
|
public LooksParam Looks { get; set; }
|
||||||
public string Name;
|
public uint Unk3 { get; set; }
|
||||||
public int Unk3;
|
public JobParam Jobs { get; set; }
|
||||||
public LooksParam Looks;
|
public byte[] unk4 { get; set; } = new byte[152]; // 152 字节的字节数组
|
||||||
public JobParam Jobs;
|
|
||||||
public string unk4; // 148 字节的字节数组
|
|
||||||
}
|
|
||||||
|
|
||||||
private CharacterCreatePacket packet = new CharacterCreatePacket();
|
|
||||||
|
|
||||||
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)
|
||||||
{
|
{
|
||||||
if (context._account == null)
|
if (context._account == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var reader = new PacketReader(data, position, 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);
|
||||||
|
|
||||||
packet.CharacterID = reader.ReadInt32();
|
var reader = new PacketReader(data, position, size);
|
||||||
packet.AccountID = reader.ReadInt32();
|
CharacterID = reader.ReadUInt32();
|
||||||
packet.Unk1 = reader.ReadInt32();//Unk1
|
AccountID = reader.ReadUInt32();
|
||||||
packet.VoiceType = reader.ReadInt32(); // VoiceType
|
Unk1 = reader.ReadUInt32();//Unk1
|
||||||
packet.Unk2 = reader.ReadInt16(); // 5 unknown bytes
|
VoiceType = reader.ReadUInt32(); // VoiceType
|
||||||
packet.VoicePitch = reader.ReadInt16(); // VoiceData
|
Unk2 = reader.ReadUInt16(); // 5 unknown bytes
|
||||||
packet.Name = reader.ReadFixedLengthUtf16(16);
|
VoicePitch = reader.ReadInt16(); // VoiceData
|
||||||
packet.Unk3 = reader.ReadInt32();
|
Name = reader.ReadFixedLengthUtf16(16);
|
||||||
packet.Looks = reader.ReadStruct<LooksParam>();
|
Looks = reader.ReadStruct<LooksParam>();
|
||||||
packet.Jobs = reader.ReadStruct<JobParam>();
|
Unk3 = reader.ReadUInt32();
|
||||||
packet.unk4 = reader.ReadFixedLengthUtf16(76);
|
Jobs = reader.ReadStruct<JobParam>();
|
||||||
|
unk4 = reader.ReadBytes(unk4.Length);
|
||||||
|
|
||||||
var newCharacter = new Character
|
var newCharacter = new Character
|
||||||
{
|
{
|
||||||
CharacterID = 0,
|
CharacterID = 0,
|
||||||
AccountID = context._account.AccountId,
|
AccountID = context._account.AccountId,
|
||||||
Unk1 = packet.Unk1,
|
Unk1 = (int)Unk1,
|
||||||
VoiceType = packet.VoiceType,
|
VoiceType = (int)VoiceType,
|
||||||
Unk2 = packet.Unk2,
|
Unk2 = (short)Unk2,
|
||||||
VoicePitch = packet.VoicePitch,
|
VoicePitch = VoicePitch,
|
||||||
Name = packet.Name,
|
Name = Name,
|
||||||
Unk3 = packet.Unk3,
|
Looks = Looks,
|
||||||
Jobs = packet.Jobs,
|
Unk3 = (int)Unk3,
|
||||||
Looks = packet.Looks,
|
Jobs = Jobs,
|
||||||
|
Unk4 = unk4,
|
||||||
|
|
||||||
Account = context._account,
|
Account = context._account,
|
||||||
fulldata = data
|
fulldata = data
|
||||||
};
|
};
|
||||||
|
@ -42,7 +42,7 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
public byte unk9 { get; set; }
|
public byte unk9 { get; set; }
|
||||||
public ushort unk10 { get; set; }
|
public ushort unk10 { get; set; }
|
||||||
public Character _character { get; set; }
|
public Character _character { get; set; }
|
||||||
public uint unk11 { get; set; }
|
//public uint unk11 { get; set; }
|
||||||
/// Set to `1` if the player is a GM.
|
/// Set to `1` if the player is a GM.
|
||||||
public uint gm_flag { get; set; }
|
public uint gm_flag { get; set; }
|
||||||
public string nickname { get; set; }
|
public string nickname { get; set; }
|
||||||
@ -86,18 +86,8 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
pkt.Write(unk9);
|
pkt.Write(unk9);
|
||||||
pkt.Write(unk10);
|
pkt.Write(unk10);
|
||||||
// Character data.
|
// Character data.
|
||||||
pkt.Write((uint)_character.AccountID);
|
pkt.Write(_character.BuildCharacterByteArray());
|
||||||
pkt.Write((uint)_character.CharacterID);
|
//pkt.Write(unk11);
|
||||||
pkt.Write((uint)_character.Unk1);//4
|
|
||||||
pkt.Write((uint)_character.VoiceType);//4
|
|
||||||
pkt.Write((ushort)_character.Unk2);//2
|
|
||||||
pkt.Write(_character.VoicePitch);//2
|
|
||||||
pkt.WriteFixedLengthUtf16(_character.Name, 0x10);
|
|
||||||
pkt.Write((uint)_character.Unk3); // 0x90
|
|
||||||
pkt.WriteStruct(_character.Looks);
|
|
||||||
pkt.WriteStruct(_character.Jobs);
|
|
||||||
pkt.WriteBytes(0, 148);
|
|
||||||
pkt.Write(unk11);
|
|
||||||
pkt.Write(gm_flag);
|
pkt.Write(gm_flag);
|
||||||
pkt.WriteFixedLengthUtf16(_character.Account.Nickname, 0x10);
|
pkt.WriteFixedLengthUtf16(_character.Account.Nickname, 0x10);
|
||||||
for (var i = 0; i < 0x60; i++)
|
for (var i = 0; i < 0x60; i++)
|
||||||
|
@ -12,6 +12,29 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
{
|
{
|
||||||
public class CharacterListPacket : Packet
|
public class CharacterListPacket : Packet
|
||||||
{
|
{
|
||||||
|
// Available characters
|
||||||
|
public List<Character> Characters { get; set; } = new List<Character>();
|
||||||
|
|
||||||
|
// Equipped items (List of 10 Items for each character)
|
||||||
|
public List<PSO2Items[]> EquippedItems { get; set; } = new List<PSO2Items[]>();
|
||||||
|
|
||||||
|
// Character play times (30 times)
|
||||||
|
public uint[] PlayTimes { get; set; } = new uint[30];
|
||||||
|
|
||||||
|
// Character deletion flags (flag, deletion timestamp) (30 pairs of (u32, u32))
|
||||||
|
public (uint flag, uint timestamp)[] DeletionFlags { get; set; } = new (uint, uint)[30];
|
||||||
|
|
||||||
|
// Character ship transfer flags (30 pairs of (u32, u32))
|
||||||
|
public (uint flag, uint timestamp)[] TransferFlags { get; set; } = new (uint, uint)[30];
|
||||||
|
|
||||||
|
// Account accessory flag (unknown)
|
||||||
|
public ushort AccountAccessory { get; set; }
|
||||||
|
|
||||||
|
// Login survey flag
|
||||||
|
public uint LoginSurvey { get; set; }
|
||||||
|
|
||||||
|
// Ad flag
|
||||||
|
public uint Ad { get; set; }
|
||||||
|
|
||||||
// Ninji note: This packet may be followed by extra data,
|
// Ninji note: This packet may be followed by extra data,
|
||||||
// after a fixed-length array of character data structures.
|
// after a fixed-length array of character data structures.
|
||||||
@ -37,8 +60,6 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
|
|
||||||
public override byte[] Build()
|
public override byte[] Build()
|
||||||
{
|
{
|
||||||
var writer = new PacketWriter();
|
|
||||||
|
|
||||||
using (var db = new ServerEf())
|
using (var db = new ServerEf())
|
||||||
{
|
{
|
||||||
var chars = db.Characters
|
var chars = db.Characters
|
||||||
@ -46,41 +67,51 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
.OrderBy(o => o.CharacterID) // TODO: 按照最后游玩的角色排序
|
.OrderBy(o => o.CharacterID) // TODO: 按照最后游玩的角色排序
|
||||||
.Select(s => s);
|
.Select(s => s);
|
||||||
|
|
||||||
writer.Write((uint)chars.Count()); // 写入玩家数量
|
|
||||||
|
|
||||||
writer.Write((uint)0);
|
|
||||||
|
|
||||||
foreach (var ch in chars)
|
foreach (var ch in chars)
|
||||||
{
|
{
|
||||||
//JobParam jobParam = v;
|
Characters.Add(ch);
|
||||||
//jobParam.mainClass = ClassType.Luster;
|
|
||||||
//jobParam.subClass = ClassType.Phantom;
|
// 创建一个 Consumable 类型的物品
|
||||||
//jobParam.entries.Luster.level = 100;
|
PSO2ItemConsumable consumableItem = new PSO2ItemConsumable
|
||||||
|
{
|
||||||
|
amount = 10,
|
||||||
|
};
|
||||||
|
|
||||||
|
PSO2Items[] items = new PSO2Items[10];
|
||||||
|
|
||||||
|
for (var i = 0; i < 10; i++)
|
||||||
|
{
|
||||||
|
items[i] = new PSO2Items
|
||||||
|
{
|
||||||
|
uuid = (ulong)i,
|
||||||
|
id = new ItemId
|
||||||
|
{
|
||||||
|
ItemType = 3,
|
||||||
|
Id = 1,
|
||||||
|
Subid = 0,
|
||||||
|
},
|
||||||
|
data = new Items { Consumable = consumableItem }
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
EquippedItems.Add(items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
var writer = new PacketWriter();
|
||||||
|
|
||||||
|
writer.Write((uint)Characters.Count()); // 写入玩家数量
|
||||||
|
|
||||||
writer.Write((uint)0);
|
writer.Write((uint)0);
|
||||||
|
|
||||||
writer.Write((uint)ch.CharacterID);//4
|
foreach (var ch in Characters)
|
||||||
writer.Write((uint)ch.AccountID);//4
|
{
|
||||||
writer.Write((uint)ch.Unk1);//4
|
writer.Write((uint)0);
|
||||||
writer.Write((uint)ch.VoiceType);//4
|
|
||||||
writer.Write((ushort)ch.Unk2);//2
|
|
||||||
writer.Write(ch.VoicePitch);//2
|
|
||||||
writer.WriteFixedLengthUtf16(ch.Name, 16);
|
|
||||||
//Logger.WriteInternal("[CHR] 新增名为 {0} 的新角色.", ch.Name);
|
|
||||||
writer.Write((uint)ch.Unk3);
|
|
||||||
writer.WriteStruct(ch.Looks);
|
|
||||||
writer.WriteStruct(ch.Jobs);
|
|
||||||
writer.WriteBytes(0, 148);
|
|
||||||
|
|
||||||
}
|
writer.Write(ch.BuildCharacterByteArray());//4
|
||||||
//for (var i = 0; i < 640; i++)
|
|
||||||
// writer.Write((byte)1);
|
|
||||||
|
|
||||||
//for (var i = 0; i < 30; i++)
|
|
||||||
// writer.Write((uint)1);
|
|
||||||
|
|
||||||
//writer.Write(new byte[240]);
|
|
||||||
//writer.Write(new byte[240]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return writer.ToArray();
|
return writer.ToArray();
|
||||||
|
@ -0,0 +1,43 @@
|
|||||||
|
using PSO2SERVER.Models;
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using System.Linq;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace PSO2SERVER.Protocol.Packets
|
||||||
|
{
|
||||||
|
public class SendSystemMessagePacket : Packet
|
||||||
|
{
|
||||||
|
public string _msg { get; set; }
|
||||||
|
public uint unk1 { get; set; }
|
||||||
|
public uint unk2 { get; set; }
|
||||||
|
public uint unk3 { get; set; }
|
||||||
|
|
||||||
|
public SendSystemMessagePacket(string msg, uint unk1, uint unk2, uint unk3)
|
||||||
|
{
|
||||||
|
_msg = msg;
|
||||||
|
this.unk1 = 0x00002196;
|
||||||
|
this.unk2 = unk2;
|
||||||
|
this.unk3 = unk3;
|
||||||
|
}
|
||||||
|
|
||||||
|
#region implemented abstract members of Packet
|
||||||
|
|
||||||
|
public override byte[] Build()
|
||||||
|
{
|
||||||
|
var pkt = new PacketWriter();
|
||||||
|
pkt.WriteUtf16(_msg, 0x2126, 0xB0);
|
||||||
|
pkt.Write(unk1);
|
||||||
|
pkt.Write(unk2);
|
||||||
|
pkt.Write(unk3);
|
||||||
|
return pkt.ToArray();
|
||||||
|
}
|
||||||
|
|
||||||
|
public override PacketHeader GetHeader()
|
||||||
|
{
|
||||||
|
return new PacketHeader(0x19, 0x08, PacketFlags.PACKED);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
}
|
||||||
|
}
|
@ -8,9 +8,25 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
{
|
{
|
||||||
public class SetLobbyEventPacket : Packet
|
public class SetLobbyEventPacket : Packet
|
||||||
{
|
{
|
||||||
|
/// Event string ID.
|
||||||
|
public string event_name { get; set; } //Ascii
|
||||||
|
/// Voice line string ID.
|
||||||
|
public string voice_line { get; set; } //Ascii
|
||||||
|
/// Event start timestamp.
|
||||||
|
public Duration start_time { get; set; }
|
||||||
|
/// Event end timestamp.
|
||||||
|
public Duration end_time { get; set; }
|
||||||
|
public uint repeat_secs { get; set; }
|
||||||
|
public ulong unk4 { get; set; }
|
||||||
|
|
||||||
public SetLobbyEventPacket()
|
public SetLobbyEventPacket(string eventname, string voiceline, Duration starttime, Duration endtime, uint repeatsecs, ulong unk4)
|
||||||
{
|
{
|
||||||
|
this.event_name = eventname;
|
||||||
|
this.voice_line = voiceline;
|
||||||
|
this.start_time = starttime;
|
||||||
|
this.end_time = endtime;
|
||||||
|
this.repeat_secs = repeatsecs;
|
||||||
|
this.unk4 = unk4;
|
||||||
}
|
}
|
||||||
|
|
||||||
#region implemented abstract members of Packet
|
#region implemented abstract members of Packet
|
||||||
@ -18,12 +34,18 @@ namespace PSO2SERVER.Protocol.Packets
|
|||||||
public override byte[] Build()
|
public override byte[] Build()
|
||||||
{
|
{
|
||||||
var pkt = new PacketWriter();
|
var pkt = new PacketWriter();
|
||||||
|
pkt.WriteAscii(event_name, 0xA6E4, 0xFB);
|
||||||
|
pkt.WriteAscii(voice_line, 0xA6E4, 0xFB);
|
||||||
|
pkt.WriteStruct(start_time);
|
||||||
|
pkt.WriteStruct(end_time);
|
||||||
|
pkt.Write(repeat_secs);
|
||||||
|
pkt.Write(unk4);
|
||||||
return pkt.ToArray();
|
return pkt.ToArray();
|
||||||
}
|
}
|
||||||
|
|
||||||
public override PacketHeader GetHeader()
|
public override PacketHeader GetHeader()
|
||||||
{
|
{
|
||||||
return new PacketHeader(0x19, 0x09, PacketFlags.None);
|
return new PacketHeader(0x19, 0x09, PacketFlags.PACKED);
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
@ -177,6 +177,7 @@
|
|||||||
<Compile Include="Models\PSOPalette.cs" />
|
<Compile Include="Models\PSOPalette.cs" />
|
||||||
<Compile Include="Models\Quest.cs" />
|
<Compile Include="Models\Quest.cs" />
|
||||||
<Compile Include="Models\RevealedRegions.cs" />
|
<Compile Include="Models\RevealedRegions.cs" />
|
||||||
|
<Compile Include="Models\Time.cs" />
|
||||||
<Compile Include="Network\PortChecker.cs" />
|
<Compile Include="Network\PortChecker.cs" />
|
||||||
<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" />
|
||||||
@ -249,6 +250,7 @@
|
|||||||
<Compile Include="Protocol\Handlers\4D-ClassicMissionPassHandler\4D-02-MissionPassRequest.cs" />
|
<Compile Include="Protocol\Handlers\4D-ClassicMissionPassHandler\4D-02-MissionPassRequest.cs" />
|
||||||
<Compile Include="Protocol\Handlers\4D-ClassicMissionPassHandler\4D-00-MissionPassInfoRequest.cs" />
|
<Compile Include="Protocol\Handlers\4D-ClassicMissionPassHandler\4D-00-MissionPassInfoRequest.cs" />
|
||||||
<Compile Include="Protocol\Packets\0B-QuestPacket\0B-1B-QuestCategoryStopperPacket.cs" />
|
<Compile Include="Protocol\Packets\0B-QuestPacket\0B-1B-QuestCategoryStopperPacket.cs" />
|
||||||
|
<Compile Include="Protocol\Packets\19-LobbyPacket\19-08-SendSystemMessagePacket.cs" />
|
||||||
<Compile Include="Protocol\Packets\1E-UnkPacket\1E-0C-Unk1E0CPacket.cs" />
|
<Compile Include="Protocol\Packets\1E-UnkPacket\1E-0C-Unk1E0CPacket.cs" />
|
||||||
<Compile Include="Protocol\Packets\0B-QuestPacket\0B-1C-QuestDifficultySendFinishedPacket.cs" />
|
<Compile Include="Protocol\Packets\0B-QuestPacket\0B-1C-QuestDifficultySendFinishedPacket.cs" />
|
||||||
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-0C-LoadEquipedPacket.cs" />
|
<Compile Include="Protocol\Packets\0F-ItemPacket\0F-0C-LoadEquipedPacket.cs" />
|
||||||
|
Loading…
Reference in New Issue
Block a user