Merge pull request #2974 from HeatXD/netplay_dev
Upstream Netplay Changes
This commit is contained in:
commit
5de071900d
24
README.md
24
README.md
|
@ -104,13 +104,9 @@ You will need a device with armv7 (32-bit ARM), AArch64 (64-bit ARM), or x86_64
|
||||||
|
|
||||||
Google Play is the preferred distribution mechanism and will result in smaller download sizes: https://play.google.com/store/apps/details?id=com.github.stenzek.duckstation
|
Google Play is the preferred distribution mechanism and will result in smaller download sizes: https://play.google.com/store/apps/details?id=com.github.stenzek.duckstation
|
||||||
|
|
||||||
**No support is provided for the Android app**, it is free and your expectations should be in line with that. Please **do not** email me about issues about it, they will be ignored. This repository should also not be used to raise issues about the app, as it does not contain the app code, only the desktop versions.
|
**No support is provided for the Android app**, it is free and your expectations should be in line with that. Please **do not** email me about issues about it, they will be ignored.
|
||||||
|
|
||||||
If you must use an APK, download links are:
|
If you must use an APK, download links are listed in https://www.duckstation.org/android/
|
||||||
|
|
||||||
Download link: https://www.duckstation.org/android/duckstation-android.apk
|
|
||||||
|
|
||||||
Changelog link: https://www.duckstation.org/android/changelog.txt
|
|
||||||
|
|
||||||
To use:
|
To use:
|
||||||
1. Install and run the app for the first time.
|
1. Install and run the app for the first time.
|
||||||
|
@ -215,22 +211,6 @@ Hotkeys:
|
||||||
- **Tab:** Temporarily disable speed limiter
|
- **Tab:** Temporarily disable speed limiter
|
||||||
- **Space:** Pause/resume emulation
|
- **Space:** Pause/resume emulation
|
||||||
|
|
||||||
## Screenshots
|
|
||||||
<p align="center">
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/monkey.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/monkey.jpg" alt="Monkey Hero" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/rrt4.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/rrt4.jpg" alt="Ridge Racer Type 4" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/tr2.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/tr2.jpg" alt="Tomb Raider 2" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/quake2.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/quake2.jpg" alt="Quake 2" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/croc.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/croc.jpg" alt="Croc" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/croc2.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/croc2.jpg" alt="Croc 2" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/ff7.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/ff7.jpg" alt="Final Fantasy 7" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/mm8.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/mm8.jpg" alt="Mega Man 8" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/ff8.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/ff8.jpg" alt="Final Fantasy 8 in Fullscreen UI" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/spyro.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/spyro.jpg" alt="Spyro in Fullscreen UI" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/tof.jpg"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/tof.jpg" alt="Threads of Fate in Fullscreen UI" width="400" /></a>
|
|
||||||
<a href="https://raw.githubusercontent.com/stenzek/duckstation/md-images/gamegrid.png"><img src="https://raw.githubusercontent.com/stenzek/duckstation/md-images/gamegrid.png" alt="Game Grid" width="400" /></a>
|
|
||||||
</p>
|
|
||||||
|
|
||||||
## Disclaimers
|
## Disclaimers
|
||||||
|
|
||||||
Icon by icons8: https://icons8.com/icon/74847/platforms.undefined.short-title
|
Icon by icons8: https://icons8.com/icon/74847/platforms.undefined.short-title
|
||||||
|
|
|
@ -53,7 +53,7 @@ void AnalogController::Reset()
|
||||||
|
|
||||||
if (m_force_analog_on_reset)
|
if (m_force_analog_on_reset)
|
||||||
{
|
{
|
||||||
if (g_settings.controller_disable_analog_mode_forcing || System::IsRunningBIOS())
|
if (g_settings.controller_disable_analog_mode_forcing || System::IsRunningUnknownGame())
|
||||||
{
|
{
|
||||||
Host::AddIconOSDMessage(
|
Host::AddIconOSDMessage(
|
||||||
fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
|
fmt::format("Controller{}AnalogMode", m_index), ICON_FA_GAMEPAD,
|
||||||
|
@ -835,8 +835,7 @@ static const char* s_invert_settings[] = {TRANSLATABLE("AnalogController", "Not
|
||||||
|
|
||||||
static const SettingInfo s_settings[] = {
|
static const SettingInfo s_settings[] = {
|
||||||
{SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
|
{SettingInfo::Type::Boolean, "ForceAnalogOnReset", TRANSLATABLE("AnalogController", "Force Analog Mode on Reset"),
|
||||||
TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on. May "
|
TRANSLATABLE("AnalogController", "Forces the controller to analog mode when the console is reset/powered on."),
|
||||||
"cause issues with games, so it is recommended to leave this option off."),
|
|
||||||
"true"},
|
"true"},
|
||||||
{SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode",
|
{SettingInfo::Type::Boolean, "AnalogDPadInDigitalMode",
|
||||||
TRANSLATABLE("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"),
|
TRANSLATABLE("AnalogController", "Use Analog Sticks for D-Pad in Digital Mode"),
|
||||||
|
|
|
@ -46,6 +46,7 @@ enum class ControlMessage : u32
|
||||||
ConnectResponse,
|
ConnectResponse,
|
||||||
SynchronizeSession,
|
SynchronizeSession,
|
||||||
SynchronizeComplete,
|
SynchronizeComplete,
|
||||||
|
ChatMessage,
|
||||||
};
|
};
|
||||||
|
|
||||||
#pragma pack(push, 1)
|
#pragma pack(push, 1)
|
||||||
|
@ -94,6 +95,15 @@ struct ControlSynchronizeCompleteMessage
|
||||||
|
|
||||||
static ControlMessage MessageType() { return ControlMessage::SynchronizeComplete; }
|
static ControlMessage MessageType() { return ControlMessage::SynchronizeComplete; }
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ControlChatMessage
|
||||||
|
{
|
||||||
|
ControlMessageHeader header;
|
||||||
|
|
||||||
|
u32 chat_message_size;
|
||||||
|
|
||||||
|
static ControlMessage MessageType() { return ControlMessage::ChatMessage; }
|
||||||
|
};
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
using SaveStateBuffer = std::unique_ptr<System::MemorySaveState>;
|
using SaveStateBuffer = std::unique_ptr<System::MemorySaveState>;
|
||||||
|
@ -141,6 +151,7 @@ static void HandleControlMessage(s32 player_id, const ENetPacket* pkt);
|
||||||
static void HandleConnectResponseMessage(s32 player_id, const ENetPacket* pkt);
|
static void HandleConnectResponseMessage(s32 player_id, const ENetPacket* pkt);
|
||||||
static void HandleSynchronizeSessionMessage(s32 player_id, const ENetPacket* pkt);
|
static void HandleSynchronizeSessionMessage(s32 player_id, const ENetPacket* pkt);
|
||||||
static void HandleSynchronizeCompleteMessage(s32 player_id, const ENetPacket* pkt);
|
static void HandleSynchronizeCompleteMessage(s32 player_id, const ENetPacket* pkt);
|
||||||
|
static void HandleControlChatMessage(s32 player_id, const ENetPacket* pkt);
|
||||||
|
|
||||||
// l = local, r = remote
|
// l = local, r = remote
|
||||||
static bool CreateGGPOSession();
|
static bool CreateGGPOSession();
|
||||||
|
@ -170,7 +181,6 @@ static void Throttle();
|
||||||
|
|
||||||
// Desync Detection
|
// Desync Detection
|
||||||
static void GenerateChecksumForFrame(int* checksum, int frame, unsigned char* buffer, int buffer_size);
|
static void GenerateChecksumForFrame(int* checksum, int frame, unsigned char* buffer, int buffer_size);
|
||||||
static void GenerateDesyncReport(s32 desync_frame);
|
|
||||||
|
|
||||||
//////////////////////////////////////////////////////////////////////////
|
//////////////////////////////////////////////////////////////////////////
|
||||||
// Variables
|
// Variables
|
||||||
|
@ -252,7 +262,6 @@ static bool SendControlPacket(s32 player_id, const PacketWrapper<T>& pkt)
|
||||||
DebugAssert(player_id >= 0 && player_id < MAX_PLAYERS && s_peers[player_id].peer);
|
DebugAssert(player_id >= 0 && player_id < MAX_PLAYERS && s_peers[player_id].peer);
|
||||||
return SendControlPacket<T>(s_peers[player_id].peer, pkt);
|
return SendControlPacket<T>(s_peers[player_id].peer, pkt);
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace Netplay
|
} // namespace Netplay
|
||||||
|
|
||||||
// Netplay Impl
|
// Netplay Impl
|
||||||
|
@ -505,6 +514,10 @@ void Netplay::PollEnet(Common::Timer::Value until_time)
|
||||||
const u32 enet_timeout = (current_time >= until_time) ?
|
const u32 enet_timeout = (current_time >= until_time) ?
|
||||||
0 :
|
0 :
|
||||||
static_cast<u32>(Common::Timer::ConvertValueToMilliseconds(until_time - current_time));
|
static_cast<u32>(Common::Timer::ConvertValueToMilliseconds(until_time - current_time));
|
||||||
|
|
||||||
|
// make sure s_enet_host exists
|
||||||
|
Assert(s_enet_host);
|
||||||
|
|
||||||
const int res = enet_host_service(s_enet_host, &event, enet_timeout);
|
const int res = enet_host_service(s_enet_host, &event, enet_timeout);
|
||||||
if (res > 0)
|
if (res > 0)
|
||||||
{
|
{
|
||||||
|
@ -514,7 +527,6 @@ void Netplay::PollEnet(Common::Timer::Value until_time)
|
||||||
current_time = Common::Timer::GetCurrentValue();
|
current_time = Common::Timer::GetCurrentValue();
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// exit once we're nonblocking
|
// exit once we're nonblocking
|
||||||
current_time = Common::Timer::GetCurrentValue();
|
current_time = Common::Timer::GetCurrentValue();
|
||||||
if (enet_timeout == 0 || current_time >= until_time)
|
if (enet_timeout == 0 || current_time >= until_time)
|
||||||
|
@ -693,6 +705,10 @@ void Netplay::HandleControlMessage(s32 player_id, const ENetPacket* pkt)
|
||||||
HandleSynchronizeCompleteMessage(player_id, pkt);
|
HandleSynchronizeCompleteMessage(player_id, pkt);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case ControlMessage::ChatMessage:
|
||||||
|
HandleControlChatMessage(player_id, pkt);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
Log_ErrorPrintf("Unhandled control packet %u from player %d of size %zu", hdr->type, player_id, pkt->dataLength);
|
Log_ErrorPrintf("Unhandled control packet %u from player %d of size %zu", hdr->type, player_id, pkt->dataLength);
|
||||||
break;
|
break;
|
||||||
|
@ -1003,6 +1019,22 @@ void Netplay::HandleSynchronizeCompleteMessage(s32 player_id, const ENetPacket*
|
||||||
CheckForCompleteResynchronize();
|
CheckForCompleteResynchronize();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Netplay::HandleControlChatMessage(s32 player_id, const ENetPacket* pkt)
|
||||||
|
{
|
||||||
|
const ControlChatMessage* msg = reinterpret_cast<const ControlChatMessage*>(pkt->data);
|
||||||
|
if (pkt->dataLength < sizeof(ControlChatMessage) ||
|
||||||
|
pkt->dataLength < (sizeof(ControlChatMessage) + msg->chat_message_size))
|
||||||
|
{
|
||||||
|
// invalid chat message. ignore.
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string message(pkt->data + sizeof(ControlChatMessage),
|
||||||
|
pkt->data + sizeof(ControlChatMessage) + msg->chat_message_size);
|
||||||
|
|
||||||
|
Host::OnNetplayMessage(fmt::format("Player {}: {}", PlayerIdToGGPOHandle(player_id), message));
|
||||||
|
}
|
||||||
|
|
||||||
void Netplay::CheckForCompleteResynchronize()
|
void Netplay::CheckForCompleteResynchronize()
|
||||||
{
|
{
|
||||||
if (s_synchronized_players == s_num_players)
|
if (s_synchronized_players == s_num_players)
|
||||||
|
@ -1065,6 +1097,9 @@ void Netplay::UpdateThrottlePeriod()
|
||||||
|
|
||||||
void Netplay::HandleTimeSyncEvent(float frame_delta, int update_interval)
|
void Netplay::HandleTimeSyncEvent(float frame_delta, int update_interval)
|
||||||
{
|
{
|
||||||
|
// only activate timesync if its worth correcting.
|
||||||
|
if (std::abs(frame_delta) < 1.0f)
|
||||||
|
return;
|
||||||
// Distribute the frame difference over the next N * 0.75 frames.
|
// Distribute the frame difference over the next N * 0.75 frames.
|
||||||
// only part of the interval time is used since we want to come back to normal speed.
|
// only part of the interval time is used since we want to come back to normal speed.
|
||||||
// otherwise we will keep spiraling into unplayable gameplay.
|
// otherwise we will keep spiraling into unplayable gameplay.
|
||||||
|
@ -1140,37 +1175,6 @@ void Netplay::GenerateChecksumForFrame(int* checksum, int frame, unsigned char*
|
||||||
// Log_VerbosePrintf("Netplay Checksum: f:%d wf:%d c:%u", frame, frame % num_group_of_pages, *checksum);
|
// Log_VerbosePrintf("Netplay Checksum: f:%d wf:%d c:%u", frame, frame % num_group_of_pages, *checksum);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Netplay::GenerateDesyncReport(s32 desync_frame)
|
|
||||||
{
|
|
||||||
std::string path = "\\netplaylogs\\desync_frame_" + std::to_string(desync_frame) + "_p" +
|
|
||||||
std::to_string(s_local_handle) + "_" + System::GetRunningSerial() + "_.txt";
|
|
||||||
std::string filename = EmuFolders::Dumps + path;
|
|
||||||
|
|
||||||
std::unique_ptr<ByteStream> stream =
|
|
||||||
ByteStream::OpenFile(filename.c_str(), BYTESTREAM_OPEN_CREATE | BYTESTREAM_OPEN_WRITE | BYTESTREAM_OPEN_TRUNCATE |
|
|
||||||
BYTESTREAM_OPEN_ATOMIC_UPDATE | BYTESTREAM_OPEN_STREAMED);
|
|
||||||
if (!stream)
|
|
||||||
{
|
|
||||||
Log_VerbosePrint("desync log creation failed to create stream");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!ByteStream::WriteBinaryToStream(stream.get(),
|
|
||||||
s_save_buffer_pool.back().get()->state_stream.get()->GetMemoryPointer(),
|
|
||||||
s_save_buffer_pool.back().get()->state_stream.get()->GetMemorySize()))
|
|
||||||
{
|
|
||||||
Log_VerbosePrint("desync log creation failed to write the stream");
|
|
||||||
stream->Discard();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
/* stream->Write(s_save_buffer_pool.back().get()->state_stream.get()->GetMemoryPointer(),
|
|
||||||
s_save_buffer_pool.back().get()->state_stream.get()->GetMemorySize());*/
|
|
||||||
|
|
||||||
stream->Commit();
|
|
||||||
|
|
||||||
Log_VerbosePrintf("desync log created for frame %d", desync_frame);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Netplay::AdvanceFrame()
|
void Netplay::AdvanceFrame()
|
||||||
{
|
{
|
||||||
ggpo_advance_frame(s_ggpo, 0);
|
ggpo_advance_frame(s_ggpo, 0);
|
||||||
|
@ -1178,19 +1182,13 @@ void Netplay::AdvanceFrame()
|
||||||
|
|
||||||
void Netplay::RunFrame()
|
void Netplay::RunFrame()
|
||||||
{
|
{
|
||||||
|
PollEnet(0);
|
||||||
|
|
||||||
|
if (!s_ggpo)
|
||||||
|
return;
|
||||||
// housekeeping
|
// housekeeping
|
||||||
// TODO: get rid of double polling
|
|
||||||
PollEnet(0);
|
|
||||||
if (!s_ggpo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ggpo_network_idle(s_ggpo);
|
ggpo_network_idle(s_ggpo);
|
||||||
PollEnet(0);
|
|
||||||
if (!s_ggpo)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ggpo_idle(s_ggpo);
|
ggpo_idle(s_ggpo);
|
||||||
|
|
||||||
// run game
|
// run game
|
||||||
auto result = GGPO_OK;
|
auto result = GGPO_OK;
|
||||||
int disconnect_flags = 0;
|
int disconnect_flags = 0;
|
||||||
|
@ -1238,7 +1236,36 @@ Netplay::Input Netplay::ReadLocalInput()
|
||||||
return inp;
|
return inp;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Netplay::SendMsg(const char* msg) {}
|
void Netplay::SendMsg(std::string msg)
|
||||||
|
{
|
||||||
|
ControlChatMessage header{};
|
||||||
|
const size_t msg_size = msg.size();
|
||||||
|
|
||||||
|
header.header.type = ControlMessage::ChatMessage;
|
||||||
|
header.header.size = sizeof(ControlChatMessage) + msg_size;
|
||||||
|
header.chat_message_size = msg_size;
|
||||||
|
|
||||||
|
ENetPacket* pkt = enet_packet_create(nullptr, sizeof(header) + msg_size, ENET_PACKET_FLAG_RELIABLE);
|
||||||
|
std::memcpy(pkt->data, &header, sizeof(header));
|
||||||
|
std::memcpy(pkt->data + sizeof(header), msg.c_str(), msg_size);
|
||||||
|
|
||||||
|
for (s32 i = 0; i < MAX_PLAYERS; i++)
|
||||||
|
{
|
||||||
|
if (!s_peers[i].peer)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
const int err = enet_peer_send(s_peers[i].peer, ENET_CHANNEL_CONTROL, pkt);
|
||||||
|
if (err != 0)
|
||||||
|
{
|
||||||
|
// failed to send netplay message? just clean it up.
|
||||||
|
Log_ErrorPrint("Failed to send netplay message");
|
||||||
|
enet_packet_destroy(pkt);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// add own netplay message locally to netplay messages
|
||||||
|
Host::OnNetplayMessage(fmt::format("Player {}: {}", s_local_handle, msg));
|
||||||
|
}
|
||||||
|
|
||||||
GGPOErrorCode Netplay::SyncInput(Netplay::Input inputs[2], int* disconnect_flags)
|
GGPOErrorCode Netplay::SyncInput(Netplay::Input inputs[2], int* disconnect_flags)
|
||||||
{
|
{
|
||||||
|
@ -1288,9 +1315,10 @@ void Netplay::StartNetplaySession(s32 local_handle, u16 local_port, std::string&
|
||||||
Log_ErrorPrint("Failed to Create Netplay Session!");
|
Log_ErrorPrint("Failed to Create Netplay Session!");
|
||||||
System::ShutdownSystem(false);
|
System::ShutdownSystem(false);
|
||||||
}
|
}
|
||||||
else
|
else if (IsHost())
|
||||||
{
|
{
|
||||||
// Load savestate if available
|
// Load savestate if available and only when you are the host.
|
||||||
|
// the other peers will get state from the host
|
||||||
std::string save = EmuFolders::SaveStates + "/netplay/" + System::GetRunningSerial() + ".sav";
|
std::string save = EmuFolders::SaveStates + "/netplay/" + System::GetRunningSerial() + ".sav";
|
||||||
System::LoadState(save.c_str());
|
System::LoadState(save.c_str());
|
||||||
}
|
}
|
||||||
|
@ -1377,8 +1405,7 @@ bool Netplay::NpAdvFrameCb(void* ctx, int flags)
|
||||||
bool Netplay::NpSaveFrameCb(void* ctx, unsigned char** buffer, int* len, int* checksum, int frame)
|
bool Netplay::NpSaveFrameCb(void* ctx, unsigned char** buffer, int* len, int* checksum, int frame)
|
||||||
{
|
{
|
||||||
SaveStateBuffer our_buffer;
|
SaveStateBuffer our_buffer;
|
||||||
// min size is 2 because otherwise the desync logger doesnt have enough time to dump the state.
|
if (s_save_buffer_pool.empty())
|
||||||
if (s_save_buffer_pool.size() < 2)
|
|
||||||
{
|
{
|
||||||
our_buffer = std::make_unique<System::MemorySaveState>();
|
our_buffer = std::make_unique<System::MemorySaveState>();
|
||||||
}
|
}
|
||||||
|
@ -1465,7 +1492,6 @@ bool Netplay::NpOnEventCb(void* ctx, GGPOEvent* ev)
|
||||||
CurrentFrame(), ev->u.desync.nFrameOfDesync,
|
CurrentFrame(), ev->u.desync.nFrameOfDesync,
|
||||||
CurrentFrame() - ev->u.desync.nFrameOfDesync, ev->u.desync.ourCheckSum,
|
CurrentFrame() - ev->u.desync.nFrameOfDesync, ev->u.desync.ourCheckSum,
|
||||||
ev->u.desync.remoteChecksum));
|
ev->u.desync.remoteChecksum));
|
||||||
GenerateDesyncReport(ev->u.desync.nFrameOfDesync);
|
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
Host::OnNetplayMessage(fmt::format("Netplay Event Code: {}", static_cast<int>(ev->code)));
|
Host::OnNetplayMessage(fmt::format("Netplay Event Code: {}", static_cast<int>(ev->code)));
|
||||||
|
|
|
@ -36,7 +36,7 @@ void ExecuteNetplay();
|
||||||
|
|
||||||
void CollectInput(u32 slot, u32 bind, float value);
|
void CollectInput(u32 slot, u32 bind, float value);
|
||||||
|
|
||||||
void SendMsg(const char* msg);
|
void SendMsg(std::string msg);
|
||||||
|
|
||||||
s32 GetPing();
|
s32 GetPing();
|
||||||
u32 GetMaxPrediction();
|
u32 GetMaxPrediction();
|
||||||
|
|
|
@ -138,7 +138,7 @@ static BIOS::Hash s_bios_hash = {};
|
||||||
static std::string s_running_game_path;
|
static std::string s_running_game_path;
|
||||||
static std::string s_running_game_serial;
|
static std::string s_running_game_serial;
|
||||||
static std::string s_running_game_title;
|
static std::string s_running_game_title;
|
||||||
static bool s_running_bios;
|
static bool s_running_unknown_game;
|
||||||
|
|
||||||
static float s_throttle_frequency = 60.0f;
|
static float s_throttle_frequency = 60.0f;
|
||||||
static float s_target_speed = 1.0f;
|
static float s_target_speed = 1.0f;
|
||||||
|
@ -320,9 +320,9 @@ const std::string& System::GetRunningTitle()
|
||||||
return s_running_game_title;
|
return s_running_game_title;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool System::IsRunningBIOS()
|
bool System::IsRunningUnknownGame()
|
||||||
{
|
{
|
||||||
return s_running_bios;
|
return s_running_unknown_game;
|
||||||
}
|
}
|
||||||
|
|
||||||
const BIOS::ImageInfo* System::GetBIOSImageInfo()
|
const BIOS::ImageInfo* System::GetBIOSImageInfo()
|
||||||
|
@ -958,9 +958,6 @@ void System::ResetSystem()
|
||||||
ResetPerformanceCounters();
|
ResetPerformanceCounters();
|
||||||
ResetThrottler();
|
ResetThrottler();
|
||||||
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "System reset."));
|
Host::AddOSDMessage(Host::TranslateStdString("OSDMessage", "System reset."));
|
||||||
|
|
||||||
// need to clear this here, because of eject disc -> reset.
|
|
||||||
s_running_bios = !s_running_game_path.empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::PauseSystem(bool paused)
|
void System::PauseSystem(bool paused)
|
||||||
|
@ -1239,9 +1236,6 @@ bool System::BootSystem(SystemBootParameters parameters)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Allow controller analog mode for EXEs and PSFs.
|
|
||||||
s_running_bios = s_running_game_path.empty() && exe_boot.empty() && psf_boot.empty();
|
|
||||||
|
|
||||||
UpdateControllers();
|
UpdateControllers();
|
||||||
UpdateMemoryCardTypes();
|
UpdateMemoryCardTypes();
|
||||||
UpdateMultitaps();
|
UpdateMultitaps();
|
||||||
|
@ -1510,7 +1504,7 @@ void System::ClearRunningGame()
|
||||||
s_running_game_serial.clear();
|
s_running_game_serial.clear();
|
||||||
s_running_game_path.clear();
|
s_running_game_path.clear();
|
||||||
s_running_game_title.clear();
|
s_running_game_title.clear();
|
||||||
s_running_bios = false;
|
s_running_unknown_game = false;
|
||||||
s_cheat_list.reset();
|
s_cheat_list.reset();
|
||||||
s_state = State::Shutdown;
|
s_state = State::Shutdown;
|
||||||
|
|
||||||
|
@ -3053,6 +3047,7 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
|
||||||
s_running_game_path.clear();
|
s_running_game_path.clear();
|
||||||
s_running_game_serial.clear();
|
s_running_game_serial.clear();
|
||||||
s_running_game_title.clear();
|
s_running_game_title.clear();
|
||||||
|
s_running_unknown_game = true;
|
||||||
|
|
||||||
if (path && std::strlen(path) > 0)
|
if (path && std::strlen(path) > 0)
|
||||||
{
|
{
|
||||||
|
@ -3070,6 +3065,7 @@ void System::UpdateRunningGame(const char* path, CDImage* image, bool booting)
|
||||||
{
|
{
|
||||||
s_running_game_serial = entry->serial;
|
s_running_game_serial = entry->serial;
|
||||||
s_running_game_title = entry->title;
|
s_running_game_title = entry->title;
|
||||||
|
s_running_unknown_game = false;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
|
@ -184,7 +184,7 @@ const std::string& GetRunningPath();
|
||||||
const std::string& GetRunningSerial();
|
const std::string& GetRunningSerial();
|
||||||
const std::string& GetRunningTitle();
|
const std::string& GetRunningTitle();
|
||||||
|
|
||||||
bool IsRunningBIOS();
|
bool IsRunningUnknownGame();
|
||||||
const BIOS::ImageInfo* GetBIOSImageInfo();
|
const BIOS::ImageInfo* GetBIOSImageInfo();
|
||||||
const BIOS::Hash& GetBIOSHash();
|
const BIOS::Hash& GetBIOSHash();
|
||||||
|
|
||||||
|
|
|
@ -1568,10 +1568,6 @@ void MainWindow::setupAdditionalUi()
|
||||||
m_status_vps_widget->setFixedSize(120, 16);
|
m_status_vps_widget->setFixedSize(120, 16);
|
||||||
m_status_vps_widget->hide();
|
m_status_vps_widget->hide();
|
||||||
|
|
||||||
m_status_ping_widget = new QLabel(m_ui.statusBar);
|
|
||||||
m_status_ping_widget->setFixedSize(110, 16);
|
|
||||||
m_status_ping_widget->hide();
|
|
||||||
|
|
||||||
m_settings_toolbar_menu = new QMenu(m_ui.toolBar);
|
m_settings_toolbar_menu = new QMenu(m_ui.toolBar);
|
||||||
m_settings_toolbar_menu->addAction(m_ui.actionSettings);
|
m_settings_toolbar_menu->addAction(m_ui.actionSettings);
|
||||||
m_settings_toolbar_menu->addAction(m_ui.actionViewGameProperties);
|
m_settings_toolbar_menu->addAction(m_ui.actionViewGameProperties);
|
||||||
|
@ -1777,7 +1773,6 @@ void MainWindow::updateStatusBarWidgetVisibility()
|
||||||
Update(m_status_resolution_widget, s_system_valid && !s_system_paused, 0);
|
Update(m_status_resolution_widget, s_system_valid && !s_system_paused, 0);
|
||||||
Update(m_status_fps_widget, s_system_valid && !s_system_paused, 0);
|
Update(m_status_fps_widget, s_system_valid && !s_system_paused, 0);
|
||||||
Update(m_status_vps_widget, s_system_valid && !s_system_paused, 0);
|
Update(m_status_vps_widget, s_system_valid && !s_system_paused, 0);
|
||||||
Update(m_status_ping_widget, s_system_valid && !s_system_paused && m_netplay_window != nullptr, 0);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::updateWindowTitle()
|
void MainWindow::updateWindowTitle()
|
||||||
|
|
|
@ -90,7 +90,6 @@ public:
|
||||||
ALWAYS_INLINE QLabel* getStatusResolutionWidget() const { return m_status_resolution_widget; }
|
ALWAYS_INLINE QLabel* getStatusResolutionWidget() const { return m_status_resolution_widget; }
|
||||||
ALWAYS_INLINE QLabel* getStatusFPSWidget() const { return m_status_fps_widget; }
|
ALWAYS_INLINE QLabel* getStatusFPSWidget() const { return m_status_fps_widget; }
|
||||||
ALWAYS_INLINE QLabel* getStatusVPSWidget() const { return m_status_vps_widget; }
|
ALWAYS_INLINE QLabel* getStatusVPSWidget() const { return m_status_vps_widget; }
|
||||||
ALWAYS_INLINE QLabel* getStatusPingWidget() const { return m_status_ping_widget; }
|
|
||||||
|
|
||||||
public Q_SLOTS:
|
public Q_SLOTS:
|
||||||
/// Updates debug menu visibility (hides if disabled).
|
/// Updates debug menu visibility (hides if disabled).
|
||||||
|
@ -266,7 +265,6 @@ private:
|
||||||
QLabel* m_status_renderer_widget = nullptr;
|
QLabel* m_status_renderer_widget = nullptr;
|
||||||
QLabel* m_status_fps_widget = nullptr;
|
QLabel* m_status_fps_widget = nullptr;
|
||||||
QLabel* m_status_vps_widget = nullptr;
|
QLabel* m_status_vps_widget = nullptr;
|
||||||
QLabel* m_status_ping_widget = nullptr;
|
|
||||||
QLabel* m_status_resolution_widget = nullptr;
|
QLabel* m_status_resolution_widget = nullptr;
|
||||||
|
|
||||||
QMenu* m_settings_toolbar_menu = nullptr;
|
QMenu* m_settings_toolbar_menu = nullptr;
|
||||||
|
|
|
@ -1079,12 +1079,6 @@ void EmuThread::startNetplaySession(int local_handle, quint16 local_port, const
|
||||||
Q_ARG(quint16, remote_port), Q_ARG(int, input_delay), Q_ARG(const QString&, game_path));
|
Q_ARG(quint16, remote_port), Q_ARG(int, input_delay), Q_ARG(const QString&, game_path));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// disable block linking and disable rewind and runahead during a netplay session
|
|
||||||
g_settings.cpu_recompiler_block_linking = false;
|
|
||||||
g_settings.rewind_enable = false;
|
|
||||||
g_settings.runahead_frames = 0;
|
|
||||||
|
|
||||||
Log_WarningPrintf("Disabling block linking, runahead and rewind due to rollback.");
|
|
||||||
|
|
||||||
auto remAddr = remote_addr.trimmed().toStdString();
|
auto remAddr = remote_addr.trimmed().toStdString();
|
||||||
auto gamePath = game_path.trimmed().toStdString();
|
auto gamePath = game_path.trimmed().toStdString();
|
||||||
|
@ -1101,7 +1095,8 @@ void EmuThread::sendNetplayMessage(const QString& message)
|
||||||
QMetaObject::invokeMethod(this, "sendNetplayMessage", Qt::QueuedConnection, Q_ARG(const QString&, message));
|
QMetaObject::invokeMethod(this, "sendNetplayMessage", Qt::QueuedConnection, Q_ARG(const QString&, message));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
Netplay::SendMsg(message.toStdString().c_str());
|
// TODO REDO NETPLAY UI
|
||||||
|
// Netplay::SendMsg(message.toStdString().c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::stopNetplaySession()
|
void EmuThread::stopNetplaySession()
|
||||||
|
@ -1714,14 +1709,6 @@ void EmuThread::updatePerformanceCounters()
|
||||||
m_last_speed = speed;
|
m_last_speed = speed;
|
||||||
m_last_video_fps = vfps;
|
m_last_video_fps = vfps;
|
||||||
}
|
}
|
||||||
|
|
||||||
const s32 ping = Netplay::GetPing();
|
|
||||||
if (m_last_ping != ping)
|
|
||||||
{
|
|
||||||
QMetaObject::invokeMethod(g_main_window->getStatusPingWidget(), "setText", Qt::QueuedConnection,
|
|
||||||
Q_ARG(const QString&, tr("Netplay Ping: %1 ").arg(ping, 0, 'f', 0)));
|
|
||||||
m_last_ping = ping;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void EmuThread::resetPerformanceCounters()
|
void EmuThread::resetPerformanceCounters()
|
||||||
|
|
|
@ -175,8 +175,10 @@ void ImGuiManager::DrawNetplayChatDialog()
|
||||||
const bool close_chat =
|
const bool close_chat =
|
||||||
send_message || (s_netplay_chat_message.empty() && (ImGui::IsKeyPressed(ImGuiKey_Backspace)) ||
|
send_message || (s_netplay_chat_message.empty() && (ImGui::IsKeyPressed(ImGuiKey_Backspace)) ||
|
||||||
ImGui::IsKeyPressed(ImGuiKey_Escape));
|
ImGui::IsKeyPressed(ImGuiKey_Escape));
|
||||||
|
|
||||||
|
// sending netplay message
|
||||||
if (send_message && !s_netplay_chat_message.empty())
|
if (send_message && !s_netplay_chat_message.empty())
|
||||||
Netplay::SendMsg(s_netplay_chat_message.c_str());
|
Netplay::SendMsg(s_netplay_chat_message);
|
||||||
|
|
||||||
const ImGuiIO& io = ImGui::GetIO();
|
const ImGuiIO& io = ImGui::GetIO();
|
||||||
const ImGuiStyle& style = ImGui::GetStyle();
|
const ImGuiStyle& style = ImGui::GetStyle();
|
||||||
|
|
Loading…
Reference in New Issue