1 /* Copyright (C) 2007-2011 The SpringLobby Team. All rights reserved. */
2
3 /**
4 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
5
6 DO NOT CHANGE THIS FILE!
7
8 this file is deprecated and will be replaced with
9
10 lsl/networking/tasserver.cpp
11
12 !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
13 **/
14
15
16
17 #include <wx/string.h>
18 #include <wx/regex.h>
19 #include <wx/intl.h>
20 #include <wx/protocol/http.h>
21 #include <wx/socket.h>
22 #include <wx/log.h>
23 #include <wx/tokenzr.h>
24 #include <wx/platinfo.h>
25 #include <wx/stopwatch.h>
26 #include <wx/timer.h>
27
28 #include <stdexcept>
29 #include <algorithm>
30
31 #include <map>
32
33 #include "base64.h"
34 #include "utils/md5.h"
35 #include "tasserver.h"
36 #include "user.h"
37 #include "utils/debug.h"
38 #include "utils/tasutil.h"
39 #include "utils/conversion.h"
40 #include "utils/platform.h"
41 #include "updater/updatehelper.h"
42 #include "serverevents.h"
43 #include "socket.h"
44 #include "channel/channel.h"
45 #include "tasservertokentable.h"
46
47 // for SL_MAIN_ICON
48 #include "utils/customdialogs.h"
49
50 #include "settings.h"
51
52 #define PING_TIME 30
53 #define PING_DELAY 5 //first ping is sent after PING_DELAY
54
55 const int udp_reply_timeout=10;
56
57
58 //! @brief Struct used internally by the TASServer class to get client status information.
59 struct TASClientstatus
60 {
61 unsigned int in_game :
62 1;
63 unsigned int away :
64 1;
65 unsigned int rank :
66 3;
67 unsigned int moderator :
68 1;
69 unsigned int bot :
70 1;
71 };
72
73
74 //! @brief Union used internally by the TASServer class to get client status information.
75 union UTASClientStatus
76 {
77 unsigned char byte;
78 TASClientstatus tasdata;
79 };
80
81
82 //! @brief Struct used internally by the TASServer class to get battle status information.
83 //!TODO is that last member necessary? throws a warning baout bein used uninited
84 struct TASBattleStatus
85 {
86 unsigned int :
87 1;
88 unsigned int ready :
89 1;
90 unsigned int team :
91 4;
92 unsigned int ally :
93 4;
94 unsigned int player :
95 1;
96 unsigned int handicap:
97 7;
98 unsigned int :
99 4;
100 unsigned int sync :
101 2;
102 unsigned int side :
103 4;
104 unsigned int :
105 4;
106 };
107
108 //! @brief Union used internally by the TASServer class to get battle status information.
109 union UTASBattleStatus
110 {
111 int data;
112 TASBattleStatus tasdata;
113 };
114
115 struct TASColor
116 {
117 unsigned int red :
118 8;
119 unsigned int green :
120 8;
121 unsigned int blue :
122 8;
123 unsigned int zero:
124 8;
125 };
126
127
128 union UTASColor
129 {
130 int data;
131 TASColor color;
132 };
133
134
135 /*
136
137 myteamcolor: Should be 32-bit signed integer in decimal form (e.g. 255 and not FF) where each color channel should occupy 1 byte (e.g. in hexdecimal: $00BBGGRR, B = blue, G = green, R = red). Example: 255 stands for $000000FF.
138
139 */
140
141 UserStatus ConvTasclientstatus( TASClientstatus );
142 UserBattleStatus ConvTasbattlestatus( TASBattleStatus );
143 TASBattleStatus ConvTasbattlestatus( UserBattleStatus );
144 IBattle::StartType IntToStartType( int start );
145 NatType IntToNatType( int nat );
146 IBattle::GameType IntToGameType( int gt );
147
148
TASServer(int serverEventsMode)149 TASServer::TASServer(int serverEventsMode):
150 m_ser_ver(0),
151 m_connected(false),
152 m_online(false),
153 m_debug_dont_catch( false ),
154 m_id_transmission( true ),
155 m_redirecting( false ),
156 m_buffer(wxEmptyString),
157 m_last_udp_ping(0),
158 m_last_ping(time(0) - PING_TIME + PING_DELAY), //no instant ping, delay first ping for PING_DELAY seconds
159 m_last_net_packet(0),
160 m_last_id(0),
161 m_udp_private_port(0),
162 m_nat_helper_port(0),
163 m_battle_id(-1),
164 m_server_lanmode(false),
165 m_account_id_count(0),
166 m_do_finalize_join_battle(false),
167 m_finalize_join_battle_id(-1),
168 m_token_transmission( false )
169 {
170 m_se = IServerEvents::getInstance( *this, IServerEvents::ServerEventsMode(serverEventsMode) );
171 FillAliasMap();
172 m_relay_host_manager_list.Clear();
173
174 Start(100); // call Update every 100ms
175 }
176
~TASServer()177 TASServer::~TASServer()
178 {
179 Stop();
180 Disconnect();
181 delete m_se;
182 m_se = NULL;
183 }
184
Notify()185 void TASServer::Notify() {
186 Update(GetInterval());
187 };
188
ExecuteSayCommand(const wxString & cmd)189 bool TASServer::ExecuteSayCommand( const wxString& cmd )
190 {
191 wxArrayString arrayparams = wxStringTokenize( cmd, _T(" ") );
192 if ( arrayparams.GetCount() == 0 ) return false;
193 wxString subcmd = arrayparams[0];
194 wxString params = cmd.AfterFirst( ' ' );
195 if ( subcmd == _T("/ingame") )
196 {
197 if ( arrayparams.GetCount() != 2 ) return false;
198 SendCmd( _T("GETINGAMETIME"), arrayparams[1] );
199 return true;
200 }
201 else if ( subcmd == _T("/kick") )
202 {
203 if ( arrayparams.GetCount() < 2 ) return false;
204 SendCmd( _T("KICKUSER"), params );
205 return true;
206 }
207 else if ( subcmd == _T("/ban") )
208 {
209 if ( arrayparams.GetCount() < 2 ) return false;
210 SendCmd( _T("BAN"), params );
211 return true;
212 }
213 else if ( subcmd == _T("/unban") )
214 {
215 if ( arrayparams.GetCount() != 2 ) return false;
216 SendCmd( _T("UNBAN"), arrayparams[1] );
217 return true;
218 }
219 else if ( subcmd == _T("/banlist") )
220 {
221 SendCmd( _T("BANLIST") );
222 return true;
223 }
224 else if ( subcmd == _T("/topic") )
225 {
226 params.Replace( _T("\n"), _T("\\n") );
227 SendCmd( _T("CHANNELTOPIC"), params );
228 return true;
229 }
230 else if ( subcmd == _T("/chanmsg") )
231 {
232 if ( arrayparams.GetCount() < 2 ) return false;
233 SendCmd( _T("CHANNELMESSAGE"), params );
234 return true;
235 }
236 else if ( subcmd == _T("/ring") )
237 {
238 if ( arrayparams.GetCount() != 2 ) return false;
239 SendCmd( _T("RING"), arrayparams[1] );
240 return true;
241 }
242 else if ( subcmd == _T("/ip") )
243 {
244 if ( arrayparams.GetCount() != 2 ) return false;
245 SendCmd( _T("GETIP"), arrayparams[1] );
246 return true;
247 }
248 else if ( subcmd == _T("/mute") )
249 {
250 if ( arrayparams.GetCount() < 4 ) return false;
251 if ( arrayparams.GetCount() > 5 ) return false;
252 SendCmd( _T("MUTE"), params );
253 return true;
254 }
255 else if ( subcmd == _T("/unmute") )
256 {
257 if ( arrayparams.GetCount() != 3 ) return false;
258 SendCmd( _T("UNMUTE"), arrayparams[1] + _T(" ") + arrayparams[2] );
259 return true;
260 }
261 else if ( subcmd == _T("/mutelist") )
262 {
263 if ( arrayparams.GetCount() != 2 ) return false;
264 SendCmd( _T("MUTELIST"), arrayparams[1] );
265 return true;
266 }
267 else if ( subcmd == _T("/lastlogin") )
268 {
269 if ( arrayparams.GetCount() != 2 ) return false;
270 SendCmd( _T("GETLASTLOGINTIME"), arrayparams[1] );
271 return true;
272 }
273 else if ( subcmd == _T("/findip") )
274 {
275 if ( arrayparams.GetCount() != 2 ) return false;
276 SendCmd( _T("FINDIP"), arrayparams[1] );
277 return true;
278 }
279 else if ( subcmd == _T("/lastip") )
280 {
281 if ( arrayparams.GetCount() != 2 ) return false;
282 SendCmd( _T("GETLASTIP"), arrayparams[1] );
283 return true;
284 }
285 else if ( subcmd == _T("/rename") )
286 {
287 if ( arrayparams.GetCount() != 2 ) return false;
288 SendCmd( _T("RENAMEACCOUNT"), arrayparams[1] );
289 sett().SetServerAccountNick( sett().GetDefaultServer(), arrayparams[1] ); // this code assumes that default server hasn't changed since login ( like it should atm )
290 return true;
291 }
292 else if ( subcmd == _T("/testmd5") )
293 {
294 ExecuteCommand( _T("SERVERMSG"), GetPasswordHash(params) );
295 return true;
296 }
297 else if ( subcmd == _T("/hook") )
298 {
299 SendCmd( _T("HOOK"), params );
300 return true;
301 }
302 else if ( subcmd == _T("/quit") )
303 {
304 Disconnect();
305 return true;
306 }
307 else if ( subcmd == _T("/changepassword2") )
308 {
309 if ( arrayparams.GetCount() < 1 ) return false;
310 wxString oldpassword = sett().GetServerAccountPass( GetServerName() );
311 wxString newpassword = GetPasswordHash( params );
312 if ( oldpassword.IsEmpty() || !sett().GetServerAccountSavePass(GetServerName()) )
313 {
314 m_se->OnServerMessage(_("There is no saved password for this account, please use /changepassword"));
315 return true;
316 }
317 SendCmd( _T("CHANGEPASSWORD"), oldpassword + _T(" ") + newpassword );
318 return true;
319 }
320 else if ( subcmd == _T("/changepassword") )
321 {
322 if ( arrayparams.GetCount() != 2 ) return false;
323 wxString oldpassword = GetPasswordHash(arrayparams[1]);
324 wxString newpassword = GetPasswordHash( arrayparams[2] );
325 SendCmd( _T("CHANGEPASSWORD"), oldpassword + _T(" ") + newpassword );
326 return true;
327 }
328 else if ( subcmd == _T("/ping") )
329 {
330 Ping();
331 return true;
332 }
333 return false;
334 }
335
336
Connect(const wxString & servername,const wxString & addr,const int port)337 void TASServer::Connect( const wxString& servername ,const wxString& addr, const int port )
338 {
339 m_server_name = servername;
340 m_addr=addr;
341 m_buffer = wxEmptyString;
342 m_sock->Connect( addr, port );
343 m_sock->SetSendRateLimit( 800 ); // 1250 is the server limit but 800 just to make sure :)
344 m_connected = false;
345 m_online = false;
346 m_redirecting = false;
347 m_agreement = wxEmptyString;
348 m_crc.ResetCRC();
349 m_last_net_packet = time( 0 );
350 wxString handle = m_sock->GetHandle();
351 if ( !handle.IsEmpty() ) m_crc.UpdateData( STD_STRING( wxString( handle + m_addr ) ) );
352 }
353
Disconnect()354 void TASServer::Disconnect()
355 {
356 if (!m_connected)
357 {
358 return;
359 }
360 m_connected = false;
361 SendCmd( _T("EXIT") ); // EXIT command for new protocol compatibility
362 m_sock->Disconnect();
363 }
364
IsConnected()365 bool TASServer::IsConnected()
366 {
367 return (m_sock->State() == SS_Open) && (m_connected);
368 }
369
370
Register(const wxString & addr,const int port,const wxString & nick,const wxString & password,wxString & reason)371 bool TASServer::Register( const wxString& addr, const int port, const wxString& nick, const wxString& password, wxString& reason )
372 {
373 wxLogDebugFunc( wxEmptyString );
374 FakeNetClass temp;
375 Socket tempsocket( temp, true, true );
376 tempsocket.Connect( addr, port );
377 if ( tempsocket.State() != SS_Open ) return false;
378
379 wxString data = tempsocket.Receive().BeforeLast(_T('\n'));
380 if ( data.Find( _T("\r") ) != wxNOT_FOUND ) data = data.BeforeLast(_T('\r'));
381 if ( GetWordParam( data ) != _T("TASServer") ) return false;
382
383 tempsocket.Send( _T("REGISTER ") + nick + _T(" ") + GetPasswordHash( password ) + _T("\n") );
384
385 data = tempsocket.Receive().BeforeLast(_T('\n'));
386 tempsocket.Disconnect();
387 if ( data.Find( _T("\r") ) != wxNOT_FOUND ) data = data.BeforeLast(_T('\r'));
388 if ( data.IsEmpty() )
389 {
390 reason = _("Connection timed out");
391 return false;
392 }
393 wxString cmd = GetWordParam( data );
394 if ( cmd == _T("REGISTRATIONACCEPTED"))
395 {
396 return true;
397 }
398 else if ( cmd == _T("REGISTRATIONDENIED") )
399 {
400 reason = data;
401 return false;
402 }
403 reason = _("Unknown answer from server");
404 return false;
405 }
406
407
IsPasswordHash(const wxString & pass) const408 bool TASServer::IsPasswordHash( const wxString& pass ) const
409 {
410 return pass.length() == 24 && pass[22] == '=' && pass[23] == '=';
411 }
412
413
GetPasswordHash(const wxString & pass) const414 wxString TASServer::GetPasswordHash( const wxString& pass ) const
415 {
416 if ( IsPasswordHash(pass) ) return pass;
417
418 md5_state_t state;
419 md5_byte_t digest[16];
420 char hex_output[16*2 + 1];
421 int di;
422
423 std::string str = STD_STRING(pass);
424 char* cstr = new char [str.size()+1];
425 strcpy (cstr, str.c_str());
426
427 md5_init(&state);
428 md5_append(&state, (const md5_byte_t *) cstr, strlen( cstr ));
429 md5_finish(&state, digest);
430 for (di = 0; di < 16; ++di)
431 sprintf(hex_output + di * 2, "%02x", digest[di]);
432 delete [] cstr;
433 wxString coded = wxBase64::Encode( digest, 16 );
434 return coded;
435 }
436
437
GetMe()438 User& TASServer::GetMe() {
439 return GetUser( m_user );
440 }
GetMe() const441 const User& TASServer::GetMe() const {
442 return GetUser( m_user );
443 }
444
Useragent()445 wxString Useragent()
446 {
447 return sett().Get( _T("Useragent"), GetAppName() ) + _T(" ") +
448 sett().Get( _T("Userversion"), GetSpringLobbyVersion(false) );
449 }
450
Login()451 void TASServer::Login()
452 {
453 wxLogDebugFunc( wxEmptyString );
454 wxString pass = GetPasswordHash( m_pass );
455 wxString protocol = TowxString( m_crc.GetCRC() );
456 wxString localaddr;
457 localaddr = m_sock->GetLocalAddress();
458 if ( localaddr.IsEmpty() ) localaddr = _T("*");
459 m_id_transmission = false;
460 wxFormat login_cmd( _T("%s %s %s %s %s\t%s\ta m sp cl") );
461 SendCmd ( _T("LOGIN"), (login_cmd % m_user % pass % GetHostCPUSpeed() % localaddr % Useragent() % protocol).str() );
462 m_id_transmission = true;
463 }
464
Logout()465 void TASServer::Logout()
466 {
467 wxLogDebugFunc( wxEmptyString );
468 Disconnect();
469 }
470
IsOnline() const471 bool TASServer::IsOnline() const
472 {
473 if ( !m_connected ) return false;
474 return m_online;
475 }
476
477
RequestChannels()478 void TASServer::RequestChannels()
479 {
480 SendCmd( _T("CHANNELS") );
481 }
482
483
AcceptAgreement()484 void TASServer::AcceptAgreement()
485 {
486 SendCmd( _T("CONFIRMAGREEMENT") );
487 }
488
489
Update(int mselapsed)490 void TASServer::Update( int mselapsed )
491 {
492 if (m_sock == NULL) return;
493
494 m_sock->OnTimer( mselapsed );
495
496 if ( !m_connected ) // We are not formally connected yet, but might be.
497 {
498 if ( IsConnected() )
499 {
500 m_last_udp_ping = time( 0 );
501 m_connected = true;
502 }
503 return;
504 }
505 else // We are connected already.
506 {
507 if ( !IsConnected() ) return;
508
509 time_t now = time( 0 );
510
511 if ((m_last_ping + PING_TIME) < now) { //Send a PING every 30 seconds
512 m_last_ping = now;
513 Ping();
514 }
515
516 if ( ( m_last_net_packet > 0 ) && ( ( now - m_last_net_packet ) > PING_TIMEOUT ) ) { // no data received, assume timeout
517 m_se->OnServerMessage( _("Timeout assumed, disconnecting") );
518 Disconnect();
519 }
520
521 // joining battle with nat traversal:
522 // if we havent finalized joining yet, and udp_reply_timeout seconds has passed since
523 // we did UdpPing(our name) , join battle anyway, but with warning message that nat failed.
524 // (if we'd receive reply from server, we'd finalize already)
525 //
526 if (m_do_finalize_join_battle&&(m_last_udp_ping+udp_reply_timeout<now))
527 {
528 customMessageBoxNoModal(SL_MAIN_ICON,_("Failed to punch through NAT, playing this battle might not work for you or for other players."),_("Error"), wxICON_ERROR);
529 //wxMessageBox()
530 FinalizeJoinBattle();
531 //wxMessageBox(_("Failed to punch through NAT"), _("Error"), wxICON_INFORMATION, NULL/* m_ui.mw()*/ );
532 };
533
534 if ( ( m_last_udp_ping + m_keepalive ) < now )
535 {
536 // Is it time for a nat traversal PING?
537 m_last_udp_ping = now;
538 // Nat travelsal "ping"
539 if ( m_battle_id != -1 )
540 {
541 Battle *battle=GetCurrentBattle();
542 if (battle)
543 {
544 if ( ( battle->GetNatType() == NAT_Hole_punching || ( battle->GetNatType() == NAT_Fixed_source_ports ) ) && !battle->GetInGame() )
545 {
546 if ( battle->IsFounderMe() )
547 {
548 UdpPingTheServer(m_user);
549 UdpPingAllClients();
550 }
551 else
552 {
553 UdpPingTheServer(m_user);
554 }
555 }
556 }
557 }
558 }
559 }
560
561 }
562
563
ExecuteCommand(const wxString & in)564 void TASServer::ExecuteCommand( const wxString& in )
565 {
566 wxLogMessage( _T("%s"), in.c_str() );
567 wxString cmd;
568 wxString params = in;
569 long replyid = 0;
570
571 if ( in.empty() ) return;
572 try
573 {
574 ASSERT_LOGIC( params.AfterFirst( '\n' ).IsEmpty(), _T("losing data") );
575 }
576 catch (...)
577 {
578 return;
579 }
580 if ( params[0] == '#' )
581 {
582 wxString id = params.BeforeFirst( ' ' ).AfterFirst( '#' );
583 params = params.AfterFirst( ' ' );
584 id.ToLong( &replyid );
585 }
586 cmd = params.BeforeFirst( ' ' );
587 params = params.AfterFirst( ' ' );
588
589 // decode message if tokenized
590 wxString copy = cmd;
591 cmd = DecodeTokenMessage( cmd );
592 if ( copy != cmd ) m_token_transmission = true;
593 cmd.MakeUpper();
594
595 if ( m_debug_dont_catch )
596 {
597 ExecuteCommand( cmd, params, replyid );
598 }
599 else
600 {
601 try
602 {
603 ExecuteCommand( cmd, params, replyid );
604 }
605 catch ( ... ) // catch everything so the app doesn't crash, may makes odd beahviours but it's better than crashing randomly for normal users
606 {
607 }
608 }
609 }
610
611
ExecuteCommand(const wxString & cmd,const wxString & inparams,int replyid)612 void TASServer::ExecuteCommand( const wxString& cmd, const wxString& inparams, int replyid )
613 {
614 wxString params = inparams;
615 int pos, cpu, id, nat, port, maxplayers, rank, specs, units, top, left, right, bottom, ally, type;
616 bool haspass,lanmode = false;
617 wxString hash;
618 wxString nick, contry, host, map, title, mod, channel, error, msg, owner, ai, supported_spring_version, topic, engineName, engineVersion;
619 //NatType ntype;
620 UserStatus cstatus;
621 UTASClientStatus tasstatus;
622 UTASBattleStatus tasbstatus;
623 UserBattleStatus bstatus;
624 UTASColor color;
625
626 if ( cmd == _T("TASSERVER"))
627 {
628 mod = GetWordParam( params );
629 mod.ToDouble( &m_ser_ver );
630 supported_spring_version = GetWordParam( params );
631 m_nat_helper_port = (unsigned long)GetIntParam( params );
632 lanmode = GetBoolParam( params );
633 m_server_lanmode = lanmode;
634 m_se->OnConnected( m_server_name, mod, (m_ser_ver > 0), supported_spring_version, lanmode );
635 }
636 else if ( cmd == _T("ACCEPTED") )
637 {
638 if ( m_online ) return; // in case is the server sends WTF
639 m_online = true;
640 m_user = params;
641 m_se->OnLogin( );
642 }
643 else if ( cmd == _T("MOTD") )
644 {
645 m_se->OnMotd( params );
646 }
647 else if ( cmd == _T("ADDUSER") )
648 {
649 nick = GetWordParam( params );
650 contry = GetWordParam( params );
651 cpu = GetIntParam( params );
652 if ( params.IsEmpty() )
653 {
654 // if server didn't send any account id to us, fill with an always increasing number
655 id = m_account_id_count;
656 m_account_id_count++;
657 }
658 else
659 {
660 id = GetIntParam( params );
661 }
662 m_se->OnNewUser( nick, contry, cpu, TowxString(id) );
663 if ( nick == m_relay_host_bot )
664 {
665 RelayCmd( _T("OPENBATTLE"), m_delayed_open_command ); // relay bot is deployed, send host command
666 m_delayed_open_command = wxEmptyString;
667 }
668 }
669 else if ( cmd == _T("CLIENTSTATUS") )
670 {
671 nick = GetWordParam( params );
672 tasstatus.byte = GetIntParam( params );
673 cstatus = ConvTasclientstatus( tasstatus.tasdata );
674 m_se->OnUserStatus( nick, cstatus );
675 }
676 else if ( cmd == _T("BATTLEOPENED") )
677 {
678 id = GetIntParam( params );
679 type = GetIntParam( params );
680 nat = GetIntParam( params );
681 nick = GetWordParam( params );
682 host = GetWordParam( params );
683 port = GetIntParam( params );
684 maxplayers = GetIntParam( params );
685 haspass = GetBoolParam( params );
686 rank = GetIntParam( params );
687 hash = MakeHashUnsigned( GetWordParam( params ) );
688 engineName = GetSentenceParam( params );
689 engineVersion = GetSentenceParam( params );
690 map = GetSentenceParam( params );
691 title = GetSentenceParam( params );
692 mod = GetSentenceParam( params );
693 m_se->OnBattleOpenedEx( id, (BattleType)type, IntToNatType( nat ), nick, host, port, maxplayers,
694 haspass, rank, hash, engineName, engineVersion, map, title, mod );
695 if ( nick == m_relay_host_bot )
696 {
697 GetBattle( id ).SetProxy( m_relay_host_bot );
698 JoinBattle( id, sett().GetLastHostPassword() ); // autojoin relayed host battles
699 }
700 }
701 else if ( cmd == _T("JOINEDBATTLE") )
702 {
703 id = GetIntParam( params );
704 nick = GetWordParam( params );
705 wxString userScriptPassword = GetWordParam( params );
706 m_se->OnUserJoinedBattle( id, nick, userScriptPassword );
707 }
708 else if ( cmd == _T("UPDATEBATTLEINFO") )
709 {
710 id = GetIntParam( params );
711 specs = GetIntParam( params );
712 haspass = GetBoolParam( params );
713 hash = MakeHashUnsigned( GetWordParam( params ) );
714 map = GetSentenceParam( params );
715 m_se->OnBattleInfoUpdated( id, specs, haspass, hash, map );
716 }
717 else if ( cmd == _T("LOGININFOEND") )
718 {
719 if ( UserExists( _T("RelayHostManagerList") ) ) SayPrivate( _T("RelayHostManagerList"), _T("!lm") );
720 m_se->OnLoginInfoComplete();
721 }
722 else if ( cmd == _T("REMOVEUSER") )
723 {
724 nick = GetWordParam( params );
725 if ( nick == m_user ) return; // to prevent peet doing nasty stuff to you, watch your back!
726 m_se->OnUserQuit( nick );
727 }
728 else if ( cmd == _T("BATTLECLOSED") )
729 {
730 id = GetIntParam( params );
731 if ( m_battle_id == id ) m_relay_host_bot = wxEmptyString;
732 m_se->OnBattleClosed( id );
733 }
734 else if ( cmd == _T("LEFTBATTLE") )
735 {
736 id = GetIntParam( params );
737 nick = GetWordParam( params );
738 m_se->OnUserLeftBattle( id, nick );
739 }
740 else if ( cmd == _T("PONG") )
741 {
742 HandlePong( replyid );
743 }
744 else if ( cmd == _T("JOIN") )
745 {
746 channel = GetWordParam( params );
747 m_se->OnJoinChannelResult( true, channel, wxEmptyString );
748 }
749 else if ( cmd == _T("JOIN") )
750 {
751 channel = GetWordParam( params );
752 error = GetSentenceParam( params );
753 m_se->OnJoinChannelResult( false, channel, error );
754 }
755 else if ( cmd == _T("SAID") )
756 {
757 channel = GetWordParam( params );
758 nick = GetWordParam( params );
759 m_se->OnChannelSaid( channel, nick, params );
760 }
761 else if ( cmd == _T("JOINED") )
762 {
763 channel = GetWordParam( params );
764 nick = GetWordParam( params );
765 m_se->OnUserJoinChannel( channel, nick );
766 }
767 else if ( cmd == _T("LEFT") )
768 {
769 channel = GetWordParam( params );
770 nick = GetWordParam( params );
771 msg = GetSentenceParam( params );
772 m_se->OnChannelPart( channel, nick, msg );
773 }
774 else if ( cmd == _T("CHANNELTOPIC") )
775 {
776 channel = GetWordParam( params );
777 nick = GetWordParam( params );
778 pos = GetIntParam( params );
779 params.Replace( _T("\\n"), _T("\n") );
780 m_se->OnChannelTopic( channel, nick, params, pos/1000 );
781 }
782 else if ( cmd == _T("SAIDEX") )
783 {
784 channel = GetWordParam( params );
785 nick = GetWordParam( params );
786 m_se->OnChannelAction( channel, nick, params );
787 }
788 else if ( cmd == _T("CLIENTS") )
789 {
790 channel = GetWordParam( params );
791 while ( (nick = GetWordParam( params )) != wxEmptyString )
792 {
793 m_se->OnChannelJoin( channel, nick );
794 }
795 }
796 else if ( cmd == _T("SAYPRIVATE") )
797 {
798 nick = GetWordParam( params );
799 if ( ( ( nick == m_relay_host_bot ) || ( nick == m_relay_host_manager ) ) && params.StartsWith( _T("!") ) ) return; // drop the message
800 if ( ( nick == _T("RelayHostManagerList") ) && ( params == _T("!lm") ) ) return;// drop the message
801 if ( nick == _T("SL_bot") )
802 {
803 if ( params.StartsWith( _T("stats.report") ) ) return;
804 }
805 m_se->OnPrivateMessage( nick, params, true );
806 }
807 else if ( cmd == _T("SAYPRIVATEEX") )
808 {
809 nick = GetWordParam( params );
810 m_se->OnPrivateMessageEx( nick, params, true );
811 }
812 else if ( cmd == _T("SAIDPRIVATE") )
813 {
814 nick = GetWordParam( params );
815 if ( nick == m_relay_host_bot )
816 {
817 if ( params.StartsWith(_T("JOINEDBATTLE")) )
818 {
819 GetWordParam( params ); // skip first word, it's the message itself
820 /*id =*/ GetIntParam( params );
821 wxString usernick = GetWordParam( params );
822 wxString userScriptPassword = GetWordParam( params );
823 try
824 {
825 User& usr = GetUser(usernick);
826 usr.BattleStatus().scriptPassword = userScriptPassword;
827 Battle* battle = GetCurrentBattle();
828 if (battle)
829 {
830 if ( battle->CheckBan( usr ) ) return;
831 }
832 SetRelayIngamePassword( usr );
833 } catch (...) {}
834 return;
835 }
836 }
837 if ( nick == m_relay_host_manager )
838 {
839 if ( params.StartsWith( _T("\001") ) ) // error code
840 {
841 m_se->OnServerMessageBox( params.AfterFirst( _T(' ') ) );
842 }
843 else
844 {
845 m_relay_host_bot = params;
846 }
847 m_relay_host_manager = wxEmptyString;
848 return;
849 }
850 if ( nick == _T("RelayHostManagerList") )
851 {
852 if ( params.StartsWith(_T("list ")) )
853 {
854 wxString list = params.AfterFirst( _T(' ') );
855 m_relay_host_manager_list = wxStringTokenize( list, _T("\t") );
856 return;
857 }
858 }
859 m_se->OnPrivateMessage( nick, params, false );
860 }
861 else if ( cmd == _T("SAIDPRIVATEEX") )
862 {
863 nick = GetWordParam( params );
864 m_se->OnPrivateMessageEx( nick, params, false );
865 }
866 else if ( cmd == _T("JOINBATTLE") )
867 {
868 id = GetIntParam( params );
869 hash = MakeHashUnsigned( GetWordParam( params ) );
870 m_battle_id = id;
871 m_se->OnJoinedBattle( id, hash );
872 m_se->OnBattleInfoUpdated( m_battle_id );
873 try
874 {
875 if (GetBattle(id).IsProxy()) RelayCmd(_T("SUPPORTSCRIPTPASSWORD")); // send flag to relayhost marking we support script passwords
876 } catch(...) {}
877 }
878 else if ( cmd == _T("CLIENTBATTLESTATUS") )
879 {
880 nick = GetWordParam( params );
881 tasbstatus.data = GetIntParam( params );
882 bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
883 color.data = GetIntParam( params );
884 bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
885 m_se->OnClientBattleStatus( m_battle_id, nick, bstatus );
886 }
887 else if ( cmd == _T("ADDSTARTRECT") )
888 {
889 //ADDSTARTRECT allyno left top right bottom
890 ally = GetIntParam( params );
891 left = GetIntParam( params );
892 top = GetIntParam( params );
893 right = GetIntParam( params );
894 bottom = GetIntParam( params );;
895 m_se->OnBattleStartRectAdd( m_battle_id, ally, left, top, right, bottom );
896 }
897 else if ( cmd == _T("REMOVESTARTRECT") )
898 {
899 //REMOVESTARTRECT allyno
900 ally = GetIntParam( params );
901 m_se->OnBattleStartRectRemove( m_battle_id, ally );
902 }
903 else if ( cmd == _T("ENABLEALLUNITS") )
904 {
905 //"ENABLEALLUNITS" params: "".
906 m_se->OnBattleEnableAllUnits( m_battle_id );
907 }
908 else if ( cmd == _T("ENABLEUNITS") )
909 {
910 //ENABLEUNITS unitname1 unitname2
911 while ( (nick = GetWordParam( params )) !=wxEmptyString )
912 {
913 m_se->OnBattleEnableUnit( m_battle_id, nick );
914 }
915 }
916 else if ( cmd == _T("DISABLEUNITS") )
917 {
918 //"DISABLEUNITS" params: "arm_advanced_radar_tower arm_advanced_sonar_station arm_advanced_torpedo_launcher arm_dragons_teeth arm_energy_storage arm_eraser arm_fark arm_fart_mine arm_fibber arm_geothermal_powerplant arm_guardian"
919 while ( (nick = GetWordParam( params )) != wxEmptyString )
920 {
921 m_se->OnBattleDisableUnit( m_battle_id, nick );
922 }
923 }
924 else if ( cmd == _T("CHANNEL") )
925 {
926 channel = GetWordParam( params );
927 units = GetIntParam( params );
928 topic = GetSentenceParam( params );
929 m_se->OnChannelList( channel, units, topic );
930 }
931 else if ( cmd == _T("ENDOFCHANNELS") )
932 {
933 //Cmd: ENDOFCHANNELS params:
934 }
935 else if ( cmd == _T("REQUESTBATTLESTATUS") )
936 {
937 m_se->OnRequestBattleStatus( m_battle_id );
938 }
939 else if ( cmd == _T("SAIDBATTLE") )
940 {
941 nick = GetWordParam( params );
942 m_se->OnSaidBattle( m_battle_id, nick, params );
943 }
944 else if ( cmd == _T("SAIDBATTLEEX") )
945 {
946 nick = GetWordParam( params );
947 m_se->OnBattleAction( m_battle_id, nick, params );
948 }
949 else if ( cmd == _T("AGREEMENT") )
950 {
951 msg = GetSentenceParam( params );
952 m_agreement += msg + _T("\n");
953 }
954 else if ( cmd == _T("AGREEMENTEND") )
955 {
956 m_se->OnAcceptAgreement( m_agreement );
957 m_agreement = wxEmptyString;
958 }
959 else if ( cmd == _T("OPENBATTLE") )
960 {
961 m_battle_id = GetIntParam( params );
962 m_se->OnHostedBattle( m_battle_id );
963 }
964 else if ( cmd == _T("ADDBOT") )
965 {
966 // ADDBOT BATTLE_ID name owner battlestatus teamcolor {AIDLL}
967 id = GetIntParam( params );
968 nick = GetWordParam( params );
969 owner = GetWordParam( params );
970 tasbstatus.data = GetIntParam( params );
971 bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
972 color.data = GetIntParam( params );
973 bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
974 ai = GetSentenceParam( params );
975 if ( ai.IsEmpty() ) {
976 wxLogWarning( wxString::Format( _T("Recieved illegal ADDBOT (empty dll field) from %s for battle %d"), nick.c_str(), id ) );
977 ai = _T("INVALID|INVALID");
978 }
979 if( LSL::usync().VersionSupports( LSL::USYNC_GetSkirmishAI ) )
980 {
981 if (ai.Find(_T('|')) != -1)
982 {
983 bstatus.aiversion = ai.AfterLast( _T('|') );
984 ai = ai.BeforeLast( _T('|') );
985 }
986 bstatus.aishortname = ai;
987 }
988 else
989 {
990 bstatus.aishortname = ai;
991 }
992 bstatus.owner =owner;
993 m_se->OnBattleAddBot( id, nick, bstatus );
994 }
995 else if ( cmd == _T("UPDATEBOT") )
996 {
997 id = GetIntParam( params );
998 nick = GetWordParam( params );
999 tasbstatus.data = GetIntParam( params );
1000 bstatus = ConvTasbattlestatus( tasbstatus.tasdata );
1001 color.data = GetIntParam( params );
1002 bstatus.colour = wxColour( color.color.red, color.color.green, color.color.blue );
1003 m_se->OnBattleUpdateBot( id, nick, bstatus );
1004 //UPDATEBOT BATTLE_ID name battlestatus teamcolor
1005 }
1006 else if ( cmd == _T("REMOVEBOT") )
1007 {
1008 id = GetIntParam( params );
1009 nick = GetWordParam( params );
1010 m_se->OnBattleRemoveBot( id, nick );
1011 //REMOVEBOT BATTLE_ID name
1012 }
1013 else if ( cmd == _T("RING") )
1014 {
1015 nick = GetWordParam( params );
1016 m_se->OnRing( nick );
1017 //RING username
1018 }
1019 else if ( cmd == _T("SERVERMSG") )
1020 {
1021 m_se->OnServerMessage( params );
1022 //SERVERMSG {message}
1023 }
1024 else if ( cmd == _T("JOINBATTLEFAILED") )
1025 {
1026 msg = GetSentenceParam( params );
1027 m_se->OnServerMessage( _T("Failed to join battle. ") + msg );
1028 //JOINBATTLEFAILED {reason}
1029 }
1030 else if ( cmd == _T("OPENBATTLEFAILED") )
1031 {
1032 msg = GetSentenceParam( params );
1033 m_se->OnServerMessage( _T("Failed to host new battle on server. ") + msg );
1034 //OPENBATTLEFAILED {reason}
1035 }
1036 else if ( cmd == _T("JOINFAILED") )
1037 {
1038 channel = GetWordParam( params );
1039 msg = GetSentenceParam( params );
1040 m_se->OnServerMessage( _T("Failed to join channel #") + channel + _T(". ") + msg );
1041 //JOINFAILED channame {reason}
1042 }
1043 else if ( cmd == _T("CHANNELMESSAGE") )
1044 {
1045 channel = GetWordParam( params );
1046 m_se->OnChannelMessage( channel, params );
1047 //CHANNELMESSAGE channame {message}
1048 }
1049 else if ( cmd == _T("ACQUIREUSERID") )
1050 {
1051 SendCmd( _T("USERID"), TowxString( m_crc.GetCRC() ) );
1052 }
1053 else if ( cmd == _T("FORCELEAVECHANNEL") )
1054 {
1055 channel = GetWordParam( params );
1056 nick = GetWordParam( params );
1057 msg = GetSentenceParam( params );
1058 m_se->OnChannelPart( channel, GetMe().GetNick(), _T("Kicked by <") + nick + _T("> ") + msg );
1059 //FORCELEAVECHANNEL channame username [{reason}]
1060 }
1061 else if ( cmd == _T("DENIED") )
1062 {
1063 if ( m_online ) return;
1064 m_last_denied = msg = GetSentenceParam( params );
1065 m_se->OnServerMessage( msg );
1066 Disconnect();
1067 //Command: "DENIED" params: "Already logged in".
1068 }
1069 else if ( cmd == _T("HOSTPORT") )
1070 {
1071 unsigned int tmp_port = (unsigned int)GetIntParam( params );
1072 m_se->OnHostExternalUdpPort( tmp_port );
1073 //HOSTPORT port
1074 }
1075 else if ( cmd == _T("UDPSOURCEPORT") )
1076 {
1077 unsigned int tmp_port = (unsigned int)GetIntParam( params );
1078 m_se->OnMyExternalUdpSourcePort( tmp_port );
1079 if (m_do_finalize_join_battle)FinalizeJoinBattle();
1080 //UDPSOURCEPORT port
1081 }
1082 else if (cmd == _T("CLIENTIPPORT"))
1083 {
1084 // clientipport username ip port
1085 nick=GetWordParam( params );
1086 wxString ip=GetWordParam(params);
1087 unsigned int u_port=(unsigned int)GetIntParam( params );
1088 m_se->OnClientIPPort(nick, ip, u_port);
1089 }
1090 else if ( cmd == _T("SETSCRIPTTAGS") )
1091 {
1092 wxString command;
1093 while ( (command = GetSentenceParam( params )) != wxEmptyString )
1094 {
1095 wxString key = command.BeforeFirst( '=' ).Lower();
1096 wxString value = command.AfterFirst( '=' );
1097 m_se->OnSetBattleInfo( m_battle_id, key, value );
1098 }
1099 m_se->OnBattleInfoUpdated( m_battle_id );
1100 // !! Command: "SETSCRIPTTAGS" params: "game/startpostype=0 game/maxunits=1000 game/limitdgun=0 game/startmetal=1000 game/gamemode=0 game/ghostedbuildings=-1 game/startenergy=1000 game/diminishingmms=0"
1101 }
1102 else if ( cmd == _T("REMOVESCRIPTTAGS"))
1103 {
1104 wxString key;
1105 while ( (key = GetWordParam(params)) != wxEmptyString )
1106 {
1107 m_se->OnUnsetBattleInfo( m_battle_id, key);
1108 }
1109 m_se->OnBattleInfoUpdated(m_battle_id);
1110 }
1111 else if ( cmd == _T("SCRIPTSTART") )
1112 {
1113 m_se->OnScriptStart( m_battle_id );
1114 // !! Command: "SCRIPTSTART" params: ""
1115 }
1116 else if ( cmd == _T("SCRIPTEND") )
1117 {
1118 m_se->OnScriptEnd( m_battle_id );
1119 // !! Command: "SCRIPTEND" params: ""
1120 }
1121 else if ( cmd == _T("SCRIPT") )
1122 {
1123 m_se->OnScriptLine( m_battle_id, params );
1124 // !! Command: "SCRIPT" params: "[game]"
1125 }
1126 else if ( cmd == _T("FORCEQUITBATTLE"))
1127 {
1128 m_relay_host_bot = wxEmptyString;
1129 m_se->OnKickedFromBattle();
1130 }
1131 else if ( cmd == _T("BROADCAST"))
1132 {
1133 m_se->OnServerBroadcast( params );
1134 }
1135 else if ( cmd == _T("SERVERMSGBOX"))
1136 {
1137 m_se->OnServerMessageBox( params );
1138 }
1139 else if ( cmd == _T("REDIRECT") )
1140 {
1141 if ( m_online ) return;
1142 wxString address = GetWordParam( params );
1143 unsigned int u_port = GetIntParam( params );
1144 if ( address.IsEmpty() ) return;
1145 if ( u_port == 0 ) u_port = DEFSETT_DEFAULT_SERVER_PORT;
1146 m_redirecting = true;
1147 m_se->OnRedirect( address, u_port , m_user, m_pass );
1148 }
1149 else if ( cmd == _T("MUTELISTBEGIN") )
1150 {
1151 m_current_chan_name_mutelist = GetWordParam( params );
1152 m_se->OnMutelistBegin( m_current_chan_name_mutelist );
1153
1154 }
1155 else if ( cmd == _T("MUTELIST") )
1156 {
1157 wxString mutee = GetWordParam( params );
1158 wxString description = GetSentenceParam( params );
1159 m_se->OnMutelistItem( m_current_chan_name_mutelist, mutee, description );
1160 }
1161 else if ( cmd == _T("MUTELISTEND") )
1162 {
1163 m_se->OnMutelistEnd( m_current_chan_name_mutelist );
1164 m_current_chan_name_mutelist = wxEmptyString;
1165 }
1166 else if ( cmd == _T("FORCEJOINBATTLE") )
1167 {
1168 const int battleID = GetIntParam( params );
1169 const wxString scriptpw = GetWordParam( params );
1170 m_se->OnForceJoinBattle( battleID, scriptpw );
1171 }
1172 else
1173 {
1174 wxLogMessage( _T("??? Cmd: %s params: %s"), cmd.c_str(), params.c_str() );
1175 m_se->OnUnknownCommand( cmd, params );
1176 }
1177 }
1178
1179
RelayCmd(const wxString & command,const wxString & param)1180 void TASServer::RelayCmd( const wxString& command, const wxString& param )
1181 {
1182 if ( m_relay_host_bot.IsEmpty() )
1183 {
1184 wxLogWarning( _T("Trying to send relayed commands but no relay bot is set!") );
1185 return;
1186 }
1187
1188 wxString msg = _T("!"); // prefix comma,nds with !
1189 if ( param.IsEmpty() ) msg << command.Lower();
1190 else msg << command.Lower() << _T(" ") << param;
1191 SayPrivate( m_relay_host_bot, msg );
1192 }
1193
1194
SendCmd(const wxString & command,const wxString & param)1195 void TASServer::SendCmd( const wxString& command, const wxString& param )
1196 {
1197 wxString cmd, msg;
1198 if ( m_id_transmission )
1199 {
1200 m_last_id++;
1201 msg = msg + _T("#") + TowxString( m_last_id ) + _T(" ");
1202 }
1203 if ( m_token_transmission )
1204 {
1205 cmd = EncodeTokenMessage( command );
1206 }
1207 else cmd = command;
1208 if ( param.IsEmpty() ) msg = msg + cmd + _T("\n");
1209 else msg = msg + cmd + _T(" ") + param + _T("\n");
1210 bool send_success = m_sock->Send( msg );
1211 if ( command != _T("PING") )
1212 {
1213 if ( send_success )
1214 wxLogMessage( _T("sent: %s"), msg.c_str() );
1215 else
1216 wxLogMessage( _T("sending: %s failed"), msg.c_str() );
1217 }
1218 }
1219
SetRelayIngamePassword(const User & user)1220 void TASServer::SetRelayIngamePassword( const User& user )
1221 {
1222 Battle* battle = GetCurrentBattle();
1223 if (battle)
1224 {
1225 if ( !battle->GetInGame() ) return;
1226 }
1227 RelayCmd( _T("SETINGAMEPASSWORD"), user.GetNick() + _T(" ") + user.BattleStatus().scriptPassword );
1228 }
1229
Ping()1230 void TASServer::Ping()
1231 {
1232 SendCmd( _T("PING") );
1233 TASPingListItem pli;
1234 pli.id = m_last_id;
1235 pli.t = wxGetLocalTimeMillis();
1236 m_pinglist.push_back ( pli );
1237 }
1238
HandlePong(int replyid)1239 void TASServer::HandlePong( int replyid )
1240 {
1241 if (m_pinglist.empty()) //safety, shouldn't happen
1242 return;
1243
1244 // server connection is tcp, we assume packets are received in order
1245 TASPingListItem pli = m_pinglist.back();
1246 m_pinglist.pop_back();
1247 if (pli.id == replyid ) {
1248 m_se->OnPong( (wxGetLocalTimeMillis() - pli.t) );
1249 }
1250 }
1251
1252
JoinChannel(const wxString & channel,const wxString & key)1253 void TASServer::JoinChannel( const wxString& channel, const wxString& key )
1254 {
1255 //JOIN channame [key]
1256 wxLogDebugFunc( channel );
1257
1258 m_channel_pw[channel] = key;
1259 m_id_transmission = false; // workaround a retarded server bug
1260 SendCmd ( _T("JOIN"), channel + _T(" ") + key );
1261 m_id_transmission = true;
1262 }
1263
1264
PartChannel(const wxString & channel)1265 void TASServer::PartChannel( const wxString& channel )
1266 {
1267 //LEAVE channame
1268 wxLogDebugFunc( channel );
1269
1270 SendCmd( _T("LEAVE"), channel );
1271
1272 }
1273
1274
DoActionChannel(const wxString & channel,const wxString & msg)1275 void TASServer::DoActionChannel( const wxString& channel, const wxString& msg )
1276 {
1277 //SAYEX channame {message}
1278 wxLogDebugFunc( wxEmptyString );
1279
1280 SendCmd( _T("SAYEX"), channel + _T(" ") + msg );
1281 }
1282
1283
SayChannel(const wxString & channel,const wxString & msg)1284 void TASServer::SayChannel( const wxString& channel, const wxString& msg )
1285 {
1286 //SAY channame {message}
1287 wxLogDebugFunc( wxEmptyString );
1288
1289 SendCmd( _T("SAY"), channel + _T(" ") + msg );
1290 }
1291
1292
SayPrivate(const wxString & nick,const wxString & msg)1293 void TASServer::SayPrivate( const wxString& nick, const wxString& msg )
1294 {
1295 //SAYPRIVATE username {message}
1296 wxLogDebugFunc( wxEmptyString );
1297
1298 SendCmd( _T("SAYPRIVATE"), nick + _T(" ") + msg );
1299 }
1300
1301
DoActionPrivate(const wxString & nick,const wxString & msg)1302 void TASServer::DoActionPrivate( const wxString& nick, const wxString& msg )
1303 {
1304 wxLogDebugFunc( wxEmptyString );
1305
1306 SendCmd( _T("SAYPRIVATEEX"), nick + _T(" ") + msg );
1307 }
1308
1309
SayBattle(int,const wxString & msg)1310 void TASServer::SayBattle( int /*unused*/, const wxString& msg )
1311 {
1312 wxLogDebugFunc( wxEmptyString );
1313
1314 SendCmd( _T("SAYBATTLE"), msg );
1315 }
1316
1317
DoActionBattle(int,const wxString & msg)1318 void TASServer::DoActionBattle( int /*unused*/, const wxString& msg )
1319 {
1320 wxLogDebugFunc( wxEmptyString );
1321
1322 SendCmd( _T("SAYBATTLEEX"), msg );
1323 }
1324
1325
Ring(const wxString & nick)1326 void TASServer::Ring( const wxString& nick )
1327 {
1328 wxLogDebugFunc( wxEmptyString );
1329 try
1330 {
1331 ASSERT_EXCEPTION( m_battle_id != -1, _T("invalid m_battle_id value") );
1332 ASSERT_EXCEPTION( BattleExists(m_battle_id), _T("battle doesn't exists") );
1333
1334 Battle& battle = GetBattle( m_battle_id );
1335 ASSERT_EXCEPTION( battle.IsFounderMe(), _T("I'm not founder") );
1336
1337 if ( battle.IsProxy() )
1338 {
1339 RelayCmd( _T("RING"), nick );
1340 }
1341 else
1342 {
1343 SendCmd( _T("RING"), nick );
1344 }
1345
1346 }
1347 catch (...)
1348 {
1349 SendCmd( _T("RING"), nick );
1350 }
1351 }
1352
1353
1354
1355
ModeratorSetChannelTopic(const wxString & channel,const wxString & topic)1356 void TASServer::ModeratorSetChannelTopic( const wxString& channel, const wxString& topic )
1357 {
1358 wxString msgcopy = topic;
1359 msgcopy.Replace( _T("\n"), _T("\\n") );
1360 SendCmd( _T("CHANNELTOPIC"), channel + _T(" ") + msgcopy );
1361 }
1362
1363
ModeratorSetChannelKey(const wxString & channel,const wxString & key)1364 void TASServer::ModeratorSetChannelKey( const wxString& channel, const wxString& key)
1365 {
1366 SendCmd( _T("SETCHANNELKEY"), channel + _T(" ") + key );
1367 }
1368
1369
ModeratorMute(const wxString & channel,const wxString & nick,int duration,bool byip)1370 void TASServer::ModeratorMute( const wxString& channel, const wxString& nick, int duration, bool byip )
1371 {
1372 SendCmd( _T("MUTE"), channel + _T(" ") + nick + _T(" ") + wxString::Format( _T("%d"), duration) + (byip?_T(" ip"):wxEmptyString ) );
1373 }
1374
1375
ModeratorUnmute(const wxString & channel,const wxString & nick)1376 void TASServer::ModeratorUnmute( const wxString& channel, const wxString& nick )
1377 {
1378 SendCmd( _T("UNMUTE"), channel + _T(" ") + nick );
1379 }
1380
1381
ModeratorKick(const wxString & channel,const wxString & reason)1382 void TASServer::ModeratorKick( const wxString& channel, const wxString& reason )
1383 {
1384 SendCmd( _T("KICKUSER"), channel + _T(" ") + reason );
1385 }
1386
1387
ModeratorBan(const wxString &,bool)1388 void TASServer::ModeratorBan( const wxString& /*unused*/, bool /*unused*/ )
1389 {
1390 // FIXME TASServer::ModeratorBan not yet implemented
1391 }
1392
1393
ModeratorUnban(const wxString &)1394 void TASServer::ModeratorUnban( const wxString& /*unused*/ )
1395 {
1396 // FIXME TASServer::ModeratorUnban not yet implemented
1397 }
1398
1399
ModeratorGetIP(const wxString & nick)1400 void TASServer::ModeratorGetIP( const wxString& nick )
1401 {
1402 SendCmd( _T("GETIP"), nick );
1403 }
1404
1405
ModeratorGetLastLogin(const wxString & nick)1406 void TASServer::ModeratorGetLastLogin( const wxString& nick )
1407 {
1408 SendCmd( _T("GETLASTLOGINTIME"), nick );
1409 }
1410
1411
ModeratorGetLastIP(const wxString & nick)1412 void TASServer::ModeratorGetLastIP( const wxString& nick )
1413 {
1414 SendCmd( _T("GETLASTIP"), nick );
1415 }
1416
1417
ModeratorFindByIP(const wxString & ipadress)1418 void TASServer::ModeratorFindByIP( const wxString& ipadress )
1419 {
1420 SendCmd( _T("FINDIP"), ipadress );
1421 }
1422
1423
AdminGetAccountAccess(const wxString &)1424 void TASServer::AdminGetAccountAccess( const wxString& /*unused*/ )
1425 {
1426 // FIXME TASServer::AdminGetAccountAccess not yet implemented
1427 }
1428
1429
AdminChangeAccountAccess(const wxString &,const wxString &)1430 void TASServer::AdminChangeAccountAccess( const wxString& /*unused*/, const wxString& /*unused*/ )
1431 {
1432 // FIXME TASServer::AdminChangeAccountAccess not yet implemented
1433 }
1434
1435
AdminSetBotMode(const wxString & nick,bool isbot)1436 void TASServer::AdminSetBotMode( const wxString& nick, bool isbot )
1437 {
1438 SendCmd( _T("SETBOTMODE"), nick + _T(" ") + (isbot?_T("1"):_T("0")) );
1439 }
1440
1441
1442
1443
1444
HostBattle(BattleOptions bo,const wxString & password)1445 void TASServer::HostBattle( BattleOptions bo, const wxString& password )
1446 {
1447 wxLogDebugFunc( wxEmptyString );
1448
1449 // to see ip addresses of users as they join (in the log), pretend you're hosting with NAT.
1450 int nat_type=bo.nattype;
1451 /*
1452 if(nat_type==0 && sett().GetShowIPAddresses()){
1453 nat_type=1;
1454 }*/
1455 wxLogMessage(_T("hosting with nat type %d"),nat_type);
1456
1457 wxString cmd = wxString::Format( _T("0 %d "), nat_type );
1458 cmd += (password.IsEmpty())?_T("*"):password;
1459 cmd += wxString::Format( _T(" %d %d "), bo.port, bo.maxplayers );
1460 cmd += MakeHashSigned( bo.modhash );
1461 cmd += wxString::Format( _T(" %d "), bo.rankneeded );
1462 cmd += MakeHashSigned( bo.maphash ) + _T(" ");
1463 if (!bo.userelayhost) { //FIXME: relay host hasn't multiversion support yet, see https://github.com/springlobby/springlobby/issues/98
1464 cmd += bo.engineName + _T("\t");
1465 cmd += bo.engineVersion + _T("\t");
1466 }
1467 cmd += bo.mapname + _T("\t");
1468 cmd += bo.description + _T("\t");
1469 cmd += bo.modname;
1470
1471 m_delayed_open_command = wxEmptyString;
1472 if ( !bo.userelayhost )
1473 {
1474 SendCmd( _T("OPENBATTLE"), cmd );
1475 }
1476 else
1477 {
1478 if ( bo.relayhost.IsEmpty() )
1479 {
1480 wxArrayString relaylist = GetRelayHostList();
1481 unsigned int numbots = relaylist.GetCount();
1482 if ( numbots > 0 )
1483 {
1484 srand ( time(NULL) );
1485 unsigned int choice = rand() % numbots;
1486 m_relay_host_manager = relaylist[choice];
1487 m_delayed_open_command = cmd;
1488 SayPrivate( m_relay_host_manager, _T("!spawn") );
1489 }
1490 }
1491 else
1492 {
1493 m_relay_host_manager = bo.relayhost;
1494 m_delayed_open_command = cmd;
1495 SayPrivate(bo.relayhost,_T("!spawn"));
1496 }
1497 }
1498
1499 if (bo.nattype>0)UdpPingTheServer(m_user);
1500
1501 // OPENBATTLE type natType password port maphash {map} {title} {modname}
1502 }
1503
1504
JoinBattle(const int & battleid,const wxString & password)1505 void TASServer::JoinBattle( const int& battleid, const wxString& password )
1506 {
1507 //JOINBATTLE BATTLE_ID [parameter]
1508 wxLogDebugFunc( wxEmptyString );
1509
1510 m_finalize_join_battle_pw=password;
1511 m_finalize_join_battle_id=battleid;
1512
1513 if (BattleExists(battleid))
1514 {
1515 Battle *battle=&GetBattle(battleid);
1516
1517 if (battle)
1518 {
1519 if ( ( battle->GetNatType() == NAT_Hole_punching ) || ( battle->GetNatType() == NAT_Fixed_source_ports ) )
1520 {
1521 m_udp_private_port=sett().GetClientPort();
1522
1523 m_last_udp_ping = time(0);
1524 // its important to set time now, to prevent Update()
1525 // from calling FinalizeJoinBattle() on timeout.
1526 // m_do_finalize_join_battle must be set to true after setting time, not before.
1527 m_do_finalize_join_battle=true;
1528 for (int n=0;n<5;++n) // do 5 udp pings with tiny interval
1529 {
1530 UdpPingTheServer( m_user );
1531 // sleep(0);// sleep until end of timeslice.
1532 }
1533 m_last_udp_ping = time(0);// set time again
1534 }
1535 else
1536 {
1537 // if not using nat, finalize now.
1538 m_do_finalize_join_battle=true;
1539 FinalizeJoinBattle();
1540 }
1541 }
1542 else
1543 {
1544 wxLogMessage( _T("battle doesnt exist (null)") );
1545 }
1546 }
1547 else
1548 {
1549 wxLogMessage( _T("battle doesnt exist") );
1550 }
1551 //SendCmd( _T("JOINBATTLE"), wxString::Format( _T("%d"), battleid ) + _T(" ") + password );
1552 }
1553
1554
FinalizeJoinBattle()1555 void TASServer::FinalizeJoinBattle()
1556 {
1557 if (m_do_finalize_join_battle)
1558 {
1559 // save scriptPassword so user can rejoin if SL crashes or
1560 // loosed connection
1561 wxString scriptPassword;
1562 if (sett().GetLastBattleId() == m_finalize_join_battle_id) {
1563 scriptPassword = sett().GetLastScriptPassword();
1564 } else {
1565 srand ( time(NULL) );
1566 scriptPassword = wxString::Format(_T("%04x%04x"), rand()&0xFFFF, rand()&0xFFFF);
1567 // save assword and write settings file
1568 sett().SetLastBattleId(m_finalize_join_battle_id);
1569 sett().SetLastScriptPassword(scriptPassword);
1570 sett().SaveSettings();
1571 }
1572 SendCmd( _T("JOINBATTLE"), wxString::Format( _T("%d %s %s"), m_finalize_join_battle_id, m_finalize_join_battle_pw.c_str(), scriptPassword.c_str() ) );
1573 m_do_finalize_join_battle=false;
1574 }
1575 }
1576
1577
LeaveBattle(const int &)1578 void TASServer::LeaveBattle( const int& /*unused*/ )
1579 {
1580 //LEAVEBATTLE
1581 wxLogDebugFunc( wxEmptyString );
1582 m_relay_host_bot = wxEmptyString;
1583 SendCmd( _T("LEAVEBATTLE") );
1584 }
1585
1586
SendHostInfo(HostInfo update)1587 void TASServer::SendHostInfo( HostInfo update )
1588 {
1589 wxLogDebugFunc( wxEmptyString );
1590
1591 try
1592 {
1593 ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
1594 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1595 }
1596 catch (...)
1597 {
1598 return;
1599 }
1600
1601 Battle& battle = GetBattle( m_battle_id );
1602 try
1603 {
1604 ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
1605 }
1606 catch (...)
1607 {
1608 return;
1609 }
1610
1611 //BattleOptions bo = battle.opts();
1612
1613 if ( ( update & ( IBattle::HI_Map | IBattle::HI_Locked | IBattle::HI_Spectators ) ) > 0 )
1614 {
1615 // UPDATEBATTLEINFO SpectatorCount locked maphash {mapname}
1616 wxString cmd = wxString::Format( _T("%d %d "), battle.GetSpectators(), battle.IsLocked() );
1617 cmd += MakeHashSigned(TowxString(battle.LoadMap().hash)) + _T(" ");
1618 cmd += TowxString(battle.LoadMap().name);
1619
1620 if ( !battle.IsProxy() ) SendCmd( _T("UPDATEBATTLEINFO"), cmd );
1621 else RelayCmd( _T("UPDATEBATTLEINFO"), cmd );
1622 }
1623 if ( ( update & IBattle::HI_Send_All_opts ) > 0 )
1624 {
1625 wxString cmd;
1626 for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::OptionsWrapper::MapOption ))
1627 {
1628 const wxString newcmd = TowxString("game/mapoptions/" + it.first + "=" + it.second.second + "\t");
1629 if ( cmd.size() + newcmd.size() > 900 ) // should be 1024 add margin for relayhost name and command itself
1630 {
1631 if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1632 else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1633 cmd = wxEmptyString;
1634 }
1635 cmd << newcmd;
1636 }
1637 for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::OptionsWrapper::ModOption ))
1638 {
1639 const wxString newcmd = TowxString("game/modoptions/" + it.first + "=" + it.second.second + "\t");
1640 if ( cmd.size() + newcmd.size() > 900 )// should be 1024 add margin for relayhost name and command itself
1641 {
1642 if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1643 else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1644 cmd = wxEmptyString;
1645 }
1646 cmd << newcmd;
1647 }
1648 for (const auto& it : battle.CustomBattleOptions().getOptions( LSL::OptionsWrapper::EngineOption ))
1649 {
1650 const wxString newcmd = TowxString("game/" + it.first + "=" + it.second.second + "\t");
1651 if ( cmd.size() + newcmd.size() > 900 )// should be 1024 add margin for relayhost name and command itself
1652 {
1653 if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1654 else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1655 cmd = wxEmptyString;
1656 }
1657 cmd << newcmd;
1658 }
1659 if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1660 else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1661 }
1662
1663 if ( (update & IBattle::HI_StartRects) > 0 ) // Startrects should be updated.
1664 {
1665 unsigned int numrects = battle.GetLastRectIdx();
1666 for ( unsigned int i = 0; i <= numrects; i++ ) // Loop through all, and remove updated or deleted.
1667 {
1668 wxString cmd;
1669 BattleStartRect sr = battle.GetStartRect( i );
1670 if ( !sr.exist ) continue;
1671 if ( sr.todelete )
1672 {
1673 if ( !battle.IsProxy() ) SendCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1674 else RelayCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1675 battle.StartRectRemoved( i );
1676 }
1677 else if ( sr.toadd )
1678 {
1679 if ( !battle.IsProxy() ) SendCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1680 else RelayCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1681 battle.StartRectAdded( i );
1682 }
1683 else if ( sr.toresize )
1684 {
1685 if ( !battle.IsProxy() )
1686 {
1687 SendCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1688 SendCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1689 }
1690 else
1691 {
1692 RelayCmd( _T("REMOVESTARTRECT"), wxString::Format( _T("%d"), i ) );
1693 RelayCmd( _T("ADDSTARTRECT"), wxString::Format( _T("%d %d %d %d %d"), sr.ally, sr.left, sr.top, sr.right, sr.bottom ) );
1694 }
1695 battle.StartRectResized( i );
1696 }
1697 }
1698
1699 }
1700 if ( (update & IBattle::HI_Restrictions) > 0 )
1701 {
1702 std::map<wxString, int> units = battle.RestrictedUnits();
1703 if ( !battle.IsProxy() ) SendCmd( _T("ENABLEALLUNITS") );
1704 else RelayCmd( _T("ENABLEALLUNITS") );
1705 if ( !units.empty() )
1706 {
1707 wxString msg;
1708 wxString scriptmsg;
1709 for ( std::map<wxString, int>::const_iterator itor = units.begin(); itor != units.end(); ++itor )
1710 {
1711 msg << itor->first + _T(" ");
1712 scriptmsg << _T("game/restrict/") + itor->first + _T("=") + TowxString(itor->second) + _T('\t'); // this is a serious protocol abuse, but on the other hand, the protocol fucking suck and it's unmaintained so it will do for now
1713 }
1714 if ( !battle.IsProxy() )
1715 {
1716 SendCmd( _T("DISABLEUNITS"), msg );
1717 SendCmd( _T("SETSCRIPTTAGS"), scriptmsg );
1718 }
1719 else
1720 {
1721 RelayCmd( _T("DISABLEUNITS"), msg );
1722 RelayCmd( _T("SETSCRIPTTAGS"), scriptmsg );
1723 }
1724 }
1725 }
1726 }
1727
1728
SendHostInfo(const wxString & Tag)1729 void TASServer::SendHostInfo( const wxString& Tag )
1730 {
1731 wxLogDebugFunc( wxEmptyString );
1732
1733 try
1734 {
1735 ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
1736 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1737 }
1738 catch (...)
1739 {
1740 return;
1741 }
1742
1743 Battle& battle = GetBattle( m_battle_id );
1744
1745 try
1746 {
1747 ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
1748 }
1749 catch (...)
1750 {
1751 return;
1752 }
1753
1754 wxString cmd;
1755
1756 long type;
1757 Tag.BeforeFirst( '_' ).ToLong( &type );
1758 const wxString key = Tag.AfterFirst( '_' );
1759 if ( type == LSL::OptionsWrapper::MapOption )
1760 {
1761 cmd << _T("game/mapoptions/") << key << _T("=")
1762 << TowxString(battle.CustomBattleOptions().getSingleValue(STD_STRING(key), LSL::OptionsWrapper::MapOption ));
1763 }
1764 else if ( type == LSL::OptionsWrapper::ModOption )
1765 {
1766 cmd << _T("game/modoptions/") << key << _T("=")
1767 << TowxString(battle.CustomBattleOptions().getSingleValue(STD_STRING(key), LSL::OptionsWrapper::ModOption ));
1768 }
1769 else if ( type == LSL::OptionsWrapper::EngineOption )
1770 {
1771 cmd << _T("game/") << key << _T("=")
1772 << TowxString(battle.CustomBattleOptions().getSingleValue(STD_STRING(key), LSL::OptionsWrapper::EngineOption ));
1773 }
1774 if ( !battle.IsProxy() ) SendCmd( _T("SETSCRIPTTAGS"), cmd );
1775 else RelayCmd( _T("SETSCRIPTTAGS"), cmd );
1776 }
1777
1778
SendUserPosition(const User & user)1779 void TASServer::SendUserPosition( const User& user )
1780 {
1781 wxLogDebugFunc( wxEmptyString );
1782
1783 try
1784 {
1785 ASSERT_LOGIC( m_battle_id != -1, _T("invalid m_battle_id value") );
1786 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1787
1788 Battle& battle = GetBattle( m_battle_id );
1789 ASSERT_LOGIC( battle.IsFounderMe(), _T("I'm not founder") );
1790
1791 UserBattleStatus status = user.BattleStatus();
1792 wxString msgx = _T("game/Team") + TowxString( status.team ) + _T("/StartPosX=") + TowxString( status.pos.x );
1793 wxString msgy = _T("game/Team") + TowxString( status.team ) + _T("/StartPosY=") + TowxString( status.pos.y );
1794 wxString netmessage = msgx + _T("\t") + msgy;
1795 if ( battle.IsProxy() )
1796 {
1797 RelayCmd( _T("SETSCRIPTTAGS"), netmessage );
1798 }
1799 else
1800 {
1801 SendCmd( _T("SETSCRIPTTAGS"), netmessage );
1802 }
1803 }
1804 catch (...)
1805 {
1806 return;
1807 }
1808 }
1809
SendRaw(const wxString & raw)1810 void TASServer::SendRaw( const wxString& raw )
1811 {
1812 SendCmd( raw );
1813 }
1814
1815
RequestInGameTime(const wxString & nick)1816 void TASServer::RequestInGameTime( const wxString& nick )
1817 {
1818 SendCmd( _T("GETINGAMETIME"), nick );
1819 }
1820
1821
GetCurrentBattle()1822 Battle* TASServer::GetCurrentBattle()
1823 {
1824 try
1825 {
1826 ASSERT_EXCEPTION( m_battle_id != -1, _T("invalid m_battle_id value") );
1827 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1828 }
1829 catch (...)
1830 {
1831 return NULL;
1832 }
1833
1834 return &GetBattle( m_battle_id );
1835 }
1836
1837
SendMyBattleStatus(UserBattleStatus & bs)1838 void TASServer::SendMyBattleStatus( UserBattleStatus& bs )
1839 {
1840 wxLogDebugFunc( wxEmptyString );
1841
1842 UTASBattleStatus tasbs;
1843 tasbs.tasdata = ConvTasbattlestatus( bs );
1844 UTASColor tascl;
1845 tascl.color.red = bs.colour.Red();
1846 tascl.color.green = bs.colour.Green();
1847 tascl.color.blue = bs.colour.Blue();
1848 tascl.color.zero = 0;
1849 //MYBATTLESTATUS battlestatus myteamcolor
1850 SendCmd( _T("MYBATTLESTATUS"), wxString::Format( _T("%d %d"), tasbs.data, tascl.data ) );
1851 }
1852
1853
SendMyUserStatus()1854 void TASServer::SendMyUserStatus()
1855 {
1856 wxLogDebugFunc( wxEmptyString );
1857
1858 UserStatus& us = GetMe().Status();
1859
1860 UTASClientStatus taus;
1861 taus.tasdata.in_game = us.in_game;
1862 taus.tasdata.away = us.away;
1863 taus.tasdata.rank = us.rank;
1864 taus.tasdata.moderator = us.moderator;
1865 taus.tasdata.bot = us.bot;
1866
1867 SendCmd( _T("MYSTATUS"), wxString::Format( _T("%d"), taus.byte ) );
1868 }
1869
1870
StartHostedBattle()1871 void TASServer::StartHostedBattle()
1872 {
1873 wxLogDebugFunc( wxEmptyString );
1874 try
1875 {
1876 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1877 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1878 }
1879 catch (...)
1880 {
1881 return;
1882 }
1883 Battle *battle=GetCurrentBattle();
1884 if (battle)
1885 {
1886 if ( ( battle->GetNatType() == NAT_Hole_punching ) || ( battle->GetNatType() == NAT_Fixed_source_ports ) )
1887 {
1888 UdpPingTheServer(m_user);
1889 for (int i=0;i<5;++i)UdpPingAllClients();
1890 }
1891 }
1892
1893 m_se->OnStartHostedBattle( m_battle_id );
1894 }
1895
1896
ForceSide(int battleid,User & user,int side)1897 void TASServer::ForceSide( int battleid, User& user, int side )
1898 {
1899 wxLogDebugFunc( wxEmptyString );
1900 try
1901 {
1902 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1903 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1904 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
1905 }
1906 catch (...)
1907 {
1908 return;
1909 }
1910
1911 UserBattleStatus status = user.BattleStatus();
1912
1913 if ( &user == &GetMe() )
1914 {
1915 status.side = side;
1916 SendMyBattleStatus( status );
1917 return;
1918 }
1919
1920 if ( status.IsBot() )
1921 {
1922 status.side = side;
1923 UpdateBot( battleid, user, status );
1924 }
1925 }
1926
1927
ForceTeam(int battleid,User & user,int team)1928 void TASServer::ForceTeam( int battleid, User& user, int team )
1929 {
1930 wxLogDebugFunc( wxEmptyString );
1931 try
1932 {
1933 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1934 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1935 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
1936 }
1937 catch (...)
1938 {
1939 return;
1940 }
1941 UserBattleStatus status = user.BattleStatus();
1942 if ( status.IsBot() )
1943 {
1944 status.team = team;
1945 UpdateBot( battleid, user, status );
1946 return;
1947 }
1948 if ( &user == &GetMe() )
1949 {
1950 status.team = team;
1951 SendMyBattleStatus( status );
1952 return;
1953 }
1954 if ( !GetBattle(battleid).IsFounderMe() )
1955 {
1956 DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" changes to team #") + wxString::Format( _T("%d"), team + 1 ) + _T(".") );
1957 return;
1958 }
1959
1960 //FORCETEAMNO username teamno
1961 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCETEAMNO"), user.GetNick() + wxString::Format(_T(" %d"), team ) );
1962 else RelayCmd( _T("FORCETEAMNO"), user.GetNick() + wxString::Format(_T(" %d"), team ) );
1963 }
1964
1965
ForceAlly(int battleid,User & user,int ally)1966 void TASServer::ForceAlly( int battleid, User& user, int ally )
1967 {
1968 wxLogDebugFunc( wxEmptyString );
1969 try
1970 {
1971 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
1972 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
1973 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
1974 }
1975 catch (...)
1976 {
1977 return;
1978 }
1979 UserBattleStatus status = user.BattleStatus();
1980 if ( status.IsBot() )
1981 {
1982 status.ally = ally;
1983 UpdateBot( battleid, user, status );
1984 return;
1985 }
1986
1987 if ( &user == &GetMe() )
1988 {
1989 status.ally = ally;
1990 SendMyBattleStatus( status );
1991 return;
1992 }
1993
1994 if ( !GetBattle(battleid).IsFounderMe() )
1995 {
1996 DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" changes to ally #") + wxString::Format( _T("%d"), ally + 1 ) + _T(".") );
1997 return;
1998 }
1999
2000 //FORCEALLYNO username teamno
2001 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCEALLYNO"), user.GetNick() + wxString::Format( _T(" %d"), ally ) );
2002 else RelayCmd( _T("FORCEALLYNO"), user.GetNick() + wxString::Format( _T(" %d"), ally ) );
2003 }
2004
2005
ForceColour(int battleid,User & user,const wxColour & col)2006 void TASServer::ForceColour( int battleid, User& user, const wxColour& col )
2007 {
2008 wxLogDebugFunc( wxEmptyString );
2009 try
2010 {
2011 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2012 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2013 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2014 }
2015 catch (...)
2016 {
2017 return;
2018 }
2019 UserBattleStatus status = user.BattleStatus();
2020 if ( status.IsBot() )
2021 {
2022 status.colour = col;
2023 UpdateBot( battleid, user, status );
2024 return;
2025 }
2026 if ( &user == &GetMe() )
2027 {
2028 status.colour = col;
2029 SendMyBattleStatus( status );
2030 return;
2031 }
2032 if ( !GetBattle(battleid).IsFounderMe() )
2033 {
2034 DoActionBattle( battleid, _T("sugests that ") + user.GetNick() + _T(" changes colour.") );
2035 return;
2036 }
2037
2038 UTASColor tascl;
2039 tascl.color.red = col.Red();
2040 tascl.color.green = col.Green();
2041 tascl.color.blue = col.Blue();
2042 tascl.color.zero = 0;
2043 //FORCETEAMCOLOR username color
2044 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCETEAMCOLOR"), user.GetNick() + _T(" ") + wxString::Format( _T("%d"), tascl.data ) );
2045 else RelayCmd( _T("FORCETEAMCOLOR"), user.GetNick() + _T(" ") + wxString::Format( _T("%d"), tascl.data ) );
2046 }
2047
2048
ForceSpectator(int battleid,User & user,bool spectator)2049 void TASServer::ForceSpectator( int battleid, User& user, bool spectator )
2050 {
2051 wxLogDebugFunc( wxEmptyString );
2052 try
2053 {
2054 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2055 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2056 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2057 }
2058 catch (...)
2059 {
2060 return;
2061 }
2062 UserBattleStatus status = user.BattleStatus();
2063 if ( status.IsBot() )
2064 {
2065 status.spectator = spectator;
2066 UpdateBot( battleid, user, status );
2067 return;
2068 }
2069 if ( &user == &GetMe() )
2070 {
2071 status.spectator = spectator;
2072 SendMyBattleStatus( status );
2073 return;
2074 }
2075 if ( !GetBattle(battleid).IsFounderMe() )
2076 {
2077 if ( spectator ) DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" becomes a spectator.") );
2078 else DoActionBattle( battleid, _T("suggests that ") + user.GetNick() + _T(" plays.") );
2079 return;
2080 }
2081
2082 //FORCESPECTATORMODE username
2083 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("FORCESPECTATORMODE"), user.GetNick() );
2084 else RelayCmd( _T("FORCESPECTATORMODE"), user.GetNick() );
2085 }
2086
2087
BattleKickPlayer(int battleid,User & user)2088 void TASServer::BattleKickPlayer( int battleid, User& user )
2089 {
2090 wxLogDebugFunc( wxEmptyString );
2091 try
2092 {
2093 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2094 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2095 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2096 }
2097 catch (...)
2098 {
2099 return;
2100 }
2101 UserBattleStatus status = user.BattleStatus();
2102 if ( status.IsBot() )
2103 {
2104 RemoveBot( battleid, user );
2105 return;
2106 }
2107 if ( &user == &GetMe() )
2108 {
2109 LeaveBattle( battleid );
2110 return;
2111 }
2112 if ( !GetBattle(battleid).IsFounderMe() )
2113 {
2114 DoActionBattle( battleid, _T("thinks ") + user.GetNick() + _T(" should leave.") );
2115 return;
2116 }
2117
2118 //KICKFROMBATTLE username
2119 if( !GetBattle(battleid).IsProxy() )
2120 {
2121 user.BattleStatus().scriptPassword = wxString::Format(_T("%04x%04x"), rand()&0xFFFF, rand()&0xFFFF); // reset his password to something random, so he can't rejoin
2122 SetRelayIngamePassword( user );
2123 SendCmd( _T("KICKFROMBATTLE"), user.GetNick() );
2124 }
2125 else RelayCmd( _T("KICKFROMBATTLE"), user.GetNick() );
2126 }
2127
SetHandicap(int battleid,User & user,int handicap)2128 void TASServer::SetHandicap( int battleid, User& user, int handicap)
2129 {
2130 wxLogDebugFunc( wxEmptyString );
2131 try
2132 {
2133 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2134 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2135 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2136 }
2137 catch (...)
2138 {
2139 return;
2140 }
2141 UserBattleStatus status = user.BattleStatus();
2142 if ( status.IsBot() )
2143 {
2144 status.handicap = handicap;
2145 UpdateBot( battleid, user, status );
2146 return;
2147 }
2148
2149 if ( !GetBattle(battleid).IsFounderMe() )
2150 {
2151 DoActionBattle( battleid, _T("thinks ") + user.GetNick() + _T(" should get a ") + wxString::Format( _T("%d"), handicap) + _T("% resource bonus") );
2152 return;
2153 }
2154
2155 //HANDICAP username value
2156 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("HANDICAP"), user.GetNick() + wxString::Format( _T(" %d"), handicap ) );
2157 else RelayCmd( _T("HANDICAP"), user.GetNick() + wxString::Format( _T(" %d"), handicap ) );
2158 }
2159
2160
AddBot(int battleid,const wxString & nick,UserBattleStatus & status)2161 void TASServer::AddBot( int battleid, const wxString& nick, UserBattleStatus& status )
2162 {
2163 wxLogDebugFunc( wxEmptyString );
2164 try
2165 {
2166 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2167 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2168 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2169 }
2170 catch (...)
2171 {
2172 return;
2173 }
2174
2175 UTASBattleStatus tasbs;
2176 tasbs.tasdata = ConvTasbattlestatus( status );
2177 UTASColor tascl;
2178 tascl.color.red = status.colour.Red();
2179 tascl.color.green = status.colour.Green();
2180 tascl.color.blue = status.colour.Blue();
2181 tascl.color.zero = 0;
2182 //ADDBOT name battlestatus teamcolor {AIDLL}
2183 wxString msg;
2184 wxString ailib;
2185 ailib += status.aishortname;
2186 if ( LSL::usync().VersionSupports( LSL::USYNC_GetSkirmishAI ) ) ailib += _T("|") + status.aiversion;
2187 SendCmd( _T("ADDBOT"), nick + wxString::Format( _T(" %d %d "), tasbs.data, tascl.data ) + ailib );
2188 }
2189
2190
RemoveBot(int battleid,User & bot)2191 void TASServer::RemoveBot( int battleid, User& bot )
2192 {
2193 wxLogDebugFunc( wxEmptyString );
2194 try
2195 {
2196 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2197 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2198 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2199 }
2200 catch (...)
2201 {
2202 return;
2203 }
2204
2205 Battle& battle = GetBattle( battleid );
2206 ASSERT_LOGIC( &bot != 0, _T("Bot does not exist.") );
2207
2208 if ( !( battle.IsFounderMe() || ( bot.BattleStatus().owner == GetMe().GetNick() ) ) )
2209 {
2210 DoActionBattle( battleid, _T("thinks the bot ") + bot.GetNick() + _T(" should be removed.") );
2211 return;
2212 }
2213
2214 //REMOVEBOT name
2215 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("REMOVEBOT"), bot.GetNick() );
2216 else RelayCmd( _T("REMOVEBOT"), bot.GetNick() );
2217 }
2218
2219
UpdateBot(int battleid,User & bot,UserBattleStatus & status)2220 void TASServer::UpdateBot( int battleid, User& bot, UserBattleStatus& status )
2221 {
2222 wxLogDebugFunc( wxEmptyString );
2223 try
2224 {
2225 ASSERT_LOGIC( m_battle_id != -1, _T("Invalid m_battle_id") );
2226 ASSERT_LOGIC( BattleExists(m_battle_id), _T("battle doesn't exists") );
2227 ASSERT_LOGIC( battleid == m_battle_id, _T("Not current battle") );
2228 }
2229 catch (...)
2230 {
2231 return;
2232 }
2233
2234 UTASBattleStatus tasbs;
2235 tasbs.tasdata = ConvTasbattlestatus( status );
2236 UTASColor tascl;
2237 tascl.color.red = status.colour.Red();
2238 tascl.color.green = status.colour.Green();
2239 tascl.color.blue = status.colour.Blue();
2240 tascl.color.zero = 0;
2241 //UPDATEBOT name battlestatus teamcolor
2242 if( !GetBattle(battleid).IsProxy() ) SendCmd( _T("UPDATEBOT"), bot.GetNick() + wxString::Format( _T(" %d %d"), tasbs.data, tascl.data ) );
2243 else RelayCmd( _T("UPDATEBOT"), bot.GetNick() + wxString::Format( _T(" %d %d"), tasbs.data, tascl.data ) );
2244 }
2245
SendScriptToProxy(const wxString & script)2246 void TASServer::SendScriptToProxy( const wxString& script )
2247 {
2248 wxArrayString strings = wxStringTokenize( script, _T("\n") );
2249 int relaylenghtprefix = 10 + 1 + m_relay_host_bot.Len() + 2; // SAYPRIVATE + space + botname + space + exclamation mark lenght
2250 int lenght = script.size();
2251 lenght += relaylenghtprefix + 11 + 1; // CLEANSCRIPT command size
2252 lenght += strings.GetCount() * ( relaylenghtprefix + 16 + 1 ); // num lines * APPENDSCRIPTLINE + space command size ( \n is already counted in script.size)
2253 lenght += relaylenghtprefix + 9 + 1; // STARTGAME command size
2254 int time = lenght / m_sock->GetSendRateLimit(); // calculate time in seconds to upload script
2255 DoActionBattle( m_battle_id, wxString::Format(_T("is preparing to start the game, game will start in approximately %d seconds"),time));
2256 RelayCmd( _T("CLEANSCRIPT") );
2257 wxStringTokenizer tkzr( script, _T("\n") );
2258 while ( tkzr.HasMoreTokens() )
2259 {
2260 wxString line = tkzr.GetNextToken();
2261 RelayCmd( _T("APPENDSCRIPTLINE"), line );
2262 }
2263 RelayCmd( _T("STARTGAME") );
2264 }
2265
SendScriptToClients(const wxString & script)2266 void TASServer::SendScriptToClients( const wxString& script )
2267 {
2268 SendCmd( _T("SCRIPTSTART") );
2269 wxStringTokenizer tkzr( script, _T("\n") );
2270 while ( tkzr.HasMoreTokens() )
2271 {
2272 wxString line = tkzr.GetNextToken();
2273 SendCmd( _T("SCRIPT"), line );
2274 }
2275 SendCmd( _T("SCRIPTEND") );
2276 }
2277
OnConnected(Socket *)2278 void TASServer::OnConnected( Socket* /*unused*/ )
2279 {
2280 wxLogDebugFunc( wxEmptyString );
2281 //TASServer* serv = (TASServer*)sock->GetUserdata();
2282 m_last_udp_ping = time( 0 );
2283 m_connected = true;
2284 m_online = false;
2285 m_token_transmission = false;
2286 m_relay_host_manager_list.Clear();
2287 m_last_denied = wxEmptyString;
2288 m_last_id = 0;
2289 m_pinglist.clear();
2290 }
2291
2292
OnDisconnected(Socket *)2293 void TASServer::OnDisconnected( Socket* /*unused*/ )
2294 {
2295 wxLogDebugFunc( TowxString(m_connected) );
2296 bool connectionwaspresent = m_online || !m_last_denied.IsEmpty() || m_redirecting;
2297 m_last_denied = wxEmptyString;
2298 m_connected = false;
2299 m_online = false;
2300 m_redirecting = false;
2301 m_token_transmission = false;
2302 m_buffer = wxEmptyString;
2303 m_relay_host_manager_list.Clear();
2304 m_last_id = 0;
2305 m_pinglist.clear();
2306 m_users.Nullify();
2307 if (m_se != NULL) {
2308 m_se->OnDisconnected( connectionwaspresent );
2309 Server::OnDisconnected();
2310 }
2311 }
2312
2313
OnDataReceived(Socket * sock)2314 void TASServer::OnDataReceived( Socket* sock )
2315 {
2316 if ( sock == 0 ) return;
2317 m_last_net_packet = time( 0 );
2318 wxString data = sock->Receive();
2319 m_buffer << data;
2320 m_buffer.Replace( _T("\r\n"), _T("\n") );
2321 int returnpos = m_buffer.Find( _T("\n") );
2322 while ( returnpos != -1 )
2323 {
2324 wxString cmd = m_buffer.Left( returnpos );
2325 m_buffer = m_buffer.Mid( returnpos + 1 );
2326 ExecuteCommand( cmd );
2327 returnpos = m_buffer.Find( _T("\n") );
2328 }
2329 }
2330
2331
2332 //! @brief Send udp ping.
2333 //! @note used for nat travelsal.
2334
UdpPing(unsigned int src_port,const wxString & target,unsigned int target_port,const wxString & message)2335 unsigned int TASServer::UdpPing(unsigned int src_port, const wxString &target, unsigned int target_port, const wxString &message)// full parameters version, used to ping all clients when hosting.
2336 {
2337 int result=0;
2338 wxLogMessage(_T("UdpPing src_port=%d , target='%s' , target_port=%d , message='%s'"),src_port,target.c_str(),target_port, message.c_str());
2339 wxIPV4address local_addr;
2340 local_addr.AnyAddress(); // <--- THATS ESSENTIAL!
2341 local_addr.Service(src_port);
2342
2343 wxDatagramSocket udp_socket(local_addr,/* wxSOCKET_WAITALL*/wxSOCKET_NONE);
2344
2345 wxIPV4address wxaddr;
2346 wxaddr.Hostname(target);
2347 wxaddr.Service(target_port);
2348
2349 if (udp_socket.IsOk()&&!udp_socket.Error())
2350 {
2351 std::string m=STD_STRING(message);
2352 udp_socket.SendTo( wxaddr, m.c_str(), m.length() );
2353 wxIPV4address true_local_addr;
2354 if (udp_socket.GetLocal(true_local_addr))
2355 {
2356 result=true_local_addr.Service();
2357 }
2358 }
2359 else
2360 {
2361 wxLogMessage(_T("socket's IsOk() is false, no UDP ping done."));
2362 }
2363
2364 if (udp_socket.Error()) {
2365 wxLogWarning(_T("wxDatagramSocket Error=%d"),udp_socket.LastError());
2366 }
2367 return result;
2368 }
2369
UdpPingTheServer(const wxString & message)2370 void TASServer::UdpPingTheServer(const wxString &message)
2371 {
2372 unsigned int port=UdpPing(m_udp_private_port,m_addr,m_nat_helper_port,message);
2373 if (port>0)
2374 {
2375 m_udp_private_port=port;
2376 m_se->OnMyInternalUdpSourcePort( m_udp_private_port );
2377 }
2378 }
2379
2380
2381 // copypasta from spring.cpp , to get users ordered same way as in tasclient.
2382 struct UserOrder
2383 {
2384 int index;// user number for GetUser
2385 int order;// user order (we'll sort by it)
operator <UserOrder2386 bool operator<(UserOrder b) const // comparison function for sorting
2387 {
2388 return order<b.order;
2389 }
2390 };
2391
2392
UdpPingAllClients()2393 void TASServer::UdpPingAllClients()// used when hosting with nat holepunching. has some rudimentary support for fixed source ports.
2394 {
2395 Battle *battle=GetCurrentBattle();
2396 if (!battle)return;
2397 if (!battle->IsFounderMe())return;
2398 wxLogMessage(_T("UdpPingAllClients()"));
2399
2400 // I'm gonna mimic tasclient's behavior.
2401 // It of course doesnt matter in which order pings are sent,
2402 // but when doing "fixed source ports", the port must be
2403 // FIRST_UDP_SOURCEPORT + index of user excluding myself
2404 // so users must be reindexed in same way as in tasclient
2405 // to get same source ports for pings.
2406
2407
2408 // copypasta from spring.cpp
2409 std::vector<UserOrder> ordered_users;
2410
2411
2412 for ( UserList::user_map_t::size_type i = 0; i < battle->GetNumUsers(); i++ )
2413 {
2414 User &user=battle->GetUser(i);
2415 if (&user == &(battle->GetMe()))continue;// dont include myself (change in copypasta)
2416
2417 UserOrder tmp;
2418 tmp.index=i;
2419 ordered_users.push_back(tmp);
2420 }
2421 std::sort(ordered_users.begin(),ordered_users.end());
2422
2423
2424 for (int i=0;i<int(ordered_users.size());++i)
2425 {
2426 User &user=battle->GetUser(ordered_users[i].index);
2427
2428 wxString ip=user.BattleStatus().ip;
2429 unsigned int port=user.BattleStatus().udpport;
2430
2431 unsigned int src_port=m_udp_private_port;
2432 if ( battle->GetNatType() == NAT_Fixed_source_ports )
2433 {
2434 port = FIRST_UDP_SOURCEPORT + i;
2435 }
2436
2437 wxLogMessage(_T(" pinging nick=%s , ip=%s , port=%u"),user.GetNick().c_str(),ip.c_str(),port);
2438
2439 if (port!=0 && !ip.empty())
2440 {
2441 UdpPing(src_port,ip,port,_T("hai!"));
2442 }
2443 }
2444 }
2445
2446
2447 //! @brief used to check if the NAT is done properly when hosting
TestOpenPort(unsigned int port) const2448 int TASServer::TestOpenPort( unsigned int port ) const
2449 {
2450 wxIPV4address local_addr;
2451 local_addr.AnyAddress(); // <--- THATS ESSENTIAL!
2452 local_addr.Service(port);
2453
2454 wxSocketServer udp_socket(local_addr, wxSOCKET_NONE);
2455
2456 wxHTTP connect_to_server;
2457 connect_to_server.SetTimeout( 10 );
2458
2459 if ( !connect_to_server.Connect( _T("zjt3.com") ) ) return porttest_unreachable;
2460 connect_to_server.GetInputStream(wxString::Format( _T("/porttest.php?port=%u"), port));
2461
2462 if (udp_socket.IsOk())
2463 {
2464 if ( !udp_socket.WaitForAccept( 10 ) ) return porttest_timeout;
2465 }
2466 else
2467 {
2468 wxLogMessage(_T("socket's IsOk() is false, no UDP packets can be checked"));
2469 return porttest_socketNotOk;
2470 }
2471 if (udp_socket.Error())
2472 {
2473 wxLogMessage(_T("Error=%d"),udp_socket.LastError());
2474 return porttest_socketError;
2475 }
2476 return porttest_pass;
2477 }
2478
GetRelayHostList()2479 wxArrayString TASServer::GetRelayHostList()
2480 {
2481 if ( UserExists( _T("RelayHostManagerList") ) ) SayPrivate( _T("RelayHostManagerList"), _T("!lm") );
2482 wxArrayString ret;
2483 for ( unsigned int i = 0; i < m_relay_host_manager_list.GetCount(); i++ )
2484 {
2485 try
2486 {
2487 User& manager = GetUser( m_relay_host_manager_list[i] );
2488 if ( manager.Status().in_game ) continue; // skip the manager is not connected or reports it's ingame ( no slots available ), or it's away ( functionality disabled )
2489 if ( manager.Status().away ) continue;
2490 ret.Add( m_relay_host_manager_list[i] );
2491 }
2492 catch(...){}
2493 }
2494 return ret;
2495 }
2496
2497 ////////////////////////
2498 // Utility functions
2499 //////////////////////
2500
ConvTasclientstatus(TASClientstatus tas)2501 UserStatus ConvTasclientstatus( TASClientstatus tas )
2502 {
2503 UserStatus stat;
2504 stat.in_game = tas.in_game;
2505 stat.away = tas.away;
2506 stat.rank = (UserStatus::RankContainer)tas.rank;
2507 stat.moderator = tas.moderator;
2508 stat.bot = tas.bot;
2509 return stat;
2510 }
2511
ConvTasbattlestatus(TASBattleStatus tas)2512 UserBattleStatus ConvTasbattlestatus( TASBattleStatus tas )
2513 {
2514 UserBattleStatus stat;
2515 stat.ally = tas.ally;
2516 stat.handicap = tas.handicap;
2517 stat.ready = (tas.ready==1)?true:false;
2518 stat.side = tas.side;
2519 stat.spectator = (tas.player == 0)?true:false;
2520 stat.sync = tas.sync;
2521 stat.team = tas.team;
2522 return stat;
2523 }
2524
2525
ConvTasbattlestatus(UserBattleStatus bs)2526 TASBattleStatus ConvTasbattlestatus( UserBattleStatus bs)
2527 {
2528 TASBattleStatus stat;
2529 stat.ally = bs.ally;
2530 stat.handicap = bs.handicap;
2531 stat.ready = bs.ready?1:0;
2532 stat.side = bs.side;
2533 stat.player = bs.spectator?0:1;
2534 stat.sync = bs.sync;
2535 stat.team = bs.team;
2536 return stat;
2537 }
2538
2539
IntToStartType(int start)2540 IBattle::StartType IntToStartType( int start )
2541 {
2542 switch ( start )
2543 {
2544 case 0:
2545 return IBattle::ST_Fixed;
2546 case 1:
2547 return IBattle::ST_Random;
2548 case 2:
2549 return IBattle::ST_Choose;
2550 default:
2551 ASSERT_EXCEPTION( false, _T("invalid value") );
2552 };
2553 return IBattle::ST_Fixed;
2554 }
2555
2556
IntToNatType(int nat)2557 NatType IntToNatType( int nat )
2558 {
2559 switch ( nat )
2560 {
2561 case 0:
2562 return NAT_None;
2563 case 1:
2564 return NAT_Hole_punching;
2565 case 2:
2566 return NAT_Fixed_source_ports;
2567 default:
2568 ASSERT_EXCEPTION( false, _T("invalid value") );
2569 };
2570 return NAT_None;
2571 }
2572
2573
IntToGameType(int gt)2574 IBattle::GameType IntToGameType( int gt )
2575 {
2576 switch ( gt )
2577 {
2578 case 0:
2579 return IBattle::GT_ComContinue;
2580 case 1:
2581 return IBattle::GT_ComEnds;
2582 case 2:
2583 return IBattle::GT_Lineage;
2584 default:
2585 ASSERT_EXCEPTION( false, _T("invalid value") );
2586 };
2587 return IBattle::GT_ComContinue;
2588 }
2589