mirror of
https://github.com/EQEmu/Server.git
synced 2025-12-21 18:31:30 +00:00
335 lines
11 KiB
C#
335 lines
11 KiB
C#
using System;
|
|
using System.IO;
|
|
using System.Diagnostics;
|
|
using System.Collections.Generic;
|
|
using EQExtractor2.InternalTypes;
|
|
using EQExtractor2.OpCodes;
|
|
using EQPacket;
|
|
using MyUtils;
|
|
|
|
namespace EQExtractor2.Patches
|
|
{
|
|
class PatchMarch132013Decoder : PatchFebruary112013Decoder
|
|
{
|
|
public PatchMarch132013Decoder()
|
|
{
|
|
Version = "EQ Client Build Date March 13 2013.";
|
|
|
|
PatchConfFileName = "patch_Mar13-2013.conf";
|
|
|
|
SupportsSQLGeneration = true;
|
|
}
|
|
|
|
override public List<Door> GetDoors()
|
|
{
|
|
List<Door> DoorList = new List<Door>();
|
|
|
|
List<byte[]> SpawnDoorPacket = GetPacketsOfType("OP_SpawnDoor", PacketDirection.ServerToClient);
|
|
|
|
if ((SpawnDoorPacket.Count == 0) || (SpawnDoorPacket[0].Length == 0))
|
|
return DoorList;
|
|
|
|
int DoorCount = SpawnDoorPacket[0].Length / 100;
|
|
|
|
ByteStream Buffer = new ByteStream(SpawnDoorPacket[0]);
|
|
|
|
for (int d = 0; d < DoorCount; ++d)
|
|
{
|
|
string DoorName = Buffer.ReadFixedLengthString(32, false);
|
|
|
|
float YPos = Buffer.ReadSingle();
|
|
|
|
float XPos = Buffer.ReadSingle();
|
|
|
|
float ZPos = Buffer.ReadSingle();
|
|
|
|
float Heading = Buffer.ReadSingle();
|
|
|
|
UInt32 Incline = Buffer.ReadUInt32();
|
|
|
|
Int32 Size = Buffer.ReadInt32();
|
|
|
|
Buffer.SkipBytes(4); // Skip Unknown
|
|
|
|
Byte DoorID = Buffer.ReadByte();
|
|
|
|
Byte OpenType = Buffer.ReadByte();
|
|
|
|
Byte StateAtSpawn = Buffer.ReadByte();
|
|
|
|
Byte InvertState = Buffer.ReadByte();
|
|
|
|
Int32 DoorParam = Buffer.ReadInt32();
|
|
|
|
// Skip past the trailing unknowns in the door struct, moving to the next door in the packet.
|
|
|
|
Buffer.SkipBytes(32);
|
|
|
|
string DestZone = "NONE";
|
|
|
|
Door NewDoor = new Door(DoorName, YPos, XPos, ZPos, Heading, Incline, Size, DoorID, OpenType, StateAtSpawn, InvertState,
|
|
DoorParam, DestZone, 0, 0, 0, 0);
|
|
|
|
DoorList.Add(NewDoor);
|
|
|
|
}
|
|
return DoorList;
|
|
}
|
|
|
|
override public List<ZoneEntryStruct> GetSpawns()
|
|
{
|
|
List<ZoneEntryStruct> ZoneSpawns = new List<ZoneEntryStruct>();
|
|
|
|
List<byte[]> SpawnPackets = GetPacketsOfType("OP_ZoneEntry", PacketDirection.ServerToClient);
|
|
|
|
foreach (byte[] SpawnPacket in SpawnPackets)
|
|
{
|
|
ZoneEntryStruct NewSpawn = new ZoneEntryStruct();
|
|
|
|
ByteStream Buffer = new ByteStream(SpawnPacket);
|
|
|
|
NewSpawn.SpawnName = Buffer.ReadString(true);
|
|
|
|
NewSpawn.SpawnName = Utils.MakeCleanName(NewSpawn.SpawnName);
|
|
|
|
NewSpawn.SpawnID = Buffer.ReadUInt32();
|
|
|
|
NewSpawn.Level = Buffer.ReadByte();
|
|
|
|
float UnkSize = Buffer.ReadSingle();
|
|
|
|
NewSpawn.IsNPC = Buffer.ReadByte();
|
|
|
|
UInt32 Bitfield = Buffer.ReadUInt32();
|
|
|
|
NewSpawn.Gender = (Bitfield & 3);
|
|
|
|
Byte OtherData = Buffer.ReadByte();
|
|
|
|
Buffer.SkipBytes(8); // Skip 8 unknown bytes
|
|
|
|
NewSpawn.DestructableString1 = "";
|
|
NewSpawn.DestructableString2 = "";
|
|
NewSpawn.DestructableString3 = "";
|
|
|
|
if ((NewSpawn.IsNPC > 0) && ((OtherData & 1) > 0))
|
|
{
|
|
// Destructable Objects
|
|
NewSpawn.DestructableString1 = Buffer.ReadString(false);
|
|
NewSpawn.DestructableString2 = Buffer.ReadString(false);
|
|
NewSpawn.DestructableString3 = Buffer.ReadString(false);
|
|
Buffer.SkipBytes(53);
|
|
}
|
|
|
|
if ((OtherData & 4) > 0)
|
|
{
|
|
// Auras
|
|
Buffer.ReadString(false);
|
|
Buffer.ReadString(false);
|
|
Buffer.SkipBytes(54);
|
|
}
|
|
|
|
NewSpawn.PropCount = Buffer.ReadByte();
|
|
|
|
if (NewSpawn.PropCount > 0)
|
|
NewSpawn.BodyType = Buffer.ReadUInt32();
|
|
else
|
|
NewSpawn.BodyType = 0;
|
|
|
|
|
|
for (int j = 1; j < NewSpawn.PropCount; ++j)
|
|
Buffer.SkipBytes(4);
|
|
|
|
Buffer.SkipBytes(1); // Skip HP %
|
|
NewSpawn.HairColor = Buffer.ReadByte();
|
|
NewSpawn.BeardColor = Buffer.ReadByte();
|
|
NewSpawn.EyeColor1 = Buffer.ReadByte();
|
|
NewSpawn.EyeColor2 = Buffer.ReadByte();
|
|
NewSpawn.HairStyle = Buffer.ReadByte();
|
|
NewSpawn.Beard = Buffer.ReadByte();
|
|
|
|
NewSpawn.DrakkinHeritage = Buffer.ReadUInt32();
|
|
NewSpawn.DrakkinTattoo = Buffer.ReadUInt32();
|
|
NewSpawn.DrakkinDetails = Buffer.ReadUInt32();
|
|
|
|
NewSpawn.EquipChest2 = Buffer.ReadByte();
|
|
|
|
bool UseWorn = (NewSpawn.EquipChest2 == 255);
|
|
|
|
Buffer.SkipBytes(2); // 2 Unknown bytes;
|
|
|
|
NewSpawn.Helm = Buffer.ReadByte();
|
|
|
|
NewSpawn.Size = Buffer.ReadSingle();
|
|
|
|
NewSpawn.Face = Buffer.ReadByte();
|
|
|
|
NewSpawn.WalkSpeed = Buffer.ReadSingle();
|
|
|
|
NewSpawn.RunSpeed = Buffer.ReadSingle();
|
|
|
|
NewSpawn.Race = Buffer.ReadUInt32();
|
|
|
|
Buffer.SkipBytes(1); // Skip Holding
|
|
|
|
NewSpawn.Deity = Buffer.ReadUInt32();
|
|
|
|
Buffer.SkipBytes(8); // Skip GuildID and GuildRank
|
|
|
|
NewSpawn.Class = Buffer.ReadByte();
|
|
|
|
Buffer.SkipBytes(4); // Skip PVP, Standstate, Light, Flymode
|
|
|
|
NewSpawn.LastName = Buffer.ReadString(true);
|
|
|
|
Buffer.SkipBytes(6);
|
|
|
|
NewSpawn.PetOwnerID = Buffer.ReadUInt32();
|
|
|
|
Buffer.SkipBytes(25);
|
|
|
|
NewSpawn.MeleeTexture1 = 0;
|
|
NewSpawn.MeleeTexture2 = 0;
|
|
|
|
if ((NewSpawn.IsNPC == 0) || NPCType.IsPlayableRace(NewSpawn.Race))
|
|
{
|
|
for (int ColourSlot = 0; ColourSlot < 9; ++ColourSlot)
|
|
NewSpawn.SlotColour[ColourSlot] = Buffer.ReadUInt32();
|
|
|
|
for (int i = 0; i < 9; ++i)
|
|
{
|
|
NewSpawn.Equipment[i] = Buffer.ReadUInt32();
|
|
|
|
UInt32 Equip3 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Equip2 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Equip1 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Equip0 = Buffer.ReadUInt32();
|
|
}
|
|
|
|
if (NewSpawn.Equipment[Constants.MATERIAL_CHEST] > 0)
|
|
{
|
|
NewSpawn.EquipChest2 = (byte)NewSpawn.Equipment[Constants.MATERIAL_CHEST];
|
|
|
|
}
|
|
|
|
NewSpawn.ArmorTintRed = (byte)((NewSpawn.SlotColour[Constants.MATERIAL_CHEST] >> 16) & 0xff);
|
|
|
|
NewSpawn.ArmorTintGreen = (byte)((NewSpawn.SlotColour[Constants.MATERIAL_CHEST] >> 8) & 0xff);
|
|
|
|
NewSpawn.ArmorTintBlue = (byte)(NewSpawn.SlotColour[Constants.MATERIAL_CHEST] & 0xff);
|
|
|
|
if (NewSpawn.Equipment[Constants.MATERIAL_PRIMARY] > 0)
|
|
NewSpawn.MeleeTexture1 = NewSpawn.Equipment[Constants.MATERIAL_PRIMARY];
|
|
|
|
if (NewSpawn.Equipment[Constants.MATERIAL_SECONDARY] > 0)
|
|
NewSpawn.MeleeTexture2 = NewSpawn.Equipment[Constants.MATERIAL_SECONDARY];
|
|
|
|
if (UseWorn)
|
|
NewSpawn.Helm = (byte)NewSpawn.Equipment[Constants.MATERIAL_HEAD];
|
|
else
|
|
NewSpawn.Helm = 0;
|
|
|
|
}
|
|
else
|
|
{
|
|
// Non playable race
|
|
|
|
Buffer.SkipBytes(20);
|
|
|
|
NewSpawn.MeleeTexture1 = Buffer.ReadUInt32();
|
|
Buffer.SkipBytes(16);
|
|
NewSpawn.MeleeTexture2 = Buffer.ReadUInt32();
|
|
Buffer.SkipBytes(16);
|
|
}
|
|
|
|
if (NewSpawn.EquipChest2 == 255)
|
|
NewSpawn.EquipChest2 = 0;
|
|
|
|
if (NewSpawn.Helm == 255)
|
|
NewSpawn.Helm = 0;
|
|
|
|
UInt32 Position1 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Position2 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Position3 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Position4 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Position5 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Position6 = Buffer.ReadUInt32();
|
|
|
|
NewSpawn.YPos = Utils.EQ19ToFloat((Int32)((Position5) & 0x7FFFF));
|
|
|
|
NewSpawn.ZPos = Utils.EQ19ToFloat((Int32)(Position3) & 0x7FFFF);
|
|
|
|
NewSpawn.XPos = Utils.EQ19ToFloat((Int32)(Position4) & 0x7FFFF);
|
|
|
|
NewSpawn.Heading = Utils.EQ19ToFloat((Int32)(Position2 >> 13) & 0xFFF);
|
|
|
|
if ((OtherData & 16) > 0)
|
|
{
|
|
NewSpawn.Title = Buffer.ReadString(false);
|
|
}
|
|
|
|
if ((OtherData & 32) > 0)
|
|
{
|
|
NewSpawn.Suffix = Buffer.ReadString(false);
|
|
}
|
|
|
|
// unknowns
|
|
Buffer.SkipBytes(8);
|
|
|
|
NewSpawn.IsMercenary = Buffer.ReadByte();
|
|
|
|
Buffer.SkipBytes(54);
|
|
|
|
Debug.Assert(Buffer.GetPosition() == Buffer.Length(), "Length mismatch while parsing zone spawns");
|
|
|
|
ZoneSpawns.Add(NewSpawn);
|
|
}
|
|
|
|
return ZoneSpawns;
|
|
}
|
|
|
|
override public PositionUpdate Decode_OP_MobUpdate(byte[] MobUpdatePacket)
|
|
{
|
|
PositionUpdate PosUpdate = new PositionUpdate();
|
|
|
|
ByteStream Buffer = new ByteStream(MobUpdatePacket);
|
|
|
|
PosUpdate.SpawnID = Buffer.ReadUInt16();
|
|
|
|
Buffer.SkipBytes(2);
|
|
|
|
UInt32 Word1 = Buffer.ReadUInt32();
|
|
|
|
UInt32 Word2 = Buffer.ReadUInt32();
|
|
|
|
UInt16 Word3 = Buffer.ReadUInt16();
|
|
|
|
PosUpdate.p.y = Utils.EQ19ToFloat((Int32)(Word1 & 0x7FFFF));
|
|
|
|
// Z is in the top 13 bits of Word1 and the bottom 6 of Word2
|
|
|
|
UInt32 ZPart1 = Word1 >> 19; // ZPart1 now has low order bits of Z in bottom 13 bits
|
|
UInt32 ZPart2 = Word2 & 0x3F; // ZPart2 now has high order bits of Z in bottom 6 bits
|
|
|
|
ZPart2 = ZPart2 << 13;
|
|
|
|
PosUpdate.p.z = Utils.EQ19ToFloat((Int32)(ZPart1 | ZPart2));
|
|
|
|
PosUpdate.p.x = Utils.EQ19ToFloat((Int32)(Word2 >> 13) & 0x7FFFF);
|
|
|
|
PosUpdate.p.heading = Utils.EQ19ToFloat((Int32)((Word3) & 0xFFF));
|
|
|
|
PosUpdate.HighRes = false;
|
|
|
|
return PosUpdate;
|
|
}
|
|
}
|
|
} |