share leaderboards scores with connected players, adjust players ranks locally, and sort entries as needed by the game

This commit is contained in:
otavepto 2024-03-30 08:00:05 +02:00 committed by otavepto
parent c17cb8a4f7
commit d2f23fbea5
6 changed files with 677 additions and 216 deletions

View File

@ -4,19 +4,23 @@
- the above command introduced the ability to run without root
- if the script was ran without root, and `-packages_skip` wasn't specified,
the script will attempt to detect and use the built-in tool `sudo` if it was available
* share leaderboards scores with connected players, adjust players ranks locally, and sort entries as needed by the game, suggested by **[M4RCK5]**
* implemented the missing interface `ISteamGameServerStats`, allowing game servers to exchange user stats & achievements with players
* for windows: updated stub drm patterns and added a workaround for older variants,
this increases the compatibility, but makes it easier to be detected
* new stub dll `GameOverlayRenderer` for the experiemntal steamclient setup,
* new stub/mock dll `GameOverlayRenderer` for the experiemntal steamclient setup,
some apps verify the existence of this dll, either on disk, or inside their memory space.
**not recommended** to ignore it
* separate the config file `disable_leaderboards_create_unknown.txt`, previously it was tied to `leaderboards.txt`,
by default the emu will create any unknown leaderboards, you can disable this behavior with this file
**not recommended** to disable this behavior
* added missing example file `disable_lobby_creation.txt` in `steam_settings` folder + updated release `README`
* set the minimum game server latency/ping to 2ms
* added new function `rmCallbacks()` for the networking, to be able to cleanup callbacks on object destruction
* for windows build script: prevent permissive language extensions via the compiler flag `/permissive-`
* missing `delete` for ugc_bridge + reset pointers on client objects destruction
* allow overlay invitations to obscure game input to be able to accept/reject the request
* fixed a problem in the overlay where players connected on the same network might be missed during startup, resulting in an empty friend list
---

View File

@ -63,6 +63,7 @@ enum Callback_Ids {
CALLBACK_ID_STEAM_MESSAGES,
CALLBACK_ID_NETWORKING_MESSAGES,
CALLBACK_ID_GAMESERVER_STATS,
CALLBACK_ID_LEADERBOARDS_STATS,
CALLBACK_IDS_MAX
};

View File

@ -22,17 +22,26 @@
#include "base.h"
#include "overlay/steam_overlay.h"
struct Steam_Leaderboard_Score {
CSteamID steam_id;
int32 score;
std::vector<int32> score_details;
struct Steam_Leaderboard_Entry {
CSteamID steam_id{};
int32 score{};
std::vector<int32> score_details{};
};
struct Steam_Leaderboard {
std::string name;
ELeaderboardSortMethod sort_method;
ELeaderboardDisplayType display_type;
Steam_Leaderboard_Score self_score;
std::string name{};
ELeaderboardSortMethod sort_method = k_ELeaderboardSortMethodNone;
ELeaderboardDisplayType display_type = k_ELeaderboardDisplayTypeNone;
std::vector<Steam_Leaderboard_Entry> entries{};
Steam_Leaderboard_Entry* find_recent_entry(const CSteamID &steamid) const;
void remove_entries(const CSteamID &steamid);
// remove entries with the same steamid, keeping only most recent one
void remove_duplicate_entries();
void sort_entries();
};
struct achievement_trigger {
@ -90,7 +99,7 @@ private:
class RunEveryRunCB *run_every_runcb{};
class Steam_Overlay* overlay{};
std::vector<struct Steam_Leaderboard> leaderboards{};
std::vector<struct Steam_Leaderboard> cached_leaderboards{};
nlohmann::json defined_achievements{};
nlohmann::json user_achievements{};
@ -103,23 +112,24 @@ private:
GameServerStats_Messages::AllStats pending_server_updates{};
// returns a value 1 -> leaderboards.size(), inclusize
unsigned int find_leaderboard(std::string name);
nlohmann::detail::iter_impl<nlohmann::json> defined_achievements_find(const std::string &key);
void load_achievements_db();
void load_achievements();
void save_achievements();
void save_leaderboard_score(Steam_Leaderboard *leaderboard);
std::vector<Steam_Leaderboard_Score> load_leaderboard_scores(std::string name);
nlohmann::detail::iter_impl<nlohmann::json> defined_achievements_find(const std::string &key);
std::string get_value_for_language(nlohmann::json &json, std::string key, std::string language);
std::vector<Steam_Leaderboard_Entry> load_leaderboard_entries(const std::string &name);
void save_my_leaderboard_entry(const Steam_Leaderboard &leaderboard);
Steam_Leaderboard_Entry* update_leaderboard_entry(Steam_Leaderboard &leaderboard, const Steam_Leaderboard_Entry &entry, bool overwrite = true);
// returns a value 1 -> leaderboards.size(), inclusive
unsigned int find_cached_leaderboard(const std::string &name);
unsigned int cache_leaderboard_ifneeded(const std::string &name, ELeaderboardSortMethod eLeaderboardSortMethod, ELeaderboardDisplayType eLeaderboardDisplayType);
// null steamid means broadcast to all
void send_my_leaderboard_score(const Steam_Leaderboard &board, const CSteamID *steamid = nullptr, bool want_scores_back = false);
void request_user_leaderboard_entry(const Steam_Leaderboard &board, const CSteamID &steamid);
// change stats/achievements without sending back to server
InternalSetResult<int32> set_stat_internal( const char *pchName, int32 nData );
InternalSetResult<std::pair<GameServerStats_Messages::StatInfo::Stat_Type, float>> set_stat_internal( const char *pchName, float fData );
@ -127,16 +137,25 @@ private:
InternalSetResult<bool> set_achievement_internal( const char *pchName );
InternalSetResult<bool> clear_achievement_internal( const char *pchName );
void send_updated_stats();
void steam_run_callback();
// requests from server
void network_callback_initial_stats(Common_Message *msg);
void network_callback_updated_stats(Common_Message *msg);
void network_callback(Common_Message *msg);
void network_stats_initial(Common_Message *msg);
void network_stats_updated(Common_Message *msg);
void network_callback_stats(Common_Message *msg);
static void steam_user_stats_network_callback(void *object, Common_Message *msg);
// requests from other users to share leaderboards
void network_leaderboard_update_score(Common_Message *msg, Steam_Leaderboard &board, bool send_score_back);
void network_leaderboard_send_my_score(Common_Message *msg, const Steam_Leaderboard &board);
void network_callback_leaderboards(Common_Message *msg);
// user connect/disconnect
void network_callback_low_level(Common_Message *msg);
static void steam_user_stats_network_low_level(void *object, Common_Message *msg);
static void steam_user_stats_network_stats(void *object, Common_Message *msg);
static void steam_user_stats_network_leaderboards(void *object, Common_Message *msg);
static void steam_user_stats_run_every_runcb(void *object);
public:

View File

@ -268,6 +268,30 @@ message GameServerStats_Messages {
}
}
message Leaderboards_Messages {
message LeaderboardInfo {
string board_name = 1;
int32 sort_method = 2;
int32 display_type = 3;
}
message UserScoreEntry {
int32 score = 1;
repeated int32 score_details = 2;
}
enum Types {
UpdateUserScore = 0; // notify others on the network that our score was updated
UpdateUserScoreMutual = 1; // notify others on the network that our score was updated, and request theirs
RequestUserScore = 2; // request score data from a single user
}
Types type = 1;
LeaderboardInfo leaderboard_info = 2;
oneof data_messages {
UserScoreEntry user_score_entry = 3;
}
}
message Common_Message {
uint64 source_id = 1; // SteamID64 of the sender
uint64 dest_id = 2; // SteamID64 of the target receiver
@ -286,6 +310,7 @@ message Common_Message {
Steam_Messages steam_messages = 14;
Networking_Messages networking_messages = 15;
GameServerStats_Messages gameserver_stats_messages = 16;
Leaderboards_Messages leaderboards_messages = 17;
}
uint32 source_ip = 128;

View File

@ -590,6 +590,11 @@ void Networking::do_callbacks_message(Common_Message *msg)
run_callbacks(CALLBACK_ID_GAMESERVER_STATS, msg);
}
if (msg->has_leaderboards_messages()) {
PRINT_DEBUG("Networking has_leaderboards_messages\n");
run_callbacks(CALLBACK_ID_LEADERBOARDS_STATS, msg);
}
}
bool Networking::handle_tcp(Common_Message *msg, struct TCP_Socket &socket)

File diff suppressed because it is too large Load Diff