diff --git a/common/patches/larion.cpp b/common/patches/larion.cpp index e668934e9..2638e67cf 100644 --- a/common/patches/larion.cpp +++ b/common/patches/larion.cpp @@ -489,6 +489,91 @@ namespace Larion FINISH_ENCODE(); } + ENCODE(OP_ZoneEntry) { ENCODE_FORWARD(OP_ZoneSpawns); } + + ENCODE(OP_ZoneSpawns) + { + EQApplicationPacket* in = *p; + *p = nullptr; + + //store away the emu struct + unsigned char* __emu_buffer = in->pBuffer; + Spawn_Struct* emu = (Spawn_Struct*)__emu_buffer; + + int entrycount = in->size / sizeof(Spawn_Struct); + if (entrycount == 0 || (in->size % sizeof(Spawn_Struct)) != 0) { + LogNetcode("[STRUCTS] Wrong size on outbound [{}]: Got [{}], expected multiple of [{}]", opcodes->EmuToName(in->GetOpcode()), in->size, sizeof(Spawn_Struct)); + delete in; + return; + } + + for (int i = 0; i < entrycount; i++, emu++) { + SerializeBuffer buffer; + + auto SpawnSize = emu->size; + if (!((emu->NPC == 0) || (emu->race <= Race::Gnome) || (emu->race == Race::Iksar) || + (emu->race == Race::VahShir) || (emu->race == Race::Froglok2) || (emu->race == Race::Drakkin)) + ) + { + if (emu->size == 0) + { + emu->size = 6; + SpawnSize = 6; + } + } + + if (SpawnSize == 0) + { + SpawnSize = 3; + } + + buffer.WriteString(emu->name); + buffer.WriteUInt32(emu->spawnId); + buffer.WriteUInt8(emu->level); + if (emu->DestructibleObject) //bounding radius: we should consider supporting this officially in the future + { + buffer.WriteFloat(10.0f); + } + else + { + + buffer.WriteFloat(SpawnSize - 0.7f); + } + + buffer.WriteUInt32(emu->spawnId); //player "id" we should consider supporting this in the future + buffer.WriteUInt32(103); //not sure + buffer.WriteUInt8(emu->NPC); //npc/player flag + + structs::Spawn_Struct_Bitfields flags; + flags.gender = emu->gender; + flags.gender = emu->gender; + flags.ispet = emu->is_pet; + flags.afk = emu->afk; + flags.anon = emu->anon; + flags.gm = emu->gm; + flags.sneak = 0; + flags.lfg = emu->lfg; + flags.invis = emu->invis; + flags.linkdead = 0; + flags.showhelm = emu->showhelm; + flags.trader = emu->trader ? 1 : 0; + flags.targetable = 1; + flags.targetable_with_hotkey = emu->targetable_with_hotkey ? 1 : 0; + flags.showname = emu->show_name; + + } + } + // DECODE methods + + DECODE(OP_ZoneEntry) + { + DECODE_LENGTH_EXACT(structs::ClientZoneEntry_Struct); + SETUP_DIRECT_DECODE(ClientZoneEntry_Struct, structs::ClientZoneEntry_Struct); + + memcpy(emu->char_name, eq->char_name, sizeof(emu->char_name)); + + FINISH_DIRECT_DECODE(); + } } /*Larion*/ diff --git a/common/patches/larion_ops.h b/common/patches/larion_ops.h index f795231a3..9546e5742 100644 --- a/common/patches/larion_ops.h +++ b/common/patches/larion_ops.h @@ -1,13 +1,16 @@ //list of packets we need to encode on the way out: -//list of packets we need to decode on the way in: - E(OP_LogServer) E(OP_SendMembership) E(OP_SendMembershipDetails) E(OP_SendMaxCharacters) E(OP_SendCharInfo) E(OP_ExpansionInfo) +E(OP_ZoneEntry) +E(OP_ZoneSpawns) + +//list of packets we need to decode on the way in: +D(OP_ZoneEntry) #undef E #undef D diff --git a/common/patches/larion_structs.h b/common/patches/larion_structs.h index 4aa9cc6ef..c52f9e16f 100644 --- a/common/patches/larion_structs.h +++ b/common/patches/larion_structs.h @@ -19,6 +19,11 @@ namespace Larion { /*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 @@ -165,6 +170,40 @@ namespace Larion { /*000*/ uint32 CharCount; //number of chars in this packet }; + struct Spawn_Struct_Bitfields + { + // 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; + }; #pragma pack() }; //end namespace structs