mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-11-27 05:04:01 +08:00
separate .h/.cpp files
This commit is contained in:
parent
1169822f70
commit
e5d1a8bda7
266
dll/appticket.cpp
Normal file
266
dll/appticket.cpp
Normal file
@ -0,0 +1,266 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/appticket.h"
|
||||||
|
|
||||||
|
|
||||||
|
void AppTicketV1::Reset()
|
||||||
|
{
|
||||||
|
TicketSize = 0;
|
||||||
|
TicketVersion = 0;
|
||||||
|
Unk2 = 0;
|
||||||
|
UserData.clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AppTicketV1::Serialize() const
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
uint8_t* pBuffer{};
|
||||||
|
|
||||||
|
buffer.resize(16 + UserData.size());
|
||||||
|
pBuffer = buffer.data();
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketSize; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketVersion; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = UserData.size(); pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = Unk2; pBuffer += 4;
|
||||||
|
memcpy(pBuffer, UserData.data(), UserData.size());
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppTicketV1::Deserialize(const uint8_t* pBuffer, size_t size)
|
||||||
|
{
|
||||||
|
if (size < 16)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint32_t user_data_size;
|
||||||
|
|
||||||
|
TicketSize = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
TicketVersion = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
user_data_size = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
|
||||||
|
if (size < (user_data_size + 16))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Unk2 = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
UserData.resize(user_data_size);
|
||||||
|
memcpy(UserData.data(), pBuffer, user_data_size);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AppTicketV2::Reset()
|
||||||
|
{
|
||||||
|
TicketSize = 0;
|
||||||
|
TicketVersion = 0;
|
||||||
|
SteamID = 0;
|
||||||
|
AppID = 0;
|
||||||
|
Unk1 = 0;
|
||||||
|
Unk2 = 0;
|
||||||
|
TicketFlags = 0;
|
||||||
|
TicketIssueTime = 0;
|
||||||
|
TicketValidityEnd = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AppTicketV2::Serialize() const
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
uint8_t* pBuffer{};
|
||||||
|
|
||||||
|
buffer.resize(40);
|
||||||
|
pBuffer = buffer.data();
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketSize; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketVersion; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint64_t*>(pBuffer) = SteamID; pBuffer += 8;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = AppID; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = Unk1; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = Unk2; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketFlags; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketIssueTime; pBuffer += 4;
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = TicketValidityEnd;
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppTicketV2::Deserialize(const uint8_t* pBuffer, size_t size)
|
||||||
|
{
|
||||||
|
if (size < 40)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
TicketSize = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
TicketVersion = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
SteamID = *reinterpret_cast<const uint64_t*>(pBuffer); pBuffer += 8;
|
||||||
|
AppID = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
Unk1 = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
Unk2 = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
TicketFlags = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
TicketIssueTime = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
||||||
|
TicketValidityEnd = *reinterpret_cast<const uint32_t*>(pBuffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void AppTicketV4::Reset()
|
||||||
|
{
|
||||||
|
AppIDs.clear();
|
||||||
|
HasVACStatus = false;
|
||||||
|
HasAppValue = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AppTicketV4::Serialize()
|
||||||
|
{
|
||||||
|
std::vector<uint32_t> appids = AppIDs;
|
||||||
|
if (appids.size() == 0) {
|
||||||
|
appids.emplace_back(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t appid_count = static_cast<uint16_t>(appids.size() > 140 ? 140 : appids.size());
|
||||||
|
size_t buffer_size = static_cast<uint32_t>(appid_count) * 4ul + 2ul;
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
uint8_t* pBuffer{};
|
||||||
|
|
||||||
|
if (HasAppValue) {// VACStatus + AppValue
|
||||||
|
buffer_size += 4;
|
||||||
|
if (!HasVACStatus) {
|
||||||
|
HasVACStatus = true;
|
||||||
|
VACStatus = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasVACStatus) {// VACStatus only
|
||||||
|
buffer_size += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
buffer.resize(buffer_size);
|
||||||
|
pBuffer = buffer.data();
|
||||||
|
*reinterpret_cast<uint16_t*>(pBuffer) = appid_count;
|
||||||
|
pBuffer += 2;
|
||||||
|
|
||||||
|
for (int i = 0; i < appid_count && i < 140; ++i) {
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = appids[i];
|
||||||
|
pBuffer += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasVACStatus) {
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = VACStatus;
|
||||||
|
pBuffer += 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (HasAppValue) {
|
||||||
|
*reinterpret_cast<uint32_t*>(pBuffer) = AppValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool AppTicketV4::Deserialize(const uint8_t* pBuffer, size_t size)
|
||||||
|
{
|
||||||
|
if (size < 2)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
uint16_t appid_count = *reinterpret_cast<const uint16_t*>(pBuffer);
|
||||||
|
if (size < (appid_count * 4 + 2) || appid_count >= 140)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
AppIDs.resize(appid_count);
|
||||||
|
pBuffer += 2;
|
||||||
|
size -= 2;
|
||||||
|
for (int i = 0; i < appid_count; ++i) {
|
||||||
|
AppIDs[i] = *reinterpret_cast<const uint32_t*>(pBuffer);
|
||||||
|
pBuffer += 4;
|
||||||
|
size -= 4;
|
||||||
|
}
|
||||||
|
|
||||||
|
HasVACStatus = false;
|
||||||
|
HasAppValue = false;
|
||||||
|
|
||||||
|
if (size < 4)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
HasVACStatus = true;
|
||||||
|
VACStatus = *reinterpret_cast<const uint32_t*>(pBuffer);
|
||||||
|
pBuffer += 4;
|
||||||
|
size -= 4;
|
||||||
|
|
||||||
|
if (size < 4)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
HasAppValue = true;
|
||||||
|
AppValue = *reinterpret_cast<const uint32_t*>(pBuffer);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
bool DecryptedAppTicket::DeserializeTicket(const uint8_t* pBuffer, size_t buf_size)
|
||||||
|
{
|
||||||
|
if (!TicketV1.Deserialize(pBuffer, buf_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
pBuffer += 16 + TicketV1.UserData.size();
|
||||||
|
buf_size -= 16 + TicketV1.UserData.size();
|
||||||
|
if (!TicketV2.Deserialize(pBuffer, buf_size))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (TicketV2.TicketVersion > 2) {
|
||||||
|
pBuffer += 40;
|
||||||
|
buf_size -= 40;
|
||||||
|
if (!TicketV4.Deserialize(pBuffer, buf_size))
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> DecryptedAppTicket::SerializeTicket()
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
|
||||||
|
TicketV1.TicketSize = TicketV1.UserData.size() + 40 + 2 + ((TicketV4.AppIDs.size() == 0 ? 1 : TicketV4.AppIDs.size()) * 4) + (TicketV4.HasVACStatus ? 4 : 0) + (TicketV4.HasAppValue ? 4 : 0);
|
||||||
|
TicketV2.TicketSize = TicketV1.TicketSize - TicketV1.UserData.size();
|
||||||
|
|
||||||
|
buffer = TicketV1.Serialize();
|
||||||
|
|
||||||
|
auto v = TicketV2.Serialize();
|
||||||
|
|
||||||
|
buffer.insert(buffer.end(), v.begin(), v.end());
|
||||||
|
v = TicketV4.Serialize();
|
||||||
|
buffer.insert(buffer.end(), v.begin(), v.end());
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Steam_AppTicket::Steam_AppTicket(class Settings *settings) :
|
||||||
|
settings(settings)
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Steam_AppTicket::GetAppOwnershipTicketData( uint32 nAppID, void *pvBuffer, uint32 cbBufferLength, uint32 *piAppId, uint32 *piSteamId, uint32 *piSignature, uint32 *pcbSignature )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("TODO %u, %p, %u, %p, %p, %p, %p", nAppID, pvBuffer, cbBufferLength, piAppId, piSteamId, piSignature, pcbSignature);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
598
dll/auth.cpp
598
dll/auth.cpp
@ -1,5 +1,17 @@
|
|||||||
#include "dll/auth.h"
|
#include "dll/auth.h"
|
||||||
|
|
||||||
|
#define STEAM_ID_OFFSET_TICKET (4 + 8)
|
||||||
|
#define STEAM_TICKET_MIN_SIZE (4 + 8 + 8)
|
||||||
|
#define STEAM_TICKET_MIN_SIZE_NEW 170
|
||||||
|
|
||||||
|
#define STEAM_TICKET_PROCESS_TIME 0.03
|
||||||
|
|
||||||
|
//Conan Exiles doesn't work with 512 or 128, 256 seems to be the good size
|
||||||
|
// Usually steam send as 1024 (or recommend sending as that)
|
||||||
|
//Steam returns 234
|
||||||
|
#define STEAM_AUTH_TICKET_SIZE 256 //234
|
||||||
|
|
||||||
|
|
||||||
static inline int generate_random_int() {
|
static inline int generate_random_int() {
|
||||||
int a;
|
int a;
|
||||||
randombytes((char *)&a, sizeof(a));
|
randombytes((char *)&a, sizeof(a));
|
||||||
@ -24,7 +36,568 @@ static uint32_t get_ticket_count() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
static void steam_auth_manager_ticket_callback(void *object, Common_Message *msg)
|
// source: https://github.com/Detanup01/stmsrv/blob/main/Cert/AppTicket.key
|
||||||
|
// thanks Detanup01
|
||||||
|
const static std::string app_ticket_key =
|
||||||
|
"-----BEGIN PRIVATE KEY-----\n"
|
||||||
|
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMITHOY6pfsvaGTI\n"
|
||||||
|
"llmilPa1+ev4BsUV0IW3+F/3pQlZ+o57CO1HbepSh2a37cbGUSehOVQ7lREPVXP3\n"
|
||||||
|
"UdyF5tU5IMytJef5N7euM5z2IG9IszeOReO87h2AmtlwGqnRj7qd0MeVxSAuUq7P\n"
|
||||||
|
"C/Ir1VyOg58+wAKxaPL18upylnGJAgMBAAECgYEAnKQQj0KG9VYuTCoaL/6pfPcj\n"
|
||||||
|
"4PEvhaM1yrfSIKMg8YtOT/G+IsWkUZyK7L1HjUhD+FiIjRQKHNrjfdYAnJz20Xom\n"
|
||||||
|
"k6iVt7ugihIne1Q3pGYG8TY9P1DPdN7zEnAVY1Bh2PAlqJWrif3v8v1dUGE/dYr2\n"
|
||||||
|
"U3M0JhvzO7VL1B/chIECQQDqW9G5azGMA/cL4jOg0pbj9GfxjJZeT7M2rBoIaRWP\n"
|
||||||
|
"C3ROndyb+BNahlKk6tbvqillvvMQQiSFGw/PbmCwtLL3AkEA0/79W0q9d3YCXQGW\n"
|
||||||
|
"k3hQvR8HEbxLmRaRF2gU4MOa5C0JqwsmxzdK4mKoJCpVAiu1gmFonLjn2hm8i+vK\n"
|
||||||
|
"b7hffwJAEiMpCACTxRJJfFH1TOz/YIT5xmfq+0GPzRtkqGH5mSh5x9vPxwJb/RWI\n"
|
||||||
|
"L9s85y90JLuyc/+qc+K0Rol0Ujip4QJAGLXVJEn+8ajAt8SSn5fbmV+/fDK9gRef\n"
|
||||||
|
"S+Im5NgH+ubBBL3lBD2Orfqf7K8+f2VG3+6oufPXmpV7Y7fVPdZ40wJALDujJXgi\n"
|
||||||
|
"XiCBSht1YScYjfmJh2/xZWh8/w+vs5ZTtrnW2FQvfvVDG9c1hrChhpvmA0QxdgWB\n"
|
||||||
|
"zSsAno/utcuB9w==\n"
|
||||||
|
"-----END PRIVATE KEY-----\n";
|
||||||
|
|
||||||
|
|
||||||
|
static std::vector<uint8_t> sign_auth_data(const std::string &private_key_content, const std::vector<uint8_t> &data, size_t effective_data_len)
|
||||||
|
{
|
||||||
|
std::vector<uint8_t> signature{};
|
||||||
|
|
||||||
|
// Hash the data using SHA-1
|
||||||
|
constexpr static int SHA1_DIGEST_LENGTH = 20;
|
||||||
|
uint8_t hash[SHA1_DIGEST_LENGTH]{};
|
||||||
|
int result = mbedtls_sha1(data.data(), effective_data_len, hash);
|
||||||
|
if (result != 0) {
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
std::string err_msg(256, 0);
|
||||||
|
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
||||||
|
PRINT_DEBUG("failed to hash the data via SHA1: %s", err_msg.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_entropy_context entropy_ctx; // entropy context for random number generation
|
||||||
|
mbedtls_entropy_init(&entropy_ctx);
|
||||||
|
|
||||||
|
mbedtls_ctr_drbg_context ctr_drbg_ctx; // CTR-DRBG context for deterministic random number generation
|
||||||
|
mbedtls_ctr_drbg_init(&ctr_drbg_ctx);
|
||||||
|
|
||||||
|
// seed the CTR-DRBG context with random numbers
|
||||||
|
result = mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, nullptr, 0);
|
||||||
|
if (mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, nullptr, 0) != 0) {
|
||||||
|
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
||||||
|
mbedtls_entropy_free(&entropy_ctx);
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
std::string err_msg(256, 0);
|
||||||
|
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
||||||
|
PRINT_DEBUG("failed to seed the CTR-DRBG context: %s", err_msg.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
mbedtls_pk_context private_key_ctx; // holds the parsed private key
|
||||||
|
mbedtls_pk_init(&private_key_ctx);
|
||||||
|
|
||||||
|
result = mbedtls_pk_parse_key(
|
||||||
|
&private_key_ctx, // will hold the parsed private key
|
||||||
|
(const unsigned char *)private_key_content.c_str(),
|
||||||
|
private_key_content.size() + 1, // we MUST include the null terminator, otherwise this API returns an error!
|
||||||
|
nullptr, 0, // no password stuff, private key isn't protected
|
||||||
|
mbedtls_ctr_drbg_random, &ctr_drbg_ctx // random number generation function + the CTR-DRBG context it requires as an input
|
||||||
|
);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
mbedtls_pk_free(&private_key_ctx);
|
||||||
|
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
||||||
|
mbedtls_entropy_free(&entropy_ctx);
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
std::string err_msg(256, 0);
|
||||||
|
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
||||||
|
PRINT_DEBUG("failed to parse private key: %s", err_msg.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
// private key must be valid RSA key
|
||||||
|
if (mbedtls_pk_get_type(&private_key_ctx) != MBEDTLS_PK_RSA || // invalid type
|
||||||
|
mbedtls_pk_can_do(&private_key_ctx, MBEDTLS_PK_RSA) == 0) { // or initialized but not properly setup (maybe freed?)
|
||||||
|
mbedtls_pk_free(&private_key_ctx);
|
||||||
|
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
||||||
|
mbedtls_entropy_free(&entropy_ctx);
|
||||||
|
|
||||||
|
PRINT_DEBUG("parsed key is not a valid RSA private key");
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the underlying RSA context from the parsed private key
|
||||||
|
mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(private_key_ctx);
|
||||||
|
|
||||||
|
// resize the output buffer to accomodate the size of the private key
|
||||||
|
const size_t private_key_len = mbedtls_pk_get_len(&private_key_ctx);
|
||||||
|
if (private_key_len == 0) { // TODO must be 128 siglen
|
||||||
|
mbedtls_pk_free(&private_key_ctx);
|
||||||
|
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
||||||
|
mbedtls_entropy_free(&entropy_ctx);
|
||||||
|
|
||||||
|
PRINT_DEBUG("failed to get private key (final buffer) length");
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("computed private key (final buffer) length = %zu", private_key_len);
|
||||||
|
signature.resize(private_key_len);
|
||||||
|
|
||||||
|
// finally sign the computed hash using RSA and PKCS#1 padding
|
||||||
|
result = mbedtls_rsa_pkcs1_sign(
|
||||||
|
rsa_ctx,
|
||||||
|
mbedtls_ctr_drbg_random, &ctr_drbg_ctx,
|
||||||
|
MBEDTLS_MD_SHA1, // we used SHA1 to hash the data
|
||||||
|
sizeof(hash), hash,
|
||||||
|
signature.data() // output
|
||||||
|
);
|
||||||
|
|
||||||
|
mbedtls_pk_free(&private_key_ctx);
|
||||||
|
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
||||||
|
mbedtls_entropy_free(&entropy_ctx);
|
||||||
|
|
||||||
|
if (result != 0) {
|
||||||
|
signature.clear();
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
std::string err_msg(256, 0);
|
||||||
|
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
||||||
|
PRINT_DEBUG("RSA signing failed: %s", err_msg.c_str());
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
auto str = common_helpers::uint8_vector_to_hex_string(signature);
|
||||||
|
PRINT_DEBUG("final signature [%zu bytes]:\n %s", signature.size(), str.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return signature;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
std::vector<uint8_t> DLC::Serialize() const
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("AppId = %u, Licenses count = %zu", AppId, Licenses.size());
|
||||||
|
|
||||||
|
// we need this variable because we depend on the sizeof, must be 2 bytes
|
||||||
|
const uint16_t dlcs_licenses_count = (uint16_t)Licenses.size();
|
||||||
|
const size_t dlcs_licenses_total_size =
|
||||||
|
Licenses.size() * sizeof(Licenses[0]); // count * element size
|
||||||
|
|
||||||
|
const size_t total_size =
|
||||||
|
sizeof(AppId) +
|
||||||
|
sizeof(dlcs_licenses_count) +
|
||||||
|
dlcs_licenses_total_size;
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
buffer.resize(total_size);
|
||||||
|
|
||||||
|
uint8_t* pBuffer = &buffer[0];
|
||||||
|
|
||||||
|
#define SER_VAR(v) \
|
||||||
|
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
||||||
|
pBuffer += sizeof(v)
|
||||||
|
|
||||||
|
SER_VAR(AppId);
|
||||||
|
SER_VAR(dlcs_licenses_count);
|
||||||
|
for(uint32_t dlc_license : Licenses) {
|
||||||
|
SER_VAR(dlc_license);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SER_VAR
|
||||||
|
|
||||||
|
PRINT_DEBUG("final size = %zu", buffer.size());
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AppTicketGC::Serialize() const
|
||||||
|
{
|
||||||
|
const uint64_t steam_id = id.ConvertToUint64();
|
||||||
|
|
||||||
|
// must be 52
|
||||||
|
constexpr size_t total_size =
|
||||||
|
sizeof(STEAM_APPTICKET_GCLen) +
|
||||||
|
sizeof(GCToken) +
|
||||||
|
sizeof(steam_id) +
|
||||||
|
sizeof(ticketGenDate) +
|
||||||
|
sizeof(STEAM_APPTICKET_SESSIONLEN) +
|
||||||
|
sizeof(one) +
|
||||||
|
sizeof(two) +
|
||||||
|
sizeof(ExternalIP) +
|
||||||
|
sizeof(InternalIP) +
|
||||||
|
sizeof(TimeSinceStartup) +
|
||||||
|
sizeof(TicketGeneratedCount);
|
||||||
|
|
||||||
|
// check the size at compile time, we must ensure the correct size
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
static_assert(
|
||||||
|
total_size == 52,
|
||||||
|
"AUTH::AppTicketGC::SER calculated size of serialized data != 52 bytes, your compiler has some incorrect sizes"
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PRINT_DEBUG(
|
||||||
|
"\n"
|
||||||
|
" GCToken: " "%" PRIu64 "\n"
|
||||||
|
" user steam_id: " "%" PRIu64 "\n"
|
||||||
|
" ticketGenDate: %u\n"
|
||||||
|
" ExternalIP: 0x%08X, InternalIP: 0x%08X\n"
|
||||||
|
" TimeSinceStartup: %u, TicketGeneratedCount: %u\n"
|
||||||
|
" SER size = %zu",
|
||||||
|
|
||||||
|
GCToken,
|
||||||
|
steam_id,
|
||||||
|
ticketGenDate,
|
||||||
|
ExternalIP, InternalIP,
|
||||||
|
TimeSinceStartup, TicketGeneratedCount,
|
||||||
|
total_size
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
buffer.resize(total_size);
|
||||||
|
|
||||||
|
uint8_t* pBuffer = &buffer[0];
|
||||||
|
|
||||||
|
#define SER_VAR(v) \
|
||||||
|
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
||||||
|
pBuffer += sizeof(v)
|
||||||
|
|
||||||
|
SER_VAR(STEAM_APPTICKET_GCLen);
|
||||||
|
SER_VAR(GCToken);
|
||||||
|
SER_VAR(steam_id);
|
||||||
|
SER_VAR(ticketGenDate);
|
||||||
|
SER_VAR(STEAM_APPTICKET_SESSIONLEN);
|
||||||
|
SER_VAR(one);
|
||||||
|
SER_VAR(two);
|
||||||
|
SER_VAR(ExternalIP);
|
||||||
|
SER_VAR(InternalIP);
|
||||||
|
SER_VAR(TimeSinceStartup);
|
||||||
|
SER_VAR(TicketGeneratedCount);
|
||||||
|
|
||||||
|
#undef SER_VAR
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
||||||
|
PRINT_DEBUG("final data [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> AppTicket::Serialize() const
|
||||||
|
{
|
||||||
|
const uint64_t steam_id = id.ConvertToUint64();
|
||||||
|
|
||||||
|
PRINT_DEBUG(
|
||||||
|
"\n"
|
||||||
|
" Version: %u\n"
|
||||||
|
" user steam_id: " "%" PRIu64 "\n"
|
||||||
|
" AppId: %u\n"
|
||||||
|
" ExternalIP: 0x%08X, InternalIP: 0x%08X\n"
|
||||||
|
" TicketGeneratedDate: %u, TicketGeneratedExpireDate: %u\n"
|
||||||
|
" Licenses count: %zu, DLCs count: %zu",
|
||||||
|
|
||||||
|
Version,
|
||||||
|
steam_id,
|
||||||
|
AppId,
|
||||||
|
ExternalIP, InternalIP,
|
||||||
|
TicketGeneratedDate, TicketGeneratedExpireDate,
|
||||||
|
Licenses.size(), DLCs.size()
|
||||||
|
);
|
||||||
|
|
||||||
|
// we need this variable because we depend on the sizeof, must be 2 bytes
|
||||||
|
const uint16_t licenses_count = (uint16_t)Licenses.size();
|
||||||
|
const size_t licenses_total_size =
|
||||||
|
Licenses.size() * sizeof(Licenses[0]); // total count * element size
|
||||||
|
|
||||||
|
// we need this variable because we depend on the sizeof, must be 2 bytes
|
||||||
|
const uint16_t dlcs_count = (uint16_t)DLCs.size();
|
||||||
|
size_t dlcs_total_size = 0;
|
||||||
|
std::vector<std::vector<uint8_t>> serialized_dlcs{};
|
||||||
|
for (const DLC &dlc : DLCs) {
|
||||||
|
auto dlc_ser = dlc.Serialize();
|
||||||
|
dlcs_total_size += dlc_ser.size();
|
||||||
|
serialized_dlcs.push_back(dlc_ser);
|
||||||
|
}
|
||||||
|
|
||||||
|
//padding
|
||||||
|
constexpr uint16_t padding = (uint16_t)0;
|
||||||
|
|
||||||
|
// must be 42
|
||||||
|
constexpr size_t static_fields_size =
|
||||||
|
sizeof(Version) +
|
||||||
|
sizeof(steam_id) +
|
||||||
|
sizeof(AppId) +
|
||||||
|
sizeof(ExternalIP) +
|
||||||
|
sizeof(InternalIP) +
|
||||||
|
sizeof(AlwaysZero) +
|
||||||
|
sizeof(TicketGeneratedDate) +
|
||||||
|
sizeof(TicketGeneratedExpireDate) +
|
||||||
|
|
||||||
|
sizeof(licenses_count) +
|
||||||
|
sizeof(dlcs_count) +
|
||||||
|
|
||||||
|
sizeof(padding);
|
||||||
|
|
||||||
|
// check the size at compile time, we must ensure the correct size
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
static_assert(
|
||||||
|
static_fields_size == 42,
|
||||||
|
"AUTH::AppTicket::SER calculated size of serialized data != 42 bytes, your compiler has some incorrect sizes"
|
||||||
|
);
|
||||||
|
#endif
|
||||||
|
|
||||||
|
const size_t total_size =
|
||||||
|
static_fields_size +
|
||||||
|
licenses_total_size +
|
||||||
|
dlcs_total_size;
|
||||||
|
|
||||||
|
PRINT_DEBUG("final size = %zu", total_size);
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer{};
|
||||||
|
buffer.resize(total_size);
|
||||||
|
uint8_t* pBuffer = &buffer[0];
|
||||||
|
|
||||||
|
#define SER_VAR(v) \
|
||||||
|
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
||||||
|
pBuffer += sizeof(v)
|
||||||
|
|
||||||
|
SER_VAR(Version);
|
||||||
|
SER_VAR(steam_id);
|
||||||
|
SER_VAR(AppId);
|
||||||
|
SER_VAR(ExternalIP);
|
||||||
|
SER_VAR(InternalIP);
|
||||||
|
SER_VAR(AlwaysZero);
|
||||||
|
SER_VAR(TicketGeneratedDate);
|
||||||
|
SER_VAR(TicketGeneratedExpireDate);
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
{
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
||||||
|
PRINT_DEBUG("(before licenses + DLCs):\n %s", str.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* layout of licenses:
|
||||||
|
* ------------------------
|
||||||
|
* 2 bytes: count of licenses
|
||||||
|
* ------------------------
|
||||||
|
* [
|
||||||
|
* ------------------------
|
||||||
|
* | 4 bytes: license element
|
||||||
|
* ------------------------
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
SER_VAR(licenses_count);
|
||||||
|
for(uint32_t license : Licenses) {
|
||||||
|
SER_VAR(license);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* layout of DLCs:
|
||||||
|
* ------------------------
|
||||||
|
* | 2 bytes: count of DLCs
|
||||||
|
* ------------------------
|
||||||
|
* [
|
||||||
|
* ------------------------
|
||||||
|
* | 4 bytes: app id
|
||||||
|
* ------------------------
|
||||||
|
* | 2 bytes: DLC licenses count
|
||||||
|
* ------------------------
|
||||||
|
* [
|
||||||
|
* 4 bytes: DLC license element
|
||||||
|
* ]
|
||||||
|
* ]
|
||||||
|
*/
|
||||||
|
SER_VAR(dlcs_count);
|
||||||
|
for (const auto &dlc_ser : serialized_dlcs){
|
||||||
|
memcpy(pBuffer, dlc_ser.data(), dlc_ser.size());
|
||||||
|
pBuffer += dlc_ser.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
//padding
|
||||||
|
SER_VAR(padding);
|
||||||
|
|
||||||
|
#undef SER_VAR
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
{
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
||||||
|
PRINT_DEBUG("final data [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<uint8_t> Auth_Data::Serialize() const
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* layout of Auth_Data with GC:
|
||||||
|
* ------------------------
|
||||||
|
* X bytes: GC data blob (currently 52 bytes)
|
||||||
|
* ------------------------
|
||||||
|
* 4 bytes: remaining Auth_Data blob size (4 + Y + Z)
|
||||||
|
* ------------------------
|
||||||
|
* 4 bytes: size of ticket data layout (not blob!, hence blob + 4)
|
||||||
|
* ------------------------
|
||||||
|
* Y bytes: ticket data blob
|
||||||
|
* ------------------------
|
||||||
|
* Z bytes: App Ticket signature
|
||||||
|
* ------------------------
|
||||||
|
*
|
||||||
|
* total layout length = X + 4 + 4 + Y + Z
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* layout of Auth_Data without GC:
|
||||||
|
* ------------------------
|
||||||
|
* 4 bytes: size of ticket data layout (not blob!, hence blob + 4)
|
||||||
|
* ------------------------
|
||||||
|
* Y bytes: ticket data blob
|
||||||
|
* ------------------------
|
||||||
|
* Z bytes: App Ticket signature
|
||||||
|
* ------------------------
|
||||||
|
*
|
||||||
|
* total layout length = 4 + Y + Z
|
||||||
|
*/
|
||||||
|
const uint64_t steam_id = id.ConvertToUint64();
|
||||||
|
|
||||||
|
PRINT_DEBUG(
|
||||||
|
"\n"
|
||||||
|
" HasGC: %u\n"
|
||||||
|
" user steam_id: " "%" PRIu64 "\n"
|
||||||
|
" number: " "%" PRIu64 ,
|
||||||
|
|
||||||
|
(int)HasGC,
|
||||||
|
steam_id,
|
||||||
|
number
|
||||||
|
);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* layout of ticket data:
|
||||||
|
* ------------------------
|
||||||
|
* 4 bytes: size of ticket data layout (not blob!, hence blob + 4)
|
||||||
|
* ------------------------
|
||||||
|
* Y bytes: ticket data blob
|
||||||
|
* ------------------------
|
||||||
|
*
|
||||||
|
* total layout length = 4 + Y
|
||||||
|
*/
|
||||||
|
std::vector<uint8_t> tickedData = Ticket.Serialize();
|
||||||
|
// we need this variable because we depend on the sizeof, must be 4 bytes
|
||||||
|
const uint32_t ticket_data_layout_length =
|
||||||
|
sizeof(uint32_t) + // size of this uint32_t because it is included!
|
||||||
|
(uint32_t)tickedData.size();
|
||||||
|
|
||||||
|
size_t total_size_without_siglen = ticket_data_layout_length;
|
||||||
|
|
||||||
|
std::vector<uint8_t> GCData{};
|
||||||
|
size_t gc_data_layout_length = 0;
|
||||||
|
if (HasGC) {
|
||||||
|
/*
|
||||||
|
* layout of GC data:
|
||||||
|
* ------------------------
|
||||||
|
* X bytes: GC data blob (currently 52 bytes)
|
||||||
|
* ------------------------
|
||||||
|
* 4 bytes: remaining Auth_Data blob size
|
||||||
|
* ------------------------
|
||||||
|
*
|
||||||
|
* total layout length = X + 4
|
||||||
|
*/
|
||||||
|
GCData = GC.Serialize();
|
||||||
|
gc_data_layout_length +=
|
||||||
|
GCData.size() +
|
||||||
|
sizeof(uint32_t);
|
||||||
|
|
||||||
|
total_size_without_siglen += gc_data_layout_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
const size_t final_buffer_size = total_size_without_siglen + STEAM_APPTICKET_SIGLEN;
|
||||||
|
PRINT_DEBUG("size without sig len = %zu, size with sig len (final size) = %zu",
|
||||||
|
total_size_without_siglen,
|
||||||
|
final_buffer_size
|
||||||
|
);
|
||||||
|
|
||||||
|
std::vector<uint8_t> buffer;
|
||||||
|
buffer.resize(final_buffer_size);
|
||||||
|
|
||||||
|
uint8_t* pBuffer = &buffer[0];
|
||||||
|
|
||||||
|
#define SER_VAR(v) \
|
||||||
|
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
||||||
|
pBuffer += sizeof(v)
|
||||||
|
|
||||||
|
// serialize the GC data first
|
||||||
|
if (HasGC) {
|
||||||
|
memcpy(pBuffer, GCData.data(), GCData.size());
|
||||||
|
pBuffer += GCData.size();
|
||||||
|
|
||||||
|
// when GC data is written (HasGC),
|
||||||
|
// the next 4 bytes after the GCData will be the length of the remaining data in the final buffer
|
||||||
|
// i.e. final buffer size - length of GCData layout
|
||||||
|
// i.e. ticket data length + STEAM_APPTICKET_SIGLEN
|
||||||
|
//
|
||||||
|
// notice that we subtract the entire layout length, not just GCData.size(),
|
||||||
|
// otherwise these next 4 bytes will include themselves!
|
||||||
|
uint32_t remaining_length = (uint32_t)(final_buffer_size - gc_data_layout_length);
|
||||||
|
SER_VAR(remaining_length);
|
||||||
|
}
|
||||||
|
|
||||||
|
// serialize the ticket data
|
||||||
|
SER_VAR(ticket_data_layout_length);
|
||||||
|
memcpy(pBuffer, tickedData.data(), tickedData.size());
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
{
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
||||||
|
PRINT_DEBUG("final data (before signature) [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
//Todo make a signature
|
||||||
|
std::vector<uint8_t> signature = sign_auth_data(app_ticket_key, tickedData, total_size_without_siglen);
|
||||||
|
if (signature.size() == STEAM_APPTICKET_SIGLEN) {
|
||||||
|
memcpy(buffer.data() + total_size_without_siglen, signature.data(), signature.size());
|
||||||
|
|
||||||
|
#ifndef EMU_RELEASE_BUILD
|
||||||
|
{
|
||||||
|
// we nedd a live object until the printf does its job, hence this special handling
|
||||||
|
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
||||||
|
PRINT_DEBUG("final data (after signature) [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PRINT_DEBUG("signature size [%zu] is invalid", signature.size());
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef SER_VAR
|
||||||
|
|
||||||
|
return buffer;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Auth_Manager::ticket_callback(void *object, Common_Message *msg)
|
||||||
{
|
{
|
||||||
// PRINT_DEBUG_ENTRY();
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
@ -32,22 +605,22 @@ static void steam_auth_manager_ticket_callback(void *object, Common_Message *msg
|
|||||||
auth_manager->Callback(msg);
|
auth_manager->Callback(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth_Manager::Auth_Manager(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks) {
|
Auth_Manager::Auth_Manager(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks)
|
||||||
|
{
|
||||||
this->network = network;
|
this->network = network;
|
||||||
this->settings = settings;
|
this->settings = settings;
|
||||||
this->callbacks = callbacks;
|
this->callbacks = callbacks;
|
||||||
|
|
||||||
this->network->setCallback(CALLBACK_ID_AUTH_TICKET, settings->get_local_steam_id(), &steam_auth_manager_ticket_callback, this);
|
this->network->setCallback(CALLBACK_ID_AUTH_TICKET, settings->get_local_steam_id(), &Auth_Manager::ticket_callback, this);
|
||||||
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &steam_auth_manager_ticket_callback, this);
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Auth_Manager::ticket_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Auth_Manager::~Auth_Manager()
|
Auth_Manager::~Auth_Manager()
|
||||||
{
|
{
|
||||||
this->network->rmCallback(CALLBACK_ID_AUTH_TICKET, settings->get_local_steam_id(), &steam_auth_manager_ticket_callback, this);
|
this->network->rmCallback(CALLBACK_ID_AUTH_TICKET, settings->get_local_steam_id(), &Auth_Manager::ticket_callback, this);
|
||||||
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &steam_auth_manager_ticket_callback, this);
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Auth_Manager::ticket_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STEAM_TICKET_PROCESS_TIME 0.03
|
|
||||||
|
|
||||||
void Auth_Manager::launch_callback(CSteamID id, EAuthSessionResponse resp, double delay)
|
void Auth_Manager::launch_callback(CSteamID id, EAuthSessionResponse resp, double delay)
|
||||||
{
|
{
|
||||||
@ -72,10 +645,6 @@ void Auth_Manager::launch_callback_gs(CSteamID id, bool approved)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#define STEAM_ID_OFFSET_TICKET (4 + 8)
|
|
||||||
#define STEAM_TICKET_MIN_SIZE (4 + 8 + 8)
|
|
||||||
#define STEAM_TICKET_MIN_SIZE_NEW 170
|
|
||||||
|
|
||||||
Auth_Data Auth_Manager::getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
Auth_Data Auth_Manager::getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
||||||
{
|
{
|
||||||
|
|
||||||
@ -153,11 +722,6 @@ Auth_Data Auth_Manager::getTicketData( void *pTicket, int cbMaxTicket, uint32 *p
|
|||||||
return ticket_data;
|
return ticket_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
//Conan Exiles doesn't work with 512 or 128, 256 seems to be the good size
|
|
||||||
// Usually steam send as 1024 (or recommend sending as that)
|
|
||||||
//Steam returns 234
|
|
||||||
#define STEAM_AUTH_TICKET_SIZE 256 //234
|
|
||||||
|
|
||||||
HAuthTicket Auth_Manager::getTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
HAuthTicket Auth_Manager::getTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
||||||
{
|
{
|
||||||
if (settings->enable_new_app_ticket)
|
if (settings->enable_new_app_ticket)
|
||||||
@ -301,6 +865,8 @@ bool Auth_Manager::endAuth(CSteamID id)
|
|||||||
return erased;
|
return erased;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Auth_Manager::Callback(Common_Message *msg)
|
void Auth_Manager::Callback(Common_Message *msg)
|
||||||
{
|
{
|
||||||
if (msg->has_low_level()) {
|
if (msg->has_low_level()) {
|
||||||
|
15
dll/base.cpp
15
dll/base.cpp
@ -17,6 +17,12 @@
|
|||||||
|
|
||||||
#include "dll/base.h"
|
#include "dll/base.h"
|
||||||
|
|
||||||
|
std::recursive_mutex global_mutex{};
|
||||||
|
// some arbitrary counter/time for reference
|
||||||
|
const std::chrono::time_point<std::chrono::high_resolution_clock> startup_counter = std::chrono::high_resolution_clock::now();
|
||||||
|
const std::chrono::time_point<std::chrono::system_clock> startup_time = std::chrono::system_clock::now();
|
||||||
|
|
||||||
|
|
||||||
#ifdef __WINDOWS__
|
#ifdef __WINDOWS__
|
||||||
|
|
||||||
void randombytes(char *buf, size_t size)
|
void randombytes(char *buf, size_t size)
|
||||||
@ -93,11 +99,6 @@ bool set_env_variable(const std::string &name, const std::string &value)
|
|||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::recursive_mutex global_mutex{};
|
|
||||||
|
|
||||||
// some arbitrary counter/time for reference
|
|
||||||
const std::chrono::time_point<std::chrono::high_resolution_clock> startup_counter = std::chrono::high_resolution_clock::now();
|
|
||||||
const std::chrono::time_point<std::chrono::system_clock> startup_time = std::chrono::system_clock::now();
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
#ifndef EMU_RELEASE_BUILD
|
||||||
const std::string dbg_log_file = get_full_program_path() + "STEAM_LOG.txt";
|
const std::string dbg_log_file = get_full_program_path() + "STEAM_LOG.txt";
|
||||||
@ -147,10 +148,6 @@ CSteamID generate_steam_id_lobby()
|
|||||||
return CSteamID(generate_account_id(), k_EChatInstanceFlagLobby | k_EChatInstanceFlagMMSLobby, k_EUniversePublic, k_EAccountTypeChat);
|
return CSteamID(generate_account_id(), k_EChatInstanceFlagLobby | k_EChatInstanceFlagMMSLobby, k_EUniversePublic, k_EAccountTypeChat);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @brief Check for a timeout given some initial timepoint and a timeout in sec.
|
|
||||||
/// @param old The initial timepoint which will be compared against current time
|
|
||||||
/// @param timeout The max allowed time in seconds
|
|
||||||
/// @return true if the timepoint has exceeded the max allowed timeout, false otherwise
|
|
||||||
bool check_timedout(std::chrono::high_resolution_clock::time_point old, double timeout)
|
bool check_timedout(std::chrono::high_resolution_clock::time_point old, double timeout)
|
||||||
{
|
{
|
||||||
if (timeout == 0.0) return true;
|
if (timeout == 0.0) return true;
|
||||||
|
406
dll/callsystem.cpp
Normal file
406
dll/callsystem.cpp
Normal file
@ -0,0 +1,406 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/callsystem.h"
|
||||||
|
|
||||||
|
|
||||||
|
void CCallbackMgr::SetRegister(class CCallbackBase *pCallback, int iCallback)
|
||||||
|
{
|
||||||
|
pCallback->m_nCallbackFlags |= CCallbackBase::k_ECallbackFlagsRegistered;
|
||||||
|
pCallback->m_iCallback = iCallback;
|
||||||
|
};
|
||||||
|
|
||||||
|
void CCallbackMgr::SetUnregister(class CCallbackBase *pCallback)
|
||||||
|
{
|
||||||
|
if (pCallback)
|
||||||
|
pCallback->m_nCallbackFlags &= !CCallbackBase::k_ECallbackFlagsRegistered;
|
||||||
|
};
|
||||||
|
|
||||||
|
bool CCallbackMgr::isServer(class CCallbackBase *pCallback)
|
||||||
|
{
|
||||||
|
return (pCallback->m_nCallbackFlags & CCallbackBase::k_ECallbackFlagsGameServer) != 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Call_Result::Steam_Call_Result(SteamAPICall_t a, int icb, void *r, unsigned int s, double r_in, bool run_cc_cb)
|
||||||
|
{
|
||||||
|
api_call = a;
|
||||||
|
result.resize(s);
|
||||||
|
if (s > 0 && r != NULL) {
|
||||||
|
memcpy(&(result[0]), r, s);
|
||||||
|
}
|
||||||
|
run_in = r_in;
|
||||||
|
run_call_completed_cb = run_cc_cb;
|
||||||
|
iCallback = icb;
|
||||||
|
created = std::chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Call_Result::operator==(const struct Steam_Call_Result& other) const
|
||||||
|
{
|
||||||
|
return other.api_call == api_call && other.callbacks == callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Call_Result::timed_out() const
|
||||||
|
{
|
||||||
|
return check_timedout(created, STEAM_CALLRESULT_TIMEOUT);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Call_Result::call_completed() const
|
||||||
|
{
|
||||||
|
return (!reserved) && check_timedout(created, run_in);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Call_Result::can_execute() const
|
||||||
|
{
|
||||||
|
return (!to_delete) && call_completed() && (has_cb() || check_timedout(created, STEAM_CALLRESULT_WAIT_FOR_CB));
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Call_Result::has_cb() const
|
||||||
|
{
|
||||||
|
return callbacks.size() > 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void SteamCallResults::addCallCompleted(class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
if (std::find(completed_callbacks.begin(), completed_callbacks.end(), cb) == completed_callbacks.end()) {
|
||||||
|
completed_callbacks.push_back(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallResults::rmCallCompleted(class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
auto c = std::find(completed_callbacks.begin(), completed_callbacks.end(), cb);
|
||||||
|
if (c != completed_callbacks.end()) {
|
||||||
|
completed_callbacks.erase(c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallResults::addCallBack(SteamAPICall_t api_call, class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
||||||
|
if (cb_result != callresults.end()) {
|
||||||
|
cb_result->callbacks.push_back(cb);
|
||||||
|
CCallbackMgr::SetRegister(cb, cb->GetICallback());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SteamCallResults::exists(SteamAPICall_t api_call) const
|
||||||
|
{
|
||||||
|
auto cr = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) {
|
||||||
|
return item.api_call == api_call;
|
||||||
|
});
|
||||||
|
if (callresults.end() == cr) return false;
|
||||||
|
if (!cr->call_completed()) return false;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SteamCallResults::callback_result(SteamAPICall_t api_call, void *copy_to, unsigned int size)
|
||||||
|
{
|
||||||
|
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) {
|
||||||
|
return item.api_call == api_call;
|
||||||
|
});
|
||||||
|
if (cb_result != callresults.end()) {
|
||||||
|
if (!cb_result->call_completed()) return false;
|
||||||
|
if (cb_result->result.size() > size) return false;
|
||||||
|
|
||||||
|
memcpy(copy_to, &(cb_result->result[0]), cb_result->result.size());
|
||||||
|
cb_result->to_delete = true;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallResults::rmCallBack(SteamAPICall_t api_call, class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
||||||
|
if (cb_result != callresults.end()) {
|
||||||
|
auto it = std::find(cb_result->callbacks.begin(), cb_result->callbacks.end(), cb);
|
||||||
|
if (it != cb_result->callbacks.end()) {
|
||||||
|
cb_result->callbacks.erase(it);
|
||||||
|
CCallbackMgr::SetUnregister(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallResults::rmCallBack(class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
//TODO: check if callback is callback or call result?
|
||||||
|
for (auto & cr: callresults) {
|
||||||
|
auto it = std::find(cr.callbacks.begin(), cr.callbacks.end(), cb);
|
||||||
|
if (it != cr.callbacks.end()) {
|
||||||
|
cr.callbacks.erase(it);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cr.callbacks.size() == 0) {
|
||||||
|
cr.to_delete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamAPICall_t SteamCallResults::addCallResult(SteamAPICall_t api_call, int iCallback, void *result, unsigned int size, double timeout, bool run_call_completed_cb)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i", iCallback);
|
||||||
|
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
||||||
|
if (cb_result != callresults.end()) {
|
||||||
|
if (cb_result->reserved) {
|
||||||
|
std::chrono::high_resolution_clock::time_point created = cb_result->created;
|
||||||
|
std::vector<class CCallbackBase *> temp_cbs = cb_result->callbacks;
|
||||||
|
*cb_result = Steam_Call_Result(api_call, iCallback, result, size, timeout, run_call_completed_cb);
|
||||||
|
cb_result->callbacks = temp_cbs;
|
||||||
|
cb_result->created = created;
|
||||||
|
return cb_result->api_call;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct Steam_Call_Result res = Steam_Call_Result(api_call, iCallback, result, size, timeout, run_call_completed_cb);
|
||||||
|
callresults.push_back(res);
|
||||||
|
return callresults.back().api_call;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("ERROR");
|
||||||
|
return k_uAPICallInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamAPICall_t SteamCallResults::reserveCallResult()
|
||||||
|
{
|
||||||
|
struct Steam_Call_Result res = Steam_Call_Result(generate_steam_api_call_id(), 0, NULL, 0, 0.0, true);
|
||||||
|
res.reserved = true;
|
||||||
|
callresults.push_back(res);
|
||||||
|
return callresults.back().api_call;
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamAPICall_t SteamCallResults::addCallResult(int iCallback, void *result, unsigned int size, double timeout, bool run_call_completed_cb)
|
||||||
|
{
|
||||||
|
return addCallResult(generate_steam_api_call_id(), iCallback, result, size, timeout, run_call_completed_cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallResults::setCbAll(void (*cb_all)(std::vector<char> result, int callback))
|
||||||
|
{
|
||||||
|
this->cb_all = cb_all;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallResults::runCallResults()
|
||||||
|
{
|
||||||
|
unsigned long current_size = callresults.size();
|
||||||
|
for (unsigned i = 0; i < current_size; ++i) {
|
||||||
|
unsigned index = i;
|
||||||
|
|
||||||
|
if (!callresults[index].to_delete) {
|
||||||
|
if (callresults[index].can_execute()) {
|
||||||
|
std::vector<char> result = callresults[index].result;
|
||||||
|
SteamAPICall_t api_call = callresults[index].api_call;
|
||||||
|
bool run_call_completed_cb = callresults[index].run_call_completed_cb;
|
||||||
|
int iCallback = callresults[index].iCallback;
|
||||||
|
if (run_call_completed_cb) {
|
||||||
|
callresults[index].run_call_completed_cb = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
callresults[index].to_delete = true;
|
||||||
|
if (callresults[index].has_cb()) {
|
||||||
|
std::vector<class CCallbackBase *> temp_cbs = callresults[index].callbacks;
|
||||||
|
for (auto & cb : temp_cbs) {
|
||||||
|
PRINT_DEBUG("Calling callresult %p %i", cb, cb->GetICallback());
|
||||||
|
global_mutex.unlock();
|
||||||
|
//TODO: unlock relock doesn't work if mutex was locked more than once.
|
||||||
|
if (run_call_completed_cb) { //run the right function depending on if it's a callback or a call result.
|
||||||
|
cb->Run(&(result[0]), false, api_call);
|
||||||
|
} else {
|
||||||
|
cb->Run(&(result[0]));
|
||||||
|
}
|
||||||
|
//COULD BE DELETED SO DON'T TOUCH CB
|
||||||
|
global_mutex.lock();
|
||||||
|
PRINT_DEBUG("callresult done");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (run_call_completed_cb) {
|
||||||
|
//can it happen that one is removed during the callback?
|
||||||
|
std::vector<class CCallbackBase *> callbacks = completed_callbacks;
|
||||||
|
SteamAPICallCompleted_t data{};
|
||||||
|
data.m_hAsyncCall = api_call;
|
||||||
|
data.m_iCallback = iCallback;
|
||||||
|
data.m_cubParam = result.size();
|
||||||
|
|
||||||
|
for (auto & cb: callbacks) {
|
||||||
|
PRINT_DEBUG("Call complete cb %i %p %llu", iCallback, cb, api_call);
|
||||||
|
//TODO: check if this is a problem or not.
|
||||||
|
SteamAPICallCompleted_t temp = data;
|
||||||
|
global_mutex.unlock();
|
||||||
|
cb->Run(&temp);
|
||||||
|
global_mutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cb_all) {
|
||||||
|
std::vector<char> res;
|
||||||
|
res.resize(sizeof(data));
|
||||||
|
memcpy(&(res[0]), &data, sizeof(data));
|
||||||
|
cb_all(res, data.k_iCallback);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (cb_all) {
|
||||||
|
cb_all(result, iCallback);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (callresults[index].timed_out()) {
|
||||||
|
callresults[index].to_delete = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("erase to_delete");
|
||||||
|
auto c = std::begin(callresults);
|
||||||
|
while (c != std::end(callresults)) {
|
||||||
|
if (c->to_delete) {
|
||||||
|
if (c->timed_out()) {
|
||||||
|
PRINT_DEBUG("removed callresult %i", c->iCallback);
|
||||||
|
c = callresults.erase(c);
|
||||||
|
} else {
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
SteamCallBacks::SteamCallBacks(SteamCallResults *results)
|
||||||
|
{
|
||||||
|
this->results = results;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::addCallBack(int iCallback, class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i", iCallback);
|
||||||
|
if (iCallback == SteamAPICallCompleted_t::k_iCallback) {
|
||||||
|
results->addCallCompleted(cb);
|
||||||
|
CCallbackMgr::SetRegister(cb, iCallback);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (std::find(callbacks[iCallback].callbacks.begin(), callbacks[iCallback].callbacks.end(), cb) == callbacks[iCallback].callbacks.end()) {
|
||||||
|
callbacks[iCallback].callbacks.push_back(cb);
|
||||||
|
CCallbackMgr::SetRegister(cb, iCallback);
|
||||||
|
for (auto & res: callbacks[iCallback].results) {
|
||||||
|
//TODO: timeout?
|
||||||
|
SteamAPICall_t api_id = results->addCallResult(iCallback, &(res[0]), res.size(), 0.0, false);
|
||||||
|
results->addCallBack(api_id, cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::addCBResult(int iCallback, void *result, unsigned int size, double timeout, bool dont_post_if_already)
|
||||||
|
{
|
||||||
|
if (dont_post_if_already) {
|
||||||
|
for (auto & r : callbacks[iCallback].results) {
|
||||||
|
if (r.size() == size) {
|
||||||
|
if (memcmp(&(r[0]), result, size) == 0) {
|
||||||
|
//cb already posted
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<char> temp{};
|
||||||
|
temp.resize(size);
|
||||||
|
memcpy(&(temp[0]), result, size);
|
||||||
|
callbacks[iCallback].results.push_back(temp);
|
||||||
|
for (auto cb: callbacks[iCallback].callbacks) {
|
||||||
|
SteamAPICall_t api_id = results->addCallResult(iCallback, result, size, timeout, false);
|
||||||
|
results->addCallBack(api_id, cb);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (callbacks[iCallback].callbacks.empty()) {
|
||||||
|
results->addCallResult(iCallback, result, size, timeout, false);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::addCBResult(int iCallback, void *result, unsigned int size)
|
||||||
|
{
|
||||||
|
addCBResult(iCallback, result, size, DEFAULT_CB_TIMEOUT, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::addCBResult(int iCallback, void *result, unsigned int size, bool dont_post_if_already)
|
||||||
|
{
|
||||||
|
addCBResult(iCallback, result, size, DEFAULT_CB_TIMEOUT, dont_post_if_already);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::addCBResult(int iCallback, void *result, unsigned int size, double timeout)
|
||||||
|
{
|
||||||
|
addCBResult(iCallback, result, size, timeout, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::rmCallBack(int iCallback, class CCallbackBase *cb)
|
||||||
|
{
|
||||||
|
if (iCallback == SteamAPICallCompleted_t::k_iCallback) {
|
||||||
|
results->rmCallCompleted(cb);
|
||||||
|
CCallbackMgr::SetUnregister(cb);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto c = std::find(callbacks[iCallback].callbacks.begin(), callbacks[iCallback].callbacks.end(), cb);
|
||||||
|
if (c != callbacks[iCallback].callbacks.end()) {
|
||||||
|
callbacks[iCallback].callbacks.erase(c);
|
||||||
|
CCallbackMgr::SetUnregister(cb);
|
||||||
|
results->rmCallBack(cb);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void SteamCallBacks::runCallBacks()
|
||||||
|
{
|
||||||
|
for (auto & c : callbacks) {
|
||||||
|
c.second.results.clear();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void RunEveryRunCB::add(void (*cb)(void *object), void *object)
|
||||||
|
{
|
||||||
|
remove(cb, object);
|
||||||
|
RunCBs rcb;
|
||||||
|
rcb.function = cb;
|
||||||
|
rcb.object = object;
|
||||||
|
cbs.push_back(rcb);
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunEveryRunCB::remove(void (*cb)(void *object), void *object)
|
||||||
|
{
|
||||||
|
auto c = std::begin(cbs);
|
||||||
|
while (c != std::end(cbs)) {
|
||||||
|
if (c->function == cb && c->object == object) {
|
||||||
|
c = cbs.erase(c);
|
||||||
|
} else {
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void RunEveryRunCB::run() const
|
||||||
|
{
|
||||||
|
std::vector<struct RunCBs> temp_cbs = cbs;
|
||||||
|
for (auto c : temp_cbs) {
|
||||||
|
c.function(c.object);
|
||||||
|
}
|
||||||
|
}
|
@ -24,55 +24,16 @@
|
|||||||
struct AppTicketV1
|
struct AppTicketV1
|
||||||
{
|
{
|
||||||
// Total ticket size - 16
|
// Total ticket size - 16
|
||||||
uint32_t TicketSize;
|
uint32_t TicketSize{};
|
||||||
uint32_t TicketVersion;
|
uint32_t TicketVersion{};
|
||||||
uint32_t Unk2;
|
uint32_t Unk2{};
|
||||||
std::vector<uint8_t> UserData;
|
std::vector<uint8_t> UserData{};
|
||||||
|
|
||||||
void Reset()
|
void Reset();
|
||||||
{
|
|
||||||
TicketSize = 0;
|
|
||||||
TicketVersion = 0;
|
|
||||||
Unk2 = 0;
|
|
||||||
UserData.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize() const;
|
||||||
{
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
uint8_t* pBuffer;
|
|
||||||
|
|
||||||
buffer.resize(16 + UserData.size());
|
bool Deserialize(const uint8_t* pBuffer, size_t size);
|
||||||
pBuffer = buffer.data();
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketSize; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketVersion; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = UserData.size(); pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = Unk2; pBuffer += 4;
|
|
||||||
memcpy(pBuffer, UserData.data(), UserData.size());
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Deserialize(const uint8_t* pBuffer, size_t size)
|
|
||||||
{
|
|
||||||
if (size < 16)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint32_t user_data_size;
|
|
||||||
|
|
||||||
TicketSize = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
TicketVersion = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
user_data_size = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
|
|
||||||
if (size < (user_data_size + 16))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
Unk2 = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
UserData.resize(user_data_size);
|
|
||||||
memcpy(UserData.data(), pBuffer, user_data_size);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//inline uint32_t TicketSize() { return *reinterpret_cast<uint32_t*>(_Buffer); }
|
//inline uint32_t TicketSize() { return *reinterpret_cast<uint32_t*>(_Buffer); }
|
||||||
//inline uint32_t TicketVersion(){ return *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(_Buffer) + 4); }
|
//inline uint32_t TicketVersion(){ return *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(_Buffer) + 4); }
|
||||||
@ -84,69 +45,24 @@ struct AppTicketV1
|
|||||||
struct AppTicketV2
|
struct AppTicketV2
|
||||||
{
|
{
|
||||||
// Totals ticket size - 16 - TicketV1::UserData.size()
|
// Totals ticket size - 16 - TicketV1::UserData.size()
|
||||||
uint32_t TicketSize;
|
uint32_t TicketSize{};
|
||||||
uint32_t TicketVersion;
|
uint32_t TicketVersion{};
|
||||||
uint64_t SteamID;
|
uint64_t SteamID{};
|
||||||
uint32_t AppID;
|
uint32_t AppID{};
|
||||||
uint32_t Unk1;
|
uint32_t Unk1{};
|
||||||
uint32_t Unk2;
|
uint32_t Unk2{};
|
||||||
uint32_t TicketFlags;
|
uint32_t TicketFlags{};
|
||||||
uint32_t TicketIssueTime;
|
uint32_t TicketIssueTime{};
|
||||||
uint32_t TicketValidityEnd;
|
uint32_t TicketValidityEnd{};
|
||||||
|
|
||||||
static constexpr uint32_t LicenseBorrowed = 0x00000002; // Bit 1: IsLicenseBorrowed
|
static constexpr const uint32_t LicenseBorrowed = 0x00000002; // Bit 1: IsLicenseBorrowed
|
||||||
static constexpr uint32_t LicenseTemporary = 0x00000004; // Bit 2: IsLicenseTemporary
|
static constexpr const uint32_t LicenseTemporary = 0x00000004; // Bit 2: IsLicenseTemporary
|
||||||
|
|
||||||
void Reset()
|
void Reset();
|
||||||
{
|
|
||||||
TicketSize = 0;
|
|
||||||
TicketVersion = 0;
|
|
||||||
SteamID = 0;
|
|
||||||
AppID = 0;
|
|
||||||
Unk1 = 0;
|
|
||||||
Unk2 = 0;
|
|
||||||
TicketFlags = 0;
|
|
||||||
TicketIssueTime = 0;
|
|
||||||
TicketValidityEnd = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize() const;
|
||||||
{
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
uint8_t* pBuffer;
|
|
||||||
|
|
||||||
buffer.resize(40);
|
bool Deserialize(const uint8_t* pBuffer, size_t size);
|
||||||
pBuffer = buffer.data();
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketSize; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketVersion; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint64_t*>(pBuffer) = SteamID; pBuffer += 8;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = AppID; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = Unk1; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = Unk2; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketFlags; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketIssueTime; pBuffer += 4;
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = TicketValidityEnd;
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Deserialize(const uint8_t* pBuffer, size_t size)
|
|
||||||
{
|
|
||||||
if (size < 40)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
TicketSize = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
TicketVersion = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
SteamID = *reinterpret_cast<const uint64_t*>(pBuffer); pBuffer += 8;
|
|
||||||
AppID = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
Unk1 = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
Unk2 = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
TicketFlags = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
TicketIssueTime = *reinterpret_cast<const uint32_t*>(pBuffer); pBuffer += 4;
|
|
||||||
TicketValidityEnd = *reinterpret_cast<const uint32_t*>(pBuffer);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
//inline uint32_t TicketSize() { return *reinterpret_cast<uint32_t*>(_Buffer); }
|
//inline uint32_t TicketSize() { return *reinterpret_cast<uint32_t*>(_Buffer); }
|
||||||
//inline uint32_t TicketVersion() { return *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(_Buffer) + 4); }
|
//inline uint32_t TicketVersion() { return *reinterpret_cast<uint32_t*>(reinterpret_cast<uintptr_t>(_Buffer) + 4); }
|
||||||
@ -161,109 +77,18 @@ struct AppTicketV2
|
|||||||
|
|
||||||
struct AppTicketV4
|
struct AppTicketV4
|
||||||
{
|
{
|
||||||
std::vector<uint32_t> AppIDs;
|
std::vector<uint32_t> AppIDs{};
|
||||||
|
|
||||||
bool HasVACStatus = false;
|
bool HasVACStatus = false;
|
||||||
uint32_t VACStatus;
|
uint32_t VACStatus{};
|
||||||
bool HasAppValue = false;
|
bool HasAppValue = false;
|
||||||
uint32_t AppValue;
|
uint32_t AppValue{};
|
||||||
|
|
||||||
void Reset()
|
void Reset();
|
||||||
{
|
|
||||||
AppIDs.clear();
|
|
||||||
HasVACStatus = false;
|
|
||||||
HasAppValue = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize();
|
||||||
{
|
|
||||||
std::vector<uint32_t> appids = AppIDs;
|
|
||||||
if (appids.size() == 0)
|
|
||||||
{
|
|
||||||
appids.emplace_back(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint16_t appid_count = static_cast<uint16_t>(appids.size() > 140 ? 140 : appids.size());
|
bool Deserialize(const uint8_t* pBuffer, size_t size);
|
||||||
size_t buffer_size = static_cast<uint32_t>(appid_count) * 4ul + 2ul;
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
uint8_t* pBuffer;
|
|
||||||
|
|
||||||
if (HasAppValue)
|
|
||||||
{// VACStatus + AppValue
|
|
||||||
buffer_size += 4;
|
|
||||||
if (!HasVACStatus)
|
|
||||||
{
|
|
||||||
HasVACStatus = true;
|
|
||||||
VACStatus = 0;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (HasVACStatus)
|
|
||||||
{// VACStatus only
|
|
||||||
buffer_size += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
buffer.resize(buffer_size);
|
|
||||||
pBuffer = buffer.data();
|
|
||||||
*reinterpret_cast<uint16_t*>(pBuffer) = appid_count;
|
|
||||||
pBuffer += 2;
|
|
||||||
|
|
||||||
for (int i = 0; i < appid_count && i < 140; ++i)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = appids[i];
|
|
||||||
pBuffer += 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (HasVACStatus)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = VACStatus;
|
|
||||||
pBuffer += 4;
|
|
||||||
}
|
|
||||||
if (HasAppValue)
|
|
||||||
{
|
|
||||||
*reinterpret_cast<uint32_t*>(pBuffer) = AppValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Deserialize(const uint8_t* pBuffer, size_t size)
|
|
||||||
{
|
|
||||||
if (size < 2)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
uint16_t appid_count = *reinterpret_cast<const uint16_t*>(pBuffer);
|
|
||||||
if (size < (appid_count * 4 + 2) || appid_count >= 140)
|
|
||||||
return false;
|
|
||||||
|
|
||||||
AppIDs.resize(appid_count);
|
|
||||||
pBuffer += 2;
|
|
||||||
size -= 2;
|
|
||||||
for (int i = 0; i < appid_count; ++i)
|
|
||||||
{
|
|
||||||
AppIDs[i] = *reinterpret_cast<const uint32_t*>(pBuffer);
|
|
||||||
pBuffer += 4;
|
|
||||||
size -= 4;
|
|
||||||
}
|
|
||||||
|
|
||||||
HasVACStatus = false;
|
|
||||||
HasAppValue = false;
|
|
||||||
|
|
||||||
if (size < 4)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
HasVACStatus = true;
|
|
||||||
VACStatus = *reinterpret_cast<const uint32_t*>(pBuffer);
|
|
||||||
pBuffer += 4;
|
|
||||||
size -= 4;
|
|
||||||
|
|
||||||
if (size < 4)
|
|
||||||
return true;
|
|
||||||
|
|
||||||
HasAppValue = true;
|
|
||||||
AppValue = *reinterpret_cast<const uint32_t*>(pBuffer);
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Often 1 with empty appid
|
// Often 1 with empty appid
|
||||||
//inline uint16_t AppIDCount() { return *reinterpret_cast<uint16_t*>(_Buffer); }
|
//inline uint16_t AppIDCount() { return *reinterpret_cast<uint16_t*>(_Buffer); }
|
||||||
@ -277,48 +102,13 @@ struct AppTicketV4
|
|||||||
class DecryptedAppTicket
|
class DecryptedAppTicket
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
AppTicketV1 TicketV1;
|
AppTicketV1 TicketV1{};
|
||||||
AppTicketV2 TicketV2;
|
AppTicketV2 TicketV2{};
|
||||||
AppTicketV4 TicketV4;
|
AppTicketV4 TicketV4{};
|
||||||
|
|
||||||
bool DeserializeTicket(const uint8_t* pBuffer, size_t buf_size)
|
bool DeserializeTicket(const uint8_t* pBuffer, size_t buf_size);
|
||||||
{
|
|
||||||
if (!TicketV1.Deserialize(pBuffer, buf_size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
pBuffer += 16 + TicketV1.UserData.size();
|
std::vector<uint8_t> SerializeTicket();
|
||||||
buf_size -= 16 + TicketV1.UserData.size();
|
|
||||||
if (!TicketV2.Deserialize(pBuffer, buf_size))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
if (TicketV2.TicketVersion > 2)
|
|
||||||
{
|
|
||||||
pBuffer += 40;
|
|
||||||
buf_size -= 40;
|
|
||||||
if (!TicketV4.Deserialize(pBuffer, buf_size))
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<uint8_t> SerializeTicket()
|
|
||||||
{
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
|
|
||||||
TicketV1.TicketSize = TicketV1.UserData.size() + 40 + 2 + ((TicketV4.AppIDs.size() == 0 ? 1 : TicketV4.AppIDs.size()) * 4) + (TicketV4.HasVACStatus ? 4 : 0) + (TicketV4.HasAppValue ? 4 : 0);
|
|
||||||
TicketV2.TicketSize = TicketV1.TicketSize - TicketV1.UserData.size();
|
|
||||||
|
|
||||||
buffer = TicketV1.Serialize();
|
|
||||||
|
|
||||||
auto v = TicketV2.Serialize();
|
|
||||||
|
|
||||||
buffer.insert(buffer.end(), v.begin(), v.end());
|
|
||||||
v = TicketV4.Serialize();
|
|
||||||
buffer.insert(buffer.end(), v.begin(), v.end());
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
@ -326,23 +116,13 @@ class Steam_AppTicket :
|
|||||||
public ISteamAppTicket
|
public ISteamAppTicket
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_AppTicket(class Settings *settings) :
|
Steam_AppTicket(class Settings *settings);
|
||||||
settings(settings)
|
|
||||||
{
|
|
||||||
|
|
||||||
}
|
virtual uint32 GetAppOwnershipTicketData( uint32 nAppID, void *pvBuffer, uint32 cbBufferLength, uint32 *piAppId, uint32 *piSteamId, uint32 *piSignature, uint32 *pcbSignature );
|
||||||
|
|
||||||
virtual uint32 GetAppOwnershipTicketData( uint32 nAppID, void *pvBuffer, uint32 cbBufferLength, uint32 *piAppId, uint32 *piSteamId, uint32 *piSignature, uint32 *pcbSignature )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("TODO %u, %p, %u, %p, %p, %p, %p", nAppID, pvBuffer, cbBufferLength, piAppId, piSteamId, piSignature, pcbSignature);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // __INCLUDED_STEAM_APP_TICKET_H__
|
#endif // __INCLUDED_STEAM_APP_TICKET_H__
|
||||||
|
648
dll/dll/auth.h
648
dll/dll/auth.h
@ -1,8 +1,8 @@
|
|||||||
// source: https://github.com/Detanup01/stmsrv/blob/main/Steam3Server/Others/AppTickets.cs
|
// source: https://github.com/Detanup01/stmsrv/blob/main/Steam3Server/Others/AppTickets.cs
|
||||||
// thanks Detanup01
|
// thanks Detanup01
|
||||||
|
|
||||||
#ifndef AUTH_INCLUDE
|
#ifndef AUTH_INCLUDE_H
|
||||||
#define AUTH_INCLUDE
|
#define AUTH_INCLUDE_H
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "mbedtls/pk.h"
|
#include "mbedtls/pk.h"
|
||||||
@ -14,646 +14,96 @@
|
|||||||
|
|
||||||
|
|
||||||
// the data type is important, we depend on sizeof() for each one of them
|
// the data type is important, we depend on sizeof() for each one of them
|
||||||
constexpr uint32_t STEAM_APPTICKET_SIGLEN = 128;
|
constexpr const static uint32_t STEAM_APPTICKET_SIGLEN = 128;
|
||||||
constexpr uint32_t STEAM_APPTICKET_GCLen = 20;
|
constexpr const static uint32_t STEAM_APPTICKET_GCLen = 20;
|
||||||
constexpr uint32_t STEAM_APPTICKET_SESSIONLEN = 24;
|
constexpr const static uint32_t STEAM_APPTICKET_SESSIONLEN = 24;
|
||||||
|
|
||||||
// source: https://github.com/Detanup01/stmsrv/blob/main/Cert/AppTicket.key
|
|
||||||
// thanks Detanup01
|
|
||||||
const static std::string app_ticket_key =
|
|
||||||
"-----BEGIN PRIVATE KEY-----\n"
|
|
||||||
"MIICdgIBADANBgkqhkiG9w0BAQEFAASCAmAwggJcAgEAAoGBAMITHOY6pfsvaGTI\n"
|
|
||||||
"llmilPa1+ev4BsUV0IW3+F/3pQlZ+o57CO1HbepSh2a37cbGUSehOVQ7lREPVXP3\n"
|
|
||||||
"UdyF5tU5IMytJef5N7euM5z2IG9IszeOReO87h2AmtlwGqnRj7qd0MeVxSAuUq7P\n"
|
|
||||||
"C/Ir1VyOg58+wAKxaPL18upylnGJAgMBAAECgYEAnKQQj0KG9VYuTCoaL/6pfPcj\n"
|
|
||||||
"4PEvhaM1yrfSIKMg8YtOT/G+IsWkUZyK7L1HjUhD+FiIjRQKHNrjfdYAnJz20Xom\n"
|
|
||||||
"k6iVt7ugihIne1Q3pGYG8TY9P1DPdN7zEnAVY1Bh2PAlqJWrif3v8v1dUGE/dYr2\n"
|
|
||||||
"U3M0JhvzO7VL1B/chIECQQDqW9G5azGMA/cL4jOg0pbj9GfxjJZeT7M2rBoIaRWP\n"
|
|
||||||
"C3ROndyb+BNahlKk6tbvqillvvMQQiSFGw/PbmCwtLL3AkEA0/79W0q9d3YCXQGW\n"
|
|
||||||
"k3hQvR8HEbxLmRaRF2gU4MOa5C0JqwsmxzdK4mKoJCpVAiu1gmFonLjn2hm8i+vK\n"
|
|
||||||
"b7hffwJAEiMpCACTxRJJfFH1TOz/YIT5xmfq+0GPzRtkqGH5mSh5x9vPxwJb/RWI\n"
|
|
||||||
"L9s85y90JLuyc/+qc+K0Rol0Ujip4QJAGLXVJEn+8ajAt8SSn5fbmV+/fDK9gRef\n"
|
|
||||||
"S+Im5NgH+ubBBL3lBD2Orfqf7K8+f2VG3+6oufPXmpV7Y7fVPdZ40wJALDujJXgi\n"
|
|
||||||
"XiCBSht1YScYjfmJh2/xZWh8/w+vs5ZTtrnW2FQvfvVDG9c1hrChhpvmA0QxdgWB\n"
|
|
||||||
"zSsAno/utcuB9w==\n"
|
|
||||||
"-----END PRIVATE KEY-----\n";
|
|
||||||
|
|
||||||
|
|
||||||
static std::vector<uint8_t> sign_auth_data(const std::string &private_key_content, const std::vector<uint8_t> &data, size_t effective_data_len) {
|
|
||||||
std::vector<uint8_t> signature{};
|
|
||||||
|
|
||||||
// Hash the data using SHA-1
|
|
||||||
constexpr static int SHA1_DIGEST_LENGTH = 20;
|
|
||||||
uint8_t hash[SHA1_DIGEST_LENGTH]{};
|
|
||||||
int result = mbedtls_sha1(data.data(), effective_data_len, hash);
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
std::string err_msg(256, 0);
|
|
||||||
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
|
||||||
PRINT_DEBUG("failed to hash the data via SHA1: %s", err_msg.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_entropy_context entropy_ctx; // entropy context for random number generation
|
|
||||||
mbedtls_entropy_init(&entropy_ctx);
|
|
||||||
|
|
||||||
mbedtls_ctr_drbg_context ctr_drbg_ctx; // CTR-DRBG context for deterministic random number generation
|
|
||||||
mbedtls_ctr_drbg_init(&ctr_drbg_ctx);
|
|
||||||
|
|
||||||
// seed the CTR-DRBG context with random numbers
|
|
||||||
result = mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, nullptr, 0);
|
|
||||||
if (mbedtls_ctr_drbg_seed(&ctr_drbg_ctx, mbedtls_entropy_func, &entropy_ctx, nullptr, 0) != 0)
|
|
||||||
{
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
|
||||||
mbedtls_entropy_free(&entropy_ctx);
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
std::string err_msg(256, 0);
|
|
||||||
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
|
||||||
PRINT_DEBUG("failed to seed the CTR-DRBG context: %s", err_msg.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
mbedtls_pk_context private_key_ctx; // holds the parsed private key
|
|
||||||
mbedtls_pk_init(&private_key_ctx);
|
|
||||||
|
|
||||||
result = mbedtls_pk_parse_key(
|
|
||||||
&private_key_ctx, // will hold the parsed private key
|
|
||||||
(const unsigned char *)private_key_content.c_str(),
|
|
||||||
private_key_content.size() + 1, // we MUST include the null terminator, otherwise this API returns an error!
|
|
||||||
nullptr, 0, // no password stuff, private key isn't protected
|
|
||||||
mbedtls_ctr_drbg_random, &ctr_drbg_ctx // random number generation function + the CTR-DRBG context it requires as an input
|
|
||||||
);
|
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
mbedtls_pk_free(&private_key_ctx);
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
|
||||||
mbedtls_entropy_free(&entropy_ctx);
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
std::string err_msg(256, 0);
|
|
||||||
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
|
||||||
PRINT_DEBUG("failed to parse private key: %s", err_msg.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
// private key must be valid RSA key
|
|
||||||
if (mbedtls_pk_get_type(&private_key_ctx) != MBEDTLS_PK_RSA || // invalid type
|
|
||||||
mbedtls_pk_can_do(&private_key_ctx, MBEDTLS_PK_RSA) == 0) // or initialized but not properly setup (maybe freed?)
|
|
||||||
{
|
|
||||||
mbedtls_pk_free(&private_key_ctx);
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
|
||||||
mbedtls_entropy_free(&entropy_ctx);
|
|
||||||
|
|
||||||
PRINT_DEBUG("parsed key is not a valid RSA private key");
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
// get the underlying RSA context from the parsed private key
|
|
||||||
mbedtls_rsa_context* rsa_ctx = mbedtls_pk_rsa(private_key_ctx);
|
|
||||||
|
|
||||||
// resize the output buffer to accomodate the size of the private key
|
|
||||||
const size_t private_key_len = mbedtls_pk_get_len(&private_key_ctx);
|
|
||||||
if (private_key_len == 0) // TODO must be 128 siglen
|
|
||||||
{
|
|
||||||
mbedtls_pk_free(&private_key_ctx);
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
|
||||||
mbedtls_entropy_free(&entropy_ctx);
|
|
||||||
|
|
||||||
PRINT_DEBUG("failed to get private key (final buffer) length");
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_DEBUG("computed private key (final buffer) length = %zu", private_key_len);
|
|
||||||
signature.resize(private_key_len);
|
|
||||||
|
|
||||||
// finally sign the computed hash using RSA and PKCS#1 padding
|
|
||||||
result = mbedtls_rsa_pkcs1_sign(
|
|
||||||
rsa_ctx,
|
|
||||||
mbedtls_ctr_drbg_random, &ctr_drbg_ctx,
|
|
||||||
MBEDTLS_MD_SHA1, // we used SHA1 to hash the data
|
|
||||||
sizeof(hash), hash,
|
|
||||||
signature.data() // output
|
|
||||||
);
|
|
||||||
|
|
||||||
mbedtls_pk_free(&private_key_ctx);
|
|
||||||
mbedtls_ctr_drbg_free(&ctr_drbg_ctx);
|
|
||||||
mbedtls_entropy_free(&entropy_ctx);
|
|
||||||
|
|
||||||
if (result != 0)
|
|
||||||
{
|
|
||||||
signature.clear();
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
std::string err_msg(256, 0);
|
|
||||||
mbedtls_strerror(result, &err_msg[0], err_msg.size());
|
|
||||||
PRINT_DEBUG("RSA signing failed: %s", err_msg.c_str());
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
auto str = common_helpers::uint8_vector_to_hex_string(signature);
|
|
||||||
PRINT_DEBUG("final signature [%zu bytes]:\n %s", signature.size(), str.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return signature;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
struct DLC {
|
struct DLC {
|
||||||
uint32_t AppId;
|
uint32_t AppId{};
|
||||||
std::vector<uint32_t> Licenses;
|
std::vector<uint32_t> Licenses{};
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize() const;
|
||||||
{
|
|
||||||
PRINT_DEBUG("AppId = %u, Licenses count = %zu", AppId, Licenses.size());
|
|
||||||
|
|
||||||
// we need this variable because we depend on the sizeof, must be 2 bytes
|
|
||||||
const uint16_t dlcs_licenses_count = (uint16_t)Licenses.size();
|
|
||||||
const size_t dlcs_licenses_total_size =
|
|
||||||
Licenses.size() * sizeof(Licenses[0]); // count * element size
|
|
||||||
|
|
||||||
const size_t total_size =
|
|
||||||
sizeof(AppId) +
|
|
||||||
sizeof(dlcs_licenses_count) +
|
|
||||||
dlcs_licenses_total_size;
|
|
||||||
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
buffer.resize(total_size);
|
|
||||||
|
|
||||||
uint8_t* pBuffer = buffer.data();
|
|
||||||
|
|
||||||
#define SER_VAR(v) \
|
|
||||||
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
|
||||||
pBuffer += sizeof(v)
|
|
||||||
|
|
||||||
SER_VAR(AppId);
|
|
||||||
SER_VAR(dlcs_licenses_count);
|
|
||||||
for(uint32_t dlc_license : Licenses)
|
|
||||||
{
|
|
||||||
SER_VAR(dlc_license);
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef SER_VAR
|
|
||||||
|
|
||||||
PRINT_DEBUG("final size = %zu", buffer.size());
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AppTicketGC {
|
struct AppTicketGC {
|
||||||
uint64_t GCToken;
|
uint64_t GCToken{};
|
||||||
CSteamID id;
|
CSteamID id{};
|
||||||
uint32_t ticketGenDate; //epoch
|
uint32_t ticketGenDate{}; //epoch
|
||||||
uint32_t ExternalIP;
|
uint32_t ExternalIP{};
|
||||||
uint32_t InternalIP;
|
uint32_t InternalIP{};
|
||||||
uint32_t TimeSinceStartup;
|
uint32_t TimeSinceStartup{};
|
||||||
uint32_t TicketGeneratedCount;
|
uint32_t TicketGeneratedCount{};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
uint32_t one = 1;
|
uint32_t one = 1;
|
||||||
uint32_t two = 2;
|
uint32_t two = 2;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize() const;
|
||||||
{
|
|
||||||
const uint64_t steam_id = id.ConvertToUint64();
|
|
||||||
|
|
||||||
// must be 52
|
|
||||||
constexpr size_t total_size =
|
|
||||||
sizeof(STEAM_APPTICKET_GCLen) +
|
|
||||||
sizeof(GCToken) +
|
|
||||||
sizeof(steam_id) +
|
|
||||||
sizeof(ticketGenDate) +
|
|
||||||
sizeof(STEAM_APPTICKET_SESSIONLEN) +
|
|
||||||
sizeof(one) +
|
|
||||||
sizeof(two) +
|
|
||||||
sizeof(ExternalIP) +
|
|
||||||
sizeof(InternalIP) +
|
|
||||||
sizeof(TimeSinceStartup) +
|
|
||||||
sizeof(TicketGeneratedCount);
|
|
||||||
|
|
||||||
// check the size at compile time, we must ensure the correct size
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
static_assert(
|
|
||||||
total_size == 52,
|
|
||||||
"AUTH::AppTicketGC::SER calculated size of serialized data != 52 bytes, your compiler has some incorrect sizes"
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
PRINT_DEBUG(
|
|
||||||
"\n"
|
|
||||||
" GCToken: " "%" PRIu64 "\n"
|
|
||||||
" user steam_id: " "%" PRIu64 "\n"
|
|
||||||
" ticketGenDate: %u\n"
|
|
||||||
" ExternalIP: 0x%08X, InternalIP: 0x%08X\n"
|
|
||||||
" TimeSinceStartup: %u, TicketGeneratedCount: %u\n"
|
|
||||||
" SER size = %zu",
|
|
||||||
|
|
||||||
GCToken,
|
|
||||||
steam_id,
|
|
||||||
ticketGenDate,
|
|
||||||
ExternalIP, InternalIP,
|
|
||||||
TimeSinceStartup, TicketGeneratedCount,
|
|
||||||
total_size
|
|
||||||
);
|
|
||||||
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
buffer.resize(total_size);
|
|
||||||
|
|
||||||
uint8_t* pBuffer = buffer.data();
|
|
||||||
|
|
||||||
#define SER_VAR(v) \
|
|
||||||
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
|
||||||
pBuffer += sizeof(v)
|
|
||||||
|
|
||||||
SER_VAR(STEAM_APPTICKET_GCLen);
|
|
||||||
SER_VAR(GCToken);
|
|
||||||
SER_VAR(steam_id);
|
|
||||||
SER_VAR(ticketGenDate);
|
|
||||||
SER_VAR(STEAM_APPTICKET_SESSIONLEN);
|
|
||||||
SER_VAR(one);
|
|
||||||
SER_VAR(two);
|
|
||||||
SER_VAR(ExternalIP);
|
|
||||||
SER_VAR(InternalIP);
|
|
||||||
SER_VAR(TimeSinceStartup);
|
|
||||||
SER_VAR(TicketGeneratedCount);
|
|
||||||
|
|
||||||
#undef SER_VAR
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
|
||||||
PRINT_DEBUG("final data [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct AppTicket {
|
struct AppTicket {
|
||||||
uint32_t Version;
|
uint32_t Version{};
|
||||||
CSteamID id;
|
CSteamID id{};
|
||||||
uint32_t AppId;
|
uint32_t AppId{};
|
||||||
uint32_t ExternalIP;
|
uint32_t ExternalIP{};
|
||||||
uint32_t InternalIP;
|
uint32_t InternalIP{};
|
||||||
uint32_t AlwaysZero = 0; //OwnershipFlags?
|
uint32_t AlwaysZero = 0; //OwnershipFlags?
|
||||||
uint32_t TicketGeneratedDate;
|
uint32_t TicketGeneratedDate{};
|
||||||
uint32_t TicketGeneratedExpireDate;
|
uint32_t TicketGeneratedExpireDate{};
|
||||||
std::vector<uint32_t> Licenses;
|
std::vector<uint32_t> Licenses{};
|
||||||
std::vector<DLC> DLCs;
|
std::vector<DLC> DLCs{};
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize() const;
|
||||||
{
|
|
||||||
const uint64_t steam_id = id.ConvertToUint64();
|
|
||||||
|
|
||||||
PRINT_DEBUG(
|
|
||||||
"\n"
|
|
||||||
" Version: %u\n"
|
|
||||||
" user steam_id: " "%" PRIu64 "\n"
|
|
||||||
" AppId: %u\n"
|
|
||||||
" ExternalIP: 0x%08X, InternalIP: 0x%08X\n"
|
|
||||||
" TicketGeneratedDate: %u, TicketGeneratedExpireDate: %u\n"
|
|
||||||
" Licenses count: %zu, DLCs count: %zu",
|
|
||||||
|
|
||||||
Version,
|
|
||||||
steam_id,
|
|
||||||
AppId,
|
|
||||||
ExternalIP, InternalIP,
|
|
||||||
TicketGeneratedDate, TicketGeneratedExpireDate,
|
|
||||||
Licenses.size(), DLCs.size()
|
|
||||||
);
|
|
||||||
|
|
||||||
// we need this variable because we depend on the sizeof, must be 2 bytes
|
|
||||||
const uint16_t licenses_count = (uint16_t)Licenses.size();
|
|
||||||
const size_t licenses_total_size =
|
|
||||||
Licenses.size() * sizeof(Licenses[0]); // total count * element size
|
|
||||||
|
|
||||||
// we need this variable because we depend on the sizeof, must be 2 bytes
|
|
||||||
const uint16_t dlcs_count = (uint16_t)DLCs.size();
|
|
||||||
size_t dlcs_total_size = 0;
|
|
||||||
std::vector<std::vector<uint8_t>> serialized_dlcs;
|
|
||||||
for (DLC &dlc : DLCs)
|
|
||||||
{
|
|
||||||
auto dlc_ser = dlc.Serialize();
|
|
||||||
dlcs_total_size += dlc_ser.size();
|
|
||||||
serialized_dlcs.push_back(dlc_ser);
|
|
||||||
}
|
|
||||||
|
|
||||||
//padding
|
|
||||||
constexpr uint16_t padding = (uint16_t)0;
|
|
||||||
|
|
||||||
// must be 42
|
|
||||||
constexpr size_t static_fields_size =
|
|
||||||
sizeof(Version) +
|
|
||||||
sizeof(steam_id) +
|
|
||||||
sizeof(AppId) +
|
|
||||||
sizeof(ExternalIP) +
|
|
||||||
sizeof(InternalIP) +
|
|
||||||
sizeof(AlwaysZero) +
|
|
||||||
sizeof(TicketGeneratedDate) +
|
|
||||||
sizeof(TicketGeneratedExpireDate) +
|
|
||||||
|
|
||||||
sizeof(licenses_count) +
|
|
||||||
sizeof(dlcs_count) +
|
|
||||||
|
|
||||||
sizeof(padding);
|
|
||||||
|
|
||||||
// check the size at compile time, we must ensure the correct size
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
static_assert(
|
|
||||||
static_fields_size == 42,
|
|
||||||
"AUTH::AppTicket::SER calculated size of serialized data != 42 bytes, your compiler has some incorrect sizes"
|
|
||||||
);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const size_t total_size =
|
|
||||||
static_fields_size +
|
|
||||||
licenses_total_size +
|
|
||||||
dlcs_total_size;
|
|
||||||
|
|
||||||
PRINT_DEBUG("final size = %zu", total_size);
|
|
||||||
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
buffer.resize(total_size);
|
|
||||||
uint8_t* pBuffer = buffer.data();
|
|
||||||
|
|
||||||
#define SER_VAR(v) \
|
|
||||||
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
|
||||||
pBuffer += sizeof(v)
|
|
||||||
|
|
||||||
SER_VAR(Version);
|
|
||||||
SER_VAR(steam_id);
|
|
||||||
SER_VAR(AppId);
|
|
||||||
SER_VAR(ExternalIP);
|
|
||||||
SER_VAR(InternalIP);
|
|
||||||
SER_VAR(AlwaysZero);
|
|
||||||
SER_VAR(TicketGeneratedDate);
|
|
||||||
SER_VAR(TicketGeneratedExpireDate);
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
{
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
|
||||||
PRINT_DEBUG("(before licenses + DLCs):\n %s", str.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
/*
|
|
||||||
* layout of licenses:
|
|
||||||
* ------------------------
|
|
||||||
* 2 bytes: count of licenses
|
|
||||||
* ------------------------
|
|
||||||
* [
|
|
||||||
* ------------------------
|
|
||||||
* | 4 bytes: license element
|
|
||||||
* ------------------------
|
|
||||||
* ]
|
|
||||||
*/
|
|
||||||
SER_VAR(licenses_count);
|
|
||||||
for(uint32_t license : Licenses)
|
|
||||||
{
|
|
||||||
SER_VAR(license);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* layout of DLCs:
|
|
||||||
* ------------------------
|
|
||||||
* | 2 bytes: count of DLCs
|
|
||||||
* ------------------------
|
|
||||||
* [
|
|
||||||
* ------------------------
|
|
||||||
* | 4 bytes: app id
|
|
||||||
* ------------------------
|
|
||||||
* | 2 bytes: DLC licenses count
|
|
||||||
* ------------------------
|
|
||||||
* [
|
|
||||||
* 4 bytes: DLC license element
|
|
||||||
* ]
|
|
||||||
* ]
|
|
||||||
*/
|
|
||||||
SER_VAR(dlcs_count);
|
|
||||||
for (std::vector<uint8_t> &dlc_ser : serialized_dlcs)
|
|
||||||
{
|
|
||||||
memcpy(pBuffer, dlc_ser.data(), dlc_ser.size());
|
|
||||||
pBuffer += dlc_ser.size();
|
|
||||||
}
|
|
||||||
|
|
||||||
//padding
|
|
||||||
SER_VAR(padding);
|
|
||||||
|
|
||||||
#undef SER_VAR
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
{
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
|
||||||
PRINT_DEBUG("final data [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Auth_Data {
|
struct Auth_Data {
|
||||||
bool HasGC;
|
bool HasGC{};
|
||||||
AppTicketGC GC;
|
AppTicketGC GC{};
|
||||||
AppTicket Ticket;
|
AppTicket Ticket{};
|
||||||
//old data
|
//old data
|
||||||
CSteamID id;
|
CSteamID id{};
|
||||||
uint64_t number;
|
uint64_t number{};
|
||||||
std::chrono::high_resolution_clock::time_point created;
|
std::chrono::high_resolution_clock::time_point created{};
|
||||||
|
|
||||||
std::vector<uint8_t> Serialize()
|
std::vector<uint8_t> Serialize() const;
|
||||||
{
|
|
||||||
/*
|
|
||||||
* layout of Auth_Data with GC:
|
|
||||||
* ------------------------
|
|
||||||
* X bytes: GC data blob (currently 52 bytes)
|
|
||||||
* ------------------------
|
|
||||||
* 4 bytes: remaining Auth_Data blob size (4 + Y + Z)
|
|
||||||
* ------------------------
|
|
||||||
* 4 bytes: size of ticket data layout (not blob!, hence blob + 4)
|
|
||||||
* ------------------------
|
|
||||||
* Y bytes: ticket data blob
|
|
||||||
* ------------------------
|
|
||||||
* Z bytes: App Ticket signature
|
|
||||||
* ------------------------
|
|
||||||
*
|
|
||||||
* total layout length = X + 4 + 4 + Y + Z
|
|
||||||
*/
|
|
||||||
|
|
||||||
/*
|
|
||||||
* layout of Auth_Data without GC:
|
|
||||||
* ------------------------
|
|
||||||
* 4 bytes: size of ticket data layout (not blob!, hence blob + 4)
|
|
||||||
* ------------------------
|
|
||||||
* Y bytes: ticket data blob
|
|
||||||
* ------------------------
|
|
||||||
* Z bytes: App Ticket signature
|
|
||||||
* ------------------------
|
|
||||||
*
|
|
||||||
* total layout length = 4 + Y + Z
|
|
||||||
*/
|
|
||||||
const uint64_t steam_id = id.ConvertToUint64();
|
|
||||||
|
|
||||||
PRINT_DEBUG(
|
|
||||||
"\n"
|
|
||||||
" HasGC: %u\n"
|
|
||||||
" user steam_id: " "%" PRIu64 "\n"
|
|
||||||
" number: " "%" PRIu64 ,
|
|
||||||
|
|
||||||
(int)HasGC,
|
|
||||||
steam_id,
|
|
||||||
number
|
|
||||||
);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* layout of ticket data:
|
|
||||||
* ------------------------
|
|
||||||
* 4 bytes: size of ticket data layout (not blob!, hence blob + 4)
|
|
||||||
* ------------------------
|
|
||||||
* Y bytes: ticket data blob
|
|
||||||
* ------------------------
|
|
||||||
*
|
|
||||||
* total layout length = 4 + Y
|
|
||||||
*/
|
|
||||||
std::vector<uint8_t> tickedData = Ticket.Serialize();
|
|
||||||
// we need this variable because we depend on the sizeof, must be 4 bytes
|
|
||||||
const uint32_t ticket_data_layout_length =
|
|
||||||
sizeof(uint32_t) + // size of this uint32_t because it is included!
|
|
||||||
(uint32_t)tickedData.size();
|
|
||||||
|
|
||||||
size_t total_size_without_siglen = ticket_data_layout_length;
|
|
||||||
|
|
||||||
std::vector<uint8_t> GCData;
|
|
||||||
size_t gc_data_layout_length = 0;
|
|
||||||
if (HasGC)
|
|
||||||
{
|
|
||||||
/*
|
|
||||||
* layout of GC data:
|
|
||||||
* ------------------------
|
|
||||||
* X bytes: GC data blob (currently 52 bytes)
|
|
||||||
* ------------------------
|
|
||||||
* 4 bytes: remaining Auth_Data blob size
|
|
||||||
* ------------------------
|
|
||||||
*
|
|
||||||
* total layout length = X + 4
|
|
||||||
*/
|
|
||||||
GCData = GC.Serialize();
|
|
||||||
gc_data_layout_length +=
|
|
||||||
GCData.size() +
|
|
||||||
sizeof(uint32_t);
|
|
||||||
|
|
||||||
total_size_without_siglen += gc_data_layout_length;
|
|
||||||
}
|
|
||||||
|
|
||||||
const size_t final_buffer_size = total_size_without_siglen + STEAM_APPTICKET_SIGLEN;
|
|
||||||
PRINT_DEBUG("size without sig len = %zu, size with sig len (final size) = %zu",
|
|
||||||
total_size_without_siglen,
|
|
||||||
final_buffer_size
|
|
||||||
);
|
|
||||||
|
|
||||||
std::vector<uint8_t> buffer;
|
|
||||||
buffer.resize(final_buffer_size);
|
|
||||||
|
|
||||||
uint8_t* pBuffer = buffer.data();
|
|
||||||
|
|
||||||
#define SER_VAR(v) \
|
|
||||||
*reinterpret_cast<std::remove_const<decltype(v)>::type *>(pBuffer) = v; \
|
|
||||||
pBuffer += sizeof(v)
|
|
||||||
|
|
||||||
// serialize the GC data first
|
|
||||||
if (HasGC)
|
|
||||||
{
|
|
||||||
memcpy(pBuffer, GCData.data(), GCData.size());
|
|
||||||
pBuffer += GCData.size();
|
|
||||||
|
|
||||||
// when GC data is written (HasGC),
|
|
||||||
// the next 4 bytes after the GCData will be the length of the remaining data in the final buffer
|
|
||||||
// i.e. final buffer size - length of GCData layout
|
|
||||||
// i.e. ticket data length + STEAM_APPTICKET_SIGLEN
|
|
||||||
//
|
|
||||||
// notice that we subtract the entire layout length, not just GCData.size(),
|
|
||||||
// otherwise these next 4 bytes will include themselves!
|
|
||||||
uint32_t remaining_length = (uint32_t)(final_buffer_size - gc_data_layout_length);
|
|
||||||
SER_VAR(remaining_length);
|
|
||||||
}
|
|
||||||
|
|
||||||
// serialize the ticket data
|
|
||||||
SER_VAR(ticket_data_layout_length);
|
|
||||||
memcpy(pBuffer, tickedData.data(), tickedData.size());
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
{
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
|
||||||
PRINT_DEBUG("final data (before signature) [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
//Todo make a signature
|
|
||||||
std::vector<uint8_t> signature = sign_auth_data(app_ticket_key, tickedData, total_size_without_siglen);
|
|
||||||
if (signature.size() == STEAM_APPTICKET_SIGLEN) {
|
|
||||||
memcpy(buffer.data() + total_size_without_siglen, signature.data(), signature.size());
|
|
||||||
|
|
||||||
#ifndef EMU_RELEASE_BUILD
|
|
||||||
{
|
|
||||||
// we nedd a live object until the printf does its job, hence this special handling
|
|
||||||
auto str = common_helpers::uint8_vector_to_hex_string(buffer);
|
|
||||||
PRINT_DEBUG("final data (after signature) [%zu bytes]:\n %s", buffer.size(), str.c_str());
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
} else {
|
|
||||||
PRINT_DEBUG("signature size [%zu] is invalid", signature.size());
|
|
||||||
}
|
|
||||||
|
|
||||||
#undef SER_VAR
|
|
||||||
|
|
||||||
return buffer;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class Auth_Manager {
|
class Auth_Manager {
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
|
std::vector<struct Auth_Data> inbound{};
|
||||||
|
std::vector<struct Auth_Data> outbound{};
|
||||||
|
|
||||||
void launch_callback(CSteamID id, EAuthSessionResponse resp, double delay=0);
|
void launch_callback(CSteamID id, EAuthSessionResponse resp, double delay=0);
|
||||||
void launch_callback_gs(CSteamID id, bool approved);
|
void launch_callback_gs(CSteamID id, bool approved);
|
||||||
std::vector<struct Auth_Data> inbound;
|
|
||||||
std::vector<struct Auth_Data> outbound;
|
static void ticket_callback(void *object, Common_Message *msg);
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Auth_Manager(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks);
|
Auth_Manager(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks);
|
||||||
~Auth_Manager();
|
~Auth_Manager();
|
||||||
|
|
||||||
void Callback(Common_Message *msg);
|
|
||||||
HAuthTicket getTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
|
HAuthTicket getTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
|
||||||
HAuthTicket getWebApiTicket( const char *pchIdentity );
|
HAuthTicket getWebApiTicket( const char *pchIdentity );
|
||||||
void cancelTicket(uint32 number);
|
void cancelTicket(uint32 number);
|
||||||
|
|
||||||
EBeginAuthSessionResult beginAuth(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID);
|
EBeginAuthSessionResult beginAuth(const void *pAuthTicket, int cbAuthTicket, CSteamID steamID);
|
||||||
bool endAuth(CSteamID id);
|
bool endAuth(CSteamID id);
|
||||||
|
|
||||||
uint32 countInboundAuth();
|
uint32 countInboundAuth();
|
||||||
|
|
||||||
bool SendUserConnectAndAuthenticate( uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser );
|
bool SendUserConnectAndAuthenticate( uint32 unIPClient, const void *pvAuthBlob, uint32 cubAuthBlobSize, CSteamID *pSteamIDUser );
|
||||||
|
|
||||||
CSteamID fakeUser();
|
CSteamID fakeUser();
|
||||||
|
|
||||||
Auth_Data getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
|
Auth_Data getTicketData( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // AUTH_INCLUDE
|
#endif // AUTH_INCLUDE_H
|
||||||
|
402
dll/dll/base.h
402
dll/dll/base.h
@ -15,17 +15,14 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#ifndef BASE_INCLUDE
|
#ifndef BASE_INCLUDE_H
|
||||||
#define BASE_INCLUDE
|
#define BASE_INCLUDE_H
|
||||||
|
|
||||||
#include "common_includes.h"
|
#include "common_includes.h"
|
||||||
|
#include "callsystem.h"
|
||||||
|
|
||||||
#define PUSH_BACK_IF_NOT_IN(vector, element) { if(std::find(vector.begin(), vector.end(), element) == vector.end()) vector.push_back(element); }
|
#define PUSH_BACK_IF_NOT_IN(vector, element) { if(std::find(vector.begin(), vector.end(), element) == vector.end()) vector.push_back(element); }
|
||||||
|
|
||||||
#define STEAM_CALLRESULT_TIMEOUT 120.0
|
|
||||||
#define STEAM_CALLRESULT_WAIT_FOR_CB 0.01
|
|
||||||
#define DEFAULT_CB_TIMEOUT 0.002
|
|
||||||
|
|
||||||
|
|
||||||
extern std::recursive_mutex global_mutex;
|
extern std::recursive_mutex global_mutex;
|
||||||
extern const std::chrono::time_point<std::chrono::high_resolution_clock> startup_counter;
|
extern const std::chrono::time_point<std::chrono::high_resolution_clock> startup_counter;
|
||||||
@ -34,70 +31,13 @@ extern const std::chrono::time_point<std::chrono::system_clock> startup_time;
|
|||||||
void randombytes(char *buf, size_t size);
|
void randombytes(char *buf, size_t size);
|
||||||
std::string get_env_variable(const std::string &name);
|
std::string get_env_variable(const std::string &name);
|
||||||
bool set_env_variable(const std::string &name, const std::string &value);
|
bool set_env_variable(const std::string &name, const std::string &value);
|
||||||
|
|
||||||
|
/// @brief Check for a timeout given some initial timepoint and a timeout in sec.
|
||||||
|
/// @param old The initial timepoint which will be compared against current time
|
||||||
|
/// @param timeout The max allowed time in seconds
|
||||||
|
/// @return true if the timepoint has exceeded the max allowed timeout, false otherwise
|
||||||
bool check_timedout(std::chrono::high_resolution_clock::time_point old, double timeout);
|
bool check_timedout(std::chrono::high_resolution_clock::time_point old, double timeout);
|
||||||
|
|
||||||
class CCallbackMgr
|
|
||||||
{
|
|
||||||
public:
|
|
||||||
static void SetRegister(class CCallbackBase *pCallback, int iCallback) {
|
|
||||||
pCallback->m_nCallbackFlags |= CCallbackBase::k_ECallbackFlagsRegistered;
|
|
||||||
pCallback->m_iCallback = iCallback;
|
|
||||||
};
|
|
||||||
|
|
||||||
static void SetUnregister(class CCallbackBase *pCallback) {
|
|
||||||
if (pCallback)
|
|
||||||
pCallback->m_nCallbackFlags &= !CCallbackBase::k_ECallbackFlagsRegistered;
|
|
||||||
};
|
|
||||||
|
|
||||||
static bool isServer(class CCallbackBase *pCallback) {
|
|
||||||
return (pCallback->m_nCallbackFlags & CCallbackBase::k_ECallbackFlagsGameServer) != 0;
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Steam_Call_Result {
|
|
||||||
Steam_Call_Result(SteamAPICall_t a, int icb, void *r, unsigned int s, double r_in, bool run_cc_cb) {
|
|
||||||
api_call = a;
|
|
||||||
result.resize(s);
|
|
||||||
if (s > 0 && r != NULL)
|
|
||||||
memcpy(&(result[0]), r, s);
|
|
||||||
created = std::chrono::high_resolution_clock::now();
|
|
||||||
run_in = r_in;
|
|
||||||
run_call_completed_cb = run_cc_cb;
|
|
||||||
iCallback = icb;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(const struct Steam_Call_Result& a)
|
|
||||||
{
|
|
||||||
return a.api_call == api_call && a.callbacks == callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool timed_out() {
|
|
||||||
return check_timedout(created, STEAM_CALLRESULT_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool call_completed() {
|
|
||||||
return (!reserved) && check_timedout(created, run_in);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool can_execute() {
|
|
||||||
return (!to_delete) && call_completed() && (has_cb() || check_timedout(created, STEAM_CALLRESULT_WAIT_FOR_CB));
|
|
||||||
}
|
|
||||||
|
|
||||||
bool has_cb() {
|
|
||||||
return callbacks.size() > 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
SteamAPICall_t api_call{};
|
|
||||||
std::vector<class CCallbackBase *> callbacks{};
|
|
||||||
std::vector<char> result{};
|
|
||||||
bool to_delete = false;
|
|
||||||
bool reserved = false;
|
|
||||||
std::chrono::high_resolution_clock::time_point created{};
|
|
||||||
double run_in{};
|
|
||||||
bool run_call_completed_cb{};
|
|
||||||
int iCallback{};
|
|
||||||
};
|
|
||||||
|
|
||||||
unsigned generate_account_id();
|
unsigned generate_account_id();
|
||||||
CSteamID generate_steam_anon_user();
|
CSteamID generate_steam_anon_user();
|
||||||
SteamAPICall_t generate_steam_api_call_id();
|
SteamAPICall_t generate_steam_api_call_id();
|
||||||
@ -112,334 +52,10 @@ std::string canonical_path(const std::string &path);
|
|||||||
bool file_exists_(const std::string &full_path);
|
bool file_exists_(const std::string &full_path);
|
||||||
unsigned int file_size_(const std::string &full_path);
|
unsigned int file_size_(const std::string &full_path);
|
||||||
|
|
||||||
class SteamCallResults {
|
|
||||||
std::vector<struct Steam_Call_Result> callresults{};
|
|
||||||
std::vector<class CCallbackBase *> completed_callbacks{};
|
|
||||||
void (*cb_all)(std::vector<char> result, int callback) = nullptr;
|
|
||||||
|
|
||||||
public:
|
|
||||||
void addCallCompleted(class CCallbackBase *cb) {
|
|
||||||
if (std::find(completed_callbacks.begin(), completed_callbacks.end(), cb) == completed_callbacks.end()) {
|
|
||||||
completed_callbacks.push_back(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rmCallCompleted(class CCallbackBase *cb) {
|
|
||||||
auto c = std::find(completed_callbacks.begin(), completed_callbacks.end(), cb);
|
|
||||||
if (c != completed_callbacks.end()) {
|
|
||||||
completed_callbacks.erase(c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCallBack(SteamAPICall_t api_call, class CCallbackBase *cb) {
|
|
||||||
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
|
||||||
if (cb_result != callresults.end()) {
|
|
||||||
cb_result->callbacks.push_back(cb);
|
|
||||||
CCallbackMgr::SetRegister(cb, cb->GetICallback());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool exists(SteamAPICall_t api_call) {
|
|
||||||
auto cr = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
|
||||||
if (cr == callresults.end()) return false;
|
|
||||||
if (!cr->call_completed()) return false;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool callback_result(SteamAPICall_t api_call, void *copy_to, unsigned int size) {
|
|
||||||
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
|
||||||
if (cb_result != callresults.end()) {
|
|
||||||
if (!cb_result->call_completed()) return false;
|
|
||||||
if (cb_result->result.size() > size) return false;
|
|
||||||
|
|
||||||
memcpy(copy_to, &(cb_result->result[0]), cb_result->result.size());
|
|
||||||
cb_result->to_delete = true;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rmCallBack(SteamAPICall_t api_call, class CCallbackBase *cb) {
|
|
||||||
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
|
||||||
if (cb_result != callresults.end()) {
|
|
||||||
auto it = std::find(cb_result->callbacks.begin(), cb_result->callbacks.end(), cb);
|
|
||||||
if (it != cb_result->callbacks.end()) {
|
|
||||||
cb_result->callbacks.erase(it);
|
|
||||||
CCallbackMgr::SetUnregister(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void rmCallBack(class CCallbackBase *cb) {
|
|
||||||
//TODO: check if callback is callback or call result?
|
|
||||||
for (auto & cr: callresults) {
|
|
||||||
auto it = std::find(cr.callbacks.begin(), cr.callbacks.end(), cb);
|
|
||||||
if (it != cr.callbacks.end()) {
|
|
||||||
cr.callbacks.erase(it);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cr.callbacks.size() == 0) {
|
|
||||||
cr.to_delete = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SteamAPICall_t addCallResult(SteamAPICall_t api_call, int iCallback, void *result, unsigned int size, double timeout=DEFAULT_CB_TIMEOUT, bool run_call_completed_cb=true) {
|
|
||||||
PRINT_DEBUG("%i", iCallback);
|
|
||||||
auto cb_result = std::find_if(callresults.begin(), callresults.end(), [api_call](struct Steam_Call_Result const& item) { return item.api_call == api_call; });
|
|
||||||
if (cb_result != callresults.end()) {
|
|
||||||
if (cb_result->reserved) {
|
|
||||||
std::chrono::high_resolution_clock::time_point created = cb_result->created;
|
|
||||||
std::vector<class CCallbackBase *> temp_cbs = cb_result->callbacks;
|
|
||||||
*cb_result = Steam_Call_Result(api_call, iCallback, result, size, timeout, run_call_completed_cb);
|
|
||||||
cb_result->callbacks = temp_cbs;
|
|
||||||
cb_result->created = created;
|
|
||||||
return cb_result->api_call;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
struct Steam_Call_Result res = Steam_Call_Result(api_call, iCallback, result, size, timeout, run_call_completed_cb);
|
|
||||||
callresults.push_back(res);
|
|
||||||
return callresults.back().api_call;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_DEBUG("ERROR");
|
|
||||||
return k_uAPICallInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
SteamAPICall_t reserveCallResult() {
|
|
||||||
struct Steam_Call_Result res = Steam_Call_Result(generate_steam_api_call_id(), 0, NULL, 0, 0.0, true);
|
|
||||||
res.reserved = true;
|
|
||||||
callresults.push_back(res);
|
|
||||||
return callresults.back().api_call;
|
|
||||||
}
|
|
||||||
|
|
||||||
SteamAPICall_t addCallResult(int iCallback, void *result, unsigned int size, double timeout=DEFAULT_CB_TIMEOUT, bool run_call_completed_cb=true) {
|
|
||||||
return addCallResult(generate_steam_api_call_id(), iCallback, result, size, timeout, run_call_completed_cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void setCbAll(void (*cb_all)(std::vector<char> result, int callback)) {
|
|
||||||
this->cb_all = cb_all;
|
|
||||||
}
|
|
||||||
|
|
||||||
void runCallResults() {
|
|
||||||
unsigned long current_size = callresults.size();
|
|
||||||
for (unsigned i = 0; i < current_size; ++i) {
|
|
||||||
unsigned index = i;
|
|
||||||
|
|
||||||
if (!callresults[index].to_delete) {
|
|
||||||
if (callresults[index].can_execute()) {
|
|
||||||
std::vector<char> result = callresults[index].result;
|
|
||||||
SteamAPICall_t api_call = callresults[index].api_call;
|
|
||||||
bool run_call_completed_cb = callresults[index].run_call_completed_cb;
|
|
||||||
int iCallback = callresults[index].iCallback;
|
|
||||||
if (run_call_completed_cb) {
|
|
||||||
callresults[index].run_call_completed_cb = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
callresults[index].to_delete = true;
|
|
||||||
if (callresults[index].has_cb()) {
|
|
||||||
std::vector<class CCallbackBase *> temp_cbs = callresults[index].callbacks;
|
|
||||||
for (auto & cb : temp_cbs) {
|
|
||||||
PRINT_DEBUG("Calling callresult %p %i", cb, cb->GetICallback());
|
|
||||||
global_mutex.unlock();
|
|
||||||
//TODO: unlock relock doesn't work if mutex was locked more than once.
|
|
||||||
if (run_call_completed_cb) { //run the right function depending on if it's a callback or a call result.
|
|
||||||
cb->Run(&(result[0]), false, api_call);
|
|
||||||
} else {
|
|
||||||
cb->Run(&(result[0]));
|
|
||||||
}
|
|
||||||
//COULD BE DELETED SO DON'T TOUCH CB
|
|
||||||
global_mutex.lock();
|
|
||||||
PRINT_DEBUG("callresult done");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (run_call_completed_cb) {
|
|
||||||
//can it happen that one is removed during the callback?
|
|
||||||
std::vector<class CCallbackBase *> callbacks = completed_callbacks;
|
|
||||||
SteamAPICallCompleted_t data{};
|
|
||||||
data.m_hAsyncCall = api_call;
|
|
||||||
data.m_iCallback = iCallback;
|
|
||||||
data.m_cubParam = result.size();
|
|
||||||
|
|
||||||
for (auto & cb: callbacks) {
|
|
||||||
PRINT_DEBUG("Call complete cb %i %p %llu", iCallback, cb, api_call);
|
|
||||||
//TODO: check if this is a problem or not.
|
|
||||||
SteamAPICallCompleted_t temp = data;
|
|
||||||
global_mutex.unlock();
|
|
||||||
cb->Run(&temp);
|
|
||||||
global_mutex.lock();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (cb_all) {
|
|
||||||
std::vector<char> res;
|
|
||||||
res.resize(sizeof(data));
|
|
||||||
memcpy(&(res[0]), &data, sizeof(data));
|
|
||||||
cb_all(res, data.k_iCallback);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (cb_all) {
|
|
||||||
cb_all(result, iCallback);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (callresults[index].timed_out()) {
|
|
||||||
callresults[index].to_delete = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_DEBUG("erase to_delete");
|
|
||||||
auto c = std::begin(callresults);
|
|
||||||
while (c != std::end(callresults)) {
|
|
||||||
if (c->to_delete) {
|
|
||||||
if (c->timed_out()) {
|
|
||||||
PRINT_DEBUG("removed callresult %i", c->iCallback);
|
|
||||||
c = callresults.erase(c);
|
|
||||||
} else {
|
|
||||||
++c;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
++c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Steam_Call_Back {
|
|
||||||
std::vector<class CCallbackBase *> callbacks{};
|
|
||||||
std::vector<std::vector<char>> results{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class SteamCallBacks {
|
|
||||||
std::map<int, struct Steam_Call_Back> callbacks{};
|
|
||||||
SteamCallResults *results{};
|
|
||||||
|
|
||||||
public:
|
|
||||||
SteamCallBacks(SteamCallResults *results) {
|
|
||||||
this->results = results;
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCallBack(int iCallback, class CCallbackBase *cb) {
|
|
||||||
PRINT_DEBUG("%i", iCallback);
|
|
||||||
if (iCallback == SteamAPICallCompleted_t::k_iCallback) {
|
|
||||||
results->addCallCompleted(cb);
|
|
||||||
CCallbackMgr::SetRegister(cb, iCallback);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (std::find(callbacks[iCallback].callbacks.begin(), callbacks[iCallback].callbacks.end(), cb) == callbacks[iCallback].callbacks.end()) {
|
|
||||||
callbacks[iCallback].callbacks.push_back(cb);
|
|
||||||
CCallbackMgr::SetRegister(cb, iCallback);
|
|
||||||
for (auto & res: callbacks[iCallback].results) {
|
|
||||||
//TODO: timeout?
|
|
||||||
SteamAPICall_t api_id = results->addCallResult(iCallback, &(res[0]), res.size(), 0.0, false);
|
|
||||||
results->addCallBack(api_id, cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCBResult(int iCallback, void *result, unsigned int size, double timeout, bool dont_post_if_already) {
|
|
||||||
if (dont_post_if_already) {
|
|
||||||
for (auto & r : callbacks[iCallback].results) {
|
|
||||||
if (r.size() == size) {
|
|
||||||
if (memcmp(&(r[0]), result, size) == 0) {
|
|
||||||
//cb already posted
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::vector<char> temp{};
|
|
||||||
temp.resize(size);
|
|
||||||
memcpy(&(temp[0]), result, size);
|
|
||||||
callbacks[iCallback].results.push_back(temp);
|
|
||||||
for (auto cb: callbacks[iCallback].callbacks) {
|
|
||||||
SteamAPICall_t api_id = results->addCallResult(iCallback, result, size, timeout, false);
|
|
||||||
results->addCallBack(api_id, cb);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (callbacks[iCallback].callbacks.empty()) {
|
|
||||||
results->addCallResult(iCallback, result, size, timeout, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCBResult(int iCallback, void *result, unsigned int size) {
|
|
||||||
addCBResult(iCallback, result, size, DEFAULT_CB_TIMEOUT, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCBResult(int iCallback, void *result, unsigned int size, bool dont_post_if_already) {
|
|
||||||
addCBResult(iCallback, result, size, DEFAULT_CB_TIMEOUT, dont_post_if_already);
|
|
||||||
}
|
|
||||||
|
|
||||||
void addCBResult(int iCallback, void *result, unsigned int size, double timeout) {
|
|
||||||
addCBResult(iCallback, result, size, timeout, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
void rmCallBack(int iCallback, class CCallbackBase *cb) {
|
|
||||||
if (iCallback == SteamAPICallCompleted_t::k_iCallback) {
|
|
||||||
results->rmCallCompleted(cb);
|
|
||||||
CCallbackMgr::SetUnregister(cb);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto c = std::find(callbacks[iCallback].callbacks.begin(), callbacks[iCallback].callbacks.end(), cb);
|
|
||||||
if (c != callbacks[iCallback].callbacks.end()) {
|
|
||||||
callbacks[iCallback].callbacks.erase(c);
|
|
||||||
CCallbackMgr::SetUnregister(cb);
|
|
||||||
results->rmCallBack(cb);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void runCallBacks() {
|
|
||||||
for (auto & c : callbacks) {
|
|
||||||
c.second.results.clear();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RunCBs {
|
|
||||||
void (*function)(void *object) = nullptr;
|
|
||||||
void *object{};
|
|
||||||
};
|
|
||||||
|
|
||||||
class RunEveryRunCB {
|
|
||||||
std::vector<struct RunCBs> cbs{};
|
|
||||||
public:
|
|
||||||
void add(void (*cb)(void *object), void *object) {
|
|
||||||
remove(cb, object);
|
|
||||||
RunCBs rcb;
|
|
||||||
rcb.function = cb;
|
|
||||||
rcb.object = object;
|
|
||||||
cbs.push_back(rcb);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove(void (*cb)(void *object), void *object) {
|
|
||||||
auto c = std::begin(cbs);
|
|
||||||
while (c != std::end(cbs)) {
|
|
||||||
if (c->function == cb && c->object == object) {
|
|
||||||
c = cbs.erase(c);
|
|
||||||
} else {
|
|
||||||
++c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void run() {
|
|
||||||
std::vector<struct RunCBs> temp_cbs = cbs;
|
|
||||||
for (auto c : temp_cbs) {
|
|
||||||
c.function(c.object);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void set_whitelist_ips(uint32_t *from, uint32_t *to, unsigned num_ips);
|
void set_whitelist_ips(uint32_t *from, uint32_t *to, unsigned num_ips);
|
||||||
#ifdef EMU_EXPERIMENTAL_BUILD
|
#ifdef EMU_EXPERIMENTAL_BUILD
|
||||||
bool crack_SteamAPI_RestartAppIfNecessary(uint32 unOwnAppID);
|
bool crack_SteamAPI_RestartAppIfNecessary(uint32 unOwnAppID);
|
||||||
bool crack_SteamAPI_Init();
|
bool crack_SteamAPI_Init();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#endif
|
#endif // BASE_INCLUDE_H
|
||||||
|
132
dll/dll/callsystem.h
Normal file
132
dll/dll/callsystem.h
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_CALLSYSTEM_H__
|
||||||
|
#define __INCLUDED_CALLSYSTEM_H__
|
||||||
|
|
||||||
|
#include "common_includes.h"
|
||||||
|
|
||||||
|
#define DEFAULT_CB_TIMEOUT 0.002
|
||||||
|
#define STEAM_CALLRESULT_TIMEOUT 120.0
|
||||||
|
#define STEAM_CALLRESULT_WAIT_FOR_CB 0.01
|
||||||
|
|
||||||
|
|
||||||
|
class CCallbackMgr
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
static void SetRegister(class CCallbackBase *pCallback, int iCallback);
|
||||||
|
static void SetUnregister(class CCallbackBase *pCallback);
|
||||||
|
|
||||||
|
static bool isServer(class CCallbackBase *pCallback);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Steam_Call_Result {
|
||||||
|
SteamAPICall_t api_call{};
|
||||||
|
std::vector<class CCallbackBase *> callbacks{};
|
||||||
|
std::vector<char> result{};
|
||||||
|
bool to_delete = false;
|
||||||
|
bool reserved = false;
|
||||||
|
std::chrono::high_resolution_clock::time_point created{};
|
||||||
|
double run_in{};
|
||||||
|
bool run_call_completed_cb{};
|
||||||
|
int iCallback{};
|
||||||
|
|
||||||
|
Steam_Call_Result(SteamAPICall_t a, int icb, void *r, unsigned int s, double r_in, bool run_cc_cb);
|
||||||
|
|
||||||
|
bool operator==(const struct Steam_Call_Result& other) const;
|
||||||
|
|
||||||
|
bool timed_out() const;
|
||||||
|
|
||||||
|
bool call_completed() const;
|
||||||
|
|
||||||
|
bool can_execute() const;
|
||||||
|
|
||||||
|
bool has_cb() const;
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
class SteamCallResults {
|
||||||
|
std::vector<struct Steam_Call_Result> callresults{};
|
||||||
|
std::vector<class CCallbackBase *> completed_callbacks{};
|
||||||
|
void (*cb_all)(std::vector<char> result, int callback) = nullptr;
|
||||||
|
|
||||||
|
public:
|
||||||
|
void addCallCompleted(class CCallbackBase *cb);
|
||||||
|
|
||||||
|
void rmCallCompleted(class CCallbackBase *cb);
|
||||||
|
|
||||||
|
void addCallBack(SteamAPICall_t api_call, class CCallbackBase *cb);
|
||||||
|
|
||||||
|
bool exists(SteamAPICall_t api_call) const;
|
||||||
|
|
||||||
|
bool callback_result(SteamAPICall_t api_call, void *copy_to, unsigned int size);
|
||||||
|
|
||||||
|
void rmCallBack(SteamAPICall_t api_call, class CCallbackBase *cb);
|
||||||
|
|
||||||
|
void rmCallBack(class CCallbackBase *cb);
|
||||||
|
|
||||||
|
SteamAPICall_t addCallResult(SteamAPICall_t api_call, int iCallback, void *result, unsigned int size, double timeout=DEFAULT_CB_TIMEOUT, bool run_call_completed_cb=true);
|
||||||
|
|
||||||
|
SteamAPICall_t reserveCallResult();
|
||||||
|
|
||||||
|
SteamAPICall_t addCallResult(int iCallback, void *result, unsigned int size, double timeout=DEFAULT_CB_TIMEOUT, bool run_call_completed_cb=true);
|
||||||
|
|
||||||
|
void setCbAll(void (*cb_all)(std::vector<char> result, int callback));
|
||||||
|
|
||||||
|
void runCallResults();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Steam_Call_Back {
|
||||||
|
std::vector<class CCallbackBase *> callbacks{};
|
||||||
|
std::vector<std::vector<char>> results{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class SteamCallBacks {
|
||||||
|
std::map<int, struct Steam_Call_Back> callbacks{};
|
||||||
|
SteamCallResults *results{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
SteamCallBacks(SteamCallResults *results);
|
||||||
|
|
||||||
|
void addCallBack(int iCallback, class CCallbackBase *cb);
|
||||||
|
void addCBResult(int iCallback, void *result, unsigned int size, double timeout, bool dont_post_if_already);
|
||||||
|
void addCBResult(int iCallback, void *result, unsigned int size);
|
||||||
|
void addCBResult(int iCallback, void *result, unsigned int size, bool dont_post_if_already);
|
||||||
|
void addCBResult(int iCallback, void *result, unsigned int size, double timeout);
|
||||||
|
|
||||||
|
void rmCallBack(int iCallback, class CCallbackBase *cb);
|
||||||
|
|
||||||
|
void runCallBacks();
|
||||||
|
};
|
||||||
|
|
||||||
|
struct RunCBs {
|
||||||
|
void (*function)(void *object) = nullptr;
|
||||||
|
void *object{};
|
||||||
|
};
|
||||||
|
|
||||||
|
class RunEveryRunCB {
|
||||||
|
std::vector<struct RunCBs> cbs{};
|
||||||
|
|
||||||
|
public:
|
||||||
|
void add(void (*cb)(void *object), void *object);
|
||||||
|
|
||||||
|
void remove(void (*cb)(void *object), void *object);
|
||||||
|
|
||||||
|
void run() const;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_CALLSYSTEM_H__
|
@ -244,4 +244,4 @@ static inline void reset_LastError()
|
|||||||
|
|
||||||
#define LOBBY_CONNECT_APPID ((uint32)-2)
|
#define LOBBY_CONNECT_APPID ((uint32)-2)
|
||||||
|
|
||||||
#endif//__INCLUDED_COMMON_INCLUDES__
|
#endif //__INCLUDED_COMMON_INCLUDES__
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_DLL_H__
|
||||||
|
#define __INCLUDED_DLL_H__
|
||||||
|
|
||||||
#include "steam_client.h"
|
#include "steam_client.h"
|
||||||
|
|
||||||
#ifdef STEAMCLIENT_DLL
|
#ifdef STEAMCLIENT_DLL
|
||||||
@ -32,3 +35,5 @@ HSteamUser flat_hsteamuser();
|
|||||||
HSteamPipe flat_hsteampipe();
|
HSteamPipe flat_hsteampipe();
|
||||||
HSteamUser flat_gs_hsteamuser();
|
HSteamUser flat_gs_hsteamuser();
|
||||||
HSteamPipe flat_gs_hsteampipe();
|
HSteamPipe flat_gs_hsteampipe();
|
||||||
|
|
||||||
|
#endif // __INCLUDED_DLL_H__
|
||||||
|
@ -15,18 +15,17 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#ifndef LOCAL_STORAGE_INCLUDE
|
#ifndef LOCAL_STORAGE_INCLUDE_H
|
||||||
#define LOCAL_STORAGE_INCLUDE
|
#define LOCAL_STORAGE_INCLUDE_H
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
#define MAX_FILENAME_LENGTH 300
|
#define MAX_FILENAME_LENGTH 300
|
||||||
|
|
||||||
union image_pixel_t
|
union image_pixel_t {
|
||||||
{
|
|
||||||
uint32_t pixel;
|
uint32_t pixel;
|
||||||
struct pixel_channels_t
|
|
||||||
{
|
struct pixel_channels_t {
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
@ -34,11 +33,10 @@ union image_pixel_t
|
|||||||
} channels;
|
} channels;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct image_t
|
struct image_t {
|
||||||
{
|
size_t width{};
|
||||||
size_t width;
|
size_t height{};
|
||||||
size_t height;
|
std::vector<image_pixel_t> pix_map{};
|
||||||
std::vector<image_pixel_t> pix_map;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Local_Storage {
|
class Local_Storage {
|
||||||
@ -105,4 +103,4 @@ public:
|
|||||||
static std::string desanitize_string(std::string name);
|
static std::string desanitize_string(std::string name);
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // LOCAL_STORAGE_INCLUDE_H
|
||||||
|
@ -21,13 +21,6 @@
|
|||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
inline bool protobuf_message_equal(const google::protobuf::MessageLite& msg_a,
|
|
||||||
const google::protobuf::MessageLite& msg_b) {
|
|
||||||
return (msg_a.GetTypeName() == msg_b.GetTypeName()) &&
|
|
||||||
(msg_a.SerializeAsString() == msg_b.SerializeAsString());
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
#define DEFAULT_PORT 47584
|
#define DEFAULT_PORT 47584
|
||||||
|
|
||||||
#if defined(STEAM_WIN32)
|
#if defined(STEAM_WIN32)
|
||||||
@ -36,9 +29,18 @@ typedef unsigned int sock_t;
|
|||||||
typedef int sock_t;
|
typedef int sock_t;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
static inline bool protobuf_message_equal(
|
||||||
|
const google::protobuf::MessageLite& msg_a,
|
||||||
|
const google::protobuf::MessageLite& msg_b)
|
||||||
|
{
|
||||||
|
return (msg_a.GetTypeName() == msg_b.GetTypeName()) &&
|
||||||
|
(msg_a.SerializeAsString() == msg_b.SerializeAsString());
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
struct IP_PORT {
|
struct IP_PORT {
|
||||||
uint32 ip;
|
uint32 ip{};
|
||||||
uint16 port;
|
uint16 port{};
|
||||||
bool operator <(const IP_PORT& other) const
|
bool operator <(const IP_PORT& other) const
|
||||||
{
|
{
|
||||||
return (ip < other.ip) || (ip == other.ip && port < other.port);
|
return (ip < other.ip) || (ip == other.ip && port < other.port);
|
||||||
@ -46,9 +48,9 @@ struct IP_PORT {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Network_Callback {
|
struct Network_Callback {
|
||||||
void (*message_callback)(void *object, Common_Message *msg);
|
void (*message_callback)(void *object, Common_Message *msg) = nullptr;
|
||||||
void *object;
|
void *object{};
|
||||||
CSteamID steam_id;
|
CSteamID steam_id{};
|
||||||
};
|
};
|
||||||
|
|
||||||
enum Callback_Ids {
|
enum Callback_Ids {
|
||||||
@ -73,39 +75,33 @@ struct Network_Callback_Container {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct TCP_Socket {
|
struct TCP_Socket {
|
||||||
sock_t sock = ~0;
|
sock_t sock = static_cast<sock_t>(~0);
|
||||||
bool received_data = false;
|
bool received_data = false;
|
||||||
std::vector<char> recv_buffer;
|
std::vector<char> recv_buffer{};
|
||||||
std::vector<char> send_buffer;
|
std::vector<char> send_buffer{};
|
||||||
std::chrono::high_resolution_clock::time_point last_heartbeat_sent, last_heartbeat_received;
|
std::chrono::high_resolution_clock::time_point last_heartbeat_sent{}, last_heartbeat_received{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Connection {
|
struct Connection {
|
||||||
struct TCP_Socket tcp_socket_outgoing, tcp_socket_incoming;
|
struct TCP_Socket tcp_socket_outgoing{}, tcp_socket_incoming{};
|
||||||
bool connected = false;
|
bool connected = false;
|
||||||
IP_PORT udp_ip_port;
|
IP_PORT udp_ip_port{};
|
||||||
bool udp_pinged = false;
|
bool udp_pinged = false;
|
||||||
IP_PORT tcp_ip_port;
|
IP_PORT tcp_ip_port{};
|
||||||
std::vector<CSteamID> ids;
|
std::vector<CSteamID> ids{};
|
||||||
uint32 appid;
|
uint32 appid{};
|
||||||
std::chrono::high_resolution_clock::time_point last_received;
|
std::chrono::high_resolution_clock::time_point last_received{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Networking {
|
class Networking
|
||||||
|
{
|
||||||
bool enabled = false;
|
bool enabled = false;
|
||||||
bool query_alive;
|
bool query_alive{};
|
||||||
std::chrono::high_resolution_clock::time_point last_run;
|
std::chrono::high_resolution_clock::time_point last_run{};
|
||||||
sock_t query_socket, udp_socket, tcp_socket;
|
sock_t query_socket, udp_socket{}, tcp_socket{};
|
||||||
uint16 udp_port, tcp_port;
|
uint16 udp_port{}, tcp_port{};
|
||||||
uint32 own_ip;
|
uint32 own_ip{};
|
||||||
std::vector<struct Connection> connections;
|
std::vector<struct Connection> connections{};
|
||||||
struct Connection *find_connection(CSteamID id, uint32 appid = 0);
|
|
||||||
struct Connection *new_connection(CSteamID id, uint32 appid);
|
|
||||||
|
|
||||||
bool handle_announce(Common_Message *msg, IP_PORT ip_port);
|
|
||||||
bool handle_low_level_udp(Common_Message *msg, IP_PORT ip_port);
|
|
||||||
bool handle_tcp(Common_Message *msg, struct TCP_Socket &socket);
|
|
||||||
void send_announce_broadcasts();
|
|
||||||
|
|
||||||
std::vector<CSteamID> ids;
|
std::vector<CSteamID> ids;
|
||||||
uint32 appid;
|
uint32 appid;
|
||||||
@ -118,18 +114,30 @@ class Networking {
|
|||||||
struct Network_Callback_Container callbacks[CALLBACK_IDS_MAX];
|
struct Network_Callback_Container callbacks[CALLBACK_IDS_MAX];
|
||||||
std::vector<Common_Message> local_send;
|
std::vector<Common_Message> local_send;
|
||||||
|
|
||||||
|
struct Connection *find_connection(CSteamID id, uint32 appid = 0);
|
||||||
|
struct Connection *new_connection(CSteamID id, uint32 appid);
|
||||||
|
|
||||||
|
bool handle_announce(Common_Message *msg, IP_PORT ip_port);
|
||||||
|
bool handle_low_level_udp(Common_Message *msg, IP_PORT ip_port);
|
||||||
|
bool handle_tcp(Common_Message *msg, struct TCP_Socket &socket);
|
||||||
|
void send_announce_broadcasts();
|
||||||
|
|
||||||
bool add_id_connection(struct Connection *connection, CSteamID steam_id);
|
bool add_id_connection(struct Connection *connection, CSteamID steam_id);
|
||||||
void run_callbacks(Callback_Ids id, Common_Message *msg);
|
void run_callbacks(Callback_Ids id, Common_Message *msg);
|
||||||
void run_callback_user(CSteamID steam_id, bool online, uint32 appid);
|
void run_callback_user(CSteamID steam_id, bool online, uint32 appid);
|
||||||
void do_callbacks_message(Common_Message *msg);
|
void do_callbacks_message(Common_Message *msg);
|
||||||
|
|
||||||
Common_Message create_announce(bool request);
|
Common_Message create_announce(bool request);
|
||||||
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Networking(CSteamID id, uint32 appid, uint16 port, std::set<IP_PORT> *custom_broadcasts, bool disable_sockets);
|
||||||
|
~Networking();
|
||||||
|
|
||||||
//NOTE: for all functions ips/ports are passed/returned in host byte order
|
//NOTE: for all functions ips/ports are passed/returned in host byte order
|
||||||
//ex: 127.0.0.1 should be passed as 0x7F000001
|
//ex: 127.0.0.1 should be passed as 0x7F000001
|
||||||
static std::set<IP_PORT> resolve_ip(std::string dns);
|
static std::set<IP_PORT> resolve_ip(std::string dns);
|
||||||
Networking(CSteamID id, uint32 appid, uint16 port, std::set<IP_PORT> *custom_broadcasts, bool disable_sockets);
|
|
||||||
~Networking();
|
|
||||||
void addListenId(CSteamID id);
|
void addListenId(CSteamID id);
|
||||||
void setAppID(uint32 appid);
|
void setAppID(uint32 appid);
|
||||||
void Run();
|
void Run();
|
||||||
@ -161,4 +169,4 @@ public:
|
|||||||
bool isQueryAlive();
|
bool isQueryAlive();
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // NETWORK_INCLUDE_H
|
||||||
|
@ -15,54 +15,57 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#ifndef SETTINGS_INCLUDE
|
#ifndef SETTINGS_INCLUDE_H
|
||||||
#define SETTINGS_INCLUDE
|
#define SETTINGS_INCLUDE_H
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
struct IP_PORT;
|
struct IP_PORT;
|
||||||
|
|
||||||
struct DLC_entry {
|
struct DLC_entry {
|
||||||
AppId_t appID;
|
AppId_t appID{};
|
||||||
std::string name;
|
std::string name{};
|
||||||
bool available;
|
bool available{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Mod_entry {
|
struct Mod_entry {
|
||||||
PublishedFileId_t id;
|
PublishedFileId_t id{};
|
||||||
std::string title;
|
std::string title{};
|
||||||
std::string path;
|
std::string path{};
|
||||||
|
|
||||||
|
std::string previewURL{};
|
||||||
|
EWorkshopFileType fileType{};
|
||||||
|
std::string description{};
|
||||||
|
uint64 steamIDOwner{};
|
||||||
|
uint32 timeCreated{};
|
||||||
|
uint32 timeUpdated{};
|
||||||
|
uint32 timeAddedToUserList{};
|
||||||
|
ERemoteStoragePublishedFileVisibility visibility{};
|
||||||
|
bool banned = false;
|
||||||
|
bool acceptedForUse{};
|
||||||
|
bool tagsTruncated{};
|
||||||
|
std::string tags{};
|
||||||
|
|
||||||
std::string previewURL;
|
|
||||||
EWorkshopFileType fileType;
|
|
||||||
std::string description;
|
|
||||||
uint64 steamIDOwner;
|
|
||||||
uint32 timeCreated;
|
|
||||||
uint32 timeUpdated;
|
|
||||||
uint32 timeAddedToUserList;
|
|
||||||
ERemoteStoragePublishedFileVisibility visibility;
|
|
||||||
bool banned;
|
|
||||||
bool acceptedForUse;
|
|
||||||
bool tagsTruncated;
|
|
||||||
std::string tags;
|
|
||||||
// file/url information
|
// file/url information
|
||||||
UGCHandle_t handleFile = generate_file_handle();
|
UGCHandle_t handleFile = generate_file_handle();
|
||||||
UGCHandle_t handlePreviewFile = generate_file_handle();
|
UGCHandle_t handlePreviewFile = generate_file_handle();
|
||||||
std::string primaryFileName;
|
|
||||||
int32 primaryFileSize;
|
std::string primaryFileName{};
|
||||||
std::string previewFileName;
|
int32 primaryFileSize{};
|
||||||
int32 previewFileSize;
|
std::string previewFileName{};
|
||||||
std::string workshopItemURL;
|
int32 previewFileSize{};
|
||||||
|
std::string workshopItemURL{};
|
||||||
|
|
||||||
// voting information
|
// voting information
|
||||||
uint32 votesUp;
|
uint32 votesUp{};
|
||||||
uint32 votesDown;
|
uint32 votesDown{};
|
||||||
float score;
|
float score{};
|
||||||
|
|
||||||
// collection details
|
// collection details
|
||||||
uint32 numChildren;
|
uint32 numChildren{}; // TODO
|
||||||
|
|
||||||
private:
|
private:
|
||||||
UGCHandle_t generate_file_handle()
|
UGCHandle_t generate_file_handle() {
|
||||||
{
|
|
||||||
static UGCHandle_t val = 0;
|
static UGCHandle_t val = 0;
|
||||||
|
|
||||||
++val;
|
++val;
|
||||||
@ -74,12 +77,12 @@ private:
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Leaderboard_config {
|
struct Leaderboard_config {
|
||||||
enum ELeaderboardSortMethod sort_method;
|
enum ELeaderboardSortMethod sort_method{};
|
||||||
enum ELeaderboardDisplayType display_type;
|
enum ELeaderboardDisplayType display_type{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Stat_config {
|
struct Stat_config {
|
||||||
GameServerStats_Messages::StatInfo::Stat_Type type;
|
GameServerStats_Messages::StatInfo::Stat_Type type{};
|
||||||
union {
|
union {
|
||||||
float default_value_float;
|
float default_value_float;
|
||||||
int32 default_value_int;
|
int32 default_value_int;
|
||||||
@ -87,21 +90,21 @@ struct Stat_config {
|
|||||||
};
|
};
|
||||||
|
|
||||||
struct Image_Data {
|
struct Image_Data {
|
||||||
uint32 width;
|
uint32 width{};
|
||||||
uint32 height;
|
uint32 height{};
|
||||||
std::string data;
|
std::string data{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Controller_Settings {
|
struct Controller_Settings {
|
||||||
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_sets;
|
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_sets{};
|
||||||
std::map<std::string, std::string> action_set_layer_parents;
|
std::map<std::string, std::string> action_set_layer_parents{};
|
||||||
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_set_layers;
|
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_set_layers{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Group_Clans {
|
struct Group_Clans {
|
||||||
CSteamID id;
|
CSteamID id{};
|
||||||
std::string name;
|
std::string name{};
|
||||||
std::string tag;
|
std::string tag{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Overlay_Appearance {
|
struct Overlay_Appearance {
|
||||||
@ -112,7 +115,7 @@ struct Overlay_Appearance {
|
|||||||
|
|
||||||
constexpr const static NotificationPosition default_pos = NotificationPosition::top_right;
|
constexpr const static NotificationPosition default_pos = NotificationPosition::top_right;
|
||||||
|
|
||||||
std::string font_override{}; // path to a custom user-provided font
|
std::string font_override{}; // path to a custom user-provided TTF font
|
||||||
float font_size = 16.0f;
|
float font_size = 16.0f;
|
||||||
|
|
||||||
float icon_size = 64.0f;
|
float icon_size = 64.0f;
|
||||||
@ -157,23 +160,12 @@ struct Overlay_Appearance {
|
|||||||
NotificationPosition invite_pos = default_pos; // lobby/game invitation
|
NotificationPosition invite_pos = default_pos; // lobby/game invitation
|
||||||
NotificationPosition chat_msg_pos = NotificationPosition::top_center; // chat message from a friend
|
NotificationPosition chat_msg_pos = NotificationPosition::top_center; // chat message from a friend
|
||||||
|
|
||||||
static NotificationPosition translate_notification_position(const std::string &str)
|
static NotificationPosition translate_notification_position(const std::string &str);
|
||||||
{
|
|
||||||
if (str == "top_left") return NotificationPosition::top_left;
|
|
||||||
else if (str == "top_center") return NotificationPosition::top_center;
|
|
||||||
else if (str == "top_right") return NotificationPosition::top_right;
|
|
||||||
else if (str == "bot_left") return NotificationPosition::bot_left;
|
|
||||||
else if (str == "bot_center") return NotificationPosition::bot_center;
|
|
||||||
else if (str == "bot_right") return NotificationPosition::bot_right;
|
|
||||||
|
|
||||||
PRINT_DEBUG("Invalid position '%s'", str.c_str());
|
|
||||||
return default_pos;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Settings {
|
class Settings {
|
||||||
CSteamID steam_id; // user id
|
CSteamID steam_id{}; // user id
|
||||||
CGameID game_id;
|
CGameID game_id{};
|
||||||
std::string name{};
|
std::string name{};
|
||||||
std::string language{}; // default "english"
|
std::string language{}; // default "english"
|
||||||
CSteamID lobby_id = k_steamIDNil;
|
CSteamID lobby_id = k_steamIDNil;
|
||||||
@ -294,17 +286,21 @@ public:
|
|||||||
|
|
||||||
|
|
||||||
#ifdef LOBBY_CONNECT
|
#ifdef LOBBY_CONNECT
|
||||||
static const bool is_lobby_connect = true;
|
static constexpr const bool is_lobby_connect = true;
|
||||||
#else
|
#else
|
||||||
static const bool is_lobby_connect = false;
|
static constexpr const bool is_lobby_connect = false;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
static std::string sanitize(const std::string &name);
|
|
||||||
Settings(CSteamID steam_id, CGameID game_id, const std::string &name, const std::string &language, bool offline);
|
Settings(CSteamID steam_id, CGameID game_id, const std::string &name, const std::string &language, bool offline);
|
||||||
|
|
||||||
|
static std::string sanitize(const std::string &name);
|
||||||
|
|
||||||
CSteamID get_local_steam_id();
|
CSteamID get_local_steam_id();
|
||||||
CGameID get_local_game_id();
|
CGameID get_local_game_id();
|
||||||
|
|
||||||
const char *get_local_name();
|
const char *get_local_name();
|
||||||
void set_local_name(const char *name);
|
void set_local_name(const char *name);
|
||||||
|
|
||||||
const char *get_language();
|
const char *get_language();
|
||||||
void set_language(const char *language);
|
void set_language(const char *language);
|
||||||
|
|
||||||
@ -313,9 +309,12 @@ public:
|
|||||||
const std::string& get_supported_languages() const;
|
const std::string& get_supported_languages() const;
|
||||||
|
|
||||||
void set_game_id(CGameID game_id);
|
void set_game_id(CGameID game_id);
|
||||||
|
|
||||||
void set_lobby(CSteamID lobby_id);
|
void set_lobby(CSteamID lobby_id);
|
||||||
CSteamID get_lobby();
|
CSteamID get_lobby();
|
||||||
|
|
||||||
bool is_offline();
|
bool is_offline();
|
||||||
|
|
||||||
uint16 get_port();
|
uint16 get_port();
|
||||||
void set_port(uint16 port);
|
void set_port(uint16 port);
|
||||||
|
|
||||||
@ -361,4 +360,4 @@ public:
|
|||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // SETTINGS_INCLUDE_H
|
||||||
|
@ -15,10 +15,10 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#include "settings.h"
|
#ifndef SETTINGS_PARSER_INCLUDE_H
|
||||||
|
#define SETTINGS_PARSER_INCLUDE_H
|
||||||
|
|
||||||
#ifndef SETTINGS_PARSER_INCLUDE
|
#include "settings.h"
|
||||||
#define SETTINGS_PARSER_INCLUDE
|
|
||||||
|
|
||||||
//returns game appid
|
//returns game appid
|
||||||
uint32 create_localstorage_settings(Settings **settings_client_out, Settings **settings_server_out, Local_Storage **local_storage_out);
|
uint32 create_localstorage_settings(Settings **settings_client_out, Settings **settings_server_out, Local_Storage **local_storage_out);
|
||||||
@ -55,4 +55,4 @@ enum class SettingsItf {
|
|||||||
|
|
||||||
const std::map<SettingsItf, std::string>& settings_old_interfaces();
|
const std::map<SettingsItf, std::string>& settings_old_interfaces();
|
||||||
|
|
||||||
#endif
|
#endif // SETTINGS_PARSER_INCLUDE_H
|
||||||
|
@ -15,14 +15,18 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_SOURCE_QUERY_H__
|
||||||
|
#define __INCLUDED_SOURCE_QUERY_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Source_Query
|
class Source_Query
|
||||||
{
|
{
|
||||||
Source_Query () = delete;
|
Source_Query() = delete;
|
||||||
~Source_Query() = delete;
|
~Source_Query() = delete;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static std::vector<uint8_t> handle_source_query(const void* buffer, size_t len, Gameserver const& gs);
|
static std::vector<uint8_t> handle_source_query(const void* buffer, size_t len, Gameserver const& gs);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_SOURCE_QUERY_H__
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_HTMLSURFACE_H__
|
||||||
|
#define __INCLUDED_STEAM_HTMLSURFACE_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_HTMLsurface :
|
class Steam_HTMLsurface :
|
||||||
@ -24,354 +27,166 @@ public ISteamHTMLSurface003,
|
|||||||
public ISteamHTMLSurface004,
|
public ISteamHTMLSurface004,
|
||||||
public ISteamHTMLSurface
|
public ISteamHTMLSurface
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_HTMLsurface(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
|
Steam_HTMLsurface(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks);
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Must call init and shutdown when starting/ending use of the interface
|
// Must call init and shutdown when starting/ending use of the interface
|
||||||
bool Init()
|
bool Init();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Shutdown()
|
bool Shutdown();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Create a browser object for display of a html page, when creation is complete the call handle
|
// Create a browser object for display of a html page, when creation is complete the call handle
|
||||||
// will return a HTML_BrowserReady_t callback for the HHTMLBrowser of your new browser.
|
// will return a HTML_BrowserReady_t callback for the HHTMLBrowser of your new browser.
|
||||||
// The user agent string is a substring to be added to the general user agent string so you can
|
// The user agent string is a substring to be added to the general user agent string so you can
|
||||||
// identify your client on web servers.
|
// identify your client on web servers.
|
||||||
// The userCSS string lets you apply a CSS style sheet to every displayed page, leave null if
|
// The userCSS string lets you apply a CSS style sheet to every displayed page, leave null if
|
||||||
// you do not require this functionality.
|
// you do not require this functionality.
|
||||||
//
|
//
|
||||||
// YOU MUST HAVE IMPLEMENTED HANDLERS FOR HTML_BrowserReady_t, HTML_StartRequest_t,
|
// YOU MUST HAVE IMPLEMENTED HANDLERS FOR HTML_BrowserReady_t, HTML_StartRequest_t,
|
||||||
// HTML_JSAlert_t, HTML_JSConfirm_t, and HTML_FileOpenDialog_t! See the CALLBACKS
|
// HTML_JSAlert_t, HTML_JSConfirm_t, and HTML_FileOpenDialog_t! See the CALLBACKS
|
||||||
// section of this interface (AllowStartRequest, etc) for more details. If you do
|
// section of this interface (AllowStartRequest, etc) for more details. If you do
|
||||||
// not implement these callback handlers, the browser may appear to hang instead of
|
// not implement these callback handlers, the browser may appear to hang instead of
|
||||||
// navigating to new pages or triggering javascript popups.
|
// navigating to new pages or triggering javascript popups.
|
||||||
//
|
//
|
||||||
STEAM_CALL_RESULT( HTML_BrowserReady_t )
|
STEAM_CALL_RESULT( HTML_BrowserReady_t )
|
||||||
SteamAPICall_t CreateBrowser( const char *pchUserAgent, const char *pchUserCSS )
|
SteamAPICall_t CreateBrowser( const char *pchUserAgent, const char *pchUserCSS );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
HTML_BrowserReady_t data;
|
|
||||||
data.unBrowserHandle = 1234869;
|
|
||||||
|
|
||||||
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Call this when you are done with a html surface, this lets us free the resources being used by it
|
// Call this when you are done with a html surface, this lets us free the resources being used by it
|
||||||
void RemoveBrowser( HHTMLBrowser unBrowserHandle )
|
void RemoveBrowser( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Navigate to this URL, results in a HTML_StartRequest_t as the request commences
|
// Navigate to this URL, results in a HTML_StartRequest_t as the request commences
|
||||||
void LoadURL( HHTMLBrowser unBrowserHandle, const char *pchURL, const char *pchPostData )
|
void LoadURL( HHTMLBrowser unBrowserHandle, const char *pchURL, const char *pchPostData );
|
||||||
{
|
|
||||||
PRINT_DEBUG("TODO %s %s", pchURL, pchPostData);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
static char url[256];
|
|
||||||
strncpy(url, pchURL, sizeof(url));
|
|
||||||
static char target[] = "_self";
|
|
||||||
static char title[] = "title";
|
|
||||||
|
|
||||||
{
|
|
||||||
HTML_StartRequest_t data;
|
|
||||||
data.unBrowserHandle = unBrowserHandle;
|
|
||||||
data.pchURL = url;
|
|
||||||
data.pchTarget = target;
|
|
||||||
data.pchPostData = "";
|
|
||||||
data.bIsRedirect = false;
|
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
HTML_FinishedRequest_t data;
|
|
||||||
data.unBrowserHandle = unBrowserHandle;
|
|
||||||
data.pchURL = url;
|
|
||||||
data.pchPageTitle = title;
|
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.8);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Tells the surface the size in pixels to display the surface
|
// Tells the surface the size in pixels to display the surface
|
||||||
void SetSize( HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight )
|
void SetSize( HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Stop the load of the current html page
|
// Stop the load of the current html page
|
||||||
void StopLoad( HHTMLBrowser unBrowserHandle )
|
void StopLoad( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reload (most likely from local cache) the current page
|
// Reload (most likely from local cache) the current page
|
||||||
void Reload( HHTMLBrowser unBrowserHandle )
|
void Reload( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// navigate back in the page history
|
// navigate back in the page history
|
||||||
void GoBack( HHTMLBrowser unBrowserHandle )
|
void GoBack( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// navigate forward in the page history
|
// navigate forward in the page history
|
||||||
void GoForward( HHTMLBrowser unBrowserHandle )
|
void GoForward( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// add this header to any url requests from this browser
|
// add this header to any url requests from this browser
|
||||||
void AddHeader( HHTMLBrowser unBrowserHandle, const char *pchKey, const char *pchValue )
|
void AddHeader( HHTMLBrowser unBrowserHandle, const char *pchKey, const char *pchValue );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// run this javascript script in the currently loaded page
|
// run this javascript script in the currently loaded page
|
||||||
void ExecuteJavascript( HHTMLBrowser unBrowserHandle, const char *pchScript )
|
void ExecuteJavascript( HHTMLBrowser unBrowserHandle, const char *pchScript );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mouse click and mouse movement commands
|
// Mouse click and mouse movement commands
|
||||||
void MouseUp( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton )
|
void MouseUp( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseDown( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton )
|
void MouseDown( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void MouseDoubleClick( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton )
|
void MouseDoubleClick( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// x and y are relative to the HTML bounds
|
// x and y are relative to the HTML bounds
|
||||||
void MouseMove( HHTMLBrowser unBrowserHandle, int x, int y )
|
void MouseMove( HHTMLBrowser unBrowserHandle, int x, int y );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// nDelta is pixels of scroll
|
// nDelta is pixels of scroll
|
||||||
void MouseWheel( HHTMLBrowser unBrowserHandle, int32 nDelta )
|
void MouseWheel( HHTMLBrowser unBrowserHandle, int32 nDelta );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// keyboard interactions, native keycode is the key code value from your OS
|
// keyboard interactions, native keycode is the key code value from your OS
|
||||||
void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers, bool bIsSystemKey = false )
|
void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers, bool bIsSystemKey = false );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers)
|
void KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers);
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
KeyDown(unBrowserHandle, nNativeKeyCode, eHTMLKeyModifiers, false);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void KeyUp( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers )
|
void KeyUp( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers );
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// cUnicodeChar is the unicode character point for this keypress (and potentially multiple chars per press)
|
// cUnicodeChar is the unicode character point for this keypress (and potentially multiple chars per press)
|
||||||
void KeyChar( HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, EHTMLKeyModifiers eHTMLKeyModifiers )
|
void KeyChar( HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, EHTMLKeyModifiers eHTMLKeyModifiers );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// programmatically scroll this many pixels on the page
|
// programmatically scroll this many pixels on the page
|
||||||
void SetHorizontalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll )
|
void SetHorizontalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SetVerticalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll )
|
void SetVerticalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// tell the html control if it has key focus currently, controls showing the I-beam cursor in text controls amongst other things
|
// tell the html control if it has key focus currently, controls showing the I-beam cursor in text controls amongst other things
|
||||||
void SetKeyFocus( HHTMLBrowser unBrowserHandle, bool bHasKeyFocus )
|
void SetKeyFocus( HHTMLBrowser unBrowserHandle, bool bHasKeyFocus );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// open the current pages html code in the local editor of choice, used for debugging
|
// open the current pages html code in the local editor of choice, used for debugging
|
||||||
void ViewSource( HHTMLBrowser unBrowserHandle )
|
void ViewSource( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// copy the currently selected text on the html page to the local clipboard
|
// copy the currently selected text on the html page to the local clipboard
|
||||||
void CopyToClipboard( HHTMLBrowser unBrowserHandle )
|
void CopyToClipboard( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// paste from the local clipboard to the current html page
|
// paste from the local clipboard to the current html page
|
||||||
void PasteFromClipboard( HHTMLBrowser unBrowserHandle )
|
void PasteFromClipboard( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// find this string in the browser, if bCurrentlyInFind is true then instead cycle to the next matching element
|
// find this string in the browser, if bCurrentlyInFind is true then instead cycle to the next matching element
|
||||||
void Find( HHTMLBrowser unBrowserHandle, const char *pchSearchStr, bool bCurrentlyInFind, bool bReverse )
|
void Find( HHTMLBrowser unBrowserHandle, const char *pchSearchStr, bool bCurrentlyInFind, bool bReverse );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// cancel a currently running find
|
// cancel a currently running find
|
||||||
void StopFind( HHTMLBrowser unBrowserHandle )
|
void StopFind( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// return details about the link at position x,y on the current page
|
// return details about the link at position x,y on the current page
|
||||||
void GetLinkAtPosition( HHTMLBrowser unBrowserHandle, int x, int y )
|
void GetLinkAtPosition( HHTMLBrowser unBrowserHandle, int x, int y );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// set a webcookie for the hostname in question
|
// set a webcookie for the hostname in question
|
||||||
void SetCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath, RTime32 nExpires, bool bSecure, bool bHTTPOnly )
|
void SetCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath, RTime32 nExpires, bool bSecure, bool bHTTPOnly );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Zoom the current page by flZoom ( from 0.0 to 2.0, so to zoom to 120% use 1.2 ), zooming around point X,Y in the page (use 0,0 if you don't care)
|
// Zoom the current page by flZoom ( from 0.0 to 2.0, so to zoom to 120% use 1.2 ), zooming around point X,Y in the page (use 0,0 if you don't care)
|
||||||
void SetPageScaleFactor( HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY )
|
void SetPageScaleFactor( HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Enable/disable low-resource background mode, where javascript and repaint timers are throttled, resources are
|
// Enable/disable low-resource background mode, where javascript and repaint timers are throttled, resources are
|
||||||
// more aggressively purged from memory, and audio/video elements are paused. When background mode is enabled,
|
// more aggressively purged from memory, and audio/video elements are paused. When background mode is enabled,
|
||||||
// all HTML5 video and audio objects will execute ".pause()" and gain the property "._steam_background_paused = 1".
|
// all HTML5 video and audio objects will execute ".pause()" and gain the property "._steam_background_paused = 1".
|
||||||
// When background mode is disabled, any video or audio objects with that property will resume with ".play()".
|
// When background mode is disabled, any video or audio objects with that property will resume with ".play()".
|
||||||
void SetBackgroundMode( HHTMLBrowser unBrowserHandle, bool bBackgroundMode )
|
void SetBackgroundMode( HHTMLBrowser unBrowserHandle, bool bBackgroundMode );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Scale the output display space by this factor, this is useful when displaying content on high dpi devices.
|
// Scale the output display space by this factor, this is useful when displaying content on high dpi devices.
|
||||||
// Specifies the ratio between physical and logical pixels.
|
// Specifies the ratio between physical and logical pixels.
|
||||||
void SetDPIScalingFactor( HHTMLBrowser unBrowserHandle, float flDPIScaling )
|
void SetDPIScalingFactor( HHTMLBrowser unBrowserHandle, float flDPIScaling );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void OpenDeveloperTools( HHTMLBrowser unBrowserHandle )
|
void OpenDeveloperTools( HHTMLBrowser unBrowserHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
// CALLBACKS
|
// CALLBACKS
|
||||||
//
|
//
|
||||||
// These set of functions are used as responses to callback requests
|
// These set of functions are used as responses to callback requests
|
||||||
//
|
//
|
||||||
|
|
||||||
// You MUST call this in response to a HTML_StartRequest_t callback
|
// You MUST call this in response to a HTML_StartRequest_t callback
|
||||||
// Set bAllowed to true to allow this navigation, false to cancel it and stay
|
// Set bAllowed to true to allow this navigation, false to cancel it and stay
|
||||||
// on the current page. You can use this feature to limit the valid pages
|
// on the current page. You can use this feature to limit the valid pages
|
||||||
// allowed in your HTML surface.
|
// allowed in your HTML surface.
|
||||||
void AllowStartRequest( HHTMLBrowser unBrowserHandle, bool bAllowed )
|
void AllowStartRequest( HHTMLBrowser unBrowserHandle, bool bAllowed );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// You MUST call this in response to a HTML_JSAlert_t or HTML_JSConfirm_t callback
|
// You MUST call this in response to a HTML_JSAlert_t or HTML_JSConfirm_t callback
|
||||||
// Set bResult to true for the OK option of a confirm, use false otherwise
|
// Set bResult to true for the OK option of a confirm, use false otherwise
|
||||||
void JSDialogResponse( HHTMLBrowser unBrowserHandle, bool bResult )
|
void JSDialogResponse( HHTMLBrowser unBrowserHandle, bool bResult );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// You MUST call this in response to a HTML_FileOpenDialog_t callback
|
// You MUST call this in response to a HTML_FileOpenDialog_t callback
|
||||||
STEAM_IGNOREATTR()
|
STEAM_IGNOREATTR()
|
||||||
void FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelectedFiles )
|
void FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelectedFiles );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_HTMLSURFACE_H__
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_APPLIST_H__
|
||||||
|
#define __INCLUDED_STEAM_APPLIST_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Applist : public ISteamAppList
|
class Steam_Applist :
|
||||||
|
public ISteamAppList
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
uint32 GetNumInstalledApps();
|
uint32 GetNumInstalledApps();
|
||||||
@ -28,3 +32,5 @@ public:
|
|||||||
|
|
||||||
int GetAppBuildId( AppId_t nAppID ); // return the buildid of this app, may change at any time based on backend updates to the game
|
int GetAppBuildId( AppId_t nAppID ); // return the buildid of this app, may change at any time based on backend updates to the game
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_APPLIST_H__
|
||||||
|
@ -1,3 +1,23 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_APPS_H__
|
||||||
|
#define __INCLUDED_STEAM_APPS_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Apps :
|
class Steam_Apps :
|
||||||
@ -10,7 +30,7 @@ public ISteamApps006,
|
|||||||
public ISteamApps007,
|
public ISteamApps007,
|
||||||
public ISteamApps
|
public ISteamApps
|
||||||
{
|
{
|
||||||
Settings *settings{};
|
class Settings *settings{};
|
||||||
class SteamCallResults *callback_results{};
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks{};
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
@ -115,3 +135,5 @@ public:
|
|||||||
// set current DLC AppID being played (or 0 if none). Allows Steam to track usage of major DLC extensions
|
// set current DLC AppID being played (or 0 if none). Allows Steam to track usage of major DLC extensions
|
||||||
bool SetDlcContext( AppId_t nAppID );
|
bool SetDlcContext( AppId_t nAppID );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_APPS_H__
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_CLIENT_H__
|
||||||
|
#define __INCLUDED_STEAM_CLIENT_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "appticket.h"
|
#include "appticket.h"
|
||||||
#include "steam_user.h"
|
#include "steam_user.h"
|
||||||
@ -79,78 +82,81 @@ public ISteamClient020,
|
|||||||
public ISteamClient
|
public ISteamClient
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
Networking *network;
|
Networking *network{};
|
||||||
SteamCallResults *callback_results_server, *callback_results_client;
|
SteamCallResults *callback_results_server{}, *callback_results_client{};
|
||||||
SteamCallBacks *callbacks_server, *callbacks_client;
|
SteamCallBacks *callbacks_server{}, *callbacks_client{};
|
||||||
Settings *settings_client, *settings_server;
|
Settings *settings_client{}, *settings_server{};
|
||||||
Local_Storage *local_storage;
|
Local_Storage *local_storage{};
|
||||||
RunEveryRunCB *run_every_runcb;
|
RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
Ugc_Remote_Storage_Bridge *ugc_bridge;
|
Ugc_Remote_Storage_Bridge *ugc_bridge{};
|
||||||
|
|
||||||
Steam_User *steam_user;
|
Steam_User *steam_user{};
|
||||||
Steam_Friends *steam_friends;
|
Steam_Friends *steam_friends{};
|
||||||
Steam_Utils *steam_utils;
|
Steam_Utils *steam_utils{};
|
||||||
Steam_Matchmaking *steam_matchmaking;
|
Steam_Matchmaking *steam_matchmaking{};
|
||||||
Steam_Matchmaking_Servers *steam_matchmaking_servers;
|
Steam_Matchmaking_Servers *steam_matchmaking_servers{};
|
||||||
Steam_User_Stats *steam_user_stats;
|
Steam_User_Stats *steam_user_stats{};
|
||||||
Steam_Apps *steam_apps;
|
Steam_Apps *steam_apps{};
|
||||||
Steam_Networking *steam_networking;
|
Steam_Networking *steam_networking{};
|
||||||
Steam_Remote_Storage *steam_remote_storage;
|
Steam_Remote_Storage *steam_remote_storage{};
|
||||||
Steam_Screenshots *steam_screenshots;
|
Steam_Screenshots *steam_screenshots{};
|
||||||
Steam_HTTP *steam_http;
|
Steam_HTTP *steam_http{};
|
||||||
Steam_Controller *steam_controller;
|
Steam_Controller *steam_controller{};
|
||||||
Steam_UGC *steam_ugc;
|
Steam_UGC *steam_ugc{};
|
||||||
Steam_Applist *steam_applist;
|
Steam_Applist *steam_applist{};
|
||||||
Steam_Music *steam_music;
|
Steam_Music *steam_music{};
|
||||||
Steam_MusicRemote *steam_musicremote;
|
Steam_MusicRemote *steam_musicremote{};
|
||||||
Steam_HTMLsurface *steam_HTMLsurface;
|
Steam_HTMLsurface *steam_HTMLsurface{};
|
||||||
Steam_Inventory *steam_inventory;
|
Steam_Inventory *steam_inventory{};
|
||||||
Steam_Video *steam_video;
|
Steam_Video *steam_video{};
|
||||||
Steam_Parental *steam_parental;
|
Steam_Parental *steam_parental{};
|
||||||
Steam_Networking_Sockets *steam_networking_sockets;
|
Steam_Networking_Sockets *steam_networking_sockets{};
|
||||||
Steam_Networking_Sockets_Serialized *steam_networking_sockets_serialized;
|
Steam_Networking_Sockets_Serialized *steam_networking_sockets_serialized{};
|
||||||
Steam_Networking_Messages *steam_networking_messages;
|
Steam_Networking_Messages *steam_networking_messages{};
|
||||||
Steam_Game_Coordinator *steam_game_coordinator;
|
Steam_Game_Coordinator *steam_game_coordinator{};
|
||||||
Steam_Networking_Utils *steam_networking_utils;
|
Steam_Networking_Utils *steam_networking_utils{};
|
||||||
Steam_Unified_Messages *steam_unified_messages;
|
Steam_Unified_Messages *steam_unified_messages{};
|
||||||
Steam_Game_Search *steam_game_search;
|
Steam_Game_Search *steam_game_search{};
|
||||||
Steam_Parties *steam_parties;
|
Steam_Parties *steam_parties{};
|
||||||
Steam_RemotePlay *steam_remoteplay;
|
Steam_RemotePlay *steam_remoteplay{};
|
||||||
Steam_TV *steam_tv;
|
Steam_TV *steam_tv{};
|
||||||
|
|
||||||
Steam_GameServer *steam_gameserver;
|
Steam_GameServer *steam_gameserver{};
|
||||||
Steam_Utils *steam_gameserver_utils;
|
Steam_Utils *steam_gameserver_utils{};
|
||||||
Steam_GameServerStats *steam_gameserverstats;
|
Steam_GameServerStats *steam_gameserverstats{};
|
||||||
Steam_Networking *steam_gameserver_networking;
|
Steam_Networking *steam_gameserver_networking{};
|
||||||
Steam_HTTP *steam_gameserver_http;
|
Steam_HTTP *steam_gameserver_http{};
|
||||||
Steam_Inventory *steam_gameserver_inventory;
|
Steam_Inventory *steam_gameserver_inventory{};
|
||||||
Steam_UGC *steam_gameserver_ugc;
|
Steam_UGC *steam_gameserver_ugc{};
|
||||||
Steam_Apps *steam_gameserver_apps;
|
Steam_Apps *steam_gameserver_apps{};
|
||||||
Steam_Networking_Sockets *steam_gameserver_networking_sockets;
|
Steam_Networking_Sockets *steam_gameserver_networking_sockets{};
|
||||||
Steam_Networking_Sockets_Serialized *steam_gameserver_networking_sockets_serialized;
|
Steam_Networking_Sockets_Serialized *steam_gameserver_networking_sockets_serialized{};
|
||||||
Steam_Networking_Messages *steam_gameserver_networking_messages;
|
Steam_Networking_Messages *steam_gameserver_networking_messages{};
|
||||||
Steam_Game_Coordinator *steam_gameserver_game_coordinator;
|
Steam_Game_Coordinator *steam_gameserver_game_coordinator{};
|
||||||
Steam_Masterserver_Updater *steam_masterserver_updater;
|
Steam_Masterserver_Updater *steam_masterserver_updater{};
|
||||||
Steam_AppTicket *steam_app_ticket;
|
Steam_AppTicket *steam_app_ticket{};
|
||||||
|
|
||||||
Steam_Overlay* steam_overlay;
|
Steam_Overlay* steam_overlay{};
|
||||||
|
|
||||||
bool user_logged_in = false;
|
bool user_logged_in = false;
|
||||||
bool server_init = false;
|
bool server_init = false;
|
||||||
std::thread background_keepalive;
|
|
||||||
bool steamclient_server_inited = false;
|
bool steamclient_server_inited = false;
|
||||||
|
|
||||||
|
bool gameserver_has_ipv6_functions{};
|
||||||
|
|
||||||
|
std::thread background_keepalive{};
|
||||||
std::atomic<unsigned long long> last_cb_run{};
|
std::atomic<unsigned long long> last_cb_run{};
|
||||||
std::atomic_bool cb_run_active = false;
|
std::atomic_bool cb_run_active = false;
|
||||||
|
|
||||||
unsigned steam_pipe_counter = 1;
|
unsigned steam_pipe_counter = 1;
|
||||||
std::map<HSteamPipe, enum Steam_Pipe> steam_pipes;
|
std::map<HSteamPipe, enum Steam_Pipe> steam_pipes{};
|
||||||
|
|
||||||
bool gameserver_has_ipv6_functions;
|
|
||||||
|
|
||||||
Steam_Client();
|
Steam_Client();
|
||||||
~Steam_Client();
|
~Steam_Client();
|
||||||
// Creates a communication pipe to the Steam client.
|
|
||||||
|
// Creates a communication pipe to the Steam client.
|
||||||
// NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling
|
// NOT THREADSAFE - ensure that no other threads are accessing Steamworks API when calling
|
||||||
HSteamPipe CreateSteamPipe();
|
HSteamPipe CreateSteamPipe();
|
||||||
|
|
||||||
@ -311,3 +317,5 @@ public:
|
|||||||
|
|
||||||
void DestroyAllInterfaces();
|
void DestroyAllInterfaces();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_CLIENT_H__
|
||||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -15,143 +15,48 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_GAME_COORDINATOR_H__
|
||||||
|
#define __INCLUDED_STEAM_GAME_COORDINATOR_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Game_Coordinator :
|
class Steam_Game_Coordinator :
|
||||||
public ISteamGameCoordinator
|
public ISteamGameCoordinator
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
constexpr const static uint32 protobuf_mask = 0x80000000;
|
||||||
class Networking *network;
|
|
||||||
class SteamCallResults *callback_results;
|
|
||||||
class SteamCallBacks *callbacks;
|
|
||||||
class RunEveryRunCB *run_every_runcb;
|
|
||||||
|
|
||||||
static const uint32 protobuf_mask = 0x80000000;
|
class Settings *settings{};
|
||||||
std::queue<std::string> outgoing_messages;
|
class Networking *network{};
|
||||||
|
class SteamCallResults *callback_results{};
|
||||||
|
class SteamCallBacks *callbacks{};
|
||||||
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
void push_incoming(std::string message)
|
std::queue<std::string> outgoing_messages{};
|
||||||
{
|
|
||||||
outgoing_messages.push(message);
|
|
||||||
|
|
||||||
struct GCMessageAvailable_t data;
|
void push_incoming(std::string message);
|
||||||
data.m_nMessageSize = message.size();
|
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
}
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
|
void RunCallbacks();
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Game_Coordinator(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Game_Coordinator();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Game_Coordinator *steam_gamecoordinator = (Steam_Game_Coordinator *)object;
|
// sends a message to the Game Coordinator
|
||||||
steam_gamecoordinator->Callback(msg);
|
EGCResults SendMessage_( uint32 unMsgType, const void *pubData, uint32 cubData );
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
// returns true if there is a message waiting from the game coordinator
|
||||||
{
|
bool IsMessageAvailable( uint32 *pcubMsgSize );
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Game_Coordinator *steam_gamecoordinator = (Steam_Game_Coordinator *)object;
|
// fills the provided buffer with the first message in the queue and returns k_EGCResultOK or
|
||||||
steam_gamecoordinator->RunCallbacks();
|
// returns k_EGCResultNoMessage if there is no message waiting. pcubMsgSize is filled with the message size.
|
||||||
}
|
// If the provided buffer is not large enough to fit the entire message, k_EGCResultBufferTooSmall is returned
|
||||||
|
// and the message remains at the head of the queue.
|
||||||
Steam_Game_Coordinator(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
EGCResults RetrieveMessage( uint32 *punMsgType, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize );
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
//this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Coordinator::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Game_Coordinator::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Game_Coordinator()
|
|
||||||
{
|
|
||||||
//this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Coordinator::steam_callback, this);
|
|
||||||
this->run_every_runcb->remove(&Steam_Game_Coordinator::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// sends a message to the Game Coordinator
|
|
||||||
EGCResults SendMessage_( uint32 unMsgType, const void *pubData, uint32 cubData )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%X %u len %u", unMsgType, (~protobuf_mask) & unMsgType, cubData);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (protobuf_mask & unMsgType) {
|
|
||||||
uint32 message_type = (~protobuf_mask) & unMsgType;
|
|
||||||
if (message_type == 4006) { //client hello
|
|
||||||
std::string message("\xA4\x0F\x00\x80\x00\x00\x00\x00\x08\x00", 10);
|
|
||||||
push_incoming(message);
|
|
||||||
} else
|
|
||||||
if (message_type == 4007) { //server hello
|
|
||||||
std::string message("\xA5\x0F\x00\x80\x00\x00\x00\x00\x08\x00", 10);
|
|
||||||
push_incoming(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return k_EGCResultOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if there is a message waiting from the game coordinator
|
|
||||||
bool IsMessageAvailable( uint32 *pcubMsgSize )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (outgoing_messages.size()) {
|
|
||||||
if (pcubMsgSize) *pcubMsgSize = outgoing_messages.front().size();
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// fills the provided buffer with the first message in the queue and returns k_EGCResultOK or
|
|
||||||
// returns k_EGCResultNoMessage if there is no message waiting. pcubMsgSize is filled with the message size.
|
|
||||||
// If the provided buffer is not large enough to fit the entire message, k_EGCResultBufferTooSmall is returned
|
|
||||||
// and the message remains at the head of the queue.
|
|
||||||
EGCResults RetrieveMessage( uint32 *punMsgType, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (outgoing_messages.size()) {
|
|
||||||
if (outgoing_messages.front().size() > cubDest) {
|
|
||||||
return k_EGCResultBufferTooSmall;
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoing_messages.front().copy((char *)pubDest, cubDest);
|
|
||||||
if (pcubMsgSize) *pcubMsgSize = outgoing_messages.front().size();
|
|
||||||
if (punMsgType && outgoing_messages.front().size() >= sizeof(uint32)) {
|
|
||||||
outgoing_messages.front().copy((char *)punMsgType, sizeof(uint32));
|
|
||||||
*punMsgType = ntohl(*punMsgType);
|
|
||||||
}
|
|
||||||
|
|
||||||
outgoing_messages.pop();
|
|
||||||
return k_EGCResultOK;
|
|
||||||
} else {
|
|
||||||
return k_EGCResultNoMessage;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_sockets()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_GAME_COORDINATOR_H__
|
||||||
|
@ -15,215 +15,104 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_GAMESEARCH_H__
|
||||||
|
#define __INCLUDED_STEAM_GAMESEARCH_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Game_Search :
|
class Steam_Game_Search :
|
||||||
public ISteamGameSearch
|
public ISteamGameSearch
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
||||||
FSteamNetworkingSocketsDebugOutput debug_function;
|
FSteamNetworkingSocketsDebugOutput debug_function{};
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
|
void RunCallbacks();
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Game_Search(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Game_Search();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Game_Search *steam_gamesearch = (Steam_Game_Search *)object;
|
// =============================================================================================
|
||||||
steam_gamesearch->Callback(msg);
|
// Game Player APIs
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
// a keyname and a list of comma separated values: one of which is must be found in order for the match to qualify
|
||||||
{
|
// fails if a search is currently in progress
|
||||||
// PRINT_DEBUG_ENTRY();
|
EGameSearchErrorCode_t AddGameSearchParams( const char *pchKeyToFind, const char *pchValuesToFind );
|
||||||
|
|
||||||
Steam_Game_Search *steam_gamesearch = (Steam_Game_Search *)object;
|
|
||||||
steam_gamesearch->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_Game_Search(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
//this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Search::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Game_Search::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Game_Search()
|
|
||||||
{
|
|
||||||
//this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Search::steam_callback, this);
|
|
||||||
this->run_every_runcb->remove(&Steam_Game_Search::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// =============================================================================================
|
|
||||||
// Game Player APIs
|
|
||||||
|
|
||||||
// a keyname and a list of comma separated values: one of which is must be found in order for the match to qualify
|
|
||||||
// fails if a search is currently in progress
|
|
||||||
EGameSearchErrorCode_t AddGameSearchParams( const char *pchKeyToFind, const char *pchValuesToFind )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// all players in lobby enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress
|
// all players in lobby enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress
|
||||||
// if not the owner of the lobby or search already in progress this call fails
|
// if not the owner of the lobby or search already in progress this call fails
|
||||||
// periodic callbacks will be sent as queue time estimates change
|
// periodic callbacks will be sent as queue time estimates change
|
||||||
EGameSearchErrorCode_t SearchForGameWithLobby( CSteamID steamIDLobby, int nPlayerMin, int nPlayerMax )
|
EGameSearchErrorCode_t SearchForGameWithLobby( CSteamID steamIDLobby, int nPlayerMin, int nPlayerMax );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// user enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress
|
// user enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress
|
||||||
// periodic callbacks will be sent as queue time estimates change
|
// periodic callbacks will be sent as queue time estimates change
|
||||||
EGameSearchErrorCode_t SearchForGameSolo( int nPlayerMin, int nPlayerMax )
|
EGameSearchErrorCode_t SearchForGameSolo( int nPlayerMin, int nPlayerMax );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// after receiving SearchForGameResultCallback_t, accept or decline the game
|
// after receiving SearchForGameResultCallback_t, accept or decline the game
|
||||||
// multiple SearchForGameResultCallback_t will follow as players accept game until the host starts or cancels the game
|
// multiple SearchForGameResultCallback_t will follow as players accept game until the host starts or cancels the game
|
||||||
EGameSearchErrorCode_t AcceptGame()
|
EGameSearchErrorCode_t AcceptGame();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
EGameSearchErrorCode_t DeclineGame()
|
EGameSearchErrorCode_t DeclineGame();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// after receiving GameStartedByHostCallback_t get connection details to server
|
// after receiving GameStartedByHostCallback_t get connection details to server
|
||||||
EGameSearchErrorCode_t RetrieveConnectionDetails( CSteamID steamIDHost, char *pchConnectionDetails, int cubConnectionDetails )
|
EGameSearchErrorCode_t RetrieveConnectionDetails( CSteamID steamIDHost, char *pchConnectionDetails, int cubConnectionDetails );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// leaves queue if still waiting
|
// leaves queue if still waiting
|
||||||
EGameSearchErrorCode_t EndGameSearch()
|
EGameSearchErrorCode_t EndGameSearch();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
// Game Host APIs
|
// Game Host APIs
|
||||||
|
|
||||||
// a keyname and a list of comma separated values: all the values you allow
|
// a keyname and a list of comma separated values: all the values you allow
|
||||||
EGameSearchErrorCode_t SetGameHostParams( const char *pchKey, const char *pchValue )
|
EGameSearchErrorCode_t SetGameHostParams( const char *pchKey, const char *pchValue );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// set connection details for players once game is found so they can connect to this server
|
// set connection details for players once game is found so they can connect to this server
|
||||||
EGameSearchErrorCode_t SetConnectionDetails( const char *pchConnectionDetails, int cubConnectionDetails )
|
EGameSearchErrorCode_t SetConnectionDetails( const char *pchConnectionDetails, int cubConnectionDetails );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// mark server as available for more players with nPlayerMin,nPlayerMax desired
|
// mark server as available for more players with nPlayerMin,nPlayerMax desired
|
||||||
// accept no lobbies with playercount greater than nMaxTeamSize
|
// accept no lobbies with playercount greater than nMaxTeamSize
|
||||||
// the set of lobbies returned must be partitionable into teams of no more than nMaxTeamSize
|
// the set of lobbies returned must be partitionable into teams of no more than nMaxTeamSize
|
||||||
// RequestPlayersForGameNotificationCallback_t callback will be sent when the search has started
|
// RequestPlayersForGameNotificationCallback_t callback will be sent when the search has started
|
||||||
// multple RequestPlayersForGameResultCallback_t callbacks will follow when players are found
|
// multple RequestPlayersForGameResultCallback_t callbacks will follow when players are found
|
||||||
EGameSearchErrorCode_t RequestPlayersForGame( int nPlayerMin, int nPlayerMax, int nMaxTeamSize )
|
EGameSearchErrorCode_t RequestPlayersForGame( int nPlayerMin, int nPlayerMax, int nMaxTeamSize );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// accept the player list and release connection details to players
|
// accept the player list and release connection details to players
|
||||||
// players will only be given connection details and host steamid when this is called
|
// players will only be given connection details and host steamid when this is called
|
||||||
// ( allows host to accept after all players confirm, some confirm, or none confirm. decision is entirely up to the host )
|
// ( allows host to accept after all players confirm, some confirm, or none confirm. decision is entirely up to the host )
|
||||||
EGameSearchErrorCode_t HostConfirmGameStart( uint64 ullUniqueGameID )
|
EGameSearchErrorCode_t HostConfirmGameStart( uint64 ullUniqueGameID );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// cancel request and leave the pool of game hosts looking for players
|
// cancel request and leave the pool of game hosts looking for players
|
||||||
// if a set of players has already been sent to host, all players will receive SearchForGameHostFailedToConfirm_t
|
// if a set of players has already been sent to host, all players will receive SearchForGameHostFailedToConfirm_t
|
||||||
EGameSearchErrorCode_t CancelRequestPlayersForGame()
|
EGameSearchErrorCode_t CancelRequestPlayersForGame();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// submit a result for one player. does not end the game. ullUniqueGameID continues to describe this game
|
// submit a result for one player. does not end the game. ullUniqueGameID continues to describe this game
|
||||||
EGameSearchErrorCode_t SubmitPlayerResult( uint64 ullUniqueGameID, CSteamID steamIDPlayer, EPlayerResult_t EPlayerResult )
|
EGameSearchErrorCode_t SubmitPlayerResult( uint64 ullUniqueGameID, CSteamID steamIDPlayer, EPlayerResult_t EPlayerResult );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// ends the game. no further SubmitPlayerResults for ullUniqueGameID will be accepted
|
// ends the game. no further SubmitPlayerResults for ullUniqueGameID will be accepted
|
||||||
// any future requests will provide a new ullUniqueGameID
|
// any future requests will provide a new ullUniqueGameID
|
||||||
EGameSearchErrorCode_t EndGame( uint64 ullUniqueGameID )
|
EGameSearchErrorCode_t EndGame( uint64 ullUniqueGameID );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EGameSearchErrorCode_Failed_Offline;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_sockets()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_GAMESEARCH_H__
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_GAMESERVER_H__
|
||||||
|
#define __INCLUDED_STEAM_GAMESERVER_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
|
|
||||||
@ -23,16 +26,16 @@
|
|||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
struct Gameserver_Outgoing_Packet {
|
struct Gameserver_Outgoing_Packet {
|
||||||
std::vector<uint8_t> data;
|
std::vector<uint8_t> data{};
|
||||||
|
|
||||||
uint32 ip;
|
uint32 ip{};
|
||||||
uint16 port;
|
uint16 port{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Gameserver_Player_Info_t {
|
struct Gameserver_Player_Info_t {
|
||||||
std::chrono::steady_clock::time_point join_time;
|
std::chrono::steady_clock::time_point join_time{};
|
||||||
std::string name;
|
std::string name{};
|
||||||
uint32 score;
|
uint32 score{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Steam_GameServer :
|
class Steam_GameServer :
|
||||||
@ -47,27 +50,28 @@ public ISteamGameServer013,
|
|||||||
public ISteamGameServer014,
|
public ISteamGameServer014,
|
||||||
public ISteamGameServer
|
public ISteamGameServer
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
CSteamID steam_id;
|
CSteamID steam_id{};
|
||||||
|
|
||||||
bool call_servers_connected = false;
|
bool call_servers_connected = false;
|
||||||
bool logged_in = false;
|
bool logged_in = false;
|
||||||
bool call_servers_disconnected = false;
|
bool call_servers_disconnected = false;
|
||||||
Gameserver server_data;
|
Gameserver server_data{};
|
||||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> players;
|
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> players{};
|
||||||
|
|
||||||
uint32 flags;
|
uint32 flags{};
|
||||||
bool policy_response_called;
|
bool policy_response_called{};
|
||||||
|
|
||||||
|
std::chrono::high_resolution_clock::time_point last_sent_server_info{};
|
||||||
|
Auth_Manager *auth_manager{};
|
||||||
|
|
||||||
|
std::vector<struct Gameserver_Outgoing_Packet> outgoing_packets{};
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point last_sent_server_info;
|
|
||||||
Auth_Manager *auth_manager;
|
|
||||||
|
|
||||||
std::vector<struct Gameserver_Outgoing_Packet> outgoing_packets;
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
Steam_GameServer(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks);
|
Steam_GameServer(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks);
|
||||||
~Steam_GameServer();
|
~Steam_GameServer();
|
||||||
|
|
||||||
@ -361,6 +365,10 @@ public:
|
|||||||
STEAM_CALL_RESULT( ComputeNewPlayerCompatibilityResult_t )
|
STEAM_CALL_RESULT( ComputeNewPlayerCompatibilityResult_t )
|
||||||
SteamAPICall_t ComputeNewPlayerCompatibility( CSteamID steamIDNewPlayer );
|
SteamAPICall_t ComputeNewPlayerCompatibility( CSteamID steamIDNewPlayer );
|
||||||
|
|
||||||
//
|
|
||||||
|
// called by steam_client::runcallbacks
|
||||||
void RunCallbacks();
|
void RunCallbacks();
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_GAMESERVER_H__
|
||||||
|
@ -15,18 +15,22 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_GAMESERVERSTATS_H__
|
||||||
|
#define __INCLUDED_STEAM_GAMESERVERSTATS_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Purpose: Functions for authenticating users via Steam to play on a game server
|
// Purpose: Functions for authenticating users via Steam to play on a game server
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
class Steam_GameServerStats : public ISteamGameServerStats
|
class Steam_GameServerStats :
|
||||||
|
public ISteamGameServerStats
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
struct RequestAllStats {
|
struct RequestAllStats {
|
||||||
std::chrono::high_resolution_clock::time_point created{};
|
std::chrono::high_resolution_clock::time_point created{};
|
||||||
@ -109,3 +113,5 @@ public:
|
|||||||
STEAM_CALL_RESULT( GSStatsStored_t )
|
STEAM_CALL_RESULT( GSStatsStored_t )
|
||||||
SteamAPICall_t StoreUserStats( CSteamID steamIDUser );
|
SteamAPICall_t StoreUserStats( CSteamID steamIDUser );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_GAMESERVERSTATS_H__
|
||||||
|
@ -15,14 +15,16 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_HTTP_H__
|
||||||
|
#define __INCLUDED_STEAM_HTTP_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "common_includes.h"
|
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
|
|
||||||
|
|
||||||
struct Steam_Http_Request {
|
struct Steam_Http_Request {
|
||||||
HTTPRequestHandle handle;
|
HTTPRequestHandle handle{};
|
||||||
EHTTPMethod request_method;
|
EHTTPMethod request_method{};
|
||||||
std::string url{};
|
std::string url{};
|
||||||
uint64 timeout_sec = 60;
|
uint64 timeout_sec = 60;
|
||||||
bool requires_valid_ssl = false;
|
bool requires_valid_ssl = false;
|
||||||
@ -37,7 +39,7 @@ struct Steam_Http_Request {
|
|||||||
std::map<std::string, std::string> get_or_post_params{};
|
std::map<std::string, std::string> get_or_post_params{};
|
||||||
std::string post_raw{};
|
std::string post_raw{};
|
||||||
|
|
||||||
uint64 context_value;
|
uint64 context_value{};
|
||||||
|
|
||||||
// target local filepath to save
|
// target local filepath to save
|
||||||
std::string target_filepath{};
|
std::string target_filepath{};
|
||||||
@ -48,17 +50,18 @@ struct Steam_Http_Request {
|
|||||||
std::string response{};
|
std::string response{};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
class Steam_HTTP :
|
class Steam_HTTP :
|
||||||
public ISteamHTTP001,
|
public ISteamHTTP001,
|
||||||
public ISteamHTTP002,
|
public ISteamHTTP002,
|
||||||
public ISteamHTTP
|
public ISteamHTTP
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
std::vector<Steam_Http_Request> requests;
|
std::vector<Steam_Http_Request> requests{};
|
||||||
|
|
||||||
Steam_Http_Request *get_request(HTTPRequestHandle hRequest);
|
Steam_Http_Request *get_request(HTTPRequestHandle hRequest);
|
||||||
void online_http_request(Steam_Http_Request *request, SteamAPICall_t *pCallHandle);
|
void online_http_request(Steam_Http_Request *request, SteamAPICall_t *pCallHandle);
|
||||||
@ -177,3 +180,5 @@ public:
|
|||||||
// Check if the reason the request failed was because we timed it out (rather than some harder failure)
|
// Check if the reason the request failed was because we timed it out (rather than some harder failure)
|
||||||
bool GetHTTPRequestWasTimedOut( HTTPRequestHandle hRequest, bool *pbWasTimedOut );
|
bool GetHTTPRequestWasTimedOut( HTTPRequestHandle hRequest, bool *pbWasTimedOut );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_HTTP_H__
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,219 +15,117 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_MASTERSERVER_UPDATER_H__
|
||||||
|
#define __INCLUDED_STEAM_MASTERSERVER_UPDATER_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Masterserver_Updater :
|
class Steam_Masterserver_Updater :
|
||||||
public ISteamMasterServerUpdater
|
public ISteamMasterServerUpdater
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
|
void RunCallbacks();
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Masterserver_Updater(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Masterserver_Updater();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Masterserver_Updater *steam_masterserverupdater = (Steam_Masterserver_Updater *)object;
|
// Call this as often as you like to tell the master server updater whether or not
|
||||||
steam_masterserverupdater->Callback(msg);
|
// you want it to be active (default: off).
|
||||||
}
|
void SetActive( bool bActive );
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
|
||||||
{
|
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Masterserver_Updater *steam_masterserverupdater = (Steam_Masterserver_Updater *)object;
|
|
||||||
steam_masterserverupdater->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_Masterserver_Updater(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Masterserver_Updater::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Masterserver_Updater::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Masterserver_Updater()
|
|
||||||
{
|
|
||||||
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Masterserver_Updater::steam_callback, this);
|
|
||||||
this->run_every_runcb->remove(&Steam_Masterserver_Updater::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Call this as often as you like to tell the master server updater whether or not
|
|
||||||
// you want it to be active (default: off).
|
|
||||||
void SetActive( bool bActive )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// You usually don't need to modify this.
|
// You usually don't need to modify this.
|
||||||
// Pass -1 to use the default value for iHeartbeatInterval.
|
// Pass -1 to use the default value for iHeartbeatInterval.
|
||||||
// Some mods change this.
|
// Some mods change this.
|
||||||
void SetHeartbeatInterval( int iHeartbeatInterval )
|
void SetHeartbeatInterval( int iHeartbeatInterval );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// These are in GameSocketShare mode, where instead of ISteamMasterServerUpdater creating its own
|
// These are in GameSocketShare mode, where instead of ISteamMasterServerUpdater creating its own
|
||||||
// socket to talk to the master server on, it lets the game use its socket to forward messages
|
// socket to talk to the master server on, it lets the game use its socket to forward messages
|
||||||
// back and forth. This prevents us from requiring server ops to open up yet another port
|
// back and forth. This prevents us from requiring server ops to open up yet another port
|
||||||
// in their firewalls.
|
// in their firewalls.
|
||||||
//
|
//
|
||||||
// the IP address and port should be in host order, i.e 127.0.0.1 == 0x7f000001
|
// the IP address and port should be in host order, i.e 127.0.0.1 == 0x7f000001
|
||||||
|
|
||||||
// These are used when you've elected to multiplex the game server's UDP socket
|
// These are used when you've elected to multiplex the game server's UDP socket
|
||||||
// rather than having the master server updater use its own sockets.
|
// rather than having the master server updater use its own sockets.
|
||||||
//
|
//
|
||||||
// Source games use this to simplify the job of the server admins, so they
|
// Source games use this to simplify the job of the server admins, so they
|
||||||
// don't have to open up more ports on their firewalls.
|
// don't have to open up more ports on their firewalls.
|
||||||
|
|
||||||
// Call this when a packet that starts with 0xFFFFFFFF comes in. That means
|
// Call this when a packet that starts with 0xFFFFFFFF comes in. That means
|
||||||
// it's for us.
|
// it's for us.
|
||||||
bool HandleIncomingPacket( const void *pData, int cbData, uint32 srcIP, uint16 srcPort )
|
bool HandleIncomingPacket( const void *pData, int cbData, uint32 srcIP, uint16 srcPort );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// AFTER calling HandleIncomingPacket for any packets that came in that frame, call this.
|
// AFTER calling HandleIncomingPacket for any packets that came in that frame, call this.
|
||||||
// This gets a packet that the master server updater needs to send out on UDP.
|
// This gets a packet that the master server updater needs to send out on UDP.
|
||||||
// It returns the length of the packet it wants to send, or 0 if there are no more packets to send.
|
// It returns the length of the packet it wants to send, or 0 if there are no more packets to send.
|
||||||
// Call this each frame until it returns 0.
|
// Call this each frame until it returns 0.
|
||||||
int GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort )
|
int GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// Functions to set various fields that are used to respond to queries.
|
// Functions to set various fields that are used to respond to queries.
|
||||||
|
|
||||||
// Call this to set basic data that is passed to the server browser.
|
// Call this to set basic data that is passed to the server browser.
|
||||||
void SetBasicServerData(
|
void SetBasicServerData(
|
||||||
unsigned short nProtocolVersion,
|
unsigned short nProtocolVersion,
|
||||||
bool bDedicatedServer,
|
bool bDedicatedServer,
|
||||||
const char *pRegionName,
|
const char *pRegionName,
|
||||||
const char *pProductName,
|
const char *pProductName,
|
||||||
unsigned short nMaxReportedClients,
|
unsigned short nMaxReportedClients,
|
||||||
bool bPasswordProtected,
|
bool bPasswordProtected,
|
||||||
const char *pGameDescription )
|
const char *pGameDescription );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Call this to clear the whole list of key/values that are sent in rules queries.
|
// Call this to clear the whole list of key/values that are sent in rules queries.
|
||||||
void ClearAllKeyValues()
|
void ClearAllKeyValues();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Call this to add/update a key/value pair.
|
// Call this to add/update a key/value pair.
|
||||||
void SetKeyValue( const char *pKey, const char *pValue )
|
void SetKeyValue( const char *pKey, const char *pValue );
|
||||||
{
|
|
||||||
PRINT_DEBUG("TODO '%s'='%s'", pKey, pValue);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
// You can call this upon shutdown to clear out data stored for this game server and
|
// You can call this upon shutdown to clear out data stored for this game server and
|
||||||
// to tell the master servers that this server is going away.
|
// to tell the master servers that this server is going away.
|
||||||
void NotifyShutdown()
|
void NotifyShutdown();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns true if the master server has requested a restart.
|
// Returns true if the master server has requested a restart.
|
||||||
// Only returns true once per request.
|
// Only returns true once per request.
|
||||||
bool WasRestartRequested()
|
bool WasRestartRequested();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Force it to request a heartbeat from the master servers.
|
// Force it to request a heartbeat from the master servers.
|
||||||
void ForceHeartbeat()
|
void ForceHeartbeat();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Manually edit and query the master server list.
|
// Manually edit and query the master server list.
|
||||||
// It will provide name resolution and use the default master server port if none is provided.
|
// It will provide name resolution and use the default master server port if none is provided.
|
||||||
bool AddMasterServer( const char *pServerAddress )
|
bool AddMasterServer( const char *pServerAddress );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool RemoveMasterServer( const char *pServerAddress )
|
bool RemoveMasterServer( const char *pServerAddress );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetNumMasterServers()
|
int GetNumMasterServers();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns the # of bytes written to pOut.
|
// Returns the # of bytes written to pOut.
|
||||||
int GetMasterServerAddress( int iServer, char *pOut, int outBufferSize )
|
int GetMasterServerAddress( int iServer, char *pOut, int outBufferSize );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_MASTERSERVER_UPDATER_H__
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,59 +15,69 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_MATCHMAKING_SERVERS_H__
|
||||||
|
#define __INCLUDED_STEAM_MATCHMAKING_SERVERS_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include <ssq/a2s.h>
|
#include <ssq/a2s.h>
|
||||||
|
|
||||||
#define SERVER_TIMEOUT 10.0
|
|
||||||
#define DIRECT_IP_DELAY 0.05
|
|
||||||
|
|
||||||
struct Steam_Matchmaking_Servers_Direct_IP_Request {
|
struct Steam_Matchmaking_Servers_Direct_IP_Request {
|
||||||
HServerQuery id;
|
HServerQuery id{};
|
||||||
uint32 ip;
|
uint32 ip{};
|
||||||
uint16 port;
|
uint16 port{};
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point created;
|
std::chrono::high_resolution_clock::time_point created{};
|
||||||
ISteamMatchmakingRulesResponse *rules_response = NULL;
|
ISteamMatchmakingRulesResponse *rules_response{};
|
||||||
ISteamMatchmakingPlayersResponse *players_response = NULL;
|
ISteamMatchmakingPlayersResponse *players_response{};
|
||||||
ISteamMatchmakingPingResponse *ping_response = NULL;
|
ISteamMatchmakingPingResponse *ping_response{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Steam_Matchmaking_Servers_Gameserver_Friends {
|
struct Steam_Matchmaking_Servers_Gameserver_Friends {
|
||||||
uint64 source_id;
|
uint64 source_id{};
|
||||||
uint32 ip;
|
uint32 ip{};
|
||||||
uint16 port;
|
uint16 port{};
|
||||||
std::chrono::high_resolution_clock::time_point last_recv;
|
std::chrono::high_resolution_clock::time_point last_recv{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Steam_Matchmaking_Servers_Gameserver {
|
struct Steam_Matchmaking_Servers_Gameserver {
|
||||||
Gameserver server;
|
Gameserver server{};
|
||||||
std::chrono::high_resolution_clock::time_point last_recv;
|
std::chrono::high_resolution_clock::time_point last_recv{};
|
||||||
EMatchMakingType type;
|
EMatchMakingType type{};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Steam_Matchmaking_Request {
|
struct Steam_Matchmaking_Request {
|
||||||
AppId_t appid;
|
AppId_t appid{};
|
||||||
HServerListRequest id;
|
HServerListRequest id{};
|
||||||
ISteamMatchmakingServerListResponse *callbacks;
|
ISteamMatchmakingServerListResponse *callbacks{};
|
||||||
ISteamMatchmakingServerListResponse001 *old_callbacks;
|
ISteamMatchmakingServerListResponse001 *old_callbacks{};
|
||||||
bool completed, cancelled, released;
|
bool completed{}, cancelled{}, released{};
|
||||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers_filtered;
|
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers_filtered{};
|
||||||
EMatchMakingType type;
|
EMatchMakingType type{};
|
||||||
};
|
};
|
||||||
|
|
||||||
class Steam_Matchmaking_Servers : public ISteamMatchmakingServers,
|
class Steam_Matchmaking_Servers :
|
||||||
public ISteamMatchmakingServers001
|
public ISteamMatchmakingServers001,
|
||||||
|
public ISteamMatchmakingServers
|
||||||
{
|
{
|
||||||
class Settings *settings{};
|
class Settings *settings{};
|
||||||
class Local_Storage *local_storage{};
|
class Local_Storage *local_storage{};
|
||||||
class Networking *network{};
|
class Networking *network{};
|
||||||
|
|
||||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers;
|
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers{};
|
||||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver_Friends> gameservers_friends;
|
std::vector <struct Steam_Matchmaking_Servers_Gameserver_Friends> gameservers_friends{};
|
||||||
std::vector <struct Steam_Matchmaking_Request> requests;
|
std::vector <struct Steam_Matchmaking_Request> requests{};
|
||||||
std::vector <struct Steam_Matchmaking_Servers_Direct_IP_Request> direct_ip_requests;
|
std::vector <struct Steam_Matchmaking_Servers_Direct_IP_Request> direct_ip_requests{};
|
||||||
|
|
||||||
HServerListRequest RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type);
|
HServerListRequest RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type);
|
||||||
void RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type);
|
void RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type);
|
||||||
|
|
||||||
|
//
|
||||||
|
static void network_callback(void *object, Common_Message *msg);
|
||||||
|
void server_details(Gameserver *g, gameserveritem_t *server);
|
||||||
|
void server_details_players(Gameserver *g, Steam_Matchmaking_Servers_Direct_IP_Request *r);
|
||||||
|
void server_details_rules(Gameserver *g, Steam_Matchmaking_Servers_Direct_IP_Request *r);
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_Matchmaking_Servers(class Settings *settings, class Local_Storage *local_storage, class Networking *network);
|
Steam_Matchmaking_Servers(class Settings *settings, class Local_Storage *local_storage, class Networking *network);
|
||||||
~Steam_Matchmaking_Servers();
|
~Steam_Matchmaking_Servers();
|
||||||
@ -195,25 +205,25 @@ public:
|
|||||||
// Get details on a given server in the list, you can get the valid range of index
|
// Get details on a given server in the list, you can get the valid range of index
|
||||||
// values by calling GetServerCount(). You will also receive index values in
|
// values by calling GetServerCount(). You will also receive index values in
|
||||||
// ISteamMatchmakingServerListResponse::ServerResponded() callbacks
|
// ISteamMatchmakingServerListResponse::ServerResponded() callbacks
|
||||||
gameserveritem_t *GetServerDetails( EMatchMakingType eType, int iServer ) { return GetServerDetails((HServerListRequest) eType , iServer ); }
|
gameserveritem_t *GetServerDetails( EMatchMakingType eType, int iServer );
|
||||||
|
|
||||||
// Cancel an request which is operation on the given list type. You should call this to cancel
|
// Cancel an request which is operation on the given list type. You should call this to cancel
|
||||||
// any in-progress requests before destructing a callback object that may have been passed
|
// any in-progress requests before destructing a callback object that may have been passed
|
||||||
// to one of the above list request calls. Not doing so may result in a crash when a callback
|
// to one of the above list request calls. Not doing so may result in a crash when a callback
|
||||||
// occurs on the destructed object.
|
// occurs on the destructed object.
|
||||||
void CancelQuery( EMatchMakingType eType ) { return CancelQuery((HServerListRequest) eType); }
|
void CancelQuery( EMatchMakingType eType );
|
||||||
|
|
||||||
// Ping every server in your list again but don't update the list of servers
|
// Ping every server in your list again but don't update the list of servers
|
||||||
void RefreshQuery( EMatchMakingType eType ) { return RefreshQuery((HServerListRequest) eType); }
|
void RefreshQuery( EMatchMakingType eType );
|
||||||
|
|
||||||
// Returns true if the list is currently refreshing its server list
|
// Returns true if the list is currently refreshing its server list
|
||||||
bool IsRefreshing( EMatchMakingType eType ) { return IsRefreshing((HServerListRequest) eType); }
|
bool IsRefreshing( EMatchMakingType eType );
|
||||||
|
|
||||||
// How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1
|
// How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1
|
||||||
int GetServerCount( EMatchMakingType eType ) { return GetServerCount((HServerListRequest) eType); }
|
int GetServerCount( EMatchMakingType eType );
|
||||||
|
|
||||||
// Refresh a single server inside of a query (rather than all the servers )
|
// Refresh a single server inside of a query (rather than all the servers )
|
||||||
void RefreshServer( EMatchMakingType eType, int iServer ) { return RefreshServer((HServerListRequest) eType, iServer); }
|
void RefreshServer( EMatchMakingType eType, int iServer );
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
//-----------------------------------------------------------------------------
|
||||||
// Queries to individual servers directly via IP/Port
|
// Queries to individual servers directly via IP/Port
|
||||||
@ -233,10 +243,9 @@ public:
|
|||||||
// to one of the above calls to avoid crashing when callbacks occur.
|
// to one of the above calls to avoid crashing when callbacks occur.
|
||||||
void CancelServerQuery( HServerQuery hServerQuery );
|
void CancelServerQuery( HServerQuery hServerQuery );
|
||||||
|
|
||||||
//
|
// called by steam_client::runcallbacks
|
||||||
void RunCallbacks();
|
void RunCallbacks();
|
||||||
void Callback(Common_Message *msg);
|
|
||||||
void server_details(Gameserver *g, gameserveritem_t *server);
|
|
||||||
void server_details_players(Gameserver *g, Steam_Matchmaking_Servers_Direct_IP_Request *r);
|
|
||||||
void server_details_rules(Gameserver *g, Steam_Matchmaking_Servers_Direct_IP_Request *r);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_MATCHMAKING_SERVERS_H__
|
||||||
|
@ -15,15 +15,20 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_MUSIC_H__
|
||||||
|
#define __INCLUDED_STEAM_MUSIC_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Music : public ISteamMusic
|
class Steam_Music :
|
||||||
|
public ISteamMusic
|
||||||
{
|
{
|
||||||
int playing;
|
int playing{};;
|
||||||
float volume;
|
float volume{};;
|
||||||
void change_playstate(int new_playing);
|
void change_playstate(int new_playing);
|
||||||
|
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_Music(class SteamCallBacks *callbacks);
|
Steam_Music(class SteamCallBacks *callbacks);
|
||||||
|
|
||||||
@ -41,3 +46,5 @@ public:
|
|||||||
void SetVolume( float flVolume );
|
void SetVolume( float flVolume );
|
||||||
float GetVolume();
|
float GetVolume();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_MUSIC_H__
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_MUSICREMOTE_H__
|
||||||
|
#define __INCLUDED_STEAM_MUSICREMOTE_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_MusicRemote : public ISteamMusicRemote
|
class Steam_MusicRemote :
|
||||||
|
public ISteamMusicRemote
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
// Service Definition
|
// Service Definition
|
||||||
@ -65,3 +69,5 @@ public:
|
|||||||
bool SetCurrentPlaylistEntry( int nID );
|
bool SetCurrentPlaylistEntry( int nID );
|
||||||
bool PlaylistDidChange();
|
bool PlaylistDidChange();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_MUSICREMOTE_H__
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,19 +15,20 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_NETWORKING_MESSAGES_H__
|
||||||
|
#define __INCLUDED_STEAM_NETWORKING_MESSAGES_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
#define NETWORKING_MESSAGES_TIMEOUT 30.0
|
|
||||||
|
|
||||||
struct Steam_Message_Connection {
|
struct Steam_Message_Connection {
|
||||||
SteamNetworkingIdentity remote_identity;
|
SteamNetworkingIdentity remote_identity{};
|
||||||
std::map<int, std::queue<std::string>> data;
|
std::map<int, std::queue<std::string>> data{};
|
||||||
|
|
||||||
std::list<int> channels;
|
std::list<int> channels{};
|
||||||
bool accepted = false;
|
bool accepted = false;
|
||||||
bool dead = false;
|
bool dead = false;
|
||||||
|
|
||||||
unsigned id;
|
unsigned id{};
|
||||||
unsigned remote_id = 0;
|
unsigned remote_id = 0;
|
||||||
|
|
||||||
std::chrono::high_resolution_clock::time_point created = std::chrono::high_resolution_clock::now();
|
std::chrono::high_resolution_clock::time_point created = std::chrono::high_resolution_clock::now();
|
||||||
@ -36,412 +37,119 @@ struct Steam_Message_Connection {
|
|||||||
class Steam_Networking_Messages :
|
class Steam_Networking_Messages :
|
||||||
public ISteamNetworkingMessages
|
public ISteamNetworkingMessages
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
std::map<CSteamID, Steam_Message_Connection> connections;
|
std::map<CSteamID, Steam_Message_Connection> connections{};
|
||||||
std::list<Common_Message> incoming_data;
|
std::list<Common_Message> incoming_data{};
|
||||||
|
|
||||||
unsigned id_counter = 0;
|
unsigned id_counter = 0;
|
||||||
std::chrono::steady_clock::time_point created;
|
std::chrono::steady_clock::time_point created{};
|
||||||
|
|
||||||
|
static void free_steam_message_data(SteamNetworkingMessage_t *pMsg);
|
||||||
|
static void delete_steam_message(SteamNetworkingMessage_t *pMsg);
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
|
std::map<CSteamID, Steam_Message_Connection>::iterator find_or_create_message_connection(SteamNetworkingIdentity identityRemote, bool incoming, bool restartbroken);
|
||||||
|
|
||||||
|
void end_connection(CSteamID steam_id);
|
||||||
|
|
||||||
|
void RunCallbacks();
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Networking_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Networking_Messages();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Networking_Messages *steam_networking_messages = (Steam_Networking_Messages *)object;
|
/// Sends a message to the specified host. If we don't already have a session with that user,
|
||||||
steam_networking_messages->Callback(msg);
|
/// a session is implicitly created. There might be some handshaking that needs to happen
|
||||||
}
|
/// before we can actually begin sending message data. If this handshaking fails and we can't
|
||||||
|
/// get through, an error will be posted via the callback SteamNetworkingMessagesSessionFailed_t.
|
||||||
|
/// There is no notification when the operation succeeds. (You should have the peer send a reply
|
||||||
|
/// for this purpose.)
|
||||||
|
///
|
||||||
|
/// Sending a message to a host will also implicitly accept any incoming connection from that host.
|
||||||
|
///
|
||||||
|
/// nSendFlags is a bitmask of k_nSteamNetworkingSend_xxx options
|
||||||
|
///
|
||||||
|
/// nRemoteChannel is a routing number you can use to help route message to different systems.
|
||||||
|
/// You'll have to call ReceiveMessagesOnChannel() with the same channel number in order to retrieve
|
||||||
|
/// the data on the other end.
|
||||||
|
///
|
||||||
|
/// Using different channels to talk to the same user will still use the same underlying
|
||||||
|
/// connection, saving on resources. If you don't need this feature, use 0.
|
||||||
|
/// Otherwise, small integers are the most efficient.
|
||||||
|
///
|
||||||
|
/// It is guaranteed that reliable messages to the same host on the same channel
|
||||||
|
/// will be be received by the remote host (if they are received at all) exactly once,
|
||||||
|
/// and in the same order that they were send.
|
||||||
|
///
|
||||||
|
/// NO other order guarantees exist! In particular, unreliable messages may be dropped,
|
||||||
|
/// received out of order with respect to each other and with respect to reliable data,
|
||||||
|
/// or may be received multiple times. Messages on different channels are *not* guaranteed
|
||||||
|
/// to be received in the order they were sent.
|
||||||
|
///
|
||||||
|
/// A note for those familiar with TCP/IP ports, or converting an existing codebase that
|
||||||
|
/// opened multiple sockets: You might notice that there is only one channel, and with
|
||||||
|
/// TCP/IP each endpoint has a port number. You can think of the channel number as the
|
||||||
|
/// *destination* port. If you need each message to also include a "source port" (so the
|
||||||
|
/// recipient can route the reply), then just put that in your message. That is essentially
|
||||||
|
/// how UDP works!
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// - k_EREsultOK on success.
|
||||||
|
/// - k_EResultNoConnection will be returned if the session has failed or was closed by the peer,
|
||||||
|
/// and k_nSteamNetworkingSend_AutoRestartBrokwnSession is not used. (You can use
|
||||||
|
/// GetSessionConnectionInfo to get the details.) In order to acknowledge the broken session
|
||||||
|
/// and start a new one, you must call CloseSessionWithUser
|
||||||
|
/// - See SendMessageToConnection::SendMessageToConnection for more
|
||||||
|
EResult SendMessageToUser( const SteamNetworkingIdentity &identityRemote, const void *pubData, uint32 cubData, int nSendFlags, int nRemoteChannel );
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
/// Reads the next message that has been sent from another user via SendMessageToUser() on the given channel.
|
||||||
{
|
/// Returns number of messages returned into your list. (0 if no message are available on that channel.)
|
||||||
// PRINT_DEBUG_ENTRY();
|
///
|
||||||
|
/// When you're done with the message object(s), make sure and call Release()!
|
||||||
|
int ReceiveMessagesOnChannel( int nLocalChannel, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages );
|
||||||
|
|
||||||
Steam_Networking_Messages *steam_networking_messages = (Steam_Networking_Messages *)object;
|
/// AcceptSessionWithUser() should only be called in response to a SteamP2PSessionRequest_t callback
|
||||||
steam_networking_messages->RunCallbacks();
|
/// SteamP2PSessionRequest_t will be posted if another user tries to send you a message, and you haven't
|
||||||
}
|
/// tried to talk to them. If you don't want to talk to them, just ignore the request.
|
||||||
|
/// If the user continues to send you messages, SteamP2PSessionRequest_t callbacks will continue to
|
||||||
|
/// be posted periodically. This may be called multiple times for a single user.
|
||||||
|
///
|
||||||
|
/// Calling SendMessage() on the other user, this implicitly accepts any pending session request.
|
||||||
|
bool AcceptSessionWithUser( const SteamNetworkingIdentity &identityRemote );
|
||||||
|
|
||||||
Steam_Networking_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
/// Call this when you're done talking to a user to immediately free up resources under-the-hood.
|
||||||
{
|
/// If the remote user tries to send data to you again, another P2PSessionRequest_t callback will
|
||||||
this->settings = settings;
|
/// be posted.
|
||||||
this->network = network;
|
///
|
||||||
this->run_every_runcb = run_every_runcb;
|
/// Note that sessions that go unused for a few minutes are automatically timed out.
|
||||||
this->network->setCallback(CALLBACK_ID_NETWORKING_MESSAGES, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
bool CloseSessionWithUser( const SteamNetworkingIdentity &identityRemote );
|
||||||
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Networking_Messages::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
/// Call this when you're done talking to a user on a specific channel. Once all
|
||||||
this->callbacks = callbacks;
|
/// open channels to a user have been closed, the open session to the user will be
|
||||||
|
/// closed, and any new data from this user will trigger a SteamP2PSessionRequest_t
|
||||||
|
/// callback
|
||||||
|
bool CloseChannelWithUser( const SteamNetworkingIdentity &identityRemote, int nLocalChannel );
|
||||||
|
|
||||||
this->created = std::chrono::steady_clock::now();
|
/// Returns information about the latest state of a connection, if any, with the given peer.
|
||||||
}
|
/// Primarily intended for debugging purposes, but can also be used to get more detailed
|
||||||
|
/// failure information. (See SendMessageToUser and k_nSteamNetworkingSend_AutoRestartBrokwnSession.)
|
||||||
~Steam_Networking_Messages()
|
///
|
||||||
{
|
/// Returns the value of SteamNetConnectionInfo_t::m_eState, or k_ESteamNetworkingConnectionState_None
|
||||||
this->network->rmCallback(CALLBACK_ID_NETWORKING_MESSAGES, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
/// if no connection exists with specified peer. You may pass nullptr for either parameter if
|
||||||
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
/// you do not need the corresponding details. Note that sessions time out after a while,
|
||||||
this->run_every_runcb->remove(&Steam_Networking_Messages::steam_run_every_runcb, this);
|
/// so if a connection fails, or SendMessageToUser returns SendMessageToUser, you cannot wait
|
||||||
}
|
/// indefinitely to obtain the reason for failure.
|
||||||
|
ESteamNetworkingConnectionState GetSessionConnectionInfo( const SteamNetworkingIdentity &identityRemote, SteamNetConnectionInfo_t *pConnectionInfo, SteamNetConnectionRealTimeStatus_t *pQuickStatus );
|
||||||
std::map<CSteamID, Steam_Message_Connection>::iterator find_or_create_message_connection(SteamNetworkingIdentity identityRemote, bool incoming, bool restartbroken)
|
|
||||||
{
|
|
||||||
auto conn = connections.find(identityRemote.GetSteamID());
|
|
||||||
if (conn == connections.end() || (conn->second.dead && restartbroken)) {
|
|
||||||
++id_counter;
|
|
||||||
struct Steam_Message_Connection con;
|
|
||||||
con.remote_identity = identityRemote;
|
|
||||||
con.id = id_counter;
|
|
||||||
connections[identityRemote.GetSteamID()] = con;
|
|
||||||
|
|
||||||
Common_Message msg;
|
|
||||||
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
|
||||||
msg.set_dest_id(con.remote_identity.GetSteamID64());
|
|
||||||
msg.set_allocated_networking_messages(new Networking_Messages);
|
|
||||||
if (incoming) {
|
|
||||||
msg.mutable_networking_messages()->set_type(Networking_Messages::CONNECTION_ACCEPT);
|
|
||||||
} else {
|
|
||||||
msg.mutable_networking_messages()->set_type(Networking_Messages::CONNECTION_NEW);
|
|
||||||
}
|
|
||||||
msg.mutable_networking_messages()->set_channel(0);
|
|
||||||
msg.mutable_networking_messages()->set_id_from(con.id);
|
|
||||||
network->sendTo(&msg, true);
|
|
||||||
|
|
||||||
conn = connections.find(identityRemote.GetSteamID());
|
|
||||||
|
|
||||||
if (incoming) {
|
|
||||||
SteamNetworkingMessagesSessionRequest_t data;
|
|
||||||
data.m_identityRemote = con.remote_identity;
|
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!incoming) {
|
|
||||||
conn->second.accepted = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sends a message to the specified host. If we don't already have a session with that user,
|
|
||||||
/// a session is implicitly created. There might be some handshaking that needs to happen
|
|
||||||
/// before we can actually begin sending message data. If this handshaking fails and we can't
|
|
||||||
/// get through, an error will be posted via the callback SteamNetworkingMessagesSessionFailed_t.
|
|
||||||
/// There is no notification when the operation succeeds. (You should have the peer send a reply
|
|
||||||
/// for this purpose.)
|
|
||||||
///
|
|
||||||
/// Sending a message to a host will also implicitly accept any incoming connection from that host.
|
|
||||||
///
|
|
||||||
/// nSendFlags is a bitmask of k_nSteamNetworkingSend_xxx options
|
|
||||||
///
|
|
||||||
/// nRemoteChannel is a routing number you can use to help route message to different systems.
|
|
||||||
/// You'll have to call ReceiveMessagesOnChannel() with the same channel number in order to retrieve
|
|
||||||
/// the data on the other end.
|
|
||||||
///
|
|
||||||
/// Using different channels to talk to the same user will still use the same underlying
|
|
||||||
/// connection, saving on resources. If you don't need this feature, use 0.
|
|
||||||
/// Otherwise, small integers are the most efficient.
|
|
||||||
///
|
|
||||||
/// It is guaranteed that reliable messages to the same host on the same channel
|
|
||||||
/// will be be received by the remote host (if they are received at all) exactly once,
|
|
||||||
/// and in the same order that they were send.
|
|
||||||
///
|
|
||||||
/// NO other order guarantees exist! In particular, unreliable messages may be dropped,
|
|
||||||
/// received out of order with respect to each other and with respect to reliable data,
|
|
||||||
/// or may be received multiple times. Messages on different channels are *not* guaranteed
|
|
||||||
/// to be received in the order they were sent.
|
|
||||||
///
|
|
||||||
/// A note for those familiar with TCP/IP ports, or converting an existing codebase that
|
|
||||||
/// opened multiple sockets: You might notice that there is only one channel, and with
|
|
||||||
/// TCP/IP each endpoint has a port number. You can think of the channel number as the
|
|
||||||
/// *destination* port. If you need each message to also include a "source port" (so the
|
|
||||||
/// recipient can route the reply), then just put that in your message. That is essentially
|
|
||||||
/// how UDP works!
|
|
||||||
///
|
|
||||||
/// Returns:
|
|
||||||
/// - k_EREsultOK on success.
|
|
||||||
/// - k_EResultNoConnection will be returned if the session has failed or was closed by the peer,
|
|
||||||
/// and k_nSteamNetworkingSend_AutoRestartBrokwnSession is not used. (You can use
|
|
||||||
/// GetSessionConnectionInfo to get the details.) In order to acknowledge the broken session
|
|
||||||
/// and start a new one, you must call CloseSessionWithUser
|
|
||||||
/// - See SendMessageToConnection::SendMessageToConnection for more
|
|
||||||
EResult SendMessageToUser( const SteamNetworkingIdentity &identityRemote, const void *pubData, uint32 cubData, int nSendFlags, int nRemoteChannel )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
const SteamNetworkingIPAddr *ip = identityRemote.GetIPAddr();
|
|
||||||
bool reliable = false;
|
|
||||||
if (nSendFlags & k_nSteamNetworkingSend_Reliable) {
|
|
||||||
reliable = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool restart_broken = false;
|
|
||||||
if (nSendFlags & k_nSteamNetworkingSend_AutoRestartBrokenSession) {
|
|
||||||
restart_broken = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (identityRemote.m_eType == k_ESteamNetworkingIdentityType_SteamID) {
|
|
||||||
PRINT_DEBUG("%llu", identityRemote.GetSteamID64());
|
|
||||||
//steam id identity
|
|
||||||
} else if (ip) {
|
|
||||||
PRINT_DEBUG("%u:%u ipv4? %u", ip->GetIPv4(), ip->m_port, ip->IsIPv4());
|
|
||||||
//ip addr
|
|
||||||
return k_EResultNoConnection; //TODO
|
|
||||||
} else {
|
|
||||||
return k_EResultNoConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto conn = find_or_create_message_connection(identityRemote, false, restart_broken);
|
|
||||||
if (conn->second.dead) {
|
|
||||||
return k_EResultNoConnection;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common_Message msg;
|
|
||||||
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
|
||||||
msg.set_dest_id(conn->second.remote_identity.GetSteamID64());
|
|
||||||
msg.set_allocated_networking_messages(new Networking_Messages);
|
|
||||||
msg.mutable_networking_messages()->set_type(Networking_Messages::DATA);
|
|
||||||
msg.mutable_networking_messages()->set_channel(nRemoteChannel);
|
|
||||||
msg.mutable_networking_messages()->set_id_from(conn->second.id);
|
|
||||||
msg.mutable_networking_messages()->set_data(pubData, cubData);
|
|
||||||
|
|
||||||
network->sendTo(&msg, reliable);
|
|
||||||
return k_EResultOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_steam_message_data(SteamNetworkingMessage_t *pMsg)
|
|
||||||
{
|
|
||||||
free(pMsg->m_pData);
|
|
||||||
pMsg->m_pData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_steam_message(SteamNetworkingMessage_t *pMsg)
|
|
||||||
{
|
|
||||||
if (pMsg->m_pfnFreeData) pMsg->m_pfnFreeData(pMsg);
|
|
||||||
delete pMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Reads the next message that has been sent from another user via SendMessageToUser() on the given channel.
|
|
||||||
/// Returns number of messages returned into your list. (0 if no message are available on that channel.)
|
|
||||||
///
|
|
||||||
/// When you're done with the message object(s), make sure and call Release()!
|
|
||||||
int ReceiveMessagesOnChannel( int nLocalChannel, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
int message_counter = 0;
|
|
||||||
|
|
||||||
for (auto & conn : connections) {
|
|
||||||
auto chan = conn.second.data.find(nLocalChannel);
|
|
||||||
if (chan != conn.second.data.end()) {
|
|
||||||
while (!chan->second.empty() && message_counter < nMaxMessages) {
|
|
||||||
SteamNetworkingMessage_t *pMsg = new SteamNetworkingMessage_t(); //TODO size is wrong
|
|
||||||
unsigned long size = chan->second.front().size();
|
|
||||||
pMsg->m_pData = malloc(size);
|
|
||||||
pMsg->m_cbSize = size;
|
|
||||||
memcpy(pMsg->m_pData, chan->second.front().data(), size);
|
|
||||||
pMsg->m_conn = conn.second.id;
|
|
||||||
pMsg->m_identityPeer = conn.second.remote_identity;
|
|
||||||
pMsg->m_nConnUserData = -1;
|
|
||||||
pMsg->m_usecTimeReceived = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - created).count();
|
|
||||||
//TODO: messagenumber?
|
|
||||||
// pMsg->m_nMessageNumber = connect_socket->second.packet_receive_counter;
|
|
||||||
// ++connect_socket->second.packet_receive_counter;
|
|
||||||
|
|
||||||
pMsg->m_pfnFreeData = &free_steam_message_data;
|
|
||||||
pMsg->m_pfnRelease = &delete_steam_message;
|
|
||||||
pMsg->m_nChannel = nLocalChannel;
|
|
||||||
ppOutMessages[message_counter] = pMsg;
|
|
||||||
++message_counter;
|
|
||||||
chan->second.pop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (message_counter >= nMaxMessages) {
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_DEBUG("got %u", message_counter);
|
|
||||||
return message_counter;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// AcceptSessionWithUser() should only be called in response to a SteamP2PSessionRequest_t callback
|
|
||||||
/// SteamP2PSessionRequest_t will be posted if another user tries to send you a message, and you haven't
|
|
||||||
/// tried to talk to them. If you don't want to talk to them, just ignore the request.
|
|
||||||
/// If the user continues to send you messages, SteamP2PSessionRequest_t callbacks will continue to
|
|
||||||
/// be posted periodically. This may be called multiple times for a single user.
|
|
||||||
///
|
|
||||||
/// Calling SendMessage() on the other user, this implicitly accepts any pending session request.
|
|
||||||
bool AcceptSessionWithUser( const SteamNetworkingIdentity &identityRemote )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
auto conn = connections.find(identityRemote.GetSteamID());
|
|
||||||
if (conn == connections.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
conn->second.accepted = true;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call this when you're done talking to a user to immediately free up resources under-the-hood.
|
|
||||||
/// If the remote user tries to send data to you again, another P2PSessionRequest_t callback will
|
|
||||||
/// be posted.
|
|
||||||
///
|
|
||||||
/// Note that sessions that go unused for a few minutes are automatically timed out.
|
|
||||||
bool CloseSessionWithUser( const SteamNetworkingIdentity &identityRemote )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
auto conn = connections.find(identityRemote.GetSteamID());
|
|
||||||
if (conn == connections.end()) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
Common_Message msg;
|
|
||||||
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
|
||||||
msg.set_dest_id(conn->second.remote_identity.GetSteamID64());
|
|
||||||
msg.set_allocated_networking_messages(new Networking_Messages);
|
|
||||||
msg.mutable_networking_messages()->set_type(Networking_Messages::CONNECTION_END);
|
|
||||||
msg.mutable_networking_messages()->set_channel(0);
|
|
||||||
msg.mutable_networking_messages()->set_id_from(conn->second.id);
|
|
||||||
network->sendTo(&msg, true);
|
|
||||||
|
|
||||||
connections.erase(conn);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Call this when you're done talking to a user on a specific channel. Once all
|
|
||||||
/// open channels to a user have been closed, the open session to the user will be
|
|
||||||
/// closed, and any new data from this user will trigger a SteamP2PSessionRequest_t
|
|
||||||
/// callback
|
|
||||||
bool CloseChannelWithUser( const SteamNetworkingIdentity &identityRemote, int nLocalChannel )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
//TODO
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns information about the latest state of a connection, if any, with the given peer.
|
|
||||||
/// Primarily intended for debugging purposes, but can also be used to get more detailed
|
|
||||||
/// failure information. (See SendMessageToUser and k_nSteamNetworkingSend_AutoRestartBrokwnSession.)
|
|
||||||
///
|
|
||||||
/// Returns the value of SteamNetConnectionInfo_t::m_eState, or k_ESteamNetworkingConnectionState_None
|
|
||||||
/// if no connection exists with specified peer. You may pass nullptr for either parameter if
|
|
||||||
/// you do not need the corresponding details. Note that sessions time out after a while,
|
|
||||||
/// so if a connection fails, or SendMessageToUser returns SendMessageToUser, you cannot wait
|
|
||||||
/// indefinitely to obtain the reason for failure.
|
|
||||||
ESteamNetworkingConnectionState GetSessionConnectionInfo( const SteamNetworkingIdentity &identityRemote, SteamNetConnectionInfo_t *pConnectionInfo, SteamNetConnectionRealTimeStatus_t *pQuickStatus )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
auto conn = connections.find(identityRemote.GetSteamID());
|
|
||||||
if (conn == connections.end()) {
|
|
||||||
return k_ESteamNetworkingConnectionState_None;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESteamNetworkingConnectionState state = k_ESteamNetworkingConnectionState_Connected;
|
|
||||||
if (conn->second.remote_id == 0 || !conn->second.accepted) {
|
|
||||||
state = k_ESteamNetworkingConnectionState_Connecting;
|
|
||||||
} else if (conn->second.dead) {
|
|
||||||
state = k_ESteamNetworkingConnectionState_ClosedByPeer;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pConnectionInfo) {
|
|
||||||
memset(pConnectionInfo, 0, sizeof(SteamNetConnectionInfo_t));
|
|
||||||
pConnectionInfo->m_eState = state;
|
|
||||||
pConnectionInfo->m_identityRemote = conn->second.remote_identity;
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pQuickStatus) {
|
|
||||||
memset(pQuickStatus, 0, sizeof(SteamNetConnectionRealTimeStatus_t));
|
|
||||||
pQuickStatus->m_eState = state;
|
|
||||||
pQuickStatus->m_nPing = 10; //TODO: calculate real numbers?
|
|
||||||
pQuickStatus->m_flConnectionQualityLocal = 1.0;
|
|
||||||
pQuickStatus->m_flConnectionQualityRemote = 1.0;
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
return k_ESteamNetworkingConnectionState_Connected;
|
|
||||||
}
|
|
||||||
|
|
||||||
void end_connection(CSteamID steam_id)
|
|
||||||
{
|
|
||||||
auto conn = connections.find(steam_id);
|
|
||||||
if (conn != connections.end()) {
|
|
||||||
conn->second.dead = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
auto msg = std::begin(incoming_data);
|
|
||||||
while (msg != std::end(incoming_data)) {
|
|
||||||
CSteamID source_id((uint64)msg->source_id());
|
|
||||||
|
|
||||||
auto conn = connections.find(source_id);
|
|
||||||
if (conn != connections.end()) {
|
|
||||||
if (conn->second.remote_id == msg->networking_messages().id_from())
|
|
||||||
conn->second.data[msg->networking_messages().channel()].push(msg->networking_messages().data());
|
|
||||||
}
|
|
||||||
|
|
||||||
msg = incoming_data.erase(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
auto conn = std::begin(connections);
|
|
||||||
while (conn != std::end(connections)) {
|
|
||||||
if (!conn->second.accepted && check_timedout(conn->second.created, NETWORKING_MESSAGES_TIMEOUT)) {
|
|
||||||
conn = connections.erase(conn);
|
|
||||||
} else {
|
|
||||||
++conn;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
end_connection((uint64)msg->source_id());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_messages()) {
|
|
||||||
PRINT_DEBUG("got network socket msg %u", msg->networking_messages().type());
|
|
||||||
if (msg->networking_messages().type() == Networking_Messages::CONNECTION_NEW) {
|
|
||||||
SteamNetworkingIdentity identity;
|
|
||||||
identity.SetSteamID64(msg->source_id());
|
|
||||||
auto conn = find_or_create_message_connection(identity, true, false);
|
|
||||||
conn->second.remote_id = msg->networking_messages().id_from();
|
|
||||||
conn->second.dead = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->networking_messages().type() == Networking_Messages::CONNECTION_ACCEPT) {
|
|
||||||
auto conn = connections.find((uint64)msg->source_id());
|
|
||||||
if (conn != connections.end()) {
|
|
||||||
conn->second.remote_id = msg->networking_messages().id_from();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->networking_messages().type() == Networking_Messages::CONNECTION_END) {
|
|
||||||
end_connection((uint64)msg->source_id());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->networking_messages().type() == Networking_Messages::DATA) {
|
|
||||||
incoming_data.push_back(Common_Message(*msg));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_NETWORKING_MESSAGES_H__
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,6 +15,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_NETWORKING_SOCKETSERIALIZED_H__
|
||||||
|
#define __INCLUDED_STEAM_NETWORKING_SOCKETSERIALIZED_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Networking_Sockets_Serialized :
|
class Steam_Networking_Sockets_Serialized :
|
||||||
@ -23,145 +26,47 @@ public ISteamNetworkingSocketsSerialized003,
|
|||||||
public ISteamNetworkingSocketsSerialized004,
|
public ISteamNetworkingSocketsSerialized004,
|
||||||
public ISteamNetworkingSocketsSerialized005
|
public ISteamNetworkingSocketsSerialized005
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Networking_Sockets_Serialized(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Networking_Sockets_Serialized();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Networking_Sockets_Serialized *steam_networkingsockets = (Steam_Networking_Sockets_Serialized *)object;
|
void SendP2PRendezvous( CSteamID steamIDRemote, uint32 unConnectionIDSrc, const void *pMsgRendezvous, uint32 cbRendezvous );
|
||||||
steam_networkingsockets->Callback(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
void SendP2PConnectionFailure( CSteamID steamIDRemote, uint32 unConnectionIDDest, uint32 nReason, const char *pszReason );
|
||||||
{
|
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Networking_Sockets_Serialized *steam_networkingsockets = (Steam_Networking_Sockets_Serialized *)object;
|
SteamAPICall_t GetCertAsync();
|
||||||
steam_networkingsockets->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_Networking_Sockets_Serialized(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
int GetNetworkConfigJSON( void *buf, uint32 cbBuf, const char *pszLauncherPartner );
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Sockets_Serialized::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Networking_Sockets_Serialized::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
int GetNetworkConfigJSON( void *buf, uint32 cbBuf );
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Networking_Sockets_Serialized()
|
void CacheRelayTicket( const void *pTicket, uint32 cbTicket );
|
||||||
{
|
|
||||||
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Sockets_Serialized::steam_callback, this);
|
|
||||||
this->run_every_runcb->remove(&Steam_Networking_Sockets_Serialized::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendP2PRendezvous( CSteamID steamIDRemote, uint32 unConnectionIDSrc, const void *pMsgRendezvous, uint32 cbRendezvous )
|
uint32 GetCachedRelayTicketCount();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void SendP2PConnectionFailure( CSteamID steamIDRemote, uint32 unConnectionIDDest, uint32 nReason, const char *pszReason )
|
int GetCachedRelayTicket( uint32 idxTicket, void *buf, uint32 cbBuf );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
SteamAPICall_t GetCertAsync()
|
void PostConnectionStateMsg( const void *pMsg, uint32 cbMsg );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
struct SteamNetworkingSocketsCert_t data = {};
|
|
||||||
data.m_eResult = k_EResultOK;
|
|
||||||
|
|
||||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
bool GetSTUNServer(int dont_know, char *buf, unsigned int len);
|
||||||
}
|
|
||||||
|
|
||||||
int GetNetworkConfigJSON( void *buf, uint32 cbBuf, const char *pszLauncherPartner )
|
bool BAllowDirectConnectToPeer(SteamNetworkingIdentity const &identity);
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetNetworkConfigJSON( void *buf, uint32 cbBuf )
|
int BeginAsyncRequestFakeIP(int a);
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return GetNetworkConfigJSON(buf, cbBuf, "");
|
|
||||||
}
|
|
||||||
|
|
||||||
void CacheRelayTicket( const void *pTicket, uint32 cbTicket )
|
void RunCallbacks();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 GetCachedRelayTicketCount()
|
void Callback(Common_Message *msg);
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetCachedRelayTicket( uint32 idxTicket, void *buf, uint32 cbBuf )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void PostConnectionStateMsg( const void *pMsg, uint32 cbMsg )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetSTUNServer(int dont_know, char *buf, unsigned int len)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BAllowDirectConnectToPeer(SteamNetworkingIdentity const &identity)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
int BeginAsyncRequestFakeIP(int a)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_NETWORKING_SOCKETSERIALIZED_H__
|
||||||
|
@ -15,6 +15,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_NETWORKING_UTILS_H__
|
||||||
|
#define __INCLUDED_STEAM_NETWORKING_UTILS_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Networking_Utils :
|
class Steam_Networking_Utils :
|
||||||
@ -23,728 +26,246 @@ public ISteamNetworkingUtils002,
|
|||||||
public ISteamNetworkingUtils003,
|
public ISteamNetworkingUtils003,
|
||||||
public ISteamNetworkingUtils
|
public ISteamNetworkingUtils
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
||||||
FSteamNetworkingSocketsDebugOutput debug_function;
|
FSteamNetworkingSocketsDebugOutput debug_function{};
|
||||||
bool relay_initialized = false;
|
bool relay_initialized = false;
|
||||||
bool init_relay = false;
|
bool init_relay = false;
|
||||||
|
|
||||||
|
static void free_steam_message_data(SteamNetworkingMessage_t *pMsg);
|
||||||
|
static void delete_steam_message(SteamNetworkingMessage_t *pMsg);
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Networking_Utils(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Networking_Utils();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Networking_Utils *steam_networkingutils = (Steam_Networking_Utils *)object;
|
|
||||||
steam_networkingutils->Callback(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
|
||||||
{
|
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Networking_Utils *steam_networkingutils = (Steam_Networking_Utils *)object;
|
|
||||||
steam_networkingutils->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_Networking_Utils(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
//this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Utils::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Networking_Utils::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Networking_Utils()
|
|
||||||
{
|
|
||||||
//this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Utils::steam_callback, this);
|
|
||||||
this->run_every_runcb->remove(&Steam_Networking_Utils::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void free_steam_message_data(SteamNetworkingMessage_t *pMsg)
|
|
||||||
{
|
|
||||||
free(pMsg->m_pData);
|
|
||||||
pMsg->m_pData = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void delete_steam_message(SteamNetworkingMessage_t *pMsg)
|
|
||||||
{
|
|
||||||
if (pMsg->m_pfnFreeData) pMsg->m_pfnFreeData(pMsg);
|
|
||||||
delete pMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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.
|
|
||||||
///
|
|
||||||
/// Optionally you can also request that this system allocate space to
|
|
||||||
/// hold the payload itself. If cbAllocateBuffer is nonzero, the system
|
|
||||||
/// will allocate memory to hold a payload of at least cbAllocateBuffer bytes.
|
|
||||||
/// m_pData will point to the allocated buffer, m_cbSize will be set to the
|
|
||||||
/// size, and m_pfnFreeData will be set to the proper function to free up
|
|
||||||
/// the buffer.
|
|
||||||
///
|
|
||||||
/// If cbAllocateBuffer=0, then no buffer is allocated. m_pData will be NULL,
|
|
||||||
/// m_cbSize will be zero, and m_pfnFreeData will be NULL. You will need to
|
|
||||||
/// set each of these.
|
|
||||||
///
|
|
||||||
/// You can use SteamNetworkingMessage_t::Release to free up the message
|
|
||||||
/// bookkeeping object and any associated buffer. See
|
|
||||||
/// ISteamNetworkingSockets::SendMessages for details on reference
|
|
||||||
/// counting and ownership.
|
|
||||||
SteamNetworkingMessage_t *AllocateMessage( int cbAllocateBuffer )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
SteamNetworkingMessage_t *pMsg = new SteamNetworkingMessage_t();
|
|
||||||
pMsg->m_pfnFreeData = &free_steam_message_data;
|
|
||||||
pMsg->m_pfnRelease = &delete_steam_message;
|
|
||||||
if (cbAllocateBuffer < 0)
|
|
||||||
cbAllocateBuffer = 0;
|
|
||||||
|
|
||||||
pMsg->m_pData = nullptr;
|
|
||||||
if (cbAllocateBuffer)
|
|
||||||
pMsg->m_pData = malloc(cbAllocateBuffer);
|
|
||||||
|
|
||||||
pMsg->m_cbSize = cbAllocateBuffer;
|
|
||||||
return pMsg;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool InitializeRelayAccess()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
init_relay = true;
|
|
||||||
return relay_initialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
SteamRelayNetworkStatus_t get_network_status()
|
|
||||||
{
|
|
||||||
SteamRelayNetworkStatus_t data = {};
|
|
||||||
data.m_eAvail = k_ESteamNetworkingAvailability_Current;
|
|
||||||
data.m_bPingMeasurementInProgress = 0;
|
|
||||||
data.m_eAvailAnyRelay = k_ESteamNetworkingAvailability_Current;
|
|
||||||
data.m_eAvailNetworkConfig = k_ESteamNetworkingAvailability_Current;
|
|
||||||
strcpy(data.m_debugMsg, "OK");
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Fetch current status of the relay network.
|
|
||||||
///
|
|
||||||
/// SteamRelayNetworkStatus_t is also a callback. It will be triggered on
|
|
||||||
/// both the user and gameserver interfaces any time the status changes, or
|
|
||||||
/// ping measurement starts or stops.
|
|
||||||
///
|
|
||||||
/// SteamRelayNetworkStatus_t::m_eAvail is returned. If you want
|
|
||||||
/// more details, you can pass a non-NULL value.
|
|
||||||
ESteamNetworkingAvailability GetRelayNetworkStatus( SteamRelayNetworkStatus_t *pDetails )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("TODO %p", pDetails);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
//TODO: check if this is how real steam returns it
|
|
||||||
SteamRelayNetworkStatus_t data = {};
|
|
||||||
if (relay_initialized) {
|
|
||||||
data = get_network_status();
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pDetails) {
|
|
||||||
*pDetails = data;
|
|
||||||
}
|
|
||||||
|
|
||||||
return k_ESteamNetworkingAvailability_Current;
|
|
||||||
}
|
|
||||||
|
|
||||||
float GetLocalPingLocation( SteamNetworkPingLocation_t &result )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (relay_initialized) {
|
|
||||||
result.m_data[2] = 123;
|
|
||||||
result.m_data[8] = 67;
|
|
||||||
return 2.0;
|
|
||||||
}
|
|
||||||
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
//return k_nSteamNetworkingPing_Unknown;
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void ConvertPingLocationToString( const SteamNetworkPingLocation_t &location, char *pszBuf, int cchBufSize )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
strncpy(pszBuf, "fra=10+2", cchBufSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool ParsePingLocationString( const char *pszString, SteamNetworkPingLocation_t &result )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool CheckPingDataUpToDate( float flMaxAgeSeconds )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("TODO %f", flMaxAgeSeconds);
|
|
||||||
init_relay = true;
|
|
||||||
return relay_initialized;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool IsPingMeasurementInProgress()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetDirectPingToPOP( SteamNetworkingPOPID popID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetPOPCount()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
int GetPOPList( SteamNetworkingPOPID *list, int nListSz )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Misc
|
|
||||||
//
|
|
||||||
|
|
||||||
/// Fetch current timestamp. This timer has the following properties:
|
|
||||||
///
|
|
||||||
/// - Monotonicity is guaranteed.
|
|
||||||
/// - The initial value will be at least 24*3600*30*1e6, i.e. about
|
|
||||||
/// 30 days worth of microseconds. In this way, the timestamp value of
|
|
||||||
/// 0 will always be at least "30 days ago". Also, negative numbers
|
|
||||||
/// will never be returned.
|
|
||||||
/// - Wraparound / overflow is not a practical concern.
|
|
||||||
///
|
|
||||||
/// If you are running under the debugger and stop the process, the clock
|
|
||||||
/// might not advance the full wall clock time that has elapsed between
|
|
||||||
/// calls. If the process is not blocked from normal operation, the
|
|
||||||
/// timestamp values will track wall clock time, even if you don't call
|
|
||||||
/// the function frequently.
|
|
||||||
///
|
|
||||||
/// The value is only meaningful for this run of the process. Don't compare
|
|
||||||
/// it to values obtained on another computer, or other runs of the same process.
|
|
||||||
SteamNetworkingMicroseconds GetLocalTimestamp()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - initialized_time).count() + (SteamNetworkingMicroseconds)24*3600*30*1e6;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Set a function to receive network-related information that is useful for debugging.
|
|
||||||
/// This can be very useful during development, but it can also be useful for troubleshooting
|
|
||||||
/// problems with tech savvy end users. If you have a console or other log that customers
|
|
||||||
/// can examine, these log messages can often be helpful to troubleshoot network issues.
|
|
||||||
/// (Especially any warning/error messages.)
|
|
||||||
///
|
|
||||||
/// The detail level indicates what message to invoke your callback on. Lower numeric
|
|
||||||
/// value means more important, and the value you pass is the lowest priority (highest
|
|
||||||
/// numeric value) you wish to receive callbacks for.
|
|
||||||
///
|
|
||||||
/// Except when debugging, you should only use k_ESteamNetworkingSocketsDebugOutputType_Msg
|
|
||||||
/// or k_ESteamNetworkingSocketsDebugOutputType_Warning. For best performance, do NOT
|
|
||||||
/// request a high detail level and then filter out messages in your callback. Instead,
|
|
||||||
/// call function function to adjust the desired level of detail.
|
|
||||||
///
|
|
||||||
/// IMPORTANT: This may be called from a service thread, while we own a mutex, etc.
|
|
||||||
/// Your output function must be threadsafe and fast! Do not make any other
|
|
||||||
/// Steamworks calls from within the handler.
|
|
||||||
void SetDebugOutputFunction( ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%i", eDetailLevel);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (eDetailLevel != k_ESteamNetworkingSocketsDebugOutputType_None) {
|
|
||||||
debug_function = pfnFunc;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
// Fake IP
|
|
||||||
//
|
|
||||||
// Useful for interfacing with code that assumes peers are identified using an IPv4 address
|
|
||||||
//
|
|
||||||
|
|
||||||
/// Return true if an IPv4 address is one that might be used as a "fake" one.
|
|
||||||
/// This function is fast; it just does some logical tests on the IP and does
|
|
||||||
/// not need to do any lookup operations.
|
|
||||||
// inline bool IsFakeIPv4( uint32 nIPv4 ) { return GetIPv4FakeIPType( nIPv4 ) > k_ESteamNetworkingFakeIPType_NotFake; }
|
|
||||||
ESteamNetworkingFakeIPType GetIPv4FakeIPType( uint32 nIPv4 )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ESteamNetworkingFakeIPType_NotFake;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get the real identity associated with a given FakeIP.
|
|
||||||
///
|
|
||||||
/// On failure, returns:
|
|
||||||
/// - k_EResultInvalidParam: the IP is not a FakeIP.
|
|
||||||
/// - k_EResultNoMatch: we don't recognize that FakeIP and don't know the corresponding identity.
|
|
||||||
///
|
|
||||||
/// FakeIP's used by active connections, or the FakeIPs assigned to local identities,
|
|
||||||
/// will always work. FakeIPs for recently destroyed connections will continue to
|
|
||||||
/// return results for a little while, but not forever. At some point, we will forget
|
|
||||||
/// FakeIPs to save space. It's reasonably safe to assume that you can read back the
|
|
||||||
/// real identity of a connection very soon after it is destroyed. But do not wait
|
|
||||||
/// indefinitely.
|
|
||||||
EResult GetRealIdentityForFakeIP( const SteamNetworkingIPAddr &fakeIP, SteamNetworkingIdentity *pOutRealIdentity )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_EResultNoMatch;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
//
|
|
||||||
// Set and get configuration values, see ESteamNetworkingConfigValue for individual descriptions.
|
|
||||||
//
|
|
||||||
|
|
||||||
// Shortcuts for common cases. (Implemented as inline functions below)
|
|
||||||
/*
|
|
||||||
bool SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val );
|
|
||||||
bool SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val );
|
|
||||||
bool SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val );
|
|
||||||
bool SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val );
|
|
||||||
bool SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val );
|
|
||||||
bool SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val );
|
|
||||||
*/
|
|
||||||
/// Set a configuration value.
|
|
||||||
/// - eValue: which value is being set
|
|
||||||
/// - eScope: Onto what type of object are you applying the setting?
|
|
||||||
/// - scopeArg: Which object you want to change? (Ignored for global scope). E.g. connection handle, listen socket handle, interface pointer, etc.
|
|
||||||
/// - eDataType: What type of data is in the buffer at pValue? This must match the type of the variable exactly!
|
|
||||||
/// - pArg: Value to set it to. You can pass NULL to remove a non-global sett at this scope,
|
|
||||||
/// causing the value for that object to use global defaults. Or at global scope, passing NULL
|
|
||||||
/// will reset any custom value and restore it to the system default.
|
|
||||||
/// NOTE: When setting callback functions, do not pass the function pointer directly.
|
|
||||||
/// Your argument should be a pointer to a function pointer.
|
|
||||||
bool SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
|
||||||
ESteamNetworkingConfigDataType eDataType, const void *pArg )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("TODO %i %i " "%" PRIdPTR " %i %p", eValue, eScopeType, scopeObj, eDataType, pArg);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Get a configuration value.
|
|
||||||
/// - eValue: which value to fetch
|
|
||||||
/// - eScopeType: query setting on what type of object
|
|
||||||
/// - eScopeArg: the object to query the setting for
|
|
||||||
/// - pOutDataType: If non-NULL, the data type of the value is returned.
|
|
||||||
/// - pResult: Where to put the result. Pass NULL to query the required buffer size. (k_ESteamNetworkingGetConfigValue_BufferTooSmall will be returned.)
|
|
||||||
/// - cbResult: IN: the size of your buffer. OUT: the number of bytes filled in or required.
|
|
||||||
ESteamNetworkingGetConfigValueResult GetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
|
||||||
ESteamNetworkingConfigDataType *pOutDataType, void *pResult, size_t *cbResult )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ESteamNetworkingGetConfigValue_BadValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// Returns info about a configuration value. Returns false if the value does not exist.
|
|
||||||
/// pOutNextValue can be used to iterate through all of the known configuration values.
|
|
||||||
/// (Use GetFirstConfigValue() to begin the iteration, will be k_ESteamNetworkingConfig_Invalid on the last value)
|
|
||||||
/// Any of the output parameters can be NULL if you do not need that information.
|
|
||||||
bool GetConfigValueInfo( ESteamNetworkingConfigValue eValue, const char **pOutName, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope, ESteamNetworkingConfigValue *pOutNextValue )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
//TODO flat api
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get info about a configuration value. Returns the name of the value,
|
|
||||||
/// or NULL if the value doesn't exist. Other output parameters can be NULL
|
|
||||||
/// if you do not need them.
|
|
||||||
const char *GetConfigValueInfo( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
//TODO flat api
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Return the lowest numbered configuration value available in the current environment.
|
|
||||||
ESteamNetworkingConfigValue GetFirstConfigValue()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ESteamNetworkingConfig_Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate the list of all configuration values in the current environment that it might
|
|
||||||
/// be possible to display or edit using a generic UI. To get the first iterable value,
|
|
||||||
/// pass k_ESteamNetworkingConfig_Invalid. Returns k_ESteamNetworkingConfig_Invalid
|
|
||||||
/// to signal end of list.
|
|
||||||
///
|
|
||||||
/// The bEnumerateDevVars argument can be used to include "dev" vars. These are vars that
|
|
||||||
/// are recommended to only be editable in "debug" or "dev" mode and typically should not be
|
|
||||||
/// shown in a retail environment where a malicious local user might use this to cheat.
|
|
||||||
ESteamNetworkingConfigValue IterateGenericEditableConfigValues( ESteamNetworkingConfigValue eCurrent, bool bEnumerateDevVars )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ESteamNetworkingConfig_Invalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// String conversions. You'll usually access these using the respective
|
|
||||||
// inline methods.
|
|
||||||
void SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr &addr, char *buf, size_t cbBuf, bool bWithPort )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (buf == nullptr || cbBuf == 0) return;
|
|
||||||
|
|
||||||
char buffer[64]{}; // enough for ipv4 & ipv6 + port
|
|
||||||
std::string str_addr{};
|
|
||||||
if (addr.IsIPv4()) {
|
|
||||||
in_addr ipv4_addr;
|
|
||||||
ipv4_addr.s_addr = htonl(addr.GetIPv4());
|
|
||||||
|
|
||||||
if (inet_ntop(AF_INET, &ipv4_addr, buffer, sizeof(buffer) / sizeof(*buffer)) != nullptr) {
|
|
||||||
if (bWithPort) {
|
|
||||||
str_addr = buffer;
|
|
||||||
str_addr += ':';
|
|
||||||
str_addr += std::to_string(addr.m_port);
|
|
||||||
} else {
|
|
||||||
str_addr = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
in6_addr ipv6_addr{};
|
|
||||||
memcpy(ipv6_addr.s6_addr, addr.m_ipv6, sizeof(addr.m_ipv6));
|
|
||||||
|
|
||||||
if (inet_ntop(AF_INET6, &ipv6_addr, buffer, sizeof(buffer) / sizeof(*buffer)) != nullptr) {
|
|
||||||
if (bWithPort) {
|
|
||||||
str_addr = '[';
|
|
||||||
str_addr += buffer;
|
|
||||||
str_addr += "]:";
|
|
||||||
str_addr += std::to_string(addr.m_port);
|
|
||||||
} else {
|
|
||||||
str_addr = buffer;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cbBuf = std::min<size_t>(cbBuf, str_addr.length() + 1);
|
|
||||||
strncpy(buf, str_addr.c_str(), cbBuf);
|
|
||||||
buf[cbBuf - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
bool valid = false;
|
|
||||||
|
|
||||||
if (pAddr == nullptr || pszStr == nullptr) return valid;
|
|
||||||
|
|
||||||
std::string str(pszStr);
|
|
||||||
size_t pos = str.find(':');
|
|
||||||
|
|
||||||
if (pos != std::string::npos) {// Try ipv4 with port
|
|
||||||
in_addr ipv4_addr;
|
|
||||||
std::string tmp(str);
|
|
||||||
tmp[pos] = 0;
|
|
||||||
const char* ip = tmp.c_str();
|
|
||||||
const char* port = &tmp[pos + 1];
|
|
||||||
|
|
||||||
if (inet_pton(AF_INET, ip, &ipv4_addr) == 1)
|
|
||||||
{
|
|
||||||
valid = true;
|
|
||||||
pAddr->SetIPv4(ntohl(ipv4_addr.s_addr), strtoul(port, nullptr, 10));
|
|
||||||
}
|
|
||||||
} else {// Try ipv4 without port
|
|
||||||
in_addr ipv4_addr;
|
|
||||||
if (inet_pton(AF_INET, str.c_str(), &ipv4_addr) == 1)
|
|
||||||
{
|
|
||||||
valid = true;
|
|
||||||
pAddr->SetIPv4(ntohl(ipv4_addr.s_addr), 0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid) {// Try ipv6
|
|
||||||
addrinfo* info = nullptr;
|
|
||||||
addrinfo hints = {};
|
|
||||||
hints.ai_family = AF_INET6;
|
|
||||||
hints.ai_socktype = SOCK_STREAM;
|
|
||||||
hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
|
|
||||||
|
|
||||||
size_t sep_pos = 0;
|
|
||||||
std::string ip;
|
|
||||||
int sep_count = 0;
|
|
||||||
for (int i = 0; i < str.length(); ++i) {
|
|
||||||
if (str[i] == ':') {
|
|
||||||
sep_pos = i;
|
|
||||||
++sep_count;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (sep_count == 8) {
|
|
||||||
ip = std::move(std::string(str.begin(), str.begin() + sep_pos));
|
|
||||||
} else {
|
|
||||||
ip = str;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (getaddrinfo(ip.c_str(), nullptr, &hints, &info) == 0) {
|
|
||||||
sockaddr_in6* maddr = (sockaddr_in6*)info->ai_addr;
|
|
||||||
|
|
||||||
size_t pos = str.find(']');
|
|
||||||
std::string str_port("0");
|
|
||||||
if (pos != std::string::npos) {
|
|
||||||
str_port = std::move(std::string(str.begin() + pos + 2, str.end()));
|
|
||||||
} else if (sep_count == 8) {
|
|
||||||
str_port = std::move(std::string(str.begin() + sep_pos + 1, str.end()));
|
|
||||||
}
|
|
||||||
|
|
||||||
try {
|
|
||||||
int port = std::stoi(str_port);
|
|
||||||
if (port >= 0 && port <= 65535) {
|
|
||||||
pAddr->SetIPv6(maddr->sin6_addr.s6_addr, port);
|
|
||||||
valid = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(...) { }
|
|
||||||
}
|
|
||||||
|
|
||||||
if (info) {
|
|
||||||
freeaddrinfo(info);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!valid) {
|
|
||||||
pAddr->Clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
ESteamNetworkingFakeIPType SteamNetworkingIPAddr_GetFakeIPType( const SteamNetworkingIPAddr &addr )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ESteamNetworkingFakeIPType_NotFake;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (buf == nullptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
std::string str;
|
|
||||||
str.reserve(SteamNetworkingIdentity::k_cchMaxString);
|
|
||||||
switch (identity.m_eType)
|
|
||||||
{
|
|
||||||
case k_ESteamNetworkingIdentityType_SteamID:
|
|
||||||
{
|
|
||||||
str = "steamid:";
|
|
||||||
str += std::move(std::to_string(identity.GetSteamID64()));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case k_ESteamNetworkingIdentityType_IPAddress:
|
|
||||||
{
|
|
||||||
str = "ip:";
|
|
||||||
char buff[SteamNetworkingIPAddr::k_cchMaxString];
|
|
||||||
auto& addr = *identity.GetIPAddr();
|
|
||||||
SteamNetworkingIPAddr_ToString(addr, buff, sizeof(buff), true);
|
|
||||||
str += buff;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case k_ESteamNetworkingIdentityType_GenericBytes:
|
|
||||||
{
|
|
||||||
int generic_len;
|
|
||||||
const uint8* pBuf = identity.GetGenericBytes(generic_len);
|
|
||||||
|
|
||||||
str = "gen:";
|
|
||||||
str.resize(4 + (generic_len * 2));
|
|
||||||
|
|
||||||
char* pDest = &str[4];
|
|
||||||
while(generic_len--)
|
|
||||||
{
|
|
||||||
// I don't care for the last char, I've reserved the max string size
|
|
||||||
snprintf(pDest, 3, "%02x", *pBuf);
|
|
||||||
++pBuf;
|
|
||||||
pDest += 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case k_ESteamNetworkingIdentityType_GenericString:
|
|
||||||
{
|
|
||||||
str = "str:";
|
|
||||||
str += identity.GetGenericString();
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case k_ESteamNetworkingIdentityType_UnknownType:
|
|
||||||
{
|
|
||||||
str = identity.m_szUnknownRawString;
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
cbBuf = std::min<size_t>(cbBuf, str.length() + 1);
|
|
||||||
strncpy(buf, str.c_str(), cbBuf);
|
|
||||||
buf[cbBuf - 1] = '\0';
|
|
||||||
}
|
|
||||||
|
|
||||||
bool SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, const char *pszStr )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
bool valid = false;
|
|
||||||
if (pIdentity == nullptr)
|
|
||||||
{
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pszStr != nullptr)
|
|
||||||
{
|
|
||||||
const char* end = strchr(pszStr, ':');
|
|
||||||
if (end != nullptr)
|
|
||||||
{
|
|
||||||
++end;
|
|
||||||
if (strncmp(pszStr, "gen:", end - pszStr) == 0)
|
|
||||||
{
|
|
||||||
size_t length = strlen(end);
|
|
||||||
if (!(length % 2) && length <= (sizeof(pIdentity->m_genericBytes) * 2))
|
|
||||||
{// Must be even
|
|
||||||
valid = true;
|
|
||||||
length /= 2;
|
|
||||||
pIdentity->m_eType = k_ESteamNetworkingIdentityType_GenericBytes;
|
|
||||||
pIdentity->m_cbSize = length;
|
|
||||||
uint8* pBytes = pIdentity->m_genericBytes;
|
|
||||||
|
|
||||||
char hex[3] = { 0,0,0 };
|
|
||||||
while (length)
|
|
||||||
{
|
|
||||||
hex[0] = end[0];
|
|
||||||
hex[1] = end[1];
|
|
||||||
// Steam doesn't check if wasn't a hex char
|
|
||||||
*pBytes = strtol(hex, nullptr, 16);
|
|
||||||
|
|
||||||
++pBytes;
|
|
||||||
end += 2;
|
|
||||||
--length;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strncmp(pszStr, "steamid:", end - pszStr) == 0)
|
|
||||||
{
|
|
||||||
CSteamID steam_id(uint64(strtoull(end, nullptr, 10)));
|
|
||||||
if (steam_id.IsValid())
|
|
||||||
{
|
|
||||||
valid = true;
|
|
||||||
pIdentity->SetSteamID(steam_id);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else if (strncmp(pszStr, "str:", end - pszStr) == 0)
|
|
||||||
{
|
|
||||||
valid = pIdentity->SetGenericString(end);
|
|
||||||
}
|
|
||||||
else if (strncmp(pszStr, "ip:", end - pszStr) == 0)
|
|
||||||
{
|
|
||||||
SteamNetworkingIPAddr steam_addr;
|
|
||||||
if (SteamNetworkingIPAddr_ParseString(&steam_addr, end))
|
|
||||||
{
|
|
||||||
valid = true;
|
|
||||||
pIdentity->SetIPAddr(steam_addr);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return valid;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
if (init_relay && !relay_initialized) {
|
|
||||||
relay_initialized = true;
|
|
||||||
SteamRelayNetworkStatus_t data = get_network_status();
|
|
||||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_sockets()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Optionally you can also request that this system allocate space to
|
||||||
|
/// hold the payload itself. If cbAllocateBuffer is nonzero, the system
|
||||||
|
/// will allocate memory to hold a payload of at least cbAllocateBuffer bytes.
|
||||||
|
/// m_pData will point to the allocated buffer, m_cbSize will be set to the
|
||||||
|
/// size, and m_pfnFreeData will be set to the proper function to free up
|
||||||
|
/// the buffer.
|
||||||
|
///
|
||||||
|
/// If cbAllocateBuffer=0, then no buffer is allocated. m_pData will be NULL,
|
||||||
|
/// m_cbSize will be zero, and m_pfnFreeData will be NULL. You will need to
|
||||||
|
/// set each of these.
|
||||||
|
///
|
||||||
|
/// You can use SteamNetworkingMessage_t::Release to free up the message
|
||||||
|
/// bookkeeping object and any associated buffer. See
|
||||||
|
/// ISteamNetworkingSockets::SendMessages for details on reference
|
||||||
|
/// counting and ownership.
|
||||||
|
SteamNetworkingMessage_t *AllocateMessage( int cbAllocateBuffer );
|
||||||
|
|
||||||
|
bool InitializeRelayAccess();
|
||||||
|
|
||||||
|
SteamRelayNetworkStatus_t get_network_status();
|
||||||
|
|
||||||
|
/// Fetch current status of the relay network.
|
||||||
|
///
|
||||||
|
/// SteamRelayNetworkStatus_t is also a callback. It will be triggered on
|
||||||
|
/// both the user and gameserver interfaces any time the status changes, or
|
||||||
|
/// ping measurement starts or stops.
|
||||||
|
///
|
||||||
|
/// SteamRelayNetworkStatus_t::m_eAvail is returned. If you want
|
||||||
|
/// more details, you can pass a non-NULL value.
|
||||||
|
ESteamNetworkingAvailability GetRelayNetworkStatus( SteamRelayNetworkStatus_t *pDetails );
|
||||||
|
|
||||||
|
float GetLocalPingLocation( SteamNetworkPingLocation_t &result );
|
||||||
|
|
||||||
|
int EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 );
|
||||||
|
|
||||||
|
|
||||||
|
int EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation );
|
||||||
|
|
||||||
|
|
||||||
|
void ConvertPingLocationToString( const SteamNetworkPingLocation_t &location, char *pszBuf, int cchBufSize );
|
||||||
|
|
||||||
|
|
||||||
|
bool ParsePingLocationString( const char *pszString, SteamNetworkPingLocation_t &result );
|
||||||
|
|
||||||
|
|
||||||
|
bool CheckPingDataUpToDate( float flMaxAgeSeconds );
|
||||||
|
|
||||||
|
|
||||||
|
bool IsPingMeasurementInProgress();
|
||||||
|
|
||||||
|
|
||||||
|
int GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP );
|
||||||
|
|
||||||
|
|
||||||
|
int GetDirectPingToPOP( SteamNetworkingPOPID popID );
|
||||||
|
|
||||||
|
|
||||||
|
int GetPOPCount();
|
||||||
|
|
||||||
|
|
||||||
|
int GetPOPList( SteamNetworkingPOPID *list, int nListSz );
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Misc
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Fetch current timestamp. This timer has the following properties:
|
||||||
|
///
|
||||||
|
/// - Monotonicity is guaranteed.
|
||||||
|
/// - The initial value will be at least 24*3600*30*1e6, i.e. about
|
||||||
|
/// 30 days worth of microseconds. In this way, the timestamp value of
|
||||||
|
/// 0 will always be at least "30 days ago". Also, negative numbers
|
||||||
|
/// will never be returned.
|
||||||
|
/// - Wraparound / overflow is not a practical concern.
|
||||||
|
///
|
||||||
|
/// If you are running under the debugger and stop the process, the clock
|
||||||
|
/// might not advance the full wall clock time that has elapsed between
|
||||||
|
/// calls. If the process is not blocked from normal operation, the
|
||||||
|
/// timestamp values will track wall clock time, even if you don't call
|
||||||
|
/// the function frequently.
|
||||||
|
///
|
||||||
|
/// The value is only meaningful for this run of the process. Don't compare
|
||||||
|
/// it to values obtained on another computer, or other runs of the same process.
|
||||||
|
SteamNetworkingMicroseconds GetLocalTimestamp();
|
||||||
|
|
||||||
|
|
||||||
|
/// Set a function to receive network-related information that is useful for debugging.
|
||||||
|
/// This can be very useful during development, but it can also be useful for troubleshooting
|
||||||
|
/// problems with tech savvy end users. If you have a console or other log that customers
|
||||||
|
/// can examine, these log messages can often be helpful to troubleshoot network issues.
|
||||||
|
/// (Especially any warning/error messages.)
|
||||||
|
///
|
||||||
|
/// The detail level indicates what message to invoke your callback on. Lower numeric
|
||||||
|
/// value means more important, and the value you pass is the lowest priority (highest
|
||||||
|
/// numeric value) you wish to receive callbacks for.
|
||||||
|
///
|
||||||
|
/// Except when debugging, you should only use k_ESteamNetworkingSocketsDebugOutputType_Msg
|
||||||
|
/// or k_ESteamNetworkingSocketsDebugOutputType_Warning. For best performance, do NOT
|
||||||
|
/// request a high detail level and then filter out messages in your callback. Instead,
|
||||||
|
/// call function function to adjust the desired level of detail.
|
||||||
|
///
|
||||||
|
/// IMPORTANT: This may be called from a service thread, while we own a mutex, etc.
|
||||||
|
/// Your output function must be threadsafe and fast! Do not make any other
|
||||||
|
/// Steamworks calls from within the handler.
|
||||||
|
void SetDebugOutputFunction( ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc );
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fake IP
|
||||||
|
//
|
||||||
|
// Useful for interfacing with code that assumes peers are identified using an IPv4 address
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Return true if an IPv4 address is one that might be used as a "fake" one.
|
||||||
|
/// This function is fast; it just does some logical tests on the IP and does
|
||||||
|
/// not need to do any lookup operations.
|
||||||
|
// inline bool IsFakeIPv4( uint32 nIPv4 ) { return GetIPv4FakeIPType( nIPv4 ) > k_ESteamNetworkingFakeIPType_NotFake; }
|
||||||
|
ESteamNetworkingFakeIPType GetIPv4FakeIPType( uint32 nIPv4 );
|
||||||
|
|
||||||
|
/// Get the real identity associated with a given FakeIP.
|
||||||
|
///
|
||||||
|
/// On failure, returns:
|
||||||
|
/// - k_EResultInvalidParam: the IP is not a FakeIP.
|
||||||
|
/// - k_EResultNoMatch: we don't recognize that FakeIP and don't know the corresponding identity.
|
||||||
|
///
|
||||||
|
/// FakeIP's used by active connections, or the FakeIPs assigned to local identities,
|
||||||
|
/// will always work. FakeIPs for recently destroyed connections will continue to
|
||||||
|
/// return results for a little while, but not forever. At some point, we will forget
|
||||||
|
/// FakeIPs to save space. It's reasonably safe to assume that you can read back the
|
||||||
|
/// real identity of a connection very soon after it is destroyed. But do not wait
|
||||||
|
/// indefinitely.
|
||||||
|
EResult GetRealIdentityForFakeIP( const SteamNetworkingIPAddr &fakeIP, SteamNetworkingIdentity *pOutRealIdentity );
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set and get configuration values, see ESteamNetworkingConfigValue for individual descriptions.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Shortcuts for common cases. (Implemented as inline functions below)
|
||||||
|
/*
|
||||||
|
bool SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val );
|
||||||
|
bool SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val );
|
||||||
|
bool SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val );
|
||||||
|
bool SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val );
|
||||||
|
bool SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val );
|
||||||
|
bool SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val );
|
||||||
|
*/
|
||||||
|
/// Set a configuration value.
|
||||||
|
/// - eValue: which value is being set
|
||||||
|
/// - eScope: Onto what type of object are you applying the setting?
|
||||||
|
/// - scopeArg: Which object you want to change? (Ignored for global scope). E.g. connection handle, listen socket handle, interface pointer, etc.
|
||||||
|
/// - eDataType: What type of data is in the buffer at pValue? This must match the type of the variable exactly!
|
||||||
|
/// - pArg: Value to set it to. You can pass NULL to remove a non-global sett at this scope,
|
||||||
|
/// causing the value for that object to use global defaults. Or at global scope, passing NULL
|
||||||
|
/// will reset any custom value and restore it to the system default.
|
||||||
|
/// NOTE: When setting callback functions, do not pass the function pointer directly.
|
||||||
|
/// Your argument should be a pointer to a function pointer.
|
||||||
|
bool SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
||||||
|
ESteamNetworkingConfigDataType eDataType, const void *pArg );
|
||||||
|
|
||||||
|
|
||||||
|
/// Get a configuration value.
|
||||||
|
/// - eValue: which value to fetch
|
||||||
|
/// - eScopeType: query setting on what type of object
|
||||||
|
/// - eScopeArg: the object to query the setting for
|
||||||
|
/// - pOutDataType: If non-NULL, the data type of the value is returned.
|
||||||
|
/// - pResult: Where to put the result. Pass NULL to query the required buffer size. (k_ESteamNetworkingGetConfigValue_BufferTooSmall will be returned.)
|
||||||
|
/// - cbResult: IN: the size of your buffer. OUT: the number of bytes filled in or required.
|
||||||
|
ESteamNetworkingGetConfigValueResult GetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
||||||
|
ESteamNetworkingConfigDataType *pOutDataType, void *pResult, size_t *cbResult );
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns info about a configuration value. Returns false if the value does not exist.
|
||||||
|
/// pOutNextValue can be used to iterate through all of the known configuration values.
|
||||||
|
/// (Use GetFirstConfigValue() to begin the iteration, will be k_ESteamNetworkingConfig_Invalid on the last value)
|
||||||
|
/// Any of the output parameters can be NULL if you do not need that information.
|
||||||
|
bool GetConfigValueInfo( ESteamNetworkingConfigValue eValue, const char **pOutName, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope, ESteamNetworkingConfigValue *pOutNextValue );
|
||||||
|
|
||||||
|
/// Get info about a configuration value. Returns the name of the value,
|
||||||
|
/// or NULL if the value doesn't exist. Other output parameters can be NULL
|
||||||
|
/// if you do not need them.
|
||||||
|
const char *GetConfigValueInfo( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope );
|
||||||
|
|
||||||
|
/// Return the lowest numbered configuration value available in the current environment.
|
||||||
|
ESteamNetworkingConfigValue GetFirstConfigValue();
|
||||||
|
|
||||||
|
/// Iterate the list of all configuration values in the current environment that it might
|
||||||
|
/// be possible to display or edit using a generic UI. To get the first iterable value,
|
||||||
|
/// pass k_ESteamNetworkingConfig_Invalid. Returns k_ESteamNetworkingConfig_Invalid
|
||||||
|
/// to signal end of list.
|
||||||
|
///
|
||||||
|
/// The bEnumerateDevVars argument can be used to include "dev" vars. These are vars that
|
||||||
|
/// are recommended to only be editable in "debug" or "dev" mode and typically should not be
|
||||||
|
/// shown in a retail environment where a malicious local user might use this to cheat.
|
||||||
|
ESteamNetworkingConfigValue IterateGenericEditableConfigValues( ESteamNetworkingConfigValue eCurrent, bool bEnumerateDevVars );
|
||||||
|
|
||||||
|
|
||||||
|
// String conversions. You'll usually access these using the respective
|
||||||
|
// inline methods.
|
||||||
|
void SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr &addr, char *buf, size_t cbBuf, bool bWithPort );
|
||||||
|
|
||||||
|
bool SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr );
|
||||||
|
|
||||||
|
ESteamNetworkingFakeIPType SteamNetworkingIPAddr_GetFakeIPType( const SteamNetworkingIPAddr &addr );
|
||||||
|
|
||||||
|
|
||||||
|
void SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf );
|
||||||
|
|
||||||
|
bool SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, const char *pszStr );
|
||||||
|
|
||||||
|
|
||||||
|
void RunCallbacks();
|
||||||
|
|
||||||
|
void Callback(Common_Message *msg);
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_NETWORKING_UTILS_H__
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_PARENTAL_H__
|
||||||
|
#define __INCLUDED_STEAM_PARENTAL_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Parental : public ISteamParentalSettings
|
class Steam_Parental :
|
||||||
|
public ISteamParentalSettings
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
bool BIsParentalLockEnabled();
|
bool BIsParentalLockEnabled();
|
||||||
@ -29,3 +33,5 @@ public:
|
|||||||
bool BIsFeatureBlocked( EParentalFeature eFeature );
|
bool BIsFeatureBlocked( EParentalFeature eFeature );
|
||||||
bool BIsFeatureInBlockList( EParentalFeature eFeature );
|
bool BIsFeatureInBlockList( EParentalFeature eFeature );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_PARENTAL_H__
|
||||||
|
@ -15,192 +15,95 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_PARTIES_H__
|
||||||
|
#define __INCLUDED_STEAM_PARTIES_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Parties :
|
class Steam_Parties :
|
||||||
public ISteamParties
|
public ISteamParties
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
||||||
FSteamNetworkingSocketsDebugOutput debug_function;
|
FSteamNetworkingSocketsDebugOutput debug_function{};
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Parties(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Parties();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Parties *steam_parties = (Steam_Parties *)object;
|
|
||||||
steam_parties->Callback(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
|
||||||
{
|
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Parties *steam_parties = (Steam_Parties *)object;
|
|
||||||
steam_parties->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_Parties(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
//this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Parties::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_Parties::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Parties()
|
|
||||||
{
|
|
||||||
//this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Parties::steam_callback, this);
|
|
||||||
this->run_every_runcb->remove(&Steam_Parties::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
// Party Client APIs
|
// Party Client APIs
|
||||||
|
|
||||||
// Enumerate any active beacons for parties you may wish to join
|
// Enumerate any active beacons for parties you may wish to join
|
||||||
uint32 GetNumActiveBeacons()
|
uint32 GetNumActiveBeacons();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
PartyBeaconID_t GetBeaconByIndex( uint32 unIndex )
|
PartyBeaconID_t GetBeaconByIndex( uint32 unIndex );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ulPartyBeaconIdInvalid;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetBeaconDetails( PartyBeaconID_t ulBeaconID, CSteamID *pSteamIDBeaconOwner, STEAM_OUT_STRUCT() SteamPartyBeaconLocation_t *pLocation, STEAM_OUT_STRING_COUNT(cchMetadata) char *pchMetadata, int cchMetadata )
|
bool GetBeaconDetails( PartyBeaconID_t ulBeaconID, CSteamID *pSteamIDBeaconOwner, STEAM_OUT_STRUCT() SteamPartyBeaconLocation_t *pLocation, STEAM_OUT_STRING_COUNT(cchMetadata) char *pchMetadata, int cchMetadata );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Join an open party. Steam will reserve one beacon slot for your SteamID,
|
// Join an open party. Steam will reserve one beacon slot for your SteamID,
|
||||||
// and return the necessary JoinGame string for you to use to connect
|
// and return the necessary JoinGame string for you to use to connect
|
||||||
STEAM_CALL_RESULT( JoinPartyCallback_t )
|
STEAM_CALL_RESULT( JoinPartyCallback_t )
|
||||||
SteamAPICall_t JoinParty( PartyBeaconID_t ulBeaconID )
|
SteamAPICall_t JoinParty( PartyBeaconID_t ulBeaconID );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// =============================================================================================
|
// =============================================================================================
|
||||||
// Party Host APIs
|
// Party Host APIs
|
||||||
|
|
||||||
// Get a list of possible beacon locations
|
// Get a list of possible beacon locations
|
||||||
bool GetNumAvailableBeaconLocations( uint32 *puNumLocations )
|
bool GetNumAvailableBeaconLocations( uint32 *puNumLocations );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool GetAvailableBeaconLocations( SteamPartyBeaconLocation_t *pLocationList, uint32 uMaxNumLocations )
|
bool GetAvailableBeaconLocations( SteamPartyBeaconLocation_t *pLocationList, uint32 uMaxNumLocations );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Create a new party beacon and activate it in the selected location.
|
// Create a new party beacon and activate it in the selected location.
|
||||||
// unOpenSlots is the maximum number of users that Steam will send to you.
|
// unOpenSlots is the maximum number of users that Steam will send to you.
|
||||||
// When people begin responding to your beacon, Steam will send you
|
// When people begin responding to your beacon, Steam will send you
|
||||||
// PartyReservationCallback_t callbacks to let you know who is on the way.
|
// PartyReservationCallback_t callbacks to let you know who is on the way.
|
||||||
STEAM_CALL_RESULT( CreateBeaconCallback_t )
|
STEAM_CALL_RESULT( CreateBeaconCallback_t )
|
||||||
SteamAPICall_t CreateBeacon( uint32 unOpenSlots, SteamPartyBeaconLocation_t *pBeaconLocation, const char *pchConnectString, const char *pchMetadata )
|
SteamAPICall_t CreateBeacon( uint32 unOpenSlots, SteamPartyBeaconLocation_t *pBeaconLocation, const char *pchConnectString, const char *pchMetadata );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Call this function when a user that had a reservation (see callback below)
|
// Call this function when a user that had a reservation (see callback below)
|
||||||
// has successfully joined your party.
|
// has successfully joined your party.
|
||||||
// Steam will manage the remaining open slots automatically.
|
// Steam will manage the remaining open slots automatically.
|
||||||
void OnReservationCompleted( PartyBeaconID_t ulBeacon, CSteamID steamIDUser )
|
void OnReservationCompleted( PartyBeaconID_t ulBeacon, CSteamID steamIDUser );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// To cancel a reservation (due to timeout or user input), call this.
|
// To cancel a reservation (due to timeout or user input), call this.
|
||||||
// Steam will open a new reservation slot.
|
// Steam will open a new reservation slot.
|
||||||
// Note: The user may already be in-flight to your game, so it's possible they will still connect and try to join your party.
|
// Note: The user may already be in-flight to your game, so it's possible they will still connect and try to join your party.
|
||||||
void CancelReservation( PartyBeaconID_t ulBeacon, CSteamID steamIDUser )
|
void CancelReservation( PartyBeaconID_t ulBeacon, CSteamID steamIDUser );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Change the number of open beacon reservation slots.
|
// Change the number of open beacon reservation slots.
|
||||||
// Call this if, for example, someone without a reservation joins your party (eg a friend, or via your own matchmaking system).
|
// Call this if, for example, someone without a reservation joins your party (eg a friend, or via your own matchmaking system).
|
||||||
STEAM_CALL_RESULT( ChangeNumOpenSlotsCallback_t )
|
STEAM_CALL_RESULT( ChangeNumOpenSlotsCallback_t )
|
||||||
SteamAPICall_t ChangeNumOpenSlots( PartyBeaconID_t ulBeacon, uint32 unOpenSlots )
|
SteamAPICall_t ChangeNumOpenSlots( PartyBeaconID_t ulBeacon, uint32 unOpenSlots );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Turn off the beacon.
|
// Turn off the beacon.
|
||||||
bool DestroyBeacon( PartyBeaconID_t ulBeacon )
|
bool DestroyBeacon( PartyBeaconID_t ulBeacon );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Utils
|
// Utils
|
||||||
bool GetBeaconLocationData( SteamPartyBeaconLocation_t BeaconLocation, ESteamPartyBeaconLocationData eData, STEAM_OUT_STRING_COUNT(cchDataStringOut) char *pchDataStringOut, int cchDataStringOut )
|
bool GetBeaconLocationData( SteamPartyBeaconLocation_t BeaconLocation, ESteamPartyBeaconLocationData eData, STEAM_OUT_STRING_COUNT(cchDataStringOut) char *pchDataStringOut, int cchDataStringOut );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RunCallbacks()
|
void RunCallbacks();
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
void Callback(Common_Message *msg);
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_sockets()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_PARTIES_H__
|
||||||
|
File diff suppressed because it is too large
Load Diff
@ -15,140 +15,58 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_REMOTEPLAY_H__
|
||||||
|
#define __INCLUDED_STEAM_REMOTEPLAY_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_RemotePlay :
|
class Steam_RemotePlay :
|
||||||
public ISteamRemotePlay001,
|
public ISteamRemotePlay001,
|
||||||
public ISteamRemotePlay
|
public ISteamRemotePlay
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_RemotePlay(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_RemotePlay();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_RemotePlay *steam_remoteplay = (Steam_RemotePlay *)object;
|
// Get the number of currently connected Steam Remote Play sessions
|
||||||
steam_remoteplay->Callback(msg);
|
uint32 GetSessionCount();
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
// Get the currently connected Steam Remote Play session ID at the specified index. Returns zero if index is out of bounds.
|
||||||
{
|
uint32 GetSessionID( int iSessionIndex );
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_RemotePlay *steam_remoteplay = (Steam_RemotePlay *)object;
|
// Get the SteamID of the connected user
|
||||||
steam_remoteplay->RunCallbacks();
|
CSteamID GetSessionSteamID( uint32 unSessionID );
|
||||||
}
|
|
||||||
|
|
||||||
Steam_RemotePlay(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
// Get the name of the session client device
|
||||||
{
|
// This returns NULL if the sessionID is not valid
|
||||||
this->settings = settings;
|
const char *GetSessionClientName( uint32 unSessionID );
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
//this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_RemotePlay::steam_callback, this);
|
|
||||||
this->run_every_runcb->add(&Steam_RemotePlay::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
// Get the form factor of the session client device
|
||||||
this->callbacks = callbacks;
|
ESteamDeviceFormFactor GetSessionClientFormFactor( uint32 unSessionID );
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_RemotePlay()
|
// Get the resolution, in pixels, of the session client device
|
||||||
{
|
// This is set to 0x0 if the resolution is not available
|
||||||
//this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_RemotePlay::steam_callback, this);
|
bool BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY );
|
||||||
this->run_every_runcb->remove(&Steam_RemotePlay::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the number of currently connected Steam Remote Play sessions
|
bool BStartRemotePlayTogether( bool bShowOverlay );
|
||||||
uint32 GetSessionCount()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the currently connected Steam Remote Play session ID at the specified index. Returns zero if index is out of bounds.
|
// Invite a friend to Remote Play Together
|
||||||
uint32 GetSessionID( int iSessionIndex )
|
// This returns false if the invite can't be sent
|
||||||
{
|
bool BSendRemotePlayTogetherInvite( CSteamID steamIDFriend );
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the SteamID of the connected user
|
void RunCallbacks();
|
||||||
CSteamID GetSessionSteamID( uint32 unSessionID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_steamIDNil;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the name of the session client device
|
void Callback(Common_Message *msg);
|
||||||
// This returns NULL if the sessionID is not valid
|
|
||||||
const char *GetSessionClientName( uint32 unSessionID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the form factor of the session client device
|
|
||||||
ESteamDeviceFormFactor GetSessionClientFormFactor( uint32 unSessionID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return k_ESteamDeviceFormFactorUnknown;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get the resolution, in pixels, of the session client device
|
|
||||||
// This is set to 0x0 if the resolution is not available
|
|
||||||
bool BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (pnResolutionX) *pnResolutionX = 0;
|
|
||||||
if (pnResolutionY) *pnResolutionY = 0;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BStartRemotePlayTogether( bool bShowOverlay )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invite a friend to Remote Play Together
|
|
||||||
// This returns false if the invite can't be sent
|
|
||||||
bool BSendRemotePlayTogetherInvite( CSteamID steamIDFriend )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_sockets()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_REMOTEPLAY_H__
|
||||||
|
@ -15,21 +15,24 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_SCRNSHOTS_H__
|
||||||
|
#define __INCLUDED_STEAM_SCRNSHOTS_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
struct screenshot_infos_t
|
struct screenshot_infos_t {
|
||||||
{
|
std::string screenshot_name{};
|
||||||
std::string screenshot_name;
|
nlohmann::json metadatas{};
|
||||||
nlohmann::json metadatas;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Steam_Screenshots : public ISteamScreenshots
|
class Steam_Screenshots :
|
||||||
|
public ISteamScreenshots
|
||||||
{
|
{
|
||||||
bool hooked = false;
|
class Local_Storage *local_storage{};
|
||||||
std::map<ScreenshotHandle, screenshot_infos_t> _screenshots;
|
class SteamCallBacks *callbacks{};
|
||||||
|
|
||||||
class Local_Storage* local_storage;
|
bool hooked = false;
|
||||||
class SteamCallBacks* callbacks;
|
std::map<ScreenshotHandle, screenshot_infos_t> _screenshots{};
|
||||||
|
|
||||||
ScreenshotHandle create_screenshot_handle();
|
ScreenshotHandle create_screenshot_handle();
|
||||||
|
|
||||||
@ -73,3 +76,5 @@ public:
|
|||||||
// JPEG, TGA, and PNG formats are supported.
|
// JPEG, TGA, and PNG formats are supported.
|
||||||
ScreenshotHandle AddVRScreenshotToLibrary( EVRScreenshotType eType, const char *pchFilename, const char *pchVRFilename );
|
ScreenshotHandle AddVRScreenshotToLibrary( EVRScreenshotType eType, const char *pchFilename, const char *pchVRFilename );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif //__INCLUDED_STEAM_SCRNSHOTS_H__
|
||||||
|
@ -15,117 +15,47 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_TV_H__
|
||||||
|
#define __INCLUDED_STEAM_TV_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_TV :
|
class Steam_TV :
|
||||||
public ISteamTV
|
public ISteamTV
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
std::chrono::time_point<std::chrono::steady_clock> initialized_time = std::chrono::steady_clock::now();
|
||||||
FSteamNetworkingSocketsDebugOutput debug_function;
|
FSteamNetworkingSocketsDebugOutput debug_function{};
|
||||||
|
|
||||||
|
static void steam_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_run_every_runcb(void *object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_TV(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_TV();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_TV *steam_parties = (Steam_TV *)object;
|
bool IsBroadcasting(int *pnNumViewers);
|
||||||
steam_parties->Callback(msg);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
void AddBroadcastGameData(const char * pchKey, const char * pchValue);
|
||||||
{
|
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_TV *steam_parties = (Steam_TV *)object;
|
void RemoveBroadcastGameData(const char * pchKey);
|
||||||
steam_parties->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_TV(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
void AddTimelineMarker(const char * pchTemplateName, bool bPersistent, uint8 nColorR, uint8 nColorG, uint8 nColorB);
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
//this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_TV::steam_callback, this);
|
|
||||||
// this->run_every_runcb->add(&Steam_TV::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
void RemoveTimelineMarker();
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_TV()
|
uint32 AddRegion(const char * pchElementName, const char * pchTimelineDataSection, const SteamTVRegion_t * pSteamTVRegion, ESteamTVRegionBehavior eSteamTVRegionBehavior);
|
||||||
{
|
|
||||||
//this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_TV::steam_callback, this);
|
|
||||||
//this->run_every_runcb->remove(&Steam_TV::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool IsBroadcasting(int *pnNumViewers)
|
void RemoveRegion(uint32 unRegionHandle);
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddBroadcastGameData(const char * pchKey, const char * pchValue)
|
void RunCallbacks();
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveBroadcastGameData(const char * pchKey)
|
void Callback(Common_Message *msg);
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void AddTimelineMarker(const char * pchTemplateName, bool bPersistent, uint8 nColorR, uint8 nColorG, uint8 nColorB)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveTimelineMarker()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
uint32 AddRegion(const char * pchElementName, const char * pchTimelineDataSection, const SteamTVRegion_t * pSteamTVRegion, ESteamTVRegionBehavior eSteamTVRegionBehavior)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void RemoveRegion(uint32 unRegionHandle)
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
}
|
|
||||||
|
|
||||||
void RunCallbacks()
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->has_networking_sockets()) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_TV_H__
|
||||||
|
1475
dll/dll/steam_ugc.h
1475
dll/dll/steam_ugc.h
File diff suppressed because it is too large
Load Diff
@ -15,114 +15,53 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_UNIFIED_MESSAGES_H__
|
||||||
|
#define __INCLUDED_STEAM_UNIFIED_MESSAGES_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Unified_Messages :
|
class Steam_Unified_Messages:
|
||||||
public ISteamUnifiedMessages
|
public ISteamUnifiedMessages
|
||||||
{
|
{
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class RunEveryRunCB *run_every_runcb;
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
|
|
||||||
|
static void network_callback(void *object, Common_Message *msg);
|
||||||
|
static void steam_runcb(void *object);
|
||||||
|
|
||||||
public:
|
public:
|
||||||
static void steam_callback(void *object, Common_Message *msg)
|
Steam_Unified_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb);
|
||||||
{
|
~Steam_Unified_Messages();
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Unified_Messages *steam_steamunifiedmessages = (Steam_Unified_Messages *)object;
|
// Sends a service method (in binary serialized form) using the Steam Client.
|
||||||
steam_steamunifiedmessages->Callback(msg);
|
// Returns a unified message handle (k_InvalidUnifiedMessageHandle if could not send the message).
|
||||||
}
|
ClientUnifiedMessageHandle SendMethod( const char *pchServiceMethod, const void *pRequestBuffer, uint32 unRequestBufferSize, uint64 unContext );
|
||||||
|
|
||||||
static void steam_run_every_runcb(void *object)
|
|
||||||
{
|
|
||||||
// PRINT_DEBUG_ENTRY();
|
|
||||||
|
|
||||||
Steam_Unified_Messages *steam_steamunifiedmessages = (Steam_Unified_Messages *)object;
|
|
||||||
steam_steamunifiedmessages->RunCallbacks();
|
|
||||||
}
|
|
||||||
|
|
||||||
Steam_Unified_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
|
||||||
{
|
|
||||||
this->settings = settings;
|
|
||||||
this->network = network;
|
|
||||||
this->run_every_runcb = run_every_runcb;
|
|
||||||
// this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Unified_Messages::steam_callback, this);
|
|
||||||
// this->run_every_runcb->add(&Steam_Unified_Messages::steam_run_every_runcb, this);
|
|
||||||
|
|
||||||
this->callback_results = callback_results;
|
|
||||||
this->callbacks = callbacks;
|
|
||||||
}
|
|
||||||
|
|
||||||
~Steam_Unified_Messages()
|
|
||||||
{
|
|
||||||
// this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Unified_Messages::steam_callback, this);
|
|
||||||
// this->run_every_runcb->remove(&Steam_Unified_Messages::steam_run_every_runcb, this);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sends a service method (in binary serialized form) using the Steam Client.
|
|
||||||
// Returns a unified message handle (k_InvalidUnifiedMessageHandle if could not send the message).
|
|
||||||
ClientUnifiedMessageHandle SendMethod( const char *pchServiceMethod, const void *pRequestBuffer, uint32 unRequestBufferSize, uint64 unContext )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return ISteamUnifiedMessages::k_InvalidUnifiedMessageHandle;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Gets the size of the response and the EResult. Returns false if the response is not ready yet.
|
// Gets the size of the response and the EResult. Returns false if the response is not ready yet.
|
||||||
bool GetMethodResponseInfo( ClientUnifiedMessageHandle hHandle, uint32 *punResponseSize, EResult *peResult )
|
bool GetMethodResponseInfo( ClientUnifiedMessageHandle hHandle, uint32 *punResponseSize, EResult *peResult );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Gets a response in binary serialized form (and optionally release the corresponding allocated memory).
|
// Gets a response in binary serialized form (and optionally release the corresponding allocated memory).
|
||||||
bool GetMethodResponseData( ClientUnifiedMessageHandle hHandle, void *pResponseBuffer, uint32 unResponseBufferSize, bool bAutoRelease )
|
bool GetMethodResponseData( ClientUnifiedMessageHandle hHandle, void *pResponseBuffer, uint32 unResponseBufferSize, bool bAutoRelease );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Releases the message and its corresponding allocated memory.
|
// Releases the message and its corresponding allocated memory.
|
||||||
bool ReleaseMethod( ClientUnifiedMessageHandle hHandle )
|
bool ReleaseMethod( ClientUnifiedMessageHandle hHandle );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Sends a service notification (in binary serialized form) using the Steam Client.
|
// Sends a service notification (in binary serialized form) using the Steam Client.
|
||||||
// Returns true if the notification was sent successfully.
|
// Returns true if the notification was sent successfully.
|
||||||
bool SendNotification( const char *pchServiceNotification, const void *pNotificationBuffer, uint32 unNotificationBufferSize )
|
bool SendNotification( const char *pchServiceNotification, const void *pNotificationBuffer, uint32 unNotificationBufferSize );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void RunCallbacks()
|
void RunCallbacks();
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
void Callback(Common_Message *msg)
|
void Callback(Common_Message *msg);
|
||||||
{
|
|
||||||
if (msg->has_low_level()) {
|
|
||||||
if (msg->low_level().type() == Low_Level::CONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_UNIFIED_MESSAGES_H__
|
||||||
|
@ -15,9 +15,11 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_USER_H__
|
||||||
|
#define __INCLUDED_STEAM_USER_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
#include "auth.h"
|
#include "auth.h"
|
||||||
#include "appticket.h"
|
|
||||||
|
|
||||||
class Steam_User :
|
class Steam_User :
|
||||||
public ISteamUser009,
|
public ISteamUser009,
|
||||||
@ -35,524 +37,223 @@ public ISteamUser020,
|
|||||||
public ISteamUser021,
|
public ISteamUser021,
|
||||||
public ISteamUser
|
public ISteamUser
|
||||||
{
|
{
|
||||||
Settings *settings;
|
Settings *settings{};
|
||||||
class Networking *network;
|
class Networking *network{};
|
||||||
class SteamCallBacks *callbacks;
|
class SteamCallBacks *callbacks{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
Local_Storage *local_storage;
|
Local_Storage *local_storage{};
|
||||||
|
|
||||||
bool recording = false;
|
bool recording = false;
|
||||||
std::chrono::high_resolution_clock::time_point last_get_voice;
|
std::chrono::high_resolution_clock::time_point last_get_voice{};
|
||||||
std::string encrypted_app_ticket;
|
std::string encrypted_app_ticket{};
|
||||||
Auth_Manager *auth_manager;
|
Auth_Manager *auth_manager{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks);
|
||||||
Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
|
~Steam_User();
|
||||||
{
|
|
||||||
this->settings = settings;
|
// returns the HSteamUser this interface represents
|
||||||
this->local_storage = local_storage;
|
// this is only used internally by the API, and by a few select interfaces that support multi-user
|
||||||
this->network = network;
|
HSteamUser GetHSteamUser();
|
||||||
this->callbacks = callbacks;
|
|
||||||
this->callback_results = callback_results;
|
// returns true if the Steam client current has a live connection to the Steam servers.
|
||||||
recording = false;
|
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
|
||||||
auth_manager = new Auth_Manager(settings, network, callbacks);
|
// The Steam client will automatically be trying to recreate the connection as often as possible.
|
||||||
}
|
bool BLoggedOn();
|
||||||
|
|
||||||
~Steam_User()
|
// returns the CSteamID of the account currently logged into the Steam client
|
||||||
{
|
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
|
||||||
delete auth_manager;
|
CSteamID GetSteamID();
|
||||||
}
|
|
||||||
|
// Multiplayer Authentication functions
|
||||||
// returns the HSteamUser this interface represents
|
|
||||||
// this is only used internally by the API, and by a few select interfaces that support multi-user
|
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
|
||||||
HSteamUser GetHSteamUser()
|
// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
|
||||||
{
|
//
|
||||||
PRINT_DEBUG_ENTRY();
|
// Parameters:
|
||||||
return CLIENT_HSTEAMUSER;
|
// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
|
||||||
}
|
// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
|
||||||
|
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
|
||||||
// returns true if the Steam client current has a live connection to the Steam servers.
|
// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( <appID> )
|
||||||
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
|
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
|
||||||
// The Steam client will automatically be trying to recreate the connection as often as possible.
|
// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
|
||||||
bool BLoggedOn()
|
//
|
||||||
{
|
// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
|
||||||
PRINT_DEBUG_ENTRY();
|
// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
|
||||||
return !settings->is_offline();
|
|
||||||
}
|
int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure );
|
||||||
|
|
||||||
// returns the CSteamID of the account currently logged into the Steam client
|
int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure );
|
||||||
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
|
|
||||||
CSteamID GetSteamID()
|
// notify of disconnect
|
||||||
{
|
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
|
||||||
PRINT_DEBUG_ENTRY();
|
void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer );
|
||||||
CSteamID id = settings->get_local_steam_id();
|
|
||||||
|
// Legacy functions
|
||||||
return id;
|
|
||||||
}
|
// used by only a few games to track usage events
|
||||||
|
void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo);
|
||||||
// Multiplayer Authentication functions
|
|
||||||
|
void RefreshSteam2Login();
|
||||||
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
|
|
||||||
// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
|
// get the local storage folder for current Steam account to write application data, e.g. save games, configs etc.
|
||||||
//
|
// this will usually be something like "C:\Progam Files\Steam\userdata\<SteamID>\<AppID>\local"
|
||||||
// Parameters:
|
bool GetUserDataFolder( char *pchBuffer, int cubBuffer );
|
||||||
// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
|
|
||||||
// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
|
// Starts voice recording. Once started, use GetVoice() to get the data
|
||||||
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
|
void StartVoiceRecording( );
|
||||||
// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( <appID> )
|
|
||||||
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
|
// Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for
|
||||||
// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
|
// a little bit after this function is called. GetVoice() should continue to be called until it returns
|
||||||
//
|
// k_eVoiceResultNotRecording
|
||||||
// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
|
void StopVoiceRecording( );
|
||||||
// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
|
|
||||||
|
// Determine the size of captured audio data that is available from GetVoice.
|
||||||
//steam returns 206 bytes
|
// Most applications will only use compressed data and should ignore the other
|
||||||
#define INITIATE_GAME_CONNECTION_TICKET_SIZE 206
|
// parameters, which exist primarily for backwards compatibility. See comments
|
||||||
|
// below for further explanation of "uncompressed" data.
|
||||||
int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure )
|
EVoiceResult GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated );
|
||||||
{
|
|
||||||
PRINT_DEBUG("%i %llu %u %u %u %p", cbMaxAuthBlob, steamIDGameServer.ConvertToUint64(), unIPServer, usPortServer, bSecure, pAuthBlob);
|
EVoiceResult GetAvailableVoice(uint32 *pcbCompressed, uint32 *pcbUncompressed);
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
if (cbMaxAuthBlob < INITIATE_GAME_CONNECTION_TICKET_SIZE) return 0;
|
// ---------------------------------------------------------------------------
|
||||||
if (!pAuthBlob) return 0;
|
// NOTE: "uncompressed" audio is a deprecated feature and should not be used
|
||||||
uint32 out_size = INITIATE_GAME_CONNECTION_TICKET_SIZE;
|
// by most applications. It is raw single-channel 16-bit PCM wave data which
|
||||||
auth_manager->getTicketData(pAuthBlob, INITIATE_GAME_CONNECTION_TICKET_SIZE, &out_size);
|
// may have been run through preprocessing filters and/or had silence removed,
|
||||||
if (out_size > INITIATE_GAME_CONNECTION_TICKET_SIZE)
|
// so the uncompressed audio could have a shorter duration than you expect.
|
||||||
return 0;
|
// There may be no data at all during long periods of silence. Also, fetching
|
||||||
return out_size;
|
// uncompressed audio will cause GetVoice to discard any leftover compressed
|
||||||
}
|
// audio, so you must fetch both types at once. Finally, GetAvailableVoice is
|
||||||
|
// not precisely accurate when the uncompressed size is requested. So if you
|
||||||
int InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure )
|
// really need to use uncompressed audio, you should call GetVoice frequently
|
||||||
{
|
// with two very large (20kb+) output buffers instead of trying to allocate
|
||||||
PRINT_DEBUG_ENTRY();
|
// perfectly-sized buffers. But most applications should ignore all of these
|
||||||
return InitiateGameConnection(pAuthBlob, cbMaxAuthBlob, steamIDGameServer, unIPServer, usPortServer, bSecure);
|
// details and simply leave the "uncompressed" parameters as NULL/zero.
|
||||||
}
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
// notify of disconnect
|
// Read captured audio data from the microphone buffer. This should be called
|
||||||
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
|
// at least once per frame, and preferably every few milliseconds, to keep the
|
||||||
void TerminateGameConnection( uint32 unIPServer, uint16 usPortServer )
|
// microphone input delay as low as possible. Most applications will only use
|
||||||
{
|
// compressed data and should pass NULL/zero for the "uncompressed" parameters.
|
||||||
PRINT_DEBUG_TODO();
|
// Compressed data can be transmitted by your application and decoded into raw
|
||||||
}
|
// using the DecompressVoice function below.
|
||||||
|
EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed_Deprecated, void *pUncompressedDestBuffer_Deprecated , uint32 cbUncompressedDestBufferSize_Deprecated , uint32 *nUncompressBytesWritten_Deprecated , uint32 nUncompressedVoiceDesiredSampleRate_Deprecated );
|
||||||
// Legacy functions
|
|
||||||
|
EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed, void *pUncompressedDestBuffer, uint32 cbUncompressedDestBufferSize, uint32 *nUncompressBytesWritten );
|
||||||
// used by only a few games to track usage events
|
|
||||||
void TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo)
|
EVoiceResult GetCompressedVoice( void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten );
|
||||||
{
|
|
||||||
PRINT_DEBUG_TODO();
|
// Decodes the compressed voice data returned by GetVoice. The output data is
|
||||||
}
|
// raw single-channel 16-bit PCM audio. The decoder supports any sample rate
|
||||||
|
// from 11025 to 48000; see GetVoiceOptimalSampleRate() below for details.
|
||||||
void RefreshSteam2Login()
|
// If the output buffer is not large enough, then *nBytesWritten will be set
|
||||||
{
|
// to the required buffer size, and k_EVoiceResultBufferTooSmall is returned.
|
||||||
PRINT_DEBUG_TODO();
|
// It is suggested to start with a 20kb buffer and reallocate as necessary.
|
||||||
}
|
EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate );
|
||||||
|
|
||||||
// get the local storage folder for current Steam account to write application data, e.g. save games, configs etc.
|
EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten );
|
||||||
// this will usually be something like "C:\Progam Files\Steam\userdata\<SteamID>\<AppID>\local"
|
|
||||||
bool GetUserDataFolder( char *pchBuffer, int cubBuffer )
|
EVoiceResult DecompressVoice( void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten );
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
// This returns the native sample rate of the Steam voice decompressor
|
||||||
if (!cubBuffer) return false;
|
// this sample rate for DecompressVoice will perform the least CPU processing.
|
||||||
|
// However, the final audio quality will depend on how well the audio device
|
||||||
std::string user_data = local_storage->get_path(Local_Storage::user_data_storage);
|
// (and/or your application's audio output SDK) deals with lower sample rates.
|
||||||
strncpy(pchBuffer, user_data.c_str(), cubBuffer - 1);
|
// You may find that you get the best audio output quality when you ignore
|
||||||
pchBuffer[cubBuffer - 1] = 0;
|
// this function and use the native sample rate of your audio output device,
|
||||||
return true;
|
// which is usually 48000 or 44100.
|
||||||
}
|
uint32 GetVoiceOptimalSampleRate();
|
||||||
|
|
||||||
// Starts voice recording. Once started, use GetVoice() to get the data
|
// Retrieve ticket to be sent to the entity who wishes to authenticate you.
|
||||||
void StartVoiceRecording( )
|
// pcbTicket retrieves the length of the actual ticket.
|
||||||
{
|
HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
|
||||||
PRINT_DEBUG_ENTRY();
|
// SteamNetworkingIdentity is an optional input parameter to hold the public IP address or SteamID of the entity you are connecting to
|
||||||
last_get_voice = std::chrono::high_resolution_clock::now();
|
// if an IP address is passed Steam will only allow the ticket to be used by an entity with that IP address
|
||||||
recording = true;
|
// if a Steam ID is passed Steam will only allow the ticket to be used by that Steam ID
|
||||||
//TODO:fix
|
HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, const SteamNetworkingIdentity *pSteamNetworkingIdentity );
|
||||||
recording = false;
|
|
||||||
}
|
// Request a ticket which will be used for webapi "ISteamUserAuth\AuthenticateUserTicket"
|
||||||
|
// pchIdentity is an optional input parameter to identify the service the ticket will be sent to
|
||||||
// Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for
|
// the ticket will be returned in callback GetTicketForWebApiResponse_t
|
||||||
// a little bit after this function is called. GetVoice() should continue to be called until it returns
|
HAuthTicket GetAuthTicketForWebApi( const char *pchIdentity );
|
||||||
// k_eVoiceResultNotRecording
|
|
||||||
void StopVoiceRecording( )
|
// Authenticate ticket from entity steamID to be sure it is valid and isnt reused
|
||||||
{
|
// Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse )
|
||||||
PRINT_DEBUG_ENTRY();
|
EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID );
|
||||||
recording = false;
|
|
||||||
}
|
// Stop tracking started by BeginAuthSession - called when no longer playing game with this entity
|
||||||
|
void EndAuthSession( CSteamID steamID );
|
||||||
// Determine the size of captured audio data that is available from GetVoice.
|
|
||||||
// Most applications will only use compressed data and should ignore the other
|
// Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to
|
||||||
// parameters, which exist primarily for backwards compatibility. See comments
|
void CancelAuthTicket( HAuthTicket hAuthTicket );
|
||||||
// below for further explanation of "uncompressed" data.
|
|
||||||
EVoiceResult GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated )
|
// After receiving a user's authentication data, and passing it to BeginAuthSession, use this function
|
||||||
{
|
// to determine if the user owns downloadable content specified by the provided AppID.
|
||||||
PRINT_DEBUG_ENTRY();
|
EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID );
|
||||||
if (pcbCompressed) *pcbCompressed = 0;
|
|
||||||
if (pcbUncompressed_Deprecated) *pcbUncompressed_Deprecated = 0;
|
// returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam
|
||||||
if (!recording) return k_EVoiceResultNotRecording;
|
// (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT.
|
||||||
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
|
bool BIsBehindNAT();
|
||||||
if (pcbCompressed) *pcbCompressed = seconds * 1024.0 * 64.0 / 8.0;
|
|
||||||
if (pcbUncompressed_Deprecated) *pcbUncompressed_Deprecated = seconds * (double)nUncompressedVoiceDesiredSampleRate_Deprecated * 2.0;
|
// set data to be replicated to friends so that they can join your game
|
||||||
|
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
|
||||||
return k_EVoiceResultOK;
|
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
|
||||||
}
|
void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer );
|
||||||
|
|
||||||
EVoiceResult GetAvailableVoice(uint32 *pcbCompressed, uint32 *pcbUncompressed)
|
// Requests a ticket encrypted with an app specific shared key
|
||||||
{
|
// pDataToInclude, cbDataToInclude will be encrypted into the ticket
|
||||||
PRINT_DEBUG("old");
|
// ( This is asynchronous, you must wait for the ticket to be completed by the server )
|
||||||
return GetAvailableVoice(pcbCompressed, pcbUncompressed, 11025);
|
STEAM_CALL_RESULT( EncryptedAppTicketResponse_t )
|
||||||
}
|
SteamAPICall_t RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude );
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// retrieve a finished ticket
|
||||||
// NOTE: "uncompressed" audio is a deprecated feature and should not be used
|
bool GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket );
|
||||||
// by most applications. It is raw single-channel 16-bit PCM wave data which
|
|
||||||
// may have been run through preprocessing filters and/or had silence removed,
|
// Trading Card badges data access
|
||||||
// so the uncompressed audio could have a shorter duration than you expect.
|
// if you only have one set of cards, the series will be 1
|
||||||
// There may be no data at all during long periods of silence. Also, fetching
|
// the user has can have two different badges for a series; the regular (max level 5) and the foil (max level 1)
|
||||||
// uncompressed audio will cause GetVoice to discard any leftover compressed
|
int GetGameBadgeLevel( int nSeries, bool bFoil );
|
||||||
// audio, so you must fetch both types at once. Finally, GetAvailableVoice is
|
|
||||||
// not precisely accurate when the uncompressed size is requested. So if you
|
// gets the Steam Level of the user, as shown on their profile
|
||||||
// really need to use uncompressed audio, you should call GetVoice frequently
|
int GetPlayerSteamLevel();
|
||||||
// with two very large (20kb+) output buffers instead of trying to allocate
|
|
||||||
// perfectly-sized buffers. But most applications should ignore all of these
|
// Requests a URL which authenticates an in-game browser for store check-out,
|
||||||
// details and simply leave the "uncompressed" parameters as NULL/zero.
|
// and then redirects to the specified URL. As long as the in-game browser
|
||||||
// ---------------------------------------------------------------------------
|
// accepts and handles session cookies, Steam microtransaction checkout pages
|
||||||
|
// will automatically recognize the user instead of presenting a login page.
|
||||||
// Read captured audio data from the microphone buffer. This should be called
|
// The result of this API call will be a StoreAuthURLResponse_t callback.
|
||||||
// at least once per frame, and preferably every few milliseconds, to keep the
|
// NOTE: The URL has a very short lifetime to prevent history-snooping attacks,
|
||||||
// microphone input delay as low as possible. Most applications will only use
|
// so you should only call this API when you are about to launch the browser,
|
||||||
// compressed data and should pass NULL/zero for the "uncompressed" parameters.
|
// or else immediately navigate to the result URL using a hidden browser window.
|
||||||
// Compressed data can be transmitted by your application and decoded into raw
|
// NOTE 2: The resulting authorization cookie has an expiration time of one day,
|
||||||
// using the DecompressVoice function below.
|
// so it would be a good idea to request and visit a new auth URL every 12 hours.
|
||||||
EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed_Deprecated, void *pUncompressedDestBuffer_Deprecated , uint32 cbUncompressedDestBufferSize_Deprecated , uint32 *nUncompressBytesWritten_Deprecated , uint32 nUncompressedVoiceDesiredSampleRate_Deprecated )
|
STEAM_CALL_RESULT( StoreAuthURLResponse_t )
|
||||||
{
|
SteamAPICall_t RequestStoreAuthURL( const char *pchRedirectURL );
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
if (!recording) return k_EVoiceResultNotRecording;
|
// gets whether the users phone number is verified
|
||||||
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
|
bool BIsPhoneVerified();
|
||||||
if (bWantCompressed) {
|
|
||||||
uint32 towrite = seconds * 1024.0 * 64.0 / 8.0;
|
// gets whether the user has two factor enabled on their account
|
||||||
if (cbDestBufferSize < towrite) towrite = cbDestBufferSize;
|
bool BIsTwoFactorEnabled();
|
||||||
if (pDestBuffer) memset(pDestBuffer, 0, towrite);
|
|
||||||
if (nBytesWritten) *nBytesWritten = towrite;
|
// gets whether the users phone number is identifying
|
||||||
}
|
bool BIsPhoneIdentifying();
|
||||||
|
|
||||||
if (bWantUncompressed_Deprecated) {
|
// gets whether the users phone number is awaiting (re)verification
|
||||||
PRINT_DEBUG("Wanted Uncompressed");
|
bool BIsPhoneRequiringVerification();
|
||||||
}
|
|
||||||
|
STEAM_CALL_RESULT( MarketEligibilityResponse_t )
|
||||||
last_get_voice = std::chrono::high_resolution_clock::now();
|
SteamAPICall_t GetMarketEligibility();
|
||||||
return k_EVoiceResultOK;
|
|
||||||
}
|
// Retrieves anti indulgence / duration control for current user
|
||||||
|
STEAM_CALL_RESULT( DurationControl_t )
|
||||||
EVoiceResult GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed, void *pUncompressedDestBuffer, uint32 cbUncompressedDestBufferSize, uint32 *nUncompressBytesWritten )
|
SteamAPICall_t GetDurationControl();
|
||||||
{
|
|
||||||
PRINT_DEBUG("old");
|
// Advise steam china duration control system about the online state of the game.
|
||||||
return GetVoice(bWantCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, bWantUncompressed, pUncompressedDestBuffer, cbUncompressedDestBufferSize, nUncompressBytesWritten, 11025);
|
// This will prevent offline gameplay time from counting against a user's
|
||||||
}
|
// playtime limits.
|
||||||
|
bool BSetDurationControlOnlineState( EDurationControlOnlineState eNewState );
|
||||||
EVoiceResult GetCompressedVoice( void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return GetVoice(true, pDestBuffer, cbDestBufferSize, nBytesWritten, false, NULL, 0, NULL);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Decodes the compressed voice data returned by GetVoice. The output data is
|
|
||||||
// raw single-channel 16-bit PCM audio. The decoder supports any sample rate
|
|
||||||
// from 11025 to 48000; see GetVoiceOptimalSampleRate() below for details.
|
|
||||||
// If the output buffer is not large enough, then *nBytesWritten will be set
|
|
||||||
// to the required buffer size, and k_EVoiceResultBufferTooSmall is returned.
|
|
||||||
// It is suggested to start with a 20kb buffer and reallocate as necessary.
|
|
||||||
EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
if (!recording) return k_EVoiceResultNotRecording;
|
|
||||||
uint32 uncompressed = (double)cbCompressed * ((double)nDesiredSampleRate / 8192.0);
|
|
||||||
if(nBytesWritten) *nBytesWritten = uncompressed;
|
|
||||||
if (uncompressed > cbDestBufferSize) uncompressed = cbDestBufferSize;
|
|
||||||
if (pDestBuffer) memset(pDestBuffer, 0, uncompressed);
|
|
||||||
|
|
||||||
return k_EVoiceResultOK;
|
|
||||||
}
|
|
||||||
|
|
||||||
EVoiceResult DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("old");
|
|
||||||
return DecompressVoice(pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, 11025);
|
|
||||||
}
|
|
||||||
|
|
||||||
EVoiceResult DecompressVoice( void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("older");
|
|
||||||
return DecompressVoice(pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, 11025);
|
|
||||||
}
|
|
||||||
|
|
||||||
// This returns the native sample rate of the Steam voice decompressor
|
|
||||||
// this sample rate for DecompressVoice will perform the least CPU processing.
|
|
||||||
// However, the final audio quality will depend on how well the audio device
|
|
||||||
// (and/or your application's audio output SDK) deals with lower sample rates.
|
|
||||||
// You may find that you get the best audio output quality when you ignore
|
|
||||||
// this function and use the native sample rate of your audio output device,
|
|
||||||
// which is usually 48000 or 44100.
|
|
||||||
uint32 GetVoiceOptimalSampleRate()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return 48000;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieve ticket to be sent to the entity who wishes to authenticate you.
|
|
||||||
// pcbTicket retrieves the length of the actual ticket.
|
|
||||||
HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
|
||||||
{
|
|
||||||
return GetAuthSessionTicket(pTicket, cbMaxTicket, pcbTicket, NULL);
|
|
||||||
}
|
|
||||||
// SteamNetworkingIdentity is an optional input parameter to hold the public IP address or SteamID of the entity you are connecting to
|
|
||||||
// if an IP address is passed Steam will only allow the ticket to be used by an entity with that IP address
|
|
||||||
// if a Steam ID is passed Steam will only allow the ticket to be used by that Steam ID
|
|
||||||
HAuthTicket GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, const SteamNetworkingIdentity *pSteamNetworkingIdentity )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p [%i] %p", pTicket, cbMaxTicket, pcbTicket);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
if (!pTicket) return k_HAuthTicketInvalid;
|
|
||||||
|
|
||||||
return auth_manager->getTicket(pTicket, cbMaxTicket, pcbTicket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request a ticket which will be used for webapi "ISteamUserAuth\AuthenticateUserTicket"
|
|
||||||
// pchIdentity is an optional input parameter to identify the service the ticket will be sent to
|
|
||||||
// the ticket will be returned in callback GetTicketForWebApiResponse_t
|
|
||||||
HAuthTicket GetAuthTicketForWebApi( const char *pchIdentity )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%s", pchIdentity);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
return auth_manager->getWebApiTicket(pchIdentity);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Authenticate ticket from entity steamID to be sure it is valid and isnt reused
|
|
||||||
// Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse )
|
|
||||||
EBeginAuthSessionResult BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%i %llu", cbAuthTicket, steamID.ConvertToUint64());
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
return auth_manager->beginAuth(pAuthTicket, cbAuthTicket, steamID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Stop tracking started by BeginAuthSession - called when no longer playing game with this entity
|
|
||||||
void EndAuthSession( CSteamID steamID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
auth_manager->endAuth(steamID);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to
|
|
||||||
void CancelAuthTicket( HAuthTicket hAuthTicket )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
auth_manager->cancelTicket(hAuthTicket);
|
|
||||||
}
|
|
||||||
|
|
||||||
// After receiving a user's authentication data, and passing it to BeginAuthSession, use this function
|
|
||||||
// to determine if the user owns downloadable content specified by the provided AppID.
|
|
||||||
EUserHasLicenseForAppResult UserHasLicenseForApp( CSteamID steamID, AppId_t appID )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return k_EUserHasLicenseResultHasLicense;
|
|
||||||
}
|
|
||||||
|
|
||||||
// returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam
|
|
||||||
// (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT.
|
|
||||||
bool BIsBehindNAT()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// set data to be replicated to friends so that they can join your game
|
|
||||||
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
|
|
||||||
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
|
|
||||||
void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
Gameserver *server = new Gameserver();
|
|
||||||
server->set_id(steamIDGameServer.ConvertToUint64());
|
|
||||||
server->set_ip(unIPServer);
|
|
||||||
server->set_port(usPortServer);
|
|
||||||
server->set_query_port(usPortServer);
|
|
||||||
server->set_appid(settings->get_local_game_id().ToUint64());
|
|
||||||
|
|
||||||
if (settings->matchmaking_server_list_always_lan_type)
|
|
||||||
server->set_type(eLANServer);
|
|
||||||
else
|
|
||||||
server->set_type(eFriendsServer);
|
|
||||||
|
|
||||||
Common_Message msg;
|
|
||||||
msg.set_allocated_gameserver(server);
|
|
||||||
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
|
||||||
network->sendToAllIndividuals(&msg, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Requests a ticket encrypted with an app specific shared key
|
|
||||||
// pDataToInclude, cbDataToInclude will be encrypted into the ticket
|
|
||||||
// ( This is asynchronous, you must wait for the ticket to be completed by the server )
|
|
||||||
STEAM_CALL_RESULT( EncryptedAppTicketResponse_t )
|
|
||||||
SteamAPICall_t RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%i", cbDataToInclude);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
EncryptedAppTicketResponse_t data;
|
|
||||||
data.m_eResult = k_EResultOK;
|
|
||||||
|
|
||||||
DecryptedAppTicket ticket;
|
|
||||||
ticket.TicketV1.Reset();
|
|
||||||
ticket.TicketV2.Reset();
|
|
||||||
ticket.TicketV4.Reset();
|
|
||||||
|
|
||||||
ticket.TicketV1.TicketVersion = 1;
|
|
||||||
if (pDataToInclude) {
|
|
||||||
ticket.TicketV1.UserData.assign((uint8_t*)pDataToInclude, (uint8_t*)pDataToInclude + cbDataToInclude);
|
|
||||||
}
|
|
||||||
|
|
||||||
ticket.TicketV2.TicketVersion = 4;
|
|
||||||
ticket.TicketV2.SteamID = settings->get_local_steam_id().ConvertToUint64();
|
|
||||||
ticket.TicketV2.TicketIssueTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
|
||||||
ticket.TicketV2.TicketValidityEnd = ticket.TicketV2.TicketIssueTime + (21 * 24 * 60 * 60);
|
|
||||||
|
|
||||||
for (int i = 0; i < 140; ++i)
|
|
||||||
{
|
|
||||||
AppId_t appid;
|
|
||||||
bool available;
|
|
||||||
std::string name;
|
|
||||||
if (!settings->getDLC(appid, appid, available, name)) break;
|
|
||||||
ticket.TicketV4.AppIDs.emplace_back(appid);
|
|
||||||
}
|
|
||||||
|
|
||||||
ticket.TicketV4.HasVACStatus = true;
|
|
||||||
ticket.TicketV4.VACStatus = 0;
|
|
||||||
|
|
||||||
auto serialized = ticket.SerializeTicket();
|
|
||||||
|
|
||||||
SteamAppTicket_pb pb;
|
|
||||||
pb.set_ticket_version_no(1);
|
|
||||||
pb.set_crc_encryptedticket(0); // TODO: Find out how to compute the CRC
|
|
||||||
pb.set_cb_encrypteduserdata(cbDataToInclude);
|
|
||||||
pb.set_cb_encrypted_appownershipticket(serialized.size() - 16);
|
|
||||||
pb.mutable_encrypted_ticket()->assign(serialized.begin(), serialized.end()); // TODO: Find how to encrypt datas
|
|
||||||
|
|
||||||
encrypted_app_ticket = pb.SerializeAsString();
|
|
||||||
|
|
||||||
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
|
||||||
}
|
|
||||||
|
|
||||||
// retrieve a finished ticket
|
|
||||||
bool GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%i", cbMaxTicket);
|
|
||||||
unsigned int ticket_size = encrypted_app_ticket.size();
|
|
||||||
if (!cbMaxTicket) {
|
|
||||||
if (!pcbTicket) return false;
|
|
||||||
*pcbTicket = ticket_size;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!pTicket) return false;
|
|
||||||
if (ticket_size > cbMaxTicket) return false;
|
|
||||||
encrypted_app_ticket.copy((char *)pTicket, cbMaxTicket);
|
|
||||||
if (pcbTicket) *pcbTicket = ticket_size;
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Trading Card badges data access
|
|
||||||
// if you only have one set of cards, the series will be 1
|
|
||||||
// the user has can have two different badges for a series; the regular (max level 5) and the foil (max level 1)
|
|
||||||
int GetGameBadgeLevel( int nSeries, bool bFoil )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets the Steam Level of the user, as shown on their profile
|
|
||||||
int GetPlayerSteamLevel()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return 100;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Requests a URL which authenticates an in-game browser for store check-out,
|
|
||||||
// and then redirects to the specified URL. As long as the in-game browser
|
|
||||||
// accepts and handles session cookies, Steam microtransaction checkout pages
|
|
||||||
// will automatically recognize the user instead of presenting a login page.
|
|
||||||
// The result of this API call will be a StoreAuthURLResponse_t callback.
|
|
||||||
// NOTE: The URL has a very short lifetime to prevent history-snooping attacks,
|
|
||||||
// so you should only call this API when you are about to launch the browser,
|
|
||||||
// or else immediately navigate to the result URL using a hidden browser window.
|
|
||||||
// NOTE 2: The resulting authorization cookie has an expiration time of one day,
|
|
||||||
// so it would be a good idea to request and visit a new auth URL every 12 hours.
|
|
||||||
STEAM_CALL_RESULT( StoreAuthURLResponse_t )
|
|
||||||
SteamAPICall_t RequestStoreAuthURL( const char *pchRedirectURL )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets whether the users phone number is verified
|
|
||||||
bool BIsPhoneVerified()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets whether the user has two factor enabled on their account
|
|
||||||
bool BIsTwoFactorEnabled()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets whether the users phone number is identifying
|
|
||||||
bool BIsPhoneIdentifying()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// gets whether the users phone number is awaiting (re)verification
|
|
||||||
bool BIsPhoneRequiringVerification()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
STEAM_CALL_RESULT( MarketEligibilityResponse_t )
|
|
||||||
SteamAPICall_t GetMarketEligibility()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retrieves anti indulgence / duration control for current user
|
|
||||||
STEAM_CALL_RESULT( DurationControl_t )
|
|
||||||
SteamAPICall_t GetDurationControl()
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Advise steam china duration control system about the online state of the game.
|
|
||||||
// This will prevent offline gameplay time from counting against a user's
|
|
||||||
// playtime limits.
|
|
||||||
bool BSetDurationControlOnlineState( EDurationControlOnlineState eNewState )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_USER_H__
|
||||||
|
@ -50,21 +50,8 @@ struct achievement_trigger {
|
|||||||
std::string min_value{};
|
std::string min_value{};
|
||||||
std::string max_value{};
|
std::string max_value{};
|
||||||
|
|
||||||
bool check_triggered(float stat) {
|
bool check_triggered(float stat) const;
|
||||||
try {
|
bool check_triggered(int32 stat) const;
|
||||||
if (std::stof(max_value) <= stat) return true;
|
|
||||||
} catch (...) {}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool check_triggered(int32 stat) {
|
|
||||||
try {
|
|
||||||
if (std::stoi(max_value) <= stat) return true;
|
|
||||||
} catch (...) {}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Steam_User_Stats :
|
class Steam_User_Stats :
|
||||||
@ -91,9 +78,9 @@ private:
|
|||||||
T current_val{};
|
T current_val{};
|
||||||
};
|
};
|
||||||
|
|
||||||
Local_Storage *local_storage{};
|
class Local_Storage *local_storage{};
|
||||||
Settings *settings{};
|
class Settings *settings{};
|
||||||
SteamCallResults *callback_results{};
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks{};
|
class SteamCallBacks *callbacks{};
|
||||||
class Networking *network{};
|
class Networking *network{};
|
||||||
class RunEveryRunCB *run_every_runcb{};
|
class RunEveryRunCB *run_every_runcb{};
|
||||||
@ -115,7 +102,6 @@ private:
|
|||||||
|
|
||||||
GameServerStats_Messages::AllStats pending_server_updates{};
|
GameServerStats_Messages::AllStats pending_server_updates{};
|
||||||
|
|
||||||
|
|
||||||
void load_achievements_db();
|
void load_achievements_db();
|
||||||
void load_achievements();
|
void load_achievements();
|
||||||
void save_achievements();
|
void save_achievements();
|
||||||
|
@ -1,5 +1,3 @@
|
|||||||
#ifndef __STEAM_UTILS_H__
|
|
||||||
#define __STEAM_UTILS_H__
|
|
||||||
|
|
||||||
/* Copyright (C) 2019 Mr Goldberg
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
This file is part of the Goldberg Emulator
|
This file is part of the Goldberg Emulator
|
||||||
@ -18,6 +16,9 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __STEAM_UTILS_H__
|
||||||
|
#define __STEAM_UTILS_H__
|
||||||
|
|
||||||
#include "common_includes.h"
|
#include "common_includes.h"
|
||||||
#include "local_storage.h"
|
#include "local_storage.h"
|
||||||
#include "overlay/steam_overlay.h"
|
#include "overlay/steam_overlay.h"
|
||||||
@ -35,10 +36,10 @@ public ISteamUtils009,
|
|||||||
public ISteamUtils
|
public ISteamUtils
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
Settings *settings;
|
Settings *settings{};
|
||||||
class SteamCallResults *callback_results;
|
class SteamCallResults *callback_results{};
|
||||||
class SteamCallBacks *callbacks{};
|
class SteamCallBacks *callbacks{};
|
||||||
Steam_Overlay* overlay;
|
Steam_Overlay* overlay{};
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Steam_Utils(Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, Steam_Overlay *overlay);
|
Steam_Utils(Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, Steam_Overlay *overlay);
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
License along with the Goldberg Emulator; if not, see
|
License along with the Goldberg Emulator; if not, see
|
||||||
<http://www.gnu.org/licenses/>. */
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#ifndef __INCLUDED_STEAM_VIDEO_H__
|
||||||
|
#define __INCLUDED_STEAM_VIDEO_H__
|
||||||
|
|
||||||
#include "base.h"
|
#include "base.h"
|
||||||
|
|
||||||
class Steam_Video : public ISteamVideo
|
class Steam_Video :
|
||||||
|
public ISteamVideo
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
|
||||||
@ -32,3 +36,5 @@ public:
|
|||||||
void GetOPFSettings( AppId_t unVideoAppID );
|
void GetOPFSettings( AppId_t unVideoAppID );
|
||||||
bool GetOPFStringForApp( AppId_t unVideoAppID, char *pchBuffer, int32 *pnBufferSize );
|
bool GetOPFStringForApp( AppId_t unVideoAppID, char *pchBuffer, int32 *pnBufferSize );
|
||||||
};
|
};
|
||||||
|
|
||||||
|
#endif // __INCLUDED_STEAM_VIDEO_H__
|
||||||
|
@ -1,3 +1,19 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
#ifndef __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
#ifndef __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
||||||
#define __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
#define __INCLUDED_UGC_REMOTE_STORAGE_BRIDGE_H__
|
||||||
@ -8,19 +24,20 @@ class Ugc_Remote_Storage_Bridge
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
struct QueryInfo {
|
struct QueryInfo {
|
||||||
PublishedFileId_t mod_id; // mod id
|
PublishedFileId_t mod_id{}; // mod id
|
||||||
bool is_primary_file; // was this query for the primary mod file or preview file
|
bool is_primary_file{}; // was this query for the primary mod file or preview file
|
||||||
};
|
};
|
||||||
|
|
||||||
private:
|
private:
|
||||||
class Settings *settings;
|
class Settings *settings{};
|
||||||
// key: UGCHandle_t which is the file handle (primary or preview)
|
// key: UGCHandle_t which is the file handle (primary or preview)
|
||||||
// value: the mod id, true if UGCHandle_t of primary file | false if UGCHandle_t of preview file
|
// value: the mod id, true if UGCHandle_t of primary file | false if UGCHandle_t of preview file
|
||||||
std::map<UGCHandle_t, QueryInfo> steam_ugc_queries{};
|
std::map<UGCHandle_t, QueryInfo> steam_ugc_queries{};
|
||||||
std::set<PublishedFileId_t> subscribed; // just to keep the running state of subscription
|
std::set<PublishedFileId_t> subscribed{}; // just to keep the running state of subscription
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Ugc_Remote_Storage_Bridge(class Settings *settings);
|
Ugc_Remote_Storage_Bridge(class Settings *settings);
|
||||||
|
~Ugc_Remote_Storage_Bridge();
|
||||||
|
|
||||||
// called from Steam_UGC::SendQueryUGCRequest() after a successful query
|
// called from Steam_UGC::SendQueryUGCRequest() after a successful query
|
||||||
void add_ugc_query_result(UGCHandle_t file_handle, PublishedFileId_t fileid, bool handle_of_primary_file);
|
void add_ugc_query_result(UGCHandle_t file_handle, PublishedFileId_t fileid, bool handle_of_primary_file);
|
||||||
@ -34,7 +51,6 @@ public:
|
|||||||
std::set<PublishedFileId_t>::iterator subbed_mods_itr_begin() const;
|
std::set<PublishedFileId_t>::iterator subbed_mods_itr_begin() const;
|
||||||
std::set<PublishedFileId_t>::iterator subbed_mods_itr_end() const;
|
std::set<PublishedFileId_t>::iterator subbed_mods_itr_end() const;
|
||||||
|
|
||||||
~Ugc_Remote_Storage_Bridge();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
@ -121,6 +121,19 @@ static void merge_ini(const CSimpleIniA &new_ini, bool overwrite = false) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Overlay_Appearance::NotificationPosition Overlay_Appearance::translate_notification_position(const std::string &str)
|
||||||
|
{
|
||||||
|
if (str == "top_left") return NotificationPosition::top_left;
|
||||||
|
else if (str == "top_center") return NotificationPosition::top_center;
|
||||||
|
else if (str == "top_right") return NotificationPosition::top_right;
|
||||||
|
else if (str == "bot_left") return NotificationPosition::bot_left;
|
||||||
|
else if (str == "bot_center") return NotificationPosition::bot_center;
|
||||||
|
else if (str == "bot_right") return NotificationPosition::bot_right;
|
||||||
|
|
||||||
|
PRINT_DEBUG("Invalid position '%s'", str.c_str());
|
||||||
|
return default_pos;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
// custom_broadcasts.txt
|
// custom_broadcasts.txt
|
||||||
static void load_custom_broadcasts(const std::string &base_path, std::set<IP_PORT> &custom_broadcasts)
|
static void load_custom_broadcasts(const std::string &base_path, std::set<IP_PORT> &custom_broadcasts)
|
||||||
|
@ -18,58 +18,48 @@
|
|||||||
#include "dll/source_query.h"
|
#include "dll/source_query.h"
|
||||||
#include "dll/dll.h"
|
#include "dll/dll.h"
|
||||||
|
|
||||||
using lock_t = std::lock_guard<std::mutex>;
|
enum class source_query_magic : uint32_t {
|
||||||
|
|
||||||
enum class source_query_magic : uint32_t
|
|
||||||
{
|
|
||||||
simple = 0xFFFFFFFFul,
|
simple = 0xFFFFFFFFul,
|
||||||
multi = 0xFFFFFFFEul, // <--- TODO ?
|
multi = 0xFFFFFFFEul, // <--- TODO ?
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class source_query_header : uint8_t
|
enum class source_query_header : uint8_t {
|
||||||
{
|
|
||||||
A2S_INFO = 'T',
|
A2S_INFO = 'T',
|
||||||
A2S_PLAYER = 'U',
|
A2S_PLAYER = 'U',
|
||||||
A2S_RULES = 'V',
|
A2S_RULES = 'V',
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class source_response_header : uint8_t
|
enum class source_response_header : uint8_t {
|
||||||
{
|
|
||||||
A2S_CHALLENGE = 'A',
|
A2S_CHALLENGE = 'A',
|
||||||
A2S_INFO = 'I',
|
A2S_INFO = 'I',
|
||||||
A2S_PLAYER = 'D',
|
A2S_PLAYER = 'D',
|
||||||
A2S_RULES = 'E',
|
A2S_RULES = 'E',
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class source_server_type : uint8_t
|
enum class source_server_type : uint8_t {
|
||||||
{
|
|
||||||
dedicated = 'd',
|
dedicated = 'd',
|
||||||
non_dedicated = 'i',
|
non_dedicated = 'i',
|
||||||
source_tc = 'p',
|
source_tc = 'p',
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class source_server_env : uint8_t
|
enum class source_server_env : uint8_t {
|
||||||
{
|
|
||||||
linux = 'l',
|
linux = 'l',
|
||||||
windows = 'w',
|
windows = 'w',
|
||||||
old_mac = 'm',
|
old_mac = 'm',
|
||||||
mac = 'o',
|
mac = 'o',
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class source_server_visibility : uint8_t
|
enum class source_server_visibility : uint8_t {
|
||||||
{
|
|
||||||
_public = 0,
|
_public = 0,
|
||||||
_private = 1,
|
_private = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class source_server_vac : uint8_t
|
enum class source_server_vac : uint8_t {
|
||||||
{
|
|
||||||
unsecured = 0,
|
unsecured = 0,
|
||||||
secured = 1,
|
secured = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum source_server_extra_flag : uint8_t
|
enum source_server_extra_flag : uint8_t {
|
||||||
{
|
|
||||||
none = 0x00,
|
none = 0x00,
|
||||||
gameid = 0x01,
|
gameid = 0x01,
|
||||||
steamid = 0x10,
|
steamid = 0x10,
|
||||||
@ -79,21 +69,20 @@ enum source_server_extra_flag : uint8_t
|
|||||||
};
|
};
|
||||||
|
|
||||||
#if defined(STEAM_WIN32)
|
#if defined(STEAM_WIN32)
|
||||||
static constexpr source_server_env my_server_env = source_server_env::windows;
|
static constexpr const source_server_env my_server_env = source_server_env::windows;
|
||||||
#else
|
#else
|
||||||
static constexpr source_server_env my_server_env = source_server_env::linux;
|
static constexpr const source_server_env my_server_env = source_server_env::linux;
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
#pragma pack(push)
|
#pragma pack(push)
|
||||||
#pragma pack(1)
|
#pragma pack(1)
|
||||||
|
constexpr static const char a2s_info_payload[] = "Source Engine Query";
|
||||||
|
constexpr static const size_t a2s_info_payload_size = sizeof(a2s_info_payload);
|
||||||
|
|
||||||
constexpr char a2s_info_payload[] = "Source Engine Query";
|
struct source_query_data {
|
||||||
constexpr size_t a2s_info_payload_size = sizeof(a2s_info_payload);
|
source_query_magic magic{};
|
||||||
|
source_query_header header{};
|
||||||
struct source_query_data
|
|
||||||
{
|
|
||||||
source_query_magic magic;
|
|
||||||
source_query_header header;
|
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
char a2s_info_payload[a2s_info_payload_size];
|
char a2s_info_payload[a2s_info_payload_size];
|
||||||
@ -101,12 +90,12 @@ struct source_query_data
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
static constexpr size_t source_query_header_size = sizeof(source_query_magic) + sizeof(source_query_header);
|
static constexpr const size_t source_query_header_size = sizeof(source_query_magic) + sizeof(source_query_header);
|
||||||
static constexpr size_t a2s_query_info_size = source_query_header_size + sizeof(source_query_data::a2s_info_payload);
|
static constexpr const size_t a2s_query_info_size = source_query_header_size + sizeof(source_query_data::a2s_info_payload);
|
||||||
static constexpr size_t a2s_query_challenge_size = source_query_header_size + sizeof(source_query_data::challenge);
|
static constexpr const size_t a2s_query_challenge_size = source_query_header_size + sizeof(source_query_data::challenge);
|
||||||
|
|
||||||
#pragma pack(pop)
|
#pragma pack(pop)
|
||||||
|
|
||||||
|
|
||||||
void serialize_response(std::vector<uint8_t>& buffer, const void* _data, size_t len)
|
void serialize_response(std::vector<uint8_t>& buffer, const void* _data, size_t len)
|
||||||
{
|
{
|
||||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(_data);
|
const uint8_t* data = reinterpret_cast<const uint8_t*>(_data);
|
||||||
@ -156,10 +145,9 @@ std::vector<uint8_t> Source_Query::handle_source_query(const void* buffer, size_
|
|||||||
|
|
||||||
switch (query.header)
|
switch (query.header)
|
||||||
{
|
{
|
||||||
case source_query_header::A2S_INFO:
|
case source_query_header::A2S_INFO: {
|
||||||
PRINT_DEBUG("got request for server info");
|
PRINT_DEBUG("got request for server info");
|
||||||
if (len >= a2s_query_info_size && !strncmp(query.a2s_info_payload, a2s_info_payload, a2s_info_payload_size))
|
if (len >= a2s_query_info_size && !strncmp(query.a2s_info_payload, a2s_info_payload, a2s_info_payload_size)) {
|
||||||
{
|
|
||||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> const& players = *get_steam_client()->steam_gameserver->get_players();
|
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> const& players = *get_steam_client()->steam_gameserver->get_players();
|
||||||
|
|
||||||
serialize_response(output_buffer, source_query_magic::simple);
|
serialize_response(output_buffer, source_query_magic::simple);
|
||||||
@ -181,93 +169,77 @@ std::vector<uint8_t> Source_Query::handle_source_query(const void* buffer, size_
|
|||||||
|
|
||||||
uint8_t flags = source_server_extra_flag::none;
|
uint8_t flags = source_server_extra_flag::none;
|
||||||
|
|
||||||
if (gs.port() != 0)
|
if (gs.port() != 0) flags |= source_server_extra_flag::port;
|
||||||
flags |= source_server_extra_flag::port;
|
|
||||||
|
|
||||||
if (gs.spectator_port() != 0)
|
if (gs.spectator_port() != 0) flags |= source_server_extra_flag::spectator;
|
||||||
flags |= source_server_extra_flag::spectator;
|
|
||||||
|
|
||||||
if(CGameID(gs.appid()).IsValid())
|
if (CGameID(gs.appid()).IsValid()) flags |= source_server_extra_flag::gameid;
|
||||||
flags |= source_server_extra_flag::gameid;
|
|
||||||
|
|
||||||
if (flags != source_server_extra_flag::none)
|
if (flags != source_server_extra_flag::none) serialize_response(output_buffer, flags);
|
||||||
serialize_response(output_buffer, flags);
|
|
||||||
|
|
||||||
if (flags & source_server_extra_flag::port)
|
if (flags & source_server_extra_flag::port) serialize_response(output_buffer, static_cast<uint16_t>(gs.port()));
|
||||||
serialize_response(output_buffer, static_cast<uint16_t>(gs.port()));
|
|
||||||
|
|
||||||
// add steamid
|
// add steamid
|
||||||
|
|
||||||
if (flags & source_server_extra_flag::spectator)
|
if (flags & source_server_extra_flag::spectator) {
|
||||||
{
|
|
||||||
serialize_response(output_buffer, static_cast<uint16_t>(gs.spectator_port()));
|
serialize_response(output_buffer, static_cast<uint16_t>(gs.spectator_port()));
|
||||||
serialize_response(output_buffer, gs.spectator_server_name());
|
serialize_response(output_buffer, gs.spectator_server_name());
|
||||||
}
|
}
|
||||||
|
|
||||||
// keywords
|
// keywords
|
||||||
|
|
||||||
if (flags & source_server_extra_flag::gameid)
|
if (flags & source_server_extra_flag::gameid) serialize_response(output_buffer, CGameID(gs.appid()).ToUint64());
|
||||||
serialize_response(output_buffer, CGameID(gs.appid()).ToUint64());
|
|
||||||
|
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case source_query_header::A2S_PLAYER:
|
case source_query_header::A2S_PLAYER: {
|
||||||
PRINT_DEBUG("got request for player info");
|
PRINT_DEBUG("got request for player info");
|
||||||
if (len >= a2s_query_challenge_size)
|
if (len >= a2s_query_challenge_size) {
|
||||||
{
|
if (query.challenge == 0xFFFFFFFFul) {
|
||||||
if (query.challenge == 0xFFFFFFFFul)
|
|
||||||
{
|
|
||||||
get_challenge(output_buffer);
|
get_challenge(output_buffer);
|
||||||
}
|
} else if (query.challenge == 0x00112233ul) {
|
||||||
else if (query.challenge == 0x00112233ul)
|
|
||||||
{
|
|
||||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> const& players = *get_steam_client()->steam_gameserver->get_players();
|
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> const& players = *get_steam_client()->steam_gameserver->get_players();
|
||||||
|
|
||||||
serialize_response(output_buffer, source_query_magic::simple);
|
serialize_response(output_buffer, source_query_magic::simple);
|
||||||
serialize_response(output_buffer, source_response_header::A2S_PLAYER);
|
serialize_response(output_buffer, source_response_header::A2S_PLAYER);
|
||||||
serialize_response(output_buffer, static_cast<uint8_t>(players.size())); // num_players
|
serialize_response(output_buffer, static_cast<uint8_t>(players.size())); // num_players
|
||||||
|
|
||||||
for (int i = 0; i < players.size(); ++i)
|
for (int i = 0; i < players.size(); ++i) {
|
||||||
{
|
|
||||||
serialize_response(output_buffer, static_cast<uint8_t>(i)); // player index
|
serialize_response(output_buffer, static_cast<uint8_t>(i)); // player index
|
||||||
serialize_response(output_buffer, players[i].second.name); // player name
|
serialize_response(output_buffer, players[i].second.name); // player name
|
||||||
serialize_response(output_buffer, players[i].second.score); // player score
|
serialize_response(output_buffer, players[i].second.score); // player score
|
||||||
serialize_response(output_buffer, static_cast<float>(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - players[i].second.join_time).count()));
|
serialize_response(output_buffer, static_cast<float>(std::chrono::duration_cast<std::chrono::seconds>(std::chrono::steady_clock::now() - players[i].second.join_time).count()));
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
case source_query_header::A2S_RULES:
|
case source_query_header::A2S_RULES: {
|
||||||
PRINT_DEBUG("got request for rules info");
|
PRINT_DEBUG("got request for rules info");
|
||||||
if (len >= a2s_query_challenge_size)
|
if (len >= a2s_query_challenge_size) {
|
||||||
{
|
if (query.challenge == 0xFFFFFFFFul) {
|
||||||
if (query.challenge == 0xFFFFFFFFul)
|
|
||||||
{
|
|
||||||
get_challenge(output_buffer);
|
get_challenge(output_buffer);
|
||||||
}
|
} else if (query.challenge == 0x00112233ul) {
|
||||||
else if (query.challenge == 0x00112233ul)
|
|
||||||
{
|
|
||||||
auto values = gs.values();
|
auto values = gs.values();
|
||||||
|
|
||||||
serialize_response(output_buffer, source_query_magic::simple);
|
serialize_response(output_buffer, source_query_magic::simple);
|
||||||
serialize_response(output_buffer, source_response_header::A2S_RULES);
|
serialize_response(output_buffer, source_response_header::A2S_RULES);
|
||||||
serialize_response(output_buffer, static_cast<uint16_t>(values.size()));
|
serialize_response(output_buffer, static_cast<uint16_t>(values.size()));
|
||||||
|
|
||||||
for (auto const& i : values)
|
for (const auto &i : values) {
|
||||||
{
|
|
||||||
serialize_response(output_buffer, i.first);
|
serialize_response(output_buffer, i.first);
|
||||||
serialize_response(output_buffer, i.second);
|
serialize_response(output_buffer, i.second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
PRINT_DEBUG("got unknown request");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default: PRINT_DEBUG("got unknown request"); break;
|
||||||
|
}
|
||||||
|
|
||||||
return output_buffer;
|
return output_buffer;
|
||||||
}
|
}
|
||||||
|
363
dll/steam_HTMLsurface.cpp
Normal file
363
dll/steam_HTMLsurface.cpp
Normal file
@ -0,0 +1,363 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_HTMLsurface.h"
|
||||||
|
|
||||||
|
Steam_HTMLsurface::Steam_HTMLsurface(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Must call init and shutdown when starting/ending use of the interface
|
||||||
|
bool Steam_HTMLsurface::Init()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_HTMLsurface::Shutdown()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create a browser object for display of a html page, when creation is complete the call handle
|
||||||
|
// will return a HTML_BrowserReady_t callback for the HHTMLBrowser of your new browser.
|
||||||
|
// The user agent string is a substring to be added to the general user agent string so you can
|
||||||
|
// identify your client on web servers.
|
||||||
|
// The userCSS string lets you apply a CSS style sheet to every displayed page, leave null if
|
||||||
|
// you do not require this functionality.
|
||||||
|
//
|
||||||
|
// YOU MUST HAVE IMPLEMENTED HANDLERS FOR HTML_BrowserReady_t, HTML_StartRequest_t,
|
||||||
|
// HTML_JSAlert_t, HTML_JSConfirm_t, and HTML_FileOpenDialog_t! See the CALLBACKS
|
||||||
|
// section of this interface (AllowStartRequest, etc) for more details. If you do
|
||||||
|
// not implement these callback handlers, the browser may appear to hang instead of
|
||||||
|
// navigating to new pages or triggering javascript popups.
|
||||||
|
//
|
||||||
|
STEAM_CALL_RESULT( HTML_BrowserReady_t )
|
||||||
|
SteamAPICall_t Steam_HTMLsurface::CreateBrowser( const char *pchUserAgent, const char *pchUserCSS )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
HTML_BrowserReady_t data;
|
||||||
|
data.unBrowserHandle = 1234869;
|
||||||
|
|
||||||
|
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call this when you are done with a html surface, this lets us free the resources being used by it
|
||||||
|
void Steam_HTMLsurface::RemoveBrowser( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Navigate to this URL, results in a HTML_StartRequest_t as the request commences
|
||||||
|
void Steam_HTMLsurface::LoadURL( HHTMLBrowser unBrowserHandle, const char *pchURL, const char *pchPostData )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("TODO %s %s", pchURL, pchPostData);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
static char url[256];
|
||||||
|
strncpy(url, pchURL, sizeof(url));
|
||||||
|
static char target[] = "_self";
|
||||||
|
static char title[] = "title";
|
||||||
|
|
||||||
|
{
|
||||||
|
HTML_StartRequest_t data;
|
||||||
|
data.unBrowserHandle = unBrowserHandle;
|
||||||
|
data.pchURL = url;
|
||||||
|
data.pchTarget = target;
|
||||||
|
data.pchPostData = "";
|
||||||
|
data.bIsRedirect = false;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.1);
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
HTML_FinishedRequest_t data;
|
||||||
|
data.unBrowserHandle = unBrowserHandle;
|
||||||
|
data.pchURL = url;
|
||||||
|
data.pchPageTitle = title;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.8);
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Tells the surface the size in pixels to display the surface
|
||||||
|
void Steam_HTMLsurface::SetSize( HHTMLBrowser unBrowserHandle, uint32 unWidth, uint32 unHeight )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Stop the load of the current html page
|
||||||
|
void Steam_HTMLsurface::StopLoad( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reload (most likely from local cache) the current page
|
||||||
|
void Steam_HTMLsurface::Reload( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// navigate back in the page history
|
||||||
|
void Steam_HTMLsurface::GoBack( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// navigate forward in the page history
|
||||||
|
void Steam_HTMLsurface::GoForward( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// add this header to any url requests from this browser
|
||||||
|
void Steam_HTMLsurface::AddHeader( HHTMLBrowser unBrowserHandle, const char *pchKey, const char *pchValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// run this javascript script in the currently loaded page
|
||||||
|
void Steam_HTMLsurface::ExecuteJavascript( HHTMLBrowser unBrowserHandle, const char *pchScript )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Mouse click and mouse movement commands
|
||||||
|
void Steam_HTMLsurface::MouseUp( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_HTMLsurface::MouseDown( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_HTMLsurface::MouseDoubleClick( HHTMLBrowser unBrowserHandle, EHTMLMouseButton eMouseButton )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// x and y are relative to the HTML bounds
|
||||||
|
void Steam_HTMLsurface::MouseMove( HHTMLBrowser unBrowserHandle, int x, int y )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// nDelta is pixels of scroll
|
||||||
|
void Steam_HTMLsurface::MouseWheel( HHTMLBrowser unBrowserHandle, int32 nDelta )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// keyboard interactions, native keycode is the key code value from your OS
|
||||||
|
void Steam_HTMLsurface::KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers, bool bIsSystemKey )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_HTMLsurface::KeyDown( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
KeyDown(unBrowserHandle, nNativeKeyCode, eHTMLKeyModifiers, false);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_HTMLsurface::KeyUp( HHTMLBrowser unBrowserHandle, uint32 nNativeKeyCode, EHTMLKeyModifiers eHTMLKeyModifiers )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cUnicodeChar is the unicode character point for this keypress (and potentially multiple chars per press)
|
||||||
|
void Steam_HTMLsurface::KeyChar( HHTMLBrowser unBrowserHandle, uint32 cUnicodeChar, EHTMLKeyModifiers eHTMLKeyModifiers )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// programmatically scroll this many pixels on the page
|
||||||
|
void Steam_HTMLsurface::SetHorizontalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_HTMLsurface::SetVerticalScroll( HHTMLBrowser unBrowserHandle, uint32 nAbsolutePixelScroll )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// tell the html control if it has key focus currently, controls showing the I-beam cursor in text controls amongst other things
|
||||||
|
void Steam_HTMLsurface::SetKeyFocus( HHTMLBrowser unBrowserHandle, bool bHasKeyFocus )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// open the current pages html code in the local editor of choice, used for debugging
|
||||||
|
void Steam_HTMLsurface::ViewSource( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// copy the currently selected text on the html page to the local clipboard
|
||||||
|
void Steam_HTMLsurface::CopyToClipboard( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// paste from the local clipboard to the current html page
|
||||||
|
void Steam_HTMLsurface::PasteFromClipboard( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// find this string in the browser, if bCurrentlyInFind is true then instead cycle to the next matching element
|
||||||
|
void Steam_HTMLsurface::Find( HHTMLBrowser unBrowserHandle, const char *pchSearchStr, bool bCurrentlyInFind, bool bReverse )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// cancel a currently running find
|
||||||
|
void Steam_HTMLsurface::StopFind( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// return details about the link at position x,y on the current page
|
||||||
|
void Steam_HTMLsurface::GetLinkAtPosition( HHTMLBrowser unBrowserHandle, int x, int y )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set a webcookie for the hostname in question
|
||||||
|
void Steam_HTMLsurface::SetCookie( const char *pchHostname, const char *pchKey, const char *pchValue, const char *pchPath, RTime32 nExpires, bool bSecure, bool bHTTPOnly )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Zoom the current page by flZoom ( from 0.0 to 2.0, so to zoom to 120% use 1.2 ), zooming around point X,Y in the page (use 0,0 if you don't care)
|
||||||
|
void Steam_HTMLsurface::SetPageScaleFactor( HHTMLBrowser unBrowserHandle, float flZoom, int nPointX, int nPointY )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Enable/disable low-resource background mode, where javascript and repaint timers are throttled, resources are
|
||||||
|
// more aggressively purged from memory, and audio/video elements are paused. When background mode is enabled,
|
||||||
|
// all HTML5 video and audio objects will execute ".pause()" and gain the property "._steam_background_paused = 1".
|
||||||
|
// When background mode is disabled, any video or audio objects with that property will resume with ".play()".
|
||||||
|
void Steam_HTMLsurface::SetBackgroundMode( HHTMLBrowser unBrowserHandle, bool bBackgroundMode )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Scale the output display space by this factor, this is useful when displaying content on high dpi devices.
|
||||||
|
// Specifies the ratio between physical and logical pixels.
|
||||||
|
void Steam_HTMLsurface::SetDPIScalingFactor( HHTMLBrowser unBrowserHandle, float flDPIScaling )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_HTMLsurface::OpenDeveloperTools( HHTMLBrowser unBrowserHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
// CALLBACKS
|
||||||
|
//
|
||||||
|
// These set of functions are used as responses to callback requests
|
||||||
|
//
|
||||||
|
|
||||||
|
// You MUST call this in response to a HTML_StartRequest_t callback
|
||||||
|
// Set bAllowed to true to allow this navigation, false to cancel it and stay
|
||||||
|
// on the current page. You can use this feature to limit the valid pages
|
||||||
|
// allowed in your HTML surface.
|
||||||
|
void Steam_HTMLsurface::AllowStartRequest( HHTMLBrowser unBrowserHandle, bool bAllowed )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// You MUST call this in response to a HTML_JSAlert_t or HTML_JSConfirm_t callback
|
||||||
|
// Set bResult to true for the OK option of a confirm, use false otherwise
|
||||||
|
void Steam_HTMLsurface::JSDialogResponse( HHTMLBrowser unBrowserHandle, bool bResult )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// You MUST call this in response to a HTML_FileOpenDialog_t callback
|
||||||
|
STEAM_IGNOREATTR()
|
||||||
|
void Steam_HTMLsurface::FileLoadDialogResponse( HHTMLBrowser unBrowserHandle, const char **pchSelectedFiles )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
@ -18,13 +18,13 @@
|
|||||||
#include "dll/steam_client.h"
|
#include "dll/steam_client.h"
|
||||||
#include "dll/settings_parser.h"
|
#include "dll/settings_parser.h"
|
||||||
|
|
||||||
static std::mutex kill_background_thread_mutex;
|
static std::mutex kill_background_thread_mutex{};
|
||||||
static std::condition_variable kill_background_thread_cv;
|
static std::condition_variable kill_background_thread_cv{};
|
||||||
static bool kill_background_thread;
|
static bool kill_background_thread{};
|
||||||
static void background_thread(Steam_Client *client)
|
static void background_thread(Steam_Client *client)
|
||||||
{
|
{
|
||||||
// max allowed time in which RunCallbacks() might not be called
|
// max allowed time in which RunCallbacks() might not be called
|
||||||
constexpr const static auto max_stall_ms = std::chrono::milliseconds(200);
|
constexpr const static auto max_stall_ms = std::chrono::milliseconds(300);
|
||||||
|
|
||||||
// wait 1 sec
|
// wait 1 sec
|
||||||
{
|
{
|
||||||
@ -228,12 +228,13 @@ Steam_Client::~Steam_Client()
|
|||||||
|
|
||||||
delete ugc_bridge; ugc_bridge = nullptr;
|
delete ugc_bridge; ugc_bridge = nullptr;
|
||||||
|
|
||||||
delete network; network = nullptr;
|
|
||||||
delete run_every_runcb; run_every_runcb = nullptr;
|
|
||||||
delete callbacks_server; callbacks_server = nullptr;
|
delete callbacks_server; callbacks_server = nullptr;
|
||||||
delete callbacks_client; callbacks_client = nullptr;
|
delete callbacks_client; callbacks_client = nullptr;
|
||||||
delete callback_results_server; callback_results_server = nullptr;
|
delete callback_results_server; callback_results_server = nullptr;
|
||||||
delete callback_results_client; callback_results_client = nullptr;
|
delete callback_results_client; callback_results_client = nullptr;
|
||||||
|
|
||||||
|
delete network; network = nullptr;
|
||||||
|
delete run_every_runcb; run_every_runcb = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Client::userLogIn()
|
void Steam_Client::userLogIn()
|
||||||
@ -275,11 +276,13 @@ void Steam_Client::setAppID(uint32 appid)
|
|||||||
settings_server->set_game_id(CGameID(appid));
|
settings_server->set_game_id(CGameID(appid));
|
||||||
local_storage->setAppId(appid);
|
local_storage->setAppId(appid);
|
||||||
network->setAppID(appid);
|
network->setAppID(appid);
|
||||||
set_env_variable("SteamAppId", std::to_string(appid));
|
|
||||||
set_env_variable("SteamGameId", std::to_string(appid));
|
std::string appid_str(std::to_string(appid));
|
||||||
|
set_env_variable("SteamAppId", appid_str);
|
||||||
|
set_env_variable("SteamGameId", appid_str);
|
||||||
|
|
||||||
if (!settings_client->disable_steamoverlaygameid_env_var) {
|
if (!settings_client->disable_steamoverlaygameid_env_var) {
|
||||||
set_env_variable("SteamOverlayGameId", std::to_string(appid));
|
set_env_variable("SteamOverlayGameId", appid_str);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1974,5 +1977,5 @@ void Steam_Client::RunCallbacks(bool runClientCB, bool runGameserverCB)
|
|||||||
|
|
||||||
void Steam_Client::DestroyAllInterfaces()
|
void Steam_Client::DestroyAllInterfaces()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG_ENTRY();
|
PRINT_DEBUG_TODO();
|
||||||
}
|
}
|
||||||
|
1167
dll/steam_controller.cpp
Normal file
1167
dll/steam_controller.cpp
Normal file
File diff suppressed because it is too large
Load Diff
1291
dll/steam_friends.cpp
Normal file
1291
dll/steam_friends.cpp
Normal file
File diff suppressed because it is too large
Load Diff
146
dll/steam_game_coordinator.cpp
Normal file
146
dll/steam_game_coordinator.cpp
Normal file
@ -0,0 +1,146 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_game_coordinator.h"
|
||||||
|
|
||||||
|
void Steam_Game_Coordinator::push_incoming(std::string message)
|
||||||
|
{
|
||||||
|
outgoing_messages.push(message);
|
||||||
|
|
||||||
|
struct GCMessageAvailable_t data;
|
||||||
|
data.m_nMessageSize = message.size();
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Game_Coordinator::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Game_Coordinator *steam_gamecoordinator = (Steam_Game_Coordinator *)object;
|
||||||
|
steam_gamecoordinator->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Game_Coordinator::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Game_Coordinator *steam_gamecoordinator = (Steam_Game_Coordinator *)object;
|
||||||
|
steam_gamecoordinator->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Game_Coordinator::Steam_Game_Coordinator(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Coordinator::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Game_Coordinator::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Game_Coordinator::~Steam_Game_Coordinator()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Coordinator::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Game_Coordinator::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// sends a message to the Game Coordinator
|
||||||
|
EGCResults Steam_Game_Coordinator::SendMessage_( uint32 unMsgType, const void *pubData, uint32 cubData )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%X %u len %u", unMsgType, (~protobuf_mask) & unMsgType, cubData);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (protobuf_mask & unMsgType) {
|
||||||
|
uint32 message_type = (~protobuf_mask) & unMsgType;
|
||||||
|
if (message_type == 4006) { //client hello
|
||||||
|
std::string message("\xA4\x0F\x00\x80\x00\x00\x00\x00\x08\x00", 10);
|
||||||
|
push_incoming(message);
|
||||||
|
} else
|
||||||
|
if (message_type == 4007) { //server hello
|
||||||
|
std::string message("\xA5\x0F\x00\x80\x00\x00\x00\x00\x08\x00", 10);
|
||||||
|
push_incoming(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return k_EGCResultOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if there is a message waiting from the game coordinator
|
||||||
|
bool Steam_Game_Coordinator::IsMessageAvailable( uint32 *pcubMsgSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (outgoing_messages.size()) {
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = outgoing_messages.front().size();
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fills the provided buffer with the first message in the queue and returns k_EGCResultOK or
|
||||||
|
// returns k_EGCResultNoMessage if there is no message waiting. pcubMsgSize is filled with the message size.
|
||||||
|
// If the provided buffer is not large enough to fit the entire message, k_EGCResultBufferTooSmall is returned
|
||||||
|
// and the message remains at the head of the queue.
|
||||||
|
EGCResults Steam_Game_Coordinator::RetrieveMessage( uint32 *punMsgType, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (outgoing_messages.size()) {
|
||||||
|
if (outgoing_messages.front().size() > cubDest) {
|
||||||
|
return k_EGCResultBufferTooSmall;
|
||||||
|
}
|
||||||
|
|
||||||
|
outgoing_messages.front().copy((char *)pubDest, cubDest);
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = outgoing_messages.front().size();
|
||||||
|
if (punMsgType && outgoing_messages.front().size() >= sizeof(uint32)) {
|
||||||
|
outgoing_messages.front().copy((char *)punMsgType, sizeof(uint32));
|
||||||
|
*punMsgType = ntohl(*punMsgType);
|
||||||
|
}
|
||||||
|
|
||||||
|
outgoing_messages.pop();
|
||||||
|
return k_EGCResultOK;
|
||||||
|
} else {
|
||||||
|
return k_EGCResultNoMessage;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Game_Coordinator::RunCallbacks()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Game_Coordinator::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_sockets()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
215
dll/steam_gamesearch.cpp
Normal file
215
dll/steam_gamesearch.cpp
Normal file
@ -0,0 +1,215 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_gamesearch.h"
|
||||||
|
|
||||||
|
void Steam_Game_Search::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Game_Search *steam_gamesearch = (Steam_Game_Search *)object;
|
||||||
|
steam_gamesearch->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Game_Search::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Game_Search *steam_gamesearch = (Steam_Game_Search *)object;
|
||||||
|
steam_gamesearch->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Game_Search::Steam_Game_Search(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Search::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Game_Search::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Game_Search::~Steam_Game_Search()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Game_Search::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Game_Search::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// =============================================================================================
|
||||||
|
// Game Player APIs
|
||||||
|
|
||||||
|
// a keyname and a list of comma separated values: one of which is must be found in order for the match to qualify
|
||||||
|
// fails if a search is currently in progress
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::AddGameSearchParams( const char *pchKeyToFind, const char *pchValuesToFind )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// all players in lobby enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress
|
||||||
|
// if not the owner of the lobby or search already in progress this call fails
|
||||||
|
// periodic callbacks will be sent as queue time estimates change
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::SearchForGameWithLobby( CSteamID steamIDLobby, int nPlayerMin, int nPlayerMax )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// user enter the queue and await a SearchForGameNotificationCallback_t callback. fails if another search is currently in progress
|
||||||
|
// periodic callbacks will be sent as queue time estimates change
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::SearchForGameSolo( int nPlayerMin, int nPlayerMax )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// after receiving SearchForGameResultCallback_t, accept or decline the game
|
||||||
|
// multiple SearchForGameResultCallback_t will follow as players accept game until the host starts or cancels the game
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::AcceptGame()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::DeclineGame()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// after receiving GameStartedByHostCallback_t get connection details to server
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::RetrieveConnectionDetails( CSteamID steamIDHost, char *pchConnectionDetails, int cubConnectionDetails )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// leaves queue if still waiting
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::EndGameSearch()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =============================================================================================
|
||||||
|
// Game Host APIs
|
||||||
|
|
||||||
|
// a keyname and a list of comma separated values: all the values you allow
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::SetGameHostParams( const char *pchKey, const char *pchValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// set connection details for players once game is found so they can connect to this server
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::SetConnectionDetails( const char *pchConnectionDetails, int cubConnectionDetails )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// mark server as available for more players with nPlayerMin,nPlayerMax desired
|
||||||
|
// accept no lobbies with playercount greater than nMaxTeamSize
|
||||||
|
// the set of lobbies returned must be partitionable into teams of no more than nMaxTeamSize
|
||||||
|
// RequestPlayersForGameNotificationCallback_t callback will be sent when the search has started
|
||||||
|
// multple RequestPlayersForGameResultCallback_t callbacks will follow when players are found
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::RequestPlayersForGame( int nPlayerMin, int nPlayerMax, int nMaxTeamSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// accept the player list and release connection details to players
|
||||||
|
// players will only be given connection details and host steamid when this is called
|
||||||
|
// ( allows host to accept after all players confirm, some confirm, or none confirm. decision is entirely up to the host )
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::HostConfirmGameStart( uint64 ullUniqueGameID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// cancel request and leave the pool of game hosts looking for players
|
||||||
|
// if a set of players has already been sent to host, all players will receive SearchForGameHostFailedToConfirm_t
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::CancelRequestPlayersForGame()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// submit a result for one player. does not end the game. ullUniqueGameID continues to describe this game
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::SubmitPlayerResult( uint64 ullUniqueGameID, CSteamID steamIDPlayer, EPlayerResult_t EPlayerResult )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ends the game. no further SubmitPlayerResults for ullUniqueGameID will be accepted
|
||||||
|
// any future requests will provide a new ullUniqueGameID
|
||||||
|
EGameSearchErrorCode_t Steam_Game_Search::EndGame( uint64 ullUniqueGameID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EGameSearchErrorCode_Failed_Offline;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Game_Search::RunCallbacks()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Game_Search::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_sockets()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -20,20 +20,24 @@
|
|||||||
|
|
||||||
#define SEND_SERVER_RATE 5.0
|
#define SEND_SERVER_RATE 5.0
|
||||||
|
|
||||||
|
|
||||||
Steam_GameServer::Steam_GameServer(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks)
|
Steam_GameServer::Steam_GameServer(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks)
|
||||||
{
|
{
|
||||||
this->network = network;
|
this->network = network;
|
||||||
this->settings = settings;
|
this->settings = settings;
|
||||||
server_data.set_id(settings->get_local_steam_id().ConvertToUint64());
|
|
||||||
this->callbacks = callbacks;
|
this->callbacks = callbacks;
|
||||||
auth_manager = new Auth_Manager(settings, network, callbacks);
|
auth_manager = new Auth_Manager(settings, network, callbacks);
|
||||||
|
|
||||||
|
server_data.set_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam_GameServer::~Steam_GameServer()
|
Steam_GameServer::~Steam_GameServer()
|
||||||
{
|
{
|
||||||
delete auth_manager;
|
delete auth_manager;
|
||||||
|
auth_manager = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>>* Steam_GameServer::get_players()
|
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>>* Steam_GameServer::get_players()
|
||||||
{
|
{
|
||||||
return &players;
|
return &players;
|
||||||
@ -803,6 +807,8 @@ SteamAPICall_t Steam_GameServer::ComputeNewPlayerCompatibility( CSteamID steamID
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Steam_GameServer::RunCallbacks()
|
void Steam_GameServer::RunCallbacks()
|
||||||
{
|
{
|
||||||
bool temp_call_servers_connected = call_servers_connected;
|
bool temp_call_servers_connected = call_servers_connected;
|
||||||
|
963
dll/steam_inventory.cpp
Normal file
963
dll/steam_inventory.cpp
Normal file
@ -0,0 +1,963 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_inventory.h"
|
||||||
|
|
||||||
|
|
||||||
|
bool Steam_Inventory_Requests::result_done() const
|
||||||
|
{
|
||||||
|
return done;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Steam_Inventory_Requests::timestamp() const
|
||||||
|
{
|
||||||
|
return std::chrono::duration_cast<std::chrono::duration<uint32>>(time_created.time_since_epoch()).count();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
struct Steam_Inventory_Requests* Steam_Inventory::new_inventory_result(bool full_query, const SteamItemInstanceID_t* pInstanceIDs, uint32 unCountInstanceIDs)
|
||||||
|
{
|
||||||
|
static SteamInventoryResult_t result;
|
||||||
|
++result;
|
||||||
|
|
||||||
|
struct Steam_Inventory_Requests request;
|
||||||
|
request.inventory_result = result;
|
||||||
|
request.full_query = full_query;
|
||||||
|
if (pInstanceIDs && unCountInstanceIDs) {
|
||||||
|
request.instance_ids.reserve(unCountInstanceIDs);
|
||||||
|
std::copy(pInstanceIDs, pInstanceIDs + unCountInstanceIDs, std::back_inserter(request.instance_ids));
|
||||||
|
}
|
||||||
|
|
||||||
|
request.time_created = std::chrono::system_clock::now();
|
||||||
|
inventory_requests.push_back(request);
|
||||||
|
|
||||||
|
return &(inventory_requests.back());
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Steam_Inventory_Requests* Steam_Inventory::get_inventory_result(SteamInventoryResult_t resultHandle)
|
||||||
|
{
|
||||||
|
auto request = std::find_if(inventory_requests.begin(), inventory_requests.end(), [&resultHandle](struct Steam_Inventory_Requests const& item) { return item.inventory_result == resultHandle; });
|
||||||
|
if (inventory_requests.end() == request)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &(*request);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Inventory::read_items_db()
|
||||||
|
{
|
||||||
|
std::string items_db_path = Local_Storage::get_game_settings_path() + items_user_file;
|
||||||
|
PRINT_DEBUG("file path: %s", items_db_path.c_str());
|
||||||
|
local_storage->load_json(items_db_path, defined_items);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Inventory::read_inventory_db()
|
||||||
|
{
|
||||||
|
// If we havn't got any inventory
|
||||||
|
if (!local_storage->load_json_file("", items_user_file, user_items))
|
||||||
|
{
|
||||||
|
// Try to load a default one
|
||||||
|
std::string items_db_path = Local_Storage::get_game_settings_path() + items_default_file;
|
||||||
|
PRINT_DEBUG("items file path: %s", items_db_path.c_str());
|
||||||
|
local_storage->load_json(items_db_path, user_items);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Inventory::run_every_runcb_cb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Inventory *obj = (Steam_Inventory *)object;
|
||||||
|
obj->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Inventory::Steam_Inventory(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb, class Local_Storage *local_storage):
|
||||||
|
settings(settings),
|
||||||
|
callback_results(callback_results),
|
||||||
|
callbacks(callbacks),
|
||||||
|
run_every_runcb(run_every_runcb),
|
||||||
|
local_storage(local_storage),
|
||||||
|
|
||||||
|
defined_items(nlohmann::json::object()),
|
||||||
|
user_items(nlohmann::json::object()),
|
||||||
|
|
||||||
|
inventory_loaded(false),
|
||||||
|
call_definition_update(false),
|
||||||
|
item_definitions_loaded(false)
|
||||||
|
{
|
||||||
|
this->run_every_runcb->add(&Steam_Inventory::run_every_runcb_cb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Inventory::~Steam_Inventory()
|
||||||
|
{
|
||||||
|
this->run_every_runcb->remove(&Steam_Inventory::run_every_runcb_cb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// INVENTORY ASYNC RESULT MANAGEMENT
|
||||||
|
//
|
||||||
|
// Asynchronous inventory queries always output a result handle which can be used with
|
||||||
|
// GetResultStatus, GetResultItems, etc. A SteamInventoryResultReady_t callback will
|
||||||
|
// be triggered when the asynchronous result becomes ready (or fails).
|
||||||
|
//
|
||||||
|
|
||||||
|
// Find out the status of an asynchronous inventory result handle. Possible values:
|
||||||
|
// k_EResultPending - still in progress
|
||||||
|
// k_EResultOK - done, result ready
|
||||||
|
// k_EResultExpired - done, result ready, maybe out of date (see DeserializeResult)
|
||||||
|
// k_EResultInvalidParam - ERROR: invalid API call parameters
|
||||||
|
// k_EResultServiceUnavailable - ERROR: service temporarily down, you may retry later
|
||||||
|
// k_EResultLimitExceeded - ERROR: operation would exceed per-user inventory limits
|
||||||
|
// k_EResultFail - ERROR: unknown / generic error
|
||||||
|
STEAM_METHOD_DESC(Find out the status of an asynchronous inventory result handle.)
|
||||||
|
EResult Steam_Inventory::GetResultStatus( SteamInventoryResult_t resultHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests *request = get_inventory_result(resultHandle);
|
||||||
|
if (!request) return k_EResultInvalidParam;
|
||||||
|
if (!request->result_done()) return k_EResultPending;
|
||||||
|
return k_EResultOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Copies the contents of a result set into a flat array. The specific
|
||||||
|
// contents of the result set depend on which query which was used.
|
||||||
|
STEAM_METHOD_DESC(Copies the contents of a result set into a flat array. The specific contents of the result set depend on which query which was used.)
|
||||||
|
bool Steam_Inventory::GetResultItems( SteamInventoryResult_t resultHandle,
|
||||||
|
STEAM_OUT_ARRAY_COUNT( punOutItemsArraySize,Output array) SteamItemDetails_t *pOutItemsArray,
|
||||||
|
uint32 *punOutItemsArraySize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests *request = get_inventory_result(resultHandle);
|
||||||
|
if (!request) return false;
|
||||||
|
if (!request->result_done()) return false;
|
||||||
|
if (!inventory_loaded) return false;
|
||||||
|
|
||||||
|
if (pOutItemsArray != nullptr)
|
||||||
|
{
|
||||||
|
SteamItemDetails_t *items_array_base = pOutItemsArray;
|
||||||
|
uint32 max_items = *punOutItemsArraySize;
|
||||||
|
|
||||||
|
if (request->full_query) {
|
||||||
|
// We end if we reached the end of items or the end of buffer
|
||||||
|
for( auto i = user_items.begin(); i != user_items.end() && max_items; ++i, --max_items )
|
||||||
|
{
|
||||||
|
pOutItemsArray->m_iDefinition = std::stoi(i.key());
|
||||||
|
pOutItemsArray->m_itemId = pOutItemsArray->m_iDefinition;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pOutItemsArray->m_unQuantity = i.value().get<int>();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pOutItemsArray->m_unQuantity = 0;
|
||||||
|
}
|
||||||
|
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
||||||
|
++pOutItemsArray;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
for (auto &itemid : request->instance_ids) {
|
||||||
|
if (!max_items) break;
|
||||||
|
auto it = user_items.find(std::to_string(itemid));
|
||||||
|
if (it != user_items.end()) {
|
||||||
|
pOutItemsArray->m_iDefinition = itemid;
|
||||||
|
pOutItemsArray->m_itemId = itemid;
|
||||||
|
|
||||||
|
try
|
||||||
|
{
|
||||||
|
pOutItemsArray->m_unQuantity = it->get<int>();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pOutItemsArray->m_unQuantity = 0;
|
||||||
|
}
|
||||||
|
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
||||||
|
++pOutItemsArray;
|
||||||
|
--max_items;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*punOutItemsArraySize = pOutItemsArray - items_array_base;
|
||||||
|
}
|
||||||
|
else if (punOutItemsArraySize != nullptr)
|
||||||
|
{
|
||||||
|
if (request->full_query) {
|
||||||
|
*punOutItemsArraySize = user_items.size();
|
||||||
|
} else {
|
||||||
|
*punOutItemsArraySize = std::count_if(request->instance_ids.begin(), request->instance_ids.end(), [this](SteamItemInstanceID_t item_id){ return user_items.find(std::to_string(item_id)) != user_items.end();});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("good");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// In combination with GetResultItems, you can use GetResultItemProperty to retrieve
|
||||||
|
// dynamic string properties for a given item returned in the result set.
|
||||||
|
//
|
||||||
|
// Property names are always composed of ASCII letters, numbers, and/or underscores.
|
||||||
|
//
|
||||||
|
// Pass a NULL pointer for pchPropertyName to get a comma - separated list of available
|
||||||
|
// property names.
|
||||||
|
//
|
||||||
|
// If pchValueBuffer is NULL, *punValueBufferSize will contain the
|
||||||
|
// suggested buffer size. Otherwise it will be the number of bytes actually copied
|
||||||
|
// to pchValueBuffer. If the results do not fit in the given buffer, partial
|
||||||
|
// results may be copied.
|
||||||
|
bool Steam_Inventory::GetResultItemProperty( SteamInventoryResult_t resultHandle,
|
||||||
|
uint32 unItemIndex,
|
||||||
|
const char *pchPropertyName,
|
||||||
|
STEAM_OUT_STRING_COUNT( punValueBufferSizeOut ) char *pchValueBuffer, uint32 *punValueBufferSizeOut )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the server time at which the result was generated. Compare against
|
||||||
|
// the value of IClientUtils::GetServerRealTime() to determine age.
|
||||||
|
STEAM_METHOD_DESC(Returns Steam_Inventory::the server time at which the result was generated. Compare against the value of IClientUtils::GetServerRealTime() to determine age.)
|
||||||
|
uint32 Steam_Inventory::GetResultTimestamp( SteamInventoryResult_t resultHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests *request = get_inventory_result(resultHandle);
|
||||||
|
if (!request || !request->result_done()) return 0;
|
||||||
|
return request->timestamp();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if the result belongs to the target steam ID, false if the
|
||||||
|
// result does not. This is important when using DeserializeResult, to verify
|
||||||
|
// that a remote player is not pretending to have a different user's inventory.
|
||||||
|
STEAM_METHOD_DESC(Returns true if the result belongs to the target steam ID or false if the result does not. This is important when using DeserializeResult to verify that a remote player is not pretending to have a different users inventory.)
|
||||||
|
bool Steam_Inventory::CheckResultSteamID( SteamInventoryResult_t resultHandle, CSteamID steamIDExpected )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Destroys a result handle and frees all associated memory.
|
||||||
|
STEAM_METHOD_DESC(Destroys a result handle and frees all associated memory.)
|
||||||
|
void Steam_Inventory::DestroyResult( SteamInventoryResult_t resultHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto request = std::find_if(inventory_requests.begin(), inventory_requests.end(), [&resultHandle](struct Steam_Inventory_Requests const& item) { return item.inventory_result == resultHandle; });
|
||||||
|
if (inventory_requests.end() == request)
|
||||||
|
return;
|
||||||
|
|
||||||
|
inventory_requests.erase(request);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// INVENTORY ASYNC QUERY
|
||||||
|
//
|
||||||
|
|
||||||
|
// Captures the entire state of the current user's Steam inventory.
|
||||||
|
// You must call DestroyResult on this handle when you are done with it.
|
||||||
|
// Returns false and sets *pResultHandle to zero if inventory is unavailable.
|
||||||
|
// Note: calls to this function are subject to rate limits and may return
|
||||||
|
// cached results if called too frequently. It is suggested that you call
|
||||||
|
// this function only when you are about to display the user's full inventory,
|
||||||
|
// or if you expect that the inventory may have changed.
|
||||||
|
STEAM_METHOD_DESC(Captures the entire state of the current users Steam inventory.)
|
||||||
|
bool Steam_Inventory::GetAllItems( SteamInventoryResult_t *pResultHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests* request = new_inventory_result();
|
||||||
|
|
||||||
|
if (pResultHandle != nullptr)
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Captures the state of a subset of the current user's Steam inventory,
|
||||||
|
// identified by an array of item instance IDs. The results from this call
|
||||||
|
// can be serialized and passed to other players to "prove" that the current
|
||||||
|
// user owns specific items, without exposing the user's entire inventory.
|
||||||
|
// For example, you could call GetItemsByID with the IDs of the user's
|
||||||
|
// currently equipped cosmetic items and serialize this to a buffer, and
|
||||||
|
// then transmit this buffer to other players upon joining a game.
|
||||||
|
STEAM_METHOD_DESC(Captures the state of a subset of the current users Steam inventory identified by an array of item instance IDs.)
|
||||||
|
bool Steam_Inventory::GetItemsByID( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT( unCountInstanceIDs ) const SteamItemInstanceID_t *pInstanceIDs, uint32 unCountInstanceIDs )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (pResultHandle) {
|
||||||
|
struct Steam_Inventory_Requests *request = new_inventory_result(false, pInstanceIDs, unCountInstanceIDs);
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// RESULT SERIALIZATION AND AUTHENTICATION
|
||||||
|
//
|
||||||
|
// Serialized result sets contain a short signature which can't be forged
|
||||||
|
// or replayed across different game sessions. A result set can be serialized
|
||||||
|
// on the local client, transmitted to other players via your game networking,
|
||||||
|
// and deserialized by the remote players. This is a secure way of preventing
|
||||||
|
// hackers from lying about posessing rare/high-value items.
|
||||||
|
|
||||||
|
// Serializes a result set with signature bytes to an output buffer. Pass
|
||||||
|
// NULL as an output buffer to get the required size via punOutBufferSize.
|
||||||
|
// The size of a serialized result depends on the number items which are being
|
||||||
|
// serialized. When securely transmitting items to other players, it is
|
||||||
|
// recommended to use "GetItemsByID" first to create a minimal result set.
|
||||||
|
// Results have a built-in timestamp which will be considered "expired" after
|
||||||
|
// an hour has elapsed. See DeserializeResult for expiration handling.
|
||||||
|
bool Steam_Inventory::SerializeResult( SteamInventoryResult_t resultHandle, STEAM_OUT_BUFFER_COUNT(punOutBufferSize) void *pOutBuffer, uint32 *punOutBufferSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i", resultHandle);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO
|
||||||
|
struct Steam_Inventory_Requests *request = get_inventory_result(resultHandle);
|
||||||
|
if (!request) return false;
|
||||||
|
if (!request->result_done()) return false;
|
||||||
|
|
||||||
|
uint8 buffer[8 + 128] = {};
|
||||||
|
memset(buffer, 0x5F, sizeof(buffer));
|
||||||
|
|
||||||
|
if (!punOutBufferSize) return false;
|
||||||
|
PRINT_DEBUG(" Size %u", *punOutBufferSize);
|
||||||
|
if (!pOutBuffer) {
|
||||||
|
*punOutBufferSize = sizeof(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*punOutBufferSize < sizeof(buffer)) {
|
||||||
|
*punOutBufferSize = sizeof(buffer);
|
||||||
|
return false; //??
|
||||||
|
}
|
||||||
|
|
||||||
|
memcpy(pOutBuffer, buffer, sizeof(buffer));
|
||||||
|
*punOutBufferSize = sizeof(buffer);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Deserializes a result set and verifies the signature bytes. Returns false
|
||||||
|
// if bRequireFullOnlineVerify is set but Steam is running in Offline mode.
|
||||||
|
// Otherwise returns true and then delivers error codes via GetResultStatus.
|
||||||
|
//
|
||||||
|
// The bRESERVED_MUST_BE_FALSE flag is reserved for future use and should not
|
||||||
|
// be set to true by your game at this time.
|
||||||
|
//
|
||||||
|
// DeserializeResult has a potential soft-failure mode where the handle status
|
||||||
|
// is set to k_EResultExpired. GetResultItems() still succeeds in this mode.
|
||||||
|
// The "expired" result could indicate that the data may be out of date - not
|
||||||
|
// just due to timed expiration (one hour), but also because one of the items
|
||||||
|
// in the result set may have been traded or consumed since the result set was
|
||||||
|
// generated. You could compare the timestamp from GetResultTimestamp() to
|
||||||
|
// ISteamUtils::GetServerRealTime() to determine how old the data is. You could
|
||||||
|
// simply ignore the "expired" result code and continue as normal, or you
|
||||||
|
// could challenge the player with expired data to send an updated result set.
|
||||||
|
bool Steam_Inventory::DeserializeResult( SteamInventoryResult_t *pOutResultHandle, STEAM_BUFFER_COUNT(punOutBufferSize) const void *pBuffer, uint32 unBufferSize, bool bRESERVED_MUST_BE_FALSE)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO
|
||||||
|
if (pOutResultHandle) {
|
||||||
|
struct Steam_Inventory_Requests *request = new_inventory_result(false);
|
||||||
|
*pOutResultHandle = request->inventory_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// INVENTORY ASYNC MODIFICATION
|
||||||
|
//
|
||||||
|
|
||||||
|
// GenerateItems() creates one or more items and then generates a SteamInventoryCallback_t
|
||||||
|
// notification with a matching nCallbackContext parameter. This API is only intended
|
||||||
|
// for prototyping - it is only usable by Steam accounts that belong to the publisher group
|
||||||
|
// for your game.
|
||||||
|
// If punArrayQuantity is not NULL, it should be the same length as pArrayItems and should
|
||||||
|
// describe the quantity of each item to generate.
|
||||||
|
bool Steam_Inventory::GenerateItems( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, STEAM_ARRAY_COUNT(unArrayLength) const uint32 *punArrayQuantity, uint32 unArrayLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GrantPromoItems() checks the list of promotional items for which the user may be eligible
|
||||||
|
// and grants the items (one time only). On success, the result set will include items which
|
||||||
|
// were granted, if any. If no items were granted because the user isn't eligible for any
|
||||||
|
// promotions, this is still considered a success.
|
||||||
|
STEAM_METHOD_DESC(GrantPromoItems() Steam_Inventory::checks the list of promotional items for which the user may be eligible and grants the items (one time only).)
|
||||||
|
bool Steam_Inventory::GrantPromoItems( SteamInventoryResult_t *pResultHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests* request = new_inventory_result(false);
|
||||||
|
|
||||||
|
if (pResultHandle != nullptr)
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AddPromoItem() / AddPromoItems() are restricted versions of GrantPromoItems(). Instead of
|
||||||
|
// scanning for all eligible promotional items, the check is restricted to a single item
|
||||||
|
// definition or set of item definitions. This can be useful if your game has custom UI for
|
||||||
|
// showing a specific promo item to the user.
|
||||||
|
bool Steam_Inventory::AddPromoItem( SteamInventoryResult_t *pResultHandle, SteamItemDef_t itemDef )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
//TODO
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests* request = new_inventory_result(false);
|
||||||
|
|
||||||
|
if (pResultHandle != nullptr)
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::AddPromoItems( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, uint32 unArrayLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
//TODO
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests* request = new_inventory_result(false);
|
||||||
|
|
||||||
|
if (pResultHandle != nullptr)
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ConsumeItem() removes items from the inventory, permanently. They cannot be recovered.
|
||||||
|
// Not for the faint of heart - if your game implements item removal at all, a high-friction
|
||||||
|
// UI confirmation process is highly recommended.
|
||||||
|
STEAM_METHOD_DESC(ConsumeItem() removes items from the inventory permanently.)
|
||||||
|
bool Steam_Inventory::ConsumeItem( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemConsume, uint32 unQuantity )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%llu %u", itemConsume, unQuantity);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
auto it = user_items.find(std::to_string(itemConsume));
|
||||||
|
if (it != user_items.end()) {
|
||||||
|
try
|
||||||
|
{
|
||||||
|
uint32 current = it->get<int>();
|
||||||
|
PRINT_DEBUG("previous %u", current);
|
||||||
|
if (current < unQuantity) unQuantity = current;
|
||||||
|
uint32 result = current - unQuantity;
|
||||||
|
if (result == 0) {
|
||||||
|
user_items.erase(it);
|
||||||
|
} else {
|
||||||
|
*it = result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch (...) {}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Steam_Inventory_Requests* request = new_inventory_result(false, &itemConsume, 1);
|
||||||
|
|
||||||
|
if (pResultHandle != nullptr)
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// ExchangeItems() is an atomic combination of item generation and consumption.
|
||||||
|
// It can be used to implement crafting recipes or transmutations, or items which unpack
|
||||||
|
// themselves into other items (e.g., a chest).
|
||||||
|
// Exchange recipes are defined in the ItemDef, and explicitly list the required item
|
||||||
|
// types and resulting generated type.
|
||||||
|
// Exchange recipes are evaluated atomically by the Inventory Service; if the supplied
|
||||||
|
// components do not match the recipe, or do not contain sufficient quantity, the
|
||||||
|
// exchange will fail.
|
||||||
|
bool Steam_Inventory::ExchangeItems( SteamInventoryResult_t *pResultHandle,
|
||||||
|
STEAM_ARRAY_COUNT(unArrayGenerateLength) const SteamItemDef_t *pArrayGenerate, STEAM_ARRAY_COUNT(unArrayGenerateLength) const uint32 *punArrayGenerateQuantity, uint32 unArrayGenerateLength,
|
||||||
|
STEAM_ARRAY_COUNT(unArrayDestroyLength) const SteamItemInstanceID_t *pArrayDestroy, STEAM_ARRAY_COUNT(unArrayDestroyLength) const uint32 *punArrayDestroyQuantity, uint32 unArrayDestroyLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TransferItemQuantity() is intended for use with items which are "stackable" (can have
|
||||||
|
// quantity greater than one). It can be used to split a stack into two, or to transfer
|
||||||
|
// quantity from one stack into another stack of identical items. To split one stack into
|
||||||
|
// two, pass k_SteamItemInstanceIDInvalid for itemIdDest and a new item will be generated.
|
||||||
|
bool Steam_Inventory::TransferItemQuantity( SteamInventoryResult_t *pResultHandle, SteamItemInstanceID_t itemIdSource, uint32 unQuantity, SteamItemInstanceID_t itemIdDest )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// TIMED DROPS AND PLAYTIME CREDIT
|
||||||
|
//
|
||||||
|
|
||||||
|
// Deprecated. Calling this method is not required for proper playtime accounting.
|
||||||
|
STEAM_METHOD_DESC( Deprecated method. Playtime accounting is performed on the Steam servers. )
|
||||||
|
void Steam_Inventory::SendItemDropHeartbeat()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Playtime credit must be consumed and turned into item drops by your game. Only item
|
||||||
|
// definitions which are marked as "playtime item generators" can be spawned. The call
|
||||||
|
// will return an empty result set if there is not enough playtime credit for a drop.
|
||||||
|
// Your game should call TriggerItemDrop at an appropriate time for the user to receive
|
||||||
|
// new items, such as between rounds or while the player is dead. Note that players who
|
||||||
|
// hack their clients could modify the value of "dropListDefinition", so do not use it
|
||||||
|
// to directly control rarity.
|
||||||
|
// See your Steamworks configuration to set playtime drop rates for individual itemdefs.
|
||||||
|
// The client library will suppress too-frequent calls to this method.
|
||||||
|
STEAM_METHOD_DESC(Playtime credit must be consumed and turned into item drops by your game.)
|
||||||
|
bool Steam_Inventory::TriggerItemDrop( SteamInventoryResult_t *pResultHandle, SteamItemDef_t dropListDefinition )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p %i", pResultHandle, dropListDefinition);
|
||||||
|
//TODO: if gameserver return false
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Inventory_Requests* request = new_inventory_result(false);
|
||||||
|
|
||||||
|
if (pResultHandle != nullptr)
|
||||||
|
*pResultHandle = request->inventory_result;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Deprecated. This method is not supported.
|
||||||
|
bool Steam_Inventory::TradeItems( SteamInventoryResult_t *pResultHandle, CSteamID steamIDTradePartner,
|
||||||
|
STEAM_ARRAY_COUNT(nArrayGiveLength) const SteamItemInstanceID_t *pArrayGive, STEAM_ARRAY_COUNT(nArrayGiveLength) const uint32 *pArrayGiveQuantity, uint32 nArrayGiveLength,
|
||||||
|
STEAM_ARRAY_COUNT(nArrayGetLength) const SteamItemInstanceID_t *pArrayGet, STEAM_ARRAY_COUNT(nArrayGetLength) const uint32 *pArrayGetQuantity, uint32 nArrayGetLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// ITEM DEFINITIONS
|
||||||
|
//
|
||||||
|
// Item definitions are a mapping of "definition IDs" (integers between 1 and 1000000)
|
||||||
|
// to a set of string properties. Some of these properties are required to display items
|
||||||
|
// on the Steam community web site. Other properties can be defined by applications.
|
||||||
|
// Use of these functions is optional; there is no reason to call LoadItemDefinitions
|
||||||
|
// if your game hardcodes the numeric definition IDs (eg, purple face mask = 20, blue
|
||||||
|
// weapon mod = 55) and does not allow for adding new item types without a client patch.
|
||||||
|
//
|
||||||
|
|
||||||
|
// LoadItemDefinitions triggers the automatic load and refresh of item definitions.
|
||||||
|
// Every time new item definitions are available (eg, from the dynamic addition of new
|
||||||
|
// item types while players are still in-game), a SteamInventoryDefinitionUpdate_t
|
||||||
|
// callback will be fired.
|
||||||
|
STEAM_METHOD_DESC(LoadItemDefinitions triggers the automatic load and refresh of item definitions.)
|
||||||
|
bool Steam_Inventory::LoadItemDefinitions()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
if (!item_definitions_loaded) {
|
||||||
|
call_definition_update = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
//real steam launches a SteamInventoryResultReady_t which is why I create a new inventory result
|
||||||
|
new_inventory_result(false);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GetItemDefinitionIDs returns the set of all defined item definition IDs (which are
|
||||||
|
// defined via Steamworks configuration, and not necessarily contiguous integers).
|
||||||
|
// If pItemDefIDs is null, the call will return true and *punItemDefIDsArraySize will
|
||||||
|
// contain the total size necessary for a subsequent call. Otherwise, the call will
|
||||||
|
// return false if and only if there is not enough space in the output array.
|
||||||
|
bool Steam_Inventory::GetItemDefinitionIDs(
|
||||||
|
STEAM_OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs,
|
||||||
|
STEAM_DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p", pItemDefIDs);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (!punItemDefIDsArraySize)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
PRINT_DEBUG(" array_size %u", *punItemDefIDsArraySize);
|
||||||
|
|
||||||
|
if (!item_definitions_loaded)
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (pItemDefIDs == nullptr || *punItemDefIDsArraySize == 0)
|
||||||
|
{
|
||||||
|
*punItemDefIDsArraySize = defined_items.size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (*punItemDefIDsArraySize < defined_items.size())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
for (auto i = defined_items.begin(); i != defined_items.end(); ++i)
|
||||||
|
*pItemDefIDs++ = std::stoi(i.key());
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// GetItemDefinitionProperty returns a string property from a given item definition.
|
||||||
|
// Note that some properties (for example, "name") may be localized and will depend
|
||||||
|
// on the current Steam language settings (see ISteamApps::GetCurrentGameLanguage).
|
||||||
|
// Property names are always composed of ASCII letters, numbers, and/or underscores.
|
||||||
|
// Pass a NULL pointer for pchPropertyName to get a comma - separated list of available
|
||||||
|
// property names. If pchValueBuffer is NULL, *punValueBufferSize will contain the
|
||||||
|
// suggested buffer size. Otherwise it will be the number of bytes actually copied
|
||||||
|
// to pchValueBuffer. If the results do not fit in the given buffer, partial
|
||||||
|
// results may be copied.
|
||||||
|
bool Steam_Inventory::GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPropertyName,
|
||||||
|
STEAM_OUT_STRING_COUNT(punValueBufferSizeOut) char *pchValueBuffer, uint32 *punValueBufferSizeOut )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i %s", iDefinition, pchPropertyName);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
auto item = defined_items.find(std::to_string(iDefinition));
|
||||||
|
if (item != defined_items.end())
|
||||||
|
{
|
||||||
|
if (pchPropertyName != nullptr)
|
||||||
|
{
|
||||||
|
// Should I check for punValueBufferSizeOut == nullptr ?
|
||||||
|
// Try to get the property
|
||||||
|
auto attr = item.value().find(pchPropertyName);
|
||||||
|
if (attr != item.value().end())
|
||||||
|
{
|
||||||
|
std::string val;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
val = attr.value().get<std::string>();
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
pchPropertyName = "";
|
||||||
|
*punValueBufferSizeOut = 0;
|
||||||
|
PRINT_DEBUG(" Error, item: %d, attr: %s is not a string!", iDefinition, pchPropertyName);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
if (pchValueBuffer != nullptr)
|
||||||
|
{
|
||||||
|
// copy what we can
|
||||||
|
strncpy(pchValueBuffer, val.c_str(), *punValueBufferSizeOut);
|
||||||
|
*punValueBufferSizeOut = std::min(static_cast<uint32>(val.length() + 1), *punValueBufferSizeOut);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// Set punValueBufferSizeOut to the property size
|
||||||
|
*punValueBufferSizeOut = val.length() + 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pchValueBuffer != nullptr)
|
||||||
|
{
|
||||||
|
// Make sure we have a null terminator
|
||||||
|
pchValueBuffer[*punValueBufferSizeOut-1] = '\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Property not found
|
||||||
|
else
|
||||||
|
{
|
||||||
|
*punValueBufferSizeOut = 0;
|
||||||
|
PRINT_DEBUG(" Attr %s not found for item %d", pchPropertyName, iDefinition);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else // Pass a NULL pointer for pchPropertyName to get a comma - separated list of available property names.
|
||||||
|
{
|
||||||
|
// If pchValueBuffer is NULL, *punValueBufferSize will contain the suggested buffer size
|
||||||
|
if (pchValueBuffer == nullptr)
|
||||||
|
{
|
||||||
|
// Should I check for punValueBufferSizeOut == nullptr ?
|
||||||
|
*punValueBufferSizeOut = 0;
|
||||||
|
for (auto i = item.value().begin(); i != item.value().end(); ++i)
|
||||||
|
*punValueBufferSizeOut += i.key().length() + 1; // Size of key + comma, and the last is not a comma but null char
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// strncat always add the null terminator, so remove 1 to the string length
|
||||||
|
uint32_t len = *punValueBufferSizeOut-1;
|
||||||
|
*punValueBufferSizeOut = 0;
|
||||||
|
memset(pchValueBuffer, 0, len);
|
||||||
|
for( auto i = item.value().begin(); i != item.value().end() && len > 0; ++i )
|
||||||
|
{
|
||||||
|
strncat(pchValueBuffer, i.key().c_str(), len);
|
||||||
|
// Count how many chars we copied
|
||||||
|
// Either the string length or the buffer size if its too small
|
||||||
|
uint32 x = std::min(len, static_cast<uint32>(i.key().length()));
|
||||||
|
*punValueBufferSizeOut += x;
|
||||||
|
len -= x;
|
||||||
|
|
||||||
|
if (len && std::distance(i, item.value().end()) != 1) // If this is not the last item, add a comma
|
||||||
|
strncat(pchValueBuffer, ",", len--);
|
||||||
|
|
||||||
|
// Always add 1, its a comma or the null terminator
|
||||||
|
++*punValueBufferSizeOut;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Request the list of "eligible" promo items that can be manually granted to the given
|
||||||
|
// user. These are promo items of type "manual" that won't be granted automatically.
|
||||||
|
// An example usage of this is an item that becomes available every week.
|
||||||
|
STEAM_CALL_RESULT( SteamInventoryEligiblePromoItemDefIDs_t )
|
||||||
|
SteamAPICall_t Steam_Inventory::RequestEligiblePromoItemDefinitionsIDs( CSteamID steamID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// After handling a SteamInventoryEligiblePromoItemDefIDs_t call result, use this
|
||||||
|
// function to pull out the list of item definition ids that the user can be
|
||||||
|
// manually granted via the AddPromoItems() call.
|
||||||
|
bool Steam_Inventory::GetEligiblePromoItemDefinitionIDs(
|
||||||
|
CSteamID steamID,
|
||||||
|
STEAM_OUT_ARRAY_COUNT(punItemDefIDsArraySize,List of item definition IDs) SteamItemDef_t *pItemDefIDs,
|
||||||
|
STEAM_DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Starts the purchase process for the given item definitions. The callback SteamInventoryStartPurchaseResult_t
|
||||||
|
// will be posted if Steam was able to initialize the transaction.
|
||||||
|
//
|
||||||
|
// Once the purchase has been authorized and completed by the user, the callback SteamInventoryResultReady_t
|
||||||
|
// will be posted.
|
||||||
|
STEAM_CALL_RESULT( SteamInventoryStartPurchaseResult_t )
|
||||||
|
SteamAPICall_t Steam_Inventory::StartPurchase( STEAM_ARRAY_COUNT(unArrayLength) const SteamItemDef_t *pArrayItemDefs, STEAM_ARRAY_COUNT(unArrayLength) const uint32 *punArrayQuantity, uint32 unArrayLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Request current prices for all applicable item definitions
|
||||||
|
STEAM_CALL_RESULT( SteamInventoryRequestPricesResult_t )
|
||||||
|
SteamAPICall_t Steam_Inventory::RequestPrices()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
SteamInventoryRequestPricesResult_t data{};
|
||||||
|
data.m_result = k_EResultOK;
|
||||||
|
memcpy(data.m_rgchCurrency, "USD", 4);
|
||||||
|
|
||||||
|
auto ret = callback_results->addCallResult(data.k_iCallback, &data, sizeof(data), 0.2);
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.2);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the number of items with prices. Need to call RequestPrices() first.
|
||||||
|
uint32 Steam_Inventory::GetNumItemsWithPrices()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::GetItemsWithPrices( STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pArrayItemDefs, Items with prices) SteamItemDef_t *pArrayItemDefs,
|
||||||
|
STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pPrices, List of prices for the given item defs) uint64 *pCurrentPrices,
|
||||||
|
STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pPrices, List of prices for the given item defs) uint64 *pBasePrices,
|
||||||
|
uint32 unArrayLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns item definition ids and their prices in the user's local currency.
|
||||||
|
// Need to call RequestPrices() first.
|
||||||
|
bool Steam_Inventory::GetItemsWithPrices( STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pArrayItemDefs, Items with prices) SteamItemDef_t *pArrayItemDefs,
|
||||||
|
STEAM_ARRAY_COUNT(unArrayLength) STEAM_OUT_ARRAY_COUNT(pPrices, List of prices for the given item defs) uint64 *pPrices,
|
||||||
|
uint32 unArrayLength )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return GetItemsWithPrices(pArrayItemDefs, pPrices, NULL, unArrayLength);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::GetItemPrice( SteamItemDef_t iDefinition, uint64 *pCurrentPrice, uint64 *pBasePrice )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves the price for the item definition id
|
||||||
|
// Returns false if there is no price stored for the item definition.
|
||||||
|
bool Steam_Inventory::GetItemPrice( SteamItemDef_t iDefinition, uint64 *pPrice )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return GetItemPrice(iDefinition, pPrice, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create a request to update properties on items
|
||||||
|
SteamInventoryUpdateHandle_t Steam_Inventory::StartUpdateProperties()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove the property on the item
|
||||||
|
bool Steam_Inventory::RemoveProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accessor methods to set properties on items
|
||||||
|
bool Steam_Inventory::SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, const char *pchPropertyValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, bool bValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, int64 nValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::SetProperty( SteamInventoryUpdateHandle_t handle, SteamItemInstanceID_t nItemID, const char *pchPropertyName, float flValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Submit the update request by handle
|
||||||
|
bool Steam_Inventory::SubmitUpdateProperties( SteamInventoryUpdateHandle_t handle, SteamInventoryResult_t * pResultHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Inventory::InspectItem( SteamInventoryResult_t *pResultHandle, const char *pchItemToken )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Inventory::RunCallbacks()
|
||||||
|
{
|
||||||
|
if (call_definition_update || !inventory_requests.empty()) {
|
||||||
|
if (!item_definitions_loaded) {
|
||||||
|
read_items_db();
|
||||||
|
item_definitions_loaded = true;
|
||||||
|
|
||||||
|
//only gets called once
|
||||||
|
//also gets called when getting items
|
||||||
|
SteamInventoryDefinitionUpdate_t data = {};
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), 0.05);
|
||||||
|
}
|
||||||
|
|
||||||
|
call_definition_update = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!inventory_requests.empty() && !inventory_loaded) {
|
||||||
|
read_inventory_db();
|
||||||
|
inventory_loaded = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (inventory_loaded)
|
||||||
|
{
|
||||||
|
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||||
|
for (auto& r : inventory_requests) {
|
||||||
|
if (!r.done && std::chrono::duration_cast<std::chrono::duration<double>>(now - r.time_created).count() > r.timeout) {
|
||||||
|
if (r.full_query) {
|
||||||
|
// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems
|
||||||
|
// successfully returns a result which is newer / fresher than the last
|
||||||
|
// known result.
|
||||||
|
struct SteamInventoryFullUpdate_t data;
|
||||||
|
data.m_handle = r.inventory_result;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
struct SteamInventoryResultReady_t data;
|
||||||
|
data.m_handle = r.inventory_result;
|
||||||
|
data.m_result = k_EResultOK;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
r.done = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
224
dll/steam_masterserver_updater.cpp
Normal file
224
dll/steam_masterserver_updater.cpp
Normal file
@ -0,0 +1,224 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_masterserver_updater.h"
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Masterserver_Updater::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Masterserver_Updater *steam_masterserverupdater = (Steam_Masterserver_Updater *)object;
|
||||||
|
steam_masterserverupdater->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Masterserver_Updater::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Masterserver_Updater *steam_masterserverupdater = (Steam_Masterserver_Updater *)object;
|
||||||
|
steam_masterserverupdater->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Masterserver_Updater::Steam_Masterserver_Updater(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Masterserver_Updater::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Masterserver_Updater::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Masterserver_Updater::~Steam_Masterserver_Updater()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Masterserver_Updater::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Masterserver_Updater::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call this as often as you like to tell the master server updater whether or not
|
||||||
|
// you want it to be active (default: off).
|
||||||
|
void Steam_Masterserver_Updater::SetActive( bool bActive )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// You usually don't need to modify this.
|
||||||
|
// Pass -1 to use the default value for iHeartbeatInterval.
|
||||||
|
// Some mods change this.
|
||||||
|
void Steam_Masterserver_Updater::SetHeartbeatInterval( int iHeartbeatInterval )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// These are in GameSocketShare mode, where instead of ISteamMasterServerUpdater creating its own
|
||||||
|
// socket to talk to the master server on, it lets the game use its socket to forward messages
|
||||||
|
// back and forth. This prevents us from requiring server ops to open up yet another port
|
||||||
|
// in their firewalls.
|
||||||
|
//
|
||||||
|
// the IP address and port should be in host order, i.e 127.0.0.1 == 0x7f000001
|
||||||
|
|
||||||
|
// These are used when you've elected to multiplex the game server's UDP socket
|
||||||
|
// rather than having the master server updater use its own sockets.
|
||||||
|
//
|
||||||
|
// Source games use this to simplify the job of the server admins, so they
|
||||||
|
// don't have to open up more ports on their firewalls.
|
||||||
|
|
||||||
|
// Call this when a packet that starts with 0xFFFFFFFF comes in. That means
|
||||||
|
// it's for us.
|
||||||
|
bool Steam_Masterserver_Updater::HandleIncomingPacket( const void *pData, int cbData, uint32 srcIP, uint16 srcPort )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// AFTER calling HandleIncomingPacket for any packets that came in that frame, call this.
|
||||||
|
// This gets a packet that the master server updater needs to send out on UDP.
|
||||||
|
// It returns the length of the packet it wants to send, or 0 if there are no more packets to send.
|
||||||
|
// Call this each frame until it returns 0.
|
||||||
|
int Steam_Masterserver_Updater::GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *pNetAdr, uint16 *pPort )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Functions to set various fields that are used to respond to queries.
|
||||||
|
|
||||||
|
// Call this to set basic data that is passed to the server browser.
|
||||||
|
void Steam_Masterserver_Updater::SetBasicServerData(
|
||||||
|
unsigned short nProtocolVersion,
|
||||||
|
bool bDedicatedServer,
|
||||||
|
const char *pRegionName,
|
||||||
|
const char *pProductName,
|
||||||
|
unsigned short nMaxReportedClients,
|
||||||
|
bool bPasswordProtected,
|
||||||
|
const char *pGameDescription )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call this to clear the whole list of key/values that are sent in rules queries.
|
||||||
|
void Steam_Masterserver_Updater::ClearAllKeyValues()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call this to add/update a key/value pair.
|
||||||
|
void Steam_Masterserver_Updater::SetKeyValue( const char *pKey, const char *pValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("TODO '%s'='%s'", pKey, pValue);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// You can call this upon shutdown to clear out data stored for this game server and
|
||||||
|
// to tell the master servers that this server is going away.
|
||||||
|
void Steam_Masterserver_Updater::NotifyShutdown()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if the master server has requested a restart.
|
||||||
|
// Only returns true once per request.
|
||||||
|
bool Steam_Masterserver_Updater::WasRestartRequested()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Force it to request a heartbeat from the master servers.
|
||||||
|
void Steam_Masterserver_Updater::ForceHeartbeat()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Manually edit and query the master server list.
|
||||||
|
// It will provide name resolution and use the default master server port if none is provided.
|
||||||
|
bool Steam_Masterserver_Updater::AddMasterServer( const char *pServerAddress )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Masterserver_Updater::RemoveMasterServer( const char *pServerAddress )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Steam_Masterserver_Updater::GetNumMasterServers()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns the # of bytes written to pOut.
|
||||||
|
int Steam_Masterserver_Updater::GetMasterServerAddress( int iServer, char *pOut, int outBufferSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Masterserver_Updater::RunCallbacks()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Masterserver_Updater::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
1624
dll/steam_matchmaking.cpp
Normal file
1624
dll/steam_matchmaking.cpp
Normal file
File diff suppressed because it is too large
Load Diff
@ -17,35 +17,51 @@
|
|||||||
|
|
||||||
#include "dll/dll.h"
|
#include "dll/dll.h"
|
||||||
|
|
||||||
|
#define SERVER_TIMEOUT 10.0
|
||||||
|
#define DIRECT_IP_DELAY 0.05
|
||||||
|
|
||||||
static void network_callback(void *object, Common_Message *msg)
|
|
||||||
|
static HServerQuery new_server_query()
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("steam_matchmaking_servers_callback");
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
static unsigned int a = 0;
|
||||||
|
++a;
|
||||||
|
if (!a) ++a;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Matchmaking_Servers::network_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
Steam_Matchmaking_Servers *obj = (Steam_Matchmaking_Servers *)object;
|
Steam_Matchmaking_Servers *obj = (Steam_Matchmaking_Servers *)object;
|
||||||
obj->Callback(msg);
|
obj->Callback(msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
Steam_Matchmaking_Servers::Steam_Matchmaking_Servers(class Settings *settings, class Local_Storage *local_storage, class Networking *network)
|
Steam_Matchmaking_Servers::Steam_Matchmaking_Servers(class Settings *settings, class Local_Storage *local_storage, class Networking *network)
|
||||||
{
|
{
|
||||||
this->settings = settings;
|
this->settings = settings;
|
||||||
this->local_storage = local_storage;
|
this->local_storage = local_storage;
|
||||||
this->network = network;
|
this->network = network;
|
||||||
this->network->setCallback(CALLBACK_ID_GAMESERVER, (uint64) 0, &network_callback, this);
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_GAMESERVER, (uint64)0, &network_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam_Matchmaking_Servers::~Steam_Matchmaking_Servers()
|
Steam_Matchmaking_Servers::~Steam_Matchmaking_Servers()
|
||||||
{
|
{
|
||||||
this->network->rmCallback(CALLBACK_ID_GAMESERVER, (uint64) 0, &network_callback, this);
|
this->network->rmCallback(CALLBACK_ID_GAMESERVER, (uint64)0, &network_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
static unsigned server_list_request = 0;
|
|
||||||
|
|
||||||
HServerListRequest Steam_Matchmaking_Servers::RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type)
|
HServerListRequest Steam_Matchmaking_Servers::RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type)
|
||||||
{
|
{
|
||||||
PRINT_DEBUG("%u %p, %i", iApp, pRequestServersResponse, (int)type);
|
PRINT_DEBUG("%u %p, %i", iApp, pRequestServersResponse, (int)type);
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
static unsigned server_list_request = 0;
|
||||||
|
|
||||||
++server_list_request;
|
++server_list_request;
|
||||||
if (!server_list_request) server_list_request = 1;
|
if (!server_list_request) server_list_request = 1;
|
||||||
HServerListRequest id = (char *)0 + server_list_request; // (char *)0 silences the compiler warning
|
HServerListRequest id = (char *)0 + server_list_request; // (char *)0 silences the compiler warning
|
||||||
@ -353,6 +369,221 @@ void Steam_Matchmaking_Servers::ReleaseRequest( HServerListRequest hServerListRe
|
|||||||
- Server passes the filter if it's a linux server
|
- Server passes the filter if it's a linux server
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
// Get details on a given server in the list, you can get the valid range of index
|
||||||
|
// values by calling GetServerCount(). You will also receive index values in
|
||||||
|
// ISteamMatchmakingServerListResponse::ServerResponded() callbacks
|
||||||
|
gameserveritem_t *Steam_Matchmaking_Servers::GetServerDetails( HServerListRequest hRequest, int iServer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p %i", hRequest, iServer);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers_filtered;
|
||||||
|
auto g = std::begin(requests);
|
||||||
|
while (g != std::end(requests)) {
|
||||||
|
PRINT_DEBUG(" equal? %p %p", hRequest, g->id);
|
||||||
|
if (g->id == hRequest) {
|
||||||
|
gameservers_filtered = g->gameservers_filtered;
|
||||||
|
PRINT_DEBUG(" found %zu", gameservers_filtered.size());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++g;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (iServer >= gameservers_filtered.size() || iServer < 0) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gameserver *gs = &gameservers_filtered[iServer].server;
|
||||||
|
gameserveritem_t *server = new gameserveritem_t(); //TODO: is the new here ok?
|
||||||
|
server_details(gs, server);
|
||||||
|
PRINT_DEBUG(" Returned server details");
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cancel an request which is operation on the given list type. You should call this to cancel
|
||||||
|
// any in-progress requests before destructing a callback object that may have been passed
|
||||||
|
// to one of the above list request calls. Not doing so may result in a crash when a callback
|
||||||
|
// occurs on the destructed object.
|
||||||
|
// Canceling a query does not release the allocated request handle.
|
||||||
|
// The request handle must be released using ReleaseRequest( hRequest )
|
||||||
|
void Steam_Matchmaking_Servers::CancelQuery( HServerListRequest hRequest )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p", hRequest);
|
||||||
|
auto g = std::begin(requests);
|
||||||
|
while (g != std::end(requests)) {
|
||||||
|
if (g->id == hRequest) {
|
||||||
|
g->cancelled = true;
|
||||||
|
PRINT_DEBUG("canceled request with id: %p", g->id);
|
||||||
|
}
|
||||||
|
|
||||||
|
++g;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Ping every server in your list again but don't update the list of servers
|
||||||
|
// Query callback installed when the server list was requested will be used
|
||||||
|
// again to post notifications and RefreshComplete, so the callback must remain
|
||||||
|
// valid until another RefreshComplete is called on it or the request
|
||||||
|
// is released with ReleaseRequest( hRequest )
|
||||||
|
void Steam_Matchmaking_Servers::RefreshQuery( HServerListRequest hRequest )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p", hRequest);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Returns true if the list is currently refreshing its server list
|
||||||
|
bool Steam_Matchmaking_Servers::IsRefreshing( HServerListRequest hRequest )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p", hRequest);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1
|
||||||
|
int Steam_Matchmaking_Servers::GetServerCount( HServerListRequest hRequest )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p", hRequest);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
int size = 0;
|
||||||
|
auto g = std::begin(requests);
|
||||||
|
while (g != std::end(requests)) {
|
||||||
|
if (g->id == hRequest) {
|
||||||
|
size = g->gameservers_filtered.size();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
++g;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("final count = %i", size);
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Refresh a single server inside of a query (rather than all the servers )
|
||||||
|
void Steam_Matchmaking_Servers::RefreshServer( HServerListRequest hRequest, int iServer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p", hRequest);
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// Get details on a given server in the list, you can get the valid range of index
|
||||||
|
// values by calling GetServerCount(). You will also receive index values in
|
||||||
|
// ISteamMatchmakingServerListResponse::ServerResponded() callbacks
|
||||||
|
gameserveritem_t* Steam_Matchmaking_Servers::GetServerDetails( EMatchMakingType eType, int iServer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return GetServerDetails((HServerListRequest) eType , iServer );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel an request which is operation on the given list type. You should call this to cancel
|
||||||
|
// any in-progress requests before destructing a callback object that may have been passed
|
||||||
|
// to one of the above list request calls. Not doing so may result in a crash when a callback
|
||||||
|
// occurs on the destructed object.
|
||||||
|
void Steam_Matchmaking_Servers::CancelQuery( EMatchMakingType eType )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return CancelQuery((HServerListRequest) eType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Ping every server in your list again but don't update the list of servers
|
||||||
|
void Steam_Matchmaking_Servers::RefreshQuery( EMatchMakingType eType )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return RefreshQuery((HServerListRequest) eType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Returns true if the list is currently refreshing its server list
|
||||||
|
bool Steam_Matchmaking_Servers::IsRefreshing( EMatchMakingType eType )
|
||||||
|
{
|
||||||
|
return IsRefreshing((HServerListRequest) eType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1
|
||||||
|
int Steam_Matchmaking_Servers::GetServerCount( EMatchMakingType eType )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return GetServerCount((HServerListRequest) eType);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Refresh a single server inside of a query (rather than all the servers )
|
||||||
|
void Steam_Matchmaking_Servers::RefreshServer( EMatchMakingType eType, int iServer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return RefreshServer((HServerListRequest) eType, iServer);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
// Queries to individual servers directly via IP/Port
|
||||||
|
//-----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Request updated ping time and other details from a single server
|
||||||
|
HServerQuery Steam_Matchmaking_Servers::PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%hhu.%hhu.%hhu.%hhu:%hu", ((unsigned char *)&unIP)[3], ((unsigned char *)&unIP)[2], ((unsigned char *)&unIP)[1], ((unsigned char *)&unIP)[0], usPort);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
Steam_Matchmaking_Servers_Direct_IP_Request r;
|
||||||
|
r.id = new_server_query();
|
||||||
|
r.ip = unIP;
|
||||||
|
r.port = usPort;
|
||||||
|
r.ping_response = pRequestServersResponse;
|
||||||
|
r.created = std::chrono::high_resolution_clock::now();
|
||||||
|
direct_ip_requests.push_back(r);
|
||||||
|
return r.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request the list of players currently playing on a server
|
||||||
|
HServerQuery Steam_Matchmaking_Servers::PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%hhu.%hhu.%hhu.%hhu:%hu", ((unsigned char *)&unIP)[3], ((unsigned char *)&unIP)[2], ((unsigned char *)&unIP)[1], ((unsigned char *)&unIP)[0], usPort);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
Steam_Matchmaking_Servers_Direct_IP_Request r;
|
||||||
|
r.id = new_server_query();
|
||||||
|
r.ip = unIP;
|
||||||
|
r.port = usPort;
|
||||||
|
r.players_response = pRequestServersResponse;
|
||||||
|
r.created = std::chrono::high_resolution_clock::now();
|
||||||
|
direct_ip_requests.push_back(r);
|
||||||
|
return r.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Request the list of rules that the server is running (See ISteamGameServer::SetKeyValue() to set the rules server side)
|
||||||
|
HServerQuery Steam_Matchmaking_Servers::ServerRules( uint32 unIP, uint16 usPort, ISteamMatchmakingRulesResponse *pRequestServersResponse )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%hhu.%hhu.%hhu.%hhu:%hu", ((unsigned char *)&unIP)[3], ((unsigned char *)&unIP)[2], ((unsigned char *)&unIP)[1], ((unsigned char *)&unIP)[0], usPort);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
Steam_Matchmaking_Servers_Direct_IP_Request r;
|
||||||
|
r.id = new_server_query();
|
||||||
|
r.ip = unIP;
|
||||||
|
r.port = usPort;
|
||||||
|
r.rules_response = pRequestServersResponse;
|
||||||
|
r.created = std::chrono::high_resolution_clock::now();
|
||||||
|
direct_ip_requests.push_back(r);
|
||||||
|
return r.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Cancel an outstanding Ping/Players/Rules query from above. You should call this to cancel
|
||||||
|
// any in-progress requests before destructing a callback object that may have been passed
|
||||||
|
// to one of the above calls to avoid crashing when callbacks occur.
|
||||||
|
void Steam_Matchmaking_Servers::CancelServerQuery( HServerQuery hServerQuery )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto r = std::find_if(direct_ip_requests.begin(), direct_ip_requests.end(), [&hServerQuery](Steam_Matchmaking_Servers_Direct_IP_Request const& item) { return item.id == hServerQuery; });
|
||||||
|
if (direct_ip_requests.end() == r) return;
|
||||||
|
direct_ip_requests.erase(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Steam_Matchmaking_Servers::server_details(Gameserver *g, gameserveritem_t *server)
|
void Steam_Matchmaking_Servers::server_details(Gameserver *g, gameserveritem_t *server)
|
||||||
{
|
{
|
||||||
PRINT_DEBUG_ENTRY();
|
PRINT_DEBUG_ENTRY();
|
||||||
@ -559,179 +790,6 @@ void Steam_Matchmaking_Servers::server_details_rules(Gameserver *g, Steam_Matchm
|
|||||||
PRINT_DEBUG(" " "%" PRIu64 "", g->id());
|
PRINT_DEBUG(" " "%" PRIu64 "", g->id());
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get details on a given server in the list, you can get the valid range of index
|
|
||||||
// values by calling GetServerCount(). You will also receive index values in
|
|
||||||
// ISteamMatchmakingServerListResponse::ServerResponded() callbacks
|
|
||||||
gameserveritem_t *Steam_Matchmaking_Servers::GetServerDetails( HServerListRequest hRequest, int iServer )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p %i", hRequest, iServer);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
|
|
||||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers_filtered;
|
|
||||||
auto g = std::begin(requests);
|
|
||||||
while (g != std::end(requests)) {
|
|
||||||
PRINT_DEBUG(" equal? %p %p", hRequest, g->id);
|
|
||||||
if (g->id == hRequest) {
|
|
||||||
gameservers_filtered = g->gameservers_filtered;
|
|
||||||
PRINT_DEBUG(" found %zu", gameservers_filtered.size());
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
++g;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (iServer >= gameservers_filtered.size() || iServer < 0) {
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
Gameserver *gs = &gameservers_filtered[iServer].server;
|
|
||||||
gameserveritem_t *server = new gameserveritem_t(); //TODO: is the new here ok?
|
|
||||||
server_details(gs, server);
|
|
||||||
PRINT_DEBUG(" Returned server details");
|
|
||||||
return server;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Cancel an request which is operation on the given list type. You should call this to cancel
|
|
||||||
// any in-progress requests before destructing a callback object that may have been passed
|
|
||||||
// to one of the above list request calls. Not doing so may result in a crash when a callback
|
|
||||||
// occurs on the destructed object.
|
|
||||||
// Canceling a query does not release the allocated request handle.
|
|
||||||
// The request handle must be released using ReleaseRequest( hRequest )
|
|
||||||
void Steam_Matchmaking_Servers::CancelQuery( HServerListRequest hRequest )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p", hRequest);
|
|
||||||
auto g = std::begin(requests);
|
|
||||||
while (g != std::end(requests)) {
|
|
||||||
if (g->id == hRequest) {
|
|
||||||
g->cancelled = true;
|
|
||||||
PRINT_DEBUG("canceled request with id: %p", g->id);
|
|
||||||
}
|
|
||||||
|
|
||||||
++g;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Ping every server in your list again but don't update the list of servers
|
|
||||||
// Query callback installed when the server list was requested will be used
|
|
||||||
// again to post notifications and RefreshComplete, so the callback must remain
|
|
||||||
// valid until another RefreshComplete is called on it or the request
|
|
||||||
// is released with ReleaseRequest( hRequest )
|
|
||||||
void Steam_Matchmaking_Servers::RefreshQuery( HServerListRequest hRequest )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p", hRequest);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Returns true if the list is currently refreshing its server list
|
|
||||||
bool Steam_Matchmaking_Servers::IsRefreshing( HServerListRequest hRequest )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p", hRequest);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// How many servers in the given list, GetServerDetails above takes 0... GetServerCount() - 1
|
|
||||||
int Steam_Matchmaking_Servers::GetServerCount( HServerListRequest hRequest )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p", hRequest);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
int size = 0;
|
|
||||||
auto g = std::begin(requests);
|
|
||||||
while (g != std::end(requests)) {
|
|
||||||
if (g->id == hRequest) {
|
|
||||||
size = g->gameservers_filtered.size();
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
++g;
|
|
||||||
}
|
|
||||||
|
|
||||||
PRINT_DEBUG("final count = %i", size);
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Refresh a single server inside of a query (rather than all the servers )
|
|
||||||
void Steam_Matchmaking_Servers::RefreshServer( HServerListRequest hRequest, int iServer )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%p", hRequest);
|
|
||||||
//TODO
|
|
||||||
}
|
|
||||||
|
|
||||||
static HServerQuery new_server_query()
|
|
||||||
{
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
static int a = 0;
|
|
||||||
++a;
|
|
||||||
if (!a) ++a;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
// Queries to individual servers directly via IP/Port
|
|
||||||
//-----------------------------------------------------------------------------
|
|
||||||
|
|
||||||
// Request updated ping time and other details from a single server
|
|
||||||
HServerQuery Steam_Matchmaking_Servers::PingServer( uint32 unIP, uint16 usPort, ISteamMatchmakingPingResponse *pRequestServersResponse )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%hhu.%hhu.%hhu.%hhu:%hu", ((unsigned char *)&unIP)[3], ((unsigned char *)&unIP)[2], ((unsigned char *)&unIP)[1], ((unsigned char *)&unIP)[0], usPort);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
Steam_Matchmaking_Servers_Direct_IP_Request r;
|
|
||||||
r.id = new_server_query();
|
|
||||||
r.ip = unIP;
|
|
||||||
r.port = usPort;
|
|
||||||
r.ping_response = pRequestServersResponse;
|
|
||||||
r.created = std::chrono::high_resolution_clock::now();
|
|
||||||
direct_ip_requests.push_back(r);
|
|
||||||
return r.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Request the list of players currently playing on a server
|
|
||||||
HServerQuery Steam_Matchmaking_Servers::PlayerDetails( uint32 unIP, uint16 usPort, ISteamMatchmakingPlayersResponse *pRequestServersResponse )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%hhu.%hhu.%hhu.%hhu:%hu", ((unsigned char *)&unIP)[3], ((unsigned char *)&unIP)[2], ((unsigned char *)&unIP)[1], ((unsigned char *)&unIP)[0], usPort);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
Steam_Matchmaking_Servers_Direct_IP_Request r;
|
|
||||||
r.id = new_server_query();
|
|
||||||
r.ip = unIP;
|
|
||||||
r.port = usPort;
|
|
||||||
r.players_response = pRequestServersResponse;
|
|
||||||
r.created = std::chrono::high_resolution_clock::now();
|
|
||||||
direct_ip_requests.push_back(r);
|
|
||||||
return r.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Request the list of rules that the server is running (See ISteamGameServer::SetKeyValue() to set the rules server side)
|
|
||||||
HServerQuery Steam_Matchmaking_Servers::ServerRules( uint32 unIP, uint16 usPort, ISteamMatchmakingRulesResponse *pRequestServersResponse )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG("%hhu.%hhu.%hhu.%hhu:%hu", ((unsigned char *)&unIP)[3], ((unsigned char *)&unIP)[2], ((unsigned char *)&unIP)[1], ((unsigned char *)&unIP)[0], usPort);
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
Steam_Matchmaking_Servers_Direct_IP_Request r;
|
|
||||||
r.id = new_server_query();
|
|
||||||
r.ip = unIP;
|
|
||||||
r.port = usPort;
|
|
||||||
r.rules_response = pRequestServersResponse;
|
|
||||||
r.created = std::chrono::high_resolution_clock::now();
|
|
||||||
direct_ip_requests.push_back(r);
|
|
||||||
return r.id;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
// Cancel an outstanding Ping/Players/Rules query from above. You should call this to cancel
|
|
||||||
// any in-progress requests before destructing a callback object that may have been passed
|
|
||||||
// to one of the above calls to avoid crashing when callbacks occur.
|
|
||||||
void Steam_Matchmaking_Servers::CancelServerQuery( HServerQuery hServerQuery )
|
|
||||||
{
|
|
||||||
PRINT_DEBUG_ENTRY();
|
|
||||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
|
||||||
auto r = std::find_if(direct_ip_requests.begin(), direct_ip_requests.end(), [&hServerQuery](Steam_Matchmaking_Servers_Direct_IP_Request const& item) { return item.id == hServerQuery; });
|
|
||||||
if (direct_ip_requests.end() == r) return;
|
|
||||||
direct_ip_requests.erase(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Steam_Matchmaking_Servers::RunCallbacks()
|
void Steam_Matchmaking_Servers::RunCallbacks()
|
||||||
{
|
{
|
||||||
// PRINT_DEBUG_ENTRY();
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
972
dll/steam_networking.cpp
Normal file
972
dll/steam_networking.cpp
Normal file
@ -0,0 +1,972 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_networking.h"
|
||||||
|
|
||||||
|
|
||||||
|
//packet timeout in seconds for non connections
|
||||||
|
#define ORPHANED_PACKET_TIMEOUT (20)
|
||||||
|
#define NEW_CONNECTION_TIMEOUT (20.0)
|
||||||
|
|
||||||
|
//kingdom 2 crowns doesn't work with a 0.3 delay or lower
|
||||||
|
#define NEW_CONNECTION_DELAY (0.4)
|
||||||
|
|
||||||
|
#define OLD_CHANNEL_NUMBER 1
|
||||||
|
|
||||||
|
|
||||||
|
bool Steam_Networking::connection_exists(CSteamID id)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(connections_edit_mutex);
|
||||||
|
return std::find_if(connections.begin(), connections.end(), [&id](struct Steam_Networking_Connection const& conn) { return conn.remote == id;}) != connections.end();
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Steam_Networking_Connection* Steam_Networking::get_or_create_connection(CSteamID id)
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(connections_edit_mutex);
|
||||||
|
auto conn = std::find_if(connections.begin(), connections.end(), [&id](struct Steam_Networking_Connection const& conn) { return conn.remote == id;});
|
||||||
|
|
||||||
|
if (connections.end() == conn) {
|
||||||
|
struct Steam_Networking_Connection connection;
|
||||||
|
connection.remote = id;
|
||||||
|
connections.push_back(connection);
|
||||||
|
return &(connections[connections.size() - 1]);
|
||||||
|
} else {
|
||||||
|
return &(*conn);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking::remove_connection(CSteamID id)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(connections_edit_mutex);
|
||||||
|
auto conn = std::begin(connections);
|
||||||
|
while (conn != std::end(connections)) {
|
||||||
|
if (conn->remote == id) {
|
||||||
|
|
||||||
|
conn = connections.erase(conn);
|
||||||
|
} else {
|
||||||
|
++conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//pretty sure steam also clears the entire queue of messages for that connection
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(messages_mutex);
|
||||||
|
auto msg = std::begin(messages);
|
||||||
|
while (msg != std::end(messages)) {
|
||||||
|
if (msg->source_id() == id.ConvertToUint64()) {
|
||||||
|
msg = messages.erase(msg);
|
||||||
|
} else {
|
||||||
|
++msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
auto msg = std::begin(unprocessed_messages);
|
||||||
|
while (msg != std::end(unprocessed_messages)) {
|
||||||
|
if (msg->source_id() == id.ConvertToUint64()) {
|
||||||
|
msg = unprocessed_messages.erase(msg);
|
||||||
|
} else {
|
||||||
|
++msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SNetSocket_t Steam_Networking::create_connection_socket(CSteamID target, int nVirtualPort, uint32 nIP, uint16 nPort, SNetListenSocket_t id, enum steam_socket_connection_status status, SNetSocket_t other_id)
|
||||||
|
{
|
||||||
|
static SNetSocket_t socket_number = 0;
|
||||||
|
bool found = false;
|
||||||
|
do {
|
||||||
|
found = false;
|
||||||
|
++socket_number;
|
||||||
|
for (auto & c: connection_sockets) {
|
||||||
|
if (c.id == socket_number || socket_number == 0) {
|
||||||
|
found = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (found);
|
||||||
|
|
||||||
|
struct steam_connection_socket socket{};
|
||||||
|
socket.id = socket_number;
|
||||||
|
socket.listen_id = id;
|
||||||
|
socket.status = status;
|
||||||
|
socket.target = target;
|
||||||
|
socket.nVirtualPort = nVirtualPort;
|
||||||
|
socket.nIP = nIP;
|
||||||
|
socket.nPort = nPort;
|
||||||
|
socket.other_id = other_id;
|
||||||
|
connection_sockets.push_back(socket);
|
||||||
|
|
||||||
|
Common_Message msg{};
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
msg.set_dest_id(target.ConvertToUint64());
|
||||||
|
msg.set_allocated_network_old(new Network_Old);
|
||||||
|
if (nPort) {
|
||||||
|
msg.mutable_network_old()->set_type(Network_Old::CONNECTION_REQUEST_IP);
|
||||||
|
msg.mutable_network_old()->set_port(nPort);
|
||||||
|
} else {
|
||||||
|
msg.mutable_network_old()->set_type(Network_Old::CONNECTION_REQUEST_STEAMID);
|
||||||
|
msg.mutable_network_old()->set_port(nVirtualPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket.status == SOCKET_CONNECTED) {
|
||||||
|
msg.mutable_network_old()->set_type(Network_Old::CONNECTION_ACCEPTED);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.mutable_network_old()->set_connection_id(socket.other_id);
|
||||||
|
msg.mutable_network_old()->set_connection_id_from(socket.id);
|
||||||
|
|
||||||
|
if (target.IsValid()) {
|
||||||
|
network->sendTo(&msg, true);
|
||||||
|
} else if (nIP) {
|
||||||
|
network->sendToIPPort(&msg, nIP, nPort, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
return socket.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct steam_connection_socket* Steam_Networking::get_connection_socket(SNetSocket_t id)
|
||||||
|
{
|
||||||
|
auto conn = std::find_if(connection_sockets.begin(), connection_sockets.end(), [&id](struct steam_connection_socket const& conn) {
|
||||||
|
return conn.id == id;
|
||||||
|
});
|
||||||
|
if (connection_sockets.end() == conn) return NULL;
|
||||||
|
|
||||||
|
return &(*conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking::remove_killed_connection_sockets()
|
||||||
|
{
|
||||||
|
auto socket = std::begin(connection_sockets);
|
||||||
|
while (socket != std::end(connection_sockets)) {
|
||||||
|
if (socket->status == SOCKET_KILLED || socket->status == SOCKET_DISCONNECTED) {
|
||||||
|
socket = connection_sockets.erase(socket);
|
||||||
|
} else {
|
||||||
|
++socket;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking::steam_networking_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking *steam_networking = (Steam_Networking *)object;
|
||||||
|
steam_networking->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking::steam_networking_run_every_runcp(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking *steam_networking = (Steam_Networking *)object;
|
||||||
|
steam_networking->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking::Steam_Networking(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_NETWORKING, settings->get_local_steam_id(), &Steam_Networking::steam_networking_callback, this);
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking::steam_networking_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Networking::steam_networking_run_every_runcp, this);
|
||||||
|
|
||||||
|
PRINT_DEBUG("user id %llu messages: %p", settings->get_local_steam_id().ConvertToUint64(), &messages);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking::~Steam_Networking()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_NETWORKING, settings->get_local_steam_id(), &Steam_Networking::steam_networking_callback, this);
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking::steam_networking_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Networking::steam_networking_run_every_runcp, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// Session-less connection functions
|
||||||
|
// automatically establishes NAT-traversing or Relay server connections
|
||||||
|
|
||||||
|
// Sends a P2P packet to the specified user
|
||||||
|
// UDP-like, unreliable and a max packet size of 1200 bytes
|
||||||
|
// the first packet send may be delayed as the NAT-traversal code runs
|
||||||
|
// if we can't get through to the user, an error will be posted via the callback P2PSessionConnectFail_t
|
||||||
|
// see EP2PSend enum above for the descriptions of the different ways of sending packets
|
||||||
|
//
|
||||||
|
// nChannel is a routing number you can use to help route message to different systems - you'll have to call ReadP2PPacket()
|
||||||
|
// with the same channel number in order to retrieve the data on the other end
|
||||||
|
// using different channels to talk to the same user will still use the same underlying p2p connection, saving on resources
|
||||||
|
bool Steam_Networking::SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType, int nChannel)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("len %u sendtype: %u channel: %u to: %llu", cubData, eP2PSendType, nChannel, steamIDRemote.ConvertToUint64());
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
bool reliable = false;
|
||||||
|
if (eP2PSendType == k_EP2PSendReliable || eP2PSendType == k_EP2PSendReliableWithBuffering) reliable = true;
|
||||||
|
Common_Message msg;
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
msg.set_dest_id(steamIDRemote.ConvertToUint64());
|
||||||
|
msg.set_allocated_network(new Network_pb);
|
||||||
|
|
||||||
|
if (!connection_exists(steamIDRemote)) {
|
||||||
|
msg.mutable_network()->set_type(Network_pb::NEW_CONNECTION);
|
||||||
|
network->sendTo(&msg, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
msg.mutable_network()->set_channel(nChannel);
|
||||||
|
msg.mutable_network()->set_data(pubData, cubData);
|
||||||
|
msg.mutable_network()->set_type(Network_pb::DATA);
|
||||||
|
|
||||||
|
struct Steam_Networking_Connection *conn = get_or_create_connection(steamIDRemote);
|
||||||
|
new_connection_times.erase(steamIDRemote);
|
||||||
|
|
||||||
|
conn->open_channels.insert(nChannel);
|
||||||
|
bool ret = network->sendTo(&msg, reliable);
|
||||||
|
PRINT_DEBUG("Sent message with size: %zu %u", msg.network().data().size(), ret);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking::SendP2PPacket( CSteamID steamIDRemote, const void *pubData, uint32 cubData, EP2PSend eP2PSendType )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return SendP2PPacket(steamIDRemote, pubData, cubData, eP2PSendType, OLD_CHANNEL_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if any data is available for read, and the amount of data that will need to be read
|
||||||
|
bool Steam_Networking::IsP2PPacketAvailable( uint32 *pcubMsgSize, int nChannel)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("channel: %i", nChannel);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(messages_mutex);
|
||||||
|
//Not sure if this should be here because it slightly screws up games that don't like such low "pings"
|
||||||
|
//Commenting it out for now because it looks like it causes a bug where 20xx gets stuck in an infinite receive packet loop
|
||||||
|
//this->network->Run();
|
||||||
|
//RunCallbacks();
|
||||||
|
|
||||||
|
PRINT_DEBUG("Messages %zu %p", messages.size(), &messages);
|
||||||
|
for (auto &msg : messages) {
|
||||||
|
if (connection_exists((uint64)msg.source_id()) && msg.mutable_network()->channel() == nChannel && msg.network().processed()) {
|
||||||
|
uint32 size = msg.mutable_network()->data().size();
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = size;
|
||||||
|
PRINT_DEBUG("available with size: %u", size);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("(not available)");
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking::IsP2PPacketAvailable( uint32 *pcubMsgSize)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return IsP2PPacketAvailable(pcubMsgSize, OLD_CHANNEL_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// reads in a packet that has been sent from another user via SendP2PPacket()
|
||||||
|
// returns the size of the message and the steamID of the user who sent it in the last two parameters
|
||||||
|
// if the buffer passed in is too small, the message will be truncated
|
||||||
|
// this call is not blocking, and will return false if no data is available
|
||||||
|
bool Steam_Networking::ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote, int nChannel)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%u %i", cubDest, nChannel);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(messages_mutex);
|
||||||
|
//Not sure if this should be here because it slightly screws up games that don't like such low "pings"
|
||||||
|
//Commenting it out for now because it looks like it causes a bug where 20xx gets stuck in an infinite receive packet loop
|
||||||
|
//this->network->Run();
|
||||||
|
//RunCallbacks();
|
||||||
|
|
||||||
|
bool read = false;
|
||||||
|
PRINT_DEBUG("Number messages %zu", messages.size());
|
||||||
|
auto msg = std::begin(messages);
|
||||||
|
while (msg != std::end(messages)) {
|
||||||
|
if (connection_exists((uint64)msg->source_id()) && msg->network().channel() == nChannel && msg->network().processed()) {
|
||||||
|
uint32 msg_size = msg->network().data().size();
|
||||||
|
if (msg_size > cubDest) msg_size = cubDest;
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = msg_size;
|
||||||
|
memcpy(pubDest, msg->network().data().data(), msg_size);
|
||||||
|
|
||||||
|
PRINT_DEBUG("%s",
|
||||||
|
common_helpers::uint8_vector_to_hex_string(std::vector<uint8_t>((uint8_t*)pubDest, (uint8_t*)pubDest + msg_size)).c_str());
|
||||||
|
|
||||||
|
*psteamIDRemote = CSteamID((uint64)msg->source_id());
|
||||||
|
PRINT_DEBUG("len %u channel: %u from: " "%" PRIu64 "", msg_size, nChannel, msg->source_id());
|
||||||
|
msg = messages.erase(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
++msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = 0;
|
||||||
|
if (psteamIDRemote) *psteamIDRemote = k_steamIDNil;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking::ReadP2PPacket( void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, CSteamID *psteamIDRemote)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return ReadP2PPacket(pubDest, cubDest, pcubMsgSize, psteamIDRemote, OLD_CHANNEL_NUMBER);
|
||||||
|
}
|
||||||
|
|
||||||
|
// AcceptP2PSessionWithUser() should only be called in response to a P2PSessionRequest_t callback
|
||||||
|
// P2PSessionRequest_t will be posted if another user tries to send you a packet that you haven't talked to yet
|
||||||
|
// if you don't want to talk to the user, just ignore the request
|
||||||
|
// if the user continues to send you packets, another P2PSessionRequest_t will be posted periodically
|
||||||
|
// this may be called multiple times for a single user
|
||||||
|
// (if you've called SendP2PPacket() on the other user, this implicitly accepts the session request)
|
||||||
|
bool Steam_Networking::AcceptP2PSessionWithUser( CSteamID steamIDRemote )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%llu", steamIDRemote.ConvertToUint64());
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct Steam_Networking_Connection *conn = get_or_create_connection(steamIDRemote);
|
||||||
|
if (conn) new_connection_times.erase(steamIDRemote);
|
||||||
|
return !!conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// call CloseP2PSessionWithUser() when you're done talking to a user, will free up resources under-the-hood
|
||||||
|
// if the remote user tries to send data to you again, another P2PSessionRequest_t callback will be posted
|
||||||
|
bool Steam_Networking::CloseP2PSessionWithUser( CSteamID steamIDRemote )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%llu", steamIDRemote.ConvertToUint64());
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (!connection_exists(steamIDRemote)) {
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
remove_connection(steamIDRemote);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// call CloseP2PChannelWithUser() when you're done talking to a user on a specific channel. Once all channels
|
||||||
|
// open channels to a user have been closed, the open session to the user will be closed and new data from this
|
||||||
|
// user will trigger a P2PSessionRequest_t callback
|
||||||
|
bool Steam_Networking::CloseP2PChannelWithUser( CSteamID steamIDRemote, int nChannel )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (!connection_exists(steamIDRemote)) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct Steam_Networking_Connection *conn = get_or_create_connection(steamIDRemote);
|
||||||
|
|
||||||
|
conn->open_channels.erase(nChannel);
|
||||||
|
if (conn->open_channels.size() == 0) {
|
||||||
|
remove_connection(steamIDRemote);
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fills out P2PSessionState_t structure with details about the underlying connection to the user
|
||||||
|
// should only needed for debugging purposes
|
||||||
|
// returns false if no connection exists to the specified user
|
||||||
|
bool Steam_Networking::GetP2PSessionState( CSteamID steamIDRemote, P2PSessionState_t *pConnectionState )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%llu", steamIDRemote.ConvertToUint64());
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (!connection_exists(steamIDRemote) && (steamIDRemote != settings->get_local_steam_id())) {
|
||||||
|
if (pConnectionState) {
|
||||||
|
pConnectionState->m_bConnectionActive = false;
|
||||||
|
pConnectionState->m_bConnecting = false;
|
||||||
|
pConnectionState->m_eP2PSessionError = 0;
|
||||||
|
pConnectionState->m_bUsingRelay = false;
|
||||||
|
pConnectionState->m_nBytesQueuedForSend = 0;
|
||||||
|
pConnectionState->m_nPacketsQueuedForSend = 0;
|
||||||
|
pConnectionState->m_nRemoteIP = 0;
|
||||||
|
pConnectionState->m_nRemotePort = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("No Connection");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pConnectionState) {
|
||||||
|
pConnectionState->m_bConnectionActive = true;
|
||||||
|
pConnectionState->m_bConnecting = false;
|
||||||
|
pConnectionState->m_eP2PSessionError = 0;
|
||||||
|
pConnectionState->m_bUsingRelay = false;
|
||||||
|
pConnectionState->m_nBytesQueuedForSend = 0;
|
||||||
|
pConnectionState->m_nPacketsQueuedForSend = 0;
|
||||||
|
pConnectionState->m_nRemoteIP = network->getIP(steamIDRemote);
|
||||||
|
pConnectionState->m_nRemotePort = 12345;
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("Connection");
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Allow P2P connections to fall back to being relayed through the Steam servers if a direct connection
|
||||||
|
// or NAT-traversal cannot be established. Only applies to connections created after setting this value,
|
||||||
|
// or to existing connections that need to automatically reconnect after this value is set.
|
||||||
|
//
|
||||||
|
// P2P packet relay is allowed by default
|
||||||
|
bool Steam_Networking::AllowP2PPacketRelay( bool bAllow )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%u", bAllow);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
// LISTEN / CONNECT style interface functions
|
||||||
|
//
|
||||||
|
// This is an older set of functions designed around the Berkeley TCP sockets model
|
||||||
|
// it's preferential that you use the above P2P functions, they're more robust
|
||||||
|
// and these older functions will be removed eventually
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
SNetListenSocket_t socket_number = 0;
|
||||||
|
// creates a socket and listens others to connect
|
||||||
|
// will trigger a SocketStatusCallback_t callback on another client connecting
|
||||||
|
// nVirtualP2PPort is the unique ID that the client will connect to, in case you have multiple ports
|
||||||
|
// this can usually just be 0 unless you want multiple sets of connections
|
||||||
|
// unIP is the local IP address to bind to
|
||||||
|
// pass in 0 if you just want the default local IP
|
||||||
|
// unPort is the port to use
|
||||||
|
// pass in 0 if you don't want users to be able to connect via IP/Port, but expect to be always peer-to-peer connections only
|
||||||
|
SNetListenSocket_t Steam_Networking::CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort, bool bAllowUseOfPacketRelay )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old %i %u %hu %u", nVirtualP2PPort, nIP, nPort, bAllowUseOfPacketRelay);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
for (auto & c : listen_sockets) {
|
||||||
|
if (c.nVirtualP2PPort == nVirtualP2PPort || c.nPort == nPort)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
++socket_number;
|
||||||
|
if (!socket_number) ++socket_number;
|
||||||
|
|
||||||
|
struct steam_listen_socket socket;
|
||||||
|
socket.id = socket_number;
|
||||||
|
socket.nVirtualP2PPort = nVirtualP2PPort;
|
||||||
|
socket.nIP = nIP;
|
||||||
|
socket.nPort = nPort;
|
||||||
|
listen_sockets.push_back(socket);
|
||||||
|
return socket.id;
|
||||||
|
}
|
||||||
|
|
||||||
|
SNetListenSocket_t Steam_Networking::CreateListenSocket( int nVirtualP2PPort, SteamIPAddress_t nIP, uint16 nPort, bool bAllowUseOfPacketRelay )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i %i %u %hu %u", nVirtualP2PPort, nIP.m_eType, nIP.m_unIPv4, nPort, bAllowUseOfPacketRelay);
|
||||||
|
//TODO: ipv6
|
||||||
|
return CreateListenSocket(nVirtualP2PPort, nIP.m_unIPv4, nPort, bAllowUseOfPacketRelay);
|
||||||
|
}
|
||||||
|
|
||||||
|
SNetListenSocket_t Steam_Networking::CreateListenSocket( int nVirtualP2PPort, uint32 nIP, uint16 nPort )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return CreateListenSocket(nVirtualP2PPort, nIP, nPort, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// creates a socket and begin connection to a remote destination
|
||||||
|
// can connect via a known steamID (client or game server), or directly to an IP
|
||||||
|
// on success will trigger a SocketStatusCallback_t callback
|
||||||
|
// on failure or timeout will trigger a SocketStatusCallback_t callback with a failure code in m_eSNetSocketState
|
||||||
|
SNetSocket_t Steam_Networking::CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec, bool bAllowUseOfPacketRelay )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%llu %i %i %u", steamIDTarget.ConvertToUint64(), nVirtualPort, nTimeoutSec, bAllowUseOfPacketRelay);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO: nTimeoutSec
|
||||||
|
return create_connection_socket(steamIDTarget, nVirtualPort, 0, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
SNetSocket_t Steam_Networking::CreateP2PConnectionSocket( CSteamID steamIDTarget, int nVirtualPort, int nTimeoutSec )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return CreateP2PConnectionSocket(steamIDTarget, nVirtualPort, nTimeoutSec, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
SNetSocket_t Steam_Networking::CreateConnectionSocket( uint32 nIP, uint16 nPort, int nTimeoutSec )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%u %hu %i", nIP, nPort, nTimeoutSec);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO: nTimeoutSec
|
||||||
|
return create_connection_socket((uint64)0, 0, nIP, nPort);
|
||||||
|
}
|
||||||
|
|
||||||
|
SNetSocket_t Steam_Networking::CreateConnectionSocket( SteamIPAddress_t nIP, uint16 nPort, int nTimeoutSec )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i %u %hu %i", nIP.m_eType, nIP.m_unIPv4, nPort, nTimeoutSec);
|
||||||
|
//TODO: ipv6
|
||||||
|
return CreateConnectionSocket(nIP.m_unIPv4, nPort, nTimeoutSec);
|
||||||
|
}
|
||||||
|
|
||||||
|
// disconnects the connection to the socket, if any, and invalidates the handle
|
||||||
|
// any unread data on the socket will be thrown away
|
||||||
|
// if bNotifyRemoteEnd is set, socket will not be completely destroyed until the remote end acknowledges the disconnect
|
||||||
|
bool Steam_Networking::DestroySocket( SNetSocket_t hSocket, bool bNotifyRemoteEnd )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(hSocket);
|
||||||
|
if (!socket || socket->status == SOCKET_KILLED) return false;
|
||||||
|
socket->status = SOCKET_KILLED;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// destroying a listen socket will automatically kill all the regular sockets generated from it
|
||||||
|
bool Steam_Networking::DestroyListenSocket( SNetListenSocket_t hSocket, bool bNotifyRemoteEnd )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto c = std::begin(listen_sockets);
|
||||||
|
while (c != std::end(listen_sockets)) {
|
||||||
|
if (c->id == hSocket) {
|
||||||
|
c = listen_sockets.erase(c);
|
||||||
|
for (auto & socket : connection_sockets) {
|
||||||
|
if (socket.listen_id == hSocket) {
|
||||||
|
socket.status = SOCKET_KILLED;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
++c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// sending data
|
||||||
|
// must be a handle to a connected socket
|
||||||
|
// data is all sent via UDP, and thus send sizes are limited to 1200 bytes; after this, many routers will start dropping packets
|
||||||
|
// use the reliable flag with caution; although the resend rate is pretty aggressive,
|
||||||
|
// it can still cause stalls in receiving data (like TCP)
|
||||||
|
bool Steam_Networking::SendDataOnSocket( SNetSocket_t hSocket, void *pubData, uint32 cubData, bool bReliable )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(hSocket);
|
||||||
|
if (!socket || socket->status != SOCKET_CONNECTED) return false;
|
||||||
|
|
||||||
|
Common_Message msg;
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
msg.set_dest_id(socket->target.ConvertToUint64());
|
||||||
|
msg.set_allocated_network_old(new Network_Old);
|
||||||
|
msg.mutable_network_old()->set_type(Network_Old::DATA);
|
||||||
|
msg.mutable_network_old()->set_connection_id(socket->other_id);
|
||||||
|
msg.mutable_network_old()->set_data(pubData, cubData);
|
||||||
|
return network->sendTo(&msg, bReliable);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// receiving data
|
||||||
|
// returns false if there is no data remaining
|
||||||
|
// fills out *pcubMsgSize with the size of the next message, in bytes
|
||||||
|
bool Steam_Networking::IsDataAvailableOnSocket( SNetSocket_t hSocket, uint32 *pcubMsgSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(hSocket);
|
||||||
|
if (!socket) {
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket->data_packets.size() == 0) return false;
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = socket->data_packets[0].data().size();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// fills in pubDest with the contents of the message
|
||||||
|
// messages are always complete, of the same size as was sent (i.e. packetized, not streaming)
|
||||||
|
// if *pcubMsgSize < cubDest, only partial data is written
|
||||||
|
// returns false if no data is available
|
||||||
|
bool Steam_Networking::RetrieveDataFromSocket( SNetSocket_t hSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(hSocket);
|
||||||
|
if (!socket || socket->data_packets.size() == 0) return false;
|
||||||
|
|
||||||
|
auto msg = std::begin(socket->data_packets);
|
||||||
|
if (msg != std::end(socket->data_packets)) {
|
||||||
|
uint32 msg_size = msg->data().size();
|
||||||
|
if (msg_size > cubDest) msg_size = cubDest;
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = msg_size;
|
||||||
|
memcpy(pubDest, msg->data().data(), msg_size);
|
||||||
|
msg = socket->data_packets.erase(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// checks for data from any socket that has been connected off this listen socket
|
||||||
|
// returns false if there is no data remaining
|
||||||
|
// fills out *pcubMsgSize with the size of the next message, in bytes
|
||||||
|
// fills out *phSocket with the socket that data is available on
|
||||||
|
bool Steam_Networking::IsDataAvailable( SNetListenSocket_t hListenSocket, uint32 *pcubMsgSize, SNetSocket_t *phSocket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (!hListenSocket) return false;
|
||||||
|
|
||||||
|
for (auto & socket : connection_sockets) {
|
||||||
|
if (socket.listen_id == hListenSocket && socket.data_packets.size()) {
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = socket.data_packets[0].data().size();
|
||||||
|
if (phSocket) *phSocket = socket.id;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// retrieves data from any socket that has been connected off this listen socket
|
||||||
|
// fills in pubDest with the contents of the message
|
||||||
|
// messages are always complete, of the same size as was sent (i.e. packetized, not streaming)
|
||||||
|
// if *pcubMsgSize < cubDest, only partial data is written
|
||||||
|
// returns false if no data is available
|
||||||
|
// fills out *phSocket with the socket that data is available on
|
||||||
|
bool Steam_Networking::RetrieveData( SNetListenSocket_t hListenSocket, void *pubDest, uint32 cubDest, uint32 *pcubMsgSize, SNetSocket_t *phSocket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (!hListenSocket) return false;
|
||||||
|
|
||||||
|
for (auto & socket : connection_sockets) {
|
||||||
|
if (socket.listen_id == hListenSocket && socket.data_packets.size()) {
|
||||||
|
auto msg = std::begin(socket.data_packets);
|
||||||
|
if (msg != std::end(socket.data_packets)) {
|
||||||
|
uint32 msg_size = msg->data().size();
|
||||||
|
if (msg_size > cubDest) msg_size = cubDest;
|
||||||
|
if (pcubMsgSize) *pcubMsgSize = msg_size;
|
||||||
|
if (phSocket) *phSocket = socket.id;
|
||||||
|
memcpy(pubDest, msg->data().data(), msg_size);
|
||||||
|
msg = socket.data_packets.erase(msg);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// returns information about the specified socket, filling out the contents of the pointers
|
||||||
|
bool Steam_Networking::GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, uint32 *punIPRemote, uint16 *punPortRemote )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(hSocket);
|
||||||
|
if (!socket) return false;
|
||||||
|
if (pSteamIDRemote) *pSteamIDRemote = socket->target;
|
||||||
|
if (peSocketStatus) {
|
||||||
|
//TODO: I'm not sure what peSocketStatus is supposed to be but I'm guessing it's ESNetSocketState
|
||||||
|
if (socket->status == SOCKET_CONNECTED) {
|
||||||
|
*peSocketStatus = k_ESNetSocketStateConnected;
|
||||||
|
} else if (socket->status == SOCKET_CONNECTING) {
|
||||||
|
*peSocketStatus = k_ESNetSocketStateInitiated;
|
||||||
|
} else if (socket->status == SOCKET_DISCONNECTED) {
|
||||||
|
*peSocketStatus = k_ESNetSocketStateDisconnecting;
|
||||||
|
} else if (socket->status == SOCKET_KILLED) {
|
||||||
|
*peSocketStatus = k_ESNetSocketStateConnectionBroken;
|
||||||
|
} else {
|
||||||
|
*peSocketStatus = k_ESNetSocketStateInvalid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (punIPRemote) *punIPRemote = socket->nIP;
|
||||||
|
if (punPortRemote) *punPortRemote = socket->nPort;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking::GetSocketInfo( SNetSocket_t hSocket, CSteamID *pSteamIDRemote, int *peSocketStatus, SteamIPAddress_t *punIPRemote, uint16 *punPortRemote )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
//TODO: ipv6
|
||||||
|
uint32 *ip_remote = NULL;
|
||||||
|
if (punIPRemote) {
|
||||||
|
ip_remote = &(punIPRemote->m_unIPv4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = GetSocketInfo(hSocket, pSteamIDRemote, peSocketStatus, ip_remote, punPortRemote );
|
||||||
|
if (punIPRemote && ret) {
|
||||||
|
punIPRemote->m_eType = k_ESteamIPTypeIPv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns which local port the listen socket is bound to
|
||||||
|
// *pnIP and *pnPort will be 0 if the socket is set to listen for P2P connections only
|
||||||
|
bool Steam_Networking::GetListenSocketInfo( SNetListenSocket_t hListenSocket, uint32 *pnIP, uint16 *pnPort )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto conn = std::find_if(listen_sockets.begin(), listen_sockets.end(), [&hListenSocket](struct steam_listen_socket const& conn) { return conn.id == hListenSocket;});
|
||||||
|
if (conn == listen_sockets.end()) return false;
|
||||||
|
if (pnIP) *pnIP = conn->nIP;
|
||||||
|
if (pnPort) *pnPort = conn->nPort;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking::GetListenSocketInfo( SNetListenSocket_t hListenSocket, SteamIPAddress_t *pnIP, uint16 *pnPort )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
//TODO: ipv6
|
||||||
|
uint32 *ip = NULL;
|
||||||
|
if (pnIP) {
|
||||||
|
ip = &(pnIP->m_unIPv4);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ret = GetListenSocketInfo(hListenSocket, ip, pnPort );
|
||||||
|
if (pnIP && ret) {
|
||||||
|
pnIP->m_eType = k_ESteamIPTypeIPv4;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true to describe how the socket ended up connecting
|
||||||
|
ESNetSocketConnectionType Steam_Networking::GetSocketConnectionType( SNetSocket_t hSocket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(hSocket);
|
||||||
|
if (!socket || socket->status != SOCKET_CONNECTED) return k_ESNetSocketConnectionTypeNotConnected;
|
||||||
|
else return k_ESNetSocketConnectionTypeUDP;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// max packet size, in bytes
|
||||||
|
int Steam_Networking::GetMaxPacketSize( SNetSocket_t hSocket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 1500;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking::RunCallbacks()
|
||||||
|
{
|
||||||
|
uint64 current_time = std::chrono::duration_cast<std::chrono::duration<uint64>>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
|
||||||
|
{
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(messages_mutex);
|
||||||
|
|
||||||
|
{
|
||||||
|
auto msg = std::begin(unprocessed_messages);
|
||||||
|
while (msg != std::end(unprocessed_messages)) {
|
||||||
|
CSteamID source_id((uint64)msg->source_id());
|
||||||
|
if (!connection_exists(source_id)) {
|
||||||
|
if (new_connection_times.find(source_id) == new_connection_times.end()) {
|
||||||
|
new_connections_to_call_cb.push(source_id);
|
||||||
|
new_connection_times[source_id] = std::chrono::high_resolution_clock::now();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
struct Steam_Networking_Connection *conn = get_or_create_connection(source_id);
|
||||||
|
conn->open_channels.insert(msg->network().channel());
|
||||||
|
}
|
||||||
|
|
||||||
|
msg->mutable_network()->set_processed(true);
|
||||||
|
msg->mutable_network()->set_time_processed(current_time);
|
||||||
|
messages.push_back(*msg);
|
||||||
|
msg = unprocessed_messages.erase(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
auto msg = std::begin(messages);
|
||||||
|
while (msg != std::end(messages)) {
|
||||||
|
bool deleted = false;
|
||||||
|
if (msg->network().processed()) {
|
||||||
|
if (!connection_exists((uint64)msg->source_id())) {
|
||||||
|
if (msg->network().time_processed() + ORPHANED_PACKET_TIMEOUT < current_time) {
|
||||||
|
deleted = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (deleted) {
|
||||||
|
msg = messages.erase(msg);
|
||||||
|
} else {
|
||||||
|
++msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!new_connections_to_call_cb.empty()) {
|
||||||
|
CSteamID source_id = new_connections_to_call_cb.front();
|
||||||
|
auto t = new_connection_times.find(source_id);
|
||||||
|
if (t == new_connection_times.end()) {
|
||||||
|
new_connections_to_call_cb.pop();
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!check_timedout(t->second, NEW_CONNECTION_DELAY)) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
P2PSessionRequest_t data;
|
||||||
|
memset(&data, 0, sizeof(data));
|
||||||
|
data.m_steamIDRemote = source_id;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
new_connections_to_call_cb.pop();
|
||||||
|
}
|
||||||
|
|
||||||
|
//TODO: not sure if sockets should be wiped right away
|
||||||
|
remove_killed_connection_sockets();
|
||||||
|
|
||||||
|
for(auto it = new_connection_times.begin(); it != new_connection_times.end(); ) {
|
||||||
|
if (std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - it->second).count() > NEW_CONNECTION_TIMEOUT) {
|
||||||
|
it = new_connection_times.erase(it);
|
||||||
|
//TODO send packet to other side to tell them connection has "failed".
|
||||||
|
} else {
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_network()) {
|
||||||
|
PRINT_DEBUG("got msg from: " "%" PRIu64 " to: " "%" PRIu64 " size %zu type %u | messages %p: %zu",
|
||||||
|
msg->source_id(), msg->dest_id(), msg->network().data().size(), msg->network().type(), &messages, messages.size()
|
||||||
|
);
|
||||||
|
PRINT_DEBUG("msg data: '%s'",
|
||||||
|
common_helpers::uint8_vector_to_hex_string(std::vector<uint8_t>(msg->network().data().begin(), msg->network().data().end())).c_str());
|
||||||
|
|
||||||
|
if (msg->network().type() == Network_pb::DATA) {
|
||||||
|
unprocessed_messages.push_back(Common_Message(*msg));
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->network().type() == Network_pb::NEW_CONNECTION) {
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(messages_mutex);
|
||||||
|
auto msg_temp = std::begin(messages);
|
||||||
|
while (msg_temp != std::end(messages)) {
|
||||||
|
//only delete processed to handle unreliable message arriving at the same time.
|
||||||
|
if (msg_temp->source_id() == msg->source_id() && msg_temp->network().processed()) {
|
||||||
|
msg_temp = messages.erase(msg_temp);
|
||||||
|
} else {
|
||||||
|
++msg_temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_network_old()) {
|
||||||
|
PRINT_DEBUG("got network socket msg %u", msg->network_old().type());
|
||||||
|
if (msg->network_old().type() == Network_Old::CONNECTION_REQUEST_IP) {
|
||||||
|
for (auto & listen : listen_sockets) {
|
||||||
|
if (listen.nPort == msg->network_old().port()) {
|
||||||
|
SNetSocket_t new_sock = create_connection_socket((uint64)msg->source_id(), 0, 0, msg->network_old().port(), listen.id, SOCKET_CONNECTED, msg->network_old().connection_id_from());
|
||||||
|
if (new_sock) {
|
||||||
|
struct SocketStatusCallback_t data;
|
||||||
|
data.m_hSocket = new_sock;
|
||||||
|
data.m_hListenSocket = listen.id;
|
||||||
|
data.m_steamIDRemote = (uint64)msg->source_id();
|
||||||
|
data.m_eSNetSocketState = k_ESNetSocketStateConnected; //TODO is this the right state?
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else if (msg->network_old().type() == Network_Old::CONNECTION_REQUEST_STEAMID) {
|
||||||
|
for (auto & listen : listen_sockets) {
|
||||||
|
if (listen.nVirtualP2PPort == msg->network_old().port()) {
|
||||||
|
SNetSocket_t new_sock = create_connection_socket((uint64)msg->source_id(), msg->network_old().port(), 0, 0, listen.id, SOCKET_CONNECTED, msg->network_old().connection_id_from());
|
||||||
|
if (new_sock) {
|
||||||
|
struct SocketStatusCallback_t data;
|
||||||
|
data.m_hSocket = new_sock;
|
||||||
|
data.m_hListenSocket = listen.id;
|
||||||
|
data.m_steamIDRemote = (uint64)msg->source_id();
|
||||||
|
data.m_eSNetSocketState = k_ESNetSocketStateConnected; //TODO is this the right state?
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
} else if (msg->network_old().type() == Network_Old::CONNECTION_ACCEPTED) {
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(msg->network_old().connection_id());
|
||||||
|
if (socket && socket->nPort && socket->status == SOCKET_CONNECTING && !socket->target.IsValid()) {
|
||||||
|
socket->target = (uint64)msg->source_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (socket && socket->status == SOCKET_CONNECTING && msg->source_id() == socket->target.ConvertToUint64()) {
|
||||||
|
socket->status = SOCKET_CONNECTED;
|
||||||
|
socket->other_id = msg->network_old().connection_id_from();
|
||||||
|
struct SocketStatusCallback_t data;
|
||||||
|
data.m_hSocket = socket->id;
|
||||||
|
data.m_hListenSocket = socket->listen_id;
|
||||||
|
data.m_steamIDRemote = socket->target;
|
||||||
|
data.m_eSNetSocketState = k_ESNetSocketStateConnected; //TODO is this the right state?
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
} else if (msg->network_old().type() == Network_Old::CONNECTION_END) {
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(msg->network_old().connection_id());
|
||||||
|
if (socket && socket->status == SOCKET_CONNECTED && msg->source_id() == socket->target.ConvertToUint64()) {
|
||||||
|
struct SocketStatusCallback_t data;
|
||||||
|
socket->status = SOCKET_DISCONNECTED;
|
||||||
|
data.m_hSocket = socket->id;
|
||||||
|
data.m_hListenSocket = socket->listen_id;
|
||||||
|
data.m_steamIDRemote = socket->target;
|
||||||
|
data.m_eSNetSocketState = k_ESNetSocketStateRemoteEndDisconnected; //TODO is this the right state?
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
} else if (msg->network_old().type() == Network_Old::DATA) {
|
||||||
|
struct steam_connection_socket *socket = get_connection_socket(msg->network_old().connection_id());
|
||||||
|
if (socket && socket->status == SOCKET_CONNECTED && msg->source_id() == socket->target.ConvertToUint64()) {
|
||||||
|
socket->data_packets.push_back(msg->network_old());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
CSteamID source_id((uint64)msg->source_id());
|
||||||
|
if (connection_exists(source_id)) {
|
||||||
|
P2PSessionConnectFail_t data;
|
||||||
|
data.m_steamIDRemote = source_id;
|
||||||
|
data.m_eP2PSessionError = k_EP2PSessionErrorDestinationNotLoggedIn;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto & socket : connection_sockets) {
|
||||||
|
if (socket.target.ConvertToUint64() == msg->source_id()) {
|
||||||
|
struct SocketStatusCallback_t data;
|
||||||
|
socket.status = SOCKET_DISCONNECTED;
|
||||||
|
data.m_hSocket = socket.id;
|
||||||
|
data.m_hListenSocket = socket.listen_id;
|
||||||
|
data.m_steamIDRemote = socket.target;
|
||||||
|
data.m_eSNetSocketState = k_ESNetSocketStateConnectionBroken; //TODO is this the right state?
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
419
dll/steam_networking_messages.cpp
Normal file
419
dll/steam_networking_messages.cpp
Normal file
@ -0,0 +1,419 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_networking_messages.h"
|
||||||
|
|
||||||
|
|
||||||
|
#define NETWORKING_MESSAGES_TIMEOUT 30.0
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking_Messages *steam_networking_messages = (Steam_Networking_Messages *)object;
|
||||||
|
steam_networking_messages->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking_Messages *steam_networking_messages = (Steam_Networking_Messages *)object;
|
||||||
|
steam_networking_messages->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::free_steam_message_data(SteamNetworkingMessage_t *pMsg)
|
||||||
|
{
|
||||||
|
free(pMsg->m_pData);
|
||||||
|
pMsg->m_pData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::delete_steam_message(SteamNetworkingMessage_t *pMsg)
|
||||||
|
{
|
||||||
|
if (pMsg->m_pfnFreeData) pMsg->m_pfnFreeData(pMsg);
|
||||||
|
delete pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::end_connection(CSteamID steam_id)
|
||||||
|
{
|
||||||
|
auto conn = connections.find(steam_id);
|
||||||
|
if (conn != connections.end()) {
|
||||||
|
conn->second.dead = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::map<CSteamID, Steam_Message_Connection>::iterator Steam_Networking_Messages::find_or_create_message_connection(SteamNetworkingIdentity identityRemote, bool incoming, bool restartbroken)
|
||||||
|
{
|
||||||
|
auto conn = connections.find(identityRemote.GetSteamID());
|
||||||
|
if (conn == connections.end() || (conn->second.dead && restartbroken)) {
|
||||||
|
++id_counter;
|
||||||
|
struct Steam_Message_Connection con;
|
||||||
|
con.remote_identity = identityRemote;
|
||||||
|
con.id = id_counter;
|
||||||
|
connections[identityRemote.GetSteamID()] = con;
|
||||||
|
|
||||||
|
Common_Message msg;
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
msg.set_dest_id(con.remote_identity.GetSteamID64());
|
||||||
|
msg.set_allocated_networking_messages(new Networking_Messages);
|
||||||
|
if (incoming) {
|
||||||
|
msg.mutable_networking_messages()->set_type(Networking_Messages::CONNECTION_ACCEPT);
|
||||||
|
} else {
|
||||||
|
msg.mutable_networking_messages()->set_type(Networking_Messages::CONNECTION_NEW);
|
||||||
|
}
|
||||||
|
msg.mutable_networking_messages()->set_channel(0);
|
||||||
|
msg.mutable_networking_messages()->set_id_from(con.id);
|
||||||
|
network->sendTo(&msg, true);
|
||||||
|
|
||||||
|
conn = connections.find(identityRemote.GetSteamID());
|
||||||
|
|
||||||
|
if (incoming) {
|
||||||
|
SteamNetworkingMessagesSessionRequest_t data;
|
||||||
|
data.m_identityRemote = con.remote_identity;
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!incoming) {
|
||||||
|
conn->second.accepted = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Networking_Messages::Steam_Networking_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->created = std::chrono::steady_clock::now();
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_NETWORKING_MESSAGES, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Networking_Messages::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking_Messages::~Steam_Networking_Messages()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_NETWORKING_MESSAGES, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Messages::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Networking_Messages::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Sends a message to the specified host. If we don't already have a session with that user,
|
||||||
|
/// a session is implicitly created. There might be some handshaking that needs to happen
|
||||||
|
/// before we can actually begin sending message data. If this handshaking fails and we can't
|
||||||
|
/// get through, an error will be posted via the callback SteamNetworkingMessagesSessionFailed_t.
|
||||||
|
/// There is no notification when the operation succeeds. (You should have the peer send a reply
|
||||||
|
/// for this purpose.)
|
||||||
|
///
|
||||||
|
/// Sending a message to a host will also implicitly accept any incoming connection from that host.
|
||||||
|
///
|
||||||
|
/// nSendFlags is a bitmask of k_nSteamNetworkingSend_xxx options
|
||||||
|
///
|
||||||
|
/// nRemoteChannel is a routing number you can use to help route message to different systems.
|
||||||
|
/// You'll have to call ReceiveMessagesOnChannel() with the same channel number in order to retrieve
|
||||||
|
/// the data on the other end.
|
||||||
|
///
|
||||||
|
/// Using different channels to talk to the same user will still use the same underlying
|
||||||
|
/// connection, saving on resources. If you don't need this feature, use 0.
|
||||||
|
/// Otherwise, small integers are the most efficient.
|
||||||
|
///
|
||||||
|
/// It is guaranteed that reliable messages to the same host on the same channel
|
||||||
|
/// will be be received by the remote host (if they are received at all) exactly once,
|
||||||
|
/// and in the same order that they were send.
|
||||||
|
///
|
||||||
|
/// NO other order guarantees exist! In particular, unreliable messages may be dropped,
|
||||||
|
/// received out of order with respect to each other and with respect to reliable data,
|
||||||
|
/// or may be received multiple times. Messages on different channels are *not* guaranteed
|
||||||
|
/// to be received in the order they were sent.
|
||||||
|
///
|
||||||
|
/// A note for those familiar with TCP/IP ports, or converting an existing codebase that
|
||||||
|
/// opened multiple sockets: You might notice that there is only one channel, and with
|
||||||
|
/// TCP/IP each endpoint has a port number. You can think of the channel number as the
|
||||||
|
/// *destination* port. If you need each message to also include a "source port" (so the
|
||||||
|
/// recipient can route the reply), then just put that in your message. That is essentially
|
||||||
|
/// how UDP works!
|
||||||
|
///
|
||||||
|
/// Returns:
|
||||||
|
/// - k_EREsultOK on success.
|
||||||
|
/// - k_EResultNoConnection will be returned if the session has failed or was closed by the peer,
|
||||||
|
/// and k_nSteamNetworkingSend_AutoRestartBrokwnSession is not used. (You can use
|
||||||
|
/// GetSessionConnectionInfo to get the details.) In order to acknowledge the broken session
|
||||||
|
/// and start a new one, you must call CloseSessionWithUser
|
||||||
|
/// - See SendMessageToConnection::SendMessageToConnection for more
|
||||||
|
EResult Steam_Networking_Messages::SendMessageToUser( const SteamNetworkingIdentity &identityRemote, const void *pubData, uint32 cubData, int nSendFlags, int nRemoteChannel )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
const SteamNetworkingIPAddr *ip = identityRemote.GetIPAddr();
|
||||||
|
bool reliable = false;
|
||||||
|
if (nSendFlags & k_nSteamNetworkingSend_Reliable) {
|
||||||
|
reliable = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool restart_broken = false;
|
||||||
|
if (nSendFlags & k_nSteamNetworkingSend_AutoRestartBrokenSession) {
|
||||||
|
restart_broken = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (identityRemote.m_eType == k_ESteamNetworkingIdentityType_SteamID) {
|
||||||
|
PRINT_DEBUG("%llu", identityRemote.GetSteamID64());
|
||||||
|
//steam id identity
|
||||||
|
} else if (ip) {
|
||||||
|
PRINT_DEBUG("%u:%u ipv4? %u", ip->GetIPv4(), ip->m_port, ip->IsIPv4());
|
||||||
|
//ip addr
|
||||||
|
return k_EResultNoConnection; //TODO
|
||||||
|
} else {
|
||||||
|
return k_EResultNoConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto conn = find_or_create_message_connection(identityRemote, false, restart_broken);
|
||||||
|
if (conn->second.dead) {
|
||||||
|
return k_EResultNoConnection;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common_Message msg;
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
msg.set_dest_id(conn->second.remote_identity.GetSteamID64());
|
||||||
|
msg.set_allocated_networking_messages(new Networking_Messages);
|
||||||
|
msg.mutable_networking_messages()->set_type(Networking_Messages::DATA);
|
||||||
|
msg.mutable_networking_messages()->set_channel(nRemoteChannel);
|
||||||
|
msg.mutable_networking_messages()->set_id_from(conn->second.id);
|
||||||
|
msg.mutable_networking_messages()->set_data(pubData, cubData);
|
||||||
|
|
||||||
|
network->sendTo(&msg, reliable);
|
||||||
|
return k_EResultOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Reads the next message that has been sent from another user via SendMessageToUser() on the given channel.
|
||||||
|
/// Returns number of messages returned into your list. (0 if no message are available on that channel.)
|
||||||
|
///
|
||||||
|
/// When you're done with the message object(s), make sure and call Release()!
|
||||||
|
int Steam_Networking_Messages::ReceiveMessagesOnChannel( int nLocalChannel, SteamNetworkingMessage_t **ppOutMessages, int nMaxMessages )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
int message_counter = 0;
|
||||||
|
|
||||||
|
for (auto & conn : connections) {
|
||||||
|
auto chan = conn.second.data.find(nLocalChannel);
|
||||||
|
if (chan != conn.second.data.end()) {
|
||||||
|
while (!chan->second.empty() && message_counter < nMaxMessages) {
|
||||||
|
SteamNetworkingMessage_t *pMsg = new SteamNetworkingMessage_t(); //TODO size is wrong
|
||||||
|
unsigned long size = chan->second.front().size();
|
||||||
|
pMsg->m_pData = malloc(size);
|
||||||
|
pMsg->m_cbSize = size;
|
||||||
|
memcpy(pMsg->m_pData, chan->second.front().data(), size);
|
||||||
|
pMsg->m_conn = conn.second.id;
|
||||||
|
pMsg->m_identityPeer = conn.second.remote_identity;
|
||||||
|
pMsg->m_nConnUserData = -1;
|
||||||
|
pMsg->m_usecTimeReceived = std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - created).count();
|
||||||
|
//TODO: messagenumber?
|
||||||
|
// pMsg->m_nMessageNumber = connect_socket->second.packet_receive_counter;
|
||||||
|
// ++connect_socket->second.packet_receive_counter;
|
||||||
|
|
||||||
|
pMsg->m_pfnFreeData = &free_steam_message_data;
|
||||||
|
pMsg->m_pfnRelease = &delete_steam_message;
|
||||||
|
pMsg->m_nChannel = nLocalChannel;
|
||||||
|
ppOutMessages[message_counter] = pMsg;
|
||||||
|
++message_counter;
|
||||||
|
chan->second.pop();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (message_counter >= nMaxMessages) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
PRINT_DEBUG("got %u", message_counter);
|
||||||
|
return message_counter;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// AcceptSessionWithUser() should only be called in response to a SteamP2PSessionRequest_t callback
|
||||||
|
/// SteamP2PSessionRequest_t will be posted if another user tries to send you a message, and you haven't
|
||||||
|
/// tried to talk to them. If you don't want to talk to them, just ignore the request.
|
||||||
|
/// If the user continues to send you messages, SteamP2PSessionRequest_t callbacks will continue to
|
||||||
|
/// be posted periodically. This may be called multiple times for a single user.
|
||||||
|
///
|
||||||
|
/// Calling SendMessage() on the other user, this implicitly accepts any pending session request.
|
||||||
|
bool Steam_Networking_Messages::AcceptSessionWithUser( const SteamNetworkingIdentity &identityRemote )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto conn = connections.find(identityRemote.GetSteamID());
|
||||||
|
if (conn == connections.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
conn->second.accepted = true;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call this when you're done talking to a user to immediately free up resources under-the-hood.
|
||||||
|
/// If the remote user tries to send data to you again, another P2PSessionRequest_t callback will
|
||||||
|
/// be posted.
|
||||||
|
///
|
||||||
|
/// Note that sessions that go unused for a few minutes are automatically timed out.
|
||||||
|
bool Steam_Networking_Messages::CloseSessionWithUser( const SteamNetworkingIdentity &identityRemote )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto conn = connections.find(identityRemote.GetSteamID());
|
||||||
|
if (conn == connections.end()) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
Common_Message msg;
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
msg.set_dest_id(conn->second.remote_identity.GetSteamID64());
|
||||||
|
msg.set_allocated_networking_messages(new Networking_Messages);
|
||||||
|
msg.mutable_networking_messages()->set_type(Networking_Messages::CONNECTION_END);
|
||||||
|
msg.mutable_networking_messages()->set_channel(0);
|
||||||
|
msg.mutable_networking_messages()->set_id_from(conn->second.id);
|
||||||
|
network->sendTo(&msg, true);
|
||||||
|
|
||||||
|
connections.erase(conn);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Call this when you're done talking to a user on a specific channel. Once all
|
||||||
|
/// open channels to a user have been closed, the open session to the user will be
|
||||||
|
/// closed, and any new data from this user will trigger a SteamP2PSessionRequest_t
|
||||||
|
/// callback
|
||||||
|
bool Steam_Networking_Messages::CloseChannelWithUser( const SteamNetworkingIdentity &identityRemote, int nLocalChannel )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns information about the latest state of a connection, if any, with the given peer.
|
||||||
|
/// Primarily intended for debugging purposes, but can also be used to get more detailed
|
||||||
|
/// failure information. (See SendMessageToUser and k_nSteamNetworkingSend_AutoRestartBrokwnSession.)
|
||||||
|
///
|
||||||
|
/// Returns the value of SteamNetConnectionInfo_t::m_eState, or k_ESteamNetworkingConnectionState_None
|
||||||
|
/// if no connection exists with specified peer. You may pass nullptr for either parameter if
|
||||||
|
/// you do not need the corresponding details. Note that sessions time out after a while,
|
||||||
|
/// so if a connection fails, or SendMessageToUser returns SendMessageToUser, you cannot wait
|
||||||
|
/// indefinitely to obtain the reason for failure.
|
||||||
|
ESteamNetworkingConnectionState Steam_Networking_Messages::GetSessionConnectionInfo( const SteamNetworkingIdentity &identityRemote, SteamNetConnectionInfo_t *pConnectionInfo, SteamNetConnectionRealTimeStatus_t *pQuickStatus )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
auto conn = connections.find(identityRemote.GetSteamID());
|
||||||
|
if (conn == connections.end()) {
|
||||||
|
return k_ESteamNetworkingConnectionState_None;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESteamNetworkingConnectionState state = k_ESteamNetworkingConnectionState_Connected;
|
||||||
|
if (conn->second.remote_id == 0 || !conn->second.accepted) {
|
||||||
|
state = k_ESteamNetworkingConnectionState_Connecting;
|
||||||
|
} else if (conn->second.dead) {
|
||||||
|
state = k_ESteamNetworkingConnectionState_ClosedByPeer;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pConnectionInfo) {
|
||||||
|
memset(pConnectionInfo, 0, sizeof(SteamNetConnectionInfo_t));
|
||||||
|
pConnectionInfo->m_eState = state;
|
||||||
|
pConnectionInfo->m_identityRemote = conn->second.remote_identity;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pQuickStatus) {
|
||||||
|
memset(pQuickStatus, 0, sizeof(SteamNetConnectionRealTimeStatus_t));
|
||||||
|
pQuickStatus->m_eState = state;
|
||||||
|
pQuickStatus->m_nPing = 10; //TODO: calculate real numbers?
|
||||||
|
pQuickStatus->m_flConnectionQualityLocal = 1.0;
|
||||||
|
pQuickStatus->m_flConnectionQualityRemote = 1.0;
|
||||||
|
//TODO
|
||||||
|
}
|
||||||
|
|
||||||
|
return k_ESteamNetworkingConnectionState_Connected;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::RunCallbacks()
|
||||||
|
{
|
||||||
|
auto msg = std::begin(incoming_data);
|
||||||
|
while (msg != std::end(incoming_data)) {
|
||||||
|
CSteamID source_id((uint64)msg->source_id());
|
||||||
|
|
||||||
|
auto conn = connections.find(source_id);
|
||||||
|
if (conn != connections.end()) {
|
||||||
|
if (conn->second.remote_id == msg->networking_messages().id_from())
|
||||||
|
conn->second.data[msg->networking_messages().channel()].push(msg->networking_messages().data());
|
||||||
|
}
|
||||||
|
|
||||||
|
msg = incoming_data.erase(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
auto conn = std::begin(connections);
|
||||||
|
while (conn != std::end(connections)) {
|
||||||
|
if (!conn->second.accepted && check_timedout(conn->second.created, NETWORKING_MESSAGES_TIMEOUT)) {
|
||||||
|
conn = connections.erase(conn);
|
||||||
|
} else {
|
||||||
|
++conn;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Messages::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
end_connection((uint64)msg->source_id());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_messages()) {
|
||||||
|
PRINT_DEBUG("got network socket msg %u", msg->networking_messages().type());
|
||||||
|
if (msg->networking_messages().type() == Networking_Messages::CONNECTION_NEW) {
|
||||||
|
SteamNetworkingIdentity identity;
|
||||||
|
identity.SetSteamID64(msg->source_id());
|
||||||
|
auto conn = find_or_create_message_connection(identity, true, false);
|
||||||
|
conn->second.remote_id = msg->networking_messages().id_from();
|
||||||
|
conn->second.dead = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->networking_messages().type() == Networking_Messages::CONNECTION_ACCEPT) {
|
||||||
|
auto conn = connections.find((uint64)msg->source_id());
|
||||||
|
if (conn != connections.end()) {
|
||||||
|
conn->second.remote_id = msg->networking_messages().id_from();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->networking_messages().type() == Networking_Messages::CONNECTION_END) {
|
||||||
|
end_connection((uint64)msg->source_id());
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->networking_messages().type() == Networking_Messages::DATA) {
|
||||||
|
incoming_data.push_back(Common_Message(*msg));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
2098
dll/steam_networking_sockets.cpp
Normal file
2098
dll/steam_networking_sockets.cpp
Normal file
File diff suppressed because it is too large
Load Diff
155
dll/steam_networking_socketsserialized.cpp
Normal file
155
dll/steam_networking_socketsserialized.cpp
Normal file
@ -0,0 +1,155 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_networking_socketsserialized.h"
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking_Sockets_Serialized *steam_networkingsockets = (Steam_Networking_Sockets_Serialized *)object;
|
||||||
|
steam_networkingsockets->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking_Sockets_Serialized *steam_networkingsockets = (Steam_Networking_Sockets_Serialized *)object;
|
||||||
|
steam_networkingsockets->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking_Sockets_Serialized::Steam_Networking_Sockets_Serialized(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Sockets_Serialized::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Networking_Sockets_Serialized::steam_run_every_runcb, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking_Sockets_Serialized::~Steam_Networking_Sockets_Serialized()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Sockets_Serialized::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Networking_Sockets_Serialized::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::SendP2PRendezvous( CSteamID steamIDRemote, uint32 unConnectionIDSrc, const void *pMsgRendezvous, uint32 cbRendezvous )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::SendP2PConnectionFailure( CSteamID steamIDRemote, uint32 unConnectionIDDest, uint32 nReason, const char *pszReason )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamAPICall_t Steam_Networking_Sockets_Serialized::GetCertAsync()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
struct SteamNetworkingSocketsCert_t data = {};
|
||||||
|
data.m_eResult = k_EResultOK;
|
||||||
|
|
||||||
|
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
int Steam_Networking_Sockets_Serialized::GetNetworkConfigJSON( void *buf, uint32 cbBuf, const char *pszLauncherPartner )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Steam_Networking_Sockets_Serialized::GetNetworkConfigJSON( void *buf, uint32 cbBuf )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return GetNetworkConfigJSON(buf, cbBuf, "");
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::CacheRelayTicket( const void *pTicket, uint32 cbTicket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Steam_Networking_Sockets_Serialized::GetCachedRelayTicketCount()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Steam_Networking_Sockets_Serialized::GetCachedRelayTicket( uint32 idxTicket, void *buf, uint32 cbBuf )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::PostConnectionStateMsg( const void *pMsg, uint32 cbMsg )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking_Sockets_Serialized::GetSTUNServer(int dont_know, char *buf, unsigned int len)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking_Sockets_Serialized::BAllowDirectConnectToPeer(SteamNetworkingIdentity const &identity)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Steam_Networking_Sockets_Serialized::BeginAsyncRequestFakeIP(int a)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::RunCallbacks()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Sockets_Serialized::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
730
dll/steam_networking_utils.cpp
Normal file
730
dll/steam_networking_utils.cpp
Normal file
@ -0,0 +1,730 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_networking_utils.h"
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking_Utils *steam_networkingutils = (Steam_Networking_Utils *)object;
|
||||||
|
steam_networkingutils->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Networking_Utils *steam_networkingutils = (Steam_Networking_Utils *)object;
|
||||||
|
steam_networkingutils->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking_Utils::Steam_Networking_Utils(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Utils::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Networking_Utils::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Networking_Utils::~Steam_Networking_Utils()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Networking_Utils::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Networking_Utils::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::free_steam_message_data(SteamNetworkingMessage_t *pMsg)
|
||||||
|
{
|
||||||
|
free(pMsg->m_pData);
|
||||||
|
pMsg->m_pData = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::delete_steam_message(SteamNetworkingMessage_t *pMsg)
|
||||||
|
{
|
||||||
|
if (pMsg->m_pfnFreeData) pMsg->m_pfnFreeData(pMsg);
|
||||||
|
delete pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// 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.
|
||||||
|
///
|
||||||
|
/// Optionally you can also request that this system allocate space to
|
||||||
|
/// hold the payload itself. If cbAllocateBuffer is nonzero, the system
|
||||||
|
/// will allocate memory to hold a payload of at least cbAllocateBuffer bytes.
|
||||||
|
/// m_pData will point to the allocated buffer, m_cbSize will be set to the
|
||||||
|
/// size, and m_pfnFreeData will be set to the proper function to free up
|
||||||
|
/// the buffer.
|
||||||
|
///
|
||||||
|
/// If cbAllocateBuffer=0, then no buffer is allocated. m_pData will be NULL,
|
||||||
|
/// m_cbSize will be zero, and m_pfnFreeData will be NULL. You will need to
|
||||||
|
/// set each of these.
|
||||||
|
///
|
||||||
|
/// You can use SteamNetworkingMessage_t::Release to free up the message
|
||||||
|
/// bookkeeping object and any associated buffer. See
|
||||||
|
/// ISteamNetworkingSockets::SendMessages for details on reference
|
||||||
|
/// counting and ownership.
|
||||||
|
SteamNetworkingMessage_t* Steam_Networking_Utils::AllocateMessage( int cbAllocateBuffer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
SteamNetworkingMessage_t *pMsg = new SteamNetworkingMessage_t();
|
||||||
|
pMsg->m_pfnFreeData = &free_steam_message_data;
|
||||||
|
pMsg->m_pfnRelease = &delete_steam_message;
|
||||||
|
if (cbAllocateBuffer < 0)
|
||||||
|
cbAllocateBuffer = 0;
|
||||||
|
|
||||||
|
pMsg->m_pData = nullptr;
|
||||||
|
if (cbAllocateBuffer)
|
||||||
|
pMsg->m_pData = malloc(cbAllocateBuffer);
|
||||||
|
|
||||||
|
pMsg->m_cbSize = cbAllocateBuffer;
|
||||||
|
return pMsg;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking_Utils::InitializeRelayAccess()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
init_relay = true;
|
||||||
|
return relay_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamRelayNetworkStatus_t Steam_Networking_Utils::get_network_status()
|
||||||
|
{
|
||||||
|
SteamRelayNetworkStatus_t data = {};
|
||||||
|
data.m_eAvail = k_ESteamNetworkingAvailability_Current;
|
||||||
|
data.m_bPingMeasurementInProgress = 0;
|
||||||
|
data.m_eAvailAnyRelay = k_ESteamNetworkingAvailability_Current;
|
||||||
|
data.m_eAvailNetworkConfig = k_ESteamNetworkingAvailability_Current;
|
||||||
|
strcpy(data.m_debugMsg, "OK");
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Fetch current status of the relay network.
|
||||||
|
///
|
||||||
|
/// SteamRelayNetworkStatus_t is also a callback. It will be triggered on
|
||||||
|
/// both the user and gameserver interfaces any time the status changes, or
|
||||||
|
/// ping measurement starts or stops.
|
||||||
|
///
|
||||||
|
/// SteamRelayNetworkStatus_t::m_eAvail is returned. If you want
|
||||||
|
/// more details, you can pass a non-NULL value.
|
||||||
|
ESteamNetworkingAvailability Steam_Networking_Utils::GetRelayNetworkStatus( SteamRelayNetworkStatus_t *pDetails )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("TODO %p", pDetails);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
//TODO: check if this is how real steam returns it
|
||||||
|
SteamRelayNetworkStatus_t data = {};
|
||||||
|
if (relay_initialized) {
|
||||||
|
data = get_network_status();
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pDetails) {
|
||||||
|
*pDetails = data;
|
||||||
|
}
|
||||||
|
|
||||||
|
return k_ESteamNetworkingAvailability_Current;
|
||||||
|
}
|
||||||
|
|
||||||
|
float Steam_Networking_Utils::GetLocalPingLocation( SteamNetworkPingLocation_t &result )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (relay_initialized) {
|
||||||
|
result.m_data[2] = 123;
|
||||||
|
result.m_data[8] = 67;
|
||||||
|
return 2.0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Steam_Networking_Utils::EstimatePingTimeBetweenTwoLocations( const SteamNetworkPingLocation_t &location1, const SteamNetworkPingLocation_t &location2 )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//return k_nSteamNetworkingPing_Unknown;
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Steam_Networking_Utils::EstimatePingTimeFromLocalHost( const SteamNetworkPingLocation_t &remoteLocation )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::ConvertPingLocationToString( const SteamNetworkPingLocation_t &location, char *pszBuf, int cchBufSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
strncpy(pszBuf, "fra=10+2", cchBufSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Steam_Networking_Utils::ParsePingLocationString( const char *pszString, SteamNetworkPingLocation_t &result )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Steam_Networking_Utils::CheckPingDataUpToDate( float flMaxAgeSeconds )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("TODO %f", flMaxAgeSeconds);
|
||||||
|
init_relay = true;
|
||||||
|
return relay_initialized;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
bool Steam_Networking_Utils::IsPingMeasurementInProgress()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Steam_Networking_Utils::GetPingToDataCenter( SteamNetworkingPOPID popID, SteamNetworkingPOPID *pViaRelayPoP )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Steam_Networking_Utils::GetDirectPingToPOP( SteamNetworkingPOPID popID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Steam_Networking_Utils::GetPOPCount()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int Steam_Networking_Utils::GetPOPList( SteamNetworkingPOPID *list, int nListSz )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Misc
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Fetch current timestamp. This timer has the following properties:
|
||||||
|
///
|
||||||
|
/// - Monotonicity is guaranteed.
|
||||||
|
/// - The initial value will be at least 24*3600*30*1e6, i.e. about
|
||||||
|
/// 30 days worth of microseconds. In this way, the timestamp value of
|
||||||
|
/// 0 will always be at least "30 days ago". Also, negative numbers
|
||||||
|
/// will never be returned.
|
||||||
|
/// - Wraparound / overflow is not a practical concern.
|
||||||
|
///
|
||||||
|
/// If you are running under the debugger and stop the process, the clock
|
||||||
|
/// might not advance the full wall clock time that has elapsed between
|
||||||
|
/// calls. If the process is not blocked from normal operation, the
|
||||||
|
/// timestamp values will track wall clock time, even if you don't call
|
||||||
|
/// the function frequently.
|
||||||
|
///
|
||||||
|
/// The value is only meaningful for this run of the process. Don't compare
|
||||||
|
/// it to values obtained on another computer, or other runs of the same process.
|
||||||
|
SteamNetworkingMicroseconds Steam_Networking_Utils::GetLocalTimestamp()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return std::chrono::duration_cast<std::chrono::microseconds>(std::chrono::steady_clock::now() - initialized_time).count() + (SteamNetworkingMicroseconds)24*3600*30*1e6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Set a function to receive network-related information that is useful for debugging.
|
||||||
|
/// This can be very useful during development, but it can also be useful for troubleshooting
|
||||||
|
/// problems with tech savvy end users. If you have a console or other log that customers
|
||||||
|
/// can examine, these log messages can often be helpful to troubleshoot network issues.
|
||||||
|
/// (Especially any warning/error messages.)
|
||||||
|
///
|
||||||
|
/// The detail level indicates what message to invoke your callback on. Lower numeric
|
||||||
|
/// value means more important, and the value you pass is the lowest priority (highest
|
||||||
|
/// numeric value) you wish to receive callbacks for.
|
||||||
|
///
|
||||||
|
/// Except when debugging, you should only use k_ESteamNetworkingSocketsDebugOutputType_Msg
|
||||||
|
/// or k_ESteamNetworkingSocketsDebugOutputType_Warning. For best performance, do NOT
|
||||||
|
/// request a high detail level and then filter out messages in your callback. Instead,
|
||||||
|
/// call function function to adjust the desired level of detail.
|
||||||
|
///
|
||||||
|
/// IMPORTANT: This may be called from a service thread, while we own a mutex, etc.
|
||||||
|
/// Your output function must be threadsafe and fast! Do not make any other
|
||||||
|
/// Steamworks calls from within the handler.
|
||||||
|
void Steam_Networking_Utils::SetDebugOutputFunction( ESteamNetworkingSocketsDebugOutputType eDetailLevel, FSteamNetworkingSocketsDebugOutput pfnFunc )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i", eDetailLevel);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (eDetailLevel != k_ESteamNetworkingSocketsDebugOutputType_None) {
|
||||||
|
debug_function = pfnFunc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Fake IP
|
||||||
|
//
|
||||||
|
// Useful for interfacing with code that assumes peers are identified using an IPv4 address
|
||||||
|
//
|
||||||
|
|
||||||
|
/// Return true if an IPv4 address is one that might be used as a "fake" one.
|
||||||
|
/// This function is fast; it just does some logical tests on the IP and does
|
||||||
|
/// not need to do any lookup operations.
|
||||||
|
// inline bool IsFakeIPv4( uint32 nIPv4 ) { return GetIPv4FakeIPType( nIPv4 ) > k_ESteamNetworkingFakeIPType_NotFake; }
|
||||||
|
ESteamNetworkingFakeIPType Steam_Networking_Utils::GetIPv4FakeIPType( uint32 nIPv4 )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ESteamNetworkingFakeIPType_NotFake;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get the real identity associated with a given FakeIP.
|
||||||
|
///
|
||||||
|
/// On failure, returns:
|
||||||
|
/// - k_EResultInvalidParam: the IP is not a FakeIP.
|
||||||
|
/// - k_EResultNoMatch: we don't recognize that FakeIP and don't know the corresponding identity.
|
||||||
|
///
|
||||||
|
/// FakeIP's used by active connections, or the FakeIPs assigned to local identities,
|
||||||
|
/// will always work. FakeIPs for recently destroyed connections will continue to
|
||||||
|
/// return results for a little while, but not forever. At some point, we will forget
|
||||||
|
/// FakeIPs to save space. It's reasonably safe to assume that you can read back the
|
||||||
|
/// real identity of a connection very soon after it is destroyed. But do not wait
|
||||||
|
/// indefinitely.
|
||||||
|
EResult Steam_Networking_Utils::GetRealIdentityForFakeIP( const SteamNetworkingIPAddr &fakeIP, SteamNetworkingIdentity *pOutRealIdentity )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_EResultNoMatch;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// Set and get configuration values, see ESteamNetworkingConfigValue for individual descriptions.
|
||||||
|
//
|
||||||
|
|
||||||
|
// Shortcuts for common cases. (Implemented as inline functions below)
|
||||||
|
/*
|
||||||
|
bool Steam_Networking_Utils::SetGlobalConfigValueInt32( ESteamNetworkingConfigValue eValue, int32 val );
|
||||||
|
bool Steam_Networking_Utils::SetGlobalConfigValueFloat( ESteamNetworkingConfigValue eValue, float val );
|
||||||
|
bool Steam_Networking_Utils::SetGlobalConfigValueString( ESteamNetworkingConfigValue eValue, const char *val );
|
||||||
|
bool Steam_Networking_Utils::SetConnectionConfigValueInt32( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, int32 val );
|
||||||
|
bool Steam_Networking_Utils::SetConnectionConfigValueFloat( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, float val );
|
||||||
|
bool Steam_Networking_Utils::SetConnectionConfigValueString( HSteamNetConnection hConn, ESteamNetworkingConfigValue eValue, const char *val );
|
||||||
|
*/
|
||||||
|
/// Set a configuration value.
|
||||||
|
/// - eValue: which value is being set
|
||||||
|
/// - eScope: Onto what type of object are you applying the setting?
|
||||||
|
/// - scopeArg: Which object you want to change? (Ignored for global scope). E.g. connection handle, listen socket handle, interface pointer, etc.
|
||||||
|
/// - eDataType: What type of data is in the buffer at pValue? This must match the type of the variable exactly!
|
||||||
|
/// - pArg: Value to set it to. You can pass NULL to remove a non-global sett at this scope,
|
||||||
|
/// causing the value for that object to use global defaults. Or at global scope, passing NULL
|
||||||
|
/// will reset any custom value and restore it to the system default.
|
||||||
|
/// NOTE: When setting callback functions, do not pass the function pointer directly.
|
||||||
|
/// Your argument should be a pointer to a function pointer.
|
||||||
|
bool Steam_Networking_Utils::SetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
||||||
|
ESteamNetworkingConfigDataType eDataType, const void *pArg )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("TODO %i %i " "%" PRIdPTR " %i %p", eValue, eScopeType, scopeObj, eDataType, pArg);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Get a configuration value.
|
||||||
|
/// - eValue: which value to fetch
|
||||||
|
/// - eScopeType: query setting on what type of object
|
||||||
|
/// - eScopeArg: the object to query the setting for
|
||||||
|
/// - pOutDataType: If non-NULL, the data type of the value is returned.
|
||||||
|
/// - pResult: Where to put the result. Pass NULL to query the required buffer size. (k_ESteamNetworkingGetConfigValue_BufferTooSmall will be returned.)
|
||||||
|
/// - cbResult: IN: the size of your buffer. OUT: the number of bytes filled in or required.
|
||||||
|
ESteamNetworkingGetConfigValueResult Steam_Networking_Utils::GetConfigValue( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigScope eScopeType, intptr_t scopeObj,
|
||||||
|
ESteamNetworkingConfigDataType *pOutDataType, void *pResult, size_t *cbResult )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ESteamNetworkingGetConfigValue_BadValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/// Returns info about a configuration value. Returns false if the value does not exist.
|
||||||
|
/// pOutNextValue can be used to iterate through all of the known configuration values.
|
||||||
|
/// (Use GetFirstConfigValue() to begin the iteration, will be k_ESteamNetworkingConfig_Invalid on the last value)
|
||||||
|
/// Any of the output parameters can be NULL if you do not need that information.
|
||||||
|
bool Steam_Networking_Utils::GetConfigValueInfo( ESteamNetworkingConfigValue eValue, const char **pOutName, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope, ESteamNetworkingConfigValue *pOutNextValue )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO flat api
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get info about a configuration value. Returns the name of the value,
|
||||||
|
/// or NULL if the value doesn't exist. Other output parameters can be NULL
|
||||||
|
/// if you do not need them.
|
||||||
|
const char* Steam_Networking_Utils::GetConfigValueInfo( ESteamNetworkingConfigValue eValue, ESteamNetworkingConfigDataType *pOutDataType, ESteamNetworkingConfigScope *pOutScope )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
//TODO flat api
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Return the lowest numbered configuration value available in the current environment.
|
||||||
|
ESteamNetworkingConfigValue Steam_Networking_Utils::GetFirstConfigValue()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ESteamNetworkingConfig_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate the list of all configuration values in the current environment that it might
|
||||||
|
/// be possible to display or edit using a generic UI. To get the first iterable value,
|
||||||
|
/// pass k_ESteamNetworkingConfig_Invalid. Returns k_ESteamNetworkingConfig_Invalid
|
||||||
|
/// to signal end of list.
|
||||||
|
///
|
||||||
|
/// The bEnumerateDevVars argument can be used to include "dev" vars. These are vars that
|
||||||
|
/// are recommended to only be editable in "debug" or "dev" mode and typically should not be
|
||||||
|
/// shown in a retail environment where a malicious local user might use this to cheat.
|
||||||
|
ESteamNetworkingConfigValue Steam_Networking_Utils::IterateGenericEditableConfigValues( ESteamNetworkingConfigValue eCurrent, bool bEnumerateDevVars )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ESteamNetworkingConfig_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// String conversions. You'll usually access these using the respective
|
||||||
|
// inline methods.
|
||||||
|
void Steam_Networking_Utils::SteamNetworkingIPAddr_ToString( const SteamNetworkingIPAddr &addr, char *buf, size_t cbBuf, bool bWithPort )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (buf == nullptr || cbBuf == 0) return;
|
||||||
|
|
||||||
|
char buffer[64]{}; // enough for ipv4 & ipv6 + port
|
||||||
|
std::string str_addr{};
|
||||||
|
if (addr.IsIPv4()) {
|
||||||
|
in_addr ipv4_addr;
|
||||||
|
ipv4_addr.s_addr = htonl(addr.GetIPv4());
|
||||||
|
|
||||||
|
if (inet_ntop(AF_INET, &ipv4_addr, buffer, sizeof(buffer) / sizeof(*buffer)) != nullptr) {
|
||||||
|
if (bWithPort) {
|
||||||
|
str_addr = buffer;
|
||||||
|
str_addr += ':';
|
||||||
|
str_addr += std::to_string(addr.m_port);
|
||||||
|
} else {
|
||||||
|
str_addr = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
in6_addr ipv6_addr{};
|
||||||
|
memcpy(ipv6_addr.s6_addr, addr.m_ipv6, sizeof(addr.m_ipv6));
|
||||||
|
|
||||||
|
if (inet_ntop(AF_INET6, &ipv6_addr, buffer, sizeof(buffer) / sizeof(*buffer)) != nullptr) {
|
||||||
|
if (bWithPort) {
|
||||||
|
str_addr = '[';
|
||||||
|
str_addr += buffer;
|
||||||
|
str_addr += "]:";
|
||||||
|
str_addr += std::to_string(addr.m_port);
|
||||||
|
} else {
|
||||||
|
str_addr = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
cbBuf = std::min<size_t>(cbBuf, str_addr.length() + 1);
|
||||||
|
strncpy(buf, str_addr.c_str(), cbBuf);
|
||||||
|
buf[cbBuf - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking_Utils::SteamNetworkingIPAddr_ParseString( SteamNetworkingIPAddr *pAddr, const char *pszStr )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
bool valid = false;
|
||||||
|
|
||||||
|
if (pAddr == nullptr || pszStr == nullptr) return valid;
|
||||||
|
|
||||||
|
std::string str(pszStr);
|
||||||
|
size_t pos = str.find(':');
|
||||||
|
|
||||||
|
if (pos != std::string::npos) {// Try ipv4 with port
|
||||||
|
in_addr ipv4_addr;
|
||||||
|
std::string tmp(str);
|
||||||
|
tmp[pos] = 0;
|
||||||
|
const char* ip = tmp.c_str();
|
||||||
|
const char* port = &tmp[pos + 1];
|
||||||
|
|
||||||
|
if (inet_pton(AF_INET, ip, &ipv4_addr) == 1)
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
pAddr->SetIPv4(ntohl(ipv4_addr.s_addr), strtoul(port, nullptr, 10));
|
||||||
|
}
|
||||||
|
} else {// Try ipv4 without port
|
||||||
|
in_addr ipv4_addr;
|
||||||
|
if (inet_pton(AF_INET, str.c_str(), &ipv4_addr) == 1)
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
pAddr->SetIPv4(ntohl(ipv4_addr.s_addr), 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid) {// Try ipv6
|
||||||
|
addrinfo* info = nullptr;
|
||||||
|
addrinfo hints = {};
|
||||||
|
hints.ai_family = AF_INET6;
|
||||||
|
hints.ai_socktype = SOCK_STREAM;
|
||||||
|
hints.ai_flags = AI_NUMERICHOST | AI_NUMERICSERV;
|
||||||
|
|
||||||
|
size_t sep_pos = 0;
|
||||||
|
std::string ip;
|
||||||
|
int sep_count = 0;
|
||||||
|
for (int i = 0; i < str.length(); ++i) {
|
||||||
|
if (str[i] == ':') {
|
||||||
|
sep_pos = i;
|
||||||
|
++sep_count;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (sep_count == 8) {
|
||||||
|
ip = std::move(std::string(str.begin(), str.begin() + sep_pos));
|
||||||
|
} else {
|
||||||
|
ip = str;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (getaddrinfo(ip.c_str(), nullptr, &hints, &info) == 0) {
|
||||||
|
sockaddr_in6* maddr = (sockaddr_in6*)info->ai_addr;
|
||||||
|
|
||||||
|
size_t pos = str.find(']');
|
||||||
|
std::string str_port("0");
|
||||||
|
if (pos != std::string::npos) {
|
||||||
|
str_port = std::move(std::string(str.begin() + pos + 2, str.end()));
|
||||||
|
} else if (sep_count == 8) {
|
||||||
|
str_port = std::move(std::string(str.begin() + sep_pos + 1, str.end()));
|
||||||
|
}
|
||||||
|
|
||||||
|
try {
|
||||||
|
int port = std::stoi(str_port);
|
||||||
|
if (port >= 0 && port <= 65535) {
|
||||||
|
pAddr->SetIPv6(maddr->sin6_addr.s6_addr, port);
|
||||||
|
valid = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
catch(...) { }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (info) {
|
||||||
|
freeaddrinfo(info);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!valid) {
|
||||||
|
pAddr->Clear();
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
ESteamNetworkingFakeIPType Steam_Networking_Utils::SteamNetworkingIPAddr_GetFakeIPType( const SteamNetworkingIPAddr &addr )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ESteamNetworkingFakeIPType_NotFake;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::SteamNetworkingIdentity_ToString( const SteamNetworkingIdentity &identity, char *buf, size_t cbBuf )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (buf == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
std::string str;
|
||||||
|
str.reserve(SteamNetworkingIdentity::k_cchMaxString);
|
||||||
|
switch (identity.m_eType)
|
||||||
|
{
|
||||||
|
case k_ESteamNetworkingIdentityType_SteamID:
|
||||||
|
{
|
||||||
|
str = "steamid:";
|
||||||
|
str += std::move(std::to_string(identity.GetSteamID64()));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case k_ESteamNetworkingIdentityType_IPAddress:
|
||||||
|
{
|
||||||
|
str = "ip:";
|
||||||
|
char buff[SteamNetworkingIPAddr::k_cchMaxString];
|
||||||
|
auto& addr = *identity.GetIPAddr();
|
||||||
|
SteamNetworkingIPAddr_ToString(addr, buff, sizeof(buff), true);
|
||||||
|
str += buff;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case k_ESteamNetworkingIdentityType_GenericBytes:
|
||||||
|
{
|
||||||
|
int generic_len;
|
||||||
|
const uint8* pBuf = identity.GetGenericBytes(generic_len);
|
||||||
|
|
||||||
|
str = "gen:";
|
||||||
|
str.resize(4 + (generic_len * 2));
|
||||||
|
|
||||||
|
char* pDest = &str[4];
|
||||||
|
while(generic_len--)
|
||||||
|
{
|
||||||
|
// I don't care for the last char, I've reserved the max string size
|
||||||
|
snprintf(pDest, 3, "%02x", *pBuf);
|
||||||
|
++pBuf;
|
||||||
|
pDest += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case k_ESteamNetworkingIdentityType_GenericString:
|
||||||
|
{
|
||||||
|
str = "str:";
|
||||||
|
str += identity.GetGenericString();
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case k_ESteamNetworkingIdentityType_UnknownType:
|
||||||
|
{
|
||||||
|
str = identity.m_szUnknownRawString;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
cbBuf = std::min<size_t>(cbBuf, str.length() + 1);
|
||||||
|
strncpy(buf, str.c_str(), cbBuf);
|
||||||
|
buf[cbBuf - 1] = '\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Networking_Utils::SteamNetworkingIdentity_ParseString( SteamNetworkingIdentity *pIdentity, const char *pszStr )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
bool valid = false;
|
||||||
|
if (pIdentity == nullptr)
|
||||||
|
{
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (pszStr != nullptr)
|
||||||
|
{
|
||||||
|
const char* end = strchr(pszStr, ':');
|
||||||
|
if (end != nullptr)
|
||||||
|
{
|
||||||
|
++end;
|
||||||
|
if (strncmp(pszStr, "gen:", end - pszStr) == 0)
|
||||||
|
{
|
||||||
|
size_t length = strlen(end);
|
||||||
|
if (!(length % 2) && length <= (sizeof(pIdentity->m_genericBytes) * 2))
|
||||||
|
{// Must be even
|
||||||
|
valid = true;
|
||||||
|
length /= 2;
|
||||||
|
pIdentity->m_eType = k_ESteamNetworkingIdentityType_GenericBytes;
|
||||||
|
pIdentity->m_cbSize = length;
|
||||||
|
uint8* pBytes = pIdentity->m_genericBytes;
|
||||||
|
|
||||||
|
char hex[3] = { 0,0,0 };
|
||||||
|
while (length)
|
||||||
|
{
|
||||||
|
hex[0] = end[0];
|
||||||
|
hex[1] = end[1];
|
||||||
|
// Steam doesn't check if wasn't a hex char
|
||||||
|
*pBytes = strtol(hex, nullptr, 16);
|
||||||
|
|
||||||
|
++pBytes;
|
||||||
|
end += 2;
|
||||||
|
--length;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strncmp(pszStr, "steamid:", end - pszStr) == 0)
|
||||||
|
{
|
||||||
|
CSteamID steam_id(uint64(strtoull(end, nullptr, 10)));
|
||||||
|
if (steam_id.IsValid())
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
pIdentity->SetSteamID(steam_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (strncmp(pszStr, "str:", end - pszStr) == 0)
|
||||||
|
{
|
||||||
|
valid = pIdentity->SetGenericString(end);
|
||||||
|
}
|
||||||
|
else if (strncmp(pszStr, "ip:", end - pszStr) == 0)
|
||||||
|
{
|
||||||
|
SteamNetworkingIPAddr steam_addr;
|
||||||
|
if (SteamNetworkingIPAddr_ParseString(&steam_addr, end))
|
||||||
|
{
|
||||||
|
valid = true;
|
||||||
|
pIdentity->SetIPAddr(steam_addr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return valid;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::RunCallbacks()
|
||||||
|
{
|
||||||
|
if (init_relay && !relay_initialized) {
|
||||||
|
relay_initialized = true;
|
||||||
|
SteamRelayNetworkStatus_t data = get_network_status();
|
||||||
|
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Networking_Utils::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_sockets()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
195
dll/steam_parties.cpp
Normal file
195
dll/steam_parties.cpp
Normal file
@ -0,0 +1,195 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_parties.h"
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Parties::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Parties *steam_parties = (Steam_Parties *)object;
|
||||||
|
steam_parties->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Parties::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Parties *steam_parties = (Steam_Parties *)object;
|
||||||
|
steam_parties->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Parties::Steam_Parties(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Parties::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Parties::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Parties::~Steam_Parties()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Parties::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Parties::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =============================================================================================
|
||||||
|
// Party Client APIs
|
||||||
|
|
||||||
|
// Enumerate any active beacons for parties you may wish to join
|
||||||
|
uint32 Steam_Parties::GetNumActiveBeacons()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
PartyBeaconID_t Steam_Parties::GetBeaconByIndex( uint32 unIndex )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ulPartyBeaconIdInvalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Parties::GetBeaconDetails( PartyBeaconID_t ulBeaconID, CSteamID *pSteamIDBeaconOwner, STEAM_OUT_STRUCT() SteamPartyBeaconLocation_t *pLocation, STEAM_OUT_STRING_COUNT(cchMetadata) char *pchMetadata, int cchMetadata )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Join an open party. Steam will reserve one beacon slot for your SteamID,
|
||||||
|
// and return the necessary JoinGame string for you to use to connect
|
||||||
|
STEAM_CALL_RESULT( JoinPartyCallback_t )
|
||||||
|
SteamAPICall_t Steam_Parties::JoinParty( PartyBeaconID_t ulBeaconID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// =============================================================================================
|
||||||
|
// Party Host APIs
|
||||||
|
|
||||||
|
// Get a list of possible beacon locations
|
||||||
|
bool Steam_Parties::GetNumAvailableBeaconLocations( uint32 *puNumLocations )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_Parties::GetAvailableBeaconLocations( SteamPartyBeaconLocation_t *pLocationList, uint32 uMaxNumLocations )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Create a new party beacon and activate it in the selected location.
|
||||||
|
// unOpenSlots is the maximum number of users that Steam will send to you.
|
||||||
|
// When people begin responding to your beacon, Steam will send you
|
||||||
|
// PartyReservationCallback_t callbacks to let you know who is on the way.
|
||||||
|
STEAM_CALL_RESULT( CreateBeaconCallback_t )
|
||||||
|
SteamAPICall_t Steam_Parties::CreateBeacon( uint32 unOpenSlots, SteamPartyBeaconLocation_t *pBeaconLocation, const char *pchConnectString, const char *pchMetadata )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Call this function when a user that had a reservation (see callback below)
|
||||||
|
// has successfully joined your party.
|
||||||
|
// Steam will manage the remaining open slots automatically.
|
||||||
|
void Steam_Parties::OnReservationCompleted( PartyBeaconID_t ulBeacon, CSteamID steamIDUser )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// To cancel a reservation (due to timeout or user input), call this.
|
||||||
|
// Steam will open a new reservation slot.
|
||||||
|
// Note: The user may already be in-flight to your game, so it's possible they will still connect and try to join your party.
|
||||||
|
void Steam_Parties::CancelReservation( PartyBeaconID_t ulBeacon, CSteamID steamIDUser )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Change the number of open beacon reservation slots.
|
||||||
|
// Call this if, for example, someone without a reservation joins your party (eg a friend, or via your own matchmaking system).
|
||||||
|
STEAM_CALL_RESULT( ChangeNumOpenSlotsCallback_t )
|
||||||
|
SteamAPICall_t Steam_Parties::ChangeNumOpenSlots( PartyBeaconID_t ulBeacon, uint32 unOpenSlots )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Turn off the beacon.
|
||||||
|
bool Steam_Parties::DestroyBeacon( PartyBeaconID_t ulBeacon )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Utils
|
||||||
|
bool Steam_Parties::GetBeaconLocationData( SteamPartyBeaconLocation_t BeaconLocation, ESteamPartyBeaconLocationData eData, STEAM_OUT_STRING_COUNT(cchDataStringOut) char *pchDataStringOut, int cchDataStringOut )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Parties::RunCallbacks()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Parties::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_sockets()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1187
dll/steam_remote_storage.cpp
Normal file
1187
dll/steam_remote_storage.cpp
Normal file
File diff suppressed because it is too large
Load Diff
142
dll/steam_remoteplay.cpp
Normal file
142
dll/steam_remoteplay.cpp
Normal file
@ -0,0 +1,142 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_remoteplay.h"
|
||||||
|
|
||||||
|
void Steam_RemotePlay::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_RemotePlay *steam_remoteplay = (Steam_RemotePlay *)object;
|
||||||
|
steam_remoteplay->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_RemotePlay::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_RemotePlay *steam_remoteplay = (Steam_RemotePlay *)object;
|
||||||
|
steam_remoteplay->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_RemotePlay::Steam_RemotePlay(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_RemotePlay::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_RemotePlay::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_RemotePlay::~Steam_RemotePlay()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_RemotePlay::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_RemotePlay::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the number of currently connected Steam Remote Play sessions
|
||||||
|
uint32 Steam_RemotePlay::GetSessionCount()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the currently connected Steam Remote Play session ID at the specified index. Returns zero if index is out of bounds.
|
||||||
|
uint32 Steam_RemotePlay::GetSessionID( int iSessionIndex )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the SteamID of the connected user
|
||||||
|
CSteamID Steam_RemotePlay::GetSessionSteamID( uint32 unSessionID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_steamIDNil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the name of the session client device
|
||||||
|
// This returns NULL if the sessionID is not valid
|
||||||
|
const char* Steam_RemotePlay::GetSessionClientName( uint32 unSessionID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the form factor of the session client device
|
||||||
|
ESteamDeviceFormFactor Steam_RemotePlay::GetSessionClientFormFactor( uint32 unSessionID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return k_ESteamDeviceFormFactorUnknown;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Get the resolution, in pixels, of the session client device
|
||||||
|
// This is set to 0x0 if the resolution is not available
|
||||||
|
bool Steam_RemotePlay::BGetSessionClientResolution( uint32 unSessionID, int *pnResolutionX, int *pnResolutionY )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (pnResolutionX) *pnResolutionX = 0;
|
||||||
|
if (pnResolutionY) *pnResolutionY = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_RemotePlay::BStartRemotePlayTogether( bool bShowOverlay )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Invite a friend to Remote Play Together
|
||||||
|
// This returns false if the invite can't be sent
|
||||||
|
bool Steam_RemotePlay::BSendRemotePlayTogetherInvite( CSteamID steamIDFriend )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_RemotePlay::RunCallbacks()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_RemotePlay::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_sockets()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
@ -21,6 +21,7 @@ Steam_Screenshots::Steam_Screenshots(class Local_Storage* local_storage, class S
|
|||||||
local_storage(local_storage),
|
local_storage(local_storage),
|
||||||
callbacks(callbacks)
|
callbacks(callbacks)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ScreenshotHandle Steam_Screenshots::create_screenshot_handle()
|
ScreenshotHandle Steam_Screenshots::create_screenshot_handle()
|
||||||
|
119
dll/steam_tv.cpp
Normal file
119
dll/steam_tv.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_tv.h"
|
||||||
|
|
||||||
|
void Steam_TV::steam_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_TV *steam_parties = (Steam_TV *)object;
|
||||||
|
steam_parties->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::steam_run_every_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_TV *steam_parties = (Steam_TV *)object;
|
||||||
|
steam_parties->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_TV::Steam_TV(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_TV::steam_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_TV::steam_run_every_runcb, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_TV::~Steam_TV()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_TV::steam_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_TV::steam_run_every_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Steam_TV::IsBroadcasting(int *pnNumViewers)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::AddBroadcastGameData(const char * pchKey, const char * pchValue)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::RemoveBroadcastGameData(const char * pchKey)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::AddTimelineMarker(const char * pchTemplateName, bool bPersistent, uint8 nColorR, uint8 nColorG, uint8 nColorB)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::RemoveTimelineMarker()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint32 Steam_TV::AddRegion(const char * pchElementName, const char * pchTimelineDataSection, const SteamTVRegion_t * pSteamTVRegion, ESteamTVRegionBehavior eSteamTVRegionBehavior)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::RemoveRegion(uint32 unRegionHandle)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::RunCallbacks()
|
||||||
|
{
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_TV::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->has_networking_sockets()) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
1429
dll/steam_ugc.cpp
Normal file
1429
dll/steam_ugc.cpp
Normal file
File diff suppressed because it is too large
Load Diff
119
dll/steam_unified_messages.cpp
Normal file
119
dll/steam_unified_messages.cpp
Normal file
@ -0,0 +1,119 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_unified_messages.h"
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Unified_Messages::network_callback(void *object, Common_Message *msg)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Unified_Messages *steam_steamunifiedmessages = (Steam_Unified_Messages *)object;
|
||||||
|
steam_steamunifiedmessages->Callback(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Unified_Messages::steam_runcb(void *object)
|
||||||
|
{
|
||||||
|
// PRINT_DEBUG_ENTRY();
|
||||||
|
|
||||||
|
Steam_Unified_Messages *steam_steamunifiedmessages = (Steam_Unified_Messages *)object;
|
||||||
|
steam_steamunifiedmessages->RunCallbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Steam_Unified_Messages::Steam_Unified_Messages(class Settings *settings, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->network = network;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->run_every_runcb = run_every_runcb;
|
||||||
|
|
||||||
|
this->network->setCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Unified_Messages::network_callback, this);
|
||||||
|
this->run_every_runcb->add(&Steam_Unified_Messages::steam_runcb, this);
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_Unified_Messages::~Steam_Unified_Messages()
|
||||||
|
{
|
||||||
|
this->network->rmCallback(CALLBACK_ID_USER_STATUS, settings->get_local_steam_id(), &Steam_Unified_Messages::network_callback, this);
|
||||||
|
this->run_every_runcb->remove(&Steam_Unified_Messages::steam_runcb, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sends a service method (in binary serialized form) using the Steam Client.
|
||||||
|
// Returns a unified message handle (k_InvalidUnifiedMessageHandle if could not send the message).
|
||||||
|
ClientUnifiedMessageHandle Steam_Unified_Messages::SendMethod( const char *pchServiceMethod, const void *pRequestBuffer, uint32 unRequestBufferSize, uint64 unContext )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return ISteamUnifiedMessages::k_InvalidUnifiedMessageHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Gets the size of the response and the EResult. Returns false if the response is not ready yet.
|
||||||
|
bool Steam_Unified_Messages::GetMethodResponseInfo( ClientUnifiedMessageHandle hHandle, uint32 *punResponseSize, EResult *peResult )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Gets a response in binary serialized form (and optionally release the corresponding allocated memory).
|
||||||
|
bool Steam_Unified_Messages::GetMethodResponseData( ClientUnifiedMessageHandle hHandle, void *pResponseBuffer, uint32 unResponseBufferSize, bool bAutoRelease )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Releases the message and its corresponding allocated memory.
|
||||||
|
bool Steam_Unified_Messages::ReleaseMethod( ClientUnifiedMessageHandle hHandle )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Sends a service notification (in binary serialized form) using the Steam Client.
|
||||||
|
// Returns true if the notification was sent successfully.
|
||||||
|
bool Steam_Unified_Messages::SendNotification( const char *pchServiceNotification, const void *pNotificationBuffer, uint32 unNotificationBufferSize )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void Steam_Unified_Messages::RunCallbacks()
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_Unified_Messages::Callback(Common_Message *msg)
|
||||||
|
{
|
||||||
|
if (msg->has_low_level()) {
|
||||||
|
if (msg->low_level().type() == Low_Level::CONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
if (msg->low_level().type() == Low_Level::DISCONNECT) {
|
||||||
|
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
528
dll/steam_user.cpp
Normal file
528
dll/steam_user.cpp
Normal file
@ -0,0 +1,528 @@
|
|||||||
|
/* Copyright (C) 2019 Mr Goldberg
|
||||||
|
This file is part of the Goldberg Emulator
|
||||||
|
|
||||||
|
The Goldberg Emulator is free software; you can redistribute it and/or
|
||||||
|
modify it under the terms of the GNU Lesser General Public
|
||||||
|
License as published by the Free Software Foundation; either
|
||||||
|
version 3 of the License, or (at your option) any later version.
|
||||||
|
|
||||||
|
The Goldberg Emulator is distributed in the hope that it will be useful,
|
||||||
|
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||||
|
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||||
|
Lesser General Public License for more details.
|
||||||
|
|
||||||
|
You should have received a copy of the GNU Lesser General Public
|
||||||
|
License along with the Goldberg Emulator; if not, see
|
||||||
|
<http://www.gnu.org/licenses/>. */
|
||||||
|
|
||||||
|
#include "dll/steam_user.h"
|
||||||
|
#include "dll/auth.h"
|
||||||
|
#include "dll/appticket.h"
|
||||||
|
|
||||||
|
Steam_User::Steam_User(Settings *settings, Local_Storage *local_storage, class Networking *network, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
|
||||||
|
{
|
||||||
|
this->settings = settings;
|
||||||
|
this->local_storage = local_storage;
|
||||||
|
this->network = network;
|
||||||
|
this->callbacks = callbacks;
|
||||||
|
this->callback_results = callback_results;
|
||||||
|
|
||||||
|
recording = false;
|
||||||
|
auth_manager = new Auth_Manager(settings, network, callbacks);
|
||||||
|
}
|
||||||
|
|
||||||
|
Steam_User::~Steam_User()
|
||||||
|
{
|
||||||
|
delete auth_manager;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the HSteamUser this interface represents
|
||||||
|
// this is only used internally by the API, and by a few select interfaces that support multi-user
|
||||||
|
HSteamUser Steam_User::GetHSteamUser()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return CLIENT_HSTEAMUSER;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if the Steam client current has a live connection to the Steam servers.
|
||||||
|
// If false, it means there is no active connection due to either a networking issue on the local machine, or the Steam server is down/busy.
|
||||||
|
// The Steam client will automatically be trying to recreate the connection as often as possible.
|
||||||
|
bool Steam_User::BLoggedOn()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return !settings->is_offline();
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns the CSteamID of the account currently logged into the Steam client
|
||||||
|
// a CSteamID is a unique identifier for an account, and used to differentiate users in all parts of the Steamworks API
|
||||||
|
CSteamID Steam_User::GetSteamID()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
CSteamID id = settings->get_local_steam_id();
|
||||||
|
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Multiplayer Authentication functions
|
||||||
|
|
||||||
|
// InitiateGameConnection() starts the state machine for authenticating the game client with the game server
|
||||||
|
// It is the client portion of a three-way handshake between the client, the game server, and the steam servers
|
||||||
|
//
|
||||||
|
// Parameters:
|
||||||
|
// void *pAuthBlob - a pointer to empty memory that will be filled in with the authentication token.
|
||||||
|
// int cbMaxAuthBlob - the number of bytes of allocated memory in pBlob. Should be at least 2048 bytes.
|
||||||
|
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
|
||||||
|
// CGameID gameID - the ID of the current game. For games without mods, this is just CGameID( <appID> )
|
||||||
|
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
|
||||||
|
// bool bSecure - whether or not the client thinks that the game server is reporting itself as secure (i.e. VAC is running)
|
||||||
|
//
|
||||||
|
// return value - returns the number of bytes written to pBlob. If the return is 0, then the buffer passed in was too small, and the call has failed
|
||||||
|
// The contents of pBlob should then be sent to the game server, for it to use to complete the authentication process.
|
||||||
|
|
||||||
|
//steam returns 206 bytes
|
||||||
|
#define INITIATE_GAME_CONNECTION_TICKET_SIZE 206
|
||||||
|
|
||||||
|
int Steam_User::InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer, bool bSecure )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i %llu %u %u %u %p", cbMaxAuthBlob, steamIDGameServer.ConvertToUint64(), unIPServer, usPortServer, bSecure, pAuthBlob);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
if (cbMaxAuthBlob < INITIATE_GAME_CONNECTION_TICKET_SIZE) return 0;
|
||||||
|
if (!pAuthBlob) return 0;
|
||||||
|
uint32 out_size = INITIATE_GAME_CONNECTION_TICKET_SIZE;
|
||||||
|
auth_manager->getTicketData(pAuthBlob, INITIATE_GAME_CONNECTION_TICKET_SIZE, &out_size);
|
||||||
|
if (out_size > INITIATE_GAME_CONNECTION_TICKET_SIZE)
|
||||||
|
return 0;
|
||||||
|
return out_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
int Steam_User::InitiateGameConnection( void *pAuthBlob, int cbMaxAuthBlob, CSteamID steamIDGameServer, CGameID gameID, uint32 unIPServer, uint16 usPortServer, bool bSecure )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return InitiateGameConnection(pAuthBlob, cbMaxAuthBlob, steamIDGameServer, unIPServer, usPortServer, bSecure);
|
||||||
|
}
|
||||||
|
|
||||||
|
// notify of disconnect
|
||||||
|
// needs to occur when the game client leaves the specified game server, needs to match with the InitiateGameConnection() call
|
||||||
|
void Steam_User::TerminateGameConnection( uint32 unIPServer, uint16 usPortServer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Legacy functions
|
||||||
|
|
||||||
|
// used by only a few games to track usage events
|
||||||
|
void Steam_User::TrackAppUsageEvent( CGameID gameID, int eAppUsageEvent, const char *pchExtraInfo)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Steam_User::RefreshSteam2Login()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_TODO();
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the local storage folder for current Steam account to write application data, e.g. save games, configs etc.
|
||||||
|
// this will usually be something like "C:\Progam Files\Steam\userdata\<SteamID>\<AppID>\local"
|
||||||
|
bool Steam_User::GetUserDataFolder( char *pchBuffer, int cubBuffer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
if (!cubBuffer) return false;
|
||||||
|
|
||||||
|
std::string user_data = local_storage->get_path(Local_Storage::user_data_storage);
|
||||||
|
strncpy(pchBuffer, user_data.c_str(), cubBuffer - 1);
|
||||||
|
pchBuffer[cubBuffer - 1] = 0;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Starts voice recording. Once started, use GetVoice() to get the data
|
||||||
|
void Steam_User::StartVoiceRecording( )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
last_get_voice = std::chrono::high_resolution_clock::now();
|
||||||
|
recording = true;
|
||||||
|
//TODO:fix
|
||||||
|
recording = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stops voice recording. Because people often release push-to-talk keys early, the system will keep recording for
|
||||||
|
// a little bit after this function is called. GetVoice() should continue to be called until it returns
|
||||||
|
// k_eVoiceResultNotRecording
|
||||||
|
void Steam_User::StopVoiceRecording( )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
recording = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Determine the size of captured audio data that is available from GetVoice.
|
||||||
|
// Most applications will only use compressed data and should ignore the other
|
||||||
|
// parameters, which exist primarily for backwards compatibility. See comments
|
||||||
|
// below for further explanation of "uncompressed" data.
|
||||||
|
EVoiceResult Steam_User::GetAvailableVoice( uint32 *pcbCompressed, uint32 *pcbUncompressed_Deprecated, uint32 nUncompressedVoiceDesiredSampleRate_Deprecated )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
if (pcbCompressed) *pcbCompressed = 0;
|
||||||
|
if (pcbUncompressed_Deprecated) *pcbUncompressed_Deprecated = 0;
|
||||||
|
if (!recording) return k_EVoiceResultNotRecording;
|
||||||
|
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
|
||||||
|
if (pcbCompressed) *pcbCompressed = seconds * 1024.0 * 64.0 / 8.0;
|
||||||
|
if (pcbUncompressed_Deprecated) *pcbUncompressed_Deprecated = seconds * (double)nUncompressedVoiceDesiredSampleRate_Deprecated * 2.0;
|
||||||
|
|
||||||
|
return k_EVoiceResultOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVoiceResult Steam_User::GetAvailableVoice(uint32 *pcbCompressed, uint32 *pcbUncompressed)
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return GetAvailableVoice(pcbCompressed, pcbUncompressed, 11025);
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
// NOTE: "uncompressed" audio is a deprecated feature and should not be used
|
||||||
|
// by most applications. It is raw single-channel 16-bit PCM wave data which
|
||||||
|
// may have been run through preprocessing filters and/or had silence removed,
|
||||||
|
// so the uncompressed audio could have a shorter duration than you expect.
|
||||||
|
// There may be no data at all during long periods of silence. Also, fetching
|
||||||
|
// uncompressed audio will cause GetVoice to discard any leftover compressed
|
||||||
|
// audio, so you must fetch both types at once. Finally, GetAvailableVoice is
|
||||||
|
// not precisely accurate when the uncompressed size is requested. So if you
|
||||||
|
// really need to use uncompressed audio, you should call GetVoice frequently
|
||||||
|
// with two very large (20kb+) output buffers instead of trying to allocate
|
||||||
|
// perfectly-sized buffers. But most applications should ignore all of these
|
||||||
|
// details and simply leave the "uncompressed" parameters as NULL/zero.
|
||||||
|
// ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
// Read captured audio data from the microphone buffer. This should be called
|
||||||
|
// at least once per frame, and preferably every few milliseconds, to keep the
|
||||||
|
// microphone input delay as low as possible. Most applications will only use
|
||||||
|
// compressed data and should pass NULL/zero for the "uncompressed" parameters.
|
||||||
|
// Compressed data can be transmitted by your application and decoded into raw
|
||||||
|
// using the DecompressVoice function below.
|
||||||
|
EVoiceResult Steam_User::GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed_Deprecated, void *pUncompressedDestBuffer_Deprecated , uint32 cbUncompressedDestBufferSize_Deprecated , uint32 *nUncompressBytesWritten_Deprecated , uint32 nUncompressedVoiceDesiredSampleRate_Deprecated )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
if (!recording) return k_EVoiceResultNotRecording;
|
||||||
|
double seconds = std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::high_resolution_clock::now() - last_get_voice).count();
|
||||||
|
if (bWantCompressed) {
|
||||||
|
uint32 towrite = seconds * 1024.0 * 64.0 / 8.0;
|
||||||
|
if (cbDestBufferSize < towrite) towrite = cbDestBufferSize;
|
||||||
|
if (pDestBuffer) memset(pDestBuffer, 0, towrite);
|
||||||
|
if (nBytesWritten) *nBytesWritten = towrite;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (bWantUncompressed_Deprecated) {
|
||||||
|
PRINT_DEBUG("Wanted Uncompressed");
|
||||||
|
}
|
||||||
|
|
||||||
|
last_get_voice = std::chrono::high_resolution_clock::now();
|
||||||
|
return k_EVoiceResultOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVoiceResult Steam_User::GetVoice( bool bWantCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, bool bWantUncompressed, void *pUncompressedDestBuffer, uint32 cbUncompressedDestBufferSize, uint32 *nUncompressBytesWritten )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return GetVoice(bWantCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, bWantUncompressed, pUncompressedDestBuffer, cbUncompressedDestBufferSize, nUncompressBytesWritten, 11025);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVoiceResult Steam_User::GetCompressedVoice( void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return GetVoice(true, pDestBuffer, cbDestBufferSize, nBytesWritten, false, NULL, 0, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decodes the compressed voice data returned by GetVoice. The output data is
|
||||||
|
// raw single-channel 16-bit PCM audio. The decoder supports any sample rate
|
||||||
|
// from 11025 to 48000; see GetVoiceOptimalSampleRate() below for details.
|
||||||
|
// If the output buffer is not large enough, then *nBytesWritten will be set
|
||||||
|
// to the required buffer size, and k_EVoiceResultBufferTooSmall is returned.
|
||||||
|
// It is suggested to start with a 20kb buffer and reallocate as necessary.
|
||||||
|
EVoiceResult Steam_User::DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten, uint32 nDesiredSampleRate )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
if (!recording) return k_EVoiceResultNotRecording;
|
||||||
|
uint32 uncompressed = (double)cbCompressed * ((double)nDesiredSampleRate / 8192.0);
|
||||||
|
if(nBytesWritten) *nBytesWritten = uncompressed;
|
||||||
|
if (uncompressed > cbDestBufferSize) uncompressed = cbDestBufferSize;
|
||||||
|
if (pDestBuffer) memset(pDestBuffer, 0, uncompressed);
|
||||||
|
|
||||||
|
return k_EVoiceResultOK;
|
||||||
|
}
|
||||||
|
|
||||||
|
EVoiceResult Steam_User::DecompressVoice( const void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("old");
|
||||||
|
return DecompressVoice(pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, 11025);
|
||||||
|
}
|
||||||
|
|
||||||
|
EVoiceResult Steam_User::DecompressVoice( void *pCompressed, uint32 cbCompressed, void *pDestBuffer, uint32 cbDestBufferSize, uint32 *nBytesWritten )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("older");
|
||||||
|
return DecompressVoice(pCompressed, cbCompressed, pDestBuffer, cbDestBufferSize, nBytesWritten, 11025);
|
||||||
|
}
|
||||||
|
|
||||||
|
// This returns the native sample rate of the Steam voice decompressor
|
||||||
|
// this sample rate for DecompressVoice will perform the least CPU processing.
|
||||||
|
// However, the final audio quality will depend on how well the audio device
|
||||||
|
// (and/or your application's audio output SDK) deals with lower sample rates.
|
||||||
|
// You may find that you get the best audio output quality when you ignore
|
||||||
|
// this function and use the native sample rate of your audio output device,
|
||||||
|
// which is usually 48000 or 44100.
|
||||||
|
uint32 Steam_User::GetVoiceOptimalSampleRate()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 48000;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieve ticket to be sent to the entity who wishes to authenticate you.
|
||||||
|
// pcbTicket retrieves the length of the actual ticket.
|
||||||
|
HAuthTicket Steam_User::GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
||||||
|
{
|
||||||
|
return GetAuthSessionTicket(pTicket, cbMaxTicket, pcbTicket, NULL);
|
||||||
|
}
|
||||||
|
// SteamNetworkingIdentity is an optional input parameter to hold the public IP address or SteamID of the entity you are connecting to
|
||||||
|
// if an IP address is passed Steam will only allow the ticket to be used by an entity with that IP address
|
||||||
|
// if a Steam ID is passed Steam will only allow the ticket to be used by that Steam ID
|
||||||
|
HAuthTicket Steam_User::GetAuthSessionTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket, const SteamNetworkingIdentity *pSteamNetworkingIdentity )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%p [%i] %p", pTicket, cbMaxTicket, pcbTicket);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
if (!pTicket) return k_HAuthTicketInvalid;
|
||||||
|
|
||||||
|
return auth_manager->getTicket(pTicket, cbMaxTicket, pcbTicket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Request a ticket which will be used for webapi "ISteamUserAuth\AuthenticateUserTicket"
|
||||||
|
// pchIdentity is an optional input parameter to identify the service the ticket will be sent to
|
||||||
|
// the ticket will be returned in callback GetTicketForWebApiResponse_t
|
||||||
|
HAuthTicket Steam_User::GetAuthTicketForWebApi( const char *pchIdentity )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%s", pchIdentity);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
return auth_manager->getWebApiTicket(pchIdentity);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Authenticate ticket from entity steamID to be sure it is valid and isnt reused
|
||||||
|
// Registers for callbacks if the entity goes offline or cancels the ticket ( see ValidateAuthTicketResponse_t callback and EAuthSessionResponse )
|
||||||
|
EBeginAuthSessionResult Steam_User::BeginAuthSession( const void *pAuthTicket, int cbAuthTicket, CSteamID steamID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i %llu", cbAuthTicket, steamID.ConvertToUint64());
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
return auth_manager->beginAuth(pAuthTicket, cbAuthTicket, steamID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Stop tracking started by BeginAuthSession - called when no longer playing game with this entity
|
||||||
|
void Steam_User::EndAuthSession( CSteamID steamID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
auth_manager->endAuth(steamID);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Cancel auth ticket from GetAuthSessionTicket, called when no longer playing game with the entity you gave the ticket to
|
||||||
|
void Steam_User::CancelAuthTicket( HAuthTicket hAuthTicket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
|
||||||
|
auth_manager->cancelTicket(hAuthTicket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// After receiving a user's authentication data, and passing it to BeginAuthSession, use this function
|
||||||
|
// to determine if the user owns downloadable content specified by the provided AppID.
|
||||||
|
EUserHasLicenseForAppResult Steam_User::UserHasLicenseForApp( CSteamID steamID, AppId_t appID )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return k_EUserHasLicenseResultHasLicense;
|
||||||
|
}
|
||||||
|
|
||||||
|
// returns true if this users looks like they are behind a NAT device. Only valid once the user has connected to steam
|
||||||
|
// (i.e a SteamServersConnected_t has been issued) and may not catch all forms of NAT.
|
||||||
|
bool Steam_User::BIsBehindNAT()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// set data to be replicated to friends so that they can join your game
|
||||||
|
// CSteamID steamIDGameServer - the steamID of the game server, received from the game server by the client
|
||||||
|
// uint32 unIPServer, uint16 usPortServer - the IP address of the game server
|
||||||
|
void Steam_User::AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
Gameserver *server = new Gameserver();
|
||||||
|
server->set_id(steamIDGameServer.ConvertToUint64());
|
||||||
|
server->set_ip(unIPServer);
|
||||||
|
server->set_port(usPortServer);
|
||||||
|
server->set_query_port(usPortServer);
|
||||||
|
server->set_appid(settings->get_local_game_id().ToUint64());
|
||||||
|
|
||||||
|
if (settings->matchmaking_server_list_always_lan_type)
|
||||||
|
server->set_type(eLANServer);
|
||||||
|
else
|
||||||
|
server->set_type(eFriendsServer);
|
||||||
|
|
||||||
|
Common_Message msg;
|
||||||
|
msg.set_allocated_gameserver(server);
|
||||||
|
msg.set_source_id(settings->get_local_steam_id().ConvertToUint64());
|
||||||
|
network->sendToAllIndividuals(&msg, true);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requests a ticket encrypted with an app specific shared key
|
||||||
|
// pDataToInclude, cbDataToInclude will be encrypted into the ticket
|
||||||
|
// ( This is asynchronous, you must wait for the ticket to be completed by the server )
|
||||||
|
STEAM_CALL_RESULT( EncryptedAppTicketResponse_t )
|
||||||
|
SteamAPICall_t Steam_User::RequestEncryptedAppTicket( void *pDataToInclude, int cbDataToInclude )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i", cbDataToInclude);
|
||||||
|
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||||
|
EncryptedAppTicketResponse_t data;
|
||||||
|
data.m_eResult = k_EResultOK;
|
||||||
|
|
||||||
|
DecryptedAppTicket ticket;
|
||||||
|
ticket.TicketV1.Reset();
|
||||||
|
ticket.TicketV2.Reset();
|
||||||
|
ticket.TicketV4.Reset();
|
||||||
|
|
||||||
|
ticket.TicketV1.TicketVersion = 1;
|
||||||
|
if (pDataToInclude) {
|
||||||
|
ticket.TicketV1.UserData.assign((uint8_t*)pDataToInclude, (uint8_t*)pDataToInclude + cbDataToInclude);
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket.TicketV2.TicketVersion = 4;
|
||||||
|
ticket.TicketV2.SteamID = settings->get_local_steam_id().ConvertToUint64();
|
||||||
|
ticket.TicketV2.TicketIssueTime = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
|
||||||
|
ticket.TicketV2.TicketValidityEnd = ticket.TicketV2.TicketIssueTime + (21 * 24 * 60 * 60);
|
||||||
|
|
||||||
|
for (int i = 0; i < 140; ++i)
|
||||||
|
{
|
||||||
|
AppId_t appid;
|
||||||
|
bool available;
|
||||||
|
std::string name;
|
||||||
|
if (!settings->getDLC(appid, appid, available, name)) break;
|
||||||
|
ticket.TicketV4.AppIDs.emplace_back(appid);
|
||||||
|
}
|
||||||
|
|
||||||
|
ticket.TicketV4.HasVACStatus = true;
|
||||||
|
ticket.TicketV4.VACStatus = 0;
|
||||||
|
|
||||||
|
auto serialized = ticket.SerializeTicket();
|
||||||
|
|
||||||
|
SteamAppTicket_pb pb;
|
||||||
|
pb.set_ticket_version_no(1);
|
||||||
|
pb.set_crc_encryptedticket(0); // TODO: Find out how to compute the CRC
|
||||||
|
pb.set_cb_encrypteduserdata(cbDataToInclude);
|
||||||
|
pb.set_cb_encrypted_appownershipticket(serialized.size() - 16);
|
||||||
|
pb.mutable_encrypted_ticket()->assign(serialized.begin(), serialized.end()); // TODO: Find how to encrypt datas
|
||||||
|
|
||||||
|
encrypted_app_ticket = pb.SerializeAsString();
|
||||||
|
|
||||||
|
return callback_results->addCallResult(data.k_iCallback, &data, sizeof(data));
|
||||||
|
}
|
||||||
|
|
||||||
|
// retrieve a finished ticket
|
||||||
|
bool Steam_User::GetEncryptedAppTicket( void *pTicket, int cbMaxTicket, uint32 *pcbTicket )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG("%i", cbMaxTicket);
|
||||||
|
unsigned int ticket_size = encrypted_app_ticket.size();
|
||||||
|
if (!cbMaxTicket) {
|
||||||
|
if (!pcbTicket) return false;
|
||||||
|
*pcbTicket = ticket_size;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!pTicket) return false;
|
||||||
|
if (ticket_size > cbMaxTicket) return false;
|
||||||
|
encrypted_app_ticket.copy((char *)pTicket, cbMaxTicket);
|
||||||
|
if (pcbTicket) *pcbTicket = ticket_size;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Trading Card badges data access
|
||||||
|
// if you only have one set of cards, the series will be 1
|
||||||
|
// the user has can have two different badges for a series; the regular (max level 5) and the foil (max level 1)
|
||||||
|
int Steam_User::GetGameBadgeLevel( int nSeries, bool bFoil )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets the Steam Level of the user, as shown on their profile
|
||||||
|
int Steam_User::GetPlayerSteamLevel()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 100;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Requests a URL which authenticates an in-game browser for store check-out,
|
||||||
|
// and then redirects to the specified URL. As long as the in-game browser
|
||||||
|
// accepts and handles session cookies, Steam microtransaction checkout pages
|
||||||
|
// will automatically recognize the user instead of presenting a login page.
|
||||||
|
// The result of this API call will be a StoreAuthURLResponse_t callback.
|
||||||
|
// NOTE: The URL has a very short lifetime to prevent history-snooping attacks,
|
||||||
|
// so you should only call this API when you are about to launch the browser,
|
||||||
|
// or else immediately navigate to the result URL using a hidden browser window.
|
||||||
|
// NOTE 2: The resulting authorization cookie has an expiration time of one day,
|
||||||
|
// so it would be a good idea to request and visit a new auth URL every 12 hours.
|
||||||
|
STEAM_CALL_RESULT( StoreAuthURLResponse_t )
|
||||||
|
SteamAPICall_t Steam_User::RequestStoreAuthURL( const char *pchRedirectURL )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets whether the users phone number is verified
|
||||||
|
bool Steam_User::BIsPhoneVerified()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets whether the user has two factor enabled on their account
|
||||||
|
bool Steam_User::BIsTwoFactorEnabled()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets whether the users phone number is identifying
|
||||||
|
bool Steam_User::BIsPhoneIdentifying()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// gets whether the users phone number is awaiting (re)verification
|
||||||
|
bool Steam_User::BIsPhoneRequiringVerification()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
STEAM_CALL_RESULT( MarketEligibilityResponse_t )
|
||||||
|
SteamAPICall_t Steam_User::GetMarketEligibility()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retrieves anti indulgence / duration control for current user
|
||||||
|
STEAM_CALL_RESULT( DurationControl_t )
|
||||||
|
SteamAPICall_t Steam_User::GetDurationControl()
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Advise steam china duration control system about the online state of the game.
|
||||||
|
// This will prevent offline gameplay time from counting against a user's
|
||||||
|
// playtime limits.
|
||||||
|
bool Steam_User::BSetDurationControlOnlineState( EDurationControlOnlineState eNewState )
|
||||||
|
{
|
||||||
|
PRINT_DEBUG_ENTRY();
|
||||||
|
return false;
|
||||||
|
}
|
@ -68,6 +68,28 @@ void Steam_Leaderboard::sort_entries()
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
// --- achievement_trigger ---
|
||||||
|
bool achievement_trigger::check_triggered(float stat) const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (std::stof(max_value) <= stat) return true;
|
||||||
|
} catch (...) {}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool achievement_trigger::check_triggered(int32 stat) const
|
||||||
|
{
|
||||||
|
try {
|
||||||
|
if (std::stoi(max_value) <= stat) return true;
|
||||||
|
} catch (...) {}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
// --- achievement_trigger ---
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
void Steam_User_Stats::load_achievements_db()
|
void Steam_User_Stats::load_achievements_db()
|
||||||
{
|
{
|
||||||
std::string file_path = Local_Storage::get_game_settings_path() + achievements_user_file;
|
std::string file_path = Local_Storage::get_game_settings_path() + achievements_user_file;
|
||||||
|
@ -20,10 +20,10 @@
|
|||||||
|
|
||||||
|
|
||||||
Steam_Utils::Steam_Utils(Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, Steam_Overlay *overlay):
|
Steam_Utils::Steam_Utils(Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, Steam_Overlay *overlay):
|
||||||
settings(settings),
|
settings(settings),
|
||||||
callback_results(callback_results),
|
callback_results(callback_results),
|
||||||
callbacks(callbacks),
|
callbacks(callbacks),
|
||||||
overlay(overlay)
|
overlay(overlay)
|
||||||
{
|
{
|
||||||
|
|
||||||
}
|
}
|
||||||
|
@ -9,6 +9,13 @@ Ugc_Remote_Storage_Bridge::Ugc_Remote_Storage_Bridge(class Settings *settings)
|
|||||||
subscribed = settings->modSet();
|
subscribed = settings->modSet();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ugc_Remote_Storage_Bridge::~Ugc_Remote_Storage_Bridge()
|
||||||
|
{
|
||||||
|
std::lock_guard lock(global_mutex);
|
||||||
|
|
||||||
|
steam_ugc_queries.clear();
|
||||||
|
}
|
||||||
|
|
||||||
void Ugc_Remote_Storage_Bridge::add_ugc_query_result(UGCHandle_t file_handle, PublishedFileId_t fileid, bool handle_of_primary_file)
|
void Ugc_Remote_Storage_Bridge::add_ugc_query_result(UGCHandle_t file_handle, PublishedFileId_t fileid, bool handle_of_primary_file)
|
||||||
{
|
{
|
||||||
std::lock_guard lock(global_mutex);
|
std::lock_guard lock(global_mutex);
|
||||||
@ -62,10 +69,3 @@ std::set<PublishedFileId_t>::iterator Ugc_Remote_Storage_Bridge::subbed_mods_itr
|
|||||||
{
|
{
|
||||||
return subscribed.end();
|
return subscribed.end();
|
||||||
}
|
}
|
||||||
|
|
||||||
Ugc_Remote_Storage_Bridge::~Ugc_Remote_Storage_Bridge()
|
|
||||||
{
|
|
||||||
std::lock_guard lock(global_mutex);
|
|
||||||
|
|
||||||
steam_ugc_queries.clear();
|
|
||||||
}
|
|
||||||
|
@ -254,7 +254,7 @@ public:
|
|||||||
void AddAchievementNotification(nlohmann::json const& ach);
|
void AddAchievementNotification(nlohmann::json const& ach);
|
||||||
};
|
};
|
||||||
|
|
||||||
#else
|
#else // EMU_OVERLAY
|
||||||
|
|
||||||
class Steam_Overlay
|
class Steam_Overlay
|
||||||
{
|
{
|
||||||
@ -288,6 +288,6 @@ public:
|
|||||||
void AddAchievementNotification(nlohmann::json const& ach) {}
|
void AddAchievementNotification(nlohmann::json const& ach) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif // EMU_OVERLAY
|
||||||
|
|
||||||
#endif//__INCLUDED_STEAM_OVERLAY_H__
|
#endif //__INCLUDED_STEAM_OVERLAY_H__
|
||||||
|
@ -6,8 +6,6 @@
|
|||||||
// avoids confusing ImGui when another label has the same text "MyText"
|
// avoids confusing ImGui when another label has the same text "MyText"
|
||||||
|
|
||||||
#include "overlay/steam_overlay.h"
|
#include "overlay/steam_overlay.h"
|
||||||
#include "overlay/notification.h"
|
|
||||||
#include "overlay/steam_overlay_translations.h"
|
|
||||||
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include <string>
|
#include <string>
|
||||||
@ -17,14 +15,17 @@
|
|||||||
#include <random>
|
#include <random>
|
||||||
|
|
||||||
#include "InGameOverlay/ImGui/imgui.h"
|
#include "InGameOverlay/ImGui/imgui.h"
|
||||||
|
#include "InGameOverlay/RendererDetector.h"
|
||||||
|
|
||||||
#include "dll/dll.h"
|
#include "dll/dll.h"
|
||||||
#include "dll/settings_parser.h"
|
#include "dll/settings_parser.h"
|
||||||
|
|
||||||
#include "InGameOverlay/RendererDetector.h"
|
// translation
|
||||||
|
#include "overlay/steam_overlay_translations.h"
|
||||||
// fonts
|
// fonts
|
||||||
#include "fonts/unifont.hpp"
|
#include "fonts/unifont.hpp"
|
||||||
|
// builtin audio
|
||||||
|
#include "overlay/notification.h"
|
||||||
|
|
||||||
#define URL_WINDOW_NAME "URL Window"
|
#define URL_WINDOW_NAME "URL Window"
|
||||||
|
|
||||||
@ -135,7 +136,7 @@ Steam_Overlay::Steam_Overlay(Settings* settings, Local_Storage *local_storage, S
|
|||||||
}
|
}
|
||||||
|
|
||||||
this->network->setCallback(CALLBACK_ID_STEAM_MESSAGES, settings->get_local_steam_id(), &Steam_Overlay::overlay_networking_callback, this);
|
this->network->setCallback(CALLBACK_ID_STEAM_MESSAGES, settings->get_local_steam_id(), &Steam_Overlay::overlay_networking_callback, this);
|
||||||
run_every_runcb->add(&Steam_Overlay::overlay_run_callback, this);
|
this->run_every_runcb->add(&Steam_Overlay::overlay_run_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
Steam_Overlay::~Steam_Overlay()
|
Steam_Overlay::~Steam_Overlay()
|
||||||
@ -143,7 +144,7 @@ Steam_Overlay::~Steam_Overlay()
|
|||||||
if (settings->disable_overlay) return;
|
if (settings->disable_overlay) return;
|
||||||
|
|
||||||
this->network->rmCallback(CALLBACK_ID_STEAM_MESSAGES, settings->get_local_steam_id(), &Steam_Overlay::overlay_networking_callback, this);
|
this->network->rmCallback(CALLBACK_ID_STEAM_MESSAGES, settings->get_local_steam_id(), &Steam_Overlay::overlay_networking_callback, this);
|
||||||
run_every_runcb->remove(&Steam_Overlay::overlay_run_callback, this);
|
this->run_every_runcb->remove(&Steam_Overlay::overlay_run_callback, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Steam_Overlay::request_renderer_detector()
|
void Steam_Overlay::request_renderer_detector()
|
||||||
@ -1038,7 +1039,7 @@ void Steam_Overlay::build_notifications(int width, int height)
|
|||||||
friend_actions_temp.push(it->frd->first);
|
friend_actions_temp.push(it->frd->first);
|
||||||
// when we click "accept game invite" from someone else, we want to remove this notification immediately since it's no longer relevant
|
// when we click "accept game invite" from someone else, we want to remove this notification immediately since it's no longer relevant
|
||||||
// this assignment will make the notification elapsed time insanely large
|
// this assignment will make the notification elapsed time insanely large
|
||||||
it->start_time = std::chrono::milliseconds(0);
|
it->start_time = {};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
Loading…
Reference in New Issue
Block a user