From 836704e987e368d7edc835d44552a5d6809faa32 Mon Sep 17 00:00:00 2001 From: Martin Michelsen Date: Sun, 19 May 2024 17:52:32 -0700 Subject: [PATCH] track telepipe state in games --- src/Client.hh | 2 ++ src/CommandFormats.hh | 24 +++++++++++++----------- src/ReceiveCommands.cc | 2 +- src/ReceiveSubcommands.cc | 14 +++++++++++++- src/ReceiveSubcommands.hh | 2 +- src/SendCommands.cc | 11 +++++++++++ 6 files changed, 41 insertions(+), 14 deletions(-) diff --git a/src/Client.hh b/src/Client.hh index ada106d6..4fb7e185 100644 --- a/src/Client.hh +++ b/src/Client.hh @@ -247,6 +247,8 @@ public: // These are null unless the client is within the trade sequence (D0-D4 or EE commands) std::unique_ptr pending_item_trade; std::unique_ptr pending_card_trade; + uint32_t telepipe_lobby_id; + G_SetTelepipeState_6x68 telepipe_state; std::shared_ptr ep3_config; // Null for non-Ep3 int8_t bb_character_index; ItemData bb_identify_result; diff --git a/src/CommandFormats.hh b/src/CommandFormats.hh index b3d56cf0..aff125b4 100644 --- a/src/CommandFormats.hh +++ b/src/CommandFormats.hh @@ -4680,18 +4680,20 @@ struct G_TriggerSetEvent_6x67 { le_uint32_t client_id = 0; } __packed_ws__(G_TriggerSetEvent_6x67, 0x10); -// 6x68: Create telepipe / cast Ryuker +// 6x68: Set telepipe state -struct G_CreateTelepipe_6x68 { +struct G_SetTelepipeState_6x68 { G_UnusedHeader header; le_uint16_t client_id2 = 0; le_uint16_t floor = 0; - le_uint32_t unknown_a2 = 0; + le_uint16_t unknown_b1 = 0; + uint8_t unknown_b2 = 0; + uint8_t unknown_b3 = 0; le_float x = 0.0f; le_float y = 0.0f; le_float z = 0.0f; - le_uint32_t unused3 = 0; -} __packed_ws__(G_CreateTelepipe_6x68, 0x1C); + le_uint32_t unknown_a3 = 0; +} __packed_ws__(G_SetTelepipeState_6x68, 0x1C); // 6x69: NPC control // Note: NPCs cannot be destroyed with 6x69; 6x1C is used instead for that. @@ -4838,16 +4840,16 @@ struct G_SetQuestFlags_BB_6x6F { // and instead rearranged a bunch of things. This is presumably because this // structure also includes transient state (e.g. current HP). -struct Telepipe { +struct Telepipe6x70 { /* 00 */ le_uint16_t owner_client_id = 0xFFFF; /* 02 */ le_uint16_t floor = 0; - /* 04 */ le_uint32_t unknown_a2 = 0; + /* 04 */ le_uint32_t unknown_a1 = 0; /* 08 */ le_float x = 0.0f; /* 0C */ le_float y = 0.0f; /* 10 */ le_float z = 0.0f; /* 14 */ le_uint32_t unknown_a3 = 0; /* 18 */ le_uint32_t unknown_a4 = 0x0000FFFF; -} __packed_ws__(Telepipe, 0x1C); +} __packed_ws__(Telepipe6x70, 0x1C); struct G_Unknown_6x70_SubA1 { // This is used in all versions of this command except DCNTE and 11/2000. @@ -4887,7 +4889,7 @@ struct G_SyncPlayerDispAndInventory_DCNTE_6x70 { // The following two fields appear to contain uninitialized data /* 0030 */ le_uint32_t unknown_a5 = 0; /* 0034 */ le_uint32_t unknown_a6 = 0; - /* 0038 */ Telepipe telepipe; + /* 0038 */ Telepipe6x70 telepipe; /* 0054 */ le_uint32_t unknown_a8 = 0; /* 0058 */ parray unknown_a9; /* 0068 */ le_uint32_t area = 0; @@ -4906,7 +4908,7 @@ struct G_SyncPlayerDispAndInventory_DC112000_6x70 { /* 0030 */ le_uint16_t bonus_hp_from_materials = 0; /* 0032 */ le_uint16_t bonus_tp_from_materials = 0; /* 0034 */ parray unknown_a5; - /* 0044 */ Telepipe telepipe; + /* 0044 */ Telepipe6x70 telepipe; /* 0060 */ le_uint32_t unknown_a8 = 0; /* 0064 */ parray unknown_a9; /* 0074 */ le_uint32_t area = 0; @@ -4928,7 +4930,7 @@ struct G_SyncPlayerDispAndInventory_BaseV1 { /* 006C */ le_uint32_t guild_card_number = 0; /* 0070 */ le_uint32_t unknown_a6 = 0; /* 0074 */ le_uint32_t battle_team_number = 0; - /* 0078 */ Telepipe telepipe; + /* 0078 */ Telepipe6x70 telepipe; /* 0094 */ le_uint32_t unknown_a8 = 0; /* 0098 */ G_Unknown_6x70_SubA1 unknown_a9; /* 00AC */ le_uint32_t area = 0; diff --git a/src/ReceiveCommands.cc b/src/ReceiveCommands.cc index 523fadc1..c73f3cdb 100644 --- a/src/ReceiveCommands.cc +++ b/src/ReceiveCommands.cc @@ -3204,7 +3204,7 @@ static void on_61_98(shared_ptr c, uint16_t command, uint32_t flag, stri if (command == 0x98) { // If the client had an overlay (for battle/challenge modes), delete it c->delete_overlay(); - + c->telepipe_lobby_id = 0; s->remove_client_from_lobby(c); } else if (command == 0x61) { diff --git a/src/ReceiveSubcommands.cc b/src/ReceiveSubcommands.cc index 376f833c..f8af820b 100644 --- a/src/ReceiveSubcommands.cc +++ b/src/ReceiveSubcommands.cc @@ -2991,6 +2991,18 @@ static void on_trigger_set_event(shared_ptr c, uint8_t command, uint8_t forward_subcommand(c, command, flag, data, size); } +static void on_update_telepipe_state(shared_ptr c, uint8_t command, uint8_t flag, void* data, size_t size) { + auto l = c->require_lobby(); + if (!l->is_game()) { + return; + } + + c->telepipe_state = check_size_t(data, size); + c->telepipe_lobby_id = l->lobby_id; + + forward_subcommand(c, command, flag, data, size); +} + static void on_unknown_6x91(shared_ptr c, uint8_t command, uint8_t flag, void* data, size_t size) { const auto& cmd = check_size_t(data, size); auto l = c->require_lobby(); @@ -4512,7 +4524,7 @@ const SubcommandDefinition subcommand_definitions[0x100] = { /* 6x65 */ {0x57, 0x5E, 0x65, on_forward_check_game}, /* 6x66 */ {0x00, 0x00, 0x66, on_forward_check_game}, /* 6x67 */ {0x58, 0x5F, 0x67, on_trigger_set_event}, - /* 6x68 */ {0x59, 0x60, 0x68, on_forward_check_game}, + /* 6x68 */ {0x59, 0x60, 0x68, on_update_telepipe_state}, /* 6x69 */ {0x5A, 0x61, 0x69, on_npc_control}, /* 6x6A */ {0x5B, 0x62, 0x6A, on_forward_check_game}, /* 6x6B */ {0x5C, 0x63, 0x6B, on_sync_joining_player_compressed_state}, diff --git a/src/ReceiveSubcommands.hh b/src/ReceiveSubcommands.hh index d240b7f0..e0f7ccce 100644 --- a/src/ReceiveSubcommands.hh +++ b/src/ReceiveSubcommands.hh @@ -54,7 +54,7 @@ public: uint32_t guild_card_number = 0; uint32_t unknown_a6 = 0; uint32_t battle_team_number = 0; - Telepipe telepipe; + Telepipe6x70 telepipe; uint32_t unknown_a8 = 0; parray unknown_a9_nte_112000; G_Unknown_6x70_SubA1 unknown_a9_final; diff --git a/src/SendCommands.cc b/src/SendCommands.cc index 6f49af93..b04e295f 100644 --- a/src/SendCommands.cc +++ b/src/SendCommands.cc @@ -2866,6 +2866,17 @@ void send_game_player_state(shared_ptr to_c, shared_ptr from_c, to_send.player_tag = 0x00010000; to_send.guild_card_number = from_c->login->account->account_id; + auto to_l = to_c->lobby.lock(); + if (to_l && (from_c->telepipe_lobby_id == to_l->lobby_id)) { + to_send.telepipe.owner_client_id = from_c->telepipe_state.client_id2; + to_send.telepipe.floor = from_c->telepipe_state.floor; + to_send.telepipe.unknown_a1 = from_c->telepipe_state.unknown_b3; + to_send.telepipe.x = from_c->telepipe_state.x; + to_send.telepipe.y = from_c->telepipe_state.y; + to_send.telepipe.z = from_c->telepipe_state.z; + to_send.telepipe.unknown_a3 = from_c->telepipe_state.unknown_a3; + } + if (apply_overrides) { auto from_p = from_c->character(); to_send.base.x = from_c->x;