WiimoteNew Buildfix Debug/DebugFast x86/x64
[dolphin.git] / Source / Core / DolphinWX / Src / NetFunctions.cpp
blob4faf04f677195367692fe2bcdc3c010228e5f8f4
1 // Copyright (C) 2003 Dolphin Project.
3 // This program is free software: you can redistribute it and/or modify
4 // it under the terms of the GNU General Public License as published by
5 // the Free Software Foundation, version 2.0.
7 // This program is distributed in the hope that it will be useful,
8 // but WITHOUT ANY WARRANTY; without even the implied warranty of
9 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 // GNU General Public License 2.0 for more details.
12 // A copy of the GPL 2.0 should have been included with the program.
13 // If not, see http://www.gnu.org/licenses/
15 // Official SVN repository and contact information can be found at
16 // http://code.google.com/p/dolphin-emu/
18 #include "NetSockets.h"
19 #include "NetWindow.h"
20 #include "HW/SI_DeviceGCController.h"
22 NetPlay *NetClass_ptr = NULL;
24 void NetPlay::IsGameFound(unsigned char * ptr, std::string m_selected)
26 m_critical.Enter();
28 m_selectedGame = m_selected;
30 if (m_games.find(m_selected) != std::string::npos)
31 *ptr = 0x1F;
32 else
33 *ptr = 0x1A;
35 m_critical.Leave();
38 void NetPlay::OnNetEvent(wxCommandEvent& event)
40 switch (event.GetId())
42 case HOST_FULL:
44 AppendText(_(" Server is Full !\n*You have been Disconnected.\n\n"));
45 m_isHosting = 2;
47 break;
48 case HOST_ERROR:
50 if (m_isHosting == 0)
52 AppendText(_("ERROR : Network Error !\n*You have been Disconnected.\n\n"));
53 m_isHosting = 2;
55 else
57 m_numClients--;
58 AppendText( wxString::Format(wxT("ERROR : Network Error !\n")
59 wxT("*Player : %s has been dropped from the game.\n\n"),
60 (const char *)event.GetString().mb_str()) );
63 break;
64 case HOST_DISCONNECTED:
66 // Event sent from Client's thread, it means that the thread
67 // has been killed and so we tell the GUI thread.
68 AppendText(_("*Connection to Host lost.\n*You have been Disconnected.\n\n"));
69 m_isHosting = 2;
70 m_numClients--;
72 break;
73 case HOST_PLAYERLEFT:
75 m_numClients--;
77 break;
78 case HOST_NEWPLAYER:
80 m_numClients++;
81 m_NetModel = event.GetInt();
83 break;
84 case CLIENTS_READY:
86 m_clients_ready = true;
88 // Tell clients everyone is ready...
89 if (m_ready)
90 LoadGame();
92 break;
93 case CLIENTS_NOTREADY:
95 m_clients_ready = false;
97 break;
98 case GUI_UPDATE:
99 UpdateNetWindow(false);
100 break;
101 case ADD_TEXT:
102 AppendText(event.GetString());
103 break;
104 case ADD_INFO:
105 UpdateNetWindow(true, event.GetString());
106 break;
110 void ServerSide::IsEveryoneReady()
112 int nb_ready = 0;
114 for (int i=0; i < m_numplayers ; i++)
115 if (m_client[i].ready)
116 nb_ready++;
118 if (nb_ready == m_numplayers)
119 Event->SendEvent(CLIENTS_READY);
120 else
121 Event->SendEvent(CLIENTS_NOTREADY);
124 // Actual Core function which is called on every frame
125 int CSIDevice_GCController::GetNetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
127 if (NetClass_ptr != NULL)
128 return NetClass_ptr->GetNetPads(numPAD, PadStatus, PADStatus) ? 1 : 0;
129 else
130 return 2;
133 void NetPlay::LoadGame()
135 // Two implementations, one "p2p" implementation which sends to peer
136 // and receive from peer 2 players max. and another which uses server model
137 // and always sends to the server which then send it back to all the clients
138 // -> P2P model is faster, but is limited to 2 players
139 // -> Server model is slower, but supports up to 4 players
141 if (m_isHosting == 1)
143 long ping[3] = {0};
144 unsigned char value = 0x50;
146 // Get ping
147 m_sock_server->Write(0, 0, 0, ping);
148 float fping = (ping[0]+ping[1]+ping[2])/(float)m_numClients;
150 // Tell client everyone is ready
151 for (int i=0; i < m_numClients ; i++)
152 m_sock_server->Write(i, (const char*)&value, 1);
154 // Sleep a bit to start the game at more or less the same time than the peer
155 wxMilliSleep(fping/2);
157 m_Logging->AppendText(wxString::Format(wxT("** Everyone is ready... Loading Game ! **\n")
158 wxT("** Ping to client(s) is : %f ms\n"), fping));
160 else
161 m_Logging->AppendText(_("** Everyone is ready... Loading Game ! **\n"));
163 // TODO : Throttle should be on by default, to avoid stuttering
164 //soundStream->GetMixer()->SetThrottle(true);
166 int line_p = 0;
167 int line_n = 0;
169 m_critical.Enter();
170 std::string tmp = m_games.substr(0, m_games.find(m_selectedGame));
172 for (int i=0; i < (int)tmp.size(); i++)
173 if (tmp.c_str()[i] == '\n')
174 line_n++;
176 // Enable
177 NetClass_ptr = this;
178 m_timer.Start();
179 m_data_received = false;
180 m_critical.Leave();
182 // Find corresponding game path
183 for (int i=0; i < (int)m_paths.size(); i++)
185 if (m_paths.c_str()[i] == '\n')
186 line_p++;
188 if (line_n == line_p) {
189 // Game path found, get its string
190 int str_pos = line_p > 0 ? i+1 : i;
191 int str_end = (int)m_paths.find('\n', str_pos);
192 // Boot the selected game
193 BootManager::BootCore(m_paths.substr(str_pos, str_end - str_pos));
194 break;
199 bool NetPlay::GetNetPads(u8 padnb, SPADStatus PadStatus, u32 *netValues)
201 if (m_numClients < 1)
203 m_Logging->AppendText(_("** WARNING : Ping too high (>2000ms) or connection lost ! \n** WARNING : Stopping Netplay... \n"));
204 NetClass_ptr = NULL;
205 return false;
208 // Store current pad status in netValues[]
209 netValues[0] = (u32)((u8)PadStatus.stickY);
210 netValues[0] |= (u32)((u8)PadStatus.stickX << 8);
211 netValues[0] |= (u32)((u16)PadStatus.button << 16);
212 netValues[0] |= 0x00800000;
213 netValues[1] = (u8)PadStatus.triggerRight;
214 netValues[1] |= (u32)((u8)PadStatus.triggerLeft << 8);
215 netValues[1] |= (u32)((u8)PadStatus.substickY << 16);
216 netValues[1] |= (u32)((u8)PadStatus.substickX << 24);
218 if (m_NetModel == 0) // Use 2 players Model
220 if (padnb == 0)
222 // Update the timer and increment total frame number
223 m_frame++;
225 if (m_frame == 1)
227 // We make sure everyone's pad is enabled
228 for (int i = 0; i < m_numClients+1; i++)
229 SerialInterface::ChangeDevice(SI_GC_CONTROLLER, i);
231 // Better disable unused ports
232 for (int i = m_numClients+1; i < 4; i++)
233 SerialInterface::ChangeDevice(SI_NONE, i);
236 if (m_timer.GetTimeDifference() > 1000)
237 m_timer.Update();
239 #ifdef NET_DEBUG
240 char sent[64];
241 sprintf(sent, "Sent Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
242 m_Logging->AppendText(wxString::FromAscii(sent));
243 #endif
244 unsigned char player = 0;
246 #ifdef USE_TCP
247 unsigned char init_value = 0xA1;
249 if (m_isHosting == 1) {
250 // Send pads values
251 m_sock_server->Write(0, (const char*)&init_value, 1);
252 m_sock_server->Write(0, (const char*)netValues, 8);
254 else {
255 // Send pads values
256 m_sock_client->Write((const char*)&init_value, 1);
257 m_sock_client->Write((const char*)netValues, 8);
258 player = 1;
260 #else // UDP
261 u32 padsValues[3];
263 padsValues[0] = m_frame;
264 padsValues[1] = netValues[0];
265 padsValues[2] = netValues[1];
267 if (m_isHosting == 1) {
268 // Send pads values
269 m_sock_server->WriteUDP(0, (const char*)padsValues, 12);
271 else {
272 // Send pads values
273 m_sock_client->WriteUDP((const char*)padsValues, 12);
274 player = 1;
276 #endif
278 if (!m_data_received)
280 // Save pad values
281 m_pads[player].nHi[m_loopframe] = netValues[0];
282 m_pads[player].nLow[m_loopframe] = netValues[1];
284 // Try to read from peer...
285 if (m_isHosting == 1)
286 m_data_received = m_sock_server->isNewPadData(0, false);
287 else
288 m_data_received = m_sock_client->isNewPadData(0, false);
290 if (m_data_received)
292 // Set our practical frame delay
293 m_frameDelay = m_loopframe;
294 m_loopframe = 0;
296 // First Data has been received !
297 m_Logging->AppendText(_("** Data received from Peer. Starting Sync !"));
298 m_Logging->AppendText(wxString::Format(wxT(" Frame Delay : %d **\n"), m_frameDelay));
300 else {
301 if (m_loopframe > 126)
303 m_Logging->AppendText(_("** WARNING : Ping too high (>2000ms) or connection lost ! \n** WARNING : Stopping Netplay... \n"));
304 NetClass_ptr = NULL;
307 m_loopframe++;
308 return false;
312 if (m_data_received)
314 // We have successfully received the data, now use it...
315 // If we received data, we can update our pads on each frame, here's the behaviour :
316 // we received our init number, so we should receive our pad values on each frames
317 // with a frame delay of 'm_frameDelay' frames from the peer. So here, we just wait
318 // for the pad status. note : if the peer can't keep up, sending the values
319 // (i.e : framerate is too low) we have to wait for it thus slowing down emulation
321 // Save current pad values, it will be used in 'm_frameDelay' frames :D
322 int saveslot = (m_loopframe - 1 < 0 ? m_frameDelay : m_loopframe - 1);
323 u32 recvedValues[2];
325 m_pads[player].nHi[saveslot] = netValues[0];
326 m_pads[player].nLow[saveslot] = netValues[1];
328 // Read the socket for pad values
329 if (m_isHosting == 1)
330 m_sock_server->isNewPadData(recvedValues, true);
331 else
332 m_sock_client->isNewPadData(recvedValues, true);
334 if (player == 0)
336 // Store received peer values
337 m_pads[1].nHi[m_loopframe] = recvedValues[0];
338 m_pads[1].nLow[m_loopframe] = recvedValues[1];
340 // Apply synced pad values
341 netValues[0] = m_pads[0].nHi[m_loopframe];
342 netValues[1] = m_pads[0].nLow[m_loopframe];
344 else
346 // Apply received pad values
347 netValues[0] = recvedValues[0];
348 netValues[1] = recvedValues[1];
352 #ifdef NET_DEBUG
353 char usedval[64];
354 sprintf(usedval, "Player 1 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
355 m_Logging->AppendText(wxString::FromAscii(usedval));
356 #endif
357 return true;
359 else if (padnb == 1)
361 if (m_data_received)
363 netValues[0] = m_pads[1].nHi[m_loopframe];
364 netValues[1] = m_pads[1].nLow[m_loopframe];
366 // Reset the loop to avoid reading unused values
367 if (m_loopframe == m_frameDelay)
368 m_loopframe = 0;
369 else
370 m_loopframe++;
372 else
373 return false;
374 #ifdef NET_DEBUG
375 char usedval[64];
376 sprintf(usedval, "Player 2 Values: 0x%08x : 0x%08x \n", netValues[0], netValues[1]);
377 m_Logging->AppendText(wxString::FromAscii(usedval));
378 #endif
380 return true;
383 else
385 // TODO : :D
386 return false;
389 return false;
392 void NetPlay::ChangeSelectedGame(std::string game)
394 wxCriticalSectionLocker lock(m_critical);
395 if (m_isHosting == 0)
397 m_selectedGame = game;
398 return;
401 if (game != m_selectedGame)
403 unsigned char value = 0x35;
404 int game_size = (int)game.size();
406 // Send command then Game String
407 for (int i=0; i < m_numClients ; i++)
409 m_sock_server->Write(i, (const char*)&value, 1); // 0x35 -> Change game
411 m_sock_server->Write(i, (const char*)&game_size, 4);
412 m_sock_server->Write(i, game.c_str(), game_size + 1);
415 m_selectedGame = game;
416 UpdateNetWindow(false);
417 m_Logging->AppendText(wxString::Format( wxT(" *Game has been changed to : %s \r\n "), wxString(game.c_str(), wxConvUTF8).c_str()));
418 NOTICE_LOG(NETPLAY,"Game has been changed to : %s \n",game.c_str());
422 void NetPlay::OnQuit(wxCloseEvent& WXUNUSED(event))
424 // Disable netplay
425 NetClass_ptr = NULL;
427 // Destroy the Window
428 Destroy();
430 // Then Kill the threads
431 if (m_isHosting == 0)
432 m_sock_client->Delete();
433 else if (m_isHosting == 1) {
434 m_sock_server->Delete();
439 void NetPlay::OnDisconnect(wxCommandEvent& WXUNUSED(event))
441 wxCloseEvent close;
442 OnQuit(close);
445 bool ClientSide::isNewPadData(u32 *netValues, bool current, bool isVersus)
447 #ifdef USE_TCP
448 if (current)
450 while (1)
452 m_CriticalSection.Enter();
453 if (m_data_received && isVersus)
455 netValues[0] = m_netvalues[0][0];
456 netValues[1] = m_netvalues[0][1];
457 m_data_received = false;
459 m_CriticalSection.Leave();
460 break;
462 m_CriticalSection.Leave();
464 if (TestDestroy())
465 break;
468 return true;
470 else
471 wxCriticalSectionLocker lock(m_CriticalSection);
473 return m_data_received;
474 #else
475 size_t recv_size;
477 if (current)
479 m_CriticalSection.Enter();
481 if (isVersus)
483 if (m_netvalues[0][1] != 0)
485 netValues[0] = m_netvalues[0][1];
486 netValues[1] = m_netvalues[0][2];
488 else
490 while (true)
492 u32 frame_saved = m_netvalues[0][0];
493 bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 5);
495 if (m_netvalues[0][0] < frame_saved+1)
496 continue;
497 if (m_netvalues[0][0] > frame_saved+1 || !pass)
498 PanicAlert("Network ERROR !");
500 netValues[0] = m_netvalues[0][1];
501 netValues[1] = m_netvalues[0][2];
502 break;
507 m_netvalues[0][1] = 0;
508 m_CriticalSection.Leave();
510 return true;
512 else
513 return RecvT(m_socketUDP, (char*)&m_netvalues[0], 12, recv_size, 1/1000);
515 #endif
519 bool ServerSide::isNewPadData(u32 *netValues, bool current, int client)
521 #ifdef USE_TCP
522 if (current)
524 while (1)
526 m_CriticalSection.Enter();
527 if (m_data_received)
529 netValues[0] = m_netvalues[client][0];
530 netValues[1] = m_netvalues[client][1];
531 m_data_received = false;
533 m_CriticalSection.Leave();
534 break;
536 m_CriticalSection.Leave();
538 if (TestDestroy())
539 break;
542 return true;
544 else
545 wxCriticalSectionLocker lock(m_CriticalSection);
547 return m_data_received;
548 #else
549 size_t recv_size;
551 if (current)
553 m_CriticalSection.Enter();
555 if (m_netvalues[0][1] != 0)
557 netValues[0] = m_netvalues[client][1];
558 netValues[1] = m_netvalues[client][2];
560 else
562 while (true)
564 u32 frame_saved = m_netvalues[client][0];
565 bool pass = RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 5);
567 if (m_netvalues[client][0] < frame_saved+1)
568 continue;
569 if (m_netvalues[client][0] > frame_saved+1 || !pass)
570 PanicAlert("Network ERROR !");
572 netValues[0] = m_netvalues[client][1];
573 netValues[1] = m_netvalues[client][2];
574 break;
578 m_netvalues[client][1] = 0;
579 m_CriticalSection.Leave();
581 return true;
583 else
584 return RecvT(m_socketUDP, (char*)&m_netvalues[client], 12, recv_size, 1/1000);
586 #endif