Skip to content
Permalink
Browse files

Merge pull request #7955 from Techjar/netplay-golf-mode

NetPlay golf mode
  • Loading branch information...
spycrab committed Apr 5, 2019
2 parents bfde5b9 + 6c393f9 commit e44433c2f60d51e6d7f6fc0b1e589e23567e0093
@@ -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,19 +495,47 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
}
break;

case NP_MSG_PAD_FIRST_RECEIVED:
case NP_MSG_HOST_INPUT_AUTHORITY:
{
PadIndex map;
packet >> map;
packet >> m_first_pad_status_received[map];
m_first_pad_status_received_event.Set();
packet >> m_host_input_authority;
m_dialog->OnHostInputAuthorityChanged(m_host_input_authority);
}
break;

case NP_MSG_HOST_INPUT_AUTHORITY:
case NP_MSG_GOLF_SWITCH:
{
packet >> m_host_input_authority;
m_dialog->OnHostInputAuthorityChanged(m_host_input_authority);
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;

@@ -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.
if (m_local_player->pid != m_current_golfer)
{
// 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();
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)
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
{
// run fast if the buffer is overfilled, otherwise run normal speed
SConfig::GetInstance().m_EmulationSpeed = buffer_over_target ? 0.0f : 1.0f;
// 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
bool NetPlayClient::LocalPlayerHasControllerMapped() const
std::string NetPlayClient::GetCurrentGolfer()
{
const auto mapping_matches_player_id = [this](const PlayerId& mapping) {
return mapping == m_local_player->pid;
};
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 "";
}

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);
// called from ---GUI--- thread
bool NetPlayClient::LocalPlayerHasControllerMapped() const
{
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);

0 comments on commit e44433c

Please sign in to comment.
You can’t perform that action at this time.