分离存储角色参数和结构

This commit is contained in:
Sancaros 2024-12-06 23:40:36 +08:00
parent 181d882a8e
commit 6f9d732941
6 changed files with 320 additions and 227 deletions

View File

@ -0,0 +1,180 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Text;
using System.Threading.Tasks;
namespace PSO2SERVER.Models
{
public class CharacterAddtionStruct
{
}
public enum ShortLanguage : byte
{
Japanese,
English,
Unknown,
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct CharParam
{
public int CharacterID;
public int player_id;
public uint unk1;
public uint voice_type;
public ushort unk2;
public short voice_pitch;
}
public enum ClassType : byte
{
Unknown = 0xFF,
Hunter = 0,
Ranger,
Force,
Fighter,
Gunner,
Techer,
Braver,
Bouncer,
Challenger,
Summoner,
BattleWarrior,
Hero,
Phantom,
Etole,
Luster,
}
// 每个枚举成员的值是通过位移操作计算的:
//Hunter1 << 0即 10x0001
//Ranger1 << 1即 20x0002
//Force1 << 2即 40x0004
//Fighter1 << 3即 80x0008
//Gunner1 << 4即 160x0010
//Techer1 << 5即 320x0020
//Braver1 << 6即 640x0040
//Bouncer1 << 7即 1280x0080
//Challenger1 << 8即 2560x0100
//Summoner1 << 9即 5120x0200
//BattleWarrior1 << 10即 10240x0400
//Hero1 << 11即 20480x0800
//Phantom1 << 12即 40960x1000
//Etole1 << 13即 81920x2000
//Luster1 << 14即 163840x4000
[Flags]
public enum ClassTypeField : ushort
{
Hunter = 1 << 0,
Ranger = 1 << 1,
Force = 1 << 2,
Fighter = 1 << 3,
Gunner = 1 << 4,
Techer = 1 << 5,
Braver = 1 << 6,
Bouncer = 1 << 7,
Challenger = 1 << 8,
Summoner = 1 << 9,
BattleWarrior = 1 << 10,
Hero = 1 << 11,
Phantom = 1 << 12,
Etole = 1 << 13,
Luster = 1 << 14
}
[StructLayout(LayoutKind.Sequential)]
public struct JobEntry
{
/// Main level.
public ushort level;
public ushort level2; // SubClass level
/// Current EXP.
public uint exp;
}
[StructLayout(LayoutKind.Sequential)]
public struct Entries
{
public JobEntry
hunter
, ranger
, force
, fighter
, gunner
, techer
, braver
, bouncer
, Challenger
, Summoner
, BattleWarrior
, Hero
, Phantom
, Etole
, Luster
, unk16
, unk17
, unk18
, unk19
, unk20
, unk21
, unk22
, unk23
, unk24
;
}
public enum RunAnimation : ushort
{
Walking = 9,
Hovering = 11
}
public enum Race : ushort
{
Unknown = 0xFFFF,
Human = 0,
Newman,
Cast,
Dewman,
}
public enum Gender : ushort
{
Unknown = 0xFFFF,
Male = 0,
Female,
}
[StructLayout(LayoutKind.Sequential)]
public struct Figure
{
public ushort x, y, z; // Great naming, SEGA
}
public struct AccessoryData
{
public sbyte Value1;
public sbyte Value2;
public sbyte Value3;
}
public enum SkinColor : byte
{
RaceDefined,
Human,
Deuman,
Cast
}
[StructLayout(LayoutKind.Sequential)]
public struct HSVColor
{
public ushort hue, saturation, value;
}
}

View File

@ -9,172 +9,6 @@ namespace PSO2SERVER.Models
{
public class CharacterStruct
{
public enum ShortLanguage : byte
{
Japanese,
English,
Unknown,
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct CharParam
{
public int CharacterID;
public int player_id;
public uint unk1;
public uint voice_type;
public ushort unk2;
public short voice_pitch;
}
public enum ClassType : byte
{
Unknown = 0xFF,
Hunter = 0,
Ranger,
Force,
Fighter,
Gunner,
Techer,
Braver,
Bouncer,
Challenger,
Summoner,
BattleWarrior,
Hero,
Phantom,
Etole,
Luster,
}
// 每个枚举成员的值是通过位移操作计算的:
//Hunter1 << 0即 10x0001
//Ranger1 << 1即 20x0002
//Force1 << 2即 40x0004
//Fighter1 << 3即 80x0008
//Gunner1 << 4即 160x0010
//Techer1 << 5即 320x0020
//Braver1 << 6即 640x0040
//Bouncer1 << 7即 1280x0080
//Challenger1 << 8即 2560x0100
//Summoner1 << 9即 5120x0200
//BattleWarrior1 << 10即 10240x0400
//Hero1 << 11即 20480x0800
//Phantom1 << 12即 40960x1000
//Etole1 << 13即 81920x2000
//Luster1 << 14即 163840x4000
[Flags]
public enum ClassTypeField : ushort
{
Hunter = 1 << 0,
Ranger = 1 << 1,
Force = 1 << 2,
Fighter = 1 << 3,
Gunner = 1 << 4,
Techer = 1 << 5,
Braver = 1 << 6,
Bouncer = 1 << 7,
Challenger = 1 << 8,
Summoner = 1 << 9,
BattleWarrior = 1 << 10,
Hero = 1 << 11,
Phantom = 1 << 12,
Etole = 1 << 13,
Luster = 1 << 14
}
[StructLayout(LayoutKind.Sequential)]
public struct JobEntry
{
/// Main level.
public ushort level;
public ushort level2; // SubClass level
/// Current EXP.
public uint exp;
}
[StructLayout(LayoutKind.Sequential)]
public struct Entries
{
public JobEntry
hunter
, ranger
, force
, fighter
, gunner
, techer
, braver
, bouncer
, Challenger
, Summoner
, BattleWarrior
, Hero
, Phantom
, Etole
, Luster
, unk16
, unk17
, unk18
, unk19
, unk20
, unk21
, unk22
, unk23
, unk24
;
}
public enum RunAnimation : ushort
{
Walking = 9,
Hovering = 11
}
public enum Race : ushort
{
Unknown = 0xFFFF,
Human = 0,
Newman,
Cast,
Dewman,
}
public enum Gender : ushort
{
Unknown = 0xFFFF,
Male = 0,
Female,
}
[StructLayout(LayoutKind.Sequential)]
public struct Figure
{
public ushort x, y, z; // Great naming, SEGA
}
public struct AccessoryData
{
public sbyte Value1;
public sbyte Value2;
public sbyte Value3;
}
public enum SkinColor : byte
{
RaceDefined,
Human,
Deuman,
Cast
}
[StructLayout(LayoutKind.Sequential)]
public struct HSVColor
{
public ushort hue, saturation, value;
}
[StructLayout(LayoutKind.Sequential)]
public unsafe struct LooksParam
{

View File

@ -19,88 +19,139 @@ namespace PSO2SERVER.Protocol.Packets
Undefined = 0xFF,
}
private readonly Character _character;
public byte IsItMe = (byte)CharacterSpawnType.Myself;
public uint IsGM = 0;
public PSOLocation Position;
//private readonly Character _character;
//public byte IsItMe = (byte)CharacterSpawnType.Myself;
//public uint IsGM = 0;
/// <summary>
/// CharacterSpawnPacket Struct
/// </summary>
/// Spawned character's player object.
public ObjectHeader objHeader { get; set; } = new ObjectHeader();
public PSOLocation objPosition { get; set; } = new PSOLocation();
public ushort unk1 { get; set; } = 0;
/// Always `Character`. (?)
public string objName { get; set; } = "Character";//0x20
public ushort unk3 { get; set; } = 1;
public ushort unk4 { get; set; }
public uint unk5 { get; set; }
public uint unk6 { get; set; }
public uint unk7 { get; set; }
public uint unk8 { get; set; }
public CharacterSpawnType spawn_type { get; set; }
public byte unk9 { get; set; }
public ushort unk10 { get; set; }
public Character _character { get; set; }
public uint unk11 { get; set; }
/// Set to `1` if the player is a GM.
public uint gm_flag { get; set; }
public string nickname { get; set; }
//#[SeekAfter(0x60)]
public byte[] unk12 { get; set; } = new byte[0x40];
public CharacterSpawnPacket(Character character, PSOLocation locatiion)
{
objHeader = new ObjectHeader((uint)character.Account.AccountId, ObjectType.Player);
_character = character;
Position = locatiion;
objPosition = locatiion;
}
public CharacterSpawnPacket(Character character, PSOLocation locatiion, bool isme, bool isgm)
{
objHeader = new ObjectHeader((uint)character.Account.AccountId, ObjectType.Player);
_character = character;
IsItMe = isme ? (byte)CharacterSpawnType.Myself : (byte)CharacterSpawnType.Other;
Position = locatiion;
IsGM = isgm ? (uint)1 : 0;
spawn_type = isme ? CharacterSpawnType.Myself : CharacterSpawnType.Other;
objPosition = locatiion;
gm_flag = isgm ? (uint)1 : 0;
}
#region implemented abstract members of Packet
public override byte[] Build()
{
var writer = new PacketWriter();
var pkt = new PacketWriter();
// Accounts header
writer.WriteAccountHeader((uint)_character.Account.AccountId);
pkt.WriteStruct(objHeader);
// Spawn position
writer.WritePosition(Position);
writer.Write((ushort)0);
writer.WriteFixedLengthASCII("Character", 32);
writer.Write((ushort)1); // 0x44
writer.Write((ushort)0); // 0x46
writer.Write((uint)602); // 0x48
writer.Write((uint)1); // 0x4C
writer.Write((uint)53); // 0x50
writer.Write((uint)0); // 0x54
// Character spawn type.
writer.Write(IsItMe); // 0x58
writer.Write((byte)0x00);
writer.Write((ushort)0x00);
////writer.write((ushort)0x022f); // 0x5c
//writer.write((byte)0x2f); // 0x5c
//writer.write((byte)0x02);
////writer.write((ushort)0x0132); // 0x5e
//writer.write((byte)0x32);
//writer.write((byte)0x01);
//JobParam jobParam = _character.Jobs;
//jobParam.mainClass = ClassType.Luster;
//jobParam.subClass = ClassType.Phantom;
//jobParam.entries.Luster.level = 100;
pkt.WritePosition(objPosition);
pkt.Write(unk1);
pkt.WriteFixedLengthASCII(objName, 0x20);
pkt.Write(unk3); // 0x44
pkt.Write(unk4);
pkt.Write(unk5);
pkt.Write(unk6);
pkt.Write(unk7);
pkt.Write(unk8);
pkt.Write((byte)spawn_type);
pkt.Write(unk9);
pkt.Write(unk10);
// Character data.
writer.Write((uint)_character.AccountID);
writer.Write((uint)_character.CharacterID);
writer.Write((uint)_character.Unk1);//4
writer.Write((uint)_character.VoiceType);//4
writer.Write((ushort)_character.Unk2);//2
writer.Write(_character.VoicePitch);//2
writer.WriteFixedLengthUtf16(_character.Name, 16);
writer.Write((uint)_character.Unk3); // 0x90
writer.WriteStruct(_character.Looks);
writer.WriteStruct(_character.Jobs);
writer.WriteFixedLengthUtf16(_character.Account.Nickname, 16);
writer.WriteBytes(0, 116);
writer.Write((uint)0); // 0x204
writer.Write(IsGM); // gmflag?
pkt.Write((uint)_character.AccountID);
pkt.Write((uint)_character.CharacterID);
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.WriteFixedLengthUtf16(_character.Account.Nickname, 0x10);
for (var i = 0; i < 0x60; i++)
writer.Write((byte)0);
pkt.Write((byte)0);
pkt.Write(unk12);
//pkt.Write((ushort)0); // 0x46
//pkt.Write((uint)602); // 0x48
//pkt.Write((uint)1); // 0x4C
//pkt.Write((uint)53); // 0x50
//pkt.Write((uint)0); // 0x54
//// Character spawn type.
//pkt.Write(IsItMe); // 0x58
//pkt.Write((byte)0x00);
//pkt.Write((ushort)0x00);
//////writer.write((ushort)0x022f); // 0x5c
////writer.write((byte)0x2f); // 0x5c
////writer.write((byte)0x02);
//////writer.write((ushort)0x0132); // 0x5e
////writer.write((byte)0x32);
////writer.write((byte)0x01);
////JobParam jobParam = _character.Jobs;
////jobParam.mainClass = ClassType.Luster;
////jobParam.subClass = ClassType.Phantom;
////jobParam.entries.Luster.level = 100;
//// Character data.
//pkt.Write((uint)_character.AccountID);
//pkt.Write((uint)_character.CharacterID);
//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, 16);
//pkt.Write((uint)_character.Unk3); // 0x90
//pkt.WriteStruct(_character.Looks);
//pkt.WriteStruct(_character.Jobs);
//pkt.WriteFixedLengthUtf16(_character.Account.Nickname, 16);
//pkt.WriteBytes(0, 116);
//pkt.Write((uint)0); // 0x204
//pkt.Write(IsGM); // gmflag?
//for (var i = 0; i < 0x60; i++)
// pkt.Write((byte)0);
//for (var i = 0; i < 0x40; i++)
// writer.Write((byte)0);
return writer.ToArray();
return pkt.ToArray();
}
public override PacketHeader GetHeader()

View File

@ -1,4 +1,5 @@
using PSO2SERVER.Models;
using PSO2SERVER.Zone;
using System;
using System.Collections.Generic;
using System.Linq;
@ -8,9 +9,25 @@ namespace PSO2SERVER.Protocol.Packets
{
public class TransporterSpawnPacket : Packet
{
public ObjectHeader objHeader { get; set; } = new ObjectHeader();
public PSOLocation objPosition { get; set; } = new PSOLocation();
public ushort unk1 { get; set; } = 0;
/// Enemy name.
public string objName { get; set; } = string.Empty;//0x20
public uint unk2 { get; set; } = 0;
public ushort unk3 { get; set; } = 0;
public ushort unk4 { get; set; } = 0;
public ushort unk5 { get; set; } = 0;
public ushort unk6 { get; set; } = 0;
public uint unk7 { get; set; } = 0;
public uint unk8 { get; set; } = 0;
public TransporterSpawnPacket()
public TransporterSpawnPacket(PSOObject obj)
{
objHeader = obj.Header;
objPosition = obj.Position;
objName = obj.Name;
}
#region implemented abstract members of Packet
@ -18,6 +35,17 @@ namespace PSO2SERVER.Protocol.Packets
public override byte[] Build()
{
var pkt = new PacketWriter();
pkt.WriteStruct(objHeader);
pkt.WritePosition(objPosition);
pkt.Write(unk1); // Padding?
pkt.WriteFixedLengthASCII(objName, 0x20);
pkt.Write(unk2);
pkt.Write(unk3);
pkt.Write(unk4);
pkt.Write(unk5);
pkt.Write(unk6);
pkt.Write(unk7);
pkt.Write(unk8);
return pkt.ToArray();
}

View File

@ -9,7 +9,6 @@ namespace PSO2SERVER.Protocol.Packets
{
public class EnemySpawnPacket : Packet
{
public ObjectHeader objHeader { get; set; } = new ObjectHeader();
public PSOLocation objPosition { get; set; } = new PSOLocation();
public ushort unk1 { get; set; } = 0;

View File

@ -166,6 +166,7 @@
<Compile Include="Crypto\KeyLoader.cs" />
<Compile Include="Logger.cs" />
<Compile Include="Models\Block.cs" />
<Compile Include="Models\CharacterAddtionStruct.cs" />
<Compile Include="Models\Flags.cs" />
<Compile Include="Models\Mission.cs" />
<Compile Include="Models\NetInterface.cs" />