Validating packets (starting with loot) (#5079)

This commit is contained in:
dannuic 2026-05-07 21:56:10 -06:00 committed by GitHub
parent 99f99c8b8e
commit 65330af50e
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 128 additions and 61 deletions

View File

@ -81,6 +81,7 @@ public:
void ReadString(char *str) { uint32 len = static_cast<uint32>(strlen((char *)(pBuffer + _rpos))) + 1; memcpy(str, pBuffer + _rpos, len); _rpos += len; }
void ReadString(std::string &str) { str = reinterpret_cast<char *>(pBuffer + _rpos); _rpos += str.length() + 1; }
void ReadString(char *str, uint32 Offset, uint32 MaxLength) const;
void ReadLengthString(std::string& str) { uint32 len = *(uint32*)(pBuffer + _rpos); _rpos += sizeof(uint32); str.resize(len); memcpy(&str[0], pBuffer + _rpos, len); _rpos += len; }
uint32 GetWritePosition() { return _wpos; }
uint32 GetReadPosition() { return _rpos; }

View File

@ -238,6 +238,22 @@ namespace TOB
FINISH_ENCODE();
}
ENCODE(OP_Begging)
{
ENCODE_LENGTH_EXACT(BeggingResponse_Struct);
SETUP_DIRECT_ENCODE(BeggingResponse_Struct, structs::BeggingResponse_Struct);
OUT(Unknown00);
OUT(Unknown04);
OUT(Unknown08);
eq->Result = static_cast<uint8>(emu->Result);
OUT(Amount);
eq->StringSize = 0; // set this to 0, but it's a string size
eq->Lucky = 0; // set to 1 to message a lucky beg
FINISH_ENCODE();
}
ENCODE(OP_BeginCast)
{
ENCODE_LENGTH_EXACT(BeginCast_Struct);
@ -597,8 +613,8 @@ namespace TOB
OUT(skills[i]);
}
eq->unknown408[0] = 1;
eq->unknown408[1] = 0xC9;
eq->unknown408[0] = 1; // this tells the client to update the GM window
eq->unknown408[1] = 0xC9; // these appear to be languages, but it's only testing if this is non-zero
eq->unknown408[2] = 0xC9;
eq->unknown408[3] = 0xC9;
eq->unknown408[4] = 0xC9;
@ -698,8 +714,6 @@ namespace TOB
OUT(spawnid);
OUT_str(charname);
OUT(race);
eq->unknown006[0] = 0;
eq->unknown006[1] = 0;
OUT(gender);
OUT(texture);
OUT(helmtexture);
@ -893,6 +907,7 @@ namespace TOB
ENCODE_LENGTH_EXACT(moneyOnCorpseStruct);
SETUP_DIRECT_ENCODE(moneyOnCorpseStruct, structs::moneyOnCorpseStruct);
// TODO: The type has changed to accomodate all kinds of loot options and actions, including advloot
eq->type = emu->response;
OUT(platinum);
OUT(gold);
@ -3693,6 +3708,23 @@ namespace TOB
DECODE(OP_ConsiderCorpse) { DECODE_FORWARD(OP_Consider); }
DECODE(OP_CorpseDrag)
{
std::string CorpseName;
__packet->ReadLengthString(CorpseName);
std::string DraggerName;
__packet->ReadLengthString(DraggerName);
__packet->SetReadPosition(0);
__packet->size = sizeof(CorpseDrag_Struct);
__packet->pBuffer = new unsigned char[__packet->size]{};
auto* emu = reinterpret_cast<CorpseDrag_Struct*>(__packet->pBuffer);
strncpy(emu->CorpseName, CorpseName.c_str(), 64);
strncpy(emu->DraggerName, DraggerName.c_str(), 64);
}
DECODE(OP_DeleteItem)
{
DECODE_LENGTH_EXACT(structs::DeleteItem_Struct);
@ -3759,6 +3791,21 @@ namespace TOB
DECODE_FORWARD(OP_GroupInvite);
}
DECODE(OP_LootItem)
{
DECODE_LENGTH_EXACT(structs::LootingItem_Struct);
SETUP_DIRECT_DECODE(LootingItem_Struct, structs::LootingItem_Struct);
Log(Logs::Detail, Logs::Netcode, "TOB::DECODE(OP_LootItem)");
IN(lootee);
IN(looter);
emu->slot_id = TOBToServerCorpseMainSlot(eq->slot_id);
IN(auto_loot);
FINISH_DIRECT_DECODE();
}
DECODE(OP_MemorizeSpell) {
DECODE_LENGTH_EXACT(structs::MemorizeSpell_Struct);
SETUP_DIRECT_DECODE(MemorizeSpell_Struct, structs::MemorizeSpell_Struct);

View File

@ -4,6 +4,7 @@ E(OP_Action)
E(OP_Animation)
E(OP_ApplyPoison)
E(OP_AugmentInfo)
E(OP_Begging)
E(OP_BeginCast)
E(OP_BlockedBuffs)
E(OP_CancelTrade)
@ -77,12 +78,14 @@ D(OP_ClientUpdate)
D(OP_ClickDoor)
D(OP_Consider)
D(OP_ConsiderCorpse)
D(OP_CorpseDrag)
D(OP_DeleteItem)
D(OP_EnterWorld)
D(OP_GMTraining)
D(OP_GroupDisband)
D(OP_GroupInvite)
D(OP_GroupInvite2)
D(OP_LootItem)
D(OP_MemorizeSpell)
D(OP_MoveItem)
D(OP_RemoveBlockedBuffs)

View File

@ -645,7 +645,7 @@ namespace TOB {
{
/*000*/ uint32 spawn_id;
/*004*/ uint32 killer_id;
/*008*/ uint32 corpseid; //not read by client
/*008*/ uint32 corpseid;
/*012*/ uint32 unknown1; //not read by client
/*016*/ int32 spell_id;
/*020*/ uint32 attack_skill;
@ -790,7 +790,7 @@ namespace TOB {
//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
//@0x1401f0970 MissileHitInfo::Deserialize(CUnSerializeBuffer *buffer);
//@0x1402024C0 MissileHitInfo::Deserialize(CUnSerializeBuffer *buffer);
struct MissileHitInfo
{
uint16 target;
@ -896,38 +896,34 @@ namespace TOB {
struct Illusion_Struct {
/*000*/ uint32 spawnid;
/*004*/ char charname[64];
/*068*/ uint16 race; //according to eqlib this is s32
/*070*/ char unknown006[2];
/*072*/ uint8 gender;
/*073*/ uint8 texture;
/*074*/ uint8 armorVariation;
/*075*/ uint8 armorMaterial;
/*076*/ uint8 helmtexture;
/*077*/ uint8 unknown077; //padding from this being a pack(4) struct actually
/*078*/ uint8 unknown078;
/*079*/ uint8 unknown079;
/*068*/ int32 race;
/*072*/ int32 class_;
/*076*/ float size;
/*080*/ uint32 face;
/*084*/ uint8 hairstyle;
/*085*/ uint8 haircolor;
/*086*/ uint8 beard;
/*087*/ uint8 beardcolor;
/*088*/ float size;
/*092*/ uint32_t npc_tint;
/*096*/ bool keep_armor_properties;
/*097*/ uint8 unknown097[3]; //padding from this being a pack(4) struct actually
/*100*/ ArmorPropertyStruct armorProperties[9];
/*280*/ uint32_t armorTints[9];
/*316*/ int32 class_;
/*320*/ uint32 drakkin_heritage;
/*324*/ uint32 drakkin_tattoo;
/*328*/ uint32 drakkin_details;
/*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 moneyOnCorpseStruct {
/*000*/ uint8 type;
/*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;
/*004*/ uint32 flags; // 1 = extra lucky bonus, 2 = lucky bonus, 4 = bonus
/*008*/ uint32 platinum;
/*012*/ uint32 gold;
/*016*/ uint32 silver;
@ -935,6 +931,15 @@ namespace TOB {
/*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];
@ -1102,6 +1107,17 @@ namespace TOB {
uint32 Zone;
};
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

View File

@ -12,7 +12,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_AAExpUpdate` | 🟢 Verified | | |
| `OP_AcceptNewTask` | 🔴 Not-Set | | |
| `OP_AckPacket` | 🟢 Verified | | |
| `OP_Action` | 🟡 Unverified | | |
| `OP_Action` | 🟢 Verified | | |
| `OP_Action2` | 🔴 Not-Set | | |
| `OP_AddNimbusEffect` | 🟡 Unverified | | |
| `OP_AdventureData` | 🔴 Not-Set | | |
@ -41,7 +41,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_AltCurrencyReclaim` | 🔴 Not-Set | | |
| `OP_AltCurrencySell` | 🔴 Not-Set | | |
| `OP_AltCurrencySellSelection` | 🔴 Not-Set | | |
| `OP_Animation` | 🟡 Unverified | | |
| `OP_Animation` | 🟢 Verified | | |
| `OP_AnnoyingZoneUnknown` | 🔴 Not-Set | | |
| `OP_ApplyPoison` | 🟡 Unverified | | |
| `OP_ApproveName` | 🟡 Unverified | This takes multiple parameters from the client, and it can take multiple integer values from the server | |
@ -53,7 +53,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_AugmentItem` | 🟡 Unverified | | |
| `OP_AutoAttack` | 🟡 Unverified | | |
| `OP_AutoAttack2` | 🟡 Unverified | | |
| `OP_AutoFire` | 🟡 Unverified | | |
| `OP_AutoFire` | 🟢 Verified | | |
| `OP_Bandolier` | 🔴 Not-Set | | |
| `OP_BankerChange` | 🟡 Unverified | | |
| `OP_Barter` | 🔴 Not-Set | | |
@ -62,7 +62,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_BazaarSearch` | 🔴 Not-Set | | |
| `OP_BecomeCorpse` | 🔴 Not-Set | | |
| `OP_BecomeTrader` | 🔴 Not-Set | | |
| `OP_Begging` | 🟡 Unverified | | |
| `OP_Begging` | 🟢 Verified | | |
| `OP_BeginCast` | 🟢 Verified | | |
| `OP_Bind_Wound` | 🟡 Unverified | | |
| `OP_BlockedBuffs` | 🟢 Verified | | |
@ -107,30 +107,30 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_Command` | 🔴 Not-Set | | |
| `OP_CompletedTasks` | 🔴 Not-Set | | |
| `OP_ConfirmDelete` | 🟡 Unverified | | |
| `OP_Consent` | 🟡 Unverified | | |
| `OP_ConsentDeny` | 🟡 Unverified | | |
| `OP_Consent` | 🟢 Verified | | |
| `OP_ConsentDeny` | 🟢 Verified | | |
| `OP_ConsentResponse` | 🟢 Verified | | |
| `OP_Consider` | 🟢 Verified | | |
| `OP_ConsiderCorpse` | 🟡 Unverified | | |
| `OP_ConsiderCorpse` | 🟢 Verified | | |
| `OP_Consume` | 🟡 Unverified | | |
| `OP_ControlBoat` | 🟡 Unverified | | |
| `OP_CorpseDrag` | 🟡 Unverified | | |
| `OP_CorpseDrop` | 🟡 Unverified | | |
| `OP_CorpseDrag` | 🟢 Verified | | |
| `OP_CorpseDrop` | 🟢 Verified | | |
| `OP_CrashDump` | 🔴 Not-Set | | |
| `OP_CrystalCountUpdate` | 🔴 Not-Set | | |
| `OP_CrystalCreate` | 🔴 Not-Set | | |
| `OP_CrystalReclaim` | 🔴 Not-Set | | |
| `OP_CustomTitles` | 🔴 Not-Set | | |
| `OP_Damage` | 🟡 Unverified | | |
| `OP_Death` | 🟡 Unverified | | |
| `OP_Death` | 🟢 Verified | | |
| `OP_DelegateAbility` | 🔴 Not-Set | | |
| `OP_DeleteCharacter` | 🟢 Verified | | |
| `OP_DeleteCharge` | 🟡 Unverified | | |
| `OP_DeleteItem` | 🟡 Unverified | | |
| `OP_DeletePetition` | 🔴 Not-Set | | |
| `OP_DeleteSpawn` | 🟡 Unverified | | |
| `OP_DeleteSpell` | 🟡 Unverified | | |
| `OP_DenyResponse` | 🟡 Unverified | | |
| `OP_DeleteSpell` | 🟢 Verified | | |
| `OP_DenyResponse` | 🟢 Verified | appears unused by server or client | |
| `OP_Disarm` | 🟡 Unverified | | |
| `OP_DisarmTraps` | 🟡 Unverified | | |
| `OP_DisciplineTimer` | 🟡 Unverified | | |
@ -162,7 +162,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_DzSetLeaderName` | 🔴 Not-Set | | |
| `OP_DzSwapPlayer` | 🔴 Not-Set | | |
| `OP_Emote` | 🔴 Not-Set | | |
| `OP_EndLootRequest` | 🟡 Unverified | | |
| `OP_EndLootRequest` | 🟢 Verified | can be sent to close the client's looting session (with no data) | |
| `OP_EnduranceUpdate` | 🔴 Not-Set | | |
| `OP_EnterChat` | 🔴 Not-Set | | |
| `OP_EnterWorld` | 🟢 Verified | | |
@ -194,7 +194,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_GMBecomeNPC` | 🔴 Not-Set | | |
| `OP_GMDelCorpse` | 🔴 Not-Set | | |
| `OP_GMEmoteZone` | 🔴 Not-Set | | |
| `OP_GMEndTraining` | 🟡 Unverified | | |
| `OP_GMEndTraining` | 🟢 Verified | | |
| `OP_GMEndTrainingResponse` | 🔴 Not-Set | | |
| `OP_GMFind` | 🔴 Not-Set | | |
| `OP_GMGoto` | 🔴 Not-Set | | |
@ -207,9 +207,9 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_GMServers` | 🔴 Not-Set | | |
| `OP_GMSummon` | 🔴 Not-Set | | |
| `OP_GMToggle` | 🔴 Not-Set | | |
| `OP_GMTraining` | 🟡 Unverified | | |
| `OP_GMTrainSkill` | 🟡 Unverified | | |
| `OP_GMTrainSkillConfirm` | 🟡 Unverified | | |
| `OP_GMTraining` | 🟢 Verified | | |
| `OP_GMTrainSkill` | 🟢 Verified | | |
| `OP_GMTrainSkillConfirm` | 🟢 Verified | | |
| `OP_GMZoneRequest` | 🔴 Not-Set | | |
| `OP_GMZoneRequest2` | 🔴 Not-Set | | |
| `OP_GroundSpawn` | 🟢 Verified | | |
@ -277,9 +277,9 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_GuildWar` | 🔴 Not-Set | | |
| `OP_Heartbeat` | 🔴 Not-Set | | |
| `OP_Hide` | 🟡 Unverified | | |
| `OP_HideCorpse` | 🟡 Unverified | | |
| `OP_HideCorpse` | 🟢 Verified | | |
| `OP_HPUpdate` | 🟢 Verified | | |
| `OP_Illusion` | 🟡 Unverified | | |
| `OP_Illusion` | 🟢 Verified | Actually a generic appearance change packet, including name for self | |
| `OP_IncreaseStats` | 🟡 Unverified | | |
| `OP_InitialHPUpdate` | 🔴 Not-Set | | |
| `OP_InitialMobHealth` | 🔴 Not-Set | | |
@ -342,9 +342,9 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_Logout` | 🟡 Unverified | | |
| `OP_LogoutReply` | 🔴 Not-Set | | |
| `OP_LogServer` | 🟢 Verified | Mostly unused values | |
| `OP_LootComplete` | 🟡 Unverified | | |
| `OP_LootItem` | 🟡 Unverified | | |
| `OP_LootRequest` | 🟡 Unverified | | |
| `OP_LootComplete` | 🟢 Verified | | |
| `OP_LootItem` | 🟢 Verified | | |
| `OP_LootRequest` | 🟢 Verified | | |
| `OP_ManaChange` | 🟢 Verified | | |
| `OP_ManaUpdate` | 🔴 Not-Set | | |
| `OP_MarkNPC` | 🔴 Not-Set | | |
@ -373,7 +373,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_MobManaUpdate` | 🔴 Not-Set | | |
| `OP_MobRename` | 🔴 Not-Set | | |
| `OP_MobUpdate` | 🔴 Not-Set | | |
| `OP_MoneyOnCorpse` | 🟡 Unverified | | |
| `OP_MoneyOnCorpse` | 🟢 Verified | This is the loot response struct, it provides all the logistics for things like advloot | |
| `OP_MoneyUpdate` | 🟡 Unverified | | |
| `OP_MOTD` | 🟢 Verified | | |
| `OP_MoveCoin` | 🟡 Unverified | | |
@ -440,8 +440,8 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_RaidJoin` | 🔴 Not-Set | | |
| `OP_RaidUpdate` | 🔴 Not-Set | | |
| `OP_RandomNameGenerator` | 🟢 Verified | The client no longer sends this packet (random name generation is done entirely in the client). The client will still accept this packet to set name (emu doesn't do this, but it's always been supported) | |
| `OP_RandomReply` | 🟡 Unverified | | |
| `OP_RandomReq` | 🟡 Unverified | | |
| `OP_RandomReply` | 🟢 Verified | | |
| `OP_RandomReq` | 🟢 Verified | | |
| `OP_ReadBook` | 🟡 Unverified | | |
| `OP_RecipeAutoCombine` | 🟡 Unverified | | |
| `OP_RecipeDetails` | 🟡 Unverified | | |
@ -492,7 +492,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_SendTitleList` | 🔴 Not-Set | | |
| `OP_SendTributes` | 🔴 Not-Set | | |
| `OP_SendZonepoints` | 🟢 Verified | | |
| `OP_SenseHeading` | 🟡 Unverified | | |
| `OP_SenseHeading` | 🟢 Verified | | |
| `OP_SenseTraps` | 🟡 Unverified | | |
| `OP_ServerListRequest` | 🔴 Not-Set | | |
| `OP_ServerListResponse` | 🔴 Not-Set | | |
@ -535,7 +535,7 @@ Below is a status list for the 450 opcodes we currently use on the server for th
| `OP_ShopParcelIcon` | 🟡 Unverified | | |
| `OP_ShopRequest` | 🟡 Unverified | | |
| `OP_SimpleMessage` | 🟢 Verified | | |
| `OP_SkillUpdate` | 🟡 Unverified | | |
| `OP_SkillUpdate` | 🟢 Verified | | |
| `OP_Sneak` | 🟡 Unverified | | |
| `OP_Some3ByteHPUpdate` | 🔴 Not-Set | | |
| `OP_Some6ByteHPUpdate` | 🔴 Not-Set | | |

View File

@ -183,7 +183,6 @@ OP_RefreshBuffs=0x754c
OP_RefreshTargetBuffs=0x197f
OP_RefreshPetBuffs=0x4f42
OP_Illusion=0x7fb0
OP_MoneyOnCorpse=0x6f63
OP_RandomReply=0x1234
OP_DenyResponse=0x339b
OP_SkillUpdate=0x0149
@ -225,7 +224,7 @@ OP_KeyRing=0x0000
OP_WhoAllRequest=0x3328
OP_WhoAllResponse=0x4dfd
OP_FriendsWho=0x3547
OP_ConfirmDelete=0x14a8 # This is sent fromt the client after a movement update (with just spawn ID as the content)
OP_ConfirmDelete=0x14a8 # This is sent from the client after a movement update (with just spawn ID as the content)
OP_Logout=0x46f8
OP_Rewind=0x898a
OP_TargetCommand=0x46bf
@ -415,6 +414,7 @@ OP_MercenarySuspendResponse=0x0000
OP_MercenaryUnsuspendResponse=0x0000
# Looting
OP_MoneyOnCorpse=0x6f63 # this is actually a loot logistics packet
OP_LootRequest=0x2239
OP_EndLootRequest=0x173c
OP_LootItem=0x5241