Rigs of Rods 2026.01
Soft-body Physics Simulation
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 "ServerScriptEngine.h"
37#include "Utils.h"
38
39#include <Ogre.h>
40#include <SocketW.h>
41
42#include <algorithm>
43#include <chrono>
44#include <cstring>
45
46using namespace RoR;
47
48static Ogre::ColourValue MP_COLORS[] = // Classic RoR multiplayer colors
49{
50 Ogre::ColourValue(0.0, 0.8, 0.0),
51 Ogre::ColourValue(0.0, 0.4, 0.701960784314),
52 Ogre::ColourValue(1.0, 0.501960784314, 0.0),
53 Ogre::ColourValue(1.0, 0.8, 0.0),
54 //Ogre::ColourValue(0.2, 0.0, 0.6),
55 //Ogre::ColourValue(0.6, 0.0, 0.6),
56 Ogre::ColourValue(0.8, 1.0, 0.0),
57 Ogre::ColourValue(1.0, 0.0, 0.0),
58 Ogre::ColourValue(0.501960784314, 0.501960784314, 0.501960784314),
59 Ogre::ColourValue(0.0, 0.560784313725, 0.0),
60 //Ogre::ColourValue(0.0, 0.282352941176, 0.490196078431),
61 Ogre::ColourValue(0.701960784314, 0.352941176471, 0.0),
62 Ogre::ColourValue(0.701960784314, 0.560784313725, 0.0),
63 //Ogre::ColourValue(0.419607843137, 0.0, 0.419607843137),
64 Ogre::ColourValue(0.560784313725, 0.701960784314, 0.0),
65 Ogre::ColourValue(0.701960784314, 0.0, 0.0),
66 Ogre::ColourValue(0.745098039216, 0.745098039216, 0.745098039216),
67 Ogre::ColourValue(0.501960784314, 1.0, 0.501960784314),
68 Ogre::ColourValue(0.501960784314, 0.788235294118, 1.0),
69 Ogre::ColourValue(1.0, 0.752941176471, 0.501960784314),
70 Ogre::ColourValue(1.0, 0.901960784314, 0.501960784314),
71 Ogre::ColourValue(0.666666666667, 0.501960784314, 1.0),
72 Ogre::ColourValue(0.933333333333, 0.0, 0.8),
73 Ogre::ColourValue(1.0, 0.501960784314, 0.501960784314),
74 Ogre::ColourValue(0.4, 0.4, 0.0),
75 Ogre::ColourValue(1.0, 0.749019607843, 1.0),
76 Ogre::ColourValue(0.0, 1.0, 0.8),
77 Ogre::ColourValue(0.8, 0.4, 0.6),
78 Ogre::ColourValue(0.6, 0.6, 0.0),
79};
80
81using namespace RoRnet;
82
83static const unsigned int m_packet_buffer_size = 20;
84
85#define LOG_THREAD(_MSG_) { std::stringstream s; s << _MSG_ << " (Thread ID: " << std::this_thread::get_id() << ")"; LOG(s.str()); }
86#define LOGSTREAM Ogre::LogManager().getSingleton().stream()
87
88void Network::PushNetMessage(MsgType type, std::string const & message)
89{
90 Message m(type);
91 m.description = message;
93}
94
95Ogre::ColourValue Network::GetPlayerColor(int color_num)
96{
97 int numColours = sizeof(MP_COLORS) / sizeof(Ogre::ColourValue);
98 if (color_num < 0 || color_num >= numColours)
99 return Ogre::ColourValue::White;
100
101 return MP_COLORS[color_num];
102}
103
104// Internal helper
105void DebugPacket(const char *name, RoRnet::Header *header, char *buffer)
106{
107 std::stringstream msg;
108 msg << "++ " << name << ": " << header->source << ", " << header->streamid
109 << ", "<< header->command << ", " << header->size << ", hash: " << HashData(buffer, header->size);
110 LOG(msg.str());
111}
112
113void Network::SetNetQuality(int quality)
114{
115 m_net_quality = quality;
116}
117
119{
120 return m_net_quality;
121}
122
124{
125 return m_uid;
126}
127
128bool Network::SendMessageRaw(char *buffer, int msgsize)
129{
130 SWBaseSocket::SWBaseError error;
131
132 if (m_socket.fsend(buffer, msgsize, &error) < msgsize)
133 {
134 LOG("NET send error: " + error.get_error());
135 return false;
136 }
137
138 return true;
139}
140
141bool Network::SendNetMessage(int type, unsigned int streamid, int len, char* content)
142{
143 RoRnet::Header head;
144 memset(&head, 0, sizeof(RoRnet::Header));
145 head.command = type;
146 head.source = m_uid;
147 head.size = len;
148 head.streamid = streamid;
149
150 const int msgsize = sizeof(RoRnet::Header) + len;
151
152 if (msgsize >= RORNET_MAX_MESSAGE_LENGTH)
153 {
154 return false;
155 }
156
157 char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
158 memcpy(buffer, (char *)&head, sizeof(RoRnet::Header));
159 memcpy(buffer + sizeof(RoRnet::Header), content, len);
160
161 return SendMessageRaw(buffer, msgsize);
162}
163
164void Network::QueueStreamData(RoRnet::Header &header, char *buffer, size_t buffer_len)
165{
166 NetRecvPacket packet;
167 packet.header = header;
168 memcpy(packet.buffer, buffer, std::min(buffer_len, size_t(RORNET_MAX_MESSAGE_LENGTH)));
169
170 std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
171 m_recv_packet_buffer.push_back(packet);
172}
173
174int Network::ReceiveMessage(RoRnet::Header *head, char* content, int bufferlen)
175{
176 SWBaseSocket::SWBaseError error;
177
178#ifdef DEBUG
179 LOG_THREAD("[RoR|Networking] ReceiveMessage() waiting...");
180#endif //DEBUG
181
182 if (m_socket.frecv((char*)head, sizeof(RoRnet::Header), &error) < sizeof(RoRnet::Header))
183 {
184 LOG("NET receive error 1: " + error.get_error());
185 return -1;
186 }
187
188#ifdef DEBUG
189 LOG_THREAD("[RoR|Networking] ReceiveMessage() header received");
190#endif //DEBUG
191
192 if (head->size > uint32_t(bufferlen))
193 {
194 return -3;
195 }
196
197 if (head->size > 0)
198 {
199 // Read the packet content
200 std::memset(content, 0, bufferlen);
201 if (m_socket.frecv(content, head->size, &error) < static_cast<int>(head->size))
202 {
203 LOG_THREAD("NET receive error 2: "+ error.get_error());
204 return -1;
205 }
206 }
207
208#ifdef DEBUG
209 LOG_THREAD("[RoR|Networking] ReceiveMessage() body received");
210#endif //DEBUG
211
212 return 0;
213}
214
216{
217 LOG("[RoR|Networking] SendThread started");
218 while (!m_shutdown)
219 {
220 NetSendPacket packet;
221 {
222 std::unique_lock<std::mutex> queue_lock(m_send_packetqueue_mutex);
223 while (m_send_packet_buffer.empty() && !m_shutdown)
224 {
225 m_send_packet_available_cv.wait(queue_lock);
226 }
227 if (m_shutdown)
228 {
229 break;
230 }
231 packet = m_send_packet_buffer.front();
232 m_send_packet_buffer.pop_front();
233 }
234 SendMessageRaw(packet.buffer, packet.size);
235 }
236 LOG("[RoR|Networking] SendThread stopped");
237}
238
240{
241 LOG_THREAD("[RoR|Networking] RecvThread starting...");
242
243 RoRnet::Header header;
244
245 char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
246
247 while (!m_shutdown)
248 {
249 int err = ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH);
250 //LOG("Received data: " + TOSTRING(header.command) + ", source: " + TOSTRING(header.source) + ":" + TOSTRING(header.streamid) + ", size: " + TOSTRING(header.size));
251 if (err != 0)
252 {
253 LOG_THREAD("[RoR|Networking] RecvThread: Error while receiving data: " + TOSTRING(err));
254 m_shutdown = true; // Atomic; instruct sender thread to stop
255 PushNetMessage(MSG_NET_RECV_ERROR, _LC("Network", "Error receiving data from network"));
256 continue; // Stop receiving data
257 }
258
259 if (header.command == MSG2_STREAM_REGISTER)
260 {
261 if (header.source == m_uid)
262 continue;
263
265
266 LOG(" * received stream registration: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid) + ", type: " + TOSTRING(reg->type));
267 }
268 else if (header.command == MSG2_STREAM_REGISTER_RESULT)
269 {
271 LOG(" * received stream registration result: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid) + ", status: " + TOSTRING(reg->status));
272 }
273 else if (header.command == MSG2_STREAM_UNREGISTER)
274 {
275 LOG(" * received stream deregistration: " + TOSTRING(header.source) + ": " + TOSTRING(header.streamid));
276 }
277 else if (header.command == MSG2_UTF8_CHAT || header.command == MSG2_UTF8_PRIVCHAT)
278 {
279 // Chat message
280 }
281 else if (header.command == MSG2_NETQUALITY && header.source == -1)
282 {
283 if (header.size != sizeof(int))
284 {
285 continue;
286 }
287 int quality = *(int *)buffer;
288 SetNetQuality(quality);
289 continue;
290 }
291 else if (header.command == MSG2_USER_LEAVE)
292 {
293 if (header.source == m_uid)
294 {
295 m_shutdown = true; // Atomic; stop sending/receiving data - server closes the connection quickly after kick.
296
297 std::stringstream msg;
298 msg << _L("disconnected: remote side closed the connection");
299 msg << " ** ";
300 msg << buffer;
301
302 bool was_kick = (std::strstr(buffer, "disconnected on request") == nullptr); // FIXME: Add a reason code to MSG2_USER_LEAVE, this is ugly!
305
307 }
308 else
309 {
310 std::lock_guard<std::mutex> lock(m_users_mutex);
311 auto user = std::find_if(m_users.begin(), m_users.end(), [header](const RoRnet::UserInfo& u) { return static_cast<int>(u.uniqueid) == header.source; });
312 if (user != m_users.end())
313 {
314 // Console is now threadsafe, no need to send fake chatmessages to ourselves
315 Str<300> text;
316 text << _L("left the game");
319 LOG_THREAD(text);
320
321 // Erase matching peer options
322 int peeropt_offset = (int)std::distance(m_users.begin(), user);
323 auto peeropt_itor = m_users_peeropts.begin() + peeropt_offset;
324 m_users_peeropts.erase(peeropt_itor);
325
326 m_disconnected_users.push_back(*user); // Copy
327 m_users.erase(user);
328 }
329 }
330 }
331 else if (header.command == MSG2_USER_INFO || header.command == MSG2_USER_JOIN)
332 {
333 if (header.source == m_uid)
334 {
335 std::lock_guard<std::mutex> lock(m_userdata_mutex);
336 memcpy(&m_userdata, buffer, sizeof(RoRnet::UserInfo));
338 m_username = std::string(m_userdata.username);
340 // TODO: Update the global variable 'mp_player_name' in a threadsafe way.
341 }
342 else
343 {
344 RoRnet::UserInfo user_info;
345 if (!GetUserInfo(header.source, user_info)) // Check that user doesn't exist yet.
346 {
347 memcpy(&user_info, buffer, sizeof(RoRnet::UserInfo));
348 Str<300> text;
349 if (user_info.authstatus != 0) // Show nothing for guests (no special authorization)
350 {
351 text << "(" << UserAuthToStringShort(user_info) << ") ";
352 }
353 text << _L("joined the game");
354
355 // NB: Console is threadsafe
359 // Lock and update userlist
360 std::lock_guard<std::mutex> lock(m_users_mutex);
361 m_users.push_back(user_info);
362 m_users_peeropts.push_back(BitMask_t(0));
363 } // End of lock scope
364 }
365 continue;
366 }
367 else if (header.command == MSG2_GAME_CMD)
368 {
369#ifdef USE_ANGELSCRIPT
370 App::GetScriptEngine()->queueStringForExecution(Ogre::String(buffer));
371#endif // USE_ANGELSCRIPT
372 continue;
373 }
374 //DebugPacket("recv", &header, buffer);
375
377 }
378
379 LOG_THREAD("[RoR|Networking] RecvThread stopped");
380}
381
382
383void Network::CouldNotConnect(std::string const & msg, bool close_socket /*= true*/)
384{
385 RoR::LogFormat("[RoR|Networking] Failed to connect to server [%s:%d], message: %s", m_net_host.c_str(), m_net_port, msg.c_str());
387
388 if (close_socket)
389 {
390 m_socket.set_timeout(1, 0);
391 m_socket.disconnect();
392 }
393}
394
396{
397 // Shadow vars for threaded access
403
404 try
405 {
406 m_connect_thread = std::thread(&Network::ConnectThread, this);
407 App::mp_state->setVal((int)MpState::CONNECTING); // Mark connect thread as started
408 PushNetMessage(MSG_NET_CONNECT_STARTED, _LC("Network", "Starting..."));
409 return true;
410 }
411 catch (std::exception& e)
412 {
414 PushNetMessage(MSG_NET_CONNECT_FAILURE, _L("Failed to launch connection thread"));
415 RoR::LogFormat("[RoR|Networking] Failed to launch connection thread, message: %s", e.what());
416 return false;
417 }
418}
419
421{
423
424 if (m_connect_thread.joinable())
425 m_connect_thread.join(); // Clean up
426}
427
429{
430 RoR::LogFormat("[RoR|Networking] Trying to join server '%s' on port '%d' ...", m_net_host.c_str(), m_net_port);
431
432 SWBaseSocket::SWBaseError error;
433
434 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Estabilishing connection..."));
435 m_socket = SWInetSocket();
436 m_socket.set_timeout(10, 0);
437 m_socket.connect(m_net_port, m_net_host, &error);
438 if (error != SWBaseSocket::ok)
439 {
440 CouldNotConnect(_L("Could not create connection"), false);
441 return false;
442 }
443
444 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Getting server info..."));
445 if (!SendNetMessage(MSG2_HELLO, 0, (int)strlen(RORNET_VERSION), (char *)RORNET_VERSION))
446 {
447 CouldNotConnect(_L("Establishing network session: error sending hello"));
448 return false;
449 }
450
451 RoRnet::Header header;
452 char buffer[RORNET_MAX_MESSAGE_LENGTH] = {0};
453
454 // Receive server (rornet protocol) version
455 if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
456 {
457 CouldNotConnect(_L("Establishing network session: error getting server version"));
458 return false;
459 }
460 if (header.command == MSG2_WRONG_VER_LEGACY) // Pre-RoRnet_2.40 server
461 {
463 memcpy(&info, buffer, sizeof(RoRnet::LegacyServerInfo));
464 std::string format_str = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
465 const char* server_ver = (info.protocolversion[0] != 0) ? info.protocolversion : "~ RoRnet_2.38 or earlier (not detected) ~";
466 CouldNotConnect(fmt::format(format_str.c_str(), RORNET_VERSION, server_ver));
467 return false;
468 }
469 if (header.command == MSG2_WRONG_VER)
470 {
471 CouldNotConnect(_L("server uses a different protocol version"));
472 return false;
473 }
474 if (header.command != MSG2_HELLO)
475 {
476 CouldNotConnect(_L("Establishing network session: error getting server hello"));
477 return false;
478 }
479
480 // Save server settings
481 memcpy(&m_server_settings, buffer, sizeof(RoRnet::ServerInfo));
482
484 {
485 std::string formatstr = _L("Establishing network session: wrong server version, you are using version '%s' and the server is using '%s'");
487 return false;
488 }
489
490 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Authorizing..."));
491
492 // First handshake done, increase the timeout, important!
493 m_socket.set_timeout(0, 0);
494
495 // Construct user credentials
497 memset(&c, 0, sizeof(RoRnet::UserInfo));
498 // Cut off the UTF string on the highest level, otherwise you will break UTF info
500 strncpy(c.serverpassword, Sha1Hash(m_password).c_str(), size_t(40));
501 strncpy(c.usertoken, Sha1Hash(m_token).c_str(), size_t(40));
503 strncpy(c.clientname, "RoR", 10);
504 std::string language = App::app_language->getStr().substr(0, 2);
505 std::string country = App::app_country->getStr().substr(0, 2);
506 strncpy(c.language, (language + std::string("_") + country).c_str(), 5);
507 strcpy(c.sessiontype, "normal");
508 if (!SendNetMessage(MSG2_USER_INFO, 0, sizeof(RoRnet::UserInfo), (char*)&c))
509 {
510 CouldNotConnect(_L("Establishing network session: error sending user info"));
511 return false;
512 }
513
514 // Getting authorization
515 if (ReceiveMessage(&header, buffer, RORNET_MAX_MESSAGE_LENGTH))
516 {
517 CouldNotConnect(_L("Establishing network session: error getting server authorization"));
518 return false;
519 }
520
521 if (header.command==MSG2_FULL)
522 {
523 CouldNotConnect(_L("Establishing network session: sorry, server has too many players"));
524 return false;
525 }
526 else if (header.command==MSG2_BANNED)
527 {
528 // Do NOT `disconnect()` the m_socket in this case - causes SocketW to terminate RoR.
529 CouldNotConnect(_L("Establishing network session: sorry, you are banned!"), /*close_socket=*/false);
530 return false;
531 }
532 else if (header.command==MSG2_WRONG_PW)
533 {
534 CouldNotConnect(_L("Establishing network session: sorry, wrong password!"));
535 return false;
536 }
537 else if (header.command==MSG2_WRONG_VER)
538 {
539 CouldNotConnect(_L("Establishing network session: sorry, wrong protocol version!"));
540 return false;
541 }
542 else if (header.command==MSG2_NO_RANK)
543 {
544 CouldNotConnect(_L("Establishing network session: sorry, this server requires a user token!"));
545 // ChainMessage() ensures the MP settings request is handled _after_ the MSG_NET_CONNECT_FAILURE with the text above.
547 return false;
548 }
549
550 if (header.command!=MSG2_WELCOME)
551 {
552 CouldNotConnect(_L("Establishing network session: sorry, unknown server response"));
553 return false;
554 }
555
556 PushNetMessage(MSG_NET_CONNECT_PROGRESS, _LC("Network", "Finishing..."));
557
558 m_uid = header.source;
559
560 // we get our userdata back
561 memcpy(&m_userdata, buffer, std::min<int>(sizeof(RoRnet::UserInfo), header.size));
562
563 m_shutdown = false;
564
565 LOG("[RoR|Networking] Connect(): Creating Send/Recv threads");
566 m_send_thread = std::thread(&Network::SendThread, this);
567 m_recv_thread = std::thread(&Network::RecvThread, this);
569
570 return true;
571}
572
574{
575 LOG("[RoR|Networking] Disconnect() disconnecting...");
576 bool is_clean_disconnect = !m_shutdown; // Hacky detection of invalid network state
577
578 m_shutdown = true; // Instruct Send/Recv threads to shut down.
579
580 m_send_packet_available_cv.notify_one();
581
582 m_send_thread.join();
583 LOG("[RoR|Networking] Disconnect() sender thread cleaned up");
584
585 m_socket.set_timeout(1, 0);
586
587 if (is_clean_disconnect)
588 {
590 }
591
592 m_recv_thread.join();
593 LOG("[RoR|Networking] Disconnect() receiver thread cleaned up");
594
595 if (is_clean_disconnect)
596 {
597 m_socket.disconnect();
598 }
599 else
600 {
601 m_socket.close_fd();
602 }
603
604 SetNetQuality(0);
605 m_users.clear();
606 m_disconnected_users.clear();
607 m_recv_packet_buffer.clear();
608 m_send_packet_buffer.clear();
609 App::GetConsole()->doCommand("clear net");
610
611 m_shutdown = false;
613
614 LOG("[RoR|Networking] Disconnect() done");
615}
616
617void Network::AddPacket(int streamid, int type, int len, const char *content)
618{
619 const auto max_len = RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header);
620 if (len > max_len)
621 {
622 LOGSTREAM << "[RoR|Networking] Discarding network packet (StreamID: "
623 <<streamid<<", Type: "<<type<<"), length is " << len << ", max is " << max_len;
624 return;
625 }
626
627 NetSendPacket packet;
628 memset(&packet, 0, sizeof(NetSendPacket));
629
630 char *buffer = (char*)(packet.buffer);
631
632 RoRnet::Header *head = (RoRnet::Header *)buffer;
633 head->command = type;
634 head->source = m_uid;
635 head->size = len;
636 head->streamid = streamid;
637
638 // then copy the contents
639 char *bufferContent = (char *)(buffer + sizeof(RoRnet::Header));
640 memcpy(bufferContent, content, len);
641
642 // record the packet size
643 packet.size = len + sizeof(RoRnet::Header);
644
645 { // Lock scope
646 std::lock_guard<std::mutex> lock(m_send_packetqueue_mutex);
648 {
650 {
651 // buffer full, discard unimportant data packets
652 return;
653 }
654 auto search = std::find_if(m_send_packet_buffer.begin(), m_send_packet_buffer.end(),
655 [&](const NetSendPacket& p) { return !memcmp(packet.buffer, p.buffer, sizeof(RoRnet::Header)); });
656 if (search != m_send_packet_buffer.end())
657 {
658 // Found outdated discardable streamdata -> replace it
659 (*search) = packet;
660 m_send_packet_available_cv.notify_one();
661 return;
662 }
663 }
664 //DebugPacket("send", head, buffer);
665 m_send_packet_buffer.push_back(packet);
666 }
667
668 m_send_packet_available_cv.notify_one();
669}
670
672{
673 reg->origin_sourceid = m_uid;
675 reg->status = 0;
676
677 AddPacket(m_stream_id, MSG2_STREAM_REGISTER, size, (char*)reg);
678 LOG("adding local stream: " + TOSTRING(m_uid) + ":"+ TOSTRING(m_stream_id) + ", type: " + TOSTRING(reg->type));
679
680 m_stream_id++;
681}
682
683std::vector<NetRecvPacket> Network::GetIncomingStreamData()
684{
685 std::lock_guard<std::mutex> lock(m_recv_packetqueue_mutex);
686 std::vector<NetRecvPacket> buf_copy = m_recv_packet_buffer;
687 m_recv_packet_buffer.clear();
688 return buf_copy;
689}
690
692{
694}
695
697{
698 std::lock_guard<std::mutex> lock(m_userdata_mutex);
699 return m_userdata.colournum;
700}
701
703{
704 std::lock_guard<std::mutex> lock(m_userdata_mutex);
705 return m_username;
706}
707
709{
710 std::lock_guard<std::mutex> lock(m_userdata_mutex);
711 return m_userdata;
712}
713
714std::vector<RoRnet::UserInfo> Network::GetUserInfos()
715{
716 std::lock_guard<std::mutex> lock(m_users_mutex);
717 return m_users;
718}
719
720std::vector<BitMask_t> Network::GetAllUsersPeerOpts()
721{
722 std::lock_guard<std::mutex> lock(m_users_mutex);
723 return m_users_peeropts;
724}
725
727{
728 std::lock_guard<std::mutex> lock(m_users_mutex);
729 for (RoRnet::UserInfo user : m_users)
730 {
731 if ((int)user.uniqueid == uid)
732 {
733 result = user;
734 return true;
735 }
736 }
737 return false;
738}
739
741{
742 std::lock_guard<std::mutex> lock(m_users_mutex);
743 for (size_t i = 0; i < m_users.size(); i++)
744 {
745 if (static_cast<int>(m_users[i].uniqueid) == uid)
746 {
747 result = m_users_peeropts[i];
748 return true;
749 }
750 }
751 return false;
752}
753
755{
756 std::lock_guard<std::mutex> lock(m_users_mutex);
758 {
759 if ((int)user.uniqueid == uid)
760 {
761 result = user;
762 return true;
763 }
764 }
765 return false;
766}
767
769{
771
772 // Try remote users
773 if (GetUserInfo(uid, tmp))
774 {
775 result = tmp;
776 return true;
777 }
778
779 // Try local user
780 tmp = GetLocalUserData();
781 if (tmp.uniqueid == uid)
782 {
783 result = tmp;
784 return true;
785 }
786
787 return false;
788}
789
790bool Network::FindUserInfo(std::string const& username, RoRnet::UserInfo &result)
791{
792 std::lock_guard<std::mutex> lock(m_users_mutex);
793 for (RoRnet::UserInfo user : m_users)
794 {
795 if (user.username == username)
796 {
797 result = user;
798 return true;
799 }
800 }
801 return false;
802}
803
804
806{
807 std::lock_guard<std::mutex> lock(m_users_mutex);
808
809 const bool peeropts_sane = m_users.size() == m_users_peeropts.size();
810 ROR_ASSERT(peeropts_sane);
811 if (!peeropts_sane) return;
812
813 for (size_t i = 0; i < m_users.size(); i++)
814 {
815 if (static_cast<int>(m_users[i].uniqueid) == rq->por_uid)
816 {
818 }
819 }
820}
821
823{
824 std::lock_guard<std::mutex> lock(m_users_mutex);
825
826 const bool peeropts_sane = m_users.size() == m_users_peeropts.size();
827 ROR_ASSERT(peeropts_sane);
828 if (!peeropts_sane) return;
829
830 for (size_t i = 0; i < m_users.size(); i++)
831 {
832 if (static_cast<int>(m_users[i].uniqueid) == rq->por_uid)
833 {
835 }
836 }
837}
838
839void Network::BroadcastChatMsg(const char* msg)
840{
841 if (App::mp_state->getEnum<MpState>() == MpState::LOCAL_SCRIPT)
842 {
844 }
845 else
846 {
847 AddPacket(m_stream_id, RoRnet::MSG2_UTF8_CHAT, (int)std::strlen(msg), msg);
848 }
849}
850
851void Network::WhisperChatMsg(RoRnet::UserInfo const& user, const char* msg)
852{
853 // Prepare buffer
854 char payload[RORNET_MAX_MESSAGE_LENGTH - sizeof(RoRnet::Header)];
855 size_t payload_len = 0;
856
857 // Write client ID
858 std::memcpy(payload, &user.uniqueid, sizeof(user.uniqueid));
859 payload_len += sizeof(user.uniqueid);
860
861 // Write text
862 std::strncpy(payload + payload_len, msg, sizeof(payload) - payload_len);
863 payload_len += std::strlen(msg);
864
865 // Queue packet
866 AddPacket(m_stream_id, RoRnet::MSG2_UTF8_PRIVCHAT, (int)payload_len, msg);
867}
868
870{
871 if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth", "Admin"); }
872 else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth", "Mod"); }
873 else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth", "Bot"); }
874 else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth", "Ranked"); }
875 else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth", "Banned"); }
876 else { return _LC("NetUserAuth", "Guest"); }
877}
878
880{
881 if (user.authstatus & AUTH_ADMIN) { return _LC("NetUserAuth","Server Administrator"); }
882 else if (user.authstatus & AUTH_MOD) { return _LC("NetUserAuth","Server Moderator"); }
883 else if (user.authstatus & AUTH_BOT) { return _LC("NetUserAuth","Bot"); }
884 else if (user.authstatus & AUTH_RANKED) { return _LC("NetUserAuth","Ranked user"); }
885 else if (user.authstatus & AUTH_BANNED) { return _LC("NetUserAuth","Banned user"); }
886 else { return _LC("NetUserAuth","Guest"); }
887}
888
889// ============================================
890// Plumbing for local serverscripts and AI bots
891
893{
894 ROR_ASSERT(App::mp_state->getEnum<MpState>() == MpState::LOCAL_SCRIPT);
895 std::lock_guard<std::mutex> lock(m_users_mutex);
896 m_userdata = user;
897 m_uid = user.uniqueid;
898}
899
901{
902 // Lock and update userlist
903 std::lock_guard<std::mutex> lock(m_users_mutex);
904 m_users.push_back(user);
905 m_users_peeropts.push_back(BitMask_t(0));
906}
907
909{
910 std::lock_guard<std::mutex> lock(m_users_mutex);
911 auto user = std::find_if(m_users.begin(), m_users.end(), [uid](const RoRnet::UserInfo& u) { return static_cast<int>(u.uniqueid) == uid; });
912 if (user != m_users.end())
913 {
914 // Erase matching peer options
915 int peeropt_offset = (int)std::distance(m_users.begin(), user);
916 auto peeropt_itor = m_users_peeropts.begin() + peeropt_offset;
917 m_users_peeropts.erase(peeropt_itor);
918 // omit `m_disconnected_users` for bots.
919 m_users.erase(user);
920 }
921}
922
923#endif // USE_SOCKETW
Central state/object manager and communications hub.
#define ROR_ASSERT(_EXPR)
Definition Application.h:40
#define TOSTRING(x)
Definition Application.h:58
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:105
static Ogre::ColourValue MP_COLORS[]
Definition Network.cpp:48
#define LOG_THREAD(_MSG_)
Definition Network.cpp:85
static const unsigned int m_packet_buffer_size
Definition Network.cpp:83
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:740
std::deque< NetSendPacket > m_send_packet_buffer
Definition Network.h:202
Ogre::ColourValue GetPlayerColor(int color_num)
Definition Network.cpp:95
std::mutex m_users_mutex
Definition Network.h:194
int GetUserColor()
Definition Network.cpp:696
bool FindUserInfo(std::string const &username, RoRnet::UserInfo &result)
Definition Network.cpp:790
void AddLocalStream(RoRnet::StreamRegister *reg, int size)
Definition Network.cpp:671
void SendThread()
Definition Network.cpp:215
int ReceiveMessage(RoRnet::Header *head, char *content, int bufferlen)
Definition Network.cpp:174
std::string UserAuthToStringLong(RoRnet::UserInfo const &user)
Definition Network.cpp:879
std::string m_username
Definition Network.h:177
int m_authlevel
Definition Network.h:183
std::string GetUsername()
Definition Network.cpp:702
std::thread m_connect_thread
Definition Network.h:187
std::string m_password
Definition Network.h:179
int GetNetQuality()
Definition Network.cpp:118
void SetLocalUserData(RoRnet::UserInfo const &user)
Definition Network.cpp:892
void RemovePeerOptions(PeerOptionsRequest *rq)
Definition Network.cpp:822
SWInetSocket m_socket
Definition Network.h:169
void CouldNotConnect(std::string const &msg, bool close_socket=true)
Definition Network.cpp:383
bool GetAnyUserInfo(int uid, RoRnet::UserInfo &result)
Also considers local client.
Definition Network.cpp:768
bool SendMessageRaw(char *buffer, int msgsize)
Definition Network.cpp:128
std::vector< BitMask_t > GetAllUsersPeerOpts()
Definition Network.cpp:720
std::vector< RoRnet::UserInfo > m_disconnected_users
Definition Network.h:175
int m_net_port
Definition Network.h:181
std::atomic< int > m_net_quality
Definition Network.h:191
void BroadcastChatMsg(const char *msg)
Definition Network.cpp:839
std::vector< NetRecvPacket > GetIncomingStreamData()
Definition Network.cpp:683
std::mutex m_send_packetqueue_mutex
Definition Network.h:197
std::string m_net_host
Definition Network.h:178
bool GetDisconnectedUserInfo(int uid, RoRnet::UserInfo &result)
Definition Network.cpp:754
std::string UserAuthToStringShort(RoRnet::UserInfo const &user)
Definition Network.cpp:869
std::atomic< bool > m_shutdown
Definition Network.h:190
std::vector< NetRecvPacket > m_recv_packet_buffer
Definition Network.h:201
bool StartConnecting()
Launches connecting on background.
Definition Network.cpp:395
void SetNetQuality(int quality)
Definition Network.cpp:113
bool SendNetMessage(int type, unsigned int streamid, int len, char *content)
Definition Network.cpp:141
void RecvThread()
Definition Network.cpp:239
int m_stream_id
Counter.
Definition Network.h:192
std::thread m_send_thread
Definition Network.h:185
void AddPacket(int streamid, int type, int len, const char *content)
Definition Network.cpp:617
RoRnet::ServerInfo m_server_settings
Definition Network.h:171
void Disconnect()
Definition Network.cpp:573
std::thread m_recv_thread
Definition Network.h:186
void StopConnecting()
Definition Network.cpp:420
RoRnet::UserInfo GetLocalUserData()
Definition Network.cpp:708
void AddBotUserInfo(RoRnet::UserInfo const &user)
Definition Network.cpp:900
std::mutex m_recv_packetqueue_mutex
Definition Network.h:196
void PushNetMessage(MsgType type, std::string const &message)
Definition Network.cpp:88
std::vector< BitMask_t > m_users_peeropts
See RoRnet::PeerOptions.
Definition Network.h:174
RoRnet::UserInfo m_userdata
Definition Network.h:172
std::mutex m_userdata_mutex
Definition Network.h:195
Ogre::String GetTerrainName()
Definition Network.cpp:691
bool ConnectThread()
Definition Network.cpp:428
void QueueStreamData(RoRnet::Header &header, char *buffer, size_t buffer_len)
Definition Network.cpp:164
void RemoveBotUserInfo(int uid)
Definition Network.cpp:908
void WhisperChatMsg(RoRnet::UserInfo const &user, const char *msg)
Definition Network.cpp:851
bool GetUserInfo(int uid, RoRnet::UserInfo &result)
Definition Network.cpp:726
std::vector< RoRnet::UserInfo > GetUserInfos()
Definition Network.cpp:714
std::vector< RoRnet::UserInfo > m_users
Definition Network.h:173
void AddPeerOptions(PeerOptionsRequest *rq)
Definition Network.cpp:805
std::condition_variable m_send_packet_available_cv
Definition Network.h:199
std::string m_token
Definition Network.h:180
void queueStringForExecution(const Ogre::String command)
Queues a string for execution.
void queueMessagePlayerChat(int uid, const std::string &data)
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.
@ LOCAL_SCRIPT
Not actually connected to network, but running server script locally.
MsgType
Global gameplay message loop, see struct Message in GameContext.h.
Definition Application.h:77
@ MSG_NET_CONNECT_STARTED
@ 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
ServerScriptSequencer * GetServerScript()
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