Rigs of Rods 2023.09
Soft-body Physics Simulation
All Data Structures Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Modules Pages
Loading...
Searching...
No Matches
Network.cpp
Go to the documentation of this file.
1/*
2 This source file is part of Rigs of Rods
3 Copyright 2005-2012 Pierre-Michel Ricordel
4 Copyright 2007-2012 Thomas Fischer
5 Copyright 2013-2016 Petr Ohlidal
6
7 For more information, see http://www.rigsofrods.org/
8
9 Rigs of Rods is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License version 3, as
11 published by the Free Software Foundation.
12
13 Rigs of Rods is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU General Public License for more details.
17
18 You should have received a copy of the GNU General Public License
19 along with Rigs of Rods. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#ifdef USE_SOCKETW
23
24#include "Network.h"
25
26#include "Application.h"
27#include "ChatSystem.h"
28#include "Console.h"
29#include "ErrorUtils.h"
30#include "GameContext.h"
31#include "GUIManager.h"
32#include "GUI_TopMenubar.h"
33#include "Language.h"
34#include "RoRVersion.h"
35#include "ScriptEngine.h"
36#include "Utils.h"
37
38#include <Ogre.h>
39#include <SocketW.h>
40
41#include <algorithm>
42#include <chrono>
43#include <cstring>
44
45using namespace RoR;
46
47static Ogre::ColourValue MP_COLORS[] = // Classic RoR multiplayer colors
48{
49 Ogre::ColourValue(0.0, 0.8, 0.0),
50 Ogre::ColourValue(0.0, 0.4, 0.701960784314),
51 Ogre::ColourValue(1.0, 0.501960784314, 0.0),
52 Ogre::ColourValue(1.0, 0.8, 0.0),
53 //Ogre::ColourValue(0.2, 0.0, 0.6),
54 //Ogre::ColourValue(0.6, 0.0, 0.6),
55 Ogre::ColourValue(0.8, 1.0, 0.0),
56 Ogre::ColourValue(1.0, 0.0, 0.0),
57 Ogre::ColourValue(0.501960784314, 0.501960784314, 0.501960784314),
58 Ogre::ColourValue(0.0, 0.560784313725, 0.0),
59 //Ogre::ColourValue(0.0, 0.282352941176, 0.490196078431),
60 Ogre::ColourValue(0.701960784314, 0.352941176471, 0.0),
61 Ogre::ColourValue(0.701960784314, 0.560784313725, 0.0),
62 //Ogre::ColourValue(0.419607843137, 0.0, 0.419607843137),
63 Ogre::ColourValue(0.560784313725, 0.701960784314, 0.0),
64 Ogre::ColourValue(0.701960784314, 0.0, 0.0),
65 Ogre::ColourValue(0.745098039216, 0.745098039216, 0.745098039216),
66 Ogre::ColourValue(0.501960784314, 1.0, 0.501960784314),
67 Ogre::ColourValue(0.501960784314, 0.788235294118, 1.0),
68 Ogre::ColourValue(1.0, 0.752941176471, 0.501960784314),
69 Ogre::ColourValue(1.0, 0.901960784314, 0.501960784314),
70 Ogre::ColourValue(0.666666666667, 0.501960784314, 1.0),
71 Ogre::ColourValue(0.933333333333, 0.0, 0.8),
72 Ogre::ColourValue(1.0, 0.501960784314, 0.501960784314),
73 Ogre::ColourValue(0.4, 0.4, 0.0),
74 Ogre::ColourValue(1.0, 0.749019607843, 1.0),
75 Ogre::ColourValue(0.0, 1.0, 0.8),
76 Ogre::ColourValue(0.8, 0.4, 0.6),
77 Ogre::ColourValue(0.6, 0.6, 0.0),
78};
79
80using namespace RoRnet;
81
82static const unsigned int m_packet_buffer_size = 20;
83
84#define LOG_THREAD(_MSG_) { std::stringstream s; s << _MSG_ << " (Thread ID: " << std::this_thread::get_id() << ")"; LOG(s.str()); }
85#define LOGSTREAM Ogre::LogManager().getSingleton().stream()
86
87void Network::PushNetMessage(MsgType type, std::string const & message)
88{
89 Message m(type);
90 m.description = message;
92}
93
94Ogre::ColourValue Network::GetPlayerColor(int color_num)
95{
96 int numColours = sizeof(MP_COLORS) / sizeof(Ogre::ColourValue);
97 if (color_num < 0 || color_num >= numColours)
98 return Ogre::ColourValue::White;
99
100 return MP_COLORS[color_num];
101}
102
103// Internal helper
104void DebugPacket(const char *name, RoRnet::Header *header, char *buffer)
105{
106 std::stringstream msg;
107 msg << "++ " << name << ": " << header->source << ", " << header->streamid
108 << ", "<< header->command << ", " << header->size << ", hash: " << HashData(buffer, header->size);
109 LOG(msg.str());
110}
111
112void Network::SetNetQuality(int quality)
113{
114 m_net_quality = quality;
115}
116
118{
119 return m_net_quality;
120}
121
123{
124 return m_uid;
125}
126
127bool Network::SendMessageRaw(char *buffer, int msgsize)
128{
129 SWBaseSocket::SWBaseError error;
130
131 if (m_socket.fsend(buffer, msgsize, &error) < msgsize)
132 {
133 LOG("NET send error: " + error.get_error());
134 return false;
135 }
136
137 return true;
138}
139
140bool Network::SendNetMessage(int type, unsigned int streamid, int len, char* content)
141{
142 RoRnet::Header head;
143 memset(&head, 0, sizeof(RoRnet::Header));
144 head.command = type;
145 head.source = m_uid;
146 head.size = len;
147 head.streamid = streamid;
148
149 const int msgsize = sizeof(RoRnet::Header) + len;
150
151 if (msgsize >= RORNET_MAX_MESSAGE_LENGTH)
152 {
153 return false;
154 }
155
156 char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
157 memcpy(buffer, (char *)&head, sizeof(RoRnet::Header));
158 memcpy(buffer + sizeof(RoRnet::Header), content, len);
159
160 return SendMessageRaw(buffer, msgsize);
161}
162
163void Network::QueueStreamData(RoRnet::Header &header, char *buffer, size_t buffer_len)
164{
165 NetRecvPacket packet;
166 packet.header = header;
167 memcpy(packet.buffer, buffer, std::min(buffer_len, size_t(RORNET_MAX_MESSAGE_LENGTH)));
168
169 std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
170 m_recv_packet_buffer.push_back(packet);
171}
172
173int Network::ReceiveMessage(RoRnet::Header *head, char* content, int bufferlen)
174{
175 SWBaseSocket::SWBaseError error;
176
177#ifdef DEBUG
178 LOG_THREAD("[RoR|Networking] ReceiveMessage() waiting...");
179#endif //DEBUG
180
181 if (m_socket.frecv((char*)head, sizeof(RoRnet::Header), &error) < sizeof(RoRnet::Header))
182 {
183 LOG("NET receive error 1: " + error.get_error());
184 return -1;
185 }
186
187#ifdef DEBUG
188 LOG_THREAD("[RoR|Networking] ReceiveMessage() header received");
189#endif //DEBUG
190
191 if (head->size > uint32_t(bufferlen))
192 {
193 return -3;
194 }
195
196 if (head->size > 0)
197 {
198 // Read the packet content
199 std::memset(content, 0, bufferlen);
200 if (m_socket.frecv(content, head->size, &error) < static_cast<int>(head->size))
201 {
202 LOG_THREAD("NET receive error 2: "+ error.get_error());
203 return -1;
204 }
205 }
206
207#ifdef DEBUG
208 LOG_THREAD("[RoR|Networking] ReceiveMessage() body received");
209#endif //DEBUG
210
211 return 0;
212}
213
215{
216 LOG("[RoR|Networking] SendThread started");
217 while (!m_shutdown)
218 {
219 NetSendPacket packet;
220 {
221 std::unique_lock<std::mutex> queue_lock(m_send_packetqueue_mutex);
222 while (m_send_packet_buffer.empty() && !m_shutdown)
223 {
224 m_send_packet_available_cv.wait(queue_lock);
225 }
226 if (m_shutdown)
227 {
228 break;
229 }
230 packet = m_send_packet_buffer.front();
231 m_send_packet_buffer.pop_front();
232 }
233 SendMessageRaw(packet.buffer, packet.size);
234 }
235 LOG("[RoR|Networking] SendThread stopped");
236}
237
239{
240 LOG_THREAD("[RoR|Networking] RecvThread starting...");
241
242 RoRnet::Header header;
243
244 char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
245
246 while (!m_shutdown)
247 {
248 int err = ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH);
249 //LOG("Received data: " + TOSTRING(header.command) + ", source: " + TOSTRING(header.source) + ":" + TOSTRING(header.streamid) + ", size: " + TOSTRING(header.size));
250 if (err != 0)
251 {
252 LOG_THREAD("[RoR|Networking] RecvThread: Error while receiving data: " + TOSTRING(err));
253 m_shutdown = true; // Atomic; instruct sender thread to stop
254 PushNetMessage(MSG_NET_RECV_ERROR, _LC("Network", "Error receiving data from network"));
255 continue; // Stop receiving data
256 }
257
258 if (header.command == MSG2_STREAM_REGISTER)
259 {
260 if (header.source == m_uid)
261 continue;
262
264
265 LOG(" * received stream registration: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid) + ", type: " + TOSTRING(reg->type));
266 }
267 else if (header.command == MSG2_STREAM_REGISTER_RESULT)
268 {
270 LOG(" * received stream registration result: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid) + ", status: " + TOSTRING(reg->status));
271 }
272 else if (header.command == MSG2_STREAM_UNREGISTER)
273 {
274 LOG(" * received stream deregistration: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid));
275 }
276 else if (header.command == MSG2_UTF8_CHAT || header.command == MSG2_UTF8_PRIVCHAT)
277 {
278 // Chat message
279 }
280 else if (header.command == MSG2_NETQUALITY && header.source == -1)
281 {
282 if (header.size != sizeof(int))
283 {
284 continue;
285 }
286 int quality = *(int *)buffer;
287 SetNetQuality(quality);
288 continue;
289 }
290 else if (header.command == MSG2_USER_LEAVE)
291 {
292 if (header.source == m_uid)
293 {
294 m_shutdown = true; // Atomic; stop sending/receiving data - server closes the connection quickly after kick.
295
296 std::stringstream msg;
297 msg << _L("disconnected: remote side closed the connection");
298 msg << " ** ";
299 msg << buffer;
300
301 bool was_kick = (std::strstr(buffer, "disconnected on request") == nullptr); // FIXME: Add a reason code to MSG2_USER_LEAVE, this is ugly!
304
306 }
307 else
308 {
309 std::lock_guard<std::mutex> lock(m_users_mutex);
310 auto user = std::find_if(m_users.begin(), m_users.end(), [header](const RoRnet::UserInfo& u) { return static_cast<int>(u.uniqueid) == header.source; });
311 if (user != m_users.end())
312 {
313 // Console is now threadsafe, no need to send fake chatmessages to ourselves
314 Str<300> text;
315 text << _L("left the game");
318 LOG_THREAD(text);
319
320 // Erase matching peer options
321 int peeropt_offset = (int)std::distance(m_users.begin(), user);
322 auto peeropt_itor = m_users_peeropts.begin() + peeropt_offset;
323 m_users_peeropts.erase(peeropt_itor);
324
325 m_disconnected_users.push_back(*user); // Copy
326 m_users.erase(user);
327 }
328 }
329 }
330 else if (header.command == MSG2_USER_INFO || header.command == MSG2_USER_JOIN)
331 {
332 if (header.source == m_uid)
333 {
334 std::lock_guard<std::mutex> lock(m_userdata_mutex);
335 memcpy(&m_userdata, buffer, sizeof(RoRnet::UserInfo));
337 m_username = std::string(m_userdata.username);
339 // TODO: Update the global variable 'mp_player_name' in a threadsafe way.
340 }
341 else
342 {
343 RoRnet::UserInfo user_info;
344 if (!GetUserInfo(header.source, user_info)) // Check that user doesn't exist yet.
345 {
346 memcpy(&user_info, buffer, sizeof(RoRnet::UserInfo));
347 Str<300> text;
348 if (user_info.authstatus != 0) // Show nothing for guests (no special authorization)
349 {
350 text << "(" << UserAuthToStringShort(user_info) << ") ";
351 }
352 text << _L("joined the game");
353
354 // NB: Console is threadsafe
358 // Lock and update userlist
359 std::lock_guard<std::mutex> lock(m_users_mutex);
360 m_users.push_back(user_info);
361 m_users_peeropts.push_back(BitMask_t(0));
362 } // End of lock scope
363 }
364 continue;
365 }
366 else if (header.command == MSG2_GAME_CMD)
367 {
368#ifdef USE_ANGELSCRIPT
369 App::GetScriptEngine()->queueStringForExecution(Ogre::String(buffer));
370#endif // USE_ANGELSCRIPT
371 continue;
372 }
373 //DebugPacket("recv", &header, buffer);
374
376 }
377
378 LOG_THREAD("[RoR|Networking] RecvThread stopped");
379}
380
381
382void Network::CouldNotConnect(std::string const & msg, bool close_socket /*= true*/)
383{
384 RoR::LogFormat("[RoR|Networking] Failed to connect to server [%s:%d], message: %s", m_net_host.c_str(), m_net_port, msg.c_str());
386
387 if (close_socket)
388 {
389 m_socket.set_timeout(1, 0);
390 m_socket.disconnect();
391 }
392}
393
395{
396 // Shadow vars for threaded access
402
403 try
404 {
405 m_connect_thread = std::thread(&Network::ConnectThread, this);
406 App::mp_state->setVal((int)MpState::CONNECTING); // Mark connect thread as started
407 PushNetMessage(MSG_NET_CONNECT_STARTED, _LC("Network", "Starting..."));
408 return true;
409 }
410 catch (std::exception& e)
411 {
413 PushNetMessage(MSG_NET_CONNECT_FAILURE, _L("Failed to launch connection thread"));
414 RoR::LogFormat("[RoR|Networking] Failed to launch connection thread, message: %s", e.what());
415 return false;
416 }
417}
418
420{
422
423 if (m_connect_thread.joinable())
424 m_connect_thread.join(); // Clean up
425}
426
428{
429 RoR::LogFormat("[RoR|Networking] Trying to join server '%s' on port '%d' ...", m_net_host.c_str(), m_net_port);
430
431 SWBaseSocket::SWBaseError error;
432
433 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Estabilishing connection..."));
434 m_socket = SWInetSocket();
435 m_socket.set_timeout(10, 0);
436 m_socket.connect(m_net_port, m_net_host, &error);
437 if (error != SWBaseSocket::ok)
438 {
439 CouldNotConnect(_L("Could not create connection"), false);
440 return false;
441 }
442
443 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Getting server info..."));
444 if (!SendNetMessage(MSG2_HELLO, 0, (int)strlen(RORNET_VERSION), (char *)RORNET_VERSION))
445 {
446 CouldNotConnect(_L("Establishing network session: error sending hello"));
447 return false;
448 }
449
450 RoRnet::Header header;
451 char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
452
453 // Receive server (rornet protocol) version
454 if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
455 {
456 CouldNotConnect(_L("Establishing network session: error getting server version"));
457 return false;
458 }
459 if (header.command == MSG2_WRONG_VER_LEGACY) // Pre-RoRnet_2.40 server
460 {
462 memcpy(&info, buffer, sizeof(RoRnet::LegacyServerInfo));
463 std::string format_str = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
464 const char* server_ver = (info.protocolversion[0] != 0) ? info.protocolversion : "~ RoRnet_2.38 or earlier (not detected) ~";
465 CouldNotConnect(fmt::format(format_str.c_str(), RORNET_VERSION, server_ver));
466 return false;
467 }
468 if (header.command == MSG2_WRONG_VER)
469 {
470 CouldNotConnect(_L("server uses a different protocol version"));
471 return false;
472 }
473 if (header.command != MSG2_HELLO)
474 {
475 CouldNotConnect(_L("Establishing network session: error getting server hello"));
476 return false;
477 }
478
479 // Save server settings
480 memcpy(&m_server_settings, buffer, sizeof(RoRnet::ServerInfo));
481
483 {
484 std::string formatstr = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
486 return false;
487 }
488
489 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Authorizing..."));
490
491 // First handshake done, increase the timeout, important!
492 m_socket.set_timeout(0, 0);
493
494 // Construct user credentials
496 memset(&c, 0, sizeof(RoRnet::UserInfo));
497 // Cut off the UTF string on the highest level, otherwise you will break UTF info
499 strncpy(c.serverpassword, Sha1Hash(m_password).c_str(), size_t(40));
500 strncpy(c.usertoken, Sha1Hash(m_token).c_str(), size_t(40));
502 strncpy(c.clientname, "RoR", 10);
503 std::string language = App::app_language->getStr().substr(0, 2);
504 std::string country = App::app_country->getStr().substr(0, 2);
505 strncpy(c.language, (language + std::string("_") + country).c_str(), 5);
506 strcpy(c.sessiontype, "normal");
507 if (!SendNetMessage(MSG2_USER_INFO, 0, sizeof(RoRnet::UserInfo), (char*)&c))
508 {
509 CouldNotConnect(_L("Establishing network session: error sending user info"));
510 return false;
511 }
512
513 // Getting authorization
514 if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
515 {
516 CouldNotConnect(_L("Establishing network session: error getting server authorization"));
517 return false;
518 }
519
520 if (header.command==MSG2_FULL)
521 {
522 CouldNotConnect(_L("Establishing network session: sorry, server has too many players"));
523 return false;
524 }
525 else if (header.command==MSG2_BANNED)
526 {
527 // Do NOT `disconnect()` the m_socket in this case - causes SocketW to terminate RoR.
528 CouldNotConnect(_L("Establishing network session: sorry, you are banned!"), /*close_socket=*/false);
529 return false;
530 }
531 else if (header.command==MSG2_WRONG_PW)
532 {
533 CouldNotConnect(_L("Establishing network session: sorry, wrong password!"));
534 return false;
535 }
536 else if (header.command==MSG2_WRONG_VER)
537 {
538 CouldNotConnect(_L("Establishing network session: sorry, wrong protocol version!"));
539 return false;
540 }
541 else if (header.command==MSG2_NO_RANK)
542 {
543 CouldNotConnect(_L("Establishing network session: sorry, this server requires a user token!"));
544 // ChainMessage() ensures the MP settings request is handled _after_ the MSG_NET_CONNECT_FAILURE with the text above.
546 return false;
547 }
548
549 if (header.command!=MSG2_WELCOME)
550 {
551 CouldNotConnect(_L("Establishing network session: sorry, unknown server response"));
552 return false;
553 }
554
555 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Finishing..."));
556
557 m_uid = header.source;
558
559 // we get our userdata back
560 memcpy(&m_userdata, buffer, std::min<int>(sizeof(RoRnet::UserInfo), header.size));
561
562 m_shutdown = false;
563
564 LOG("[RoR|Networking] Connect(): Creating Send/Recv threads");
565 m_send_thread = std::thread(&Network::SendThread, this);
566 m_recv_thread = std::thread(&Network::RecvThread, this);
568
569 return true;
570}
571
573{
574 LOG("[RoR|Networking] Disconnect() disconnecting...");
575 bool is_clean_disconnect = !m_shutdown; // Hacky detection of invalid network state
576
577 m_shutdown = true; // Instruct Send/Recv threads to shut down.
578
579 m_send_packet_available_cv.notify_one();
580
581 m_send_thread.join();
582 LOG("[RoR|Networking] Disconnect() sender thread cleaned up");
583
584 m_socket.set_timeout(1, 0);
585
586 if (is_clean_disconnect)
587 {
589 }
590
591 m_recv_thread.join();
592 LOG("[RoR|Networking] Disconnect() receiver thread cleaned up");
593
594 if (is_clean_disconnect)
595 {
596 m_socket.disconnect();
597 }
598 else
599 {
600 m_socket.close_fd();
601 }
602
603 SetNetQuality(0);
604 m_users.clear();
605 m_disconnected_users.clear();
606 m_recv_packet_buffer.clear();
607 m_send_packet_buffer.clear();
608 App::GetConsole()->doCommand("clear net");
609
610 m_shutdown = false;
612
613 LOG("[RoR|Networking] Disconnect() done");
614}
615
616void Network::AddPacket(int streamid, int type, int len, const char *content)
617{
618 const auto max_len = RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header);
619 if (len > max_len)
620 {
621 LOGSTREAM << "[RoR|Networking] Discarding network packet (StreamID: "
622 <<streamid<<", Type: "<<type<<"), length is " << len << ", max is " << max_len;
623 return;
624 }
625
626 NetSendPacket packet;
627 memset(&packet, 0, sizeof(NetSendPacket));
628
629 char *buffer = (char*)(packet.buffer);
630
631 RoRnet::Header *head = (RoRnet::Header *)buffer;
632 head->command = type;
633 head->source = m_uid;
634 head->size = len;
635 head->streamid = streamid;
636
637 // then copy the contents
638 char *bufferContent = (char *)(buffer + sizeof(RoRnet::Header));
639 memcpy(bufferContent, content, len);
640
641 // record the packet size
642 packet.size = len + sizeof(RoRnet::Header);
643
644 { // Lock scope
645 std::lock_guard<std::mutex> lock(m_send_packetqueue_mutex);
647 {
649 {
650 // buffer full, discard unimportant data packets
651 return;
652 }
653 auto search = std::find_if(m_send_packet_buffer.begin(), m_send_packet_buffer.end(),
654 [&](const NetSendPacket& p) { return !memcmp(packet.buffer, p.buffer, sizeof(RoRnet::Header)); });
655 if (search != m_send_packet_buffer.end())
656 {
657 // Found outdated discardable streamdata -> replace it
658 (*search) = packet;
659 m_send_packet_available_cv.notify_one();
660 return;
661 }
662 }
663 //DebugPacket("send", head, buffer);
664 m_send_packet_buffer.push_back(packet);
665 }
666
667 m_send_packet_available_cv.notify_one();
668}
669
671{
672 reg->origin_sourceid = m_uid;
674 reg->status = 0;
675
676 AddPacket(m_stream_id, MSG2_STREAM_REGISTER, size, (char*)reg);
677 LOG("adding local stream: " + TOSTRING(m_uid) + ":"+ TOSTRING(m_stream_id) + ", type: " + TOSTRING(reg->type));
678
679 m_stream_id++;
680}
681
682std::vector<NetRecvPacket> Network::GetIncomingStreamData()
683{
684 std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
685 std::vector<NetRecvPacket> buf_copy = m_recv_packet_buffer;
686 m_recv_packet_buffer.clear();
687 return buf_copy;
688}
689
691{
693}
694
696{
697 std::lock_guard<std::mutex> lock(m_userdata_mutex);
698 return m_userdata.colournum;
699}
700
702{
703 std::lock_guard<std::mutex> lock(m_userdata_mutex);
704 return m_username;
705}
706
708{
709 std::lock_guard<std::mutex> lock(m_userdata_mutex);
710 return m_userdata;
711}
712
713std::vector<RoRnet::UserInfo> Network::GetUserInfos()
714{
715 std::lock_guard<std::mutex> lock(m_users_mutex);
716 return m_users;
717}
718
719std::vector<BitMask_t> Network::GetAllUsersPeerOpts()
720{
721 std::lock_guard<std::mutex> lock(m_users_mutex);
722 return m_users_peeropts;
723}
724
726{
727 std::lock_guard<std::mutex> lock(m_users_mutex);
728 for (RoRnet::UserInfo user : m_users)
729 {
730 if ((int)user.uniqueid == uid)
731 {
732 result = user;
733 return true;
734 }
735 }
736 return false;
737}
738
740{
741 std::lock_guard<std::mutex> lock(m_users_mutex);
742 for (size_t i = 0; i < m_users.size(); i++)
743 {
744 if (static_cast<int>(m_users[i].uniqueid) == uid)
745 {
746 result = m_users_peeropts[i];
747 return true;
748 }
749 }
750 return false;
751}
752
754{
755 std::lock_guard<std::mutex> lock(m_users_mutex);
757 {
758 if ((int)user.uniqueid == uid)
759 {
760 result = user;
761 return true;
762 }
763 }
764 return false;
765}
766
768{
770
771 // Try remote users
772 if (GetUserInfo(uid, tmp))
773 {
774 result = tmp;
775 return true;
776 }
777
778 // Try local user
779 tmp = GetLocalUserData();
780 if (tmp.uniqueid == uid)
781 {
782 result = tmp;
783 return true;
784 }
785
786 return false;
787}
788
789bool Network::FindUserInfo(std::string const& username, RoRnet::UserInfo &result)
790{
791 std::lock_guard<std::mutex> lock(m_users_mutex);
792 for (RoRnet::UserInfo user : m_users)
793 {
794 if (user.username == username)
795 {
796 result = user;
797 return true;
798 }
799 }
800 return false;
801}
802
803
805{
806 std::lock_guard<std::mutex> lock(m_users_mutex);
807
808 const bool peeropts_sane = m_users.size() == m_users_peeropts.size();
809 ROR_ASSERT(peeropts_sane);
810 if (!peeropts_sane) return;
811
812 for (size_t i = 0; i < m_users.size(); i++)
813 {
814 if (static_cast<int>(m_users[i].uniqueid) == rq->por_uid)
815 {
817 }
818 }
819}
820
822{
823 std::lock_guard<std::mutex> lock(m_users_mutex);
824
825 const bool peeropts_sane = m_users.size() == m_users_peeropts.size();
826 ROR_ASSERT(peeropts_sane);
827 if (!peeropts_sane) return;
828
829 for (size_t i = 0; i < m_users.size(); i++)
830 {
831 if (static_cast<int>(m_users[i].uniqueid) == rq->por_uid)
832 {
834 }
835 }
836}
837
838void Network::BroadcastChatMsg(const char* msg)
839{
840 AddPacket(m_stream_id, RoRnet::MSG2_UTF8_CHAT, (int)std::strlen(msg), msg);
841}
842
843void Network::WhisperChatMsg(RoRnet::UserInfo const& user, const char* msg)
844{
845 // Prepare buffer
846 char payload[RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header)];
847 size_t payload_len = 0;
848
849 // Write client ID
850 std::memcpy(payload, &user.uniqueid, sizeof(user.uniqueid));
851 payload_len += sizeof(user.uniqueid);
852
853 // Write text
854 std::strncpy(payload + payload_len, msg, sizeof(payload) - payload_len);
855 payload_len += std::strlen(msg);
856
857 // Queue packet
858 AddPacket(m_stream_id, RoRnet::MSG2_UTF8_PRIVCHAT, (int)payload_len, msg);
859}
860
862{
863 if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth", "Admin"); }
864 else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth", "Mod"); }
865 else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth", "Bot"); }
866 else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth", "Ranked"); }
867 else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth", "Banned"); }
868 else { return _LC("NetUserAuth", "Guest"); }
869}
870
872{
873 if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth","Server Administrator"); }
874 else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth","Server Moderator"); }
875 else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth","Bot"); }
876 else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth","Ranked user"); }
877 else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth","Banned user"); }
878 else { return _LC("NetUserAuth","Guest"); }
879}
880
881#endif // USE_SOCKETW
Central state/object manager and communications hub.
#define ROR_ASSERT(_EXPR)
Definition Application.h:40
#define TOSTRING(x)
Definition Application.h:57
void LOG(const char *msg)
Legacy alias - formerly a macro.
#define BITMASK_SET_0(VAR, FLAGS)
Definition BitFlags.h:16
#define BITMASK_SET_1(VAR, FLAGS)
Definition BitFlags.h:17
uint32_t BitMask_t
Definition BitFlags.h:7
#define _L
Game state manager and message-queue provider.
#define strnlen(str, len)
#define _LC(ctx, str)
Definition Language.h:38
void DebugPacket(const char *name, RoRnet::Header *header, char *buffer)
Definition Network.cpp:104
static Ogre::ColourValue MP_COLORS[]
Definition Network.cpp:47
#define LOG_THREAD(_MSG_)
Definition Network.cpp:84
static const unsigned int m_packet_buffer_size
Definition Network.cpp:82
const char *const ROR_VERSION_STRING
#define LOGSTREAM
std::string const & getStr() const
Definition CVar.h:95
void setVal(T val)
Definition CVar.h:72
int getInt() const
Definition CVar.h:97
void putNetMessage(int user_id, MessageType type, const char *text)
Definition Console.cpp:108
@ CONSOLE_SYSTEM_NOTICE
Definition Console.h:51
void PushMessage(Message m)
Doesn't guarantee order! Use ChainMessage() if order matters.
void ChainMessage(Message m)
Add to last pushed message's chain.
bool GetUserPeerOpts(int uid, BitMask_t &result)
Definition Network.cpp:739
std::deque< NetSendPacket > m_send_packet_buffer
Definition Network.h:195
Ogre::ColourValue GetPlayerColor(int color_num)
Definition Network.cpp:94
std::mutex m_users_mutex
Definition Network.h:187
int GetUserColor()
Definition Network.cpp:695
bool FindUserInfo(std::string const &username, RoRnet::UserInfo &result)
Definition Network.cpp:789
void AddLocalStream(RoRnet::StreamRegister *reg, int size)
Definition Network.cpp:670
void SendThread()
Definition Network.cpp:214
int ReceiveMessage(RoRnet::Header *head, char *content, int bufferlen)
Definition Network.cpp:173
std::string UserAuthToStringLong(RoRnet::UserInfo const &user)
Definition Network.cpp:871
std::string m_username
Definition Network.h:170
int m_authlevel
Definition Network.h:176
std::string GetUsername()
Definition Network.cpp:701
std::thread m_connect_thread
Definition Network.h:180
std::string m_password
Definition Network.h:172
int GetNetQuality()
Definition Network.cpp:117
void RemovePeerOptions(PeerOptionsRequest *rq)
Definition Network.cpp:821
SWInetSocket m_socket
Definition Network.h:162
void CouldNotConnect(std::string const &msg, bool close_socket=true)
Definition Network.cpp:382
bool GetAnyUserInfo(int uid, RoRnet::UserInfo &result)
Also considers local client.
Definition Network.cpp:767
bool SendMessageRaw(char *buffer, int msgsize)
Definition Network.cpp:127
std::vector< BitMask_t > GetAllUsersPeerOpts()
Definition Network.cpp:719
std::vector< RoRnet::UserInfo > m_disconnected_users
Definition Network.h:168
int m_net_port
Definition Network.h:174
std::atomic< int > m_net_quality
Definition Network.h:184
void BroadcastChatMsg(const char *msg)
Definition Network.cpp:838
std::vector< NetRecvPacket > GetIncomingStreamData()
Definition Network.cpp:682
std::mutex m_send_packetqueue_mutex
Definition Network.h:190
std::string m_net_host
Definition Network.h:171
bool GetDisconnectedUserInfo(int uid, RoRnet::UserInfo &result)
Definition Network.cpp:753
std::string UserAuthToStringShort(RoRnet::UserInfo const &user)
Definition Network.cpp:861
std::atomic< bool > m_shutdown
Definition Network.h:183
std::vector< NetRecvPacket > m_recv_packet_buffer
Definition Network.h:194
bool StartConnecting()
Launches connecting on background.
Definition Network.cpp:394
void SetNetQuality(int quality)
Definition Network.cpp:112
bool SendNetMessage(int type, unsigned int streamid, int len, char *content)
Definition Network.cpp:140
void RecvThread()
Definition Network.cpp:238
int m_stream_id
Counter.
Definition Network.h:185
std::thread m_send_thread
Definition Network.h:178
void AddPacket(int streamid, int type, int len, const char *content)
Definition Network.cpp:616
RoRnet::ServerInfo m_server_settings
Definition Network.h:164
void Disconnect()
Definition Network.cpp:572
std::thread m_recv_thread
Definition Network.h:179
void StopConnecting()
Definition Network.cpp:419
RoRnet::UserInfo GetLocalUserData()
Definition Network.cpp:707
std::mutex m_recv_packetqueue_mutex
Definition Network.h:189
void PushNetMessage(MsgType type, std::string const &message)
Definition Network.cpp:87
std::vector< BitMask_t > m_users_peeropts
See RoRnet::PeerOptions.
Definition Network.h:167
RoRnet::UserInfo m_userdata
Definition Network.h:165
std::mutex m_userdata_mutex
Definition Network.h:188
Ogre::String GetTerrainName()
Definition Network.cpp:690
bool ConnectThread()
Definition Network.cpp:427
void QueueStreamData(RoRnet::Header &header, char *buffer, size_t buffer_len)
Definition Network.cpp:163
void WhisperChatMsg(RoRnet::UserInfo const &user, const char *msg)
Definition Network.cpp:843
bool GetUserInfo(int uid, RoRnet::UserInfo &result)
Definition Network.cpp:725
std::vector< RoRnet::UserInfo > GetUserInfos()
Definition Network.cpp:713
std::vector< RoRnet::UserInfo > m_users
Definition Network.h:166
void AddPeerOptions(PeerOptionsRequest *rq)
Definition Network.cpp:804
std::condition_variable m_send_packet_available_cv
Definition Network.h:192
std::string m_token
Definition Network.h:173
void queueStringForExecution(const Ogre::String command)
Queues a string for execution.
Wrapper for classic c-string (local buffer) Refresher: strlen() excludes '\0' terminator; strncat() A...
Definition Str.h:36
const char * ToCStr() const
Definition Str.h:46
void doCommand(std::string msg)
Identify and execute any console line.
@ DISABLED
Not connected for whatever reason.
MsgType
Global gameplay message loop, see struct Message in GameContext.h.
Definition Application.h:76
@ MSG_NET_CONNECT_STARTED
Definition Application.h:99
@ MSG_NET_RECV_ERROR
@ MSG_NET_CONNECT_FAILURE
@ MSG_GUI_MP_CLIENTS_REFRESH
@ MSG_NET_CONNECT_PROGRESS
@ MSG_NET_CONNECT_SUCCESS
@ MSG_NET_USER_DISCONNECT
@ MSG_GUI_OPEN_MP_SETTINGS_REQUESTED
@ MSG_NET_SERVER_KICK
CVar * mp_player_name
CVar * mp_server_password
CVar * app_language
CVar * app_country
CVar * mp_server_port
GameContext * GetGameContext()
CVar * mp_state
Console * GetConsole()
CVar * mp_player_token
ScriptEngine * GetScriptEngine()
CVar * mp_server_host
Ogre::String HashData(const char *key, int len)
Definition Utils.cpp:54
void LogFormat(const char *format,...)
Improved logging utility. Uses fixed 2Kb buffer.
std::string Sha1Hash(std::string const &data)
Definition Utils.cpp:141
@ AUTH_MOD
moderator status
Definition RoRnet.h:80
@ AUTH_BANNED
banned
Definition RoRnet.h:82
@ AUTH_BOT
bot status
Definition RoRnet.h:81
@ AUTH_RANKED
ranked status
Definition RoRnet.h:79
@ AUTH_ADMIN
admin on the server
Definition RoRnet.h:78
@ MSG2_STREAM_REGISTER_RESULT
result of a stream creation
Definition RoRnet.h:64
@ MSG2_STREAM_DATA_DISCARDABLE
stream data that is allowed to be discarded
Definition RoRnet.h:67
@ MSG2_NO_RANK
client has no ranked status
Definition RoRnet.h:69
@ MSG2_WRONG_VER_LEGACY
Wrong version.
Definition RoRnet.h:72
@ MSG2_WRONG_VER
wrong version
Definition RoRnet.h:44
@ MSG2_USER_LEAVE
user leaves
Definition RoRnet.h:58
@ MSG2_USER_INFO
user data that is sent from the server to the clients
Definition RoRnet.h:51
@ MSG2_WELCOME
we can proceed
Definition RoRnet.h:46
@ MSG2_STREAM_UNREGISTER
remove stream
Definition RoRnet.h:65
@ MSG2_HELLO
client sends its version as first message
Definition RoRnet.h:39
@ MSG2_USER_JOIN
new user joined
Definition RoRnet.h:57
@ MSG2_UTF8_CHAT
broadcast chat line in UTF8 encoding; Payload: const char*(text)
Definition RoRnet.h:59
@ MSG2_FULL
no more slots for us
Definition RoRnet.h:42
@ MSG2_GAME_CMD
Script message. Can be sent in both directions.
Definition RoRnet.h:56
@ MSG2_NETQUALITY
network quality information
Definition RoRnet.h:53
@ MSG2_UTF8_PRIVCHAT
private chat line in UTF8 encoding; Payload: uint32_t(uniqueid), const char*(text)
Definition RoRnet.h:60
@ MSG2_WRONG_PW
server send that on wrong pw
Definition RoRnet.h:43
@ MSG2_STREAM_REGISTER
create new stream
Definition RoRnet.h:63
@ MSG2_BANNED
client not allowed to join
Definition RoRnet.h:45
#define RORNET_MAX_MESSAGE_LENGTH
maximum size of a RoR message. 8192 bytes = 8 kibibytes
Definition RoRnet.h:31
#define RORNET_VERSION
Definition RoRnet.h:35
#define RORNET_MAX_USERNAME_LEN
bytes.
Definition RoRnet.h:33
Unified game event system - all requests and state changes are reported using a message.
Definition GameContext.h:52
std::string description
Definition GameContext.h:58
RoRnet::Header header
Definition Network.h:95
char buffer[RORNET_MAX_MESSAGE_LENGTH]
Definition Network.h:96
char buffer[RORNET_MAX_MESSAGE_LENGTH]
Definition Network.h:89
Payload of MSG_NET_{ADD/REMOVE}_PEEROPTIONS_REQUESTED.
Definition Network.h:105
int por_uid
RoRnet unique user ID.
Definition Network.h:106
BitMask_t por_peeropts
See RoRnet::PeerOptions.
Definition Network.h:107
< Common header for every packet
Definition RoRnet.h:152
uint32_t streamid
streamid for this command
Definition RoRnet.h:155
uint32_t command
the command of this packet: MSG2_*
Definition RoRnet.h:153
uint32_t size
size of the attached data block
Definition RoRnet.h:156
int32_t source
source of this command: 0 = server
Definition RoRnet.h:154
char protocolversion[20]
protocol version being used
Definition RoRnet.h:232
char terrain[128]
terrain name
Definition RoRnet.h:224
char protocolversion[20]
protocol version being used
Definition RoRnet.h:223
< Sent from the client to server and vice versa, to broadcast a new stream
Definition RoRnet.h:160
int32_t type
0 = Actor, 1 = Character, 3 = ChatSystem
Definition RoRnet.h:161
int32_t origin_streamid
origin streamid
Definition RoRnet.h:164
int32_t origin_sourceid
origin sourceid
Definition RoRnet.h:163
int32_t status
initial stream status
Definition RoRnet.h:162
int32_t authstatus
auth status set by server: AUTH_*
Definition RoRnet.h:192
char clientname[10]
the name and version of the client. For exmaple: "ror" or "gamebot"
Definition RoRnet.h:200
char language[10]
user's language. For example "de-DE" or "en-US"
Definition RoRnet.h:199
char username[RORNET_MAX_USERNAME_LEN]
the nickname of the user (UTF-8)
Definition RoRnet.h:196
int32_t colournum
colour set by server
Definition RoRnet.h:194
char usertoken[40]
user token
Definition RoRnet.h:197
char serverpassword[40]
server password
Definition RoRnet.h:198
char sessiontype[10]
the requested session type. For example "normal", "bot", "rcon"
Definition RoRnet.h:203
uint32_t uniqueid
user unique id
Definition RoRnet.h:191
char clientversion[25]
a version number of the client. For example 1 for RoR 0.35
Definition RoRnet.h:201