Files
eqemu-server/common/patches/tob_structs.h
T
dannuic 168995a5b5
Build / Linux (push) Has been cancelled
Build / Windows (push) Has been cancelled
Full Packet Review for Known Conversion (#5100)
2026-06-07 00:12:57 -07:00

1309 lines
38 KiB
C++
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
/* EQEmu: EQEmulator
Copyright (C) 2001-2026 EQEmu Development Team
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#pragma once
#include "common/eq_packet_structs.h"
#include "common/skills.h"
namespace TOB {
namespace structs {
// constants
static const uint32 MAX_PP_AA_ARRAY = 300;
static const uint32 MAX_PP_SKILL = PACKET_SKILL_ARRAY_SIZE;
static const uint32 MAX_PP_INNATE_SKILL = 25;
static const uint32 MAX_PP_DISCIPLINES = 300;
static const uint32 MAX_PP_COMBAT_ABILITY_TIMERS = 25;
static const uint32 MAX_PP_UNKNOWN_ABILITIES = 25;
static const uint32 MAX_RECAST_TYPES = 25;
static const uint32 MAX_ITEM_RECAST_TYPES = 100;
static const uint32 BLOCKED_BUFF_COUNT = 60; // this might not be needed?
static const uint32 BUFF_COUNT = 62;
static const uint32 MAX_PP_LANGUAGE = 32;
#pragma pack(1)
struct LoginInfo_Struct {
/*000*/ char login_info[64];
/*064*/ uint8 unknown064[124];
/*188*/ uint8 zoning; // 01 if zoning, 00 if not
/*189*/ uint8 unknown189[275];
/*488*/
};
struct ClientZoneEntry_Struct {
/*00*/ uint32 unknown00; // ***Placeholder
/*04*/ char char_name[64]; // Player firstname [32]
/*68*/ uint32 unknown68;
/*72*/ uint32 unknown72;
/*76*/ uint32 unknown76;
/*80*/ uint32 unknown80;
/*84*/ uint32 unknown84;
/*88*/ uint32 unknown88;
/*92*/
};
struct Membership_Struct
{
/*000*/ uint8 membership; //0 not gold, 2 gold
/*001*/ uint32 races; // Seen ff ff 01 00
/*005*/ uint32 classes; // Seen ff ff 01 00
/*009*/ uint32 entrysize; // Seen 33
/*013*/ int32 entries[33]; // Most -1, 1, and 0 for Gold Status
/*145*/
};
struct Membership_Entry_Struct
{
/*000*/ uint32 purchase_id; // Seen 1, then increments 90287 to 90300
/*004*/ uint32 bitwise_entry; // Seen 16 to 65536 - Skips 4096
/*008*/
};
struct Membership_Setting_Struct
{
/*000*/ int8 setting_index; // 0, 1, 2 or 3: f2p, silver, gold, platinum?
/*001*/ int32 setting_id; // 0 to 23 actually seen but the OP_Membership packet has up to 32
/*005*/ int32 setting_value;
/*009*/
};
struct Membership_Details_Struct
{
/*000*/ uint32 membership_setting_count; // Seen 96
/*004*/ Membership_Setting_Struct settings[96]; // 864 Bytes
/*364*/ uint32 race_entry_count; // Seen 17
/*368*/ Membership_Entry_Struct membership_races[17]; // 136 Bytes
/*3f0*/ uint32 class_entry_count; // Seen 15
/*3f4*/ Membership_Entry_Struct membership_classes[17]; // 136 Bytes
/*47c*/ uint32 exit_url_length; // Length of the exit_url string (0 for none)
/*480*/ //char exit_url[42]; // Upgrade to Silver or Gold Membership URL
};
struct MaxCharacters_Struct {
/*000*/ uint32 total_character_slots; // total character slots, different than max characters
/*004*/ uint32 marketplace_character_slots;
/*008*/ uint32 unknown008; // definitely 4 bytes, read in client, value for CEverQuest::Unknown0x0608
/*00c*/ uint8 head_start_button;
/*00d*/ uint8 unused00d;
/*00e*/ uint16 heroic_related;
/*010*/ int64 heroic_50_count; // read as 64 bits in the client
/*018*/ int32 heroic_100_count;
/*01c*/ uint8 disable_character_creation;
/*01d*/ uint8 unused01d[3];
/*020*/ int32 monthly_claim; // (-1 for don't set)
/*024*/ uint8 marketplace_related; // marketplace related boolean (int32 for convenience here, it's 4 bytes)
/*025*/ uint8 unused025[3];
/*028*/ int32 unused028;
/*02c*/ uint8 add_marketplace_chars; // boolean on whether to add or set marketplace characters
/*02d*/ uint8 add_unknown; // boolean on whether to add unknown008 or set marketplace characters to some unknown global
/*02e*/ uint8 legacy_characters_ruleset;
/*02f*/ uint8 unused02f;
/*030*/ int32 num_max_characters; // used for legacy exp calculation
/*034*/ int32 num_personas_available;
/*038*/ int32 has_de_ranger;
/*03c*/
};
struct ExpansionInfo_Struct {
/*000*/ char Unknown000[64];
/*064*/ uint64 Expansions;
};
/*
* Visible equipment.
* Size: 20 Octets
*/
struct Texture_Struct
{
uint32 Material; // type
uint32 Unknown1; // material
uint32 EliteMaterial; // variation
uint32 HeroForgeModel; // new armor ID
uint32 Material2; // new armor type
};
/*
** Color_Struct
** Size: 4 bytes
** Used for convenience
** Merth: Gave struct a name so gcc 2.96 would compile
**
*/
struct Tint_Struct
{
union {
struct {
uint8 Blue;
uint8 Green;
uint8 Red;
uint8 UseTint; // if there's a tint this is FF
};
uint32 Color;
};
};
struct CharSelectEquip : Texture_Struct, Tint_Struct {};
struct CharacterSelectEntry_Struct
{
char Name[1];
uint32 Class;
uint32 Race;
uint8 Level;
uint32 ShroudClass;
uint32 ShroudRace;
uint16 Zone;
uint16 Instance;
uint8 Gender;
uint8 Face;
CharSelectEquip Equip[9];
uint8 TextureType; //Seen 256
uint8 HeadType; //Seen 0
uint32 DrakkinTattoo; // tattoo index
uint32 DrakkinDetails; // face attachment index
uint32 Deity;
uint32 PrimaryIDFile;
uint32 SecondaryIDFile;
uint8 HairColor;
uint8 BeardColor;
uint8 EyeColor1;
uint8 EyeColor2;
uint8 HairStyle;
uint8 Beard;
uint8 GoHome;
uint8 Tutorial;
uint32 DrakkinHeritage; // parent ID
uint8 TooHighLevel;
uint8 PreFTP;
uint32 LastLogin;
uint8 Usable;
uint16 Shrouded;
uint8 Unknown;
uint64 CharacterId; // A Guess, Character I made a little bit after has a number a few hundred after the first
};
/*
** Character Selection Struct
**
*/
struct CharacterSelect_Struct
{
/*000*/ uint32 CharCount; //number of chars in this packet
};
/*
** Character Creation struct
** Length: 168 Bytes
** OpCode: 0x1859
*/
struct CharCreate_Struct
{
/*00*/ uint8 padding[72];
/*48*/ uint32 gender;
/*4c*/ uint32 race;
/*50*/ uint32 class_;
/*54*/ uint32 deity;
/*58*/ uint32 start_zone; // this is the zone ID of the start zone
/*5c*/ uint32 haircolor;
/*60*/ uint32 beard;
/*64*/ uint32 beardcolor;
/*68*/ uint32 hairstyle;
/*6c*/ uint32 face;
/*70*/ uint32 eyecolor1;
/*74*/ uint32 eyecolor2;
/*78*/ uint32 drakkin_heritage;
/*7c*/ uint32 drakkin_tattoo;
/*80*/ uint32 drakkin_details;
/*84*/ uint32 STR;
/*88*/ uint32 STA;
/*8c*/ uint32 AGI;
/*90*/ uint32 DEX;
/*94*/ uint32 WIS;
/*98*/ uint32 INT;
/*9c*/ uint32 CHA;
/*a0*/ uint32 tutorial;
/*a4*/ uint32 heroic_type;
/*a8*/
};
struct NameApproval_Struct {
char name[64];
uint32 race_id;
uint32 class_id;
uint32 deity_id;
uint32 heroic_type; // seen 0, client can also send 1-4
uint32 unknown; // always 0?
};
enum TOBAppearance : uint32
{
None,
WhoLevel,
MaxHealth,
Invisibility,
PVP,
Light,
Animation,
Sneak,
SpawnID,
Health,
Linkdead,
FlyMode,
GM,
Anonymous,
GuildID,
AFK,
Pet,
Summoned,
Unknown18,
Unknown19,
SetType,
NPCName,
CancelSneakHide,
AreaHealthRegen,
AreaManaRegen,
AreaEnduranceRegen,
FreezeBeneficialBuffs,
NPCTintIndex,
Unknown28,
Unknown29,
Unknown30,
ShowHelm,
DamageState,
Unknown33, //Some virtual function call; based on location might be EQPlayers (my guess personally) or FindBits
TextureType, //Texture ID
Unknown35,
Unknown36,
GuildShow,
OfflineMode,
Unknown39,
Unknown40,
Unknown41,
Birthdate,
EncounterLock
};
struct SpawnAppearance_Struct
{
/*0000*/ uint32 spawn_id; // ID of the spawn
/*0004*/ uint32 type; // Values associated with the type
/*0008*/ uint64 parameter; // Type of data sent
/*0016*/ uint64 lock_id; //the only place client uses this as far as I can tell is when you send 0x2c as type in which case it sets LockID = this
/*0024*/
};
struct ChangeSize_Struct
{
/*00*/ uint32 EntityID;
/*04*/ float Size;
/*08*/ float CameraOffset;
/*12*/ float AnimationSpeedRelated;
/*16*/
};
struct Spawn_Struct_Bitfields
{
union {
struct {
// byte 1
/*00*/ unsigned gender : 2; // Gender (0=male, 1=female, 2=monster)
/*02*/ unsigned ispet : 1; // Guessed based on observing live spawns
/*03*/ unsigned afk : 1; // 0=no, 1=afk
/*04*/ unsigned anon : 2; // 0=normal, 1=anon, 2=roleplay
/*06*/ unsigned gm : 1;
/*07*/ unsigned sneak : 1;
// byte 2
/*08*/ unsigned lfg : 1;
/*09*/ unsigned unk9 : 1;
/*10*/ unsigned invis : 12; // there are 3000 different (non-GM) invis levels
/*22*/ unsigned linkdead : 1; // 1 Toggles LD on or off after name. Correct for RoF2
/*23*/ unsigned showhelm : 1;
// byte 4
/*24*/ unsigned betabuffed : 1; // Prefixes name with !
/*25*/ unsigned trader : 1;
/*26*/ unsigned animationonpop : 1;
/*27*/ unsigned targetable : 1;
/*28*/ unsigned targetable_with_hotkey : 1;
/*29*/ unsigned showname : 1;
/*30*/ unsigned idleanimationsoff : 1; // what we called statue?
/*31*/ unsigned untargetable : 1; // bClickThrough
// byte 5
/*32*/ unsigned buyer : 1;
/*33*/ unsigned offline : 1;
/*34*/ unsigned interactiveobject : 1;
/*35*/ unsigned missile : 1;
/*36*/ unsigned title : 1;
/*37*/ unsigned suffix : 1;
/*38*/ unsigned unk38 : 1;
/*39*/ unsigned unk39 : 1;
};
uint8 raw[5];
};
};
struct Spawn_Struct_Position
{
union {
struct {
signed deltaHeading : 10;
signed animation : 10;
unsigned pad1 : 12;
signed deltaX : 13;
signed z : 19;
signed y : 19;
unsigned heading : 12;
unsigned pad2 : 1;
signed x : 19;
signed deltaZ : 13;
unsigned pitch : 12;
signed deltaY : 13;
unsigned pad3 : 7;
};
uint32_t raw[5];
};
};
struct Client_Position
{
/*0x00*/ float y;
/*0x04*/ float delta_y;
/*0x08*/ float x;
/*0x0c*/ int animation : 10;
signed padding1 : 22;
/*0x10*/ float delta_x;
/*0x14*/ float z;
/*0x18*/ float delta_z;
/*0x1c*/ int heading : 12;
int pitch : 12;
signed padding2 : 8;
/*0x20*/ int delta_heading : 10;
signed padding3 : 22;
/*0x24*/
};
struct PlayerPositionUpdateServer_Struct
{
/*00*/ uint16 spawn_id;
/*02*/ uint16 vehicle_id;
/*04*/ Spawn_Struct_Position position;
/*24*/
};
struct PlayerPositionUpdateClient_Struct {
/*00*/ uint16 sequence;
/*02*/ uint16 spawn_id;
/*04*/ uint16 vehicle_id;
/*06*/ Client_Position position;
/*38*/
};
struct Door_Struct
{
/*000*/ char name[32];
/*032*/ float DefaultY;
/*036*/ float DefaultX;
/*040*/ float DefaultZ;
/*044*/ float DefaultHeading;
/*048*/ uint32 DefaultDoorAngle; //rof2's incline
/*052*/ float Y; //most (all I've seen?) doors match the defaults here
/*056*/ float X;
/*060*/ float Z;
/*064*/ float Heading;
/*068*/ float DoorAngle;
/*072*/ uint32 ScaleFactor; //rof2's size
/*076*/ uint32 Unknown76; //client doesn't seem to read this
/*080*/ uint8 Id; //doorid
/*081*/ uint8 Type; //opentype
/*082*/ uint8 State; //state_at_spawn
/*083*/ uint8 DefaultState; //invert_state
/*084*/ int32 Param; //door_param (spell id?)
/*088*/ uint32 AdventureDoorId;
/*092*/ uint32 DynDoorID;
/*096*/ uint32 RealEstateDoorID;
/*100*/ uint8 bHasScript;
/*101*/ uint8 bUsable; //1 if clickable
/*102*/ uint8 bRemainOpen;
/*103*/ uint8 bVisible; //1 is visible
/*104*/ uint8 bHeadingChanged;
/*105*/ uint8 padding1[3];
/*108*/ float TopSpeed1;
/*112*/ float TopSpeed2;
/*116*/ uint8 bNeedsTimeStampSet;
/*117*/ uint8 padding2[3];
/*120*/ float unknownFloat1;
/*124*/ float unknownFloat2;
/*128*/ uint8 unknownByte1;
/*129*/ uint8 padding3[3];
/*132*/
};
struct ZonePoint_Entry {
/*00*/ uint32 iterator;
/*04*/ float y;
/*08*/ float x;
/*12*/ float z;
/*16*/ float heading;
/*20*/ uint16 zoneid;
/*22*/ uint16 zoneinstance;
/*24*/ uint32 unknown024;
/*28*/ uint32 unknown028;
/*32*/
};
struct ZonePoints {
/*00*/ uint32 count;
/*04*/ struct ZonePoint_Entry zpe[0]; // Always add one extra to the end after all zonepoints
};
struct EnterWorld_Struct {
/*000*/ char name[64];
/*064*/ int32 unknown1; // this appears to always be 0
/*068*/ int32 zoneID; // this is -1 for "last zone"
};
struct ZoneChange_Struct {
/*000*/ char char_name[64]; // Character Name
/*064*/ uint16 zoneID;
/*066*/ uint16 instanceID;
/*068*/ uint32 Unknown068;
/*072*/ uint32 Unknown072;
/*076*/ float y;
/*080*/ float x;
/*084*/ float z;
/*088*/ uint32 zone_reason; //0x0A == death, I think
/*092*/ int32 success; // =0 client->server, =1 server->client, -X=specific error
/*096*/ uint32 Unknown096; // Not sure the extra 4 bytes goes here or earlier in the struct.
/*100*/
};
struct RequestClientZoneChange_Struct {
/*000*/ uint16 zone_id;
/*002*/ uint16 instance_id;
/*004*/ uint32 unknown004;
/*008*/ float y;
/*012*/ float x;
/*016*/ float z;
/*020*/ float heading;
/*024*/ uint32 type; //unknown... values
/*032*/ uint8 unknown032[144]; // this is mostly a string passed to the teleport function (follow starting at 0x1401F71BA), it appears to be an override for a message
/*172*/ uint32 unknown172;
/*176*/
};
struct Weather_Struct {
/*000*/ uint32 val1; // 0xFF = clear weather
/*004*/ uint32 type; // 0x31=rain, 0x02=snow, 0=normal
/*008*/ uint32 unknown; // TOB wire padding; client skips this offset
/*012*/ uint32 mode; // server struct's mode field, shifted to +0x0C on TOB
/*016*/
};
struct WearChange_Struct {
/*000*/ uint32 spawn_id;
/*004*/ uint32 wear_slot_id;
/*008*/ uint32 armor_id;
/*012*/ uint32 variation;
/*016*/ uint32 material;
/*020*/ uint32 new_armor_id;
/*024*/ uint32 new_armor_type;
/*028*/ uint32 color;
/*032*/
};
struct Who_All_Struct {
/*000*/ char whom[64];
/*064*/ uint8 unknown064[64]; // always zero
/*128*/ uint32 wrace; // 0xFFFFFFFF = any race
/*132*/ uint32 wclass; // 0xFFFFFFFF = any class
/*136*/ uint32 lvllow; // 0xFFFFFFFF = any level
/*140*/ uint32 lvlhigh; // 0xFFFFFFFF = any level
/*144*/ uint32 gmlookup; // 0xFFFFFFFF = not filtering by GM
/*148*/ uint32 guildid_flag; // 0xFFFFFFFF = no special filter; 0x7FC00000 = guild/trader/buyer active
/*152*/ uint32 guildid; // actual guild ID for /who guild, else 0
/*156*/ uint32 unknown09C; // always 0
/*160*/ uint32 type; // 0 = /who, 3 = /who all
/*164*/ uint8 unknown0A4[12]; // padding
/*176*/
};
struct ExpUpdate_Struct
{
/*000*/ uint64 exp; // This is exp % / 1000 now; eg 69250 = 69.25%
/*008*/ uint64 unknown; // if this is the value "2", it opens up the tip window
};
struct DeleteSpawn_Struct
{
/*00*/ uint32 spawn_id; // Spawn ID to delete
/*04*/ uint8 Decay; // Seen 1
/*05*/
};
//OP_SetServerFilter
struct SetServerFilter_Struct {
uint32 filters[69];
};
// Was new to RoF2, doesn't look changed
// The padding is because these structs are padded to the default 4 bytes
struct InventorySlot_Struct
{
/*000*/ int32 Type;
/*004*/ int16 Slot;
/*006*/ int16 SubIndex;
/*008*/ int16 AugIndex;
/*010*/ int16 Padding2;
/*012*/
};
// Was new for RoF2 - Used for Merchant_Purchase_Struct, doesn't look changed
// Can't sellfrom other than main inventory so Slot Type is not needed.
// There is in general no padding for this, but sometimes a pad will be added
struct TypelessInventorySlot_Struct
{
/*000*/ int16 Slot;
/*002*/ int16 SubIndex;
/*004*/ int16 AugIndex;
/*006*/
};
struct Consider_Struct {
/*000*/ uint32 playerid; // PlayerID
/*004*/ uint32 targetid; // TargetID
/*008*/ uint32 faction; // Faction
/*012*/ uint32 level; // Level
/*016*/ uint32 report_mode; // 0 normally, 4 will do a more detailed report that only works if you have GM flag set
/*020*/ uint8 rare_creature; // Will do the rare creature string
/*021*/ uint8 loot_locked; // Will list the target as (loot locked)
/*022*/ uint8 unknown022; // Padding probably
/*023*/ uint8 unknown023; // Padding probably
/*024*/
};
struct Consume_Struct
{
/*000*/ InventorySlot_Struct slot; // ItemGlobalIndex: Type(4)+Slot(2)+SubIndex(2)+AugIndex(2)+Pad(2)
/*012*/ uint32 unknown; // always 0xFFFFFFFF on wire
/*016*/ uint8 type; // 0=Food, 1=Water (server expects 1=Food, 2=Water)
/*017*/ uint8 mode; // 0=auto-consume, 1=right-click
/*018*/ uint8 pad[2];
/*020*/
};
struct SpawnHPUpdate_Struct
{
/*00*/ int16 spawn_id;
/*02*/ int64 cur_hp;
/*10*/ int64 max_hp;
/*18*/
};
struct ClickDoor_Struct {
/*00*/ uint16 player_id;
/*02*/ uint8 padding1[2];
/*04*/ uint32 item_id;
/*08*/ uint32 picklockskill;
/*12*/ uint8 doorid;
/*13*/ uint8 padding2[3];
};
/*
Flags for special:
WildRampage: 0x1
Rampage: 0x2
NoCastOnText: 0x4
DoubleBowShot: 0x8
UnknownSpellFlag: 0x10 // display flag of some sort, setting to 1 calls DisplayChatText
Flurry: 0x20
Riposte: 0x40
Critical: 0x80
Lucky: 0x100
FinishingBlow: 0x200
CripplingBlow: 0x400
Assassinate: 0x800
DeadlyStrike: 0x1000
SlayUndead: 0x2000
Headshot: 0x4000
Strikethrough: 0x8000
LuckyRiposte: 0x10000
Twincast: 0x20000
ShieldBlock: 0x40000
StaffBlock: 0x80000
Locked: 0x100000
Might be more flags beyond this but I'm not sure
*/
struct CombatDamage_Struct
{
/*000*/ uint16 target;
/*002*/ uint16 source;
/*004*/ uint32 unknown1; // not read by the client
/*008*/ int64 damage;
/*016*/ uint32 special; // flags; will document above
/*020*/ int32 spellid;
/*024*/ uint32 spell_level; // spell caster level (unconfirmed; it is used for the spell link)
/*028*/ float force;
/*032*/ float hit_heading;
/*036*/ float hit_pitch;
/*040*/ uint8 type; // skill
/*041*/ uint8 isoffhand; // used for determining skill used for message
/*042*/ uint8 padding[2];
/*044*/ uint32 unknown2; // not read by the client
/*048*/
};
struct EnvDamage2_Struct {
/*0000*/ uint16 entity_id; // spawn ID of entity taking damage (self)
/*0002*/ uint16 unknown2; // source/attacker spawn_id; 0 for environmental
/*0004*/ int32 spell_id; // spell causing damage; -1 or 0 = none
/*0008*/ uint64 unknown8;
/*0010*/ int64 damage; // damage amount
/*0018*/ uint64 unknown18;
/*0020*/ uint64 unknown20;
/*0028*/ float unknown28;
/*002C*/ uint32 unknown2C;
/*0030*/ uint32 unknown30;
/*0034*/ uint32 unknown34;
/*0038*/ uint8 dmgtype; // 0xFA=Lava, 0xFB=Drowning, 0xFC=Falling, 0xFD=Trap
/*0039*/ uint8 unknown39;
};
struct Animation_Struct {
/*00*/ uint16 spawnid;
/*02*/ uint8 action;
/*03*/ uint8 speed;
/*04*/
};
struct Death_Struct
{
/*000*/ uint32 spawn_id;
/*004*/ uint32 killer_id;
/*008*/ uint32 corpseid;
/*012*/ uint32 unknown1; //not read by client
/*016*/ int32 spell_id;
/*020*/ uint32 attack_skill;
/*024*/ uint64 damage;
/*032*/ uint32 unknown2; //not read by client
/*036*/ uint32 unknown3; //not read by client
/*040*/
};
struct DeleteItem_Struct
{
/*0000*/ InventorySlot_Struct from_slot;
/*0012*/ InventorySlot_Struct to_slot;
/*0024*/ uint32 number_in_stack;
/*0028*/
};
struct MoveItem_Struct
{
/*0000*/ InventorySlot_Struct from_slot;
/*0012*/ InventorySlot_Struct to_slot;
/*0024*/ uint32 number_in_stack;
/*0028*/
};
struct ItemRecastDelay_Struct
{
/*000*/ InventorySlot_Struct item_slot; // zeroed until server struct gains item slot fields
/*012*/ uint32 recast_delay; // seconds until item can be used again
/*016*/ uint32 recast_type; // recast group (1..99); SetCoreItemRecastTimer
/*020*/
};
struct ItemVerifyRequest_Struct
{
/*000*/ InventorySlot_Struct inventory_slot; // ItemGlobalIndex: Type(+0 int32) Slot(+4) SubIndex(+6) AugIndex(+8) Pad(+10)
/*012*/ uint32 target; // Target entity ID (g_pTargetPlayer+0x168), or 0
/*016*/
};
struct ItemVerifyReply_Struct
{
/*000*/ int32 slot; // Right-clicked slot (passed as ItemGlobalIndex* to GetItemByGlobalIndex)
/*004*/ uint32 spell; // Spell ID; client reads lower 16 bits; 0x407 triggers autobook-scribe
/*008*/ uint32 target; // Target Entity ID
/*012*/ int32 unknown0; // Exit gate: handler skips if < 0; send 0
/*016*/ int32 recast_time; // fasttime() timestamp for autobook-scribe path (spell==0x407); send 0
/*020*/
};
struct MerchantClickRequest_Struct
{
/*000*/ uint32 npc_id; // Merchant NPC's entity id
/*004*/
};
struct MerchantClickResponse_Struct
{
/*000*/ uint32 npc_id; // Merchant NPC's entity id
/*004*/ uint32 player_id;
/*008*/ float rate;
/*012*/ uint32 tab_display; // bitmask b000 none, b001 Purchase/Sell, b010 Recover, b100 Parcels
/*016*/ uint32 ldon_category; // ldon cat for ldon merchants
/*020*/ uint32 alt_currency1; //These two usually match but I imagine they could be different?
/*024*/ uint32 alt_currency2;
/*028*/ uint32 unknown028; // Observed 256
/*032*/
};
struct BeginCast_Struct
{
/*000*/ int32 spell_id;
/*004*/ uint16 caster_id;
/*006*/ uint32 cast_time; // in miliseconds
/*010*/ uint32 unknown0a; // I think this is caster effective level but im not sure. live always sends 0. The client uses this for the spell link
/*014*/ uint8 unknown0e; // 0 will short circuit the cast, seen 1 from live usually, maybe related to interrupts or particles or something
/*015*/
};
// Used for OP_ReadBook in both directions (S→C text display, C→S content request).
// IDA-confirmed layout: type+target_id precede invslot (differs from RoF2 ordering).
struct BookRequest_Struct
{
/*0000*/ uint32 window; // 0xFFFFFFFF = new window; maps from emu->window (0xFF)
/*0004*/ uint32 type; // 0=note/scroll, 1=book, 2=item info
/*0008*/ uint32 target_id;
/*0012*/ TypelessInventorySlot_Struct invslot;
/*0018*/ uint8 padding;
/*0019*/ uint8 can_cast;
/*0020*/ uint8 can_scribe; // book-path cast button; note-path scribe button
/*0021*/ char txtfile[8194]; // null-terminated text / book file name
/*8215*/
};
struct BookButton_Struct
{
/*000*/ TypelessInventorySlot_Struct slot; // book ItemIndex
/*006*/ int16 unknown2; // zero padding
/*008*/ int32 target_id; // spawn_id of target player or 0
/*012*/ int32 unknown3; // zero padding
/*016*/
};
struct MemorizeSpell_Struct {
uint32 slot; // Spot in the spell book/memorized slot
int32 spell_id; // Spell id (200 or c8 is minor healing, etc)
uint32 scribing; // -1 refreshes book, 0 scribe to book, 2 end mem, 1 start mem, 3 unmem, 4 set activated item keyring -- client will send back 2 if a 0 operation updated a memorized spell of the same group + subgroup
uint32 reduction; // lower reuse (only used if scribing is 4)
};
struct LinkedSpellReuseTimer_Struct {
uint32 timer_id; // +0x00 linked spell group index (024)
uint32 unknown; // +0x04 extra DWORD present in TOB/TDS+ clients
uint32 end_time; // +0x08 absolute time when spell group is ready
uint32 start_time; // +0x0C server send timestamp (for client latency correction)
};
//I've observed 5 s16 that are all -1.
//Clicky items don't even trigger this as far as i can tell so not sure what this is for now.
//One of these could have changed to a s32 but im not sure.
struct CastSpellInventorySlot_Struct {
/*00*/ int16 type;
/*02*/ int16 slot;
/*04*/ int16 sub_index;
/*06*/ int16 aug_index;
/*08*/ int16 unknown1;
/*10*/
};
struct CastSpell_Struct
{
/*00*/ uint32 slot;
/*04*/ int32 spell_id;
/*08*/ CastSpellInventorySlot_Struct inventory_slot;
/*18*/ uint32 target_id;
/*22*/ uint32 spell_crc;
/*26*/ float y_pos;
/*30*/ float x_pos;
/*34*/ float z_pos;
/*38*/ uint8 unknown; //not sure, might also be before y_pos; only ever seen zero for both but should be easy to figure out later
/*39*/
};
struct Charm_Struct
{
/*00*/ uint32 owner_id;
/*04*/ uint32 pet_id;
/*08*/ uint32 charmer_id; // TOB-only field not present in server Charm_Struct; purpose unknown (passed to sub_1402FA570 when non-null); set to 0
/*0C*/ uint8 command; // 1=make pet, 0=release pet; server sends this as uint32 at +0x08
/*0D*/
};
struct InterruptCast_Struct
{
uint32 spawnid;
uint32 messageid;
char message[0];
};
struct EQAffectSlot_Struct {
/*00*/ int32 slot;
/*04*/ int32 padding;
/*08*/ int64 value;
/*16*/
};
struct EQAffect_Struct
{
/*000*/ EQAffectSlot_Struct slots[6];
/*096*/ EqGuid caster_id;
/*104*/ uint32 flags;
/*108*/ int32 spell_id;
/*112*/ uint32 duration;
/*116*/ uint32 initial_duration;
/*120*/ uint32 hit_count;
/*124*/ uint32 viral_timer;
/*128*/ float modifier;
/*132*/ float y;
/*136*/ float x;
/*140*/ float z;
/*144*/ uint8 type;
/*145*/ uint8 level;
/*146*/ uint8 charges; //no idea if these are right; eqlib doesn't seem to know either
/*147*/ uint8 activatable;
/*148*/ uint32 unknown1; //might be some timer, not sure though
/*152*/
};
struct EQAffectPacket_Struct {
/*000*/ uint32 entity_id;
/*004*/ int32 unknown004;
/*008*/ EQAffect_Struct affect;
/*160*/ uint32 slot_id;
/*164*/ uint32 buff_fade; // 1: remove, 2: modify, 3: add new
/*168*/
};
struct ManaChange_Struct
{
uint32 new_mana;
uint32 stamina; // endurance
int32 spell_id;
uint32 keepcasting;
int32 slot; // gem slot
};
//This is what we call OP_Action
//To the client though this is basically a missile hit though
//OP_Action is basically "instant missile hit" to the client
//@0x1402024C0 MissileHitInfo::Deserialize(CUnSerializeBuffer *buffer);
struct MissileHitInfo
{
uint16 target;
uint16 source;
int32 spell_id;
//4 leaves a buff
uint32 effect_type;
uint32 effective_casting_level;
//Client does read this but only does something if it's negative
int64 unknown1;
//I don't see the client read this one outside basic serialization
int64 unknown2;
//I don't see the client read this one either but based on captures from live it seems to match spell damage
int64 damage;
float modifier;
float force;
float hit_heading;
float hit_pitch;
//same convention as damage
//231 for spell, otherwise it's skill in use
uint8 skill;
uint8 level; //the client doesn't actually deserialize anything past level
//live however has a lot more info here depending on packet type
};
struct MobHealth_Struct
{
/*01*/ int16 spawn_id;
/*00*/ uint32 hp;
};
struct GMTrainee_Struct
{
/*000*/ uint32 npcid;
/*004*/ uint32 playerid;
/*008*/ uint32 skills[PACKET_SKILL_ARRAY_SIZE];
/*408*/ uint8 unknown408[36];
/*444*/
};
struct GMTrainSkillConfirm_Struct {
/*000*/ uint32 SkillID;
/*004*/ uint32 Cost;
/*008*/ uint8 NewSkill; // Set to 1 for 'You have learned the basics' message.
/*009*/ char TrainerName[64];
/*073*/ uint8 Unknown073[3];
/*076*/
};
struct SkillUpdate_Struct {
/*00*/ uint32 skillId;
/*04*/ uint32 value;
/*08*/ uint8 active;
/*09*/ uint8 padding[3];
/*12*/
};
struct AA_Array
{
uint32 AA;
uint32 value; // points spent
uint32 charges; // expendable charges
};
struct AATable_Struct {
/*00*/ uint32 aa_spent; // Total AAs Spent
/*04*/ uint32 aapoints_assigned[6]; // none, general, arch, class, special, focus, merc
/*24*/ AA_Array aa_list[MAX_PP_AA_ARRAY];
};
struct AltAdvStats_Struct {
/*000*/ uint32 experience;
/*004*/ uint32 unspent;
/*008*/ uint8 percentage;
/*009*/ uint8 padding[3];
};
struct ZonePlayerToBind_Struct {
//Same structure as the binds in PlayerProfile_Struct
//Assembly calls the same function
/*000*/ uint16 bind_zone_id;
/*002*/ uint16 bind_instance_id;
/*004*/ float x;
/*008*/ float y;
/*012*/ float z;
/*016*/ float heading;
/*020*/ char zone_name[1]; // Or "Bind Location"
/*021*/ uint32 unknown1;
/*025*/ uint32 unknown2;
/*029*/ uint32 unknown3;
};
struct ArmorPropertyStruct
{
/*000*/ uint32 type;
/*004*/ uint32 variation;
/*008*/ uint32 material;
/*012*/ uint32 newArmorID;
/*016*/ uint32 newArmorType;
/*020*/
};
struct Illusion_Struct {
/*000*/ uint32 spawnid;
/*004*/ char charname[64];
/*068*/ int32 race;
/*072*/ int32 class_;
/*076*/ float size;
/*080*/ uint32 face;
/*084*/ uint32 npc_tint;
/*088*/ uint32 keep_armor_properties;
/*092*/ uint32 drakkin_heritage;
/*096*/ uint32 drakkin_tattoo;
/*100*/ uint32 drakkin_details;
/*104*/ uint8 gender;
/*105*/ uint8 texture;
/*106*/ uint8 helmtexture;
/*107*/ uint8 armorVariation;
/*108*/ uint8 armorMaterial;
/*109*/ uint8 hairstyle;
/*110*/ uint8 haircolor;
/*111*/ uint8 beard;
/*112*/ uint8 beardcolor;
/*113*/ uint8 padding[3];
/*116*/ ArmorPropertyStruct armorProperties[9];
/*296*/ uint32 armorTints[9];
/*332*/
};
struct IncreaseStat_Struct {
/*000*/ uint32 spawn_id; // must equal g_pLocalPlayer->SpawnID; not in server struct (see encoder TODO)
/*004*/ uint32 stat_type; // 0=STR 1=STA 2=AGI 3=DEX 4=INT 5=WIS 6=CHA; client ignores > 6
/*008*/ uint32 value; // must be > 0 to be applied
/*012*/
};
struct moneyOnCorpseStruct {
/*000*/ uint8 type; // 0 = someone is already looting, 1 = OK, 2 = cannot access at this time, 3 = OK, 4 = cannot loot while hostile nearby, 5 = too far away to loot, 6 = loot all, 7 = cancel loot, 8 = add access, 9 = using advloot (when right clicking), 10 = show advloot
/*001*/ uint8 padding1[3];
/*004*/ uint32 flags; // 1 = extra lucky bonus, 2 = lucky bonus, 4 = bonus
/*008*/ uint32 platinum;
/*012*/ uint32 gold;
/*016*/ uint32 silver;
/*020*/ uint32 copper;
/*024*/
};
struct LootingItem_Struct {
/*000*/ uint32 lootee;
/*004*/ uint32 looter;
/*008*/ uint32 slot_id;
/*012*/ int32 auto_loot;
/*016*/ uint32 unknown16;
/*020*/
};
struct GroupGeneric_Struct {
/*0000*/ char name1[64];
/*0064*/ char name2[64];
/*0128*/ uint32 unknown0128;
/*0132*/ uint32 unknown0132;
/*0136*/ uint32 unknown0136;
/*0140*/ uint32 unknown0140;
/*0144*/ uint32 unknown0144;
/*0148*/ uint32 unknown0148;
/*0152*/ uint16 unknown0152;
/*0154*/ uint8 unknown0154[14];
/*0168*/
};
// TOB pick pocket wire format (S→C and C→S identical layout).
// coin sits at unaligned offset 0x0D; valid under pack(1).
struct PickPocket_Struct {
/*0x00*/ uint32 to;
/*0x04*/ uint32 from;
/*0x08*/ uint32 myskill;
/*0x0C*/ uint8 type;
/*0x0D*/ uint32 coin;
/*0x11*/ uint32 nameLen;
// char name[nameLen] follows, then uint8 luckily
/*0x15*/
};
struct AugmentInfo_Struct
{
/*000*/ uint32 itemid; // id of the solvent needed
/*004*/ uint32 window; // window to display the information in
/*008*/ char augment_info[64]; // total packet length 80, all the rest were always 00
/*072*/ uint32 unknown072; // seen 0, 56
/*076*/ uint32 unknown076; // seen 8, 3, 11, always matches what client sends
/*080*/
};
//seems to be unchanged from rof2?
//it's the same size at least
struct AugmentItem_Struct {
/*00*/ uint32 dest_inst_id; // The unique serial number for the item instance that is being augmented
/*04*/ uint32 container_index; // Seen 0
/*08*/ InventorySlot_Struct container_slot; // Slot of the item being augmented
/*20*/ uint32 augment_index; // Seen 0
/*24*/ InventorySlot_Struct augment_slot; // Slot of the distiller to use (if one applies)
/*36*/ int32 augment_action; // Guessed - 0 = augment, 1 = remove with distiller, 3 = delete aug
/*36*/ //int32 augment_slot;
/*40*/
};
struct ApplyPoison_Struct
{
InventorySlot_Struct inventorySlot;
uint32 success;
};
/*
** Click Object Acknowledgement Struct
** Response to client clicking on a World Container (ie, forge)
** Seems to have not changed from RoF2
*/
struct ClickObjectAction_Struct {
/*00*/ //uint32 player_id; // Appears to have been removed
/*00*/ uint32 drop_id; // Appears to use the object_count field now
/*04*/ int32 unknown04; // Seen -1
/*08*/ int32 unknown08; // Seen -1
/*08*/ //uint32 open; // 1=opening, 0=closing - Removed?
/*12*/ uint32 type; // See object.h, "Object Types"
/*16*/ uint32 unknown16; //
/*20*/ uint32 icon; // Icon to display for tradeskill containers
/*24*/ uint32 unknown24; //
/*28*/ char object_name[64]; // Object name to display
/*92*/
};
// Server→Client (38 bytes): container_slot serialized without Padding2 to match client deserializer
struct RecipeAutoCombine_Struct {
/*00*/ uint32 object_type;
/*04*/ uint32 some_id;
/*08*/ int32 container_type; // InventorySlot.Type
/*12*/ int16 container_slot_index; // InventorySlot.Slot
/*14*/ int16 container_subindex; // InventorySlot.SubIndex
/*16*/ int16 container_augindex; // InventorySlot.AugIndex
/*18*/ InventorySlot_Struct unknown_slot; // 12 bytes; echoed in reply
/*30*/ uint32 recipe_id;
/*34*/ uint32 reply_code;
/*38*/
};
// Client→Server (56 bytes): layout from CTradeskillWnd::HandleCombine
struct RecipeAutoCombine_CS_Struct {
/*00*/ uint32 con_type; // GetConType of container
/*04*/ uint32 recipe_id; // GetItemRecordNum of recipe item
/*08*/ uint32 unknown1; // constant 4
/*12*/ uint8 unknown2[8]; // zeros (uninitialized)
/*20*/ InventorySlot_Struct container_slot; // 12 bytes
/*32*/ uint32 object_type;
/*36*/ uint32 some_id;
/*40*/ uint8 flag1;
/*41*/ uint8 flag2;
/*42*/ uint8 unknown3;
/*43*/ uint8 flag3;
/*44*/ uint32 unknown4; // zeros (uninitialized)
/*48*/ int64 start_tick;
/*56*/
};
/*
** New Combine Struct
** Client requesting to perform a tradeskill combine
** Size: 28 bytes
** Used In: OP_TradeSkillCombine
** Last Updated: 01-05-2013
*/
struct NewCombine_Struct
{
/*00*/ InventorySlot_Struct container_slot;
/*12*/ InventorySlot_Struct guildtribute_slot; // Slot type is 8? (MapGuildTribute = 8)
/*24*/ uint32 unknown0x18; // TOB wire format; not used by server
/*28*/
};
struct DisciplineTimer_Struct {
/*00*/ uint32 TimerID;
/*04*/ uint32 Duration;
/*08*/ uint32 Unknown08; // server-side absolute expiry time (fasttime units)
/*0C*/ uint32 ServerTime; // server's current time when packet sent (fasttime units)
};
struct Disciplines_Struct {
uint32 values[MAX_PP_DISCIPLINES];
};
struct Merchant_Sell_Request_Struct {
/*000*/ uint32 npcid; // Merchant NPC's entity id
/*004*/ uint32 playerid; // unset by client (stack garbage at this offset)
/*008*/ uint32 itemslot; // lower 4 bytes of 8-byte item instance ID
/*012*/ uint32 unknown12; // upper 4 bytes of 8-byte item instance ID
/*016*/ uint32 quantity; // Already sold
/*020*/ uint32 unknown20; // unset by client — trailing pad; client sends 24 bytes total
/*024*/
};
struct Merchant_Sell_Response_Struct {
/*000*/ uint32 npcid; // Merchant NPC's entity id
/*004*/ uint32 playerid; // Player's entity id
/*008*/ uint32 itemslot; // Merchant Slot / Item Instance ID
/*012*/ uint32 unknown12;
/*016*/ uint32 quantity; // Already sold
/*020*/ uint32 unknown20;
/*024*/ uint32 price;
/*028*/ uint32 unknown28; // Normally 0, but seen 84 c5 63 00 as well
/*032*/
};
struct Merchant_Purchase_Request_Struct {
/*000*/ uint32 npcid; // Merchant NPC's entity id
/*004*/ TypelessInventorySlot_Struct inventory_slot;
/*010*/ int16 padding;
/*012*/ uint32 quantity;
/*016*/
};
struct Merchant_Purchase_Response_Struct {
/*000*/ TypelessInventorySlot_Struct inventory_slot;
/*006*/ int16 padding;
/*008*/ uint32 quantity;
/*012*/ uint32 price;
/*016*/ uint32 unknown016;
/*020*/
};
/*
** Cancel Trade struct
** Sent when a player cancels a trade
** Size: 8 bytes
** Used In: OP_CancelTrade
**
*/
struct CancelTrade_Struct {
/*00*/ uint32 fromid;
/*04*/ uint32 action;
/*08*/
};
struct Stun_Struct { // 8 bytes total
/*000*/ uint32 duration; // Duration of stun
/*004*/ uint8 unknown004; // seen 0
/*005*/ uint8 unknown005; // seen 163
/*006*/ uint8 unknown006; // seen 67
/*007*/ uint8 unknown007; // seen 0
/*008*/
};
/*
* Structs used in OP_CharacterCreateRequest
*/
struct RaceClassAllocation {
uint32 Index;
uint32 BaseStats[7];
uint32 DefaultPointAllocation[7];
};
struct RaceClassCombos {
uint64 ExpansionRequired;
uint32 Race;
uint32 Class;
uint32 Deity;
uint32 AllocationIndex;
uint32 Zone;
};
struct fling_struct {
/* 00 */ float speed_z; // must be > 0 for handler to proceed
/* 04 */ float new_y;
/* 08 */ float new_x;
/* 12 */ float new_z;
/* 16 */ float radius; // landing zone radius; 0.0f = land exactly at target
/* 20 */ uint32 unknown; // not accessed; padding
/* 24 */ int32 travel_time; // -1 = auto-calc; 0 = default 1000ms; >0 = explicit ms
/* 28 */ uint8 collision; // 0 = disable collision; non-zero = keep collision
/* 29 */ uint8 fall_damage; // 0 = no fall damage (player.408=1); non-zero = take damage
/* 30 */ uint8 z_override; // 1 = override z-target comparison
/* 31 */
};
struct BeggingResponse_Struct
{
/*00*/ uint32 Unknown00;
/*04*/ uint32 Unknown04;
/*08*/ uint32 Unknown08;
/*12*/ uint8 Result; // 0 = Fail, 1 = Plat, 2 = Gold, 3 = Silver, 4 = Copper
/*13*/ uint32 Amount;
/*17*/ uint32 StringSize; // set this to 0, but it's a string size
/*21*/ uint8 Lucky; // set to 1 to message a lucky beg
};
#pragma pack()
}; //end namespace structs
}; //end namespace tob