Merge pull request #8861 from JosJuice/netplay-hash

Make netplay's "same game" check more robust
This commit is contained in:
JMC47
2020-09-06 17:14:08 -04:00
committed by GitHub
35 changed files with 523 additions and 157 deletions

View File

@ -5,6 +5,7 @@
#include "UICommon/GameFile.h"
#include <algorithm>
#include <array>
#include <cinttypes>
#include <cstdio>
#include <cstring>
@ -13,11 +14,13 @@
#include <memory>
#include <sstream>
#include <string>
#include <string_view>
#include <tuple>
#include <utility>
#include <vector>
#include <fmt/format.h>
#include <mbedtls/sha1.h>
#include <pugixml.hpp>
#include "Common/ChunkFile.h"
@ -532,7 +535,7 @@ std::vector<DiscIO::Language> GameFile::GetLanguages() const
return languages;
}
std::string GameFile::GetUniqueIdentifier() const
std::string GameFile::GetNetPlayName(const Core::TitleDatabase& title_database) const
{
std::vector<std::string> info;
if (!GetGameID().empty())
@ -540,12 +543,7 @@ std::string GameFile::GetUniqueIdentifier() const
if (GetRevision() != 0)
info.push_back("Revision " + std::to_string(GetRevision()));
std::string name = GetLongName(DiscIO::Language::English);
if (name.empty())
{
// Use the file name as a fallback. Not necessarily consistent, but it's the best we have
name = m_file_name;
}
const std::string name = GetName(title_database);
int disc_number = GetDiscNumber() + 1;
@ -566,6 +564,66 @@ std::string GameFile::GetUniqueIdentifier() const
return name + " (" + ss.str() + ")";
}
std::array<u8, 20> GameFile::GetSyncHash() const
{
std::array<u8, 20> hash{};
if (m_platform == DiscIO::Platform::ELFOrDOL)
{
std::string buffer;
if (File::ReadFileToString(m_file_path, buffer))
mbedtls_sha1_ret(reinterpret_cast<unsigned char*>(buffer.data()), buffer.size(), hash.data());
}
else
{
if (std::unique_ptr<DiscIO::Volume> volume = DiscIO::CreateVolume(m_file_path))
hash = volume->GetSyncHash();
}
return hash;
}
NetPlay::SyncIdentifier GameFile::GetSyncIdentifier() const
{
const u64 dol_elf_size = m_platform == DiscIO::Platform::ELFOrDOL ? m_file_size : 0;
return NetPlay::SyncIdentifier{dol_elf_size, m_game_id, m_revision,
m_disc_number, m_is_datel_disc, GetSyncHash()};
}
NetPlay::SyncIdentifierComparison
GameFile::CompareSyncIdentifier(const NetPlay::SyncIdentifier& sync_identifier) const
{
const bool is_elf_or_dol = m_platform == DiscIO::Platform::ELFOrDOL;
if ((is_elf_or_dol ? m_file_size : 0) != sync_identifier.dol_elf_size)
return NetPlay::SyncIdentifierComparison::DifferentGame;
const auto trim = [](const std::string& str, size_t n) {
return std::string_view(str.data(), std::min(n, str.size()));
};
if (trim(m_game_id, 3) != trim(sync_identifier.game_id, 3))
return NetPlay::SyncIdentifierComparison::DifferentGame;
if (m_disc_number != sync_identifier.disc_number || m_is_datel_disc != sync_identifier.is_datel)
return NetPlay::SyncIdentifierComparison::DifferentGame;
const NetPlay::SyncIdentifierComparison mismatch_result =
is_elf_or_dol || m_is_datel_disc ? NetPlay::SyncIdentifierComparison::DifferentGame :
NetPlay::SyncIdentifierComparison::DifferentVersion;
if (m_game_id != sync_identifier.game_id)
{
const bool game_id_is_title_id = m_game_id.size() > 6 || sync_identifier.game_id.size() > 6;
return game_id_is_title_id ? NetPlay::SyncIdentifierComparison::DifferentGame : mismatch_result;
}
if (m_revision != sync_identifier.revision)
return mismatch_result;
return GetSyncHash() == sync_identifier.sync_hash ? NetPlay::SyncIdentifierComparison::SameGame :
mismatch_result;
}
std::string GameFile::GetWiiFSPath() const
{
ASSERT(DiscIO::IsWii(m_platform));

View File

@ -4,11 +4,13 @@
#pragma once
#include <array>
#include <map>
#include <string>
#include <vector>
#include "Common/CommonTypes.h"
#include "Core/SyncIdentifier.h"
#include "DiscIO/Blob.h"
#include "DiscIO/Enums.h"
@ -80,7 +82,16 @@ public:
u16 GetRevision() const { return m_revision; }
// 0 is the first disc, 1 is the second disc
u8 GetDiscNumber() const { return m_disc_number; }
std::string GetUniqueIdentifier() const;
std::string GetNetPlayName(const Core::TitleDatabase& title_database) const;
// This function is slow
std::array<u8, 20> GetSyncHash() const;
// This function is slow
NetPlay::SyncIdentifier GetSyncIdentifier() const;
// This function is slow if all of game_id, revision, disc_number, is_datel are identical
NetPlay::SyncIdentifierComparison
CompareSyncIdentifier(const NetPlay::SyncIdentifier& sync_identifier) const;
std::string GetWiiFSPath() const;
DiscIO::Region GetRegion() const { return m_region; }
DiscIO::Country GetCountry() const { return m_country; }