diff --git a/Server/ConsoleSystem.cs b/Server/ConsoleSystem.cs index f4b8d49..eefc99a 100644 --- a/Server/ConsoleSystem.cs +++ b/Server/ConsoleSystem.cs @@ -712,7 +712,7 @@ namespace PSO2SERVER }; - var fakePacket = new CharacterSpawnPacket(fakeChar, new PSOLocation(0f, 1f, 0f, 0f, x, y, z), false, 0) + var fakePacket = new CharacterSpawnPacket(fakeChar, new PSOLocation(0f, 1f, 0f, 0f, x, y, z), false, false) { }; client.SendPacket(fakePacket); @@ -1113,7 +1113,7 @@ namespace PSO2SERVER if (header.Type != 0x8 || header.Subtype != 0xC) { - Logger.WriteWarning($"[WRN] File {path} not an NPC spawn packet, skipping."); + Logger.WriteWarning($"[WRN] 文件 {path} 不是NPC生成数据包, 跳过."); continue; } @@ -1128,13 +1128,14 @@ namespace PSO2SERVER RotZ = reader.ReadEntityPosition().RotZ, RotW = reader.ReadEntityPosition().RotW, NPCName = reader.ReadFixedLengthAscii(0x20), - ZoneName = zone + ZoneName = zone, + is_active = 1 }; reader.ReadInt16(); // Assuming this read is necessary newNPCs.Add(npc); - Logger.WriteInternal($"[NPC] Adding new NPC {npc.NPCName} to the database for zone {zone}"); + Logger.WriteInternal($"[NPC] 新增 {npc.NPCName} 区域 {zone} 至数据库"); } using (var db = new ServerEf()) diff --git a/Server/Database/ServerEf.cs b/Server/Database/ServerEf.cs index fbf880e..3f58941 100644 --- a/Server/Database/ServerEf.cs +++ b/Server/Database/ServerEf.cs @@ -134,6 +134,7 @@ namespace PSO2SERVER.Database public float PosX { get; set; } public float PosY { get; set; } public float PosZ { get; set; } + public int is_active { get; set; } } public class GameObject diff --git a/Server/Models/PSOObject.cs b/Server/Models/PSOObject.cs index 875ea89..2998558 100644 --- a/Server/Models/PSOObject.cs +++ b/Server/Models/PSOObject.cs @@ -2,6 +2,8 @@ using System.Collections.Generic; using System.IO; using System.Linq; +using System.Runtime.InteropServices; +using System.Runtime.Remoting.Messaging; using System.Text; using PSO2SERVER.Database; using PSO2SERVER.Protocol; @@ -85,8 +87,37 @@ namespace PSO2SERVER.Models public class PSONPC : PSOObject { + public unsafe struct NPC { + public ObjectHeader objHeader; + public PSOLocation objPosition; + public ushort unk1; + public string objName; + public uint unk2; + public fixed byte unk3[0x0C]; + public ushort unk4; + public ushort unk5; + public uint unk6; + public uint unk7; + public uint unk8; + public uint unk9; + public uint unk10; + public uint unk11; + public uint unk12; + public string unk13; //Ascii + } + public override byte[] GenerateSpawnBlob() { + NPC npc = new NPC + { + objHeader = Header, + objPosition = Position, + objName = Name, + unk8 = 1101004800, + unk12 = 1, + unk13 = "", + }; + PacketWriter writer = new PacketWriter(); writer.WriteStruct(Header); writer.WritePosition(Position); diff --git a/Server/Object/ObjectManager.cs b/Server/Object/ObjectManager.cs index 8545f7c..6326738 100644 --- a/Server/Object/ObjectManager.cs +++ b/Server/Object/ObjectManager.cs @@ -96,7 +96,7 @@ namespace PSO2SERVER.Object using (var db = new ServerEf()) { var dbNpcs = from n in db.NPCs - where n.ZoneName == zone + where n.ZoneName == zone && n.is_active == 1 select n; foreach (NPC npc in dbNpcs) diff --git a/Server/Protocol/PacketWriter.cs b/Server/Protocol/PacketWriter.cs index ea3caf0..35113a9 100644 --- a/Server/Protocol/PacketWriter.cs +++ b/Server/Protocol/PacketWriter.cs @@ -70,9 +70,6 @@ namespace PSO2SERVER.Protocol // 写入字符串的字节数据 Write(str.ToBytes()); - // 写入 null 终结符 - Write((byte)0); - // 填充 null 字节以保证 4 字节对齐 for (var i = 0; i < padding; i++) { diff --git a/Server/Protocol/Packets/03-ServerPacket/03-00-MapTransferPacket.cs b/Server/Protocol/Packets/03-ServerPacket/03-00-MapTransferPacket.cs index 2e637c6..9205ca7 100644 --- a/Server/Protocol/Packets/03-ServerPacket/03-00-MapTransferPacket.cs +++ b/Server/Protocol/Packets/03-ServerPacket/03-00-MapTransferPacket.cs @@ -11,37 +11,41 @@ namespace PSO2SERVER.Protocol.Packets { public class MapTransferPacket : Packet { - private readonly Map _map; - private readonly int _playerid; + public ObjectHeader Map { get; set; } + public ObjectHeader target { get; set; } + public ZoneSettings settings { get; set; } public MapTransferPacket(Map map, int PlayerId) { - _map = map; - _playerid = PlayerId; + Map = new ObjectHeader((uint)map.MapID, ObjectType.Map); + target = new ObjectHeader((uint)PlayerId, ObjectType.Player); + settings = new ZoneSettings + { + WorldId = 1, + Unk1 = 0, + ZoneId = ~(uint)map.Type, + MapId = (uint)map.MapID, + ZoneType = (uint)map.Flags, + Seed = map.GenerationArgs.seed, + Args = (uint)map.VariantID, + SizeX = map.GenerationArgs.xsize, + SizeY = map.GenerationArgs.ysize, + Unk2 = 1, + AreaIndex = 1, + SubArea = 0xFFFFFFFF, + Unk3 = 0x301, + }; } #region implemented abstract members of Packet public override byte[] Build() { - PacketWriter writer = new PacketWriter(); - writer.WriteStruct(new ObjectHeader(3, ObjectType.Map)); - writer.WriteStruct(new ObjectHeader((uint)_playerid, ObjectType.Player)); - writer.Write(0x1); // 8 Zeros - writer.Write(0); // 8 Zeros - writer.Write(~(uint)_map.Type); // F4 FF FF FF - writer.Write(_map.MapID); // Map ID maybe - writer.Write((uint)_map.Flags); - writer.Write(_map.GenerationArgs.seed); // 81 8F E6 19 (Maybe seed) - writer.Write(_map.VariantID); // Randomgen enable / disable maybe - writer.Write(_map.GenerationArgs.xsize); // X Size - writer.Write(_map.GenerationArgs.ysize); // Y Size - writer.Write(1); - writer.Write(1); - writer.Write(~0); // FF FF FF FF FF FF FF FF - writer.Write(0x301); - - return writer.ToArray(); + PacketWriter pkt = new PacketWriter(); + pkt.WriteStruct(Map); + pkt.WriteStruct(target); + pkt.WriteStruct(settings); + return pkt.ToArray(); } public override PacketHeader GetHeader() diff --git a/Server/Protocol/Packets/04-ObjectRelatedPacket/04-06-DespawnObjectPacket.cs b/Server/Protocol/Packets/04-ObjectRelatedPacket/04-06-DespawnObjectPacket.cs index e387e76..2ae419e 100644 --- a/Server/Protocol/Packets/04-ObjectRelatedPacket/04-06-DespawnObjectPacket.cs +++ b/Server/Protocol/Packets/04-ObjectRelatedPacket/04-06-DespawnObjectPacket.cs @@ -29,7 +29,7 @@ namespace PSO2SERVER.Protocol.Packets public override PacketHeader GetHeader() { - return new PacketHeader(0x04, 0x06, PacketFlags.None); + return new PacketHeader(0x04, 0x06, PacketFlags.OBJECT_RELATED); } #endregion diff --git a/Server/Protocol/Packets/08-SpawnPacket/08-04-CharacterSpawnPacket.cs b/Server/Protocol/Packets/08-SpawnPacket/08-04-CharacterSpawnPacket.cs index 09babc6..c0b3c91 100644 --- a/Server/Protocol/Packets/08-SpawnPacket/08-04-CharacterSpawnPacket.cs +++ b/Server/Protocol/Packets/08-SpawnPacket/08-04-CharacterSpawnPacket.cs @@ -30,12 +30,12 @@ namespace PSO2SERVER.Protocol.Packets Position = locatiion; } - public CharacterSpawnPacket(Character character, PSOLocation locatiion, bool isme, uint isgm) + public CharacterSpawnPacket(Character character, PSOLocation locatiion, bool isme, bool isgm) { _character = character; IsItMe = isme ? (byte)CharacterSpawnType.Myself : (byte)CharacterSpawnType.Other; Position = locatiion; - IsGM = isgm; + IsGM = isgm ? (uint)1 : 0; } #region implemented abstract members of Packet @@ -71,6 +71,11 @@ namespace PSO2SERVER.Protocol.Packets //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. writer.Write((uint)_character.AccountID); writer.Write((uint)_character.CharacterID); @@ -81,11 +86,7 @@ namespace PSO2SERVER.Protocol.Packets writer.WriteFixedLengthUtf16(_character.Name, 16); writer.Write((uint)_character.Unk3); // 0x90 writer.WriteStruct(_character.Looks); - JobParam jobParam = _character.Jobs; - jobParam.mainClass = ClassType.Luster; - jobParam.subClass = ClassType.Phantom; - jobParam.entries.Luster.level = 100; - writer.WriteStruct(jobParam); + writer.WriteStruct(_character.Jobs); writer.WriteFixedLengthUtf16(_character.Account.Nickname, 16); writer.WriteBytes(0, 116); diff --git a/Server/Protocol/Packets/08-SpawnPacket/08-0B-ObjectSpawnPacket.cs b/Server/Protocol/Packets/08-SpawnPacket/08-0B-ObjectSpawnPacket.cs index ec7fe74..90e7177 100644 --- a/Server/Protocol/Packets/08-SpawnPacket/08-0B-ObjectSpawnPacket.cs +++ b/Server/Protocol/Packets/08-SpawnPacket/08-0B-ObjectSpawnPacket.cs @@ -1,5 +1,6 @@ using Org.BouncyCastle.Utilities; using PSO2SERVER.Models; +using PSO2SERVER.Zone; using System; using System.Collections.Generic; using System.IO; @@ -12,34 +13,96 @@ namespace PSO2SERVER.Protocol.Packets { public class ObjectSpawnPacket : Packet { - private readonly PSOObject _obj; + //private readonly PSOObject _obj; + + 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; + /// Enemy HP. + public uint hp { get; set; } = 0; + public uint unk4 { get; set; } = 0; + /// Enemy level. + public uint level { get; set; } = 0; + public uint unk5 { get; set; } = 0; + public uint unk6 { get; set; } = 0; + public ushort unk7 { get; set; } = 0; + public ushort unk8 { get; set; } = 0; + public uint[] unk9 { get; set; } = new uint[0x10]; + public string unk10 { get; set; } = string.Empty; //Ascii + public byte unk11 { get; set; } = 0; + public byte unk12 { get; set; } = 0; + public ushort unk13 { get; set; } = 0; + public byte[] unk14 { get; set; } = new byte[0x0C]; + public ObjectSpawnPacket(PSOObject obj) { - _obj = obj; + objHeader = obj.Header; + objPosition = obj.Position; + objName = obj.Name; + unk2 = 2; + unk4 = 2; + unk6 = 1029; + unk7 = 255; + unk8 = 65535; + unk9 = new uint[] { + 0, 0, 0, 0, 0, 0, 0, 0, 0, 1062804813, 3212836864, 0, 1570802465, 0, 0, 0 + }; + unk11 = 1; + unk12 = 255; + //_obj = obj; } #region implemented abstract members of Packet public override byte[] Build() { - PacketWriter writer = new PacketWriter(); - writer.WriteStruct(_obj.Header); - writer.WritePosition(_obj.Position); - writer.Seek(2, SeekOrigin.Current); // Padding I guess... - writer.WriteFixedLengthASCII(_obj.Name, 0x34); - writer.Write(_obj.ThingFlag); - writer.Write(_obj.Things.Length); - foreach (PSOObjectThing thing in _obj.Things) - { - writer.WriteStruct(thing); - } + PacketWriter pkt = new PacketWriter(); + pkt.WriteStruct(objHeader); + pkt.WritePosition(objPosition); + pkt.Write(unk1); // Padding? + pkt.WriteFixedLengthASCII(objName, 0x20); + pkt.Write(unk2); + pkt.Write(hp); + pkt.Write(unk4); + pkt.Write(level); + pkt.Write(unk5); + pkt.Write(unk6); + pkt.Write(unk7); + pkt.Write(unk8); + pkt.WriteUintArray(unk9); + pkt.WriteAscii(unk10, 0x258B, 0x32); + pkt.Write(unk11); + pkt.Write(unk12); + pkt.Write(unk13); + pkt.Write(unk14); - return writer.ToArray(); + + + + + + + + //pkt.WriteStruct(_obj.Header); + //pkt.WritePosition(_obj.Position); + //pkt.Seek(2, SeekOrigin.Current); // Padding I guess... + //pkt.WriteFixedLengthASCII(_obj.Name, 0x34); + //pkt.Write(_obj.ThingFlag); + //pkt.Write(_obj.Things.Length); + //foreach (PSOObjectThing thing in _obj.Things) + //{ + // pkt.WriteStruct(thing); + //} + + return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x08, 0x0B, PacketFlags.None); + return new PacketHeader(0x08, 0x0B, PacketFlags.PACKED); } #endregion diff --git a/Server/Protocol/Packets/08-SpawnPacket/08-0C-NPCSpawnPacket.cs b/Server/Protocol/Packets/08-SpawnPacket/08-0C-NPCSpawnPacket.cs index 8f155b3..51d6b47 100644 --- a/Server/Protocol/Packets/08-SpawnPacket/08-0C-NPCSpawnPacket.cs +++ b/Server/Protocol/Packets/08-SpawnPacket/08-0C-NPCSpawnPacket.cs @@ -1,5 +1,6 @@ using Org.BouncyCastle.Utilities; using PSO2SERVER.Models; +using PSO2SERVER.Zone; using System; using System.Collections.Generic; using System.IO; @@ -12,48 +13,60 @@ namespace PSO2SERVER.Protocol.Packets { public class NPCSpawnPacket : Packet { - private readonly PSOObject _obj; + public ObjectHeader objHeader { get; set; } = new ObjectHeader(); + public PSOLocation objPosition { get; set; } = new PSOLocation(); + public ushort unk1 { get; set; } = 0; + public string objName { get; set; } = string.Empty; + public uint unk2 { get; set; } = 0; + public byte[] unk3 { get; set; } = new byte[0x0C]; + public ushort unk4 { get; set; } = 0; + public ushort unk5 { get; set; } = 0; + public uint unk6 { get; set; } = 0; + public uint unk7 { get; set; } = 0; + public uint unk8 { get; set; } = 0; + public uint unk9 { get; set; } = 0; + public uint unk10 { get; set; } = 0; + public uint unk11 { get; set; } = 0; + public uint unk12 { get; set; } = 0; + public string unk13 { get; set; } = string.Empty; //Ascii + public NPCSpawnPacket(PSOObject obj) { - _obj = obj; + objHeader = obj.Header; + objPosition = obj.Position; + objName = obj.Name; + unk8 = 1101004800; + unk12 = 1; } #region implemented abstract members of Packet public override byte[] Build() { - PacketWriter writer = new PacketWriter(); - writer.WriteStruct(_obj.Header); - writer.WritePosition(_obj.Position); - writer.Seek(2, SeekOrigin.Current); // Padding I guess... - writer.WriteFixedLengthASCII(_obj.Name, 0x20); + PacketWriter pkt = new PacketWriter(); + pkt.WriteStruct(objHeader); + pkt.WritePosition(objPosition); + pkt.Write(unk1); // Padding? + pkt.WriteFixedLengthASCII(objName, 0x20); + pkt.Write(unk2); // Padding? + pkt.Write(unk3); // Unknown, usually zero + pkt.Write(unk4); + pkt.Write(unk5); + pkt.Write(unk6); + pkt.Write(unk7); + pkt.Write(unk8); // Always this 1101004800 + pkt.Write(unk9); + pkt.Write(unk10); + pkt.Write(unk11); + pkt.Write(unk12); + pkt.WriteAscii(unk13, 0x9FCD, 0xE7); - writer.Write(0); // Padding? - writer.Write(new byte[0xC]); // Unknown, usually zero - - writer.Write((UInt16)0); - writer.Write((UInt16)0); - - writer.Write((UInt32)0); - writer.Write((UInt32)0); - - writer.Write((UInt32)1101004800); // Always this - - writer.Write((UInt32)0); - writer.Write((UInt32)0); - writer.Write((UInt32)0); - - writer.Write((UInt32)1); - - writer.WriteMagic(1, 0x9FCD, 0xE7); - writer.Write((UInt32)0); - - return writer.ToArray(); + return pkt.ToArray(); } public override PacketHeader GetHeader() { - return new PacketHeader(0x08, 0x0C, PacketFlags.None); + return new PacketHeader(0x08, 0x0C, PacketFlags.PACKED); } #endregion diff --git a/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs b/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs index e4fc395..1ca824f 100644 --- a/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs +++ b/Server/Protocol/Packets/11-ClientPacket/11-01-LoginDataPacket.cs @@ -27,37 +27,37 @@ namespace PSO2SERVER.Protocol.Packets public string Error; public ObjectHeader Player; public string BlockName = new string(' ', 0x20); - public float Unk1; - public uint Unk2; - public uint LevelCap; - public uint LevelCap2; - public uint Unk5; - public float Unk6; - public float Unk7; - public uint Unk8; - public float Unk9; - public float Unk10; - public uint Unk11; - public float Unk12; - public uint Unk13; + public float Unk1 = 0; + public uint Unk2 = 0; + public uint LevelCap = 0; + public uint LevelCap2 = 0; + public uint Unk5 = 0; + public float Unk6 = 0; + public float Unk7 = 0; + public uint Unk8 = 0; + public float Unk9 = 0; + public float Unk10 = 0; + public uint Unk11 = 0; + public float Unk12 = 0; + public uint Unk13 = 0; public float[] Unk14 = new float[10]; // Length: 10 public float[] Unk15 = new float[21]; // Length: 21 - public float Unk16; - public float Unk17; + public float Unk16 = 0; + public float Unk17 = 0; public float[] Unk18 = new float[9]; // Length: 9 public uint[] Unk19 = new uint[2]; // Length: 2 - public uint Unk20; - public uint Unk21; + public uint Unk20 = 0; + public uint Unk21 = 0; public float[] Unk22 = new float[3]; // Length: 3 - public uint Unk23; - public float Unk24; - public float Unk25; - public uint Unk26; + public uint Unk23 = 0; + public float Unk24 = 0; + public float Unk25 = 0; + public uint Unk26 = 0; public byte[] Unk27 = new byte[12]; // Length: 12 public string Unk28 = new string(' ', 0x20); - public uint Unk29; + public uint Unk29 = 0; public string Unk30 = new string(' ', 0x20); - public uint Unk31; + public uint Unk31 = 0; public LoginDataPacket(string blockName, string error, uint userid) { diff --git a/Server/Protocol/Packets/11-ClientPacket/11-03-CharacterListPacket.cs b/Server/Protocol/Packets/11-ClientPacket/11-03-CharacterListPacket.cs index 2e823d0..c64447a 100644 --- a/Server/Protocol/Packets/11-ClientPacket/11-03-CharacterListPacket.cs +++ b/Server/Protocol/Packets/11-ClientPacket/11-03-CharacterListPacket.cs @@ -52,6 +52,11 @@ namespace PSO2SERVER.Protocol.Packets foreach (var ch in chars) { + //JobParam jobParam = v; + //jobParam.mainClass = ClassType.Luster; + //jobParam.subClass = ClassType.Phantom; + //jobParam.entries.Luster.level = 100; + writer.Write((uint)0); writer.Write((uint)ch.CharacterID);//4 @@ -64,11 +69,7 @@ namespace PSO2SERVER.Protocol.Packets //Logger.WriteInternal("[CHR] 新增名为 {0} 的新角色.", ch.Name); writer.Write((uint)ch.Unk3); writer.WriteStruct(ch.Looks); - JobParam jobParam = ch.Jobs; - jobParam.mainClass = ClassType.Luster; - jobParam.subClass = ClassType.Phantom; - jobParam.entries.Luster.level = 100; - writer.WriteStruct(jobParam); + writer.WriteStruct(ch.Jobs); writer.WriteBytes(0, 148); } diff --git a/Server/Zone/Map.cs b/Server/Zone/Map.cs index 8dc3ac6..4271ac2 100644 --- a/Server/Zone/Map.cs +++ b/Server/Zone/Map.cs @@ -108,6 +108,7 @@ namespace PSO2SERVER.Zone return location; } + public struct ZoneSettings { public uint WorldId; @@ -190,7 +191,7 @@ namespace PSO2SERVER.Zone c.SendPacket(new SetAccountIDPacket(c._account.AccountId)); // Spawn Character - c.SendPacket(new CharacterSpawnPacket(c.Character, location, true, 1)); + c.SendPacket(new CharacterSpawnPacket(c.Character, location, true, true)); c.CurrentLocation = location; c.CurrentZone = this; @@ -207,11 +208,11 @@ namespace PSO2SERVER.Zone } // Spawn for others, Spawn others for me - CharacterSpawnPacket spawnMe = new CharacterSpawnPacket(c.Character, location, false, 1); + CharacterSpawnPacket spawnMe = new CharacterSpawnPacket(c.Character, location, false, true); foreach (Client other in Clients) { other.SendPacket(spawnMe); - c.SendPacket(new CharacterSpawnPacket(other.Character, other.CurrentLocation, false, 1)); + c.SendPacket(new CharacterSpawnPacket(other.Character, other.CurrentLocation, false, true)); } Clients.Add(c);