2010-05-01 19:10:35 +00:00
|
|
|
// Copyright (C) 2003 Dolphin Project.
|
|
|
|
|
|
|
|
// This program is free software: you can redistribute it and/or modify
|
|
|
|
// it under the terms of the GNU General Public License as published by
|
|
|
|
// the Free Software Foundation, version 2.0.
|
|
|
|
|
|
|
|
// This program is distributed in the hope that it will be useful,
|
|
|
|
// but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
|
// GNU General Public License 2.0 for more details.
|
|
|
|
|
|
|
|
// A copy of the GPL 2.0 should have been included with the program.
|
|
|
|
// If not, see http://www.gnu.org/licenses/
|
|
|
|
|
|
|
|
// Official SVN repository and contact information can be found at
|
|
|
|
// http://code.google.com/p/dolphin-emu/
|
|
|
|
|
|
|
|
#include "NetPlay.h"
|
|
|
|
#include "NetWindow.h"
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// for wiimote
|
|
|
|
#include "IPC_HLE/WII_IPC_HLE_Device_usb.h"
|
|
|
|
#include "IPC_HLE/WII_IPC_HLE_WiiMote.h"
|
|
|
|
// for gcpad
|
|
|
|
#include "HW/SI_DeviceGCController.h"
|
|
|
|
// for gctime
|
|
|
|
#include "HW/EXI_DeviceIPL.h"
|
|
|
|
// to start/stop game
|
2010-05-01 21:27:48 +00:00
|
|
|
#include "Frame.h"
|
2010-05-05 04:31:21 +00:00
|
|
|
// for OSD msgs
|
|
|
|
#include "Core.h"
|
2010-05-01 21:27:48 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
Common::CriticalSection crit_netplay_ptr;
|
|
|
|
static NetPlay* netplay_ptr = NULL;
|
2010-05-01 19:10:35 +00:00
|
|
|
extern CFrame* main_frame;
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
#define RPT_SIZE_HACK (1 << 16)
|
|
|
|
|
2010-05-01 19:10:35 +00:00
|
|
|
DEFINE_EVENT_TYPE(wxEVT_THREAD)
|
|
|
|
|
|
|
|
THREAD_RETURN NetPlayThreadFunc(void* arg)
|
|
|
|
{
|
|
|
|
((NetPlay*)arg)->Entry();
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
//CritLocker::CritLocker(Common::CriticalSection& crit)
|
|
|
|
// : m_crit(crit)
|
|
|
|
//{
|
|
|
|
// m_crit.Enter();
|
|
|
|
//}
|
|
|
|
//
|
|
|
|
//CritLocker::~CritLocker()
|
|
|
|
//{
|
|
|
|
// m_crit.Leave();
|
|
|
|
//}
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---GUI--- thread
|
|
|
|
NetPlay::NetPlay()
|
|
|
|
: m_is_running(false), m_do_loop(true)
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
m_target_buffer_size = 20;
|
|
|
|
ClearBuffers();
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
void NetPlay_Enable(NetPlay* const np)
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker crit(::crit_netplay_ptr); // probably safe without a lock
|
|
|
|
::netplay_ptr = np;
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
void NetPlay_Disable()
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
|
|
|
::netplay_ptr = NULL;
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---GUI--- thread
|
|
|
|
NetPlay::~NetPlay()
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker crit(crit_netplay_ptr);
|
|
|
|
::netplay_ptr = NULL;
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
NetPlay::Player::Player()
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
memset(pad_map, -1, sizeof(pad_map));
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---NETPLAY--- thread
|
2010-05-01 19:10:35 +00:00
|
|
|
void NetPlay::UpdateGUI()
|
|
|
|
{
|
|
|
|
if (m_dialog)
|
|
|
|
{
|
|
|
|
wxCommandEvent evt(wxEVT_THREAD, 1);
|
2010-05-02 21:12:51 +00:00
|
|
|
m_dialog->GetEventHandler()->AddPendingEvent(evt);
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---NETPLAY--- thread
|
2010-05-02 23:01:50 +00:00
|
|
|
void NetPlay::AppendChatGUI(const std::string& msg)
|
|
|
|
{
|
|
|
|
if (m_dialog)
|
|
|
|
{
|
|
|
|
m_dialog->chat_msgs.Push(msg);
|
|
|
|
// silly
|
|
|
|
UpdateGUI();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---GUI--- thread
|
2010-05-02 23:01:50 +00:00
|
|
|
std::string NetPlay::Player::ToString() const
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
|
|
|
std::ostringstream ss;
|
2010-05-02 23:01:50 +00:00
|
|
|
ss << name << '[' << (char)(pid+'0') << "] : " << revision << " |";
|
2010-05-01 19:10:35 +00:00
|
|
|
for (unsigned int i=0; i<4; ++i)
|
2010-05-02 23:01:50 +00:00
|
|
|
ss << (pad_map[i]>=0 ? (char)(pad_map[i]+'1') : '-');
|
2010-05-01 19:10:35 +00:00
|
|
|
ss << '|';
|
|
|
|
return ss.str();
|
|
|
|
}
|
|
|
|
|
|
|
|
NetPad::NetPad()
|
|
|
|
{
|
|
|
|
nHi = 0x00808080;
|
|
|
|
nLo = 0x80800000;
|
|
|
|
}
|
|
|
|
|
|
|
|
NetPad::NetPad(const SPADStatus* const pad_status)
|
|
|
|
{
|
|
|
|
nHi = (u32)((u8)pad_status->stickY);
|
|
|
|
nHi |= (u32)((u8)pad_status->stickX << 8);
|
|
|
|
nHi |= (u32)((u16)pad_status->button << 16);
|
|
|
|
nHi |= 0x00800000;
|
|
|
|
nLo = (u8)pad_status->triggerRight;
|
|
|
|
nLo |= (u32)((u8)pad_status->triggerLeft << 8);
|
|
|
|
nLo |= (u32)((u8)pad_status->substickY << 16);
|
|
|
|
nLo |= (u32)((u8)pad_status->substickX << 24);
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---NETPLAY--- thread
|
|
|
|
void NetPlay::ClearBuffers()
|
|
|
|
{
|
|
|
|
// clear pad buffers, no clear method ?
|
|
|
|
for (unsigned int i=0; i<4; ++i)
|
|
|
|
{
|
|
|
|
while (m_pad_buffer[i].size())
|
|
|
|
m_pad_buffer[i].pop();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// called from ---CPU--- thread
|
|
|
|
bool NetPlay::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, NetPad* const netvalues)
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
m_crit.players.Enter(); // lock players
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// in game mapping for this local pad
|
|
|
|
unsigned int in_game_num = m_local_player->pad_map[pad_nb];
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// does this local pad map in game?
|
|
|
|
if (in_game_num < 4)
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
|
|
|
NetPad np(pad_status);
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
m_crit.buffer.Enter(); // lock buffer
|
|
|
|
// adjust the buffer either up or down
|
|
|
|
while (m_pad_buffer[in_game_num].size() <= m_target_buffer_size)
|
|
|
|
{
|
|
|
|
// add to buffer
|
|
|
|
m_pad_buffer[in_game_num].push(np);
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// send
|
|
|
|
SendPadState(pad_nb, np);
|
|
|
|
}
|
|
|
|
m_crit.buffer.Leave();
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
2010-05-02 23:01:50 +00:00
|
|
|
|
|
|
|
m_crit.players.Leave();
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
//Common::Timer bufftimer;
|
|
|
|
//bufftimer.Start();
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-01 19:10:35 +00:00
|
|
|
// get padstate from buffer and send to game
|
2010-05-05 04:31:21 +00:00
|
|
|
m_crit.buffer.Enter(); // lock buffer
|
2010-05-01 19:10:35 +00:00
|
|
|
while (0 == m_pad_buffer[pad_nb].size())
|
|
|
|
{
|
|
|
|
m_crit.buffer.Leave();
|
|
|
|
// wait for receiving thread to push some data
|
2010-05-02 04:24:49 +00:00
|
|
|
Common::SleepCurrentThread(1);
|
2010-05-05 04:31:21 +00:00
|
|
|
if (false == m_is_running)
|
|
|
|
return false;
|
2010-05-01 19:10:35 +00:00
|
|
|
m_crit.buffer.Enter();
|
2010-05-05 04:31:21 +00:00
|
|
|
|
|
|
|
// TODO: check the time of bufftimer here,
|
|
|
|
// if it gets pretty high, ask the user if they want to disconnect
|
|
|
|
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
*netvalues = m_pad_buffer[pad_nb].front();
|
|
|
|
m_pad_buffer[pad_nb].pop();
|
|
|
|
m_crit.buffer.Leave();
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
//u64 hangtime = bufftimer.GetTimeElapsed();
|
|
|
|
//if (hangtime > 10)
|
|
|
|
//{
|
|
|
|
// std::ostringstream ss;
|
|
|
|
// ss << "Pad " << (int)pad_nb << ": Had to wait " << hangtime << "ms for pad data. (increase pad Buffer maybe)";
|
|
|
|
// Core::DisplayMessage(ss.str(), 1000);
|
|
|
|
//}
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
return true;
|
|
|
|
}
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---CPU--- thread
|
|
|
|
void NetPlay::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
|
|
|
|
{
|
|
|
|
//m_crit.players.Enter(); // lock players
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
//// in game mapping for this local wiimote
|
|
|
|
//unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
//// does this local pad map in game?
|
|
|
|
//if (in_game_num < 4)
|
|
|
|
//{
|
|
|
|
// //NetPad np(pad_status);
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// m_crit.buffer.Enter(); // lock buffer
|
|
|
|
// // adjust the buffer either up or down
|
|
|
|
// //while (m_pad_buffer[in_game_num].size() <= m_target_buffer_size)
|
|
|
|
// {
|
|
|
|
// // add to buffer
|
|
|
|
// //m_wiimote_buffer[in_game_num].push(np);
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// // send
|
|
|
|
// //SendPadState(pad_nb, np);
|
|
|
|
// }
|
|
|
|
// m_crit.buffer.Leave();
|
|
|
|
//}
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
//// get pad from pad buffer and send to game
|
|
|
|
//GetBufferedPad(pad_nb, netvalues);
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-01 19:10:35 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---CPU--- thread
|
|
|
|
void NetPlay::WiimoteUpdate(int _number)
|
2010-05-02 23:01:50 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
// temporary
|
|
|
|
if (_number)
|
|
|
|
return;
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
m_crit.buffer.Enter(); // lock buffer
|
|
|
|
++m_wiimote_update_frame;
|
|
|
|
m_crit.buffer.Leave();
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// TODO: prolly do some wiimote input here
|
2010-05-02 23:01:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---GUI--- thread
|
2010-05-02 23:01:50 +00:00
|
|
|
bool NetPlay::StartGame(const std::string &path)
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker game_lock(m_crit.game); // lock game state
|
2010-05-01 19:10:35 +00:00
|
|
|
|
|
|
|
if (m_is_running)
|
|
|
|
{
|
|
|
|
PanicAlert("Game is already running!");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-05-02 23:01:50 +00:00
|
|
|
AppendChatGUI(" -- STARTING GAME -- ");
|
|
|
|
|
2010-05-01 19:10:35 +00:00
|
|
|
m_is_running = true;
|
2010-05-05 04:31:21 +00:00
|
|
|
NetPlay_Enable(this);
|
2010-05-01 19:10:35 +00:00
|
|
|
|
|
|
|
// boot game
|
|
|
|
::main_frame->BootGame(path);
|
|
|
|
//BootManager::BootCore(path);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---GUI--- thread and ---NETPLAY--- thread (client side)
|
2010-05-02 23:01:50 +00:00
|
|
|
bool NetPlay::StopGame()
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker game_lock(m_crit.game); // lock game state
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-02 23:01:50 +00:00
|
|
|
if (false == m_is_running)
|
|
|
|
{
|
|
|
|
PanicAlert("Game isn't running!");
|
|
|
|
return false;
|
|
|
|
}
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-02 23:01:50 +00:00
|
|
|
AppendChatGUI(" -- STOPPING GAME -- ");
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-02 23:01:50 +00:00
|
|
|
m_is_running = false;
|
2010-05-05 04:31:21 +00:00
|
|
|
NetPlay_Disable();
|
2010-05-01 19:10:35 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// stop game
|
|
|
|
::main_frame->DoStop();
|
2010-05-01 19:10:35 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---CPU--- thread
|
|
|
|
u8 NetPlay::GetPadNum(u8 numPAD)
|
2010-05-02 23:01:50 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
// TODO: i don't like that this loop is running everytime there is rumble
|
|
|
|
unsigned int i = 0;
|
|
|
|
for (; i<4; ++i)
|
|
|
|
if (numPAD == m_local_player->pad_map[i])
|
|
|
|
break;
|
2010-05-02 23:01:50 +00:00
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
return i;
|
2010-05-02 23:01:50 +00:00
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// stuff hacked into dolphin
|
|
|
|
|
|
|
|
// called from ---CPU--- thread
|
2010-05-01 19:10:35 +00:00
|
|
|
// Actual Core function which is called on every frame
|
2010-05-05 04:31:21 +00:00
|
|
|
int CSIDevice_GCController::NetPlay_GetInput(u8 numPAD, SPADStatus PadStatus, u32 *PADStatus)
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
|
|
|
|
|
|
|
if (::netplay_ptr)
|
|
|
|
return netplay_ptr->GetNetPads(numPAD, &PadStatus, (NetPad*)PADStatus) ? 1 : 0;
|
2010-05-01 19:10:35 +00:00
|
|
|
else
|
|
|
|
return 2;
|
|
|
|
}
|
|
|
|
|
2010-05-05 04:31:21 +00:00
|
|
|
// called from ---CPU--- thread
|
2010-05-01 19:10:35 +00:00
|
|
|
// so all players' games get the same time
|
2010-05-05 04:31:21 +00:00
|
|
|
u32 CEXIIPL::NetPlay_GetGCTime()
|
2010-05-01 19:10:35 +00:00
|
|
|
{
|
2010-05-05 04:31:21 +00:00
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
|
|
|
|
|
|
|
if (::netplay_ptr)
|
2010-05-01 19:10:35 +00:00
|
|
|
return 1272737767; // watev
|
|
|
|
else
|
|
|
|
return 0;
|
|
|
|
}
|
2010-05-05 04:31:21 +00:00
|
|
|
|
|
|
|
// called from ---CPU--- thread
|
|
|
|
// return the local pad num that should rumble given a ingame pad num
|
|
|
|
u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
|
|
|
|
{
|
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
|
|
|
|
|
|
|
if (::netplay_ptr)
|
|
|
|
return ::netplay_ptr->GetPadNum(numPAD);
|
|
|
|
else
|
|
|
|
return numPAD;
|
|
|
|
}
|
|
|
|
|
|
|
|
// called from ---CPU--- thread
|
|
|
|
// wiimote update / used for frame counting
|
|
|
|
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
|
|
|
|
{
|
2010-06-03 18:05:08 +00:00
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
2010-05-05 04:31:21 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// called from ---CPU--- thread
|
|
|
|
//
|
|
|
|
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
|
|
|
|
{
|
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
|
|
|
|
|
|
|
if (::netplay_ptr)
|
|
|
|
return ::netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now
|
|
|
|
else
|
|
|
|
return _number;
|
|
|
|
}
|
|
|
|
|
|
|
|
// called from ---CPU--- thread
|
|
|
|
// intercept wiimote input callback
|
|
|
|
bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, const void* _pData, u32& _Size)
|
|
|
|
{
|
|
|
|
CritLocker crit(::crit_netplay_ptr);
|
|
|
|
|
|
|
|
if (::netplay_ptr)
|
|
|
|
{
|
|
|
|
if (_Size >= RPT_SIZE_HACK)
|
|
|
|
{
|
|
|
|
_Size -= RPT_SIZE_HACK;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
::netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
return false;
|
|
|
|
}
|