/** @file src/steam_auto_sync_policy.cpp */ #include "steam_auto_sync_policy.h" #include #include namespace { constexpr std::string_view separator {"\x1f", 1}; void mix(std::uint64_t &value, std::string_view text) { // FNV-1a gives deterministic, cheap mixing while retaining path and // metadata changes for the polling watcher. for (const auto c : text) { value ^= static_cast(c); value *= 1099511628211ULL; } } template void mix_number(std::uint64_t &value, T number) { mix(value, std::to_string(number)); mix(value, separator); } void mix_path(std::uint64_t &value, const std::filesystem::path &path) { mix(value, path.generic_string()); mix(value, separator); if (path.empty()) { return; } std::error_code ec; const auto size = std::filesystem::file_size(path, ec); if (!ec) { mix_number(value, size); } else { mix(value, "missing"); } const auto timestamp = std::filesystem::last_write_time(path, ec); if (!ec) { mix_number(value, timestamp.time_since_epoch().count()); } else { mix(value, "unstatable"); } } } // namespace namespace platf::steam::autosync { std::uint64_t source_fingerprint(const std::vector &games) { std::uint64_t result = 1469598103934665603ULL; mix_number(result, games.size()); for (const auto &game : games) { mix_number(result, game.app_id); mix(result, game.stable_id); mix(result, separator); mix(result, game.name); mix(result, separator); mix_path(result, game.install_dir); mix_path(result, game.library_path); mix_path(result, game.icon_path); mix_path(result, game.header_path); mix_path(result, game.portrait_path); mix_path(result, game.boxart_path); mix_path(result, game.artwork_path); mix(result, game.session_artwork_revision); mix(result, separator); mix(result, game.artwork_format); mix(result, separator); mix_number(result, game.state_flags); mix_number(result, game.last_updated); mix_number(result, game.installed); mix_number(result, game.last_played); mix_number(result, game.playtime_minutes); mix(result, game.app_type); mix(result, separator); } return result; } } // namespace platf::steam::autosync