Made new Wiimote plugin not deinit SDL on shutdown. (Hacks, same thing old wiimote does, fixes the crash on emulation stop, refresh button still causes crash (damn SDL)) Minor new input plugin GUI changes. (left-click on rumble button opens control config dialog) Made NetPlay save/load settings to Dolphin.ini. Allow NetPlay host to adjust which/how many pads will be used in game. (more than one gamepad per Dolphin instance can be used on NetPlay) Worked on wiimote NetPlay a bit. (still nonfunctional) Improved SDL device numbering. Added some major hacks to ControllerInterface/SDL so XInput(360 controller) devices do not have their SDL interface shown in the device list on windows. (caused confusion for users)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5625 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
Jordan Woyak 2010-06-06 03:52:11 +00:00
parent 1aac546185
commit 5341bbad3a
13 changed files with 438 additions and 165 deletions

View File

@ -59,6 +59,8 @@ namespace Core
// Get core parameters kill use SConfig instead
extern SCoreStartupParameter g_CoreStartupParameter;
void Callback_WiimoteInterruptChannel(int _number, u16 _channelID, const void* _pData, u32 _Size);
void* GetWindowHandle();
#if defined HAVE_X11 && HAVE_X11
void* GetXWindow();

View File

@ -27,7 +27,7 @@
#include "HW/EXI_DeviceIPL.h"
// to start/stop game
#include "Frame.h"
// for OSD msgs
// for wiimote/ OSD messages
#include "Core.h"
Common::CriticalSection crit_netplay_ptr;
@ -44,17 +44,6 @@ THREAD_RETURN NetPlayThreadFunc(void* arg)
return 0;
}
//CritLocker::CritLocker(Common::CriticalSection& crit)
// : m_crit(crit)
//{
// m_crit.Enter();
//}
//
//CritLocker::~CritLocker()
//{
// m_crit.Leave();
//}
// called from ---GUI--- thread
NetPlay::NetPlay()
: m_is_running(false), m_do_loop(true)
@ -80,6 +69,10 @@ NetPlay::~NetPlay()
{
CritLocker crit(crit_netplay_ptr);
::netplay_ptr = NULL;
// not perfect
if (m_is_running)
StopGame();
}
NetPlay::Player::Player()
@ -145,6 +138,9 @@ void NetPlay::ClearBuffers()
{
while (m_pad_buffer[i].size())
m_pad_buffer[i].pop();
while (m_wiimote_buffer[i].size())
m_wiimote_buffer[i].pop();
m_wiimote_input[i].clear();
}
}
@ -212,46 +208,63 @@ bool NetPlay::GetNetPads(const u8 pad_nb, const SPADStatus* const pad_status, Ne
// called from ---CPU--- thread
void NetPlay::WiimoteInput(int _number, u16 _channelID, const void* _pData, u32 _Size)
{
//m_crit.players.Enter(); // lock players
//// 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
unsigned int in_game_num = m_local_player->pad_map[_number]; // just using gc pad_map for now
//// does this local pad map in game?
//if (in_game_num < 4)
//{
// //NetPad np(pad_status);
// does this local pad map in game?
if (in_game_num < 4)
{
m_crit.buffer.Enter();
m_wiimote_input[_number].resize(m_wiimote_input[_number].size() + 1);
m_wiimote_input[_number].back().assign((char*)_pData, (char*)_pData + _Size);
m_wiimote_input[_number].back().channel = _channelID;
// 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);
// // send
// //SendPadState(pad_nb, np);
// }
// m_crit.buffer.Leave();
//}
//// get pad from pad buffer and send to game
//GetBufferedPad(pad_nb, netvalues);
m_crit.buffer.Leave();
}
m_crit.players.Leave();
}
// called from ---CPU--- thread
void NetPlay::WiimoteUpdate(int _number)
{
// temporary
if (_number)
m_crit.players.Enter(); // lock players
// 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
// does this local pad map in game?
if (in_game_num < 4)
{
m_crit.buffer.Enter();
m_wiimote_buffer[in_game_num].push(m_wiimote_input[_number]);
// TODO: send it
m_wiimote_input[_number].clear();
m_crit.buffer.Leave();
}
m_crit.players.Leave();
m_crit.buffer.Enter();
if (0 == m_wiimote_buffer[_number].size())
{
//PanicAlert("PANIC");
return;
}
m_crit.buffer.Enter(); // lock buffer
++m_wiimote_update_frame;
NetWiimote& nw = m_wiimote_buffer[_number].front();
NetWiimote::const_iterator
i = nw.begin(), e = nw.end();
for ( ; i!=e; ++i)
Core::Callback_WiimoteInterruptChannel(_number, i->channel, &(*i)[0], (u32)i->size() + RPT_SIZE_HACK);
m_wiimote_buffer[_number].pop();
m_crit.buffer.Leave();
// TODO: prolly do some wiimote input here
}
// called from ---GUI--- thread
@ -274,6 +287,14 @@ bool NetPlay::StartGame(const std::string &path)
::main_frame->BootGame(path);
//BootManager::BootCore(path);
// TODO: i dont know if i like this here
ClearBuffers();
// temporary
NetWiimote nw;
for (unsigned int i = 0; i<4; ++i)
for (unsigned int f = 0; f<2; ++f)
m_wiimote_buffer[i].push(nw);
return true;
}
@ -353,20 +374,21 @@ u8 CSIDevice_GCController::NetPlay_GetPadNum(u8 numPAD)
// wiimote update / used for frame counting
void CWII_IPC_HLE_Device_usb_oh1_57e_305::NetPlay_WiimoteUpdate(int _number)
{
CritLocker crit(::crit_netplay_ptr);
//CritLocker crit(::crit_netplay_ptr);
return;
//if (::netplay_ptr)
// ::netplay_ptr->WiimoteUpdate(_number);
}
// called from ---CPU--- thread
//
int CWII_IPC_HLE_WiiMote::NetPlay_GetWiimoteNum(int _number)
{
CritLocker crit(::crit_netplay_ptr);
//CritLocker crit(::crit_netplay_ptr);
if (::netplay_ptr)
return ::netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now
else
//if (::netplay_ptr)
// return ::netplay_ptr->GetPadNum(_number); // just using gcpad mapping for now
//else
return _number;
}
@ -377,18 +399,19 @@ bool CWII_IPC_HLE_WiiMote::NetPlay_WiimoteInput(int _number, u16 _channelID, con
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);
//{
// if (_Size >= RPT_SIZE_HACK)
// {
// _Size -= RPT_SIZE_HACK;
// return false;
// }
// else
// {
// ::netplay_ptr->WiimoteInput(_number, _channelID, _pData, _Size);
// // don't use this packet
return true;
}
}
// }
//}
else
return false;
}

View File

@ -32,16 +32,13 @@ public:
u32 nLo;
};
class NetWiimote
struct Rpt : public std::vector<u8>
{
public:
NetWiimote& operator=(const NetWiimote&);
NetWiimote(const u32 _size) : size(_size), data(new u8[size]) {}
const u32 size;
u8* const data;
u16 channel;
};
typedef std::vector<Rpt> NetWiimote;
#define NETPLAY_VERSION "Dolphin NetPlay 2.2"
#ifdef _M_X64
@ -124,7 +121,7 @@ public:
void WiimoteUpdate(int _number);
bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
virtual bool ChangeGame(const std::string& game) = 0;
virtual void GetPlayerList(std::string& list) = 0;
virtual void GetPlayerList(std::string& list, std::vector<int>& pid_list) = 0;
virtual void SendChatMessage(const std::string& msg) = 0;
virtual bool StartGame(const std::string &path);
@ -161,11 +158,10 @@ protected:
std::string revision;
};
//LockingQueue<NetPad> m_pad_buffer[4];
std::queue<NetPad> m_pad_buffer[4];
std::map<FrameNum, NetWiimote> m_wiimote_buffer[4];
std::queue<NetPad> m_pad_buffer[4];
std::queue<NetWiimote> m_wiimote_buffer[4];
FrameNum m_wiimote_update_frame;
NetWiimote m_wiimote_input[4];
NetPlayDiag* m_dialog;
sf::SocketTCP m_socket;
@ -197,7 +193,7 @@ public:
NetPlayServer(const u16 port, const std::string& name, NetPlayDiag* const npd = NULL, const std::string& game = "");
~NetPlayServer();
void GetPlayerList(std::string& list);
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
// Send and receive pads values
//bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);
@ -207,6 +203,9 @@ public:
bool StartGame(const std::string &path);
bool StopGame();
bool GetPadMapping(const int pid, int map[]);
bool SetPadMapping(const int pid, const int map[]);
u64 CalculateMinimumBufferTime();
void AdjustPadBufferSize(unsigned int size);
@ -226,6 +225,7 @@ private:
unsigned int OnConnect(sf::SocketTCP& socket);
unsigned int OnDisconnect(sf::SocketTCP& socket);
unsigned int OnData(sf::Packet& packet, sf::SocketTCP& socket);
void UpdatePadMapping();
std::map<sf::SocketTCP, Client> m_players;
@ -242,7 +242,7 @@ public:
NetPlayClient(const std::string& address, const u16 port, const std::string& name, NetPlayDiag* const npd = NULL);
~NetPlayClient();
void GetPlayerList(std::string& list);
void GetPlayerList(std::string& list, std::vector<int>& pid_list);
// Send and receive pads values
//bool GetNetPads(const u8 pad_nb, const SPADStatus* const, NetPad* const netvalues);

View File

@ -19,7 +19,7 @@ NetPlayClient::NetPlayClient(const std::string& address, const u16 port, const s
is_connected = false;
// why is false successful? documentation says true is
if (0 == m_socket.Connect(port, address))
if (0 == m_socket.Connect(port, address, 5))
{
// send connect message
sf::Packet spac;
@ -193,7 +193,9 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
case NP_MSG_START_GAME :
{
m_crit.buffer.Enter(); // lock buffer
packet >> m_on_game;
m_crit.buffer.Leave();
wxCommandEvent evt(wxEVT_THREAD, NP_GUI_EVT_START_GAME);
m_dialog->GetEventHandler()->AddPendingEvent(evt);
@ -209,7 +211,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
case NP_MSG_DISABLE_GAME :
{
PanicAlert("Other client disconnected while game is running!! NetPlay is disabled. You must manually stop the game.");
PanicAlert("Other client disconnected while game is running!! NetPlay is disabled. You manually stop the game.");
CritLocker game_lock(m_crit.game); // lock game state
m_is_running = false;
NetPlay_Disable();
@ -257,7 +259,7 @@ void NetPlayClient::Entry()
default :
m_is_running = false;
NetPlay_Disable();
AppendChatGUI("< LOST CONNECION TO SERVER >");
AppendChatGUI("< LOST CONNECTION TO SERVER >");
PanicAlert("Lost connection to server!");
m_do_loop = false;
break;
@ -271,7 +273,7 @@ void NetPlayClient::Entry()
}
// called from ---GUI--- thread
void NetPlayClient::GetPlayerList(std::string &list)
void NetPlayClient::GetPlayerList(std::string& list, std::vector<int>& pid_list)
{
CritLocker player_lock(m_crit.players); // lock players
@ -281,7 +283,10 @@ void NetPlayClient::GetPlayerList(std::string &list)
i = m_players.begin(),
e = m_players.end();
for ( ; i!=e; ++i)
{
ss << i->second.ToString() << '\n';
pid_list.push_back(i->second.pid);
}
list = ss.str();
}
@ -294,9 +299,9 @@ void NetPlayClient::SendChatMessage(const std::string& msg)
spac << (MessageId)NP_MSG_CHAT_MESSAGE;
spac << msg;
m_crit.send.Enter(); // lock send
CritLocker player_lock(m_crit.players); // lock players
CritLocker send_lock(m_crit.send); // lock send
m_socket.Send(spac);
m_crit.send.Leave();
}
// called from ---CPU--- thread
@ -308,9 +313,8 @@ void NetPlayClient::SendPadState(const PadMapping local_nb, const NetPad& np)
spac << local_nb; // local pad num
spac << np.nHi << np.nLo;
m_crit.send.Enter(); // lock send
CritLocker send_lock(m_crit.send); // lock send
m_socket.Send(spac);
m_crit.send.Leave();
}
// called from ---GUI--- thread
@ -321,18 +325,15 @@ bool NetPlayClient::StartGame(const std::string &path)
if (false == NetPlay::StartGame(path))
return false;
// TODO: i dont like this here
ClearBuffers();
m_crit.buffer.Leave();
// tell server i started the game
sf::Packet spac;
spac << (MessageId)NP_MSG_START_GAME;
spac << m_on_game;
m_crit.send.Enter(); // lock send
m_crit.buffer.Leave();
CritLocker send_lock(m_crit.send); // lock send
m_socket.Send(spac);
m_crit.send.Leave();
return true;
}

View File

@ -63,7 +63,7 @@ void NetPlayServer::Entry()
spac << (MessageId)NP_MSG_PING;
spac << m_ping_key;
CritLocker player_lock(m_crit.players);
//CritLocker player_lock(m_crit.players);
CritLocker send_lock(m_crit.send);
m_ping_timer.Start();
SendToClients(spac);
@ -218,14 +218,6 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
spac << player.pid;
socket.Send(spac);
// send user their pad mapping
spac.Clear();
spac << (MessageId)NP_MSG_PAD_MAPPING;
spac << player.pid;
for (unsigned int pm = 0; pm<4; ++pm)
spac << player.pad_map[pm];
socket.Send(spac);
// send new client the selected game
spac.Clear();
spac << (MessageId)NP_MSG_CHANGE_GAME;
@ -239,13 +231,6 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
spac << (MessageId)NP_MSG_PLAYER_JOIN;
spac << i->second.pid << i->second.name << i->second.revision;
socket.Send(spac);
spac.Clear();
spac << (MessageId)NP_MSG_PAD_MAPPING;
spac << i->second.pid;
for (unsigned int pm = 0; pm<4; ++pm)
spac << i->second.pad_map[pm];
socket.Send(spac);
}
// LEAVE
@ -254,6 +239,9 @@ unsigned int NetPlayServer::OnConnect(sf::SocketTCP& socket)
// add client to the player list
m_crit.players.Enter(); // lock players
m_players[socket] = player;
m_crit.send.Enter(); // lock send
UpdatePadMapping(); // sync pad mappings with everyone
m_crit.send.Leave();
m_crit.players.Leave();
// add client to selector/ used for receiving
@ -277,9 +265,8 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket)
sf::Packet spac;
spac << (MessageId)NP_MSG_DISABLE_GAME;
// this thread doesnt need players lock
m_crit.send.Enter(); // lock send
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
}
sf::Packet spac;
@ -288,20 +275,100 @@ unsigned int NetPlayServer::OnDisconnect(sf::SocketTCP& socket)
m_selector.Remove(socket);
m_crit.players.Enter(); // lock players
CritLocker player_lock(m_crit.players); // lock players
m_players.erase(m_players.find(socket));
m_crit.players.Leave();
// alert other players of disconnect
m_crit.send.Enter(); // lock send
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
UpdateGUI();
return 0;
}
// called from ---GUI--- thread
bool NetPlayServer::GetPadMapping(const int pid, int map[])
{
CritLocker player_lock(m_crit.players); // lock players
std::map<sf::SocketTCP, Client>::const_iterator
i = m_players.begin(),
e = m_players.end();
for (; i!=e; ++i)
if (pid == i->second.pid)
break;
// player not found
if (i == e)
return false;
// get pad mapping
for (unsigned int m = 0; m<4; ++m)
map[m] = i->second.pad_map[m];
return true;
}
// called from ---GUI--- thread
bool NetPlayServer::SetPadMapping(const int pid, const int map[])
{
CritLocker game_lock(m_crit.game); // lock game
if (m_is_running)
return false;
CritLocker player_lock(m_crit.players); // lock players
std::map<sf::SocketTCP, Client>::iterator
i = m_players.begin(),
e = m_players.end();
for (; i!=e; ++i)
if (pid == i->second.pid)
break;
// player not found
if (i == e)
return false;
Client& player = i->second;
// set pad mapping
for (unsigned int m = 0; m<4; ++m)
{
player.pad_map[m] = (PadMapping)map[m];
// remove duplicate mappings
for (i = m_players.begin(); i!=e; ++i)
for (unsigned int p = 0; p<4; ++p)
if (p != m || i->second.pid != pid)
if (player.pad_map[m] == i->second.pad_map[p])
i->second.pad_map[p] = -1;
}
CritLocker send_lock(m_crit.send); // lock send
UpdatePadMapping(); // sync pad mappings with everyone
UpdateGUI();
return true;
}
// called from ---NETPLAY--- thread
void NetPlayServer::UpdatePadMapping()
{
std::map<sf::SocketTCP, Client>::const_iterator
i = m_players.begin(),
e = m_players.end();
for (; i!=e; ++i)
{
sf::Packet spac;
spac << (MessageId)NP_MSG_PAD_MAPPING;
spac << i->second.pid;
for (unsigned int pm = 0; pm<4; ++pm)
spac << i->second.pad_map[pm];
SendToClients(spac);
}
}
// called from ---GUI--- thread and ---NETPLAY--- thread
u64 NetPlayServer::CalculateMinimumBufferTime()
{
@ -312,7 +379,7 @@ u64 NetPlayServer::CalculateMinimumBufferTime()
e = m_players.end();
std::priority_queue<unsigned int> pings;
for ( ;i!=e; ++i)
pings.push(i->second.ping);
pings.push(i->second.ping/2);
unsigned int required_ms = pings.top();
// if there is more than 1 client, buffersize must be >= (2 highest ping times combined)
@ -339,11 +406,9 @@ void NetPlayServer::AdjustPadBufferSize(unsigned int size)
spac << (MessageId)NP_MSG_PAD_BUFFER;
spac << (u32)m_target_buffer_size;
m_crit.players.Enter(); // lock players
m_crit.send.Enter(); // lock send
CritLocker player_lock(m_crit.players); // lock players
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
m_crit.players.Leave();
}
// called from ---NETPLAY--- thread
@ -414,9 +479,8 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
spac << map; // in game mapping
spac << np.nHi << np.nLo;
m_crit.send.Enter(); // lock send
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac, player.pid);
m_crit.send.Leave();
}
break;
@ -452,9 +516,9 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, sf::SocketTCP& socket)
}
// called from ---GUI--- thread
void NetPlayServer::GetPlayerList(std::string &list)
void NetPlayServer::GetPlayerList(std::string& list, std::vector<int>& pid_list)
{
CritLocker player_lock(m_crit.players);
CritLocker player_lock(m_crit.players); // lock players
std::ostringstream ss;
@ -462,7 +526,10 @@ void NetPlayServer::GetPlayerList(std::string &list)
i = m_players.begin(),
e = m_players.end();
for ( ; i!=e; ++i)
{
ss << i->second.ToString() << " " << i->second.ping << "ms\n";
pid_list.push_back(i->second.pid);
}
list = ss.str();
}
@ -475,9 +542,8 @@ void NetPlayServer::SendChatMessage(const std::string& msg)
spac << (PlayerId)0; // server id always 0
spac << msg;
m_crit.send.Enter(); // lock send
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
}
// called from ---GUI--- thread
@ -492,11 +558,9 @@ bool NetPlayServer::ChangeGame(const std::string &game)
spac << (MessageId)NP_MSG_CHANGE_GAME;
spac << game;
m_crit.players.Enter(); // lock players
m_crit.send.Enter(); // lock send
CritLocker player_lock(m_crit.players); // lock players
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
m_crit.players.Leave();
return true;
}
@ -510,9 +574,8 @@ void NetPlayServer::SendPadState(const PadMapping local_nb, const NetPad& np)
spac << m_local_player->pad_map[local_nb]; // in-game pad num
spac << np.nHi << np.nLo;
m_crit.send.Enter(); // lock send
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
}
// called from ---GUI--- thread
@ -525,7 +588,6 @@ bool NetPlayServer::StartGame(const std::string &path)
// TODO: i dont like this here
m_on_game = Common::Timer::GetTimeMs();
ClearBuffers();
m_crit.buffer.Leave();
// no change, just update with clients
@ -536,11 +598,9 @@ bool NetPlayServer::StartGame(const std::string &path)
spac << (MessageId)NP_MSG_START_GAME;
spac << m_on_game;
m_crit.players.Enter(); // lock players
m_crit.send.Enter(); // lock send
CritLocker player_lock(m_crit.players); // lock players
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.send.Leave();
m_crit.players.Leave();
return true;
}
@ -556,11 +616,9 @@ bool NetPlayServer::StopGame()
sf::Packet spac;
spac << (MessageId)NP_MSG_STOP_GAME;
m_crit.players.Enter(); // lock players
m_crit.send.Enter(); // lock send
CritLocker player_lock(m_crit.players); // lock players
CritLocker send_lock(m_crit.send); // lock send
SendToClients(spac);
m_crit.players.Leave();
m_crit.send.Leave();
return true;
}

View File

@ -15,6 +15,9 @@
// Official SVN repository and contact information can be found at
// http://code.google.com/p/dolphin-emu/
#include <FileUtil.h>
#include <IniFile.h>
#include "NetPlay.h"
#include "NetWindow.h"
@ -34,13 +37,18 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
: wxFrame(parent, wxID_ANY, wxT(NETPLAY_TITLEBAR), wxDefaultPosition, wxDefaultSize)
, m_game_list(game_list)
{
//PanicAlert("ALERT: NetPlay is not 100%% functional !!!!");
IniFile inifile;
inifile.Load(std::string(File::GetUserPath(D_CONFIG_IDX)) + "Dolphin.ini");
IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
wxPanel* const panel = new wxPanel(this);
// top row
wxStaticText* const nick_lbl = new wxStaticText(panel, wxID_ANY, wxT("Nickname :"), wxDefaultPosition, wxDefaultSize);
m_nickname_text = new wxTextCtrl(panel, wxID_ANY, wxT("Player"));
std::string nickname;
netplay_section.Get("Nickname", &nickname, "Player");
m_nickname_text = new wxTextCtrl(panel, wxID_ANY, wxString::FromAscii(nickname.c_str()));
wxBoxSizer* const nick_szr = new wxBoxSizer(wxHORIZONTAL);
nick_szr->Add(nick_lbl, 0, wxCENTER);
@ -58,9 +66,17 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
// connect tab
{
wxStaticText* const ip_lbl = new wxStaticText(connect_tab, wxID_ANY, wxT("Address :"), wxDefaultPosition, wxDefaultSize);
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, wxT("localhost"));
std::string address;
netplay_section.Get("Address", &address, "localhost");
m_connect_ip_text = new wxTextCtrl(connect_tab, wxID_ANY, wxString::FromAscii(address.c_str()));
wxStaticText* const port_lbl = new wxStaticText(connect_tab, wxID_ANY, wxT("Port :"), wxDefaultPosition, wxDefaultSize);
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, wxT("2626"));
// string? w/e
std::string port;
netplay_section.Get("ConnectPort", &port, "2626");
m_connect_port_text = new wxTextCtrl(connect_tab, wxID_ANY, wxString::FromAscii(port.c_str()));
wxButton* const connect_btn = new wxButton(connect_tab, wxID_ANY, wxT("Connect"));
_connect_macro_(connect_btn, NetPlaySetupDiag::OnJoin, wxEVT_COMMAND_BUTTON_CLICKED, this);
@ -96,7 +112,11 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
// host tab
{
wxStaticText* const port_lbl = new wxStaticText(host_tab, wxID_ANY, wxT("Port :"), wxDefaultPosition, wxDefaultSize);
m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, wxT("2626"));
// string? w/e
std::string port;
netplay_section.Get("HostPort", &port, "2626");
m_host_port_text = new wxTextCtrl(host_tab, wxID_ANY, wxString::FromAscii(port.c_str()));
wxButton* const host_btn = new wxButton(host_tab, wxID_ANY, wxT("Host"));
_connect_macro_(host_btn, NetPlaySetupDiag::OnHost, wxEVT_COMMAND_BUTTON_CLICKED, this);
@ -143,6 +163,21 @@ NetPlaySetupDiag::NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl*
Show();
}
NetPlaySetupDiag::~NetPlaySetupDiag()
{
IniFile inifile;
const std::string dolphin_ini = std::string(File::GetUserPath(D_CONFIG_IDX)) + "Dolphin.ini";
inifile.Load(dolphin_ini);
IniFile::Section& netplay_section = *inifile.GetOrCreateSection("NetPlay");
netplay_section.Set("Nickname", m_nickname_text->GetValue().mb_str());
netplay_section.Set("Address", m_connect_ip_text->GetValue().mb_str());
netplay_section.Set("ConnectPort", m_connect_port_text->GetValue().mb_str());
netplay_section.Set("HostPort", m_host_port_text->GetValue().mb_str());
inifile.Save(dolphin_ini);
}
void NetPlaySetupDiag::OnHost(wxCommandEvent& event)
{
// warning removal
@ -266,8 +301,8 @@ NetPlayDiag::NetPlayDiag(wxWindow* const parent, const CGameListCtrl* const game
// player list
if (is_hosting)
{
wxButton* const player_config_btn = new wxButton(panel, wxID_ANY, wxT("Configure Pads [not implemented]"));
player_config_btn->Disable();
wxButton* const player_config_btn = new wxButton(panel, wxID_ANY, wxT("Configure Pads"));
_connect_macro_(player_config_btn, NetPlayDiag::OnConfigPads, wxEVT_COMMAND_BUTTON_CLICKED, this);
player_szr->Add(player_config_btn, 0, wxEXPAND | wxTOP, 5);
}
@ -380,8 +415,8 @@ void NetPlayDiag::OnPadBuffHelp(wxCommandEvent& event)
const u64 time = ((NetPlayServer*)::netplay_ptr)->CalculateMinimumBufferTime();
std::ostringstream ss;
ss << "< Calculated from pings: required buffer: "
<< time * (60/1000) << "(60fps) / "
<< time * (50/1000) << "(50fps) >\n";
<< time * (60.0f/1000) << "(60fps) / "
<< time * (50.0f/1000) << "(50fps) >\n";
m_chat_text->AppendText(wxString(ss.str().c_str(), *wxConvCurrent));
}
@ -412,14 +447,19 @@ void NetPlayDiag::OnThread(wxCommandEvent& event)
event.GetId();
// player list
m_playerids.clear();
std::string tmps;
::netplay_ptr->GetPlayerList(tmps);
::netplay_ptr->GetPlayerList(tmps, m_playerids);
const int selection = m_player_lbox->GetSelection();
m_player_lbox->Clear();
std::istringstream ss(tmps);
while (std::getline(ss, tmps))
m_player_lbox->Append(wxString(tmps.c_str(), *wxConvCurrent));
m_player_lbox->SetSelection(selection);
switch (event.GetId())
{
case NP_GUI_EVT_CHANGE_GAME :
@ -472,6 +512,30 @@ void NetPlayDiag::OnChangeGame(wxCommandEvent& event)
}
}
void NetPlayDiag::OnConfigPads(wxCommandEvent& event)
{
// warning removal
event.GetId();
int mapping[4];
// get selected player id
int pid = m_player_lbox->GetSelection();
if (pid < 0)
return;
pid = m_playerids.at(pid);
if (false == ((NetPlayServer*)::netplay_ptr)->GetPadMapping(pid, mapping))
return;
PadMapDiag* const pmd = new PadMapDiag(this, mapping);
pmd->ShowModal();
pmd->Destroy();
if (false == ((NetPlayServer*)::netplay_ptr)->SetPadMapping(pid, mapping))
PanicAlert("Could not set pads. The player left or the game is currently running!\n(setting pads while the game is running is not yet supported)");
}
ChangeGameDiag::ChangeGameDiag(wxWindow* const parent, const CGameListCtrl* const game_list, wxString& game_name)
: wxDialog(parent, wxID_ANY, wxT("Change Game"), wxDefaultPosition, wxDefaultSize)
, m_game_name(game_name)
@ -510,3 +574,58 @@ void ChangeGameDiag::OnPick(wxCommandEvent& event)
m_game_name = m_game_lbox->GetStringSelection();
Destroy();
}
PadMapDiag::PadMapDiag(wxWindow* const parent, int map[])
: wxDialog(parent, wxID_ANY, wxT("Configure Pads"), wxDefaultPosition, wxDefaultSize)
, m_mapping(map)
{
wxPanel* const panel = new wxPanel(this);
wxBoxSizer* const h_szr = new wxBoxSizer(wxHORIZONTAL);
h_szr->AddSpacer(20);
// labels
wxBoxSizer* const label_szr = new wxBoxSizer(wxVERTICAL);
label_szr->Add(new wxStaticText(panel,wxID_ANY, wxT("Local")), 0, wxALIGN_TOP);
label_szr->AddStretchSpacer(1);
label_szr->Add(new wxStaticText(panel,wxID_ANY, wxT("In-Game")), 0, wxALIGN_BOTTOM);
h_szr->Add(label_szr, 1, wxTOP | wxBOTTOM | wxEXPAND, 20);
// set up choices
wxString pad_names[5];
pad_names[0] = wxT("None");
for (unsigned int i=1; i<5; ++i)
pad_names[i] = wxString(wxT("Pad ")) + (wxChar)(wxT('0')+i);
for (unsigned int i=0; i<4; ++i)
{
wxChoice* const pad_cbox = m_map_cbox[i]
= new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, 5, pad_names);
pad_cbox->Select(m_mapping[i] + 1);
_connect_macro_(pad_cbox, PadMapDiag::OnAdjust, wxEVT_COMMAND_CHOICE_SELECTED, this);
wxBoxSizer* const v_szr = new wxBoxSizer(wxVERTICAL);
v_szr->Add(new wxStaticText(panel,wxID_ANY, pad_names[i + 1]), 1, wxALIGN_CENTER_HORIZONTAL);
v_szr->Add(pad_cbox, 1);
h_szr->Add(v_szr, 1, wxTOP | wxBOTTOM | wxEXPAND, 20);
}
h_szr->AddSpacer(20);
panel->SetSizerAndFit(h_szr);
wxBoxSizer* const dlg_szr = new wxBoxSizer(wxVERTICAL);
dlg_szr->Add(panel, 1, wxEXPAND);
SetSizerAndFit(dlg_szr);
}
void PadMapDiag::OnAdjust(wxCommandEvent& event)
{
(void)event;
for (unsigned int i=0; i<4; ++i)
m_mapping[i] = m_map_cbox[i]->GetSelection() - 1;
}

View File

@ -60,7 +60,7 @@ class NetPlaySetupDiag : public wxFrame
{
public:
NetPlaySetupDiag(wxWindow* const parent, const CGameListCtrl* const game_list);
~NetPlaySetupDiag();
private:
void OnJoin(wxCommandEvent& event);
void OnHost(wxCommandEvent& event);
@ -98,6 +98,7 @@ private:
void OnThread(wxCommandEvent& event);
void OnChangeGame(wxCommandEvent& event);
void OnAdjustBuffer(wxCommandEvent& event);
void OnConfigPads(wxCommandEvent& event);
wxListBox* m_player_lbox;
wxTextCtrl* m_chat_text;
@ -106,6 +107,8 @@ private:
std::string m_selected_game;
wxButton* m_game_btn;
std::vector<int> m_playerids;
const CGameListCtrl* const m_game_list;
//NetPlay* const m_netplay;
};
@ -124,5 +127,17 @@ private:
wxString& m_game_name;
};
class PadMapDiag : public wxDialog
{
public:
PadMapDiag(wxWindow* const parent, int map[]);
private:
void OnAdjust(wxCommandEvent& event);
wxChoice* m_map_cbox[4];
int* const m_mapping;
};
#endif // _NETWINDOW_H_

View File

@ -57,7 +57,7 @@ void ControllerInterface::Init()
//
// remove all devices/ call library cleanup functions
//
void ControllerInterface::DeInit()
void ControllerInterface::DeInit(const bool hacks_no_sdl_quit)
{
if ( false == m_is_init )
return;
@ -73,6 +73,13 @@ void ControllerInterface::DeInit()
(*d)->SetOutputState( *o, 0 );
// update output
(*d)->UpdateOutput();
// TODO: remove this
// major hacks to prevent gcpad/wiimote new from crashing eachother
if (hacks_no_sdl_quit)
if ((*d)->GetSource() == "SDL")
continue;
//delete device
delete *d;
}
@ -92,8 +99,9 @@ void ControllerInterface::DeInit()
ciface::OSX::DeInit();
#endif
#ifdef CIFACE_USE_SDL
// there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
SDL_Quit();
// TODO: there seems to be some sort of memory leak with SDL, quit isn't freeing everything up
if (false == hacks_no_sdl_quit)
SDL_Quit();
#endif
m_is_init = false;

View File

@ -240,7 +240,8 @@ public:
void SetHwnd( void* const hwnd );
void Init();
void DeInit();
// TODO: remove this hack param
void DeInit(const bool hacks_no_sdl_quit = false);
bool IsInit();
void UpdateReference( ControlReference* control );

View File

@ -20,15 +20,21 @@ namespace SDL
void Init( std::vector<ControllerInterface::Device*>& devices )
{
if ( SDL_Init( SDL_INIT_FLAGS ) >= 0 )
// just a struct with an int that is set to ZERO by default
struct ZeroedInt{ZeroedInt():value(0){}unsigned int value;};
// this is used to number the joysticks
// multiple joysticks with the same name shall get unique ids starting at 0
std::map<std::string, ZeroedInt> name_counts;
if (SDL_Init( SDL_INIT_FLAGS ) >= 0)
{
// joysticks
for( int i = 0; i < SDL_NumJoysticks(); ++i )
for(int i = 0; i < SDL_NumJoysticks(); ++i)
{
SDL_Joystick* dev = SDL_JoystickOpen( i );
SDL_Joystick* dev = SDL_JoystickOpen(i);
if ( dev )
{
Joystick* js = new Joystick( dev, i );
Joystick* js = new Joystick(dev, i, name_counts[SDL_JoystickName(i)].value++);
// only add if it has some inputs/outputs
if ( js->Inputs().size() || js->Outputs().size() )
devices.push_back( js );
@ -39,8 +45,32 @@ void Init( std::vector<ControllerInterface::Device*>& devices )
}
}
Joystick::Joystick( SDL_Joystick* const joystick, const unsigned int index ) : m_joystick(joystick), m_index(index)
Joystick::Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index)
: m_joystick(joystick)
, m_sdl_index(sdl_index)
, m_index(index)
{
// really bad HACKS:
// to not use SDL for an XInput device
// too many people on the forums pick the SDL device and ask:
// "why don't my 360 gamepad triggers/rumble work correctly"
#ifdef _WIN32
// checking the name is probably good (and hacky) enough
// but i'll double check with the num of buttons/axes
if (
("Controller (Xbox 360 Wireless Receiver for Windows)" == GetName())
&& (10 == SDL_JoystickNumButtons(joystick))
&& (5 == SDL_JoystickNumAxes(joystick))
&& (1 == SDL_JoystickNumHats(joystick))
&& (0 == SDL_JoystickNumBalls(joystick))
)
{
// this device won't be used
return;
}
#endif
// get buttons
for ( int i = 0; i < SDL_JoystickNumButtons( m_joystick ); ++i )
{
@ -210,7 +240,7 @@ bool Joystick::UpdateOutput()
std::string Joystick::GetName() const
{
return StripSpaces(SDL_JoystickName(m_index));
return StripSpaces(SDL_JoystickName(m_sdl_index));
}
std::string Joystick::GetSource() const

View File

@ -135,7 +135,7 @@ protected:
void SetOutputState( const ControllerInterface::Device::Output* const output, const ControlState state );
public:
Joystick( SDL_Joystick* const joystick, const unsigned int index );
Joystick(SDL_Joystick* const joystick, const int sdl_index, const unsigned int index);
~Joystick();
std::string GetName() const;
@ -144,6 +144,7 @@ public:
private:
SDL_Joystick* const m_joystick;
const int m_sdl_index;
const unsigned int m_index;
#ifdef USE_SDL_HAPTIC

View File

@ -373,6 +373,8 @@ void GamepadPage::ClearControl( wxCommandEvent& event )
btn->control_reference->device_qualifier = controller->default_device;
g_plugin->controls_crit.Enter();
if (btn->control_reference->is_input)
((ControllerInterface::InputReference*)btn->control_reference)->mode = 0;
controller->UpdateReferences( g_plugin->controller_interface );
g_plugin->controls_crit.Leave();
@ -618,22 +620,33 @@ ControlGroupBox::ControlGroupBox( ControllerEmu::ControlGroup* const group, wxWi
static_bitmap = NULL;
wxFont m_SmallFont(7, wxFONTFAMILY_DEFAULT, wxFONTSTYLE_NORMAL, wxFONTWEIGHT_NORMAL);
for ( unsigned int c = 0; c < group->controls.size(); ++c )
std::vector<ControllerEmu::ControlGroup::Control*>::iterator
ci = group->controls.begin(),
ce = group->controls.end();
for ( ; ci != ce; ++ci)
{
wxStaticText* const label = new wxStaticText( parent, -1, wxString::FromAscii( group->controls[c]->name )/*.append(wxT(" :"))*/ );
wxStaticText* const label = new wxStaticText(parent, -1, wxString::FromAscii((*ci)->name)/*.append(wxT(" :"))*/ );
ControlButton* const control_button = new ControlButton( parent, group->controls[c]->control_ref, 80 );
ControlButton* const control_button = new ControlButton(parent, (*ci)->control_ref, 80);
control_button->SetFont(m_SmallFont);
controls.push_back( control_button );
control_buttons.push_back( control_button );
controls.push_back(control_button);
control_buttons.push_back(control_button);
control_button->SetToolTip(wxT("Right-click for more options.\nMiddle-click to clear."));
if ((*ci)->control_ref->is_input)
{
control_button->SetToolTip(wxT("Left-click to detect input.\nMiddle-click to clear.\nRight-click for more options."));
_connect_macro_( control_button, GamepadPage::DetectControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink );
}
else
{
control_button->SetToolTip(wxT("Left/Right-click for more options.\nMiddle-click to clear."));
_connect_macro_( control_button, GamepadPage::ConfigControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink );
}
_connect_macro_( control_button, GamepadPage::DetectControl, wxEVT_COMMAND_BUTTON_CLICKED, eventsink );
_connect_macro_( control_button, GamepadPage::ConfigControl, wxEVT_RIGHT_UP, eventsink );
_connect_macro_( control_button, GamepadPage::ClearControl, wxEVT_MIDDLE_DOWN, eventsink );
_connect_macro_( control_button, GamepadPage::ConfigControl, wxEVT_RIGHT_UP, eventsink );
wxBoxSizer* const control_sizer = new wxBoxSizer( wxHORIZONTAL );
control_sizer->AddStretchSpacer( 1 );

View File

@ -99,7 +99,9 @@ void DeInitPlugin()
delete *i;
g_plugin.controllers.clear();
g_plugin.controller_interface.DeInit();
// true parameter to make SDL not quit in the wiimote plugin,
// the old wiimote plugin uses this hack as well, to prevent crash on stop
g_plugin.controller_interface.DeInit(true);
}
}
@ -276,7 +278,7 @@ void DllConfig(HWND _hParent)
frame->Destroy();
// /
if ( false == was_init ) // hack for showing dialog when game isnt running
if ( false == was_init )
DeInitPlugin();
#endif
}