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 Core/GameEngine/Include/Common/UserPreferences.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,11 +60,13 @@ class UserPreferences : public PreferenceMap
Real getReal(AsciiString key, Real defaultValue) const;
Int getInt(AsciiString key, Int defaultValue) const;
AsciiString getAsciiString(AsciiString key, AsciiString defaultValue) const;
UnicodeString getUnicodeString(AsciiString key, UnicodeString defaultValue) const;

void setBool(AsciiString key, Bool val);
void setReal(AsciiString key, Real val);
void setInt(AsciiString key, Int val);
void setAsciiString(AsciiString key, AsciiString val);
void setUnicodeString(AsciiString key, UnicodeString val);

protected:
AsciiString m_filename;
Expand Down
34 changes: 24 additions & 10 deletions Core/GameEngine/Source/Common/UserPreferences.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,19 @@ AsciiString UserPreferences::getAsciiString(AsciiString key, AsciiString default
return it->second;
}

UnicodeString UserPreferences::getUnicodeString(AsciiString key, UnicodeString defaultValue) const
{
UserPreferences::const_iterator it = find(key);
if (it == end())
{
return defaultValue;
}

UnicodeString ret;
ret.translate(it->second);
return ret;
}

void UserPreferences::setBool(AsciiString key, Bool val)
{
(*this)[key] = boolAsStr(val);
Expand All @@ -280,6 +293,13 @@ void UserPreferences::setAsciiString(AsciiString key, AsciiString val)
(*this)[key] = val;
}

void UserPreferences::setUnicodeString(AsciiString key, UnicodeString val)
{
AsciiString str;
str.translate(val);
(*this)[key] = str;
}

//-----------------------------------------------------------------------------
// QuickMatchPreferences base class
//-----------------------------------------------------------------------------
Expand Down Expand Up @@ -515,22 +535,16 @@ void CustomMatchPreferences::setLastLadder(const AsciiString& addr, UnsignedShor
(*this)["LastLadderPort"] = strVal;
}

AsciiString CustomMatchPreferences::getLastLobbyName() const
UnicodeString CustomMatchPreferences::getLastLobbyName() const
{
CustomMatchPreferences::const_iterator it = find("LastLobbyName");
if (it == end())
{
return AsciiString::TheEmptyString;
}

AsciiString ret = it->second;
UnicodeString ret = getUnicodeString("LastLobbyName", UnicodeString::TheEmptyString);
ret.trim();
return ret;
}

void CustomMatchPreferences::setLastLobbyName(const AsciiString& name)
void CustomMatchPreferences::setLastLobbyName(const UnicodeString& name)
{
(*this)["LastLobbyName"] = name;
setUnicodeString("LastLobbyName", name);
}

AsciiString CustomMatchPreferences::getLastLadderAddr( void )
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,8 +44,8 @@ class CustomMatchPreferences : public UserPreferences
CustomMatchPreferences();
virtual ~CustomMatchPreferences() override;

AsciiString getLastLobbyName() const;
void setLastLobbyName(const AsciiString& name);
UnicodeString getLastLobbyName() const;
void setLastLobbyName(const UnicodeString& name);

void setLastLadder(const AsciiString& addr, UnsignedShort port);
AsciiString getLastLadderAddr();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ class HTTPManager
// NOTE: set bDisableServiceAuth for endpoints that must be called with something other than the session token (e.g. the refresh endpoint, which needs the refresh token), otherwise the session token overwrites any Authorization header passed in inHeaders
void SendPOSTRequest(const char* szURI, EIPProtocolVersion protover, std::map<std::string, std::string>& inHeaders, const char* szPostData, std::function<void(bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)> completionCallback, std::function<void(size_t bytesReceived)> progressCallback = nullptr, int timeoutMS = -1, bool bDisableServiceAuth = false);
void SendPUTRequest(const char* szURI, EIPProtocolVersion protover, std::map<std::string, std::string>& inHeaders, const char* szData, std::function<void(bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)> completionCallback, std::function<void(size_t bytesReceived)> progressCallback = nullptr, int timeoutMS = -1);
void SendS3PUTRequest(const char* szURI, EIPProtocolVersion protover, std::map<std::string, std::string>& inHeaders, std::vector<uint8_t> vecBuffer, std::function<void(bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)> completionCallback, std::function<void(size_t bytesReceived)> progressCallback = nullptr, int timeoutMS = -1);
void SendS3PUTRequest(const char* szURI, EIPProtocolVersion protover, std::map<std::string, std::string>& inHeaders, std::vector<uint8_t> vecBuffer, std::function<void(bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)> completionCallback, std::function<void(size_t bytesReceived)> progressCallback = nullptr, int timeoutMS = -1, int maxSendBytesPerSec = 0);
void SendDELETERequest(const char* szURI, EIPProtocolVersion protover, std::map<std::string, std::string>& inHeaders, const char* szData, std::function<void(bool bSuccess, int statusCode, std::string strBody, HTTPRequest* pReq)> completionCallback, std::function<void(size_t bytesReceived)> progressCallback = nullptr, int timeoutMS = -1);

void Shutdown();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,11 @@ class HTTPRequest
m_bAppendAuthIfPresent = false;
}

void SetMaxSendSpeed(int bytesPerSec)
{
m_maxSendBytesPerSec = bytesPerSec;
}

void OnResponsePartialWrite(std::uint8_t* pBuffer, size_t numBytes);

bool HasStarted() const { return m_bIsStarted; }
Expand Down Expand Up @@ -77,6 +82,8 @@ class HTTPRequest

bool m_bAppendAuthIfPresent = true;

int m_maxSendBytesPerSec = 0; // 0 = unlimited

EIPProtocolVersion m_protover;

int m_timeoutMS = 5000;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#pragma once

#include "GameNetwork/GeneralsOnline/json.hpp"

// Optional field: dest keeps its default when the key is missing or null
template <typename T>
inline void JsonGetOptional(const nlohmann::json& j, const char* szKey, T& dest)
{
auto it = j.find(szKey);
if (it != j.end() && !it->is_null())
{
it->get_to(dest);
}
}

// Required field: throws when the key is missing or the wrong type
template <typename T>
inline void JsonGetRequired(const nlohmann::json& j, const char* szKey, T& dest)
{
j.at(szKey).get_to(dest);
}
Original file line number Diff line number Diff line change
Expand Up @@ -66,6 +66,9 @@ class PlayerConnection
m_State != EConnectionState::CONNECTION_DISCONNECTED;
}

// a closed connection has nothing to receive
bool CanRecv() const { return m_hSteamConnection != k_HSteamNetConnection_Invalid; }

int Recv(SteamNetworkingMessage_t** pMsg);

int GetHighestHistoricalLatency()
Expand Down Expand Up @@ -245,6 +248,9 @@ class NetworkMesh
m_vecPendingStateUpdates.emplace_back(userID, newState);
}

// drops a peer that left for good so nothing keeps polling it
void RemoveConnection(int64_t userID);

PlayerConnection* GetConnectionForUser(int64_t user_id)
{
if (m_mapConnections.contains(user_id))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

#include <thread>
#include <memory>
#include <chrono>

class HTTPManager;

Expand All @@ -28,6 +29,7 @@ struct S3ScreenshotEntry
std::vector<uint8_t> vecBytes;
std::string strSignedURI;
EScreenshotType screenshotType;
std::chrono::steady_clock::time_point notBefore; // upload is held back until this time

bool operator==(const S3ScreenshotEntry& other) const
{
Expand Down Expand Up @@ -185,12 +187,16 @@ class WebSocket
// lobby ID the check was started for; a stale reply (different lobby) is ignored
int64_t m_connectivityCheckLobbyID = -1;

// when the check was sent; Tick() gives up on it after a client-side timeout
int64_t m_connectivityCheckStartMs = -1;

void SendData_StartFullMeshConnectivityCheck(std::function<void(bool, std::list<std::pair<int64_t, int64_t>>, std::string)> cbOnConnectivityCheckComplete);

void ClearConnectivityCheckCallback()
{
m_cbOnConnectivityCheckComplete = nullptr;
m_connectivityCheckLobbyID = -1;
m_connectivityCheckStartMs = -1;
}

void Tick();
Expand All @@ -215,6 +221,13 @@ class WebSocket
m_pendingSignals.push(std::move(payload));
}

// signals queued for a lobby we've since left must not reach the next one
void ClearPendingSignals()
{
std::scoped_lock<std::mutex> lock(m_pendingSignalsMutex);
m_pendingSignals = std::queue<std::vector<uint8_t>>();
}

std::queue<std::vector<uint8_t>> DrainPendingSignals()
{
std::scoped_lock<std::mutex> lock(m_pendingSignalsMutex);
Expand Down Expand Up @@ -341,6 +354,8 @@ struct ServiceConfig

int screenshot_width = 557;
int screenshot_height = 333;
int screenshot_upload_bytes_per_sec = 131072; // 128 KB/s
int screenshot_slot_offset_ms = 2000;

// ICE client used for P2P NAT traversal: 0 = library default, 1 = native, 2 = WebRTC.
int ice_implementation = 2;
Expand All @@ -351,7 +366,7 @@ struct ServiceConfig
ra_slack_percent, frame_grouping_frames, enable_host_migration, network_do_immediate_flush_per_frame, network_send_flags, network_latency_logic_model,
use_default_config, ra_slack_override_percent_in_default, do_probes, do_replay_upload, network_mesh_histogram_duration,
ibra_ra_tweaks, ibra_minslack_default, ibra_maxslack_default, ibra_minslack_greaterthan300ms, ibra_maxslack_greaterthan300ms, ibra_minslack_greaterthan200ms, ibra_maxslack_greaterthan200ms,
screenshot_width, screenshot_height, ice_implementation, use_new_networking)
screenshot_width, screenshot_height, screenshot_upload_bytes_per_sec, screenshot_slot_offset_ms, ice_implementation, use_new_networking)
};

class NGMP_OnlineServicesManager
Expand Down Expand Up @@ -586,10 +601,10 @@ class NGMP_OnlineServicesManager
ServiceConfig& GetServiceConfig() { return m_ServiceConfig; }

public:
void CacheScreenshotBytes_StartMatch(std::vector<uint8_t>& vecData)
void CacheScreenshotBytes_StartMatch(std::vector<uint8_t> vecData)
{
std::scoped_lock<std::mutex> ssLock(m_ScreenshotMutex);
m_vecCachedScreenshotBytes_MatchStart = vecData;
m_vecCachedScreenshotBytes_MatchStart = std::move(vecData);
}

void CacheScreenshotBytes_EndMatch(uint64_t matchID, std::vector<uint8_t> data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,20 @@ struct LobbyMemberEntry : public NetworkMemberBase
int startpos = -1;
bool has_map = false;

uint16_t m_SlotIndex = 999999;
// marks a member the service sent without a usable slot
static constexpr uint16_t NO_SLOT_INDEX = UINT16_MAX;
uint16_t m_SlotIndex = NO_SLOT_INDEX;
uint16_t m_SlotState = SlotState::SLOT_OPEN;

std::string region;
std::string middlewareUserID;
int latency = 0;

bool HasValidSlot() const
{
return m_SlotIndex < MAX_SLOTS;
}

bool IsHuman() const
{
return user_id != -1 && m_SlotState == SlotState::SLOT_PLAYER;
Expand Down Expand Up @@ -384,6 +391,10 @@ class NGMP_OnlineServices_LobbyInterface

void UpdateRoomDataCache(std::function<void(bool)> fnCallback = nullptr);

// re-fetches the lobby when the roster could not be trusted, throttled
void RequestRosterRefresh();
int64_t m_lastRosterRefreshRequestMs = 0;

std::function<void(LobbyMemberEntry)> m_cbPlayerDoesntHaveMap = nullptr;
void RegisterForPlayerDoesntHaveMapCallback(std::function<void(LobbyMemberEntry)> cb)
{
Expand Down Expand Up @@ -472,7 +483,8 @@ class NGMP_OnlineServices_LobbyInterface

NetworkMesh* GetNetworkMeshForLobby() { return m_pLobbyMesh; }

void JoinLobby(LobbyEntry lobby, std::string strPassword);
// false when a join is already in progress and this request was dropped
bool JoinLobby(LobbyEntry lobby, std::string strPassword);

void LeaveCurrentLobby();
void ResetForMatchmakingRequeue();
Expand Down Expand Up @@ -551,6 +563,10 @@ class NGMP_OnlineServices_LobbyInterface
#endif

bool m_bAttemptingToJoinLobby = false;

// GET Lobby/{id} responses can arrive out of order; only apply ones newer than the last applied
std::atomic<uint64_t> m_LobbyUpdateRequestSeq = 0;
std::atomic<uint64_t> m_LobbyUpdateAppliedSeq = 0;
// Invalidates asynchronous callbacks left behind by an abandoned lobby join.
std::atomic<uint64_t> m_LobbyJoinGeneration = 0;
LobbyEntry m_LobbyTryingToJoin;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -336,12 +336,8 @@ void PopupHostGameInit( WindowLayout *layout, void *userData )
#if defined(GENERALS_ONLINE)
{
CustomMatchPreferences pref;
AsciiString lastLobbyName = pref.getLastLobbyName();
if (!lastLobbyName.isEmpty())
{
name.translate(lastLobbyName.str());
}
else
name = pref.getLastLobbyName();
if (name.isEmpty())
{
name.translate("Generals Online Lobby");
}
Expand Down Expand Up @@ -605,19 +601,8 @@ WindowMsgHandledType PopupHostGameSystem( GameWindow *window, UnsignedInt msg, W
#if defined(GENERALS_ONLINE)
// save last used lobby name to CustomPref.ini
{
char buffer[256];
const WideChar* w = name.str();
int i = 0;
for (; w[i] != 0 && i < 255; ++i)
{
buffer[i] = (char)(w[i] & 0xFF);
}
buffer[i] = 0;

AsciiString lobbyNameAscii = buffer;

CustomMatchPreferences pref;
pref.setLastLobbyName(lobbyNameAscii);
pref.setLastLobbyName(name);
pref.write();
}
#endif
Expand Down
Loading
Loading