mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-14 13:27:45 -07:00
Merge pull request #7955 from Techjar/netplay-golf-mode
NetPlay golf mode
This commit is contained in:
commit
e44433c2f6
@ -55,5 +55,8 @@ const ConfigInfo<bool> NETPLAY_HOST_INPUT_AUTHORITY{{System::Main, "NetPlay", "H
|
||||
false};
|
||||
const ConfigInfo<bool> NETPLAY_SYNC_ALL_WII_SAVES{{System::Main, "NetPlay", "SyncAllWiiSaves"},
|
||||
false};
|
||||
const ConfigInfo<bool> NETPLAY_GOLF_MODE{{System::Main, "NetPlay", "GolfMode"}, false};
|
||||
const ConfigInfo<bool> NETPLAY_GOLF_MODE_OVERLAY{{System::Main, "NetPlay", "GolfModeOverlay"},
|
||||
true};
|
||||
|
||||
} // namespace Config
|
||||
|
@ -45,5 +45,7 @@ extern const ConfigInfo<bool> NETPLAY_REDUCE_POLLING_RATE;
|
||||
extern const ConfigInfo<bool> NETPLAY_STRICT_SETTINGS_SYNC;
|
||||
extern const ConfigInfo<bool> NETPLAY_HOST_INPUT_AUTHORITY;
|
||||
extern const ConfigInfo<bool> NETPLAY_SYNC_ALL_WII_SAVES;
|
||||
extern const ConfigInfo<bool> NETPLAY_GOLF_MODE;
|
||||
extern const ConfigInfo<bool> NETPLAY_GOLF_MODE_OVERLAY;
|
||||
|
||||
} // namespace Config
|
||||
|
@ -20,7 +20,7 @@
|
||||
#include "InputCommon/GCPadStatus.h"
|
||||
|
||||
// clang-format off
|
||||
constexpr std::array<const char*, 132> s_hotkey_labels{{
|
||||
constexpr std::array<const char*, 133> s_hotkey_labels{{
|
||||
_trans("Open"),
|
||||
_trans("Change Disc"),
|
||||
_trans("Eject Disc"),
|
||||
@ -32,6 +32,7 @@ constexpr std::array<const char*, 132> s_hotkey_labels{{
|
||||
_trans("Take Screenshot"),
|
||||
_trans("Exit"),
|
||||
_trans("Activate NetPlay Chat"),
|
||||
_trans("Control NetPlay Golf Mode"),
|
||||
|
||||
_trans("Volume Down"),
|
||||
_trans("Volume Up"),
|
||||
@ -275,7 +276,7 @@ struct HotkeyGroupInfo
|
||||
};
|
||||
|
||||
constexpr std::array<HotkeyGroupInfo, NUM_HOTKEY_GROUPS> s_groups_info = {
|
||||
{{_trans("General"), HK_OPEN, HK_ACTIVATE_CHAT},
|
||||
{{_trans("General"), HK_OPEN, HK_REQUEST_GOLF_CONTROL},
|
||||
{_trans("Volume"), HK_VOLUME_DOWN, HK_VOLUME_TOGGLE_MUTE},
|
||||
{_trans("Emulation Speed"), HK_DECREASE_EMULATION_SPEED, HK_TOGGLE_THROTTLE},
|
||||
{_trans("Frame Advance"), HK_FRAME_ADVANCE, HK_FRAME_ADVANCE_RESET_SPEED},
|
||||
|
@ -15,7 +15,7 @@ namespace ControllerEmu
|
||||
{
|
||||
class ControllerEmu;
|
||||
class Buttons;
|
||||
}
|
||||
} // namespace ControllerEmu
|
||||
|
||||
enum Hotkey
|
||||
{
|
||||
@ -30,6 +30,7 @@ enum Hotkey
|
||||
HK_SCREENSHOT,
|
||||
HK_EXIT,
|
||||
HK_ACTIVATE_CHAT,
|
||||
HK_REQUEST_GOLF_CONTROL,
|
||||
|
||||
HK_VOLUME_DOWN,
|
||||
HK_VOLUME_UP,
|
||||
@ -236,4 +237,4 @@ void GetStatus();
|
||||
bool IsEnabled();
|
||||
void Enable(bool enable_toggle);
|
||||
bool IsPressed(int Id, bool held);
|
||||
}
|
||||
} // namespace HotkeyManagerEmu
|
||||
|
@ -442,6 +442,30 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_PAD_HOST_DATA:
|
||||
{
|
||||
while (!packet.endOfPacket())
|
||||
{
|
||||
PadIndex map;
|
||||
packet >> map;
|
||||
|
||||
GCPadStatus pad;
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
|
||||
// Trusting server for good map value (>=0 && <4)
|
||||
// write to last status
|
||||
m_last_pad_status[map] = pad;
|
||||
|
||||
if (!m_first_pad_status_received[map])
|
||||
{
|
||||
m_first_pad_status_received[map] = true;
|
||||
m_first_pad_status_received_event.Set();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_WIIMOTE_DATA:
|
||||
{
|
||||
PadIndex map;
|
||||
@ -471,15 +495,6 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_PAD_FIRST_RECEIVED:
|
||||
{
|
||||
PadIndex map;
|
||||
packet >> map;
|
||||
packet >> m_first_pad_status_received[map];
|
||||
m_first_pad_status_received_event.Set();
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_HOST_INPUT_AUTHORITY:
|
||||
{
|
||||
packet >> m_host_input_authority;
|
||||
@ -487,6 +502,43 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_GOLF_SWITCH:
|
||||
{
|
||||
PlayerId pid;
|
||||
packet >> pid;
|
||||
|
||||
const PlayerId previous_golfer = m_current_golfer;
|
||||
m_current_golfer = pid;
|
||||
m_dialog->OnGolferChanged(m_local_player->pid == pid, pid != 0 ? m_players[pid].name : "");
|
||||
|
||||
if (m_local_player->pid == previous_golfer)
|
||||
{
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_GOLF_RELEASE);
|
||||
Send(spac);
|
||||
}
|
||||
else if (m_local_player->pid == pid)
|
||||
{
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_GOLF_ACQUIRE);
|
||||
Send(spac);
|
||||
|
||||
// Pads are already calibrated so we can just ignore this
|
||||
m_first_pad_status_received.fill(true);
|
||||
|
||||
m_wait_on_input = false;
|
||||
m_wait_on_input_event.Set();
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_GOLF_PREPARE:
|
||||
{
|
||||
m_wait_on_input_received = true;
|
||||
m_wait_on_input = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_CHANGE_GAME:
|
||||
{
|
||||
{
|
||||
@ -622,6 +674,8 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
||||
for (int& extension : m_net_settings.m_WiimoteExtension)
|
||||
packet >> extension;
|
||||
|
||||
packet >> m_net_settings.m_GolfMode;
|
||||
|
||||
m_net_settings.m_IsHosting = m_local_player->IsHost();
|
||||
m_net_settings.m_HostInputAuthority = m_host_input_authority;
|
||||
}
|
||||
@ -1375,6 +1429,8 @@ bool NetPlayClient::StartGame(const std::string& path)
|
||||
}
|
||||
|
||||
m_timebase_frame = 0;
|
||||
m_current_golfer = 1;
|
||||
m_wait_on_input = false;
|
||||
|
||||
m_is_running.Set();
|
||||
NetPlay_Enable(this);
|
||||
@ -1686,6 +1742,27 @@ bool NetPlayClient::GetNetPads(const int pad_nb, const bool batching, GCPadStatu
|
||||
// specific pad arbitrarily. In this case, we poll just that pad
|
||||
// and send it.
|
||||
|
||||
// When here when told to so we don't deadlock in certain situations
|
||||
while (m_wait_on_input)
|
||||
{
|
||||
if (!m_is_running.IsSet())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_wait_on_input_received)
|
||||
{
|
||||
// Tell the server we've acknowledged the message
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_GOLF_PREPARE);
|
||||
Send(spac);
|
||||
|
||||
m_wait_on_input_received = false;
|
||||
}
|
||||
|
||||
m_wait_on_input_event.Wait();
|
||||
}
|
||||
|
||||
if (IsFirstInGamePad(pad_nb) && batching)
|
||||
{
|
||||
sf::Packet packet;
|
||||
@ -1720,22 +1797,30 @@ bool NetPlayClient::GetNetPads(const int pad_nb, const bool batching, GCPadStatu
|
||||
SendPadHostPoll(pad_nb);
|
||||
}
|
||||
|
||||
if (m_host_input_authority && !m_local_player->IsHost())
|
||||
if (m_host_input_authority)
|
||||
{
|
||||
// CoreTiming acts funny and causes what looks like frame skip if
|
||||
// we toggle the emulation speed too quickly, so to prevent this
|
||||
// we wait until the buffer has been over for at least 1 second.
|
||||
|
||||
const bool buffer_over_target = m_pad_buffer[pad_nb].Size() > m_target_buffer_size + 1;
|
||||
if (!buffer_over_target)
|
||||
m_buffer_under_target_last = std::chrono::steady_clock::now();
|
||||
|
||||
std::chrono::duration<double> time_diff =
|
||||
std::chrono::steady_clock::now() - m_buffer_under_target_last;
|
||||
if (time_diff.count() >= 1.0 || !buffer_over_target)
|
||||
if (m_local_player->pid != m_current_golfer)
|
||||
{
|
||||
// run fast if the buffer is overfilled, otherwise run normal speed
|
||||
SConfig::GetInstance().m_EmulationSpeed = buffer_over_target ? 0.0f : 1.0f;
|
||||
// CoreTiming acts funny and causes what looks like frame skip if
|
||||
// we toggle the emulation speed too quickly, so to prevent this
|
||||
// we wait until the buffer has been over for at least 1 second.
|
||||
|
||||
const bool buffer_over_target = m_pad_buffer[pad_nb].Size() > m_target_buffer_size + 1;
|
||||
if (!buffer_over_target)
|
||||
m_buffer_under_target_last = std::chrono::steady_clock::now();
|
||||
|
||||
std::chrono::duration<double> time_diff =
|
||||
std::chrono::steady_clock::now() - m_buffer_under_target_last;
|
||||
if (time_diff.count() >= 1.0 || !buffer_over_target)
|
||||
{
|
||||
// run fast if the buffer is overfilled, otherwise run normal speed
|
||||
SConfig::GetInstance().m_EmulationSpeed = buffer_over_target ? 0.0f : 1.0f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Set normal speed when we're the host, otherwise it can get stuck at unlimited
|
||||
SConfig::GetInstance().m_EmulationSpeed = 1.0f;
|
||||
}
|
||||
}
|
||||
|
||||
@ -1865,9 +1950,18 @@ bool NetPlayClient::PollLocalPad(const int local_pad, sf::Packet& packet)
|
||||
|
||||
if (m_host_input_authority)
|
||||
{
|
||||
// add to packet
|
||||
AddPadStateToPacket(ingame_pad, pad_status, packet);
|
||||
data_added = true;
|
||||
if (m_local_player->pid != m_current_golfer)
|
||||
{
|
||||
// add to packet
|
||||
AddPadStateToPacket(ingame_pad, pad_status, packet);
|
||||
data_added = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// set locally
|
||||
m_last_pad_status[ingame_pad] = pad_status;
|
||||
m_first_pad_status_received[ingame_pad] = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -1889,9 +1983,12 @@ bool NetPlayClient::PollLocalPad(const int local_pad, sf::Packet& packet)
|
||||
|
||||
void NetPlayClient::SendPadHostPoll(const PadIndex pad_num)
|
||||
{
|
||||
if (!m_local_player->IsHost())
|
||||
if (m_local_player->pid != m_current_golfer)
|
||||
return;
|
||||
|
||||
sf::Packet packet;
|
||||
packet << static_cast<MessageId>(NP_MSG_PAD_HOST_DATA);
|
||||
|
||||
if (pad_num < 0)
|
||||
{
|
||||
for (size_t i = 0; i < m_pad_map.size(); i++)
|
||||
@ -1907,6 +2004,16 @@ void NetPlayClient::SendPadHostPoll(const PadIndex pad_num)
|
||||
m_first_pad_status_received_event.Wait();
|
||||
}
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < m_pad_map.size(); i++)
|
||||
{
|
||||
if (m_pad_map[i] == 0 || m_pad_buffer[i].Size() > 0)
|
||||
continue;
|
||||
|
||||
const GCPadStatus& pad_status = m_last_pad_status[i];
|
||||
m_pad_buffer[i].Push(pad_status);
|
||||
AddPadStateToPacket(static_cast<int>(i), pad_status, packet);
|
||||
}
|
||||
}
|
||||
else if (m_pad_map[pad_num] != 0)
|
||||
{
|
||||
@ -1917,11 +2024,15 @@ void NetPlayClient::SendPadHostPoll(const PadIndex pad_num)
|
||||
|
||||
m_first_pad_status_received_event.Wait();
|
||||
}
|
||||
|
||||
if (m_pad_buffer[pad_num].Size() == 0)
|
||||
{
|
||||
const GCPadStatus& pad_status = m_last_pad_status[pad_num];
|
||||
m_pad_buffer[pad_num].Push(pad_status);
|
||||
AddPadStateToPacket(pad_num, pad_status, packet);
|
||||
}
|
||||
}
|
||||
|
||||
sf::Packet packet;
|
||||
packet << static_cast<MessageId>(NP_MSG_PAD_HOST_POLL);
|
||||
packet << pad_num;
|
||||
SendAsync(std::move(packet));
|
||||
}
|
||||
|
||||
@ -1934,6 +2045,7 @@ bool NetPlayClient::StopGame()
|
||||
m_gc_pad_event.Set();
|
||||
m_wii_pad_event.Set();
|
||||
m_first_pad_status_received_event.Set();
|
||||
m_wait_on_input_event.Set();
|
||||
|
||||
NetPlay_Disable();
|
||||
|
||||
@ -1957,6 +2069,7 @@ void NetPlayClient::Stop()
|
||||
m_gc_pad_event.Set();
|
||||
m_wii_pad_event.Set();
|
||||
m_first_pad_status_received_event.Set();
|
||||
m_wait_on_input_event.Set();
|
||||
|
||||
// Tell the server to stop if we have a pad mapped in game.
|
||||
if (LocalPlayerHasControllerMapped())
|
||||
@ -1979,15 +2092,35 @@ void NetPlayClient::SendPowerButtonEvent()
|
||||
SendAsync(std::move(packet));
|
||||
}
|
||||
|
||||
void NetPlayClient::RequestGolfControl(const PlayerId pid)
|
||||
{
|
||||
if (!m_host_input_authority || !m_net_settings.m_GolfMode)
|
||||
return;
|
||||
|
||||
sf::Packet packet;
|
||||
packet << static_cast<MessageId>(NP_MSG_GOLF_REQUEST);
|
||||
packet << pid;
|
||||
SendAsync(std::move(packet));
|
||||
}
|
||||
|
||||
void NetPlayClient::RequestGolfControl()
|
||||
{
|
||||
RequestGolfControl(m_local_player->pid);
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
std::string NetPlayClient::GetCurrentGolfer()
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lkp(m_crit.players);
|
||||
if (m_players.count(m_current_golfer))
|
||||
return m_players[m_current_golfer].name;
|
||||
return "";
|
||||
}
|
||||
|
||||
// called from ---GUI--- thread
|
||||
bool NetPlayClient::LocalPlayerHasControllerMapped() const
|
||||
{
|
||||
const auto mapping_matches_player_id = [this](const PlayerId& mapping) {
|
||||
return mapping == m_local_player->pid;
|
||||
};
|
||||
|
||||
return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) ||
|
||||
std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
|
||||
return PlayerHasControllerMapped(m_local_player->pid);
|
||||
}
|
||||
|
||||
bool NetPlayClient::IsFirstInGamePad(int ingame_pad) const
|
||||
@ -2040,6 +2173,19 @@ int NetPlayClient::LocalPadToInGamePad(int local_pad) const
|
||||
return ingame_pad;
|
||||
}
|
||||
|
||||
bool NetPlayClient::PlayerHasControllerMapped(const PlayerId pid) const
|
||||
{
|
||||
const auto mapping_matches_player_id = [pid](const PlayerId& mapping) { return mapping == pid; };
|
||||
|
||||
return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) ||
|
||||
std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
|
||||
}
|
||||
|
||||
bool NetPlayClient::IsLocalPlayer(const PlayerId pid) const
|
||||
{
|
||||
return pid == m_local_player->pid;
|
||||
}
|
||||
|
||||
void NetPlayClient::SendTimeBase()
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(crit_netplay_client);
|
||||
|
@ -54,6 +54,7 @@ public:
|
||||
virtual void OnTraversalError(TraversalClient::FailureReason error) = 0;
|
||||
virtual void OnTraversalStateChanged(TraversalClient::State state) = 0;
|
||||
virtual void OnSaveDataSyncFailure() = 0;
|
||||
virtual void OnGolferChanged(bool is_golfer, const std::string& golfer_name) = 0;
|
||||
|
||||
virtual bool IsRecording() = 0;
|
||||
virtual std::string FindGame(const std::string& game) = 0;
|
||||
@ -111,6 +112,9 @@ public:
|
||||
void SendChatMessage(const std::string& msg);
|
||||
void RequestStopGame();
|
||||
void SendPowerButtonEvent();
|
||||
void RequestGolfControl(PlayerId pid);
|
||||
void RequestGolfControl();
|
||||
std::string GetCurrentGolfer();
|
||||
|
||||
// Send and receive pads values
|
||||
bool WiimoteUpdate(int _number, u8* data, const u8 size, u8 reporting_mode);
|
||||
@ -128,6 +132,10 @@ public:
|
||||
int InGamePadToLocalPad(int ingame_pad) const;
|
||||
int LocalPadToInGamePad(int localPad) const;
|
||||
|
||||
bool PlayerHasControllerMapped(PlayerId pid) const;
|
||||
bool LocalPlayerHasControllerMapped() const;
|
||||
bool IsLocalPlayer(PlayerId pid) const;
|
||||
|
||||
static void SendTimeBase();
|
||||
bool DoAllPlayersHaveGame();
|
||||
|
||||
@ -158,6 +166,7 @@ protected:
|
||||
std::array<Common::SPSCQueue<GCPadStatus>, 4> m_pad_buffer;
|
||||
std::array<Common::SPSCQueue<NetWiimote>, 4> m_wiimote_buffer;
|
||||
|
||||
std::array<GCPadStatus, 4> m_last_pad_status{};
|
||||
std::array<bool, 4> m_first_pad_status_received{};
|
||||
|
||||
std::chrono::time_point<std::chrono::steady_clock> m_buffer_under_target_last;
|
||||
@ -178,6 +187,12 @@ protected:
|
||||
// speeding up the game to drain the buffer.
|
||||
unsigned int m_target_buffer_size = 20;
|
||||
bool m_host_input_authority = false;
|
||||
PlayerId m_current_golfer = 1;
|
||||
|
||||
// This bool will stall the client at the start of GetNetPads, used for switching input control
|
||||
// without deadlocking. Use the correspondingly named Event to wake it up.
|
||||
bool m_wait_on_input;
|
||||
bool m_wait_on_input_received;
|
||||
|
||||
Player* m_local_player = nullptr;
|
||||
|
||||
@ -199,8 +214,6 @@ private:
|
||||
Failure
|
||||
};
|
||||
|
||||
bool LocalPlayerHasControllerMapped() const;
|
||||
|
||||
void SendStartGamePacket();
|
||||
void SendStopGamePacket();
|
||||
|
||||
@ -238,6 +251,7 @@ private:
|
||||
Common::Event m_gc_pad_event;
|
||||
Common::Event m_wii_pad_event;
|
||||
Common::Event m_first_pad_status_received_event;
|
||||
Common::Event m_wait_on_input_event;
|
||||
u8 m_sync_save_data_count = 0;
|
||||
u8 m_sync_save_data_success_count = 0;
|
||||
u16 m_sync_gecko_codes_count = 0;
|
||||
|
@ -83,6 +83,9 @@ struct NetSettings
|
||||
std::string m_SaveDataRegion;
|
||||
bool m_SyncAllWiiSaves;
|
||||
std::array<int, 4> m_WiimoteExtension;
|
||||
bool m_GolfMode;
|
||||
|
||||
// These aren't sent over the network directly
|
||||
bool m_IsHosting;
|
||||
bool m_HostInputAuthority;
|
||||
};
|
||||
@ -123,12 +126,17 @@ enum
|
||||
NP_MSG_PAD_DATA = 0x60,
|
||||
NP_MSG_PAD_MAPPING = 0x61,
|
||||
NP_MSG_PAD_BUFFER = 0x62,
|
||||
NP_MSG_PAD_HOST_POLL = 0x63,
|
||||
NP_MSG_PAD_FIRST_RECEIVED = 0x64,
|
||||
NP_MSG_PAD_HOST_DATA = 0x63,
|
||||
|
||||
NP_MSG_WIIMOTE_DATA = 0x70,
|
||||
NP_MSG_WIIMOTE_MAPPING = 0x71,
|
||||
|
||||
NP_MSG_GOLF_REQUEST = 0x90,
|
||||
NP_MSG_GOLF_SWITCH = 0x91,
|
||||
NP_MSG_GOLF_ACQUIRE = 0x92,
|
||||
NP_MSG_GOLF_RELEASE = 0x93,
|
||||
NP_MSG_GOLF_PREPARE = 0x94,
|
||||
|
||||
NP_MSG_START_GAME = 0xA0,
|
||||
NP_MSG_CHANGE_GAME = 0xA1,
|
||||
NP_MSG_STOP_GAME = 0xA2,
|
||||
|
@ -527,12 +527,16 @@ void NetPlayServer::AdjustPadBufferSize(unsigned int size)
|
||||
|
||||
m_target_buffer_size = size;
|
||||
|
||||
// tell clients to change buffer size
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_PAD_BUFFER);
|
||||
spac << static_cast<u32>(m_target_buffer_size);
|
||||
// not needed on clients with host input authority
|
||||
if (!m_host_input_authority)
|
||||
{
|
||||
// tell clients to change buffer size
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_PAD_BUFFER);
|
||||
spac << static_cast<u32>(m_target_buffer_size);
|
||||
|
||||
SendAsyncToClients(std::move(spac));
|
||||
SendAsyncToClients(std::move(spac));
|
||||
}
|
||||
}
|
||||
|
||||
void NetPlayServer::SetHostInputAuthority(const bool enable)
|
||||
@ -652,7 +656,7 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
||||
break;
|
||||
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_PAD_DATA);
|
||||
spac << static_cast<MessageId>(m_host_input_authority ? NP_MSG_PAD_HOST_DATA : NP_MSG_PAD_DATA);
|
||||
|
||||
while (!packet.endOfPacket())
|
||||
{
|
||||
@ -670,59 +674,48 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
|
||||
if (m_host_input_authority)
|
||||
{
|
||||
m_last_pad_status[map] = pad;
|
||||
|
||||
if (!m_first_pad_status_received[map])
|
||||
{
|
||||
m_first_pad_status_received[map] = true;
|
||||
SendFirstReceivedToHost(map, true);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY
|
||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
||||
<< pad.isConnected;
|
||||
}
|
||||
}
|
||||
|
||||
if (!m_host_input_authority)
|
||||
SendToClients(spac, player.pid);
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_PAD_HOST_POLL:
|
||||
{
|
||||
PadIndex pad_num;
|
||||
packet >> pad_num;
|
||||
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_PAD_DATA);
|
||||
|
||||
if (pad_num < 0)
|
||||
{
|
||||
for (size_t i = 0; i < m_pad_map.size(); i++)
|
||||
{
|
||||
if (m_pad_map[i] == 0)
|
||||
continue;
|
||||
|
||||
const GCPadStatus& pad = m_last_pad_status[i];
|
||||
spac << static_cast<PadIndex>(i) << pad.button << pad.analogA << pad.analogB << pad.stickX
|
||||
<< pad.stickY << pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
||||
<< pad.isConnected;
|
||||
}
|
||||
}
|
||||
else if (m_pad_map.at(pad_num) != 0)
|
||||
{
|
||||
const GCPadStatus& pad = m_last_pad_status[pad_num];
|
||||
spac << pad_num << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY
|
||||
spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY
|
||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
||||
<< pad.isConnected;
|
||||
}
|
||||
|
||||
SendToClients(spac);
|
||||
if (m_host_input_authority)
|
||||
{
|
||||
// Prevent crash before game stop if the golfer disconnects
|
||||
if (m_current_golfer != 0 && m_players.find(m_current_golfer) != m_players.end())
|
||||
Send(m_players.at(m_current_golfer).socket, spac);
|
||||
}
|
||||
else
|
||||
{
|
||||
SendToClients(spac, player.pid);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_PAD_HOST_DATA:
|
||||
{
|
||||
// Kick player if they're not the golfer.
|
||||
if (m_current_golfer != 0 && player.pid != m_current_golfer)
|
||||
return 1;
|
||||
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_PAD_DATA);
|
||||
|
||||
while (!packet.endOfPacket())
|
||||
{
|
||||
PadIndex map;
|
||||
packet >> map;
|
||||
|
||||
GCPadStatus pad;
|
||||
packet >> pad.button >> pad.analogA >> pad.analogB >> pad.stickX >> pad.stickY >>
|
||||
pad.substickX >> pad.substickY >> pad.triggerLeft >> pad.triggerRight >> pad.isConnected;
|
||||
|
||||
spac << map << pad.button << pad.analogA << pad.analogB << pad.stickX << pad.stickY
|
||||
<< pad.substickX << pad.substickY << pad.triggerLeft << pad.triggerRight
|
||||
<< pad.isConnected;
|
||||
}
|
||||
|
||||
SendToClients(spac, player.pid);
|
||||
}
|
||||
break;
|
||||
|
||||
@ -758,6 +751,63 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_GOLF_REQUEST:
|
||||
{
|
||||
PlayerId pid;
|
||||
packet >> pid;
|
||||
|
||||
// Check if player ID is valid and sender isn't a spectator
|
||||
if (!m_players.count(pid) || !PlayerHasControllerMapped(player.pid))
|
||||
break;
|
||||
|
||||
if (m_host_input_authority && m_settings.m_GolfMode && m_pending_golfer == 0 &&
|
||||
m_current_golfer != pid && PlayerHasControllerMapped(pid))
|
||||
{
|
||||
m_pending_golfer = pid;
|
||||
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_GOLF_PREPARE);
|
||||
Send(m_players[pid].socket, spac);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_GOLF_RELEASE:
|
||||
{
|
||||
if (m_pending_golfer == 0)
|
||||
break;
|
||||
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_GOLF_SWITCH);
|
||||
spac << static_cast<PlayerId>(m_pending_golfer);
|
||||
SendToClients(spac);
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_GOLF_ACQUIRE:
|
||||
{
|
||||
if (m_pending_golfer == 0)
|
||||
break;
|
||||
|
||||
m_current_golfer = m_pending_golfer;
|
||||
m_pending_golfer = 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_GOLF_PREPARE:
|
||||
{
|
||||
if (m_pending_golfer == 0)
|
||||
break;
|
||||
|
||||
m_current_golfer = 0;
|
||||
|
||||
sf::Packet spac;
|
||||
spac << static_cast<MessageId>(NP_MSG_GOLF_SWITCH);
|
||||
spac << static_cast<PlayerId>(0);
|
||||
SendToClients(spac);
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_PONG:
|
||||
{
|
||||
const u32 ping = (u32)m_ping_timer.GetTimeElapsed();
|
||||
@ -1141,7 +1191,8 @@ bool NetPlayServer::StartGame()
|
||||
if (!m_host_input_authority)
|
||||
AdjustPadBufferSize(m_target_buffer_size);
|
||||
|
||||
m_first_pad_status_received.fill(false);
|
||||
m_current_golfer = 1;
|
||||
m_pending_golfer = 0;
|
||||
|
||||
const sf::Uint64 initial_rtc = GetInitialNetPlayRTC();
|
||||
|
||||
@ -1227,6 +1278,8 @@ bool NetPlayServer::StartGame()
|
||||
spac << extension;
|
||||
}
|
||||
|
||||
spac << m_settings.m_GolfMode;
|
||||
|
||||
SendAsyncToClients(std::move(spac));
|
||||
|
||||
m_start_pending = false;
|
||||
@ -1720,15 +1773,6 @@ bool NetPlayServer::CompressBufferIntoPacket(const std::vector<u8>& in_buffer, s
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPlayServer::SendFirstReceivedToHost(const PadIndex map, const bool state)
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_PAD_FIRST_RECEIVED);
|
||||
pac << map;
|
||||
pac << state;
|
||||
Send(m_players.at(1).socket, pac);
|
||||
}
|
||||
|
||||
u64 NetPlayServer::GetInitialNetPlayRTC() const
|
||||
{
|
||||
const auto& config = SConfig::GetInstance();
|
||||
@ -1771,6 +1815,14 @@ void NetPlayServer::KickPlayer(PlayerId player)
|
||||
}
|
||||
}
|
||||
|
||||
bool NetPlayServer::PlayerHasControllerMapped(const PlayerId pid) const
|
||||
{
|
||||
const auto mapping_matches_player_id = [pid](const PlayerId& mapping) { return mapping == pid; };
|
||||
|
||||
return std::any_of(m_pad_map.begin(), m_pad_map.end(), mapping_matches_player_id) ||
|
||||
std::any_of(m_wiimote_map.begin(), m_wiimote_map.end(), mapping_matches_player_id);
|
||||
}
|
||||
|
||||
u16 NetPlayServer::GetPort() const
|
||||
{
|
||||
return m_server->address.port;
|
||||
|
@ -118,7 +118,6 @@ private:
|
||||
void CheckSyncAndStartGame();
|
||||
bool CompressFileIntoPacket(const std::string& file_path, sf::Packet& packet);
|
||||
bool CompressBufferIntoPacket(const std::vector<u8>& in_buffer, sf::Packet& packet);
|
||||
void SendFirstReceivedToHost(PadIndex map, bool state);
|
||||
|
||||
u64 GetInitialNetPlayRTC() const;
|
||||
|
||||
@ -138,6 +137,8 @@ private:
|
||||
void ChunkedDataThreadFunc();
|
||||
void ChunkedDataSend(sf::Packet&& packet, PlayerId pid, const TargetMode target_mode);
|
||||
|
||||
bool PlayerHasControllerMapped(PlayerId pid) const;
|
||||
|
||||
NetSettings m_settings;
|
||||
|
||||
bool m_is_running = false;
|
||||
@ -155,15 +156,14 @@ private:
|
||||
bool m_codes_synced = true;
|
||||
bool m_start_pending = false;
|
||||
bool m_host_input_authority = false;
|
||||
PlayerId m_current_golfer = 1;
|
||||
PlayerId m_pending_golfer = 0;
|
||||
|
||||
std::map<PlayerId, Client> m_players;
|
||||
|
||||
std::unordered_map<u32, std::vector<std::pair<PlayerId, u64>>> m_timebase_by_frame;
|
||||
bool m_desync_detected;
|
||||
|
||||
std::array<GCPadStatus, 4> m_last_pad_status{};
|
||||
std::array<bool, 4> m_first_pad_status_received{};
|
||||
|
||||
struct
|
||||
{
|
||||
std::recursive_mutex game;
|
||||
|
@ -200,6 +200,9 @@ void HotkeyScheduler::Run()
|
||||
if (IsHotkey(HK_ACTIVATE_CHAT))
|
||||
emit ActivateChat();
|
||||
|
||||
if (IsHotkey(HK_REQUEST_GOLF_CONTROL))
|
||||
emit RequestGolfControl();
|
||||
|
||||
// Recording
|
||||
if (IsHotkey(HK_START_RECORDING))
|
||||
emit StartRecording();
|
||||
|
@ -27,6 +27,7 @@ signals:
|
||||
|
||||
void ExitHotkey();
|
||||
void ActivateChat();
|
||||
void RequestGolfControl();
|
||||
void FullScreenHotkey();
|
||||
void StopHotkey();
|
||||
void ResetHotkey();
|
||||
|
@ -494,6 +494,8 @@ void MainWindow::ConnectHotkeys()
|
||||
connect(m_hotkey_scheduler, &HotkeyScheduler::ExitHotkey, this, &MainWindow::close);
|
||||
connect(m_hotkey_scheduler, &HotkeyScheduler::TogglePauseHotkey, this, &MainWindow::TogglePause);
|
||||
connect(m_hotkey_scheduler, &HotkeyScheduler::ActivateChat, this, &MainWindow::OnActivateChat);
|
||||
connect(m_hotkey_scheduler, &HotkeyScheduler::RequestGolfControl, this,
|
||||
&MainWindow::OnRequestGolfControl);
|
||||
connect(m_hotkey_scheduler, &HotkeyScheduler::RefreshGameListHotkey, this,
|
||||
&MainWindow::RefreshGameList);
|
||||
connect(m_hotkey_scheduler, &HotkeyScheduler::StopHotkey, this, &MainWindow::RequestStop);
|
||||
@ -1284,8 +1286,7 @@ bool MainWindow::NetPlayJoin()
|
||||
if (server)
|
||||
{
|
||||
server->SetHostInputAuthority(host_input_authority);
|
||||
if (!host_input_authority)
|
||||
server->AdjustPadBufferSize(Config::Get(Config::NETPLAY_BUFFER_SIZE));
|
||||
server->AdjustPadBufferSize(Config::Get(Config::NETPLAY_BUFFER_SIZE));
|
||||
}
|
||||
|
||||
// Create Client
|
||||
@ -1605,6 +1606,13 @@ void MainWindow::OnActivateChat()
|
||||
g_netplay_chat_ui->Activate();
|
||||
}
|
||||
|
||||
void MainWindow::OnRequestGolfControl()
|
||||
{
|
||||
auto client = Settings::Instance().GetNetPlayClient();
|
||||
if (client)
|
||||
client->RequestGolfControl();
|
||||
}
|
||||
|
||||
void MainWindow::ShowTASInput()
|
||||
{
|
||||
for (int i = 0; i < num_gc_controllers; i++)
|
||||
|
@ -170,6 +170,7 @@ private:
|
||||
void OnStopRecording();
|
||||
void OnExportRecording();
|
||||
void OnActivateChat();
|
||||
void OnRequestGolfControl();
|
||||
void ShowTASInput();
|
||||
|
||||
void ChangeDisc();
|
||||
|
@ -55,6 +55,7 @@
|
||||
#include "UICommon/UICommon.h"
|
||||
|
||||
#include "VideoCommon/NetPlayChatUI.h"
|
||||
#include "VideoCommon/NetPlayGolfUI.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
#include "VideoCommon/VideoConfig.h"
|
||||
|
||||
@ -85,6 +86,8 @@ NetPlayDialog::NetPlayDialog(QWidget* parent)
|
||||
const bool strict_settings_sync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC);
|
||||
const bool host_input_authority = Config::Get(Config::NETPLAY_HOST_INPUT_AUTHORITY);
|
||||
const bool sync_all_wii_saves = Config::Get(Config::NETPLAY_SYNC_ALL_WII_SAVES);
|
||||
const bool golf_mode = Config::Get(Config::NETPLAY_GOLF_MODE);
|
||||
const bool golf_mode_overlay = Config::Get(Config::NETPLAY_GOLF_MODE_OVERLAY);
|
||||
|
||||
m_buffer_size_box->setValue(buffer_size);
|
||||
m_save_sd_action->setChecked(write_save_sdcard_data);
|
||||
@ -96,6 +99,8 @@ NetPlayDialog::NetPlayDialog(QWidget* parent)
|
||||
m_strict_settings_sync_action->setChecked(strict_settings_sync);
|
||||
m_host_input_authority_action->setChecked(host_input_authority);
|
||||
m_sync_all_wii_saves_action->setChecked(sync_all_wii_saves);
|
||||
m_golf_mode_action->setChecked(golf_mode);
|
||||
m_golf_mode_overlay_action->setChecked(golf_mode_overlay);
|
||||
|
||||
ConnectWidgets();
|
||||
|
||||
@ -144,10 +149,14 @@ void NetPlayDialog::CreateMainLayout()
|
||||
m_reduce_polling_rate_action->setCheckable(true);
|
||||
m_host_input_authority_action = m_network_menu->addAction(tr("Host Input Authority"));
|
||||
m_host_input_authority_action->setCheckable(true);
|
||||
m_golf_mode_action = m_network_menu->addAction(tr("Golf Mode"));
|
||||
m_golf_mode_action->setCheckable(true);
|
||||
|
||||
m_other_menu = m_menu_bar->addMenu(tr("Other"));
|
||||
m_record_input_action = m_other_menu->addAction(tr("Record Inputs"));
|
||||
m_record_input_action->setCheckable(true);
|
||||
m_golf_mode_overlay_action = m_other_menu->addAction(tr("Show Golf Mode Overlay"));
|
||||
m_golf_mode_overlay_action->setCheckable(true);
|
||||
|
||||
m_game_button->setDefault(false);
|
||||
m_game_button->setAutoDefault(false);
|
||||
@ -300,16 +309,18 @@ void NetPlayDialog::ConnectWidgets()
|
||||
|
||||
auto client = Settings::Instance().GetNetPlayClient();
|
||||
auto server = Settings::Instance().GetNetPlayServer();
|
||||
if (server)
|
||||
if (server && !m_host_input_authority)
|
||||
server->AdjustPadBufferSize(value);
|
||||
else
|
||||
client->AdjustPadBufferSize(value);
|
||||
});
|
||||
|
||||
connect(m_host_input_authority_action, &QAction::toggled, [](bool checked) {
|
||||
connect(m_host_input_authority_action, &QAction::toggled, this, [=](bool checked) {
|
||||
auto server = Settings::Instance().GetNetPlayServer();
|
||||
if (server)
|
||||
server->SetHostInputAuthority(checked);
|
||||
|
||||
m_golf_mode_action->setEnabled(checked);
|
||||
});
|
||||
|
||||
connect(m_start_button, &QPushButton::clicked, this, &NetPlayDialog::OnStart);
|
||||
@ -355,6 +366,8 @@ void NetPlayDialog::ConnectWidgets()
|
||||
connect(m_strict_settings_sync_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_host_input_authority_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_sync_all_wii_saves_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_golf_mode_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_golf_mode_overlay_action, &QAction::toggled, this, &NetPlayDialog::SaveSettings);
|
||||
}
|
||||
|
||||
void NetPlayDialog::SendMessage(const std::string& msg)
|
||||
@ -482,6 +495,7 @@ void NetPlayDialog::OnStart()
|
||||
settings.m_SyncCodes = m_sync_codes_action->isChecked();
|
||||
settings.m_SyncAllWiiSaves =
|
||||
m_sync_all_wii_saves_action->isChecked() && m_sync_save_data_action->isChecked();
|
||||
settings.m_GolfMode = m_golf_mode_action->isChecked();
|
||||
|
||||
// Unload GameINI to restore things to normal
|
||||
Config::RemoveLayer(Config::LayerType::GlobalGame);
|
||||
@ -539,8 +553,6 @@ void NetPlayDialog::show(std::string nickname, bool use_traversal)
|
||||
m_game_button->setEnabled(is_hosting);
|
||||
m_kick_button->setEnabled(false);
|
||||
|
||||
m_buffer_label->setText(is_hosting ? tr("Buffer:") : tr("Max Buffer:"));
|
||||
|
||||
QDialog::show();
|
||||
UpdateGUI();
|
||||
}
|
||||
@ -817,6 +829,7 @@ void NetPlayDialog::SetOptionsEnabled(bool enabled)
|
||||
m_strict_settings_sync_action->setEnabled(enabled);
|
||||
m_host_input_authority_action->setEnabled(enabled);
|
||||
m_sync_all_wii_saves_action->setEnabled(enabled && m_sync_save_data_action->isChecked());
|
||||
m_golf_mode_action->setEnabled(enabled && m_host_input_authority_action->isChecked());
|
||||
}
|
||||
|
||||
m_record_input_action->setEnabled(enabled);
|
||||
@ -829,6 +842,11 @@ void NetPlayDialog::OnMsgStartGame()
|
||||
g_netplay_chat_ui =
|
||||
std::make_unique<NetPlayChatUI>([this](const std::string& message) { SendMessage(message); });
|
||||
|
||||
if (Settings::Instance().GetNetPlayClient()->GetNetSettings().m_GolfMode)
|
||||
{
|
||||
g_netplay_golf_ui = std::make_unique<NetPlayGolfUI>(Settings::Instance().GetNetPlayClient());
|
||||
}
|
||||
|
||||
QueueOnObject(this, [this] {
|
||||
auto client = Settings::Instance().GetNetPlayClient();
|
||||
|
||||
@ -841,6 +859,7 @@ void NetPlayDialog::OnMsgStartGame()
|
||||
void NetPlayDialog::OnMsgStopGame()
|
||||
{
|
||||
g_netplay_chat_ui.reset();
|
||||
g_netplay_golf_ui.reset();
|
||||
QueueOnObject(this, [this] { UpdateDiscordPresence(); });
|
||||
}
|
||||
|
||||
@ -857,9 +876,8 @@ void NetPlayDialog::OnPadBufferChanged(u32 buffer)
|
||||
const QSignalBlocker blocker(m_buffer_size_box);
|
||||
m_buffer_size_box->setValue(buffer);
|
||||
});
|
||||
DisplayMessage(m_host_input_authority && !IsHosting() ?
|
||||
tr("Max buffer size changed to %1").arg(buffer) :
|
||||
tr("Buffer size changed to %1").arg(buffer),
|
||||
DisplayMessage(m_host_input_authority ? tr("Max buffer size changed to %1").arg(buffer) :
|
||||
tr("Buffer size changed to %1").arg(buffer),
|
||||
"darkcyan");
|
||||
|
||||
m_buffer_size = static_cast<int>(buffer);
|
||||
@ -867,6 +885,10 @@ void NetPlayDialog::OnPadBufferChanged(u32 buffer)
|
||||
|
||||
void NetPlayDialog::OnHostInputAuthorityChanged(bool enabled)
|
||||
{
|
||||
m_host_input_authority = enabled;
|
||||
DisplayMessage(enabled ? tr("Host input authority enabled") : tr("Host input authority disabled"),
|
||||
"");
|
||||
|
||||
QueueOnObject(this, [this, enabled] {
|
||||
const bool is_hosting = IsHosting();
|
||||
const bool enable_buffer = is_hosting != enabled;
|
||||
@ -878,8 +900,9 @@ void NetPlayDialog::OnHostInputAuthorityChanged(bool enabled)
|
||||
m_buffer_size_box->setHidden(false);
|
||||
m_buffer_label->setHidden(false);
|
||||
|
||||
QSignalBlocker blocker(m_host_input_authority_action);
|
||||
const QSignalBlocker blocker(m_host_input_authority_action);
|
||||
m_host_input_authority_action->setChecked(enabled);
|
||||
m_golf_mode_action->setEnabled(enabled);
|
||||
}
|
||||
else
|
||||
{
|
||||
@ -887,15 +910,12 @@ void NetPlayDialog::OnHostInputAuthorityChanged(bool enabled)
|
||||
m_buffer_label->setEnabled(true);
|
||||
m_buffer_size_box->setHidden(!enable_buffer);
|
||||
m_buffer_label->setHidden(!enable_buffer);
|
||||
|
||||
if (enabled)
|
||||
m_buffer_size_box->setValue(Config::Get(Config::NETPLAY_CLIENT_BUFFER_SIZE));
|
||||
}
|
||||
});
|
||||
DisplayMessage(enabled ? tr("Host input authority enabled") : tr("Host input authority disabled"),
|
||||
"");
|
||||
|
||||
m_host_input_authority = enabled;
|
||||
m_buffer_label->setText(enabled ? tr("Max Buffer:") : tr("Buffer:"));
|
||||
if (enabled)
|
||||
m_buffer_size_box->setValue(Config::Get(Config::NETPLAY_CLIENT_BUFFER_SIZE));
|
||||
});
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnDesync(u32 frame, const std::string& player)
|
||||
@ -958,6 +978,20 @@ void NetPlayDialog::OnSaveDataSyncFailure()
|
||||
QueueOnObject(this, [this] { SetOptionsEnabled(true); });
|
||||
}
|
||||
|
||||
void NetPlayDialog::OnGolferChanged(const bool is_golfer, const std::string& golfer_name)
|
||||
{
|
||||
if (m_host_input_authority)
|
||||
{
|
||||
QueueOnObject(this, [this, is_golfer] {
|
||||
m_buffer_size_box->setEnabled(!is_golfer);
|
||||
m_buffer_label->setEnabled(!is_golfer);
|
||||
});
|
||||
}
|
||||
|
||||
if (!golfer_name.empty())
|
||||
DisplayMessage(tr("%1 is now golfing").arg(QString::fromStdString(golfer_name)), "");
|
||||
}
|
||||
|
||||
bool NetPlayDialog::IsRecording()
|
||||
{
|
||||
std::optional<bool> is_recording = RunOnObject(m_record_input_action, &QAction::isChecked);
|
||||
@ -1002,14 +1036,10 @@ void NetPlayDialog::SaveSettings()
|
||||
Config::ConfigChangeCallbackGuard config_guard;
|
||||
|
||||
if (m_host_input_authority)
|
||||
{
|
||||
if (!IsHosting())
|
||||
Config::SetBase(Config::NETPLAY_CLIENT_BUFFER_SIZE, m_buffer_size_box->value());
|
||||
}
|
||||
Config::SetBase(Config::NETPLAY_CLIENT_BUFFER_SIZE, m_buffer_size_box->value());
|
||||
else
|
||||
{
|
||||
Config::SetBase(Config::NETPLAY_BUFFER_SIZE, m_buffer_size_box->value());
|
||||
}
|
||||
|
||||
Config::SetBase(Config::NETPLAY_WRITE_SAVE_SDCARD_DATA, m_save_sd_action->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_LOAD_WII_SAVE, m_load_wii_action->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_SYNC_SAVES, m_sync_save_data_action->isChecked());
|
||||
@ -1019,6 +1049,8 @@ void NetPlayDialog::SaveSettings()
|
||||
Config::SetBase(Config::NETPLAY_STRICT_SETTINGS_SYNC, m_strict_settings_sync_action->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_HOST_INPUT_AUTHORITY, m_host_input_authority_action->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_SYNC_ALL_WII_SAVES, m_sync_all_wii_saves_action->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_GOLF_MODE, m_golf_mode_action->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_GOLF_MODE_OVERLAY, m_golf_mode_overlay_action->isChecked());
|
||||
}
|
||||
|
||||
void NetPlayDialog::ShowMD5Dialog(const std::string& file_identifier)
|
||||
|
@ -58,6 +58,7 @@ public:
|
||||
void OnTraversalError(TraversalClient::FailureReason error) override;
|
||||
void OnTraversalStateChanged(TraversalClient::State state) override;
|
||||
void OnSaveDataSyncFailure() override;
|
||||
void OnGolferChanged(bool is_golfer, const std::string& golfer_name) override;
|
||||
|
||||
bool IsRecording() override;
|
||||
std::string FindGame(const std::string& game) override;
|
||||
@ -131,6 +132,8 @@ private:
|
||||
QAction* m_strict_settings_sync_action;
|
||||
QAction* m_host_input_authority_action;
|
||||
QAction* m_sync_all_wii_saves_action;
|
||||
QAction* m_golf_mode_action;
|
||||
QAction* m_golf_mode_overlay_action;
|
||||
QPushButton* m_quit_button;
|
||||
QSplitter* m_splitter;
|
||||
|
||||
|
@ -28,6 +28,7 @@
|
||||
#include "InputCommon/InputConfig.h"
|
||||
|
||||
#include "VideoCommon/NetPlayChatUI.h"
|
||||
#include "VideoCommon/NetPlayGolfUI.h"
|
||||
#include "VideoCommon/RenderBase.h"
|
||||
|
||||
Settings::Settings()
|
||||
@ -298,6 +299,7 @@ void Settings::ResetNetPlayClient(NetPlay::NetPlayClient* client)
|
||||
m_client.reset(client);
|
||||
|
||||
g_netplay_chat_ui.reset();
|
||||
g_netplay_golf_ui.reset();
|
||||
}
|
||||
|
||||
std::shared_ptr<NetPlay::NetPlayServer> Settings::GetNetPlayServer()
|
||||
|
@ -23,6 +23,7 @@ add_library(videocommon
|
||||
IndexGenerator.cpp
|
||||
LightingShaderGen.cpp
|
||||
NetPlayChatUI.cpp
|
||||
NetPlayGolfUI.cpp
|
||||
OnScreenDisplay.cpp
|
||||
OpcodeDecoding.cpp
|
||||
PerfQueryBase.cpp
|
||||
|
66
Source/Core/VideoCommon/NetPlayGolfUI.cpp
Normal file
66
Source/Core/VideoCommon/NetPlayGolfUI.cpp
Normal file
@ -0,0 +1,66 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/NetPlayClient.h"
|
||||
|
||||
#include "VideoCommon/NetPlayGolfUI.h"
|
||||
|
||||
#include <imgui.h>
|
||||
|
||||
constexpr float DEFAULT_WINDOW_WIDTH = 220.0f;
|
||||
constexpr float DEFAULT_WINDOW_HEIGHT = 45.0f;
|
||||
|
||||
std::unique_ptr<NetPlayGolfUI> g_netplay_golf_ui;
|
||||
|
||||
NetPlayGolfUI::NetPlayGolfUI(std::shared_ptr<NetPlay::NetPlayClient> netplay_client)
|
||||
{
|
||||
m_netplay_client = netplay_client;
|
||||
}
|
||||
|
||||
void NetPlayGolfUI::Display()
|
||||
{
|
||||
auto client = m_netplay_client.lock();
|
||||
if (!client)
|
||||
return;
|
||||
|
||||
const float scale = ImGui::GetIO().DisplayFramebufferScale.x;
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2((20.0f + DEFAULT_WINDOW_WIDTH) * scale, 10.0f * scale),
|
||||
ImGuiCond_FirstUseEver);
|
||||
ImGui::SetNextWindowSizeConstraints(
|
||||
ImVec2(DEFAULT_WINDOW_WIDTH * scale, DEFAULT_WINDOW_HEIGHT * scale),
|
||||
ImGui::GetIO().DisplaySize);
|
||||
|
||||
// TODO: Translate these strings once imgui has multilingual fonts
|
||||
if (!ImGui::Begin("Golf Mode", nullptr, ImGuiWindowFlags_None))
|
||||
{
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui::Text("Current Golfer: %s", client->GetCurrentGolfer().c_str());
|
||||
|
||||
if (client->LocalPlayerHasControllerMapped())
|
||||
{
|
||||
if (ImGui::Button("Take Control"))
|
||||
{
|
||||
client->RequestGolfControl();
|
||||
}
|
||||
|
||||
for (auto player : client->GetPlayers())
|
||||
{
|
||||
if (client->IsLocalPlayer(player->pid) || !client->PlayerHasControllerMapped(player->pid))
|
||||
continue;
|
||||
|
||||
if (ImGui::Button(StringFromFormat("Give Control to %s", player->name.c_str()).c_str()))
|
||||
{
|
||||
client->RequestGolfControl(player->pid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
27
Source/Core/VideoCommon/NetPlayGolfUI.h
Normal file
27
Source/Core/VideoCommon/NetPlayGolfUI.h
Normal file
@ -0,0 +1,27 @@
|
||||
// Copyright 2019 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
|
||||
namespace NetPlay
|
||||
{
|
||||
class NetPlayClient;
|
||||
}
|
||||
|
||||
class NetPlayGolfUI
|
||||
{
|
||||
public:
|
||||
explicit NetPlayGolfUI(std::shared_ptr<NetPlay::NetPlayClient> netplay_client);
|
||||
~NetPlayGolfUI() = default;
|
||||
|
||||
void Display();
|
||||
|
||||
private:
|
||||
std::weak_ptr<NetPlay::NetPlayClient> m_netplay_client;
|
||||
};
|
||||
|
||||
extern std::unique_ptr<NetPlayGolfUI> g_netplay_golf_ui;
|
@ -37,6 +37,7 @@
|
||||
#include "Common/Timer.h"
|
||||
|
||||
#include "Core/Analytics.h"
|
||||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/Config/SYSCONFSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/Core.h"
|
||||
@ -58,6 +59,7 @@
|
||||
#include "VideoCommon/FramebufferManager.h"
|
||||
#include "VideoCommon/ImageWrite.h"
|
||||
#include "VideoCommon/NetPlayChatUI.h"
|
||||
#include "VideoCommon/NetPlayGolfUI.h"
|
||||
#include "VideoCommon/OnScreenDisplay.h"
|
||||
#include "VideoCommon/PixelEngine.h"
|
||||
#include "VideoCommon/PixelShaderManager.h"
|
||||
@ -532,6 +534,9 @@ void Renderer::DrawDebugText()
|
||||
if (g_ActiveConfig.bShowNetPlayMessages && g_netplay_chat_ui)
|
||||
g_netplay_chat_ui->Display();
|
||||
|
||||
if (Config::Get(Config::NETPLAY_GOLF_MODE_OVERLAY) && g_netplay_golf_ui)
|
||||
g_netplay_golf_ui->Display();
|
||||
|
||||
if (g_ActiveConfig.bOverlayProjStats)
|
||||
Statistics::DisplayProj();
|
||||
}
|
||||
|
@ -58,6 +58,7 @@
|
||||
<ClCompile Include="ImageWrite.cpp" />
|
||||
<ClCompile Include="IndexGenerator.cpp" />
|
||||
<ClCompile Include="NetPlayChatUI.cpp" />
|
||||
<ClCompile Include="NetPlayGolfUI.cpp" />
|
||||
<ClCompile Include="OnScreenDisplay.cpp" />
|
||||
<ClCompile Include="OpcodeDecoding.cpp" />
|
||||
<ClCompile Include="PerfQueryBase.cpp" />
|
||||
@ -122,6 +123,7 @@
|
||||
<ClInclude Include="FramebufferShaderGen.h" />
|
||||
<ClInclude Include="GXPipelineTypes.h" />
|
||||
<ClInclude Include="NetPlayChatUI.h" />
|
||||
<ClInclude Include="NetPlayGolfUI.h" />
|
||||
<ClInclude Include="ShaderCache.h" />
|
||||
<ClInclude Include="UberShaderCommon.h" />
|
||||
<ClInclude Include="UberShaderPixel.h" />
|
||||
@ -192,4 +194,4 @@
|
||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
@ -200,6 +200,9 @@
|
||||
<ClCompile Include="NetPlayChatUI.cpp">
|
||||
<Filter>Util</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="NetPlayGolfUI.cpp">
|
||||
<Filter>Util</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="CommandProcessor.h" />
|
||||
@ -392,8 +395,11 @@
|
||||
<ClInclude Include="NetPlayChatUI.h">
|
||||
<Filter>Util</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="NetPlayGolfUI.h">
|
||||
<Filter>Util</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user