1
+ /*
2
+ * Copyright (c) 2010-2024 OTClient <https://github.com/edubart/otclient>
3
+ *
4
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
5
+ * of this software and associated documentation files (the "Software"), to deal
6
+ * in the Software without restriction, including without limitation the rights
7
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8
+ * copies of the Software, and to permit persons to whom the Software is
9
+ * furnished to do so, subject to the following conditions:
10
+ *
11
+ * The above copyright notice and this permission notice shall be included in
12
+ * all copies or substantial portions of the Software.
13
+ *
14
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
20
+ * THE SOFTWARE.
21
+ */
22
+
23
+ #include < framework/global.h>
24
+ #include < framework/core/clock.h>
25
+ #include < filesystem>
26
+
27
+ #include " packet_player.h"
28
+
29
+ PacketPlayer::~PacketPlayer ()
30
+ {
31
+ if (m_event)
32
+ m_event->cancel ();
33
+ }
34
+
35
+ PacketPlayer::PacketPlayer (const std::string_view& file)
36
+ {
37
+ static uint32_t sessionId = 1 ;
38
+ #ifdef ANDROID
39
+ std::ifstream f (std::string (" records/" ) + file);
40
+ #else
41
+ std::ifstream f (std::filesystem::path (" records" ) / file);
42
+ #endif
43
+ if (!f.is_open ())
44
+ return ;
45
+ std::string type, packetHex;
46
+ ticks_t time ;
47
+ while (f >> type >> time >> packetHex) {
48
+ // Convert hex string to binary data manually
49
+ std::string packetStr;
50
+ for (size_t i = 0 ; i < packetHex.length (); i += 2 ) {
51
+ std::string byteString = packetHex.substr (i, 2 );
52
+ char byte = (char )strtol (byteString.c_str (), nullptr , 16 );
53
+ packetStr.push_back (byte);
54
+ }
55
+ auto packet = std::make_shared<std::vector<uint8_t >>(packetStr.begin (), packetStr.end ());
56
+ if (type == " <" ) {
57
+ m_input.push_back (std::make_pair (time , packet));
58
+ } else if (type == " >" ) {
59
+ m_output.push_back (std::make_pair (time , packet));
60
+ }
61
+ }
62
+ }
63
+
64
+ void PacketPlayer::start (std::function<void (std::shared_ptr<std::vector<uint8_t >>)> recvCallback,
65
+ std::function<void(std::error_code)> disconnectCallback)
66
+ {
67
+ m_start = g_clock.millis ();
68
+ m_recvCallback = recvCallback;
69
+ m_disconnectCallback = disconnectCallback;
70
+ m_event = g_dispatcher.scheduleEvent (std::bind (&PacketPlayer::process, this ), 50 );
71
+ }
72
+
73
+ void PacketPlayer::stop ()
74
+ {
75
+ if (m_event)
76
+ m_event->cancel ();
77
+ m_event = nullptr ;
78
+ }
79
+
80
+ void PacketPlayer::onOutputPacket (const OutputMessagePtr& packet)
81
+ {
82
+ if (packet->getBuffer ()[0 ] == 0x14 ) { // logout
83
+ m_disconnectCallback (asio::error::eof);
84
+ stop ();
85
+ }
86
+ }
87
+
88
+ void PacketPlayer::process ()
89
+ {
90
+ ticks_t nextPacket = 1 ;
91
+ while (!m_input.empty ()) {
92
+ auto & packet = m_input.front ();
93
+ nextPacket = (packet.first + m_start) - g_clock.millis ();
94
+ if (nextPacket > 1 )
95
+ break ;
96
+ m_recvCallback (packet.second );
97
+ m_input.pop_front ();
98
+ }
99
+
100
+ if (!m_input.empty () && nextPacket > 1 ) {
101
+ m_event = g_dispatcher.scheduleEvent (std::bind (&PacketPlayer::process, this ), nextPacket);
102
+ } else {
103
+ m_disconnectCallback (asio::error::eof);
104
+ stop ();
105
+ }
106
+ }
0 commit comments