Client Upload Part 2

RD Core / Commit #5

Commit Client Upload Part 2

Alex Alex committed 19/10/2026 00:06 main Patch
1,244 files +271,215 -0
A RD_Client/src/framework/net/protocol.cpp +425-0 View file
@@ -0,0 +1,425 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "protocol.h"
24+#include "connection.h"
25+#include <framework/core/application.h>
26+#include <random>
27+
28+#include <framework/net/packet_player.h>
29+#include <framework/net/packet_recorder.h>
30+
31+extern asio::io_service g_ioService;
32+
33+Protocol::Protocol()
34+{
35+ m_xteaEncryptionEnabled = false;
36+ m_checksumEnabled = false;
37+ m_sequencedPackets = false;
38+ m_bigPackets = false;
39+ m_compression = false;
40+ m_inputMessage = InputMessagePtr(new InputMessage);
41+ m_packetNumber = 0;
42+
43+ // compression
44+ m_zstreamBuffer.resize(InputMessage::BUFFER_MAXSIZE);
45+ m_zstream.next_in = m_inputMessage->getDataBuffer();
46+ m_zstream.next_out = m_zstreamBuffer.data();
47+ m_zstream.avail_in = 0;
48+ m_zstream.avail_out = 0;
49+ m_zstream.total_in = 0;
50+ m_zstream.total_out = 0;
51+ m_zstream.zalloc = nullptr;
52+ m_zstream.zfree = nullptr;
53+ m_zstream.opaque = nullptr;
54+ m_zstream.data_type = Z_BINARY;
55+ inflateInit2(&m_zstream, -15);
56+}
57+
58+Protocol::~Protocol()
59+{
60+ VALIDATE(!g_app.isTerminated());
61+ disconnect();
62+ inflateEnd(&m_zstream);
63+}
64+
65+void Protocol::connect(const std::string& host, uint16 port)
66+{
67+ if (host == "proxy" || host == "0.0.0.0" || (host == "127.0.0.1" && g_proxy.isActive())) {
68+ m_disconnected = false;
69+ m_proxy = g_proxy.addSession(port,
70+ std::bind(&Protocol::onProxyPacket, asProtocol(), std::placeholders::_1),
71+ std::bind(&Protocol::onLocalDisconnected, asProtocol(), std::placeholders::_1));
72+ return onConnect();
73+ }
74+ m_connection = ConnectionPtr(new Connection);
75+ m_connection->setErrorCallback(std::bind(&Protocol::onError, asProtocol(), std::placeholders::_1));
76+ m_connection->connect(host, port, std::bind(&Protocol::onConnect, asProtocol()));
77+}
78+
79+void Protocol::disconnect()
80+{
81+ m_disconnected = true;
82+ if (m_player) {
83+ m_player->stop();
84+ return;
85+ }
86+ if (m_proxy) {
87+ g_proxy.removeSession(m_proxy);
88+ return;
89+ }
90+ if (m_connection) {
91+ m_connection->close();
92+ m_connection.reset();
93+ }
94+}
95+
96+
97+void Protocol::playRecord(PacketPlayerPtr player)
98+{
99+ m_disconnected = false;
100+ m_player = player;
101+ m_player->start(std::bind(&Protocol::onPlayerPacket, asProtocol(), std::placeholders::_1),
102+ std::bind(&Protocol::onLocalDisconnected, asProtocol(), std::placeholders::_1));
103+ return onConnect();
104+}
105+
106+void Protocol::setRecorder(PacketRecorderPtr recorder)
107+{
108+ m_recorder = recorder;
109+}
110+
111+bool Protocol::isConnected()
112+{
113+ if (m_player)
114+ return !m_disconnected;
115+ if (m_proxy)
116+ return !m_disconnected;
117+ if (m_connection && m_connection->isConnected())
118+ return true;
119+ return false;
120+}
121+
122+bool Protocol::isConnecting()
123+{
124+ if (m_player)
125+ return false;
126+ if (m_proxy)
127+ return false;
128+ if (m_connection && m_connection->isConnecting())
129+ return true;
130+ return false;
131+}
132+
133+void Protocol::send(const OutputMessagePtr& outputMessage, bool rawPacket)
134+{
135+ if (m_player) {
136+ m_player->onOutputPacket(outputMessage);
137+ return;
138+ }
139+
140+ if (m_recorder) {
141+ m_recorder->addOutputPacket(outputMessage);
142+ }
143+
144+ if (!rawPacket) {
145+ // encrypt
146+ if (m_xteaEncryptionEnabled)
147+ xteaEncrypt(outputMessage);
148+
149+ // write checksum
150+ if (m_sequencedPackets)
151+ outputMessage->writeSequence(m_packetNumber++);
152+ else if (m_checksumEnabled)
153+ outputMessage->writeChecksum();
154+
155+ // write message size
156+ outputMessage->writeMessageSize(m_bigPackets);
157+ }
158+
159+ if (m_proxy) {
160+ auto packet = std::make_shared<ProxyPacket>(outputMessage->getHeaderBuffer(), outputMessage->getWriteBuffer());
161+ g_proxy.send(m_proxy, packet);
162+ outputMessage->reset();
163+ return;
164+ }
165+
166+ // send
167+ if (m_connection)
168+ m_connection->write(outputMessage->getHeaderBuffer(), outputMessage->getMessageSize());
169+
170+ // reset message to allow reuse
171+ outputMessage->reset();
172+}
173+
174+void Protocol::recv()
175+{
176+ if (m_player)
177+ return;
178+
179+ if (m_proxy) {
180+ return;
181+ }
182+
183+ m_inputMessage->reset();
184+
185+ // first update message header size
186+ int headerSize = m_bigPackets ? 4 : 2; // 2 or 4 bytes for message size
187+ if (m_checksumEnabled)
188+ headerSize += 4; // 4 bytes for checksum
189+ if (m_xteaEncryptionEnabled)
190+ headerSize += m_bigPackets ? 4 : 2; // 2 or 4 bytes for XTEA encrypted message size
191+ m_inputMessage->setHeaderSize(headerSize);
192+
193+ // read the first 2 bytes which contain the message size
194+ if (m_connection)
195+ m_connection->read(m_bigPackets ? 4 : 2, std::bind(&Protocol::internalRecvHeader, asProtocol(), std::placeholders::_1, std::placeholders::_2));
196+}
197+
198+void Protocol::internalRecvHeader(uint8* buffer, uint32 size)
199+{
200+ // read message size
201+ m_inputMessage->fillBuffer(buffer, size);
202+ uint32 remainingSize = m_inputMessage->readSize(m_bigPackets);
203+
204+ // read remaining message data
205+ if (m_connection)
206+ m_connection->read(remainingSize, std::bind(&Protocol::internalRecvData, asProtocol(), std::placeholders::_1, std::placeholders::_2));
207+}
208+
209+void Protocol::internalRecvData(uint8* buffer, uint32 size)
210+{
211+ // process data only if really connected
212+ if (!isConnected()) {
213+ g_logger.traceError("received data while disconnected");
214+ return;
215+ }
216+
217+ m_inputMessage->fillBuffer(buffer, size);
218+
219+ bool decompress = false;
220+ if (m_sequencedPackets) {
221+ if (m_inputMessage->getU32() >= 0xC0000000) {
222+ decompress = true;
223+ }
224+ } else if (m_checksumEnabled) {
225+ if (m_inputMessage->peekU32() == 0) { // compressed data
226+ m_inputMessage->getU32();
227+ decompress = true;
228+ } else if (!m_inputMessage->readChecksum()) {
229+ g_logger.traceError(stdext::format("got a network message with invalid checksum, size: %i", (int)m_inputMessage->getMessageSize()));
230+ return;
231+ }
232+ }
233+
234+ if (m_xteaEncryptionEnabled) {
235+ if (!xteaDecrypt(m_inputMessage)) {
236+ g_logger.traceError("failed to decrypt message");
237+ return;
238+ }
239+ }
240+
241+ if (decompress || m_compression) {
242+ m_inputMessage->addZlibFooter();
243+ m_zstream.next_in = m_inputMessage->getDataBuffer();
244+ m_zstream.next_out = m_zstreamBuffer.data();
245+ m_zstream.avail_in = m_inputMessage->getUnreadSize();
246+ m_zstream.avail_out = m_zstreamBuffer.size();
247+ if (inflate(&m_zstream, Z_SYNC_FLUSH) != Z_OK) {
248+ g_logger.traceError("failed to decompress message");
249+ return;
250+ }
251+ int decryptedSize = m_zstreamBuffer.size() - m_zstream.avail_out;
252+ if (decryptedSize == 0) {
253+ g_logger.traceError(stdext::format("invalid size of decompressed message - %i", (int)decryptedSize));
254+ return;
255+ }
256+ m_inputMessage->fillBuffer(m_zstreamBuffer.data(), decryptedSize);
257+ m_inputMessage->setMessageSize(m_inputMessage->getHeaderSize() + decryptedSize);
258+ }
259+
260+ if (m_recorder) {
261+ m_recorder->addInputPacket(m_inputMessage);
262+ }
263+ onRecv(m_inputMessage);
264+}
265+
266+void Protocol::generateXteaKey()
267+{
268+ std::mt19937 eng(std::time(NULL));
269+ std::uniform_int_distribution<uint32> unif(0, 0xFFFFFFFF);
270+ m_xteaKey[0] = unif(eng);
271+ m_xteaKey[1] = unif(eng);
272+ m_xteaKey[2] = unif(eng);
273+ m_xteaKey[3] = unif(eng);
274+}
275+
276+void Protocol::setXteaKey(uint32 a, uint32 b, uint32 c, uint32 d)
277+{
278+ m_xteaKey[0] = a;
279+ m_xteaKey[1] = b;
280+ m_xteaKey[2] = c;
281+ m_xteaKey[3] = d;
282+}
283+
284+std::vector<uint32> Protocol::getXteaKey()
285+{
286+ std::vector<uint32> xteaKey;
287+ xteaKey.resize(4);
288+ for (int i = 0; i < 4; ++i)
289+ xteaKey[i] = m_xteaKey[i];
290+ return xteaKey;
291+}
292+
293+bool Protocol::xteaDecrypt(const InputMessagePtr& inputMessage)
294+{
295+ uint32 encryptedSize = inputMessage->getUnreadSize();
296+ if (encryptedSize % 8 != 0) {
297+ g_logger.traceError(stdext::format("invalid encrypted network message %i", (int)encryptedSize));
298+ return false;
299+ }
300+
301+ uint32* buffer = (uint32*)(inputMessage->getReadBuffer());
302+ uint32_t readPos = 0;
303+
304+ while (readPos < encryptedSize / 4) {
305+ uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
306+ uint32 delta = 0x61C88647;
307+ uint32 sum = 0xC6EF3720;
308+
309+ for (int32 i = 0; i < 32; i++) {
310+ v1 -= ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + m_xteaKey[sum >> 11 & 3]);
311+ sum += delta;
312+ v0 -= ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + m_xteaKey[sum & 3]);
313+ }
314+ buffer[readPos] = v0; buffer[readPos + 1] = v1;
315+ readPos = readPos + 2;
316+ }
317+
318+ uint32 decryptedSize = m_bigPackets ? (inputMessage->getU32() + 4) : (inputMessage->getU16() + 2);
319+ int sizeDelta = decryptedSize - encryptedSize;
320+ if (sizeDelta > 0 || -sizeDelta > (int)encryptedSize) {
321+ g_logger.traceError("invalid decrypted network message");
322+ return false;
323+ }
324+
325+ inputMessage->setMessageSize(inputMessage->getMessageSize() + sizeDelta);
326+ return true;
327+}
328+
329+void Protocol::xteaEncrypt(const OutputMessagePtr& outputMessage)
330+{
331+ outputMessage->writeMessageSize(m_bigPackets);
332+ uint32 encryptedSize = outputMessage->getMessageSize();
333+
334+ //add bytes until reach 8 multiple
335+ if ((encryptedSize % 8) != 0) {
336+ uint32 n = 8 - (encryptedSize % 8);
337+ outputMessage->addPaddingBytes(n);
338+ encryptedSize += n;
339+ }
340+
341+ uint32_t readPos = 0;
342+ uint32* buffer = (uint32*)(outputMessage->getDataBuffer() - (m_bigPackets ? 4 : 2));
343+ while (readPos < encryptedSize / 4) {
344+ uint32 v0 = buffer[readPos], v1 = buffer[readPos + 1];
345+ uint32 delta = 0x61C88647;
346+ uint32 sum = 0;
347+
348+ for (int32 i = 0; i < 32; i++) {
349+ v0 += ((v1 << 4 ^ v1 >> 5) + v1) ^ (sum + m_xteaKey[sum & 3]);
350+ sum -= delta;
351+ v1 += ((v0 << 4 ^ v0 >> 5) + v0) ^ (sum + m_xteaKey[sum >> 11 & 3]);
352+ }
353+ buffer[readPos] = v0; buffer[readPos + 1] = v1;
354+ readPos = readPos + 2;
355+ }
356+}
357+
358+void Protocol::onConnect()
359+{
360+ callLuaField("onConnect");
361+}
362+
363+void Protocol::onRecv(const InputMessagePtr& inputMessage)
364+{
365+ callLuaField("onRecv", inputMessage);
366+}
367+
368+void Protocol::onError(const boost::system::error_code& err)
369+{
370+ callLuaField("onError", err.message(), err.value());
371+ disconnect();
372+}
373+
374+void Protocol::onPlayerPacket(const std::shared_ptr<std::vector<uint8_t>>& packet)
375+{
376+ if (m_disconnected)
377+ return;
378+ auto self(asProtocol());
379+ boost::asio::post(g_ioService, [&, self, packet] {
380+ if (m_disconnected)
381+ return;
382+ m_inputMessage->reset();
383+
384+ m_inputMessage->setHeaderSize(0);
385+ m_inputMessage->fillBuffer(packet->data(), packet->size());
386+ m_inputMessage->setMessageSize(packet->size());
387+ onRecv(m_inputMessage);
388+ });
389+}
390+
391+void Protocol::onProxyPacket(const std::shared_ptr<std::vector<uint8_t>>& packet)
392+{
393+ if (m_disconnected)
394+ return;
395+ auto self(asProtocol());
396+ boost::asio::post(g_ioService, [&, self, packet] {
397+ if (m_disconnected)
398+ return;
399+ m_inputMessage->reset();
400+
401+ // first update message header size
402+ int headerSize = m_bigPackets ? 4 : 2; // 2 bytes for message size
403+ if (m_checksumEnabled)
404+ headerSize += 4; // 4 bytes for checksum
405+ if (m_xteaEncryptionEnabled)
406+ headerSize += m_bigPackets ? 4 : 2; // 2 bytes for XTEA encrypted message size
407+ m_inputMessage->setHeaderSize(headerSize);
408+ m_inputMessage->fillBuffer(packet->data(), m_bigPackets ? 4 : 2);
409+ m_inputMessage->readSize(m_bigPackets);
410+ internalRecvData(packet->data() + (m_bigPackets ? 4 : 2), packet->size() - (m_bigPackets ? 4 : 2));
411+ });
412+}
413+
414+void Protocol::onLocalDisconnected(boost::system::error_code ec)
415+{
416+ if (m_disconnected)
417+ return;
418+ auto self(asProtocol());
419+ boost::asio::post(g_ioService, [&, self, ec] {
420+ if (m_disconnected)
421+ return;
422+ m_disconnected = true;
423+ onError(ec);
424+ });
425+}
A RD_Client/src/framework/net/protocol.h +107-0 View file
@@ -0,0 +1,107 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef PROTOCOL_H
24+#define PROTOCOL_H
25+
26+#include "declarations.h"
27+#include "inputmessage.h"
28+#include "outputmessage.h"
29+#include "connection.h"
30+
31+#include <framework/luaengine/luaobject.h>
32+#include <framework/proxy/proxy.h>
33+
34+#include <zlib.h>
35+
36+// @bindclass
37+class Protocol : public LuaObject
38+{
39+public:
40+ Protocol();
41+ virtual ~Protocol();
42+
43+
44+ void connect(const std::string& host, uint16 port);
45+ void disconnect();
46+
47+ void setRecorder(PacketRecorderPtr recorder);
48+ void playRecord(PacketPlayerPtr player);
49+
50+ bool isConnected();
51+ bool isConnecting();
52+ ticks_t getElapsedTicksSinceLastRead() { return m_connection ? m_connection->getElapsedTicksSinceLastRead() : -1; }
53+
54+ ConnectionPtr getConnection() { return m_connection; }
55+ void setConnection(const ConnectionPtr& connection) { m_connection = connection; }
56+
57+ void generateXteaKey();
58+ void setXteaKey(uint32 a, uint32 b, uint32 c, uint32 d);
59+ std::vector<uint32> getXteaKey();
60+ void enableXteaEncryption() { m_xteaEncryptionEnabled = true; }
61+
62+ void enableChecksum() { m_checksumEnabled = true; }
63+ void enabledSequencedPackets() { m_sequencedPackets = true; }
64+ void enableBigPackets() { m_bigPackets = true; }
65+ void enableCompression() { m_compression = true; }
66+
67+ virtual void send(const OutputMessagePtr& outputMessage, bool rawPacket = false);
68+ virtual void recv();
69+
70+ ProtocolPtr asProtocol() { return static_self_cast<Protocol>(); }
71+
72+protected:
73+ virtual void onConnect();
74+ virtual void onRecv(const InputMessagePtr& inputMessage);
75+ virtual void onError(const boost::system::error_code& err);
76+
77+ void onProxyPacket(const std::shared_ptr<std::vector<uint8_t>>& packet);
78+ void onPlayerPacket(const std::shared_ptr<std::vector<uint8_t>>& packet);
79+ void onLocalDisconnected(boost::system::error_code ec);
80+ bool m_disconnected = false;
81+ uint32_t m_proxy = 0;
82+
83+ uint32 m_xteaKey[4];
84+ uint32 m_packetNumber;
85+
86+ PacketPlayerPtr m_player;
87+ PacketRecorderPtr m_recorder;
88+
89+private:
90+ void internalRecvHeader(uint8* buffer, uint32 size);
91+ void internalRecvData(uint8* buffer, uint32 size);
92+
93+ bool xteaDecrypt(const InputMessagePtr& inputMessage);
94+ void xteaEncrypt(const OutputMessagePtr& outputMessage);
95+
96+ bool m_checksumEnabled;
97+ bool m_sequencedPackets;
98+ bool m_xteaEncryptionEnabled;
99+ bool m_bigPackets;
100+ bool m_compression;
101+ ConnectionPtr m_connection;
102+ InputMessagePtr m_inputMessage;
103+ z_stream m_zstream;
104+ std::vector<uint8_t> m_zstreamBuffer;
105+};
106+
107+#endif
A RD_Client/src/framework/net/server.cpp +64-0 View file
@@ -0,0 +1,64 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "server.h"
24+#include "connection.h"
25+
26+extern asio::io_service g_ioService;
27+
28+Server::Server(int port)
29+ : m_acceptor(g_ioService, asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port))
30+{
31+}
32+
33+ServerPtr Server::create(int port)
34+{
35+ try {
36+ Server *server = new Server(port);
37+ return ServerPtr(server);
38+ }
39+ catch(const std::exception& e) {
40+ g_logger.error(stdext::format("Failed to initialize server: %s", e.what()));
41+ return ServerPtr();
42+ }
43+}
44+
45+void Server::close()
46+{
47+ m_isOpen = false;
48+ m_acceptor.cancel();
49+ m_acceptor.close();
50+}
51+
52+void Server::acceptNext()
53+{
54+ ConnectionPtr connection = ConnectionPtr(new Connection);
55+ connection->m_connecting = true;
56+ auto self = static_self_cast<Server>();
57+ m_acceptor.async_accept(connection->m_socket, [=](const boost::system::error_code& error) {
58+ if(!error) {
59+ connection->m_connected = true;
60+ connection->m_connecting = false;
61+ }
62+ self->callLuaField("onAccept", connection, error.message(), error.value());
63+ });
64+}
A RD_Client/src/framework/net/server.h +44-0 View file
@@ -0,0 +1,44 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef SERVER_H
24+#define SERVER_H
25+
26+#include "declarations.h"
27+#include <framework/luaengine/luaobject.h>
28+
29+class Server : public LuaObject
30+{
31+public:
32+ Server(int port);
33+ static ServerPtr create(int port);
34+ bool isOpen() { return m_isOpen; }
35+ void close();
36+
37+ void acceptNext();
38+
39+private:
40+ stdext::boolean<true> m_isOpen;
41+ asio::ip::tcp::acceptor m_acceptor;
42+};
43+
44+#endif
A RD_Client/src/framework/otml/declarations.h +37-0 View file
@@ -0,0 +1,37 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef FRAMEWORK_OTML_DECLARATIONS_H
24+#define FRAMEWORK_OTML_DECLARATIONS_H
25+
26+#include <framework/global.h>
27+
28+class OTMLNode;
29+class OTMLDocument;
30+class OTMLParser;
31+class OTMLEmitter;
32+
33+typedef stdext::shared_object_ptr<OTMLNode> OTMLNodePtr;
34+typedef stdext::shared_object_ptr<OTMLDocument> OTMLDocumentPtr;
35+typedef std::vector<OTMLNodePtr> OTMLNodeList;
36+
37+#endif
A RD_Client/src/framework/otml/otml.h +29-0 View file
@@ -0,0 +1,29 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef OTML_H
24+#define OTML_H
25+
26+#include "otmldocument.h"
27+#include "otmlnode.h"
28+
29+#endif
A RD_Client/src/framework/otml/otmldocument.cpp +69-0 View file
@@ -0,0 +1,69 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "otmldocument.h"
24+#include "otmlparser.h"
25+#include "otmlemitter.h"
26+
27+#include <framework/core/resourcemanager.h>
28+
29+OTMLDocumentPtr OTMLDocument::create()
30+{
31+ OTMLDocumentPtr doc(new OTMLDocument);
32+ doc->setTag("doc");
33+ return doc;
34+}
35+
36+OTMLDocumentPtr OTMLDocument::parse(const std::string& fileName)
37+{
38+ std::stringstream fin;
39+ std::string source = g_resources.resolvePath(fileName);
40+ g_resources.readFileStream(source, fin);
41+ return parse(fin, source);
42+}
43+
44+OTMLDocumentPtr OTMLDocument::parseString(const std::string& data, const std::string& source)
45+{
46+ std::istringstream is(data);
47+ return parse(is, source);
48+}
49+
50+OTMLDocumentPtr OTMLDocument::parse(std::istream& in, const std::string& source)
51+{
52+ OTMLDocumentPtr doc(new OTMLDocument);
53+ doc->setSource(source);
54+ OTMLParser parser(doc, in);
55+ parser.parse();
56+ return doc;
57+}
58+
59+std::string OTMLDocument::emit()
60+{
61+ return OTMLEmitter::emitNode(asOTMLNode()) + "\n";
62+}
63+
64+bool OTMLDocument::save(const std::string& fileName)
65+{
66+ m_source = fileName;
67+ return g_resources.writeFileContents(fileName, emit());
68+}
69+
A RD_Client/src/framework/otml/otmldocument.h +56-0 View file
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef OTMLDOCUMENT_H
24+#define OTMLDOCUMENT_H
25+
26+#include "otmlnode.h"
27+
28+class OTMLDocument : public OTMLNode
29+{
30+public:
31+ virtual ~OTMLDocument() { }
32+
33+ /// Create a new OTML document for filling it with nodes
34+ static OTMLDocumentPtr create();
35+
36+ /// Parse OTML from a file
37+ static OTMLDocumentPtr parse(const std::string& fileName);
38+
39+ /// Parse OTML from a string
40+ static OTMLDocumentPtr parseString(const std::string& data, const std::string& source);
41+
42+ /// Parse OTML from input stream
43+ /// @param source is the file name that will be used to show errors messages
44+ static OTMLDocumentPtr parse(std::istream& in, const std::string& source);
45+
46+ /// Emits this document and all it's children to a std::string
47+ std::string emit();
48+
49+ /// Save this document to a file
50+ bool save(const std::string& fileName);
51+
52+private:
53+ OTMLDocument() { }
54+};
55+
56+#endif
A RD_Client/src/framework/otml/otmlemitter.cpp +94-0 View file
@@ -0,0 +1,94 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "otmlemitter.h"
24+#include "otmldocument.h"
25+
26+std::string OTMLEmitter::emitNode(const OTMLNodePtr& node, int currentDepth)
27+{
28+ std::stringstream ss;
29+
30+ // emit nodes
31+ if(currentDepth >= 0) {
32+ // fill spaces for current depth
33+ for(int i=0;i<currentDepth;++i)
34+ ss << " ";
35+
36+ // emit node tag
37+ if(node->hasTag()) {
38+ ss << node->tag();
39+
40+ // add ':' to if the node is unique or has value
41+ if(node->hasValue() || node->isUnique() || node->isNull())
42+ ss << ":";
43+ } else
44+ ss << "-";
45+
46+ // emit node value
47+ if(node->isNull())
48+ ss << " ~";
49+ else if(node->hasValue()) {
50+ ss << " ";
51+
52+ std::string value = node->value();
53+
54+ // emit multiline values
55+ if(value.find("\n") != std::string::npos) {
56+ if(value[value.length()-1] == '\n' && value[value.length()-2] == '\n')
57+ ss << "|+";
58+ else if(value[value.length()-1] == '\n')
59+ ss << "|";
60+ else
61+ ss << "|-";
62+
63+ // multilines
64+ for(std::size_t pos = 0; pos < value.length(); ++pos) {
65+ ss << "\n";
66+
67+ // fill spaces for multiline depth
68+ for(int i=0;i<currentDepth+1;++i)
69+ ss << " ";
70+
71+ // fill until a new line
72+ while(pos < value.length()) {
73+ if(value[pos] == '\n')
74+ break;
75+ ss << value[pos++];
76+ }
77+ }
78+ // emit inline values
79+ } else
80+ ss << value;
81+ }
82+ }
83+
84+ // emit children
85+ int i = 0;
86+ for(auto& child : node->children()) {
87+ if(currentDepth >= 0 || i != 0)
88+ ss << "\n";
89+ ss << emitNode(child, currentDepth+1);
90+ i += 1;
91+ }
92+
93+ return ss.str();
94+}
A RD_Client/src/framework/otml/otmlemitter.h +35-0 View file
@@ -0,0 +1,35 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef OTMLEMITTER_H
24+#define OTMLEMITTER_H
25+
26+#include "declarations.h"
27+
28+class OTMLEmitter
29+{
30+public:
31+ /// Emits a node and it's children to a std::string
32+ static std::string emitNode(const OTMLNodePtr& node, int currentDepth = -1);
33+};
34+
35+#endif
A RD_Client/src/framework/otml/otmlexception.cpp +47-0 View file
@@ -0,0 +1,47 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "otmlexception.h"
24+#include "otmldocument.h"
25+
26+OTMLException::OTMLException(const OTMLNodePtr& node, const std::string& error)
27+{
28+ std::stringstream ss;
29+ ss << "OTML error";
30+ if(!node->source().empty())
31+ ss << " in '" << node->source() << "'";
32+ ss << ": " << error;
33+ m_what = ss.str();
34+}
35+
36+OTMLException::OTMLException(const OTMLDocumentPtr& doc, const std::string& error, int line)
37+{
38+ std::stringstream ss;
39+ ss << "OTML error";
40+ if(doc && !doc->source().empty()) {
41+ ss << " in '" << doc->source() << "'";
42+ if(line >= 0)
43+ ss << " at line " << line;
44+ }
45+ ss << ": " << error;
46+ m_what = ss.str();
47+}
A RD_Client/src/framework/otml/otmlexception.h +42-0 View file
@@ -0,0 +1,42 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef OTMLEXCEPTION_H
24+#define OTMLEXCEPTION_H
25+
26+#include "declarations.h"
27+
28+/// All OTML errors throw this exception
29+class OTMLException : public stdext::exception
30+{
31+public:
32+ OTMLException(const OTMLNodePtr& node, const std::string& error);
33+ OTMLException(const OTMLDocumentPtr& doc, const std::string& error, int line = -1);
34+ virtual ~OTMLException() throw() { };
35+
36+ virtual const char* what() const throw() { return m_what.c_str(); }
37+
38+protected:
39+ std::string m_what;
40+};
41+
42+#endif
A RD_Client/src/framework/otml/otmlnode.cpp +204-0 View file
@@ -0,0 +1,204 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "otmlnode.h"
24+#include "otmlemitter.h"
25+#include "otmldocument.h"
26+
27+#include <framework/util/extras.h>
28+
29+OTMLNodePtr OTMLNode::create(std::string tag, bool unique)
30+{
31+ OTMLNodePtr node(new OTMLNode);
32+ node->setTag(tag);
33+ node->setUnique(unique);
34+ return node;
35+}
36+
37+OTMLNodePtr OTMLNode::create(std::string tag, std::string value)
38+{
39+ OTMLNodePtr node(new OTMLNode);
40+ node->setTag(tag);
41+ node->setValue(value);
42+ node->setUnique(true);
43+ return node;
44+}
45+
46+bool OTMLNode::hasChildren()
47+{
48+ for (auto& [tag, children] : m_children) {
49+ for (auto& child : children) {
50+ if (!child->isNull())
51+ return true;
52+ }
53+ }
54+ return false;
55+}
56+
57+OTMLNodePtr OTMLNode::get(const std::string& childTag)
58+{
59+ if (childTag.size() > 0 && childTag[0] == '!')
60+ g_logger.fatal(stdext::format("Invalid childTag %s", childTag));
61+
62+ auto it = m_children.find(childTag);
63+ if (it == m_children.end())
64+ return nullptr;
65+
66+ for (auto& child : it->second) {
67+ if (!child->isNull())
68+ return child;
69+ }
70+
71+ return nullptr;
72+}
73+
74+OTMLNodePtr OTMLNode::at(const std::string& childTag)
75+{
76+ OTMLNodePtr res = get(childTag);
77+ if(!res)
78+ throw OTMLException(asOTMLNode(), stdext::format("child node with tag '%s' not found", childTag));
79+ return res;
80+}
81+
82+void OTMLNode::addChild(const OTMLNodePtr& newChild)
83+{
84+ // replace is needed when the tag is marked as unique
85+ if(newChild->hasTag()) {
86+ auto it = m_children.find(newChild->tag());
87+ if (it != m_children.end()) {
88+ for (auto& node : it->second) {
89+ if (!node->isUnique() && !newChild->isUnique())
90+ continue;
91+ newChild->setUnique(true);
92+
93+ if (node->hasChildren() && newChild->hasChildren()) {
94+ OTMLNodePtr tmpNode = node->clone();
95+ tmpNode->merge(newChild);
96+ newChild->copy(tmpNode);
97+ }
98+
99+ it->second.clear();
100+ break;
101+ }
102+ }
103+ }
104+
105+ static size_t index = 0;
106+ if(newChild->getIndex() == 0)
107+ newChild->setIndex(++index);
108+ m_children[newChild->tag()].push_back(newChild);
109+ newChild->lockTag();
110+}
111+
112+bool OTMLNode::removeChild(const OTMLNodePtr& oldChild)
113+{
114+ auto it = m_children.find(oldChild->tag());
115+ if (it == m_children.end())
116+ return false;
117+
118+ auto it2 = std::find(it->second.begin(), it->second.end(), oldChild);
119+ if(it2 != it->second.end()) {
120+ it->second.erase(it2);
121+ return true;
122+ }
123+ return false;
124+}
125+
126+void OTMLNode::copy(const OTMLNodePtr& node)
127+{
128+ setTag(node->tag());
129+ setValue(node->rawValue());
130+ setUnique(node->isUnique());
131+ setNull(node->isNull());
132+ setSource(node->source());
133+ setIndex(node->getIndex());
134+ clear();
135+ for (auto& [tag, children] : node->m_children) {
136+ for (auto& child : children) {
137+ addChild(child->clone());
138+ }
139+ }
140+}
141+
142+void OTMLNode::merge(const OTMLNodePtr& node)
143+{
144+ for (auto& [tag, children] : node->m_children) {
145+ for (auto& child : children) {
146+ addChild(child->clone());
147+ }
148+ }
149+ setTag(node->tag());
150+ setSource(node->source());
151+}
152+
153+void OTMLNode::clear()
154+{
155+ m_children.clear();
156+}
157+
158+OTMLNodeList OTMLNode::children()
159+{
160+ OTMLNodeList ret;
161+ for (auto& [tag, children] : m_children) {
162+ for (auto& child : children) {
163+ if (!child->isNull())
164+ ret.push_back(child);
165+ }
166+ }
167+ std::sort(ret.begin(), ret.end(), [](auto& n1, auto& n2) {
168+ return n1->getIndex() < n2->getIndex();
169+ });
170+ return ret;
171+}
172+
173+OTMLNodePtr OTMLNode::clone()
174+{
175+ OTMLNodePtr myClone(new OTMLNode);
176+ myClone->setTag(m_tag);
177+ myClone->setValue(m_value);
178+ myClone->setUnique(m_unique);
179+ myClone->setNull(m_null);
180+ myClone->setSource(m_source);
181+ myClone->setIndex(m_index);
182+ for (auto& [tag, children] : m_children) {
183+ for (auto& child : children) {
184+ myClone->addChild(child->clone());
185+ }
186+ }
187+ return myClone;
188+}
189+
190+std::string OTMLNode::emit()
191+{
192+ return OTMLEmitter::emitNode(asOTMLNode(), 0);
193+}
194+
195+void OTMLNode::setTag(const std::string& tag) {
196+ if (m_tagLocked && tag != m_tag) {
197+ std::string correct_tag = m_tag;
198+ if (correct_tag.size() > 0 && m_tag[0] == '!')
199+ correct_tag = correct_tag.substr(1);
200+ if(correct_tag != tag)
201+ g_logger.fatal(stdext::format("Trying to setTag for locked QTMLNode %s to %s", m_tag, tag));
202+ }
203+ m_tag = tag;
204+}
A RD_Client/src/framework/otml/otmlnode.h +176-0 View file
@@ -0,0 +1,176 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef OTMLNODE_H
24+#define OTMLNODE_H
25+
26+#include "declarations.h"
27+
28+class OTMLNode : public stdext::shared_object
29+{
30+public:
31+ virtual ~OTMLNode() { }
32+
33+ static OTMLNodePtr create(std::string tag = "", bool unique = false);
34+ static OTMLNodePtr create(std::string tag, std::string value);
35+
36+ std::string tag() { return m_tag; }
37+ int size() { return m_children.size(); }
38+ std::string source() { return m_source; }
39+ std::string rawValue() { return m_value; }
40+
41+ bool isUnique() { return m_unique; }
42+ bool isNull() { return m_null; }
43+
44+ bool hasTag() { return !m_tag.empty(); }
45+ bool hasValue() { return !m_value.empty(); }
46+ bool hasChildren();
47+ bool hasChildAt(const std::string& childTag) { return !!get(childTag); }
48+ size_t getIndex() { return m_index; }
49+
50+ void setTag(const std::string& tag);
51+ void setValue(const std::string& value) { m_value = value; }
52+ void setNull(bool null) { m_null = null; }
53+ void setUnique(bool unique) { m_unique = unique; }
54+ void setSource(const std::string& source) { m_source = source; }
55+ void setIndex(size_t index) { m_index = index; }
56+
57+ void lockTag() {
58+ m_tagLocked = true;
59+ }
60+
61+ OTMLNodePtr get(const std::string& childTag);
62+ OTMLNodePtr getIndex(int childIndex);
63+
64+ OTMLNodePtr at(const std::string& childTag);
65+
66+ void addChild(const OTMLNodePtr& newChild);
67+ bool removeChild(const OTMLNodePtr& oldChild);
68+ void copy(const OTMLNodePtr& node);
69+ void merge(const OTMLNodePtr& node);
70+ void clear();
71+
72+ OTMLNodeList children();
73+ OTMLNodePtr clone();
74+
75+ template<typename T = std::string>
76+ T value();
77+ template<typename T = std::string>
78+ T valueAt(const std::string& childTag);
79+ template<typename T = std::string>
80+ T valueAtIndex(int childIndex);
81+ template<typename T = std::string>
82+ T valueAt(const std::string& childTag, const T& def);
83+ template<typename T = std::string>
84+ T valueAtIndex(int childIndex, const T& def);
85+
86+ template<typename T>
87+ void write(const T& v);
88+ template<typename T>
89+ void writeAt(const std::string& childTag, const T& v);
90+ template<typename T>
91+ void writeIn(const T& v);
92+
93+ virtual std::string emit();
94+
95+ OTMLNodePtr asOTMLNode() { return static_self_cast<OTMLNode>(); }
96+
97+protected:
98+ OTMLNode() : m_unique(false), m_null(false) { }
99+
100+ std::unordered_map<std::string, std::vector<OTMLNodePtr>> m_children;
101+ std::string m_tag;
102+ std::string m_value;
103+ std::string m_source;
104+ size_t m_index = 0;
105+ bool m_unique;
106+ bool m_null;
107+ bool m_tagLocked = false;
108+};
109+
110+#include "otmlexception.h"
111+
112+template<>
113+inline std::string OTMLNode::value<std::string>() {
114+ std::string value = m_value;
115+ if(stdext::starts_with(value, "\"") && stdext::ends_with(value, "\"")) {
116+ value = value.substr(1, value.length()-2);
117+ stdext::replace_all(value, "\\\\", "\\");
118+ stdext::replace_all(value, "\\\"", "\"");
119+ stdext::replace_all(value, "\\t", "\t");
120+ stdext::replace_all(value, "\\n", "\n");
121+ stdext::replace_all(value, "\\'", "\'");
122+ }
123+ return value;
124+}
125+
126+template<typename T>
127+T OTMLNode::value() {
128+ T ret;
129+ if(!stdext::cast(m_value, ret))
130+ throw OTMLException(asOTMLNode(), stdext::format("failed to cast node value '%s' to type '%s'", m_value, stdext::demangle_type<T>()));
131+ return ret;
132+}
133+
134+template<typename T>
135+T OTMLNode::valueAt(const std::string& childTag) {
136+ OTMLNodePtr node = at(childTag);
137+ return node->value<T>();
138+}
139+
140+template<typename T>
141+T OTMLNode::valueAt(const std::string& childTag, const T& def) {
142+ if(OTMLNodePtr node = get(childTag))
143+ if(!node->isNull())
144+ return node->value<T>();
145+ return def;
146+}
147+
148+template<typename T>
149+T OTMLNode::valueAtIndex(int childIndex, const T& def) {
150+ if(OTMLNodePtr node = getIndex(childIndex))
151+ return node->value<T>();
152+ return def;
153+}
154+
155+template<typename T>
156+void OTMLNode::write(const T& v) {
157+ m_value = stdext::safe_cast<std::string>(v);
158+}
159+
160+template<typename T>
161+void OTMLNode::writeAt(const std::string& childTag, const T& v) {
162+ OTMLNodePtr child = OTMLNode::create(childTag);
163+ child->setUnique(true);
164+ child->write<T>(v);
165+ addChild(child);
166+}
167+
168+template<typename T>
169+void OTMLNode::writeIn(const T& v) {
170+ OTMLNodePtr child = OTMLNode::create();
171+ child->write<T>(v);
172+ addChild(child);
173+}
174+
175+#endif
176+
A RD_Client/src/framework/otml/otmlparser.cpp +205-0 View file
@@ -0,0 +1,205 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "otmlparser.h"
24+#include "otmldocument.h"
25+#include "otmlexception.h"
26+#include <boost/tokenizer.hpp>
27+
28+OTMLParser::OTMLParser(OTMLDocumentPtr doc, std::istream& in) :
29+ currentDepth(0), currentLine(0),
30+ doc(doc), currentParent(doc), previousNode(0),
31+ in(in)
32+{
33+}
34+
35+void OTMLParser::parse()
36+{
37+ if(!in.good())
38+ throw OTMLException(doc, "cannot read from input stream");
39+
40+ while(!in.eof())
41+ parseLine(getNextLine());
42+}
43+
44+std::string OTMLParser::getNextLine()
45+{
46+ currentLine++;
47+ std::string line;
48+ std::getline(in, line);
49+ return line;
50+}
51+
52+int OTMLParser::getLineDepth(const std::string& line, bool multilining)
53+{
54+ // count number of spaces at the line beginning
55+ std::size_t spaces = 0;
56+ while(line[spaces] == ' ')
57+ spaces++;
58+
59+ // pre calculate depth
60+ int depth = spaces / 2;
61+
62+ if(!multilining || depth <= currentDepth) {
63+ // check the next character is a tab
64+ if(line[spaces] == '\t')
65+ throw OTMLException(doc, "indentation with tabs are not allowed", currentLine);
66+
67+ // must indent every 2 spaces
68+ if(spaces % 2 != 0)
69+ throw OTMLException(doc, "must indent every 2 spaces", currentLine);
70+ }
71+
72+ return depth;
73+}
74+
75+void OTMLParser::parseLine(std::string line)
76+{
77+ int depth = getLineDepth(line);
78+
79+ if(depth == -1)
80+ return;
81+
82+ // remove line sides spaces
83+ stdext::trim(line);
84+
85+ // skip empty lines
86+ if(line.empty())
87+ return;
88+
89+ // skip comments
90+ if(stdext::starts_with(line, "//"))
91+ return;
92+
93+ // a depth above, change current parent to the previous added node
94+ if(depth == currentDepth+1) {
95+ currentParent = previousNode;
96+ // a depth below, change parent to previous parent
97+ } else if(depth < currentDepth) {
98+ for(int i=0;i<currentDepth-depth;++i)
99+ currentParent = parentMap[currentParent];
100+ // if it isn't the current depth, it's a syntax error
101+ } else if(depth != currentDepth)
102+ throw OTMLException(doc, "invalid indentation depth, are you indenting correctly?", currentLine);
103+
104+ // sets current depth
105+ currentDepth = depth;
106+
107+ // alright, new depth is set, the line is not empty and it isn't a comment
108+ // then it must be a node, so we parse it
109+ parseNode(line);
110+}
111+
112+void OTMLParser::parseNode(const std::string& data)
113+{
114+ std::string tag;
115+ std::string value;
116+ std::size_t dotsPos = data.find_first_of(':');
117+ int nodeLine = currentLine;
118+
119+ // node that has no tag and may have a value
120+ if(!data.empty() && data[0] == '-') {
121+ value = data.substr(1);
122+ stdext::trim(value);
123+ // node that has tag and possible a value
124+ } else if(dotsPos != std::string::npos) {
125+ tag = data.substr(0, dotsPos);
126+ if(data.size() > dotsPos+1)
127+ value = data.substr(dotsPos+1);
128+ // node that has only a tag
129+ } else {
130+ tag = data;
131+ }
132+
133+ stdext::trim(tag);
134+ stdext::trim(value);
135+
136+ // process multitine values
137+ if(value == "|" || value == "|-" || value == "|+") {
138+ // reads next lines until we can a value below the same depth
139+ std::string multiLineData;
140+ do {
141+ size_t lastPos = in.tellg();
142+ std::string line = getNextLine();
143+ int depth = getLineDepth(line, true);
144+
145+ // depth above current depth, add the text to the multiline
146+ if(depth > currentDepth) {
147+ multiLineData += line.substr((currentDepth+1)*2);
148+ // it has contents below the current depth
149+ } else {
150+ // if not empty, its a node
151+ stdext::trim(line);
152+ if(!line.empty()) {
153+ // rewind and break
154+ in.seekg(lastPos, std::ios::beg);
155+ currentLine--;
156+ break;
157+ }
158+ }
159+ multiLineData += "\n";
160+ } while(!in.eof());
161+
162+ /* determine how to treat new lines at the end
163+ * | strip all new lines at the end and add just a new one
164+ * |- strip all new lines at the end
165+ * |+ keep all the new lines at the end (the new lines until next node)
166+ */
167+ if(value == "|" || value == "|-") {
168+ // remove all new lines at the end
169+ int lastPos = multiLineData.length();
170+ while(multiLineData[--lastPos] == '\n')
171+ multiLineData.erase(lastPos, 1);
172+
173+ if(value == "|")
174+ multiLineData.append("\n");
175+ } // else it's |+
176+
177+ value = multiLineData;
178+ }
179+
180+ // create the node
181+ OTMLNodePtr node = OTMLNode::create(tag);
182+
183+ node->setUnique(dotsPos != std::string::npos);
184+ node->setTag(tag);
185+ node->setSource(doc->source() + ":" + stdext::unsafe_cast<std::string>(nodeLine));
186+
187+ // ~ is considered the null value
188+ if(value == "~")
189+ node->setNull(true);
190+ else {
191+ if(stdext::starts_with(value, "[") && stdext::ends_with(value, "]")) {
192+ std::string tmp = value.substr(1, value.length()-2);
193+ boost::tokenizer<boost::escaped_list_separator<char>> tokens(tmp);
194+ for(std::string v : tokens) {
195+ stdext::trim(v);
196+ node->writeIn(v);
197+ }
198+ } else
199+ node->setValue(value);
200+ }
201+
202+ currentParent->addChild(node);
203+ parentMap[node] = currentParent;
204+ previousNode = node;
205+}
A RD_Client/src/framework/otml/otmlparser.h +56-0 View file
@@ -0,0 +1,56 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef OTMLPARSER_H
24+#define OTMLPARSER_H
25+
26+#include "declarations.h"
27+
28+class OTMLParser
29+{
30+public:
31+ OTMLParser(OTMLDocumentPtr doc, std::istream& in);
32+
33+ /// Parse the entire document
34+ void parse();
35+
36+private:
37+ /// Retrieve next line from the input stream
38+ std::string getNextLine();
39+ /// Counts depth of a line (every 2 spaces increments one depth)
40+ int getLineDepth(const std::string& line, bool multilining = false);
41+
42+ /// Parse each line of the input stream
43+ void parseLine(std::string line);
44+ /// Parse nodes tag and value
45+ void parseNode(const std::string& data);
46+
47+ int currentDepth;
48+ int currentLine;
49+ OTMLDocumentPtr doc;
50+ OTMLNodePtr currentParent;
51+ std::unordered_map<OTMLNodePtr, OTMLNodePtr> parentMap;
52+ OTMLNodePtr previousNode;
53+ std::istream& in;
54+};
55+
56+#endif
A RD_Client/src/framework/pch.h +93-0 View file
@@ -0,0 +1,93 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef PCH_H
24+#define PCH_H
25+
26+// common C headers
27+#include <cstdio>
28+#include <cstdlib>
29+#include <cstddef>
30+#include <cstring>
31+#include <cmath>
32+
33+// common STL headers
34+#include <iostream>
35+#include <sstream>
36+#include <string>
37+#include <vector>
38+#include <set>
39+#include <list>
40+#include <deque>
41+#include <map>
42+#include <algorithm>
43+#include <functional>
44+#include <array>
45+#include <unordered_map>
46+#include <unordered_set>
47+#include <tuple>
48+#include <iomanip>
49+#include <typeinfo>
50+
51+// new
52+#include <thread>
53+#include <memory>
54+#include <functional>
55+#include <condition_variable>
56+#include <mutex>
57+#include <future>
58+#include <chrono>
59+#include <random>
60+#ifndef ANDROID
61+#include <filesystem>
62+#endif
63+
64+ // boost
65+#ifdef ANDROID
66+#define BOOST_UUID_RANDOM_PROVIDER_FORCE_POSIX
67+#endif
68+#include <boost/system/config.hpp>
69+#include <boost/system/error_code.hpp>
70+#include <boost/asio.hpp>
71+#include <boost/beast.hpp>
72+
73+#include <boost/asio/io_service.hpp>
74+#include <boost/asio/ip/tcp.hpp>
75+#ifndef __EMSCRIPTEN__
76+#include <boost/asio/ssl.hpp>
77+
78+#include <boost/beast/ssl.hpp>
79+#endif
80+#include <boost/beast/core/flat_buffer.hpp>
81+#include <boost/beast/http/write.hpp>
82+#include <boost/beast/http/string_body.hpp>
83+#include <boost/beast/http/dynamic_body.hpp>
84+#include <boost/beast/http/read.hpp>
85+#include <boost/beast/http/parser.hpp>
86+#ifndef __EMSCRIPTEN__
87+#include <boost/beast/websocket.hpp>
88+#include <boost/beast/websocket/ssl.hpp>
89+#endif
90+
91+#include <boost/algorithm/hex.hpp>
92+
93+#endif
A RD_Client/src/framework/platform/androidplatform.cpp +159-0 View file
@@ -0,0 +1,159 @@
1+/*
2+ * Copyright (c) 2010-2016 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+#ifdef ANDROID
24+
25+#include <framework/global.h>
26+
27+#include "platform.h"
28+#include "androidwindow.h"
29+#include <fstream>
30+#include <unistd.h>
31+#include <string.h>
32+#include <framework/stdext/stdext.h>
33+#include <framework/core/eventdispatcher.h>
34+
35+#include <sys/stat.h>
36+
37+void Platform::processArgs(std::vector<std::string>& args)
38+{
39+ //nothing todo, linux args are already utf8 encoded
40+}
41+
42+bool Platform::spawnProcess(std::string process, const std::vector<std::string>& args)
43+{
44+ return false;
45+}
46+
47+int Platform::getProcessId()
48+{
49+ return getpid();
50+}
51+
52+bool Platform::isProcessRunning(const std::string& name)
53+{
54+ return false;
55+}
56+
57+bool Platform::killProcess(const std::string& name)
58+{
59+ return false;
60+}
61+
62+std::string Platform::getTempPath()
63+{
64+ return "/tmp/";
65+}
66+
67+std::string Platform::getCurrentDir()
68+{
69+ std::string res;
70+ char cwd[2048];
71+ if (getcwd(cwd, sizeof(cwd)) != NULL) {
72+ res = cwd;
73+ res += "/";
74+ }
75+ return res;
76+}
77+
78+bool Platform::copyFile(std::string from, std::string to)
79+{
80+ return true;
81+}
82+
83+bool Platform::fileExists(std::string file)
84+{
85+ return true;
86+}
87+
88+bool Platform::removeFile(std::string file)
89+{
90+ return false;
91+}
92+
93+ticks_t Platform::getFileModificationTime(std::string file)
94+{
95+ return 0;
96+}
97+
98+bool Platform::openUrl(std::string url, bool now)
99+{
100+ g_graphicsDispatcher.addEvent(std::bind(&AndroidWindow::openUrl, g_androidWindow, url));
101+ return true;
102+}
103+
104+bool Platform::openDir(std::string path, bool now)
105+{
106+ return true;
107+}
108+
109+std::string Platform::getCPUName()
110+{
111+ return std::string();
112+}
113+
114+double Platform::getTotalSystemMemory()
115+{
116+ return 0;
117+}
118+
119+double Platform::getMemoryUsage()
120+{
121+ return 0;
122+}
123+
124+std::string Platform::getOSName()
125+{
126+ return "android";
127+}
128+
129+std::string Platform::traceback(const std::string& where, int level, int maxDepth)
130+{
131+ return "";
132+}
133+
134+std::vector<std::string> Platform::getMacAddresses()
135+{
136+ return std::vector<std::string>();
137+}
138+
139+std::string Platform::getUserName()
140+{
141+ return "android";
142+}
143+
144+std::vector<std::string> Platform::getDlls()
145+{
146+ return std::vector<std::string>();
147+}
148+
149+std::vector<std::string> Platform::getProcesses()
150+{
151+ return std::vector<std::string>();
152+}
153+
154+std::vector<std::string> Platform::getWindows()
155+{
156+ return std::vector<std::string>();
157+}
158+
159+#endif
A RD_Client/src/framework/platform/androidwindow.h +100-0 View file
@@ -0,0 +1,100 @@
1+#ifndef ANDROID_WINDOW_H
2+#define ANDROID_WINDOW_H
3+
4+#include "platformwindow.h"
5+
6+class AndroidWindow : public PlatformWindow {
7+ enum EventType {
8+ TOUCH_DOWN,
9+ TOUCH_UP,
10+ TOUCH_MOTION,
11+ TOUCH_LONGPRESS,
12+ KEY_DOWN,
13+ KEY_UP,
14+ TEXTINPUT,
15+ EVENT_UNDEFINED
16+ };
17+
18+ enum NativeMessage {
19+ RECREATE_CONTEXT,
20+ APP_TERMINATE
21+ };
22+
23+ void internalInitGL();
24+ void internalDestroyGL();
25+
26+ void internalCheckGL();
27+ void internalChooseGL();
28+ void internalCreateGLContext();
29+ void internalDestroyGLContext();
30+ void internalConnectGLContext();
31+
32+
33+public:
34+ AndroidWindow();
35+ ~AndroidWindow();
36+
37+ void init();
38+ void init(struct android_app* app);
39+ void terminate();
40+ void move(const Point& pos);
41+ void resize(const Size& size);
42+ void show();
43+ void hide();
44+ void minimize();
45+ void maximize();
46+ void poll();
47+ void swapBuffers();
48+ void showMouse();
49+ void hideMouse();
50+
51+ void setMouseCursor(int cursorId);
52+ void restoreMouseCursor();
53+
54+ void setTitle(const std::string& title);
55+ void setMinimumSize(const Size& minimumSize);
56+ void setFullscreen(bool fullscreen);
57+ void setVerticalSync(bool enable);
58+ void setIcon(const std::string& iconFile);
59+ void setClipboardText(const std::string& text);
60+
61+ Size getDisplaySize();
62+ std::string getClipboardText();
63+ std::string getPlatformType();
64+
65+ void displayFatalError(const std::string& message) override;
66+ void showTextEditor(const std::string& title, const std::string& description, const std::string& text, int flags) override;
67+
68+ void handleCmd(int32_t cmd);
69+ int handleInput(AInputEvent* event);
70+ void updateSize();
71+ void handleTextInput(std::string text);
72+ void openUrl(std::string url);
73+
74+protected:
75+ int internalLoadMouseCursor(const ImagePtr& image, const Point& hotSpot) override { return -1; };
76+
77+ JNIEnv* getJNIEnv()
78+ {
79+ return g_androidState->activity->env;
80+ }
81+ JavaVM* getJavaVM()
82+ {
83+ return g_androidState->activity->vm;
84+ }
85+ jobject getClazz()
86+ {
87+ return g_androidState->activity->clazz;
88+ }
89+
90+private:
91+ EGLConfig m_eglConfig;
92+ EGLContext m_eglContext;
93+ EGLDisplay m_eglDisplay;
94+ EGLSurface m_eglSurface;
95+ InputEvent m_multiInputEvent[3];
96+};
97+
98+extern AndroidWindow g_androidWindow;;
99+
100+#endif
A RD_Client/src/framework/platform/crashhandler.h +31-0 View file
@@ -0,0 +1,31 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef CRASHHANDLER_H
24+#define CRASHHANDLER_H
25+
26+#ifdef CRASH_HANDLER
27+void installCrashHandler();
28+void uninstallCrashHandler();
29+#endif
30+
31+#endif
A RD_Client/src/framework/platform/platform.cpp +25-0 View file
@@ -0,0 +1,25 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "platform.h"
24+
25+Platform g_platform;
A RD_Client/src/framework/platform/platform.h +60-0 View file
@@ -0,0 +1,60 @@
1+/*
2+ * Copyright (c) 2010-2017 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+#ifndef PLATFORM_H
24+#define PLATFORM_H
25+
26+#include <string>
27+#include <vector>
28+#include <framework/stdext/types.h>
29+
30+class Platform
31+{
32+public:
33+ void processArgs(std::vector<std::string>& args);
34+ bool spawnProcess(std::string process, const std::vector<std::string>& args);
35+ int getProcessId();
36+ bool isProcessRunning(const std::string& name);
37+ bool killProcess(const std::string& name);
38+ std::string getTempPath();
39+ std::string getCurrentDir();
40+ bool copyFile(std::string from, std::string to);
41+ bool fileExists(std::string file);
42+ bool removeFile(std::string file);
43+ ticks_t getFileModificationTime(std::string file);
44+ bool openUrl(std::string url, bool now = false);
45+ bool openDir(std::string path, bool now = false);
46+ std::string getCPUName();
47+ double getTotalSystemMemory();
48+ double getMemoryUsage();
49+ std::string getOSName();
50+ std::string traceback(const std::string& where, int level = 1, int maxDepth = 32);
51+ std::vector<std::string> getMacAddresses();
52+ std::string getUserName();
53+ std::vector<std::string> getDlls();
54+ std::vector<std::string> getProcesses();
55+ std::vector<std::string> getWindows();
56+};
57+
58+extern Platform g_platform;
59+
60+#endif
A RD_Client/src/framework/platform/platformwindow.cpp +216-0 View file
@@ -0,0 +1,216 @@
1+/*
2+ * Copyright (c) 2010-2017 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 "platformwindow.h"
24+
25+#if defined(WIN32)
26+#include "win32window.h"
27+WIN32Window window;
28+#elif defined(ANDROID)
29+#include "androidwindow.h"
30+#elif defined(__EMSCRIPTEN__)
31+#include "sdlwindow.h"
32+SDLWindow window;
33+#else
34+#include "x11window.h"
35+#include <framework/core/clock.h>
36+X11Window window;
37+#endif
38+
39+#include <framework/core/clock.h>
40+#include <framework/core/eventdispatcher.h>
41+#include <framework/graphics/image.h>
42+
43+#ifdef ANDROID
44+PlatformWindow& g_window = g_androidWindow;
45+#else
46+PlatformWindow& g_window = window;
47+#endif
48+
49+int PlatformWindow::loadMouseCursor(const std::string& file, const Point& hotSpot)
50+{
51+ ImagePtr image = Image::load(file);
52+
53+ if(!image) {
54+ g_logger.traceError(stdext::format("unable to load cursor image file %s", file));
55+ return -1;
56+ }
57+
58+ if(image->getBpp() != 4) {
59+ g_logger.error("the cursor image must have 4 channels");
60+ return -1;
61+ }
62+
63+ if(image->getWidth() != 32 || image->getHeight() != 32) {
64+ g_logger.error("the cursor image must have 32x32 dimension");
65+ return -1;
66+ }
67+
68+ return internalLoadMouseCursor(image, hotSpot);
69+}
70+
71+void PlatformWindow::updateUnmaximizedCoords()
72+{
73+ if(!isMaximized() && !isFullscreen()) {
74+ m_unmaximizedPos = m_position;
75+ m_unmaximizedSize = m_size;
76+ }
77+}
78+
79+void PlatformWindow::processKeyDown(Fw::Key keyCode)
80+{
81+ if (std::this_thread::get_id() != g_dispatcherThreadId) {
82+ g_dispatcher.addEvent(std::bind(&PlatformWindow::processKeyDown, this, keyCode));
83+ return;
84+ }
85+
86+ if(keyCode == Fw::KeyUnknown)
87+ return;
88+
89+ if(keyCode == Fw::KeyCtrl) {
90+ m_inputEvent.keyboardModifiers |= Fw::KeyboardCtrlModifier;
91+ return;
92+ } else if(keyCode == Fw::KeyAlt) {
93+ m_inputEvent.keyboardModifiers |= Fw::KeyboardAltModifier;
94+ return;
95+ } else if(keyCode == Fw::KeyShift) {
96+ m_inputEvent.keyboardModifiers |= Fw::KeyboardShiftModifier;
97+ return;
98+ }
99+
100+ if(m_keysState[keyCode])
101+ return;
102+
103+ m_keysState[keyCode] = true;
104+ m_lastKeysPress[keyCode] = -1;
105+
106+ m_inputEvent.reset(Fw::KeyDownInputEvent);
107+ m_inputEvent.type = Fw::KeyDownInputEvent;
108+ m_inputEvent.keyCode = keyCode;
109+
110+ if(m_onInputEvent) {
111+ m_onInputEvent(m_inputEvent);
112+
113+ m_inputEvent.reset(Fw::KeyPressInputEvent);
114+ m_inputEvent.keyCode = keyCode;
115+ m_lastKeysPress[keyCode] = g_clock.millis();
116+ m_firstKeysPress[keyCode] = g_clock.millis();
117+ m_onInputEvent(m_inputEvent);
118+ }
119+}
120+
121+void PlatformWindow::processKeyUp(Fw::Key keyCode)
122+{
123+ if (std::this_thread::get_id() != g_dispatcherThreadId) {
124+ g_dispatcher.addEvent(std::bind(&PlatformWindow::processKeyUp, this, keyCode));
125+ return;
126+ }
127+
128+ if(keyCode == Fw::KeyUnknown)
129+ return;
130+
131+ if(keyCode == Fw::KeyCtrl) {
132+ m_inputEvent.keyboardModifiers &= ~Fw::KeyboardCtrlModifier;
133+ return;
134+ } else if(keyCode == Fw::KeyAlt) {
135+ m_inputEvent.keyboardModifiers &= ~Fw::KeyboardAltModifier;
136+ return;
137+ } else if(keyCode == Fw::KeyShift) {
138+ m_inputEvent.keyboardModifiers &= ~Fw::KeyboardShiftModifier;
139+ return;
140+ } else if(keyCode == Fw::KeyNumLock) {
141+ for(uchar k = Fw::KeyNumpad0; k <= Fw::KeyNumpad9; ++k) {
142+ if(m_keysState[(Fw::Key)k])
143+ processKeyUp((Fw::Key)k);
144+ }
145+ }
146+
147+ if(!m_keysState[keyCode])
148+ return;
149+
150+ m_keysState[keyCode] = false;
151+
152+ if(m_onInputEvent) {
153+ m_inputEvent.reset(Fw::KeyUpInputEvent);
154+ m_inputEvent.keyCode = keyCode;
155+ m_onInputEvent(m_inputEvent);
156+ }
157+}
158+
159+void PlatformWindow::releaseAllKeys()
160+{
161+ if (std::this_thread::get_id() != g_dispatcherThreadId) {
162+ g_dispatcher.addEvent(std::bind(&PlatformWindow::releaseAllKeys, this));
163+ return;
164+ }
165+
166+ for(auto it : m_keysState) {
167+ Fw::Key keyCode = it.first;
168+ bool pressed = it.second;
169+
170+ if(!pressed)
171+ continue;
172+
173+ processKeyUp(keyCode);
174+ }
175+
176+ m_inputEvent.keyboardModifiers = 0;
177+
178+ for(int i=0;i<Fw::MouseButtonLast + 1;++i)
179+ m_mouseButtonStates[i] = false;
180+}
181+
182+void PlatformWindow::fireKeysPress()
183+{
184+ if (std::this_thread::get_id() != g_dispatcherThreadId) {
185+ g_dispatcher.addEvent(std::bind(&PlatformWindow::fireKeysPress, this));
186+ return;
187+ }
188+
189+ // avoid massive checks
190+ if(m_keyPressTimer.ticksElapsed() < 10)
191+ return;
192+ m_keyPressTimer.restart();
193+
194+ for(auto it : m_keysState) {
195+ Fw::Key keyCode = it.first;
196+ bool pressed = it.second;
197+
198+ if(!pressed)
199+ continue;
200+
201+ ticks_t lastPressTicks = m_lastKeysPress[keyCode];
202+ ticks_t firstKeyPress = m_firstKeysPress[keyCode];
203+ if(g_clock.millis() - lastPressTicks >= KEY_PRESS_REPEAT_INTERVAL) {
204+ if(m_onInputEvent) {
205+ m_inputEvent.reset(Fw::KeyPressInputEvent);
206+ m_inputEvent.keyCode = keyCode;
207+ m_inputEvent.autoRepeatTicks = g_clock.millis() - firstKeyPress;
208+ m_onInputEvent(m_inputEvent);
209+ }
210+ m_lastKeysPress[keyCode] = g_clock.millis();
211+ }
212+ }
213+}
214+
215+void PlatformWindow::flash() { }
216+
Top