Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions dll/dll/network.h
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ class Networking
void addListenId(CSteamID id);
void setAppID(uint32 appid);
void Run();
void sendAnnounceBroadcastsNow();
bool hasConnectedIndividualAccounts();

// send to a specific user, set_dest_id() must be called
bool sendTo(Common_Message *msg, bool reliable, Connection *conn = NULL);
Expand Down
4 changes: 3 additions & 1 deletion dll/dll/steam_matchmaking.h
Original file line number Diff line number Diff line change
Expand Up @@ -86,6 +86,7 @@ public ISteamMatchmaking
std::chrono::high_resolution_clock::time_point lobby_last_search{};
SteamAPICall_t search_call_api_id{};
bool searching{};
bool search_waiting_for_initial_sync{};

std::vector<struct Chat_Entry> chat_entries{};
std::vector<struct Data_Requested> data_requested{};
Expand All @@ -99,7 +100,8 @@ public ISteamMatchmaking
static bool leave_lobby(Lobby *lobby, CSteamID id);

Lobby *get_lobby(CSteamID id);
void send_lobby_data();
void send_lobby(Lobby const& lobby, CSteamID dest_id);
void send_lobby_data(CSteamID dest_id = k_steamIDNil);

void trigger_lobby_dataupdate(CSteamID lobby, CSteamID member, bool success, double cb_timeout=0.005, bool send_changed_lobby=true);
void trigger_lobby_member_join_leave(CSteamID lobby, CSteamID member, bool leaving, bool success, double cb_timeout=0.0);
Expand Down
7 changes: 7 additions & 0 deletions dll/dll/steam_networking_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ public ISteamNetworkingUtils
FSteamNetworkingSocketsDebugOutput debug_function{};
bool relay_initialized = false;
bool init_relay = true; // Initializing relay immediately when we ask for it. Fixing Elden Ring SeamlessCoop
static FnSteamNetConnectionStatusChanged connection_status_changed_callback;
static FnSteamNetAuthenticationStatusChanged auth_status_changed_callback;
static FnSteamRelayNetworkStatusChanged relay_network_status_changed_callback;
// NOTE from Detanup01: They should call InitializeRelayAccess BTW. Whoever write that mod cannot read valve docs.
/*
Valve docs:
Expand All @@ -57,6 +60,10 @@ public ISteamNetworkingUtils
Steam_Networking_Utils(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
~Steam_Networking_Utils();

static void InvokeConnectionStatusChanged(SteamNetConnectionStatusChangedCallback_t *data);
static void InvokeAuthStatusChanged(SteamNetAuthenticationStatus_t *data);
static void InvokeRelayNetworkStatusChanged(SteamRelayNetworkStatus_t *data);

/// Allocate and initialize a message object. Usually the reason
/// you call this is to pass it to ISteamNetworkingSockets::SendMessages.
/// The returned object will have all of the relevant fields cleared to zero.
Expand Down
1 change: 1 addition & 0 deletions dll/net.proto
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,7 @@ message Lobby_Messages {
CHANGE_OWNER = 2;
MEMBER_DATA = 3;
CHAT_MESSAGE = 4;
DATA_REQUEST = 5;
}

Types type = 2;
Expand Down
22 changes: 22 additions & 0 deletions dll/network.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1157,6 +1157,28 @@ void Networking::setAppID(uint32 appid)
this->appid = appid;
}

void Networking::sendAnnounceBroadcastsNow()
{
send_announce_broadcasts();
}

bool Networking::hasConnectedIndividualAccounts()
{
std::lock_guard<std::recursive_mutex> lock(mutex);

for (auto const &conn : connections) {
if (!conn.connected) continue;

for (auto const &steam_id : conn.ids) {
if (steam_id.BIndividualAccount()) {
return true;
}
}
}

return false;
}

bool Networking::sendToIPPort(Common_Message *msg, uint32 ip, uint16 port, bool reliable)
{
bool is_local_ip = ((ip >> 24) == 0x7F);
Expand Down
81 changes: 70 additions & 11 deletions dll/steam_matchmaking.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
#define FILTER_MAX_DEFAULT 4096

#define LOBBY_SEARCH_TIMEOUT 0.2 //Tested on real steam
#define LOBBY_SEARCH_CONNECT_TIMEOUT 0.75


google::protobuf::Map<std::string,std::string>::const_iterator Steam_Matchmaking::caseinsensitive_find(const ::google::protobuf::Map< ::std::string, ::std::string >& map, std::string key)
Expand Down Expand Up @@ -55,7 +56,20 @@ Lobby* Steam_Matchmaking::get_lobby(CSteamID id)
return &(*lobby);
}

void Steam_Matchmaking::send_lobby_data()
void Steam_Matchmaking::send_lobby(Lobby const& lobby, CSteamID dest_id)
{
Common_Message msg = Common_Message();
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
msg.set_allocated_lobby(new Lobby(lobby));
if (dest_id.IsValid()) {
msg.set_dest_id(dest_id.ConvertToUint64());
network->sendTo(&msg, true);
} else {
network->sendToAllIndividuals(&msg, true);
}
}

void Steam_Matchmaking::send_lobby_data(CSteamID dest_id)
{
if (lobbies.size()) {
PRINT_DEBUG("lobbies %zu", lobbies.size());
Expand All @@ -64,10 +78,7 @@ void Steam_Matchmaking::send_lobby_data()
for(auto & l: lobbies) {
if (get_lobby_member(&l, settings->get_local_steam_id()) && l.owner() == settings->get_local_steam_id().ConvertToUint64() && !l.deleted()) {
PRINT_DEBUG("lobby " "%" PRIu64 "", l.room_id());
Common_Message msg = Common_Message();
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
msg.set_allocated_lobby(new Lobby(l));
network->sendToAllIndividuals(&msg, true);
send_lobby(l, dest_id);
}
}
}
Expand Down Expand Up @@ -479,6 +490,11 @@ SteamAPICall_t Steam_Matchmaking::RequestLobbyList()
filter_max_results_copy = filter_max_results;
filter_values.clear();
filter_max_results = FILTER_MAX_DEFAULT;
// Give discovery a chance to receive the first announce burst.
search_waiting_for_initial_sync = !network->hasConnectedIndividualAccounts();
if (search_waiting_for_initial_sync) {
network->sendAnnounceBroadcastsNow();
}
searching = true;
if (search_call_api_id) callback_results->rmCallBack(search_call_api_id, NULL);
search_call_api_id = callback_results->reserveCallResult();
Expand Down Expand Up @@ -1043,10 +1059,34 @@ bool Steam_Matchmaking::RequestLobbyData( CSteamID steamIDLobby )
PRINT_DEBUG("%llu", steamIDLobby.ConvertToUint64());
std::lock_guard<std::recursive_mutex> lock(global_mutex);

struct Data_Requested requested{};
requested.lobby_id = steamIDLobby;
requested.requested = std::chrono::high_resolution_clock::now();
data_requested.push_back(requested);
if (get_lobby(steamIDLobby)) {
trigger_lobby_dataupdate(steamIDLobby, steamIDLobby, true);
return true;
}

auto existing_request = std::find_if(data_requested.begin(), data_requested.end(), [&steamIDLobby](Data_Requested const& item) {
return item.lobby_id == steamIDLobby;
});
if (existing_request != data_requested.end()) {
existing_request->requested = std::chrono::high_resolution_clock::now();
} else {
struct Data_Requested requested{};
requested.lobby_id = steamIDLobby;
requested.requested = std::chrono::high_resolution_clock::now();
data_requested.push_back(requested);
}

if (!network->hasConnectedIndividualAccounts()) {
network->sendAnnounceBroadcastsNow();
}

Lobby_Messages *message = new Lobby_Messages();
message->set_type(Lobby_Messages::DATA_REQUEST);
Common_Message msg{};
msg.set_allocated_lobby_messages(message);
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
msg.mutable_lobby_messages()->set_id(steamIDLobby.ConvertToUint64());
network->sendToAllIndividuals(&msg, true);
return true;
}

Expand Down Expand Up @@ -1474,17 +1514,25 @@ void Steam_Matchmaking::RunCallbacks()
callback_results->addCallResult(search_call_api_id, data.k_iCallback, &data, sizeof(data));
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
search_call_api_id = 0;
search_waiting_for_initial_sync = false;
}
}
}

if (searching && check_timedout(lobby_last_search, LOBBY_SEARCH_TIMEOUT)) {
double lobby_search_timeout = LOBBY_SEARCH_TIMEOUT;
if (search_waiting_for_initial_sync && filtered_lobbies.empty()) {
// Allow one longer search window while the first peer connection comes up.
lobby_search_timeout = LOBBY_SEARCH_CONNECT_TIMEOUT;
}

if (searching && check_timedout(lobby_last_search, lobby_search_timeout)) {
PRINT_DEBUG("LOBBY_SEARCH_TIMEOUT %zu", filtered_lobbies.size());
LobbyMatchList_t data{};
data.m_nLobbiesMatching = static_cast<uint32>(filtered_lobbies.size());
callback_results->addCallResult(search_call_api_id, data.k_iCallback, &data, sizeof(data));
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
searching = false;
search_waiting_for_initial_sync = false;
search_call_api_id = 0;
}

Expand Down Expand Up @@ -1560,6 +1608,7 @@ void Steam_Matchmaking::Callback(Common_Message *msg)
if (msg->has_lobby()) {
PRINT_DEBUG("GOT A LOBBY appid: %u " "%" PRIu64 "", msg->lobby().appid(), msg->lobby().owner());
if (msg->lobby().owner() != settings->get_local_steam_id().ConvertToUint64() && msg->lobby().appid() == settings->get_local_game_id().AppID()) {
search_waiting_for_initial_sync = false;
Lobby *lobby = get_lobby((uint64)msg->lobby().room_id());
if (!lobby) {
size_t old_size = lobbies.size();
Expand Down Expand Up @@ -1712,12 +1761,22 @@ void Steam_Matchmaking::Callback(Common_Message *msg)
}
}
}

if (msg->lobby_messages().type() == Lobby_Messages::DATA_REQUEST) {
PRINT_DEBUG("LOBBY MESSAGE: DATA REQUEST");
if (lobby->owner() == settings->get_local_steam_id().ConvertToUint64()) {
// Only the owner answers targeted lobby data requests.
send_lobby(*lobby, (uint64)msg->source_id());
}
}
}
}

if (msg->has_low_level()) {
if (msg->low_level().type() == Low_Level::CONNECT) {

if (msg->source_id() != settings->get_local_steam_id().ConvertToUint64()) {
send_lobby_data((uint64)msg->source_id());
}
}

if (msg->low_level().type() == Low_Level::DISCONNECT) {
Expand Down
35 changes: 30 additions & 5 deletions dll/steam_networking_sockets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
<http://www.gnu.org/licenses/>. */

#include "dll/steam_networking_sockets.h"
#include "dll/steam_networking_utils.h"


void Steam_Networking_Sockets::steam_callback(void *object, Common_Message *msg)
Expand Down Expand Up @@ -231,6 +232,8 @@ void Steam_Networking_Sockets::launch_callback(HSteamNetConnection m_hConn, enum
data.m_eOldState = convert_status(old_status);
set_steamnetconnectioninfo(connect_socket, &data.m_info);
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
// Also deliver the callback through the global config hook.
Steam_Networking_Utils::InvokeConnectionStatusChanged(&data);
}


Expand Down Expand Up @@ -364,7 +367,11 @@ HSteamNetConnection Steam_Networking_Sockets::ConnectByIPAddress( const SteamNet
SteamNetworkingIdentity ip_id;
ip_id.SetIPAddr(address);
HSteamNetConnection socket = new_connect_socket(ip_id, SNS_DISABLED_PORT, address.m_port);
send_packet_new_connection(socket);
if (socket != k_HSteamNetConnection_Invalid) {
send_packet_new_connection(socket);
// Mirror the initial connection state transition immediately.
launch_callback(socket, CONNECT_SOCKET_NO_CONNECTION);
}
return socket;
}

Expand All @@ -375,7 +382,11 @@ HSteamNetConnection Steam_Networking_Sockets::ConnectByIPAddress( const SteamNet
SteamNetworkingIdentity ip_id;
ip_id.SetIPAddr(*address);
HSteamNetConnection socket = new_connect_socket(ip_id, SNS_DISABLED_PORT, address->m_port);
send_packet_new_connection(socket);
if (socket != k_HSteamNetConnection_Invalid) {
send_packet_new_connection(socket);
// Mirror the initial connection state transition immediately.
launch_callback(socket, CONNECT_SOCKET_NO_CONNECTION);
}
return socket;
}

Expand All @@ -386,7 +397,11 @@ HSteamNetConnection Steam_Networking_Sockets::ConnectByIPAddress( const SteamNet
SteamNetworkingIdentity ip_id;
ip_id.SetIPAddr(address);
HSteamNetConnection socket = new_connect_socket(ip_id, SNS_DISABLED_PORT, address.m_port);
send_packet_new_connection(socket);
if (socket != k_HSteamNetConnection_Invalid) {
send_packet_new_connection(socket);
// Mirror the initial connection state transition immediately.
launch_callback(socket, CONNECT_SOCKET_NO_CONNECTION);
}
return socket;
}

Expand Down Expand Up @@ -444,7 +459,11 @@ HSteamNetConnection Steam_Networking_Sockets::ConnectP2P( const SteamNetworkingI
}

HSteamNetConnection socket = new_connect_socket(identityRemote, nVirtualPort, SNS_DISABLED_PORT);
send_packet_new_connection(socket);
if (socket != k_HSteamNetConnection_Invalid) {
send_packet_new_connection(socket);
// Mirror the initial connection state transition immediately.
launch_callback(socket, CONNECT_SOCKET_NO_CONNECTION);
}
return socket;
}

Expand Down Expand Up @@ -1312,6 +1331,8 @@ ESteamNetworkingAvailability Steam_Networking_Sockets::InitAuthentication()
data.m_eAvail = k_ESteamNetworkingAvailability_Current;
memcpy(data.m_debugMsg, "OK", 3);
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
// Also deliver the callback through the global config hook.
Steam_Networking_Utils::InvokeAuthStatusChanged(&data);
return k_ESteamNetworkingAvailability_Current;
}

Expand Down Expand Up @@ -2083,14 +2104,18 @@ void Steam_Networking_Sockets::RunCallbacks()
{
// PRINT_DEBUG_ENTRY();

//TODO: timeout unaccepted connections after a few seconds or so
auto current_time = std::chrono::steady_clock::now();
auto socket_conn = std::begin(sbcs->connect_sockets);
while (socket_conn != std::end(sbcs->connect_sockets)) {
if (socket_conn->second.connect_requests_sent < 10 && socket_conn->second.status == CONNECT_SOCKET_CONNECTING && (std::chrono::duration_cast<std::chrono::milliseconds>(current_time - socket_conn->second.connect_request_last_sent).count() > 3000)) {
send_packet_new_connection(socket_conn->first);
socket_conn->second.connect_request_last_sent = current_time;
socket_conn->second.connect_requests_sent += 1;
} else if (socket_conn->second.connect_requests_sent >= 10 && socket_conn->second.status == CONNECT_SOCKET_CONNECTING && (std::chrono::duration_cast<std::chrono::milliseconds>(current_time - socket_conn->second.connect_request_last_sent).count() > 3000)) {
// Stop retrying once the pending connect request has timed out locally.
enum connect_socket_status old_status = socket_conn->second.status;
socket_conn->second.status = CONNECT_SOCKET_TIMEDOUT;
launch_callback(socket_conn->first, old_status);
}

++socket_conn;
Expand Down
Loading