Merge pull request #7535 from UnclePunch/synccodes
Netplay: Sync AR and gecko codes with clients
This commit is contained in:
commit
6b7a1ca6d1
|
@ -83,6 +83,7 @@ enum
|
|||
// General lock. Protects codes list and internal log.
|
||||
static std::mutex s_lock;
|
||||
static std::vector<ARCode> s_active_codes;
|
||||
static std::vector<ARCode> s_synced_codes;
|
||||
static std::vector<std::string> s_internal_log;
|
||||
static std::atomic<bool> s_use_internal_log{false};
|
||||
// pointer to the code currently being run, (used by log messages that include the code name)
|
||||
|
@ -123,6 +124,37 @@ void ApplyCodes(const std::vector<ARCode>& codes)
|
|||
s_active_codes.shrink_to_fit();
|
||||
}
|
||||
|
||||
void SetSyncedCodesAsActive()
|
||||
{
|
||||
s_active_codes.clear();
|
||||
s_active_codes.reserve(s_synced_codes.size());
|
||||
s_active_codes = s_synced_codes;
|
||||
}
|
||||
|
||||
void UpdateSyncedCodes(const std::vector<ARCode>& codes)
|
||||
{
|
||||
s_synced_codes.clear();
|
||||
s_synced_codes.reserve(codes.size());
|
||||
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_synced_codes),
|
||||
[](const ARCode& code) { return code.active; });
|
||||
s_synced_codes.shrink_to_fit();
|
||||
}
|
||||
|
||||
std::vector<ARCode> ApplyAndReturnCodes(const std::vector<ARCode>& codes)
|
||||
{
|
||||
if (SConfig::GetInstance().bEnableCheats)
|
||||
{
|
||||
std::lock_guard<std::mutex> guard(s_lock);
|
||||
s_disable_logging = false;
|
||||
s_active_codes.clear();
|
||||
std::copy_if(codes.begin(), codes.end(), std::back_inserter(s_active_codes),
|
||||
[](const ARCode& code) { return code.active; });
|
||||
}
|
||||
s_active_codes.shrink_to_fit();
|
||||
|
||||
return s_active_codes;
|
||||
}
|
||||
|
||||
void AddCode(ARCode code)
|
||||
{
|
||||
if (!SConfig::GetInstance().bEnableCheats)
|
||||
|
|
|
@ -35,6 +35,9 @@ struct ARCode
|
|||
void RunAllActive();
|
||||
|
||||
void ApplyCodes(const std::vector<ARCode>& codes);
|
||||
void SetSyncedCodesAsActive();
|
||||
void UpdateSyncedCodes(const std::vector<ARCode>& codes);
|
||||
std::vector<ARCode> ApplyAndReturnCodes(const std::vector<ARCode>& codes);
|
||||
void AddCode(ARCode new_code);
|
||||
void LoadAndApplyCodes(const IniFile& global_ini, const IniFile& local_ini);
|
||||
|
||||
|
|
|
@ -44,6 +44,7 @@ const ConfigInfo<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE{
|
|||
{System::Main, "Core", "GCIFolderBPathOverride"}, ""};
|
||||
const ConfigInfo<bool> MAIN_GCI_FOLDER_CURRENT_GAME_ONLY{
|
||||
{System::Main, "Core", "GCIFolderCurrentGameOnly"}, false};
|
||||
const ConfigInfo<bool> MAIN_CODE_SYNC_OVERRIDE{{System::Main, "Core", "CheatSyncOverride"}, false};
|
||||
const ConfigInfo<int> MAIN_SLOT_A{{System::Main, "Core", "SlotA"},
|
||||
ExpansionInterface::EXIDEVICE_MEMORYCARDFOLDER};
|
||||
const ConfigInfo<int> MAIN_SLOT_B{{System::Main, "Core", "SlotB"},
|
||||
|
|
|
@ -41,6 +41,7 @@ extern const ConfigInfo<std::string> MAIN_AGP_CART_A_PATH;
|
|||
extern const ConfigInfo<std::string> MAIN_AGP_CART_B_PATH;
|
||||
extern const ConfigInfo<std::string> MAIN_GCI_FOLDER_A_PATH_OVERRIDE;
|
||||
extern const ConfigInfo<std::string> MAIN_GCI_FOLDER_B_PATH_OVERRIDE;
|
||||
extern const ConfigInfo<bool> MAIN_CODE_SYNC_OVERRIDE;
|
||||
extern const ConfigInfo<bool> MAIN_GCI_FOLDER_CURRENT_GAME_ONLY;
|
||||
extern const ConfigInfo<int> MAIN_SLOT_A;
|
||||
extern const ConfigInfo<int> MAIN_SLOT_B;
|
||||
|
|
|
@ -40,6 +40,7 @@ const ConfigInfo<bool> NETPLAY_WRITE_SAVE_SDCARD_DATA{
|
|||
{System::Main, "NetPlay", "WriteSaveSDCardData"}, false};
|
||||
const ConfigInfo<bool> NETPLAY_LOAD_WII_SAVE{{System::Main, "NetPlay", "LoadWiiSave"}, false};
|
||||
const ConfigInfo<bool> NETPLAY_SYNC_SAVES{{System::Main, "NetPlay", "SyncSaves"}, true};
|
||||
const ConfigInfo<bool> NETPLAY_SYNC_CODES{{System::Main, "NetPlay", "SyncCodes"}, true};
|
||||
const ConfigInfo<bool> NETPLAY_RECORD_INPUTS{{System::Main, "NetPlay", "RecordInputs"}, false};
|
||||
const ConfigInfo<bool> NETPLAY_REDUCE_POLLING_RATE{{System::Main, "NetPlay", "ReducePollingRate"},
|
||||
false};
|
||||
|
|
|
@ -36,6 +36,7 @@ extern const ConfigInfo<u32> NETPLAY_CLIENT_BUFFER_SIZE;
|
|||
extern const ConfigInfo<bool> NETPLAY_WRITE_SAVE_SDCARD_DATA;
|
||||
extern const ConfigInfo<bool> NETPLAY_LOAD_WII_SAVE;
|
||||
extern const ConfigInfo<bool> NETPLAY_SYNC_SAVES;
|
||||
extern const ConfigInfo<bool> NETPLAY_SYNC_CODES;
|
||||
extern const ConfigInfo<bool> NETPLAY_RECORD_INPUTS;
|
||||
extern const ConfigInfo<bool> NETPLAY_REDUCE_POLLING_RATE;
|
||||
extern const ConfigInfo<bool> NETPLAY_STRICT_SETTINGS_SYNC;
|
||||
|
|
|
@ -106,6 +106,13 @@ public:
|
|||
|
||||
layer->Set(Config::MAIN_GCI_FOLDER_CURRENT_GAME_ONLY, true);
|
||||
}
|
||||
|
||||
// Check To Override Client's Cheat Codes
|
||||
if (m_settings.m_SyncCodes && !m_settings.m_IsHosting)
|
||||
{
|
||||
// Raise flag to use host's codes
|
||||
layer->Set(Config::MAIN_CODE_SYNC_OVERRIDE, true);
|
||||
}
|
||||
}
|
||||
|
||||
void Save(Config::Layer* layer) override
|
||||
|
|
|
@ -61,6 +61,7 @@ enum class Installation
|
|||
static Installation s_code_handler_installed = Installation::Uninstalled;
|
||||
// the currently active codes
|
||||
static std::vector<GeckoCode> s_active_codes;
|
||||
static std::vector<GeckoCode> s_synced_codes;
|
||||
static std::mutex s_active_codes_lock;
|
||||
|
||||
void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
|
||||
|
@ -79,6 +80,40 @@ void SetActiveCodes(const std::vector<GeckoCode>& gcodes)
|
|||
s_code_handler_installed = Installation::Uninstalled;
|
||||
}
|
||||
|
||||
void SetSyncedCodesAsActive()
|
||||
{
|
||||
s_active_codes.clear();
|
||||
s_active_codes.reserve(s_synced_codes.size());
|
||||
s_active_codes = s_synced_codes;
|
||||
}
|
||||
|
||||
void UpdateSyncedCodes(const std::vector<GeckoCode>& gcodes)
|
||||
{
|
||||
s_synced_codes.clear();
|
||||
s_synced_codes.reserve(gcodes.size());
|
||||
std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_synced_codes),
|
||||
[](const GeckoCode& code) { return code.enabled; });
|
||||
s_synced_codes.shrink_to_fit();
|
||||
}
|
||||
|
||||
std::vector<GeckoCode> SetAndReturnActiveCodes(const std::vector<GeckoCode>& gcodes)
|
||||
{
|
||||
std::lock_guard<std::mutex> lk(s_active_codes_lock);
|
||||
|
||||
s_active_codes.clear();
|
||||
if (SConfig::GetInstance().bEnableCheats)
|
||||
{
|
||||
s_active_codes.reserve(gcodes.size());
|
||||
std::copy_if(gcodes.begin(), gcodes.end(), std::back_inserter(s_active_codes),
|
||||
[](const GeckoCode& code) { return code.enabled; });
|
||||
}
|
||||
s_active_codes.shrink_to_fit();
|
||||
|
||||
s_code_handler_installed = Installation::Uninstalled;
|
||||
|
||||
return s_active_codes;
|
||||
}
|
||||
|
||||
// Requires s_active_codes_lock
|
||||
// NOTE: Refer to "codehandleronly.s" from Gecko OS.
|
||||
static Installation InstallCodeHandlerLocked()
|
||||
|
|
|
@ -59,6 +59,9 @@ constexpr u32 HLE_TRAMPOLINE_ADDRESS = INSTALLER_END_ADDRESS - 4;
|
|||
constexpr u32 MAGIC_GAMEID = 0xD01F1BAD;
|
||||
|
||||
void SetActiveCodes(const std::vector<GeckoCode>& gcodes);
|
||||
void SetSyncedCodesAsActive();
|
||||
void UpdateSyncedCodes(const std::vector<GeckoCode>& gcodes);
|
||||
std::vector<GeckoCode> SetAndReturnActiveCodes(const std::vector<GeckoCode>& gcodes);
|
||||
void RunCodeHandler();
|
||||
void Shutdown();
|
||||
void DoState(PointerWrap&);
|
||||
|
|
|
@ -33,8 +33,10 @@
|
|||
#include "Common/StringUtil.h"
|
||||
#include "Common/Timer.h"
|
||||
#include "Common/Version.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/HW/EXI/EXI_DeviceIPL.h"
|
||||
#include "Core/HW/SI/SI.h"
|
||||
#include "Core/HW/SI/SI_DeviceGCController.h"
|
||||
|
@ -550,6 +552,7 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
|
||||
packet >> m_net_settings.m_SyncSaveData;
|
||||
packet >> m_net_settings.m_SaveDataRegion;
|
||||
packet >> m_net_settings.m_SyncCodes;
|
||||
|
||||
m_net_settings.m_IsHosting = m_local_player->IsHost();
|
||||
m_net_settings.m_HostInputAuthority = m_host_input_authority;
|
||||
|
@ -651,6 +654,9 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
{
|
||||
case SYNC_SAVE_DATA_NOTIFY:
|
||||
{
|
||||
if (m_local_player->IsHost())
|
||||
return 0;
|
||||
|
||||
packet >> m_sync_save_data_count;
|
||||
m_sync_save_data_success_count = 0;
|
||||
|
||||
|
@ -830,6 +836,163 @@ unsigned int NetPlayClient::OnData(sf::Packet& packet)
|
|||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_SYNC_CODES:
|
||||
{
|
||||
// Recieve Data Packet
|
||||
MessageId sub_id;
|
||||
packet >> sub_id;
|
||||
|
||||
// Check Which Operation to Perform with This Packet
|
||||
switch (sub_id)
|
||||
{
|
||||
case SYNC_CODES_NOTIFY:
|
||||
{
|
||||
// Set both codes as unsynced
|
||||
m_sync_gecko_codes_complete = false;
|
||||
m_sync_ar_codes_complete = false;
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_CODES_NOTIFY_GECKO:
|
||||
{
|
||||
// Return if this is the host
|
||||
if (m_local_player->IsHost())
|
||||
return 0;
|
||||
|
||||
// Receive Number of Codelines to Receive
|
||||
packet >> m_sync_gecko_codes_count;
|
||||
|
||||
m_sync_gecko_codes_success_count = 0;
|
||||
|
||||
NOTICE_LOG(ACTIONREPLAY, "Receiving %d Gecko codelines", m_sync_gecko_codes_count);
|
||||
|
||||
// Check if no codes to sync, if so return as finished
|
||||
if (m_sync_gecko_codes_count == 0)
|
||||
{
|
||||
m_sync_gecko_codes_complete = true;
|
||||
SyncCodeResponse(true);
|
||||
}
|
||||
else
|
||||
m_dialog->AppendChat(GetStringT("Synchronizing gecko codes..."));
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_CODES_DATA_GECKO:
|
||||
{
|
||||
// Return if this is the host
|
||||
if (m_local_player->IsHost())
|
||||
return 0;
|
||||
|
||||
// Create a synced code vector
|
||||
std::vector<Gecko::GeckoCode> synced_codes;
|
||||
// Create a GeckoCode
|
||||
Gecko::GeckoCode gcode;
|
||||
gcode = Gecko::GeckoCode();
|
||||
// Initialize gcode
|
||||
gcode.name = "Synced Codes";
|
||||
gcode.enabled = true;
|
||||
|
||||
// Receive code contents from packet
|
||||
for (int i = 0; i < m_sync_gecko_codes_count; i++)
|
||||
{
|
||||
Gecko::GeckoCode::Code new_code;
|
||||
packet >> new_code.address;
|
||||
packet >> new_code.data;
|
||||
|
||||
NOTICE_LOG(ACTIONREPLAY, "Received %08x %08x", new_code.address, new_code.data);
|
||||
|
||||
gcode.codes.push_back(std::move(new_code));
|
||||
|
||||
if (++m_sync_gecko_codes_success_count >= m_sync_gecko_codes_count)
|
||||
{
|
||||
m_sync_gecko_codes_complete = true;
|
||||
SyncCodeResponse(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Add gcode containing all codes to Gecko Code vector
|
||||
synced_codes.push_back(std::move(gcode));
|
||||
|
||||
// Clear Vector if received 0 codes (match host's end when using no codes)
|
||||
if (m_sync_gecko_codes_count == 0)
|
||||
synced_codes.clear();
|
||||
|
||||
// Copy this to the vector located in GeckoCode.cpp
|
||||
Gecko::UpdateSyncedCodes(synced_codes);
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_CODES_NOTIFY_AR:
|
||||
{
|
||||
// Return if this is the host
|
||||
if (m_local_player->IsHost())
|
||||
return 0;
|
||||
|
||||
// Receive Number of Codelines to Receive
|
||||
packet >> m_sync_ar_codes_count;
|
||||
|
||||
m_sync_ar_codes_success_count = 0;
|
||||
|
||||
NOTICE_LOG(ACTIONREPLAY, "Receiving %d AR codelines", m_sync_ar_codes_count);
|
||||
|
||||
// Check if no codes to sync, if so return as finished
|
||||
if (m_sync_ar_codes_count == 0)
|
||||
{
|
||||
m_sync_ar_codes_complete = true;
|
||||
SyncCodeResponse(true);
|
||||
}
|
||||
else
|
||||
m_dialog->AppendChat(GetStringT("Synchronizing AR codes..."));
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_CODES_DATA_AR:
|
||||
{
|
||||
// Return if this is the host
|
||||
if (m_local_player->IsHost())
|
||||
return 0;
|
||||
|
||||
// Create a synced code vector
|
||||
std::vector<ActionReplay::ARCode> synced_codes;
|
||||
// Create an ARCode
|
||||
ActionReplay::ARCode arcode;
|
||||
arcode = ActionReplay::ARCode();
|
||||
// Initialize arcode
|
||||
arcode.name = "Synced Codes";
|
||||
arcode.active = true;
|
||||
|
||||
// Receive code contents from packet
|
||||
for (int i = 0; i < m_sync_ar_codes_count; i++)
|
||||
{
|
||||
ActionReplay::AREntry new_code;
|
||||
packet >> new_code.cmd_addr;
|
||||
packet >> new_code.value;
|
||||
|
||||
NOTICE_LOG(ACTIONREPLAY, "Received %08x %08x", new_code.cmd_addr, new_code.value);
|
||||
arcode.ops.push_back(new_code);
|
||||
|
||||
if (++m_sync_ar_codes_success_count >= m_sync_ar_codes_count)
|
||||
{
|
||||
m_sync_ar_codes_complete = true;
|
||||
SyncCodeResponse(true);
|
||||
}
|
||||
}
|
||||
|
||||
// Add arcode containing all codes to AR Code vector
|
||||
synced_codes.push_back(std::move(arcode));
|
||||
|
||||
// Clear Vector if received 0 codes (match host's end when using no codes)
|
||||
if (m_sync_ar_codes_count == 0)
|
||||
synced_codes.clear();
|
||||
|
||||
// Copy this to the vector located in ActionReplay.cpp
|
||||
ActionReplay::UpdateSyncedCodes(synced_codes);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_COMPUTE_MD5:
|
||||
{
|
||||
std::string file_identifier;
|
||||
|
@ -1200,6 +1363,34 @@ void NetPlayClient::SyncSaveDataResponse(const bool success)
|
|||
}
|
||||
}
|
||||
|
||||
void NetPlayClient::SyncCodeResponse(const bool success)
|
||||
{
|
||||
// If something failed, immediately report back that code sync failed
|
||||
if (!success)
|
||||
{
|
||||
m_dialog->AppendChat(GetStringT("Error processing Codes."));
|
||||
|
||||
sf::Packet response_packet;
|
||||
response_packet << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
response_packet << static_cast<MessageId>(SYNC_CODES_FAILURE);
|
||||
|
||||
Send(response_packet);
|
||||
return;
|
||||
}
|
||||
|
||||
// If both gecko and AR codes have completely finished transferring, report back as successful
|
||||
if (m_sync_gecko_codes_complete && m_sync_ar_codes_complete)
|
||||
{
|
||||
m_dialog->AppendChat(GetStringT("Codes received!"));
|
||||
|
||||
sf::Packet response_packet;
|
||||
response_packet << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
response_packet << static_cast<MessageId>(SYNC_CODES_SUCCESS);
|
||||
|
||||
Send(response_packet);
|
||||
}
|
||||
}
|
||||
|
||||
bool NetPlayClient::DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path)
|
||||
{
|
||||
u64 file_size = Common::PacketReadU64(packet);
|
||||
|
|
|
@ -192,6 +192,7 @@ private:
|
|||
void SendStopGamePacket();
|
||||
|
||||
void SyncSaveDataResponse(bool success);
|
||||
void SyncCodeResponse(bool success);
|
||||
bool DecompressPacketIntoFile(sf::Packet& packet, const std::string& file_path);
|
||||
std::optional<std::vector<u8>> DecompressPacketIntoBuffer(sf::Packet& packet);
|
||||
|
||||
|
@ -226,6 +227,12 @@ private:
|
|||
Common::Event m_first_pad_status_received_event;
|
||||
u8 m_sync_save_data_count = 0;
|
||||
u8 m_sync_save_data_success_count = 0;
|
||||
u16 m_sync_gecko_codes_count = 0;
|
||||
u16 m_sync_gecko_codes_success_count = 0;
|
||||
bool m_sync_gecko_codes_complete = false;
|
||||
u16 m_sync_ar_codes_count = 0;
|
||||
u16 m_sync_ar_codes_success_count = 0;
|
||||
bool m_sync_ar_codes_complete = false;
|
||||
|
||||
u64 m_initial_rtc = 0;
|
||||
u32 m_timebase_frame = 0;
|
||||
|
|
|
@ -77,6 +77,7 @@ struct NetSettings
|
|||
bool m_DeferEFBCopies;
|
||||
bool m_StrictSettingsSync;
|
||||
bool m_SyncSaveData;
|
||||
bool m_SyncCodes;
|
||||
std::string m_SaveDataRegion;
|
||||
bool m_IsHosting;
|
||||
bool m_HostInputAuthority;
|
||||
|
@ -145,6 +146,7 @@ enum
|
|||
|
||||
NP_MSG_SYNC_GC_SRAM = 0xF0,
|
||||
NP_MSG_SYNC_SAVE_DATA = 0xF1,
|
||||
NP_MSG_SYNC_CODES = 0xF2,
|
||||
};
|
||||
|
||||
enum
|
||||
|
@ -164,6 +166,17 @@ enum
|
|||
SYNC_SAVE_DATA_WII = 5
|
||||
};
|
||||
|
||||
enum
|
||||
{
|
||||
SYNC_CODES_NOTIFY = 0,
|
||||
SYNC_CODES_NOTIFY_GECKO = 1,
|
||||
SYNC_CODES_NOTIFY_AR = 2,
|
||||
SYNC_CODES_DATA_GECKO = 3,
|
||||
SYNC_CODES_DATA_AR = 4,
|
||||
SYNC_CODES_SUCCESS = 5,
|
||||
SYNC_CODES_FAILURE = 6,
|
||||
};
|
||||
|
||||
constexpr u32 NETPLAY_LZO_IN_LEN = 1024 * 64;
|
||||
constexpr u32 NETPLAY_LZO_OUT_LEN = NETPLAY_LZO_IN_LEN + (NETPLAY_LZO_IN_LEN / 16) + 64 + 3;
|
||||
|
||||
|
|
|
@ -29,9 +29,13 @@
|
|||
#include "Common/StringUtil.h"
|
||||
#include "Common/UPnP.h"
|
||||
#include "Common/Version.h"
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/Config/NetplaySettings.h"
|
||||
#include "Core/ConfigLoaders/GameConfigLoader.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
#include "Core/HW/GCMemcard/GCMemcardDirectory.h"
|
||||
#include "Core/HW/GCMemcard/GCMemcardRaw.h"
|
||||
#include "Core/HW/Sram.h"
|
||||
|
@ -852,8 +856,11 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||
m_save_data_synced_players++;
|
||||
if (m_save_data_synced_players >= m_players.size() - 1)
|
||||
{
|
||||
m_dialog->AppendChat(GetStringT("All players synchronized."));
|
||||
StartGame();
|
||||
m_dialog->AppendChat(GetStringT("All players saves synchronized."));
|
||||
|
||||
// Saves are synced, check if codes are as well and attempt to start the game
|
||||
m_saves_synced = true;
|
||||
CheckSyncAndStartGame();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -877,6 +884,48 @@ unsigned int NetPlayServer::OnData(sf::Packet& packet, Client& player)
|
|||
}
|
||||
break;
|
||||
|
||||
case NP_MSG_SYNC_CODES:
|
||||
{
|
||||
// Receive Status of Code Sync
|
||||
MessageId sub_id;
|
||||
packet >> sub_id;
|
||||
|
||||
// Check If Code Sync was successful or not
|
||||
switch (sub_id)
|
||||
{
|
||||
case SYNC_CODES_SUCCESS:
|
||||
{
|
||||
if (m_start_pending)
|
||||
{
|
||||
if (++m_codes_synced_players >= m_players.size() - 1)
|
||||
{
|
||||
m_dialog->AppendChat(GetStringT("All players' codes synchronized."));
|
||||
|
||||
// Codes are synced, check if saves are as well and attempt to start the game
|
||||
m_codes_synced = true;
|
||||
CheckSyncAndStartGame();
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case SYNC_CODES_FAILURE:
|
||||
{
|
||||
m_dialog->AppendChat(StringFromFormat(GetStringT("%s failed to synchronize codes.").c_str(),
|
||||
player.name.c_str()));
|
||||
m_start_pending = false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlertT(
|
||||
"Unknown SYNC_GECKO_CODES message with id:%d received from player:%d Kicking player!",
|
||||
sub_id, player.pid);
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
PanicAlertT("Unknown message with id:%d received from player:%d Kicking player!", mid,
|
||||
player.pid);
|
||||
|
@ -966,17 +1015,34 @@ bool NetPlayServer::DoAllPlayersHaveIPLDump() const
|
|||
// called from ---GUI--- thread
|
||||
bool NetPlayServer::RequestStartGame()
|
||||
{
|
||||
bool start_now = true;
|
||||
|
||||
if (m_settings.m_SyncSaveData && m_players.size() > 1)
|
||||
{
|
||||
start_now = false;
|
||||
m_start_pending = true;
|
||||
if (!SyncSaveData())
|
||||
{
|
||||
PanicAlertT("Error synchronizing save data!");
|
||||
m_start_pending = false;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_start_pending = true;
|
||||
}
|
||||
else
|
||||
|
||||
// Check To Send Codes to Clients
|
||||
if (m_settings.m_SyncCodes && m_players.size() > 1)
|
||||
{
|
||||
start_now = false;
|
||||
m_start_pending = true;
|
||||
if (!SyncCodes())
|
||||
{
|
||||
PanicAlertT("Error synchronizing save gecko codes!");
|
||||
m_start_pending = false;
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (start_now)
|
||||
{
|
||||
return StartGame();
|
||||
}
|
||||
|
@ -1065,6 +1131,7 @@ bool NetPlayServer::StartGame()
|
|||
spac << initial_rtc;
|
||||
spac << m_settings.m_SyncSaveData;
|
||||
spac << region;
|
||||
spac << m_settings.m_SyncCodes;
|
||||
|
||||
SendAsyncToClients(std::move(spac));
|
||||
|
||||
|
@ -1077,6 +1144,9 @@ bool NetPlayServer::StartGame()
|
|||
// called from ---GUI--- thread
|
||||
bool NetPlayServer::SyncSaveData()
|
||||
{
|
||||
// We're about to sync saves, so set m_saves_synced to false (waits to start game)
|
||||
m_saves_synced = false;
|
||||
|
||||
m_save_data_synced_players = 0;
|
||||
|
||||
u8 save_count = 0;
|
||||
|
@ -1253,6 +1323,150 @@ bool NetPlayServer::SyncSaveData()
|
|||
return true;
|
||||
}
|
||||
|
||||
bool NetPlayServer::SyncCodes()
|
||||
{
|
||||
// Sync Codes is ticked, so set m_codes_synced to false
|
||||
m_codes_synced = false;
|
||||
|
||||
// Get Game Path
|
||||
const auto game = m_dialog->FindGameFile(m_selected_game);
|
||||
if (game == nullptr)
|
||||
{
|
||||
PanicAlertT("Selected game doesn't exist in game list!");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Find all INI files
|
||||
const auto game_id = game->GetGameID();
|
||||
const auto revision = game->GetRevision();
|
||||
IniFile globalIni;
|
||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
||||
globalIni.Load(File::GetSysDirectory() + GAMESETTINGS_DIR DIR_SEP + filename, true);
|
||||
IniFile localIni;
|
||||
for (const std::string& filename : ConfigLoaders::GetGameIniFilenames(game_id, revision))
|
||||
localIni.Load(File::GetUserPath(D_GAMESETTINGS_IDX) + filename, true);
|
||||
|
||||
// Initialize Number of Synced Players
|
||||
m_codes_synced_players = 0;
|
||||
|
||||
// Notify Clients of Incoming Code Sync
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
pac << static_cast<MessageId>(SYNC_CODES_NOTIFY);
|
||||
SendAsyncToClients(std::move(pac));
|
||||
}
|
||||
// Sync Gecko Codes
|
||||
{
|
||||
// Create a Gecko Code Vector with just the active codes
|
||||
std::vector<Gecko::GeckoCode> s_active_codes =
|
||||
Gecko::SetAndReturnActiveCodes(Gecko::LoadCodes(globalIni, localIni));
|
||||
|
||||
// Determine Codelist Size
|
||||
u16 codelines = 0;
|
||||
for (const Gecko::GeckoCode& active_code : s_active_codes)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "Indexing %s", active_code.name.c_str());
|
||||
for (const Gecko::GeckoCode::Code& code : active_code.codes)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "%08x %08x", code.address, code.data);
|
||||
codelines++;
|
||||
}
|
||||
}
|
||||
|
||||
// Output codelines to send
|
||||
NOTICE_LOG(ACTIONREPLAY, "Sending %d Gecko codelines", codelines);
|
||||
|
||||
// Send initial packet. Notify of the sync operation and total number of lines being sent.
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
pac << static_cast<MessageId>(SYNC_CODES_NOTIFY_GECKO);
|
||||
pac << codelines;
|
||||
SendAsyncToClients(std::move(pac));
|
||||
}
|
||||
|
||||
// Send entire codeset in the second packet
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
pac << static_cast<MessageId>(SYNC_CODES_DATA_GECKO);
|
||||
// Iterate through the active code vector and send each codeline
|
||||
for (const Gecko::GeckoCode& active_code : s_active_codes)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "Sending %s", active_code.name.c_str());
|
||||
for (const Gecko::GeckoCode::Code& code : active_code.codes)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "%08x %08x", code.address, code.data);
|
||||
pac << code.address;
|
||||
pac << code.data;
|
||||
}
|
||||
}
|
||||
SendAsyncToClients(std::move(pac));
|
||||
}
|
||||
}
|
||||
|
||||
// Sync AR Codes
|
||||
{
|
||||
// Create an AR Code Vector with just the active codes
|
||||
std::vector<ActionReplay::ARCode> s_active_codes =
|
||||
ActionReplay::ApplyAndReturnCodes(ActionReplay::LoadCodes(globalIni, localIni));
|
||||
|
||||
// Determine Codelist Size
|
||||
u16 codelines = 0;
|
||||
for (const ActionReplay::ARCode& active_code : s_active_codes)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "Indexing %s", active_code.name.c_str());
|
||||
for (const ActionReplay::AREntry& op : active_code.ops)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "%08x %08x", op.cmd_addr, op.value);
|
||||
codelines++;
|
||||
}
|
||||
}
|
||||
|
||||
// Output codelines to send
|
||||
NOTICE_LOG(ACTIONREPLAY, "Sending %d AR codelines", codelines);
|
||||
|
||||
// Send initial packet. Notify of the sync operation and total number of lines being sent.
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
pac << static_cast<MessageId>(SYNC_CODES_NOTIFY_AR);
|
||||
pac << codelines;
|
||||
SendAsyncToClients(std::move(pac));
|
||||
}
|
||||
|
||||
// Send entire codeset in the second packet
|
||||
{
|
||||
sf::Packet pac;
|
||||
pac << static_cast<MessageId>(NP_MSG_SYNC_CODES);
|
||||
pac << static_cast<MessageId>(SYNC_CODES_DATA_AR);
|
||||
// Iterate through the active code vector and send each codeline
|
||||
for (const ActionReplay::ARCode& active_code : s_active_codes)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "Sending %s", active_code.name.c_str());
|
||||
for (const ActionReplay::AREntry& op : active_code.ops)
|
||||
{
|
||||
NOTICE_LOG(ACTIONREPLAY, "%08x %08x", op.cmd_addr, op.value);
|
||||
pac << op.cmd_addr;
|
||||
pac << op.value;
|
||||
}
|
||||
}
|
||||
SendAsyncToClients(std::move(pac));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void NetPlayServer::CheckSyncAndStartGame()
|
||||
{
|
||||
if (m_saves_synced && m_codes_synced)
|
||||
{
|
||||
StartGame();
|
||||
}
|
||||
}
|
||||
|
||||
bool NetPlayServer::CompressFileIntoPacket(const std::string& file_path, sf::Packet& packet)
|
||||
{
|
||||
File::IOFile file(file_path, "rb");
|
||||
|
|
|
@ -85,6 +85,8 @@ private:
|
|||
};
|
||||
|
||||
bool SyncSaveData();
|
||||
bool SyncCodes();
|
||||
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(PadMapping map, bool state);
|
||||
|
@ -116,6 +118,9 @@ private:
|
|||
PadMappingArray m_pad_map;
|
||||
PadMappingArray m_wiimote_map;
|
||||
unsigned int m_save_data_synced_players = 0;
|
||||
unsigned int m_codes_synced_players = 0;
|
||||
bool m_saves_synced = true;
|
||||
bool m_codes_synced = true;
|
||||
bool m_start_pending = false;
|
||||
bool m_host_input_authority = false;
|
||||
|
||||
|
|
|
@ -21,6 +21,7 @@
|
|||
#include "Common/StringUtil.h"
|
||||
|
||||
#include "Core/ActionReplay.h"
|
||||
#include "Core/Config/MainSettings.h"
|
||||
#include "Core/ConfigManager.h"
|
||||
#include "Core/GeckoCode.h"
|
||||
#include "Core/GeckoCodeConfig.h"
|
||||
|
@ -164,9 +165,18 @@ void LoadPatches()
|
|||
IniFile localIni = SConfig::GetInstance().LoadLocalGameIni();
|
||||
|
||||
LoadPatchSection("OnFrame", s_on_frame, globalIni, localIni);
|
||||
ActionReplay::LoadAndApplyCodes(globalIni, localIni);
|
||||
|
||||
Gecko::SetActiveCodes(Gecko::LoadCodes(globalIni, localIni));
|
||||
// Check if I'm syncing Codes
|
||||
if (Config::Get(Config::MAIN_CODE_SYNC_OVERRIDE))
|
||||
{
|
||||
Gecko::SetSyncedCodesAsActive();
|
||||
ActionReplay::SetSyncedCodesAsActive();
|
||||
}
|
||||
else
|
||||
{
|
||||
Gecko::SetActiveCodes(Gecko::LoadCodes(globalIni, localIni));
|
||||
ActionReplay::LoadAndApplyCodes(globalIni, localIni);
|
||||
}
|
||||
|
||||
LoadSpeedhacks("Speedhacks", merged);
|
||||
}
|
||||
|
|
|
@ -77,6 +77,7 @@ NetPlayDialog::NetPlayDialog(QWidget* parent)
|
|||
const bool write_save_sdcard_data = Config::Get(Config::NETPLAY_WRITE_SAVE_SDCARD_DATA);
|
||||
const bool load_wii_save = Config::Get(Config::NETPLAY_LOAD_WII_SAVE);
|
||||
const bool sync_saves = Config::Get(Config::NETPLAY_SYNC_SAVES);
|
||||
const bool sync_codes = Config::Get(Config::NETPLAY_SYNC_CODES);
|
||||
const bool record_inputs = Config::Get(Config::NETPLAY_RECORD_INPUTS);
|
||||
const bool reduce_polling_rate = Config::Get(Config::NETPLAY_REDUCE_POLLING_RATE);
|
||||
const bool strict_settings_sync = Config::Get(Config::NETPLAY_STRICT_SETTINGS_SYNC);
|
||||
|
@ -86,6 +87,7 @@ NetPlayDialog::NetPlayDialog(QWidget* parent)
|
|||
m_save_sd_box->setChecked(write_save_sdcard_data);
|
||||
m_load_wii_box->setChecked(load_wii_save);
|
||||
m_sync_save_data_box->setChecked(sync_saves);
|
||||
m_sync_codes_box->setChecked(sync_codes);
|
||||
m_record_input_box->setChecked(record_inputs);
|
||||
m_reduce_polling_rate_box->setChecked(reduce_polling_rate);
|
||||
m_strict_settings_sync_box->setChecked(strict_settings_sync);
|
||||
|
@ -121,6 +123,7 @@ void NetPlayDialog::CreateMainLayout()
|
|||
m_reduce_polling_rate_box = new QCheckBox(tr("Reduce Polling Rate"));
|
||||
m_strict_settings_sync_box = new QCheckBox(tr("Strict Settings Sync"));
|
||||
m_host_input_authority_box = new QCheckBox(tr("Host Input Authority"));
|
||||
m_sync_codes_box = new QCheckBox(tr("Sync Codes"));
|
||||
m_buffer_label = new QLabel(tr("Buffer:"));
|
||||
m_quit_button = new QPushButton(tr("Quit"));
|
||||
m_splitter = new QSplitter(Qt::Horizontal);
|
||||
|
@ -129,6 +132,7 @@ void NetPlayDialog::CreateMainLayout()
|
|||
m_game_button->setAutoDefault(false);
|
||||
|
||||
m_sync_save_data_box->setChecked(true);
|
||||
m_sync_codes_box->setChecked(true);
|
||||
|
||||
auto* default_button = new QAction(tr("Calculate MD5 hash"), m_md5_button);
|
||||
|
||||
|
@ -164,6 +168,9 @@ void NetPlayDialog::CreateMainLayout()
|
|||
tr("This will sync additional graphics settings, and force everyone to the same internal "
|
||||
"resolution.\nMay prevent desync in some games that use EFB reads. Please ensure everyone "
|
||||
"uses the same video backend."));
|
||||
m_sync_codes_box->setToolTip(tr("This will sync the client's AR and Gecko Codes with the host's. "
|
||||
"The client will be sent the codes regardless "
|
||||
"\nof whether or not the client has them."));
|
||||
m_host_input_authority_box->setToolTip(
|
||||
tr("This gives the host control over when inputs are sent to the game, effectively "
|
||||
"decoupling players from each other in terms of buffering.\nThis allows players to have "
|
||||
|
@ -190,6 +197,7 @@ void NetPlayDialog::CreateMainLayout()
|
|||
options_boxes->addWidget(m_save_sd_box);
|
||||
options_boxes->addWidget(m_load_wii_box);
|
||||
options_boxes->addWidget(m_sync_save_data_box);
|
||||
options_boxes->addWidget(m_sync_codes_box);
|
||||
options_boxes->addWidget(m_record_input_box);
|
||||
options_boxes->addWidget(m_reduce_polling_rate_box);
|
||||
options_boxes->addWidget(m_strict_settings_sync_box);
|
||||
|
@ -335,6 +343,7 @@ void NetPlayDialog::ConnectWidgets()
|
|||
connect(m_save_sd_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_load_wii_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_sync_save_data_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_sync_codes_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_record_input_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_reduce_polling_rate_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
connect(m_strict_settings_sync_box, &QCheckBox::stateChanged, this, &NetPlayDialog::SaveSettings);
|
||||
|
@ -451,6 +460,7 @@ void NetPlayDialog::OnStart()
|
|||
settings.m_DeferEFBCopies = Config::Get(Config::GFX_HACK_DEFER_EFB_COPIES);
|
||||
settings.m_StrictSettingsSync = m_strict_settings_sync_box->isChecked();
|
||||
settings.m_SyncSaveData = m_sync_save_data_box->isChecked();
|
||||
settings.m_SyncCodes = m_sync_codes_box->isChecked();
|
||||
|
||||
// Unload GameINI to restore things to normal
|
||||
Config::RemoveLayer(Config::LayerType::GlobalGame);
|
||||
|
@ -499,6 +509,7 @@ void NetPlayDialog::show(std::string nickname, bool use_traversal)
|
|||
m_save_sd_box->setHidden(!is_hosting);
|
||||
m_load_wii_box->setHidden(!is_hosting);
|
||||
m_sync_save_data_box->setHidden(!is_hosting);
|
||||
m_sync_codes_box->setHidden(!is_hosting);
|
||||
m_reduce_polling_rate_box->setHidden(!is_hosting);
|
||||
m_strict_settings_sync_box->setHidden(!is_hosting);
|
||||
m_host_input_authority_box->setHidden(!is_hosting);
|
||||
|
@ -772,6 +783,7 @@ void NetPlayDialog::SetOptionsEnabled(bool enabled)
|
|||
m_load_wii_box->setEnabled(enabled);
|
||||
m_save_sd_box->setEnabled(enabled);
|
||||
m_sync_save_data_box->setEnabled(enabled);
|
||||
m_sync_codes_box->setEnabled(enabled);
|
||||
m_assign_ports_button->setEnabled(enabled);
|
||||
m_reduce_polling_rate_box->setEnabled(enabled);
|
||||
m_strict_settings_sync_box->setEnabled(enabled);
|
||||
|
@ -965,6 +977,7 @@ void NetPlayDialog::SaveSettings()
|
|||
Config::SetBase(Config::NETPLAY_WRITE_SAVE_SDCARD_DATA, m_save_sd_box->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_LOAD_WII_SAVE, m_load_wii_box->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_SYNC_SAVES, m_sync_save_data_box->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_SYNC_CODES, m_sync_codes_box->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_RECORD_INPUTS, m_record_input_box->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_REDUCE_POLLING_RATE, m_reduce_polling_rate_box->isChecked());
|
||||
Config::SetBase(Config::NETPLAY_STRICT_SETTINGS_SYNC, m_strict_settings_sync_box->isChecked());
|
||||
|
|
|
@ -110,6 +110,7 @@ private:
|
|||
QCheckBox* m_save_sd_box;
|
||||
QCheckBox* m_load_wii_box;
|
||||
QCheckBox* m_sync_save_data_box;
|
||||
QCheckBox* m_sync_codes_box;
|
||||
QCheckBox* m_record_input_box;
|
||||
QCheckBox* m_reduce_polling_rate_box;
|
||||
QCheckBox* m_strict_settings_sync_box;
|
||||
|
|
Loading…
Reference in New Issue