mirror of
https://github.com/Detanup01/gbe_fork.git
synced 2024-12-24 09:24:15 +08:00
(RIN forum) add initial hotfix by ce20fdf2
* + revert the change to SetProduct() and SetGameDescription() * + less verbose return in Steam_GameServer::BSecure() * + add missing note in ReadMe about libssq
This commit is contained in:
parent
82adbe4fc7
commit
75e6d7c8ab
15
README.md
15
README.md
@ -64,6 +64,21 @@ cd vcpkg
|
||||
./bootstrap-vcpkg.bat
|
||||
./vcpkg install protobuf --triplet x86-windows-static
|
||||
./vcpkg install protobuf --triplet x64-windows-static
|
||||
|
||||
./vcpkg install curl --triplet x86-windows-static
|
||||
./vcpkg install curl --triplet x64-windows-static
|
||||
|
||||
cd..
|
||||
git clone https://github.com/BinaryAlien/libssq.git
|
||||
cd libssq
|
||||
mkdir build32
|
||||
:: -G source: https://cmake.org/cmake/help/latest/manual/cmake-generators.7.html
|
||||
cmake -G "Visual Studio 17 2022" -A Win32 -S . -B "build32"
|
||||
cmake --build build32 --config Release
|
||||
mkdir build64
|
||||
cmake -G "Visual Studio 17 2022" -A x64 -S . -B "build64"
|
||||
cmake --build build64 --config Release
|
||||
|
||||
cd ..
|
||||
git clone https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
|
||||
cd goldberg_emulator
|
||||
|
@ -56,6 +56,11 @@ Subscribed Groups:
|
||||
Some games like payday 2 check which groups you are subscribed in and unlock things based on that. You can provide a list of subscribed groups to the game with a steam_settings\subscribed_groups.txt file.
|
||||
See steam_settings.EXAMPLE\subscribed_groups.EXAMPLE.txt for an example for payday 2.
|
||||
|
||||
Subscribed Groups (Clans):
|
||||
Some games like counter-strike check which groups you are subscribed in and allow you to choose a group clan. You can provide a list of subscribed group ids, names, and tags to the game with a subscribed_groups_clans.txt file placed in the Goldberg SteamEmu Saves\settings or in steam_settings folder.
|
||||
Group ids must be valid and can be obtained by pasting '/memberslistxml/?xml=1' at the end of a Steam group page. Double tabs that are used as seperators must not be removed.
|
||||
See steam_settings.EXAMPLE\subscribed_groups_clans.EXAMPLE.txt for an example.
|
||||
|
||||
App paths:
|
||||
Some rare games might need to be provided one or more paths to app ids. For example the path to where a dlc is installed. This sets the paths returned by the Steam_Apps::GetAppInstallDir function.
|
||||
See steam_settings.EXAMPLE\app_paths.EXAMPLE.txt for an example.
|
||||
@ -65,6 +70,7 @@ Note that paths are treated as relative paths from where the steam_api dll is lo
|
||||
Mods:
|
||||
Put your mods in the steam_settings\mods\ folder. The steam_settings folder must be placed right beside my emulator dll.
|
||||
Mod folders must be a number corresponding to the file id of the mod.
|
||||
Some games may require extra information about a mod. This information can be passed to the game by using a mods.EXAMPLE.txt file and mod_images folder stored in the steam_settings folder.
|
||||
See the steam_settings.EXAMPLE folder for an example.
|
||||
|
||||
Steam appid:
|
||||
@ -123,6 +129,18 @@ For example this url: https://en.wikipedia.org/wiki/Main_Page
|
||||
Would be: steam_settings\http\en.wikipedia.org\wiki\Main_Page
|
||||
The Main_Page file would contain the data returned by the steamHTTP api when it tries to access: https://en.wikipedia.org/wiki/Main_Page
|
||||
An example that was made for payday 2 can be found in steam_settings.EXAMPLE
|
||||
To allow external downloads which will be stored in this steam_settings\http folder copy the http_online file from the example folder to the steam_settings folder with .EXAMPLE removed from the file name.
|
||||
|
||||
Avatar:
|
||||
Copy a PNG or JPG image to your Goldberg SteamEmu Saves\settings or steam_settings folder and name it account_avatar
|
||||
You can also set a default profile picture for users who are missing one by copying a similar file called account_avatar_default
|
||||
For games that do not work with avatars you can place a disable_account_avatar.txt file into the steam_settings folder.
|
||||
You can find examples in steam_settings.EXAMPLE
|
||||
|
||||
Server browser:
|
||||
Create a text file called serverbrowser.txt with a list of ips in the Goldberg SteamEmu Saves\7\remote folder.
|
||||
serverbrowser_favorites.txt and serverbrowser_history.txt are also stored in this folder.
|
||||
Best to keep amount of servers to a low since server browser is not threaded yet and will cause the game to freeze for a bit while refreshing.
|
||||
|
||||
|
||||
Support for CPY steam_api(64).dll cracks: See the build in the experimental folder.
|
||||
|
@ -30,6 +30,9 @@
|
||||
#define STB_IMAGE_WRITE_STATIC
|
||||
#include "../stb/stb_image_write.h"
|
||||
|
||||
#define STB_IMAGE_RESIZE_IMPLEMENTATION
|
||||
#include "../stb/stb_image_resize.h"
|
||||
|
||||
struct File_Data {
|
||||
std::string name;
|
||||
};
|
||||
@ -161,6 +164,11 @@ std::vector<image_pixel_t> Local_Storage::load_image(std::string const& image_pa
|
||||
return std::vector<image_pixel_t>();
|
||||
}
|
||||
|
||||
std::string Local_Storage::load_image_resized(std::string const& image_path, std::string const& image_data, int resolution)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
bool Local_Storage::save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels)
|
||||
{
|
||||
return false;
|
||||
@ -783,6 +791,34 @@ std::vector<image_pixel_t> Local_Storage::load_image(std::string const& image_pa
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string Local_Storage::load_image_resized(std::string const& image_path, std::string const& image_data, int resolution)
|
||||
{
|
||||
int width, height;
|
||||
char *resized_img = (char *)malloc(sizeof(char) * 184 * 184 * 4);
|
||||
unsigned char* img;
|
||||
|
||||
if (image_path.length() > 0)
|
||||
{
|
||||
img = stbi_load(image_path.c_str(), &width, &height, nullptr, 4);
|
||||
|
||||
if (img != nullptr)
|
||||
{
|
||||
stbir_resize_uint8(img, width, height, NULL, (unsigned char *)resized_img, resolution, resolution, NULL, 4);
|
||||
stbi_image_free(img);
|
||||
}
|
||||
}
|
||||
else if (image_data.length() > 0)
|
||||
{
|
||||
stbir_resize_uint8((unsigned char *)image_data.c_str(), 184, 184, NULL, (unsigned char *)resized_img, resolution, resolution, NULL, 4);
|
||||
}
|
||||
|
||||
std::string resized_image(resized_img, resolution * resolution * 4);
|
||||
free(resized_img);
|
||||
|
||||
reset_LastError();
|
||||
return resized_image;
|
||||
}
|
||||
|
||||
bool Local_Storage::save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels)
|
||||
{
|
||||
std::string screenshot_path = std::move(save_directory + appid + screenshots_folder + PATH_SEPARATOR);
|
||||
|
@ -85,6 +85,7 @@ public:
|
||||
bool write_json_file(std::string folder, std::string const& file, nlohmann::json const& json);
|
||||
|
||||
std::vector<image_pixel_t> load_image(std::string const& image_path);
|
||||
static std::string load_image_resized(std::string const& image_path, std::string const& image_data, int resolution);
|
||||
bool save_screenshot(std::string const& image_path, uint8_t* img_ptr, int32_t width, int32_t height, int32_t channels);
|
||||
};
|
||||
|
||||
|
@ -169,6 +169,7 @@ message Gameserver {
|
||||
uint32 appid = 35;
|
||||
|
||||
bool offline = 48;
|
||||
uint32 type = 49;
|
||||
}
|
||||
|
||||
message Friend {
|
||||
@ -177,6 +178,7 @@ message Friend {
|
||||
map<string, bytes> rich_presence = 3;
|
||||
uint32 appid = 4;
|
||||
uint64 lobby_id = 5;
|
||||
bytes avatar = 6;
|
||||
}
|
||||
|
||||
message Auth_Ticket {
|
||||
|
@ -16,6 +16,7 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "network.h"
|
||||
#include "dll.h"
|
||||
|
||||
#define MAX_BROADCASTS 16
|
||||
static int number_broadcasts = -1;
|
||||
@ -839,6 +840,12 @@ Networking::Networking(CSteamID id, uint32 appid, uint16 port, std::set<IP_PORT>
|
||||
PRINT_DEBUG("TCP: could not initialize %i\n", get_last_error());
|
||||
}
|
||||
|
||||
if (curl_global_init(CURL_GLOBAL_NOTHING) == 0) {
|
||||
PRINT_DEBUG("CURL successful\n");
|
||||
} else {
|
||||
PRINT_DEBUG("CURL: could not initialize\n");
|
||||
}
|
||||
|
||||
if (is_socket_valid(udp_socket) && is_socket_valid(tcp_socket)) {
|
||||
PRINT_DEBUG("Networking initialized successfully on udp: %u tcp: %u \n", udp_port, tcp_port);
|
||||
enabled = true;
|
||||
@ -862,6 +869,8 @@ Networking::~Networking()
|
||||
|
||||
kill_socket(udp_socket);
|
||||
kill_socket(tcp_socket);
|
||||
|
||||
curl_global_cleanup();
|
||||
}
|
||||
|
||||
Common_Message Networking::create_announce(bool request)
|
||||
@ -930,6 +939,22 @@ void Networking::Run()
|
||||
char data[MAX_UDP_SIZE];
|
||||
int len;
|
||||
|
||||
if (query_alive && is_socket_valid(query_socket)) {
|
||||
PRINT_DEBUG("RECV QUERY\n");
|
||||
Steam_Client* client = get_steam_client();
|
||||
sockaddr_in addr;
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
while ((len = receive_packet(query_socket, &ip_port, data, sizeof(data))) >= 0) {
|
||||
client->steam_gameserver->HandleIncomingPacket(data, len, htonl(ip_port.ip), htons(ip_port.port));
|
||||
len = client->steam_gameserver->GetNextOutgoingPacket(data, sizeof(data), &ip_port.ip, &ip_port.port);
|
||||
|
||||
addr.sin_addr.s_addr = htonl(ip_port.ip);
|
||||
addr.sin_port = htons(ip_port.port);
|
||||
sendto(query_socket, data, len, 0, (sockaddr*)&addr, sizeof(addr));
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_DEBUG("RECV UDP\n");
|
||||
while((len = receive_packet(udp_socket, &ip_port, data, sizeof(data))) >= 0) {
|
||||
PRINT_DEBUG("recv %i %hhu.%hhu.%hhu.%hhu:%hu\n", len, ((unsigned char *)&ip_port.ip)[0], ((unsigned char *)&ip_port.ip)[1], ((unsigned char *)&ip_port.ip)[2], ((unsigned char *)&ip_port.ip)[3], htons(ip_port.port));
|
||||
@ -1288,3 +1313,74 @@ uint32 Networking::getOwnIP()
|
||||
{
|
||||
return own_ip;
|
||||
}
|
||||
|
||||
void Networking::startQuery(IP_PORT ip_port)
|
||||
{
|
||||
if (ip_port.port <= 1024)
|
||||
return;
|
||||
|
||||
if (!query_alive)
|
||||
{
|
||||
if (ip_port.port == MASTERSERVERUPDATERPORT_USEGAMESOCKETSHARE)
|
||||
{
|
||||
PRINT_DEBUG("Source Query in Shared Mode\n");
|
||||
return;
|
||||
}
|
||||
|
||||
int retry = 0;
|
||||
constexpr auto max_retry = 10;
|
||||
|
||||
while (retry++ < max_retry)
|
||||
{
|
||||
query_socket = socket(AF_INET, SOCK_DGRAM, IPPROTO_UDP);
|
||||
if (is_socket_valid(query_socket))
|
||||
break;
|
||||
if (retry > max_retry)
|
||||
{
|
||||
reset_last_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
retry = 0;
|
||||
|
||||
sockaddr_in addr;
|
||||
addr.sin_addr.s_addr = htonl(ip_port.ip);
|
||||
addr.sin_port = htons(ip_port.port);
|
||||
addr.sin_family = AF_INET;
|
||||
|
||||
while (retry++ < max_retry)
|
||||
{
|
||||
int res = bind(query_socket, (sockaddr*)&addr, sizeof(sockaddr_in));
|
||||
if (res == 0)
|
||||
{
|
||||
set_socket_nonblocking(query_socket);
|
||||
break;
|
||||
}
|
||||
|
||||
if (retry >= max_retry)
|
||||
{
|
||||
kill_socket(query_socket);
|
||||
query_socket = -1;
|
||||
reset_last_error();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
char str_ip[16];
|
||||
inet_ntop(AF_INET, &(addr.sin_addr), str_ip, 16);
|
||||
|
||||
PRINT_DEBUG("Started query server on %s:%d\n", str_ip, htons(addr.sin_port));
|
||||
}
|
||||
query_alive = true;
|
||||
}
|
||||
|
||||
void Networking::shutDownQuery()
|
||||
{
|
||||
query_alive = false;
|
||||
kill_socket(query_socket);
|
||||
}
|
||||
|
||||
bool Networking::isQueryAlive()
|
||||
{
|
||||
return query_alive;
|
||||
}
|
||||
|
@ -19,6 +19,7 @@
|
||||
#define NETWORK_INCLUDE
|
||||
|
||||
#include "base.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
inline bool protobuf_message_equal(const google::protobuf::MessageLite& msg_a,
|
||||
const google::protobuf::MessageLite& msg_b) {
|
||||
@ -90,8 +91,9 @@ struct Connection {
|
||||
|
||||
class Networking {
|
||||
bool enabled = false;
|
||||
bool query_alive;
|
||||
std::chrono::high_resolution_clock::time_point last_run;
|
||||
sock_t udp_socket, tcp_socket;
|
||||
sock_t query_socket, udp_socket, tcp_socket;
|
||||
uint16 udp_port, tcp_port;
|
||||
uint32 own_ip;
|
||||
std::vector<struct Connection> connections;
|
||||
@ -137,6 +139,10 @@ public:
|
||||
bool setCallback(Callback_Ids id, CSteamID steam_id, void (*message_callback)(void *object, Common_Message *msg), void *object);
|
||||
uint32 getIP(CSteamID id);
|
||||
uint32 getOwnIP();
|
||||
|
||||
void startQuery(IP_PORT ip_port);
|
||||
void shutDownQuery();
|
||||
bool isQueryAlive();
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -138,6 +138,36 @@ void Settings::addMod(PublishedFileId_t id, std::string title, std::string path)
|
||||
mods.push_back(new_entry);
|
||||
}
|
||||
|
||||
void Settings::addModDetails(PublishedFileId_t id, Mod_entry details)
|
||||
{
|
||||
auto f = std::find_if(mods.begin(), mods.end(), [&id](Mod_entry const& item) { return item.id == id; });
|
||||
if (f != mods.end()) {
|
||||
f->previewURL = details.previewURL;
|
||||
f->fileType = details.fileType;
|
||||
f->description = details.description;
|
||||
f->steamIDOwner = details.steamIDOwner;
|
||||
f->timeCreated = details.timeCreated;
|
||||
f->timeUpdated = details.timeUpdated;
|
||||
f->timeAddedToUserList = details.timeAddedToUserList;
|
||||
f->visibility = details.visibility;
|
||||
f->banned = details.banned;
|
||||
f->acceptedForUse = details.acceptedForUse;
|
||||
f->tagsTruncated = details.tagsTruncated;
|
||||
f->tags = details.tags;
|
||||
f->handleFile = details.handleFile;
|
||||
f->handlePreviewFile = details.handlePreviewFile;
|
||||
f->primaryFileName = details.primaryFileName;
|
||||
f->primaryFileSize = details.primaryFileSize;
|
||||
f->previewFileName = details.previewFileName;
|
||||
f->previewFileSize = details.previewFileSize;
|
||||
f->workshopItemURL = details.workshopItemURL;
|
||||
f->votesUp = details.votesUp;
|
||||
f->votesDown = details.votesDown;
|
||||
f->score = details.score;
|
||||
f->numChildren = details.numChildren;
|
||||
}
|
||||
}
|
||||
|
||||
Mod_entry Settings::getMod(PublishedFileId_t id)
|
||||
{
|
||||
auto f = std::find_if(mods.begin(), mods.end(), [&id](Mod_entry const& item) { return item.id == id; });
|
||||
|
@ -32,6 +32,33 @@ struct Mod_entry {
|
||||
PublishedFileId_t id;
|
||||
std::string title;
|
||||
std::string path;
|
||||
|
||||
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
|
||||
UGCHandle_t handleFile = k_UGCHandleInvalid;
|
||||
UGCHandle_t handlePreviewFile = k_UGCHandleInvalid;
|
||||
std::string primaryFileName;
|
||||
int32 primaryFileSize;
|
||||
std::string previewFileName;
|
||||
int32 previewFileSize;
|
||||
std::string workshopItemURL;
|
||||
// voting information
|
||||
uint32 votesUp;
|
||||
uint32 votesDown;
|
||||
float score;
|
||||
// collection details
|
||||
uint32 numChildren;
|
||||
};
|
||||
|
||||
struct Leaderboard_config {
|
||||
@ -65,6 +92,12 @@ struct Controller_Settings {
|
||||
std::map<std::string, std::map<std::string, std::pair<std::set<std::string>, std::string>>> action_set_layers;
|
||||
};
|
||||
|
||||
struct Group_Clans {
|
||||
CSteamID id;
|
||||
std::string name;
|
||||
std::string tag;
|
||||
};
|
||||
|
||||
class Settings {
|
||||
CSteamID steam_id;
|
||||
CGameID game_id;
|
||||
@ -119,6 +152,7 @@ public:
|
||||
|
||||
//mod stuff
|
||||
void addMod(PublishedFileId_t id, std::string title, std::string path);
|
||||
void addModDetails(PublishedFileId_t id, Mod_entry details);
|
||||
Mod_entry getMod(PublishedFileId_t id);
|
||||
bool isModInstalled(PublishedFileId_t id);
|
||||
std::set<PublishedFileId_t> modSet();
|
||||
@ -138,10 +172,12 @@ public:
|
||||
|
||||
//subscribed lobby/group ids
|
||||
std::set<uint64> subscribed_groups;
|
||||
std::vector<Group_Clans> subscribed_groups_clans;
|
||||
|
||||
//images
|
||||
std::map<int, struct Image_Data> images;
|
||||
int add_image(std::string data, uint32 width, uint32 height);
|
||||
bool disable_account_avatar = false;
|
||||
|
||||
//controller
|
||||
struct Controller_Settings controller_settings;
|
||||
@ -150,8 +186,12 @@ public:
|
||||
//networking
|
||||
bool disable_networking = false;
|
||||
|
||||
//gameserver source query
|
||||
bool disable_source_query = false;
|
||||
|
||||
//overlay
|
||||
bool disable_overlay = false;
|
||||
bool disable_overlay_achievement_notification = false;
|
||||
|
||||
//app build id
|
||||
int build_id = 10;
|
||||
@ -167,6 +207,9 @@ public:
|
||||
|
||||
//warn people who use local save
|
||||
bool warn_local_save = false;
|
||||
|
||||
//steamhttp external download support
|
||||
bool http_online = false;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -42,6 +42,46 @@ static void load_custom_broadcasts(std::string broadcasts_filepath, std::set<IP_
|
||||
}
|
||||
}
|
||||
|
||||
static void load_subscribed_groups_clans(std::string clans_filepath, Settings *settings_client, Settings *settings_server)
|
||||
{
|
||||
PRINT_DEBUG("Group clans file path: %s\n", clans_filepath.c_str());
|
||||
std::ifstream clans_file(utf8_decode(clans_filepath));
|
||||
consume_bom(clans_file);
|
||||
if (clans_file.is_open()) {
|
||||
std::string line;
|
||||
while (std::getline(clans_file, line)) {
|
||||
if (line.length() < 0) continue;
|
||||
|
||||
std::size_t seperator1 = line.find("\t\t");
|
||||
std::size_t seperator2 = line.rfind("\t\t");
|
||||
std::string clan_id;
|
||||
std::string clan_name;
|
||||
std::string clan_tag;
|
||||
if ((seperator1 != std::string::npos) && (seperator2 != std::string::npos)) {
|
||||
clan_id = line.substr(0, seperator1);
|
||||
clan_name = line.substr(seperator1+2, seperator2-2);
|
||||
clan_tag = line.substr(seperator2+2);
|
||||
|
||||
// fix persistant tabbing problem for clan name
|
||||
std::size_t seperator3 = clan_name.find("\t");
|
||||
std::string clan_name_fix = clan_name.substr(0, seperator3);
|
||||
clan_name = clan_name_fix;
|
||||
}
|
||||
|
||||
Group_Clans nclan;
|
||||
nclan.id = CSteamID( std::stoull(clan_id.c_str(), NULL, 0) );
|
||||
nclan.name = clan_name;
|
||||
nclan.tag = clan_tag;
|
||||
|
||||
try {
|
||||
settings_client->subscribed_groups_clans.push_back(nclan);
|
||||
settings_server->subscribed_groups_clans.push_back(nclan);
|
||||
PRINT_DEBUG("Added clan %s\n", clan_name.c_str());
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
template<typename Out>
|
||||
static void split_string(const std::string &s, char delim, Out result) {
|
||||
std::stringstream ss(s);
|
||||
@ -296,9 +336,13 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
||||
}
|
||||
|
||||
bool steam_offline_mode = false;
|
||||
bool steamhttp_online_mode = false;
|
||||
bool disable_networking = false;
|
||||
bool disable_overlay = false;
|
||||
bool disable_overlay_achievement_notification = false;
|
||||
bool disable_lobby_creation = false;
|
||||
bool disable_source_query = false;
|
||||
bool disable_account_avatar = false;
|
||||
int build_id = 10;
|
||||
|
||||
bool warn_forced = false;
|
||||
@ -311,12 +355,20 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
||||
PRINT_DEBUG("steam settings path %s\n", p.c_str());
|
||||
if (p == "offline.txt") {
|
||||
steam_offline_mode = true;
|
||||
} else if (p == "http_online.txt") {
|
||||
steamhttp_online_mode = true;
|
||||
} else if (p == "disable_networking.txt") {
|
||||
disable_networking = true;
|
||||
} else if (p == "disable_overlay.txt") {
|
||||
disable_overlay = true;
|
||||
} else if (p == "disable_overlay_achievement_notification.txt") {
|
||||
disable_overlay_achievement_notification = true;
|
||||
} else if (p == "disable_lobby_creation.txt") {
|
||||
disable_lobby_creation = true;
|
||||
} else if (p == "disable_source_query.txt") {
|
||||
disable_source_query = true;
|
||||
} else if (p == "disable_account_avatar.txt") {
|
||||
disable_account_avatar = true;
|
||||
} else if (p == "force_language.txt") {
|
||||
int len = Local_Storage::get_file_data(steam_settings_path + "force_language.txt", language, sizeof(language) - 1);
|
||||
if (len > 0) {
|
||||
@ -363,8 +415,14 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
||||
settings_server->disable_networking = disable_networking;
|
||||
settings_client->disable_overlay = disable_overlay;
|
||||
settings_server->disable_overlay = disable_overlay;
|
||||
settings_client->disable_overlay_achievement_notification = disable_overlay_achievement_notification;
|
||||
settings_server->disable_overlay_achievement_notification = disable_overlay_achievement_notification;
|
||||
settings_client->disable_lobby_creation = disable_lobby_creation;
|
||||
settings_server->disable_lobby_creation = disable_lobby_creation;
|
||||
settings_client->disable_source_query = disable_source_query;
|
||||
settings_server->disable_source_query = disable_source_query;
|
||||
settings_client->disable_account_avatar = disable_account_avatar;
|
||||
settings_server->disable_account_avatar = disable_account_avatar;
|
||||
settings_client->build_id = build_id;
|
||||
settings_server->build_id = build_id;
|
||||
settings_client->warn_forced = warn_forced;
|
||||
@ -373,6 +431,8 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
||||
settings_server->warn_local_save = local_save;
|
||||
settings_client->supported_languages = supported_languages;
|
||||
settings_server->supported_languages = supported_languages;
|
||||
settings_client->http_online = steamhttp_online_mode;
|
||||
settings_server->http_online = steamhttp_online_mode;
|
||||
|
||||
{
|
||||
std::string dlc_config_path = Local_Storage::get_game_settings_path() + "DLC.txt";
|
||||
@ -606,16 +666,86 @@ uint32 create_localstorage_settings(Settings **settings_client_out, Settings **s
|
||||
}
|
||||
}
|
||||
|
||||
load_subscribed_groups_clans(local_storage->get_global_settings_path() + "subscribed_groups_clans.txt", settings_client, settings_server);
|
||||
load_subscribed_groups_clans(Local_Storage::get_game_settings_path() + "subscribed_groups_clans.txt", settings_client, settings_server);
|
||||
|
||||
{
|
||||
std::string mod_path = Local_Storage::get_game_settings_path() + "mods";
|
||||
std::vector<std::string> paths = Local_Storage::get_filenames_path(mod_path);
|
||||
for (auto & p: paths) {
|
||||
PRINT_DEBUG("mod directory %s\n", p.c_str());
|
||||
try {
|
||||
PublishedFileId_t id = std::stoull(p);
|
||||
settings_client->addMod(id, p, mod_path + PATH_SEPARATOR + p);
|
||||
settings_server->addMod(id, p, mod_path + PATH_SEPARATOR + p);
|
||||
} catch (...) {}
|
||||
nlohmann::json mod_items = nlohmann::json::object();
|
||||
static constexpr auto mods_json_file = "mods.json";
|
||||
std::string mods_json_path = Local_Storage::get_game_settings_path() + mods_json_file;
|
||||
if (local_storage->load_json(mods_json_path, mod_items)) {
|
||||
for (auto mod = mod_items.begin(); mod != mod_items.end(); ++mod) {
|
||||
try {
|
||||
Mod_entry newMod;
|
||||
newMod.id = std::stoull(mod.key());
|
||||
newMod.title = mod.value().value("title", std::string(mod.key()));
|
||||
newMod.path = mod_path + PATH_SEPARATOR + std::string(mod.key());
|
||||
newMod.fileType = k_EWorkshopFileTypeCommunity;
|
||||
newMod.description = mod.value().value("description", std::string(""));
|
||||
newMod.steamIDOwner = mod.value().value("steam_id_owner", (uint64)0);
|
||||
newMod.timeCreated = mod.value().value("time_created", (uint32)1554997000);
|
||||
newMod.timeUpdated = mod.value().value("time_updated", (uint32)1554997000);
|
||||
newMod.timeAddedToUserList = mod.value().value("time_added", (uint32)1554997000);
|
||||
newMod.visibility = k_ERemoteStoragePublishedFileVisibilityPublic;
|
||||
newMod.banned = false;
|
||||
newMod.acceptedForUse = true;
|
||||
newMod.tagsTruncated = false;
|
||||
newMod.tags = mod.value().value("tags", std::string(""));
|
||||
newMod.primaryFileName = mod.value().value("primary_filename", std::string(""));
|
||||
newMod.primaryFileSize = mod.value().value("primary_filesize", (int32)1000000);
|
||||
newMod.previewFileName = mod.value().value("preview_filename", std::string(""));
|
||||
newMod.previewFileSize = mod.value().value("preview_filesize", (int32)1000000);
|
||||
newMod.workshopItemURL = mod.value().value("workshop_item_url", std::string(""));
|
||||
newMod.votesUp = mod.value().value("upvotes", (uint32)1);
|
||||
newMod.votesDown = mod.value().value("downvotes", (uint32)0);
|
||||
newMod.score = 1.0f;
|
||||
newMod.numChildren = mod.value().value("num_children", (uint32)0);
|
||||
newMod.previewURL = "file://" + Local_Storage::get_game_settings_path() + "mod_images/" + newMod.previewFileName;
|
||||
settings_client->addMod(newMod.id, newMod.title, newMod.path);
|
||||
settings_server->addMod(newMod.id, newMod.title, newMod.path);
|
||||
settings_client->addModDetails(newMod.id, newMod);
|
||||
settings_server->addModDetails(newMod.id, newMod);
|
||||
} catch (std::exception& e) {
|
||||
PRINT_DEBUG("MODLOADER ERROR: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
} else {
|
||||
std::vector<std::string> paths = Local_Storage::get_filenames_path(mod_path);
|
||||
for (auto & p: paths) {
|
||||
PRINT_DEBUG("mod directory %s\n", p.c_str());
|
||||
try {
|
||||
Mod_entry newMod;
|
||||
newMod.id = std::stoull(p);
|
||||
newMod.title = p;
|
||||
newMod.path = mod_path + PATH_SEPARATOR + p;
|
||||
newMod.fileType = k_EWorkshopFileTypeCommunity;
|
||||
newMod.description = "";
|
||||
newMod.steamIDOwner = (uint64)0;
|
||||
newMod.timeCreated = (uint32)1554997000;
|
||||
newMod.timeUpdated = (uint32)1554997000;
|
||||
newMod.timeAddedToUserList = (uint32)1554997000;
|
||||
newMod.visibility = k_ERemoteStoragePublishedFileVisibilityPublic;
|
||||
newMod.banned = false;
|
||||
newMod.acceptedForUse = true;
|
||||
newMod.tagsTruncated = false;
|
||||
newMod.tags = "";
|
||||
newMod.primaryFileName = "";
|
||||
newMod.primaryFileSize = (int32)1000000;
|
||||
newMod.previewFileName = "";
|
||||
newMod.previewFileSize = (int32)1000000;
|
||||
newMod.workshopItemURL = "";
|
||||
newMod.votesUp = (uint32)1;
|
||||
newMod.votesDown = (uint32)0;
|
||||
newMod.score = 1.0f;
|
||||
newMod.numChildren = (uint32)0;
|
||||
newMod.previewURL = "";
|
||||
settings_client->addMod(newMod.id, newMod.title, newMod.path);
|
||||
settings_server->addMod(newMod.id, newMod.title, newMod.path);
|
||||
settings_client->addModDetails(newMod.id, newMod);
|
||||
settings_server->addModDetails(newMod.id, newMod);
|
||||
} catch (...) {}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
267
dll/source_query.cpp
Normal file
267
dll/source_query.cpp
Normal file
@ -0,0 +1,267 @@
|
||||
/* Copyright (C) 2019 Mr Goldberg, , Nemirtingas
|
||||
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 "source_query.h"
|
||||
#include "dll.h"
|
||||
|
||||
using lock_t = std::lock_guard<std::mutex>;
|
||||
|
||||
enum class source_query_magic : uint32_t
|
||||
{
|
||||
simple = 0xFFFFFFFFul,
|
||||
multi = 0xFFFFFFFEul, // <--- TODO ?
|
||||
};
|
||||
|
||||
enum class source_query_header : uint8_t
|
||||
{
|
||||
A2S_INFO = 'T',
|
||||
A2S_PLAYER = 'U',
|
||||
A2S_RULES = 'V',
|
||||
};
|
||||
|
||||
enum class source_response_header : uint8_t
|
||||
{
|
||||
A2S_CHALLENGE = 'A',
|
||||
A2S_INFO = 'I',
|
||||
A2S_PLAYER = 'D',
|
||||
A2S_RULES = 'E',
|
||||
};
|
||||
|
||||
enum class source_server_type : uint8_t
|
||||
{
|
||||
dedicated = 'd',
|
||||
non_dedicated = 'i',
|
||||
source_tc = 'p',
|
||||
};
|
||||
|
||||
enum class source_server_env : uint8_t
|
||||
{
|
||||
linux = 'l',
|
||||
windows = 'w',
|
||||
old_mac = 'm',
|
||||
mac = 'o',
|
||||
};
|
||||
|
||||
enum class source_server_visibility : uint8_t
|
||||
{
|
||||
_public = 0,
|
||||
_private = 1,
|
||||
};
|
||||
|
||||
enum class source_server_vac : uint8_t
|
||||
{
|
||||
unsecured = 0,
|
||||
secured = 1,
|
||||
};
|
||||
|
||||
enum source_server_extra_flag : uint8_t
|
||||
{
|
||||
none = 0x00,
|
||||
gameid = 0x01,
|
||||
steamid = 0x10,
|
||||
keywords = 0x20,
|
||||
spectator = 0x40,
|
||||
port = 0x80,
|
||||
};
|
||||
|
||||
#if defined(STEAM_WIN32)
|
||||
static constexpr source_server_env my_server_env = source_server_env::windows;
|
||||
#else
|
||||
static constexpr source_server_env my_server_env = source_server_env::linux;
|
||||
#endif
|
||||
|
||||
#pragma pack(push)
|
||||
#pragma pack(1)
|
||||
|
||||
constexpr char a2s_info_payload[] = "Source Engine Query";
|
||||
constexpr size_t a2s_info_payload_size = sizeof(a2s_info_payload);
|
||||
|
||||
struct source_query_data
|
||||
{
|
||||
source_query_magic magic;
|
||||
source_query_header header;
|
||||
union
|
||||
{
|
||||
char a2s_info_payload[a2s_info_payload_size];
|
||||
uint32_t challenge;
|
||||
};
|
||||
};
|
||||
|
||||
static constexpr 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 size_t a2s_query_challenge_size = source_query_header_size + sizeof(source_query_data::challenge);
|
||||
|
||||
#pragma pack(pop)
|
||||
|
||||
void serialize_response(std::vector<uint8_t>& buffer, const void* _data, size_t len)
|
||||
{
|
||||
const uint8_t* data = reinterpret_cast<const uint8_t*>(_data);
|
||||
|
||||
buffer.insert(buffer.end(), data, data + len);
|
||||
}
|
||||
|
||||
template<typename T>
|
||||
void serialize_response(std::vector<uint8_t>& buffer, T const& v)
|
||||
{
|
||||
uint8_t const* data = reinterpret_cast<uint8_t const*>(&v);
|
||||
serialize_response(buffer, data, sizeof(T));
|
||||
}
|
||||
|
||||
template<>
|
||||
void serialize_response<std::string>(std::vector<uint8_t>& buffer, std::string const& v)
|
||||
{
|
||||
uint8_t const* str = reinterpret_cast<uint8_t const*>(v.c_str());
|
||||
serialize_response(buffer, str, v.length()+1);
|
||||
}
|
||||
|
||||
template<typename T, int N>
|
||||
void serialize_response(std::vector <uint8_t>& buffer, char(&str)[N])
|
||||
{
|
||||
serialize_response(buffer, reinterpret_cast<uint8_t const*>(str), N);
|
||||
}
|
||||
|
||||
void get_challenge(std::vector<uint8_t> &challenge_buff)
|
||||
{
|
||||
// TODO: generate the challenge id
|
||||
serialize_response(challenge_buff, source_query_magic::simple);
|
||||
serialize_response(challenge_buff, source_response_header::A2S_CHALLENGE);
|
||||
serialize_response(challenge_buff, static_cast<uint32_t>(0x00112233ul));
|
||||
}
|
||||
|
||||
std::vector<uint8_t> Source_Query::handle_source_query(const void* buffer, size_t len, Gameserver const& gs)
|
||||
{
|
||||
std::vector<uint8_t> output_buffer;
|
||||
|
||||
if (len < source_query_header_size) // its not at least 5 bytes long (0xFF 0xFF 0xFF 0xFF 0x??)
|
||||
return output_buffer;
|
||||
|
||||
source_query_data const& query = *reinterpret_cast<source_query_data const*>(buffer);
|
||||
|
||||
// || gs.max_player_count() == 0
|
||||
if (gs.offline() || query.magic != source_query_magic::simple)
|
||||
return output_buffer;
|
||||
|
||||
switch (query.header)
|
||||
{
|
||||
case source_query_header::A2S_INFO:
|
||||
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();
|
||||
|
||||
serialize_response(output_buffer, source_query_magic::simple);
|
||||
serialize_response(output_buffer, source_response_header::A2S_INFO);
|
||||
serialize_response(output_buffer, static_cast<uint8_t>(2));
|
||||
serialize_response(output_buffer, gs.server_name());
|
||||
serialize_response(output_buffer, gs.map_name());
|
||||
serialize_response(output_buffer, gs.mod_dir());
|
||||
serialize_response(output_buffer, gs.product());
|
||||
serialize_response(output_buffer, static_cast<uint16_t>(gs.appid()));
|
||||
serialize_response(output_buffer, static_cast<uint8_t>(players.size()));
|
||||
serialize_response(output_buffer, static_cast<uint8_t>(gs.max_player_count()));
|
||||
serialize_response(output_buffer, static_cast<uint8_t>(gs.bot_player_count()));
|
||||
serialize_response(output_buffer, (gs.dedicated_server() ? source_server_type::dedicated : source_server_type::non_dedicated));;
|
||||
serialize_response(output_buffer, my_server_env);
|
||||
serialize_response(output_buffer, (gs.password_protected() ? source_server_visibility::_private : source_server_visibility::_public));
|
||||
serialize_response(output_buffer, (gs.secure() ? source_server_vac::secured : source_server_vac::unsecured));
|
||||
serialize_response(output_buffer, std::to_string(gs.version()));
|
||||
|
||||
uint8_t flags = source_server_extra_flag::none;
|
||||
|
||||
if (gs.port() != 0)
|
||||
flags |= source_server_extra_flag::port;
|
||||
|
||||
if (gs.spectator_port() != 0)
|
||||
flags |= source_server_extra_flag::spectator;
|
||||
|
||||
if(CGameID(gs.appid()).IsValid())
|
||||
flags |= source_server_extra_flag::gameid;
|
||||
|
||||
if (flags != source_server_extra_flag::none)
|
||||
serialize_response(output_buffer, flags);
|
||||
|
||||
if (flags & source_server_extra_flag::port)
|
||||
serialize_response(output_buffer, static_cast<uint16_t>(gs.port()));
|
||||
|
||||
// add steamid
|
||||
|
||||
if (flags & source_server_extra_flag::spectator)
|
||||
{
|
||||
serialize_response(output_buffer, static_cast<uint16_t>(gs.spectator_port()));
|
||||
serialize_response(output_buffer, gs.spectator_server_name());
|
||||
}
|
||||
|
||||
// keywords
|
||||
|
||||
if (flags & source_server_extra_flag::gameid)
|
||||
serialize_response(output_buffer, CGameID(gs.appid()).ToUint64());
|
||||
|
||||
}
|
||||
break;
|
||||
|
||||
case source_query_header::A2S_PLAYER:
|
||||
if (len >= a2s_query_challenge_size)
|
||||
{
|
||||
if (query.challenge == 0xFFFFFFFFul)
|
||||
{
|
||||
get_challenge(output_buffer);
|
||||
}
|
||||
else if (query.challenge == 0x00112233ul)
|
||||
{
|
||||
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_response_header::A2S_PLAYER);
|
||||
serialize_response(output_buffer, static_cast<uint8_t>(players.size())); // num_players
|
||||
|
||||
for (int i = 0; i < players.size(); ++i)
|
||||
{
|
||||
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.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()));
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case source_query_header::A2S_RULES:
|
||||
if (len >= a2s_query_challenge_size)
|
||||
{
|
||||
if (query.challenge == 0xFFFFFFFFul)
|
||||
{
|
||||
get_challenge(output_buffer);
|
||||
}
|
||||
else if (query.challenge == 0x00112233ul)
|
||||
{
|
||||
auto values = gs.values();
|
||||
|
||||
serialize_response(output_buffer, source_query_magic::simple);
|
||||
serialize_response(output_buffer, source_response_header::A2S_RULES);
|
||||
serialize_response(output_buffer, static_cast<uint16_t>(values.size()));
|
||||
|
||||
for (auto const& i : values)
|
||||
{
|
||||
serialize_response(output_buffer, i.first);
|
||||
serialize_response(output_buffer, i.second);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
return output_buffer;
|
||||
}
|
28
dll/source_query.h
Normal file
28
dll/source_query.h
Normal file
@ -0,0 +1,28 @@
|
||||
/* 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 "base.h"
|
||||
|
||||
class Source_Query
|
||||
{
|
||||
Source_Query () = delete;
|
||||
~Source_Query() = delete;
|
||||
|
||||
public:
|
||||
static std::vector<uint8_t> handle_source_query(const void* buffer, size_t len, Gameserver const& gs);
|
||||
};
|
||||
|
@ -102,12 +102,83 @@ struct Avatar_Numbers add_friend_avatars(CSteamID id)
|
||||
return avatar_ids->second;
|
||||
}
|
||||
|
||||
//TODO: get real image data from self/other peers
|
||||
struct Avatar_Numbers avatar_numbers;
|
||||
std::string small_avatar(32 * 32 * 4, 0);
|
||||
std::string medium_avatar(64 * 64 * 4, 0);
|
||||
std::string large_avatar(184 * 184 * 4, 0);
|
||||
|
||||
if (!(settings->disable_account_avatar) && (id == settings->get_local_steam_id())) {
|
||||
std::string file_path;
|
||||
unsigned long long file_size;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string file_name;
|
||||
if (i == 0) file_name = "account_avatar.png";
|
||||
if (i == 1) file_name = "account_avatar.jpg";
|
||||
if (i == 2) file_name = "account_avatar.jpeg";
|
||||
file_path = Local_Storage::get_game_settings_path() + file_name;
|
||||
file_size = file_size_(file_path);
|
||||
if (file_size) break;
|
||||
}
|
||||
|
||||
if (!file_size) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string file_name;
|
||||
if (i == 0) file_name = "account_avatar.png";
|
||||
if (i == 1) file_name = "account_avatar.jpg";
|
||||
if (i == 2) file_name = "account_avatar.jpeg";
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/settings/" + file_name;
|
||||
file_size = file_size_(file_path);
|
||||
if (file_size) break;
|
||||
}
|
||||
}
|
||||
|
||||
// no else statement here for default or else this breaks default images for friends
|
||||
if (file_size) {
|
||||
small_avatar = Local_Storage::load_image_resized(file_path, "", 32);
|
||||
medium_avatar = Local_Storage::load_image_resized(file_path, "", 64);
|
||||
large_avatar = Local_Storage::load_image_resized(file_path, "", 184);
|
||||
}
|
||||
} else if (!(settings->disable_account_avatar)) {
|
||||
Friend *f = find_friend(id);
|
||||
if (f && (large_avatar.compare(f->avatar()) != 0)) {
|
||||
large_avatar = f->avatar();
|
||||
medium_avatar = Local_Storage::load_image_resized("", f->avatar(), 64);
|
||||
small_avatar = Local_Storage::load_image_resized("", f->avatar(), 32);
|
||||
} else {
|
||||
std::string file_path;
|
||||
unsigned long long file_size;
|
||||
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string file_name;
|
||||
if (i == 0) file_name = "account_avatar_default.png";
|
||||
if (i == 1) file_name = "account_avatar_default.jpg";
|
||||
if (i == 2) file_name = "account_avatar_default.jpeg";
|
||||
file_path = Local_Storage::get_game_settings_path() + file_name;
|
||||
file_size = file_size_(file_path);
|
||||
if (file_size) break;
|
||||
}
|
||||
|
||||
if (!file_size) {
|
||||
for (int i = 0; i < 3; i++) {
|
||||
std::string file_name;
|
||||
if (i == 0) file_name = "account_avatar_default.png";
|
||||
if (i == 1) file_name = "account_avatar_default.jpg";
|
||||
if (i == 2) file_name = "account_avatar_default.jpeg";
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/settings/" + file_name;
|
||||
file_size = file_size_(file_path);
|
||||
if (file_size) break;
|
||||
}
|
||||
}
|
||||
|
||||
if (file_size) {
|
||||
small_avatar = Local_Storage::load_image_resized(file_path, "", 32);
|
||||
medium_avatar = Local_Storage::load_image_resized(file_path, "", 64);
|
||||
large_avatar = Local_Storage::load_image_resized(file_path, "", 184);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
avatar_numbers.smallest = settings->add_image(small_avatar, 32, 32);
|
||||
avatar_numbers.medium = settings->add_image(medium_avatar, 64, 64);
|
||||
avatar_numbers.large = settings->add_image(large_avatar, 184, 184);
|
||||
@ -441,24 +512,37 @@ bool HasFriend( CSteamID steamIDFriend, EFriendFlags eFriendFlags )
|
||||
int GetClanCount()
|
||||
{
|
||||
PRINT_DEBUG("Steam_Friends::GetClanCount\n");
|
||||
return 0;
|
||||
int counter = 0;
|
||||
for (auto &c : settings->subscribed_groups_clans) counter++;
|
||||
return counter;
|
||||
}
|
||||
|
||||
CSteamID GetClanByIndex( int iClan )
|
||||
{
|
||||
PRINT_DEBUG("Steam_Friends::GetClanByIndex\n");
|
||||
int counter = 0;
|
||||
for (auto &c : settings->subscribed_groups_clans) {
|
||||
if (counter == iClan) return c.id;
|
||||
counter++;
|
||||
}
|
||||
return k_steamIDNil;
|
||||
}
|
||||
|
||||
const char *GetClanName( CSteamID steamIDClan )
|
||||
{
|
||||
PRINT_DEBUG("Steam_Friends::GetClanName\n");
|
||||
for (auto &c : settings->subscribed_groups_clans) {
|
||||
if (c.id.ConvertToUint64() == steamIDClan.ConvertToUint64()) return c.name.c_str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
const char *GetClanTag( CSteamID steamIDClan )
|
||||
{
|
||||
PRINT_DEBUG("Steam_Friends::GetClanTag\n");
|
||||
for (auto &c : settings->subscribed_groups_clans) {
|
||||
if (c.id.ConvertToUint64() == steamIDClan.ConvertToUint64()) return c.tag.c_str();
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
@ -1101,6 +1185,9 @@ void Callback(Common_Message *msg)
|
||||
f->set_name(settings->get_local_name());
|
||||
f->set_appid(settings->get_local_game_id().AppID());
|
||||
f->set_lobby_id(settings->get_lobby().ConvertToUint64());
|
||||
int avatar_number = GetLargeFriendAvatar(settings->get_local_steam_id());
|
||||
if (settings->images[avatar_number].data.length() > 0) f->set_avatar(settings->images[avatar_number].data);
|
||||
else f->set_avatar("");
|
||||
msg_.set_allocated_friend_(f);
|
||||
network->sendTo(&msg_, true);
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "steam_gameserver.h"
|
||||
#include "source_query.h"
|
||||
|
||||
#define SEND_SERVER_RATE 5.0
|
||||
|
||||
@ -33,6 +34,11 @@ Steam_GameServer::~Steam_GameServer()
|
||||
delete ticket_manager;
|
||||
}
|
||||
|
||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>>* Steam_GameServer::get_players()
|
||||
{
|
||||
return &players;
|
||||
}
|
||||
|
||||
//
|
||||
// Basic server data. These properties, if set, must be set before before calling LogOn. They
|
||||
// may not be changed after logged in.
|
||||
@ -61,6 +67,10 @@ bool Steam_GameServer::InitGameServer( uint32 unIP, uint16 usGamePort, uint16 us
|
||||
server_data.set_port(usGamePort);
|
||||
server_data.set_query_port(usQueryPort);
|
||||
server_data.set_offline(false);
|
||||
|
||||
if (!settings->disable_source_query)
|
||||
network->startQuery({ unIP, usQueryPort });
|
||||
|
||||
if (!settings->get_local_game_id().AppID()) settings->set_game_id(CGameID(nGameAppId));
|
||||
//TODO: flags should be k_unServerFlag
|
||||
flags = unFlags;
|
||||
@ -78,6 +88,8 @@ void Steam_GameServer::SetProduct( const char *pszProduct )
|
||||
{
|
||||
PRINT_DEBUG("SetProduct\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
// pszGameDescription should be used instead of pszProduct for accurate information
|
||||
// Example: 'Counter-Strike: Source' instead of 'cstrike'
|
||||
server_data.set_product(pszProduct);
|
||||
}
|
||||
|
||||
@ -89,6 +101,7 @@ void Steam_GameServer::SetGameDescription( const char *pszGameDescription )
|
||||
PRINT_DEBUG("SetGameDescription\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
server_data.set_game_description(pszGameDescription);
|
||||
//server_data.set_product(pszGameDescription);
|
||||
}
|
||||
|
||||
|
||||
@ -183,8 +196,13 @@ bool Steam_GameServer::BSecure()
|
||||
{
|
||||
PRINT_DEBUG("BSecure\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (!policy_response_called) return false;
|
||||
return !!(flags & k_unServerFlagSecure);
|
||||
if (!policy_response_called) {
|
||||
server_data.set_secure(0);
|
||||
return false;
|
||||
}
|
||||
const bool res = !!(flags & k_unServerFlagSecure);
|
||||
server_data.set_secure(res);
|
||||
return res;
|
||||
}
|
||||
|
||||
CSteamID Steam_GameServer::GetSteamID()
|
||||
@ -351,7 +369,18 @@ bool Steam_GameServer::SendUserConnectAndAuthenticate( uint32 unIPClient, const
|
||||
PRINT_DEBUG("SendUserConnectAndAuthenticate %u %u\n", unIPClient, cubAuthBlobSize);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
return ticket_manager->SendUserConnectAndAuthenticate(unIPClient, pvAuthBlob, cubAuthBlobSize, pSteamIDUser);
|
||||
bool res = ticket_manager->SendUserConnectAndAuthenticate(unIPClient, pvAuthBlob, cubAuthBlobSize, pSteamIDUser);
|
||||
|
||||
if (res) {
|
||||
std::pair<CSteamID, Gameserver_Player_Info_t> infos;
|
||||
infos.first = *pSteamIDUser;
|
||||
infos.second.join_time = std::chrono::steady_clock::now();
|
||||
infos.second.score = 0;
|
||||
infos.second.name = "unnamed";
|
||||
players.emplace_back(std::move(infos));
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
void Steam_GameServer::SendUserConnectAndAuthenticate( CSteamID steamIDUser, uint32 unIPClient, void *pvAuthBlob, uint32 cubAuthBlobSize )
|
||||
@ -368,7 +397,15 @@ CSteamID Steam_GameServer::CreateUnauthenticatedUserConnection()
|
||||
PRINT_DEBUG("CreateUnauthenticatedUserConnection\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
return ticket_manager->fakeUser();
|
||||
CSteamID bot_id = ticket_manager->fakeUser();
|
||||
std::pair<CSteamID, Gameserver_Player_Info_t> infos;
|
||||
infos.first = bot_id;
|
||||
infos.second.join_time = std::chrono::steady_clock::now();
|
||||
infos.second.score = 0;
|
||||
infos.second.name = "unnamed";
|
||||
players.emplace_back(std::move(infos));
|
||||
|
||||
return bot_id;
|
||||
}
|
||||
|
||||
|
||||
@ -380,6 +417,16 @@ void Steam_GameServer::SendUserDisconnect( CSteamID steamIDUser )
|
||||
PRINT_DEBUG("SendUserDisconnect\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
auto player_it = std::find_if(players.begin(), players.end(), [&steamIDUser](std::pair<CSteamID, Gameserver_Player_Info_t>& player)
|
||||
{
|
||||
return player.first == steamIDUser;
|
||||
});
|
||||
|
||||
if (player_it != players.end())
|
||||
{
|
||||
players.erase(player_it);
|
||||
}
|
||||
|
||||
ticket_manager->endAuth(steamIDUser);
|
||||
}
|
||||
|
||||
@ -392,7 +439,21 @@ void Steam_GameServer::SendUserDisconnect( CSteamID steamIDUser )
|
||||
bool Steam_GameServer::BUpdateUserData( CSteamID steamIDUser, const char *pchPlayerName, uint32 uScore )
|
||||
{
|
||||
PRINT_DEBUG("BUpdateUserData %llu %s %u\n", steamIDUser.ConvertToUint64(), pchPlayerName, uScore);
|
||||
return true;
|
||||
|
||||
auto player_it = std::find_if(players.begin(), players.end(), [&steamIDUser](std::pair<CSteamID, Gameserver_Player_Info_t>& player)
|
||||
{
|
||||
return player.first == steamIDUser;
|
||||
});
|
||||
|
||||
if (player_it != players.end())
|
||||
{
|
||||
if (pchPlayerName != nullptr)
|
||||
player_it->second.name = pchPlayerName;
|
||||
|
||||
player_it->second.score = uScore;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// You shouldn't need to call this as it is called internally by SteamGameServer_Init() and can only be called once.
|
||||
@ -503,6 +564,13 @@ EBeginAuthSessionResult Steam_GameServer::BeginAuthSession( const void *pAuthTic
|
||||
PRINT_DEBUG("Steam_GameServer::BeginAuthSession %i %llu\n", cbAuthTicket, steamID.ConvertToUint64());
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
std::pair<CSteamID, Gameserver_Player_Info_t> infos;
|
||||
infos.first = steamID;
|
||||
infos.second.join_time = std::chrono::steady_clock::now();
|
||||
infos.second.score = 0;
|
||||
infos.second.name = "unnamed";
|
||||
players.emplace_back(std::move(infos));
|
||||
|
||||
return ticket_manager->beginAuth(pAuthTicket, cbAuthTicket, steamID );
|
||||
}
|
||||
|
||||
@ -513,6 +581,16 @@ void Steam_GameServer::EndAuthSession( CSteamID steamID )
|
||||
PRINT_DEBUG("Steam_GameServer::EndAuthSession %llu\n", steamID.ConvertToUint64());
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
auto player_it = std::find_if(players.begin(), players.end(), [&steamID](std::pair<CSteamID, Gameserver_Player_Info_t>& player)
|
||||
{
|
||||
return player.first == steamID;
|
||||
});
|
||||
|
||||
if (player_it != players.end())
|
||||
{
|
||||
players.erase(player_it);
|
||||
}
|
||||
|
||||
ticket_manager->endAuth(steamID);
|
||||
}
|
||||
|
||||
@ -608,6 +686,18 @@ bool Steam_GameServer::HandleIncomingPacket( const void *pData, int cbData, uint
|
||||
{
|
||||
PRINT_DEBUG("HandleIncomingPacket %i %X %i\n", cbData, srcIP, srcPort);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (settings->disable_source_query) return true;
|
||||
|
||||
Gameserver_Outgoing_Packet packet;
|
||||
packet.data = std::move(Source_Query::handle_source_query(pData, cbData, server_data));
|
||||
if (packet.data.empty())
|
||||
return false;
|
||||
|
||||
|
||||
packet.ip = srcIP;
|
||||
packet.port = srcPort;
|
||||
|
||||
outgoing_packets.emplace_back(std::move(packet));
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -620,6 +710,7 @@ int Steam_GameServer::GetNextOutgoingPacket( void *pOut, int cbMaxOut, uint32 *p
|
||||
{
|
||||
PRINT_DEBUG("GetNextOutgoingPacket\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (settings->disable_source_query) return 0;
|
||||
if (outgoing_packets.size() == 0) return 0;
|
||||
|
||||
if (outgoing_packets.back().data.size() < cbMaxOut) cbMaxOut = outgoing_packets.back().data.size();
|
||||
@ -743,6 +834,10 @@ void Steam_GameServer::RunCallbacks()
|
||||
msg.set_allocated_gameserver(new Gameserver(server_data));
|
||||
msg.mutable_gameserver()->set_offline(true);
|
||||
network->sendToAllIndividuals(&msg, true);
|
||||
// Shutdown Source Query
|
||||
network->shutDownQuery();
|
||||
// And empty the queue if needed
|
||||
outgoing_packets.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,12 +22,18 @@
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct Gameserver_Outgoing_Packet {
|
||||
std::string data;
|
||||
std::vector<uint8_t> data;
|
||||
|
||||
uint32 ip;
|
||||
uint16 port;
|
||||
};
|
||||
|
||||
struct Gameserver_Player_Info_t {
|
||||
std::chrono::steady_clock::time_point join_time;
|
||||
std::string name;
|
||||
uint32 score;
|
||||
};
|
||||
|
||||
class Steam_GameServer :
|
||||
public ISteamGameServer004,
|
||||
public ISteamGameServer005,
|
||||
@ -50,6 +56,7 @@ public ISteamGameServer
|
||||
bool logged_in = false;
|
||||
bool call_servers_disconnected = false;
|
||||
Gameserver server_data;
|
||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>> players;
|
||||
|
||||
uint32 flags;
|
||||
bool policy_response_called;
|
||||
@ -62,6 +69,9 @@ public:
|
||||
|
||||
Steam_GameServer(class Settings *settings, class Networking *network, class SteamCallBacks *callbacks);
|
||||
~Steam_GameServer();
|
||||
|
||||
std::vector<std::pair<CSteamID, Gameserver_Player_Info_t>>* get_players();
|
||||
|
||||
//
|
||||
// Basic server data. These properties, if set, must be set before before calling LogOn. They
|
||||
// may not be changed after logged in.
|
||||
|
@ -58,6 +58,40 @@ HTTPRequestHandle Steam_HTTP::CreateHTTPRequest( EHTTPMethod eHTTPRequestMethod,
|
||||
long long read = Local_Storage::get_file_data(file_path, (char *)request.response.data(), file_size, 0);
|
||||
if (read < 0) read = 0;
|
||||
if (read != file_size) request.response.resize(read);
|
||||
} else if (!settings->disable_networking && settings->http_online) {
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
|
||||
std::size_t url_directory = file_path.rfind("/");
|
||||
std::string directory_path;
|
||||
std::string file_name;
|
||||
if (url_directory != std::string::npos) {
|
||||
directory_path = file_path.substr(0, url_directory);
|
||||
file_name = file_path.substr(url_directory);
|
||||
}
|
||||
Local_Storage::store_file_data(directory_path, file_name, (char *)"", sizeof(""));
|
||||
|
||||
#if defined(STEAM_WIN32)
|
||||
FILE *hfile = fopen(file_path.c_str(), "wb");
|
||||
#else
|
||||
FILE *hfile = fopen(file_path.c_str(), "w");
|
||||
#endif
|
||||
CURL *chttp = curl_easy_init();
|
||||
curl_easy_setopt(chttp, CURLOPT_URL, url.c_str());
|
||||
curl_easy_setopt(chttp, CURLOPT_WRITEDATA, (void *)hfile);
|
||||
curl_easy_setopt(chttp, CURLOPT_TIMEOUT, 60L);
|
||||
curl_easy_setopt(chttp, CURLOPT_NOSIGNAL, 1L);
|
||||
curl_easy_setopt(chttp, CURLOPT_USE_SSL, CURLUSESSL_TRY);
|
||||
curl_easy_perform(chttp);
|
||||
curl_easy_cleanup(chttp);
|
||||
fclose(hfile);
|
||||
|
||||
file_size = file_size_(file_path);
|
||||
if (file_size) {
|
||||
request.response.resize(file_size);
|
||||
long long read = Local_Storage::get_file_data(file_path, (char *)request.response.data(), file_size, 0);
|
||||
if (read < 0) read = 0;
|
||||
if (read != file_size) request.response.resize(read);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -16,6 +16,8 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "base.h"
|
||||
#include "common_includes.h"
|
||||
#include <curl/curl.h>
|
||||
|
||||
|
||||
struct Steam_Http_Request {
|
||||
|
@ -343,6 +343,16 @@ static Lobby_Member *get_lobby_member(Lobby *lobby, CSteamID user_id)
|
||||
int GetFavoriteGameCount()
|
||||
{
|
||||
PRINT_DEBUG("GetFavoriteGameCount\n");
|
||||
std::string file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt";
|
||||
unsigned long long file_size = file_size_(file_path);
|
||||
if (file_size) {
|
||||
std::string list;
|
||||
list.resize(file_size);
|
||||
Local_Storage::get_file_data(file_path, (char *)list.data(), file_size, 0);
|
||||
auto list_lines = std::count(list.begin(), list.end(), '\n');
|
||||
list_lines += (!list.empty() && list.back() != '\n');
|
||||
return list_lines;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -363,8 +373,72 @@ bool GetFavoriteGame( int iGame, AppId_t *pnAppID, uint32 *pnIP, uint16 *pnConnP
|
||||
int AddFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags, uint32 rTime32LastPlayedOnServer )
|
||||
{
|
||||
PRINT_DEBUG("AddFavoriteGame %lu %lu %hu %hu %lu %lu\n", nAppID, nIP, nConnPort, nQueryPort, unFlags, rTime32LastPlayedOnServer);
|
||||
//TODO: what should this return?
|
||||
return 0;
|
||||
|
||||
std::string file_path;
|
||||
unsigned long long file_size;
|
||||
|
||||
if (unFlags == 1) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt";
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
else if (unFlags == 2) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_history.txt";
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
else {
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned char ip[4];
|
||||
ip[0] = nIP & 0xFF;
|
||||
ip[1] = (nIP >> 8) & 0xFF;
|
||||
ip[2] = (nIP >> 16) & 0xFF;
|
||||
ip[3] = (nIP >> 24) & 0xFF;
|
||||
char newip[24];
|
||||
snprintf(newip, sizeof(newip), "%d.%d.%d.%d:%d\n", ip[3], ip[2], ip[1], ip[0], nConnPort);
|
||||
std::string newip_string;
|
||||
newip_string.append(newip);
|
||||
|
||||
if (file_size) {
|
||||
std::string list;
|
||||
list.resize(file_size);
|
||||
Local_Storage::get_file_data(file_path, (char *)list.data(), file_size, 0);
|
||||
auto list_lines = std::count(list.begin(), list.end(), '\n');
|
||||
list_lines += (!list.empty() && list.back() != '\n');
|
||||
|
||||
std::size_t find_ip = list.find(newip_string);
|
||||
if (find_ip == std::string::npos) {
|
||||
list.append(newip_string);
|
||||
list.append("\n");
|
||||
|
||||
std::size_t file_directory = file_path.rfind("/");
|
||||
std::string directory_path;
|
||||
std::string file_name;
|
||||
if (file_directory != std::string::npos) {
|
||||
directory_path = file_path.substr(0, file_directory);
|
||||
file_name = file_path.substr(file_directory);
|
||||
}
|
||||
Local_Storage::store_file_data(directory_path, file_name, (char *)list.data(), list.size());
|
||||
|
||||
return ++list_lines;
|
||||
}
|
||||
|
||||
return list_lines;
|
||||
}
|
||||
else {
|
||||
newip_string.append("\n");
|
||||
|
||||
std::size_t file_directory = file_path.rfind("/");
|
||||
std::string directory_path;
|
||||
std::string file_name;
|
||||
if (file_directory != std::string::npos) {
|
||||
directory_path = file_path.substr(0, file_directory);
|
||||
file_name = file_path.substr(file_directory);
|
||||
}
|
||||
Local_Storage::store_file_data(directory_path, file_name, (char *)newip_string.data(), newip_string.size());
|
||||
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -372,6 +446,54 @@ int AddFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQuery
|
||||
bool RemoveFavoriteGame( AppId_t nAppID, uint32 nIP, uint16 nConnPort, uint16 nQueryPort, uint32 unFlags )
|
||||
{
|
||||
PRINT_DEBUG("RemoveFavoriteGame\n");
|
||||
|
||||
std::string file_path;
|
||||
unsigned long long file_size;
|
||||
|
||||
if (unFlags == 1) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt";
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
else if (unFlags == 2) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_history.txt";
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (file_size) {
|
||||
std::string list;
|
||||
list.resize(file_size);
|
||||
Local_Storage::get_file_data(file_path, (char *)list.data(), file_size, 0);
|
||||
|
||||
unsigned char ip[4];
|
||||
ip[0] = nIP & 0xFF;
|
||||
ip[1] = (nIP >> 8) & 0xFF;
|
||||
ip[2] = (nIP >> 16) & 0xFF;
|
||||
ip[3] = (nIP >> 24) & 0xFF;
|
||||
char newip[24];
|
||||
snprintf((char *)newip, sizeof(newip), "%d.%d.%d.%d:%d\n", ip[3], ip[2], ip[1], ip[0], nConnPort);
|
||||
std::string newip_string;
|
||||
newip_string.append(newip);
|
||||
|
||||
std::size_t list_ip = list.find(newip_string);
|
||||
if (list_ip != std::string::npos) {
|
||||
list.erase(list_ip, newip_string.length());
|
||||
|
||||
std::size_t file_directory = file_path.rfind("/");
|
||||
std::string directory_path;
|
||||
std::string file_name;
|
||||
if (file_directory != std::string::npos) {
|
||||
directory_path = file_path.substr(0, file_directory);
|
||||
file_name = file_path.substr(file_directory);
|
||||
}
|
||||
Local_Storage::store_file_data(directory_path, file_name, (char *)list.data(), list.size());
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -35,19 +35,9 @@ Steam_Matchmaking_Servers::Steam_Matchmaking_Servers(class Settings *settings, c
|
||||
|
||||
static int server_list_request;
|
||||
|
||||
// Request a new list of servers of a particular type. These calls each correspond to one of the EMatchMakingType values.
|
||||
// Each call allocates a new asynchronous request object.
|
||||
// Request object must be released by calling ReleaseRequest( hServerListRequest )
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestInternetServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type)
|
||||
{
|
||||
PRINT_DEBUG("RequestInternetServerList\n");
|
||||
//TODO
|
||||
return RequestLANServerList(iApp, pRequestServersResponse);
|
||||
}
|
||||
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestLANServerList( AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestLANServerList %u\n", iApp);
|
||||
PRINT_DEBUG("RequestServerList %u\n", iApp);
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
struct Steam_Matchmaking_Request request;
|
||||
request.appid = iApp;
|
||||
@ -55,40 +45,135 @@ HServerListRequest Steam_Matchmaking_Servers::RequestLANServerList( AppId_t iApp
|
||||
request.old_callbacks = NULL;
|
||||
request.cancelled = false;
|
||||
request.completed = false;
|
||||
request.type = type;
|
||||
requests.push_back(request);
|
||||
++server_list_request;
|
||||
requests[requests.size() - 1].id = (void *)server_list_request;
|
||||
HServerListRequest id = requests[requests.size() - 1].id;
|
||||
PRINT_DEBUG("request id: %p\n", id);
|
||||
|
||||
if (type == eLANServer) return id;
|
||||
|
||||
if (type == eFriendsServer) {
|
||||
for (auto &g : gameservers_friends) {
|
||||
if (g.source_id != settings->get_local_steam_id().ConvertToUint64()) {
|
||||
Gameserver server;
|
||||
server.set_ip(g.ip);
|
||||
server.set_port(g.port);
|
||||
server.set_query_port(g.port);
|
||||
server.set_appid(iApp);
|
||||
|
||||
struct Steam_Matchmaking_Servers_Gameserver g2;
|
||||
g2.last_recv = std::chrono::high_resolution_clock::now();
|
||||
g2.server = server;
|
||||
g2.type = type;
|
||||
gameservers.push_back(g2);
|
||||
PRINT_DEBUG("SERVER ADDED\n");
|
||||
}
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
std::string file_path;
|
||||
unsigned long long file_size;
|
||||
if (type == eInternetServer || type == eSpectatorServer) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser.txt";
|
||||
file_size = file_size_(file_path);
|
||||
} else if (type == eFavoritesServer) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_favorites.txt";
|
||||
file_size = file_size_(file_path);
|
||||
} else if (type == eHistoryServer) {
|
||||
file_path = Local_Storage::get_user_appdata_path() + "/7/" + Local_Storage::remote_storage_folder + "/serverbrowser_history.txt";
|
||||
file_size = file_size_(file_path);
|
||||
}
|
||||
|
||||
std::string list;
|
||||
if (file_size) {
|
||||
list.resize(file_size);
|
||||
Local_Storage::get_file_data(file_path, (char *)list.data(), file_size, 0);
|
||||
} else {
|
||||
return id;
|
||||
}
|
||||
|
||||
std::istringstream list_ss (list);
|
||||
std::string list_ip;
|
||||
while (std::getline(list_ss, list_ip)) {
|
||||
if (list_ip.length() < 0) continue;
|
||||
|
||||
unsigned int byte4, byte3, byte2, byte1, byte0;
|
||||
uint32 ip_int;
|
||||
uint16 port_int;
|
||||
char newip[24];
|
||||
if (sscanf(list_ip.c_str(), "%u.%u.%u.%u:%u", &byte3, &byte2, &byte1, &byte0, &byte4) == 5) {
|
||||
ip_int = (byte3 << 24) + (byte2 << 16) + (byte1 << 8) + byte0;
|
||||
port_int = byte4;
|
||||
|
||||
unsigned char ip_tmp[4];
|
||||
ip_tmp[0] = ip_int & 0xFF;
|
||||
ip_tmp[1] = (ip_int >> 8) & 0xFF;
|
||||
ip_tmp[2] = (ip_int >> 16) & 0xFF;
|
||||
ip_tmp[3] = (ip_int >> 24) & 0xFF;
|
||||
snprintf(newip, sizeof(newip), "%d.%d.%d.%d", ip_tmp[3], ip_tmp[2], ip_tmp[1], ip_tmp[0]);
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
Gameserver server;
|
||||
server.set_ip(ip_int);
|
||||
server.set_port(port_int);
|
||||
server.set_query_port(port_int);
|
||||
server.set_appid(iApp);
|
||||
|
||||
struct Steam_Matchmaking_Servers_Gameserver g;
|
||||
g.last_recv = std::chrono::high_resolution_clock::now();
|
||||
g.server = server;
|
||||
g.type = type;
|
||||
gameservers.push_back(g);
|
||||
PRINT_DEBUG("SERVER ADDED\n");
|
||||
|
||||
list_ip = "";
|
||||
}
|
||||
|
||||
return id;
|
||||
}
|
||||
|
||||
// Request a new list of servers of a particular type. These calls each correspond to one of the EMatchMakingType values.
|
||||
// Each call allocates a new asynchronous request object.
|
||||
// Request object must be released by calling ReleaseRequest( hServerListRequest )
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestInternetServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestInternetServerList\n");
|
||||
return RequestServerList(iApp, pRequestServersResponse, eInternetServer);
|
||||
}
|
||||
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestLANServerList( AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestLANServerList\n");
|
||||
return RequestServerList(iApp, pRequestServersResponse, eLANServer);
|
||||
}
|
||||
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestFriendsServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestFriendsServerList\n");
|
||||
//TODO
|
||||
return RequestLANServerList(iApp, pRequestServersResponse);
|
||||
return RequestServerList(iApp, pRequestServersResponse, eFriendsServer);
|
||||
}
|
||||
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestFavoritesServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestFavoritesServerList\n");
|
||||
//TODO
|
||||
return RequestLANServerList(iApp, pRequestServersResponse);
|
||||
return RequestServerList(iApp, pRequestServersResponse, eFavoritesServer);
|
||||
}
|
||||
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestHistoryServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestHistoryServerList\n");
|
||||
//TODO
|
||||
return RequestLANServerList(iApp, pRequestServersResponse);
|
||||
return RequestServerList(iApp, pRequestServersResponse, eHistoryServer);
|
||||
}
|
||||
|
||||
HServerListRequest Steam_Matchmaking_Servers::RequestSpectatorServerList( AppId_t iApp, STEAM_ARRAY_COUNT(nFilters) MatchMakingKeyValuePair_t **ppchFilters, uint32 nFilters, ISteamMatchmakingServerListResponse *pRequestServersResponse )
|
||||
{
|
||||
PRINT_DEBUG("RequestSpectatorServerList\n");
|
||||
//TODO
|
||||
return RequestLANServerList(iApp, pRequestServersResponse);
|
||||
return RequestServerList(iApp, pRequestServersResponse, eSpectatorServer);
|
||||
}
|
||||
|
||||
void Steam_Matchmaking_Servers::RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type)
|
||||
@ -110,6 +195,7 @@ void Steam_Matchmaking_Servers::RequestOldServerList(AppId_t iApp, ISteamMatchma
|
||||
request.old_callbacks = pRequestServersResponse;
|
||||
request.cancelled = false;
|
||||
request.completed = false;
|
||||
request.type = type;
|
||||
requests.push_back(request);
|
||||
requests[requests.size() - 1].id = (void *)type;
|
||||
}
|
||||
@ -250,13 +336,70 @@ void Steam_Matchmaking_Servers::ReleaseRequest( HServerListRequest hServerListRe
|
||||
|
||||
void Steam_Matchmaking_Servers::server_details(Gameserver *g, gameserveritem_t *server)
|
||||
{
|
||||
long long latency = 10;
|
||||
if (!(g->ip() < 0) && !(g->query_port() < 0)) {
|
||||
unsigned char ip[4];
|
||||
char newip[24];
|
||||
ip[0] = g->ip() & 0xFF;
|
||||
ip[1] = (g->ip() >> 8) & 0xFF;
|
||||
ip[2] = (g->ip() >> 16) & 0xFF;
|
||||
ip[3] = (g->ip() >> 24) & 0xFF;
|
||||
snprintf(newip, sizeof(newip), "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]);
|
||||
|
||||
SSQ_SERVER *ssq = ssq_server_new(newip, g->query_port());
|
||||
if (ssq != NULL && ssq_server_eok(ssq)) {
|
||||
ssq_server_timeout(ssq, SSQ_TIMEOUT_RECV, 1200);
|
||||
ssq_server_timeout(ssq, SSQ_TIMEOUT_SEND, 1200);
|
||||
|
||||
std::chrono::high_resolution_clock::time_point t1 = std::chrono::high_resolution_clock::now();
|
||||
A2S_INFO *ssq_a2s_info = ssq_info(ssq);
|
||||
std::chrono::high_resolution_clock::time_point t2 = std::chrono::high_resolution_clock::now();
|
||||
latency = std::chrono::duration_cast<std::chrono::milliseconds>(t2 - t1).count();
|
||||
|
||||
if (ssq_server_eok(ssq)) {
|
||||
if (ssq_info_has_steamid(ssq_a2s_info)) g->set_id(ssq_a2s_info->steamid);
|
||||
g->set_game_description(ssq_a2s_info->game);
|
||||
g->set_mod_dir(ssq_a2s_info->folder);
|
||||
if (ssq_a2s_info->server_type == A2S_SERVER_TYPE_DEDICATED) g->set_dedicated_server(true);
|
||||
else if (ssq_a2s_info->server_type == A2S_SERVER_TYPE_STV_RELAY) g->set_dedicated_server(true);
|
||||
else g->set_dedicated_server(false);
|
||||
g->set_max_player_count(ssq_a2s_info->max_players);
|
||||
g->set_bot_player_count(ssq_a2s_info->bots);
|
||||
g->set_server_name(ssq_a2s_info->name);
|
||||
g->set_map_name(ssq_a2s_info->map);
|
||||
if (ssq_a2s_info->visibility) g->set_password_protected(true);
|
||||
else g->set_password_protected(false);
|
||||
if (ssq_info_has_stv(ssq_a2s_info)) {
|
||||
g->set_spectator_port(ssq_a2s_info->stv_port);
|
||||
g->set_spectator_server_name(ssq_a2s_info->stv_name);
|
||||
}
|
||||
//g->set_tags(ssq_a2s_info->keywords);
|
||||
//g->set_gamedata();
|
||||
//g->set_region();
|
||||
g->set_product(ssq_a2s_info->game);
|
||||
if (ssq_a2s_info->vac) g->set_secure(true);
|
||||
else g->set_secure(false);
|
||||
g->set_num_players(ssq_a2s_info->players);
|
||||
g->set_version(std::stoull(ssq_a2s_info->version, NULL, 0));
|
||||
if (ssq_info_has_port(ssq_a2s_info)) g->set_port(ssq_a2s_info->port);
|
||||
if (ssq_info_has_gameid(ssq_a2s_info)) g->set_appid(ssq_a2s_info->gameid);
|
||||
else g->set_appid(ssq_a2s_info->id);
|
||||
g->set_offline(false);
|
||||
}
|
||||
|
||||
if (ssq_a2s_info != NULL) ssq_info_free(ssq_a2s_info);
|
||||
}
|
||||
|
||||
if (ssq != NULL) ssq_server_free(ssq);
|
||||
}
|
||||
|
||||
uint16 query_port = g->query_port();
|
||||
if (g->query_port() == 0xFFFF) {
|
||||
query_port = g->port();
|
||||
}
|
||||
|
||||
server->m_NetAdr.Init(g->ip(), query_port, g->port());
|
||||
server->m_nPing = 10; //TODO
|
||||
server->m_nPing = latency;
|
||||
server->m_bHadSuccessfulResponse = true;
|
||||
server->m_bDoNotRefresh = false;
|
||||
strncpy(server->m_szGameDir, g->mod_dir().c_str(), k_cbMaxGameServerGameDir - 1);
|
||||
@ -283,6 +426,74 @@ void Steam_Matchmaking_Servers::server_details(Gameserver *g, gameserveritem_t *
|
||||
server->m_szGameTags[k_cbMaxGameServerTags - 1] = 0;
|
||||
}
|
||||
|
||||
void Steam_Matchmaking_Servers::server_details_players(Gameserver *g, Steam_Matchmaking_Servers_Direct_IP_Request *r)
|
||||
{
|
||||
if (!(g->ip() < 0) && !(g->query_port() < 0)) {
|
||||
unsigned char ip[4];
|
||||
char newip[24];
|
||||
ip[0] = g->ip() & 0xFF;
|
||||
ip[1] = (g->ip() >> 8) & 0xFF;
|
||||
ip[2] = (g->ip() >> 16) & 0xFF;
|
||||
ip[3] = (g->ip() >> 24) & 0xFF;
|
||||
snprintf(newip, sizeof(newip), "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]);
|
||||
|
||||
SSQ_SERVER *ssq = ssq_server_new(newip, g->query_port());
|
||||
if (ssq != NULL && ssq_server_eok(ssq)) {
|
||||
ssq_server_timeout(ssq, SSQ_TIMEOUT_RECV, 1200);
|
||||
ssq_server_timeout(ssq, SSQ_TIMEOUT_SEND, 1200);
|
||||
|
||||
uint8_t ssq_a2s_player_count;
|
||||
A2S_PLAYER *ssq_a2s_player = ssq_player(ssq, &ssq_a2s_player_count);
|
||||
|
||||
if (ssq_server_eok(ssq)) {
|
||||
for (int i = 0; i < ssq_a2s_player_count; i++) {
|
||||
r->players_response->AddPlayerToList(ssq_a2s_player[i].name, ssq_a2s_player[i].score, ssq_a2s_player[i].duration);
|
||||
}
|
||||
}
|
||||
|
||||
if (ssq_a2s_player != NULL) ssq_player_free(ssq_a2s_player, ssq_a2s_player_count);
|
||||
}
|
||||
|
||||
if (ssq != NULL) ssq_server_free(ssq);
|
||||
}
|
||||
|
||||
PRINT_DEBUG("server_details_players %llu\n", g->id());
|
||||
}
|
||||
|
||||
void Steam_Matchmaking_Servers::server_details_rules(Gameserver *g, Steam_Matchmaking_Servers_Direct_IP_Request *r)
|
||||
{
|
||||
if (!(g->ip() < 0) && !(g->query_port() < 0)) {
|
||||
unsigned char ip[4];
|
||||
char newip[24];
|
||||
ip[0] = g->ip() & 0xFF;
|
||||
ip[1] = (g->ip() >> 8) & 0xFF;
|
||||
ip[2] = (g->ip() >> 16) & 0xFF;
|
||||
ip[3] = (g->ip() >> 24) & 0xFF;
|
||||
snprintf(newip, sizeof(newip), "%d.%d.%d.%d", ip[3], ip[2], ip[1], ip[0]);
|
||||
|
||||
SSQ_SERVER *ssq = ssq_server_new(newip, g->query_port());
|
||||
if (ssq != NULL && ssq_server_eok(ssq)) {
|
||||
ssq_server_timeout(ssq, SSQ_TIMEOUT_RECV, 1200);
|
||||
ssq_server_timeout(ssq, SSQ_TIMEOUT_SEND, 1200);
|
||||
|
||||
uint16_t ssq_a2s_rules_count;
|
||||
A2S_RULES *ssq_a2s_rules = ssq_rules(ssq, &ssq_a2s_rules_count);
|
||||
|
||||
if (ssq_server_eok(ssq)) {
|
||||
for (int i = 0; i < ssq_a2s_rules_count; i++) {
|
||||
r->rules_response->RulesResponded(ssq_a2s_rules[i].name, ssq_a2s_rules[i].value);
|
||||
}
|
||||
}
|
||||
|
||||
if (ssq_a2s_rules != NULL) ssq_rules_free(ssq_a2s_rules, ssq_a2s_rules_count);
|
||||
}
|
||||
|
||||
if (ssq != NULL) ssq_server_free(ssq);
|
||||
}
|
||||
|
||||
PRINT_DEBUG("server_details_rules %llu\n", 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
|
||||
@ -477,7 +688,7 @@ void Steam_Matchmaking_Servers::RunCallbacks()
|
||||
r.gameservers_filtered.clear();
|
||||
for (auto &g : gameservers) {
|
||||
PRINT_DEBUG("game_server_check %u %u\n", g.server.appid(), r.appid);
|
||||
if (g.server.appid() == r.appid) {
|
||||
if ((g.server.appid() == r.appid) && (g.type == r.type)) {
|
||||
PRINT_DEBUG("REQUESTS server found\n");
|
||||
r.gameservers_filtered.push_back(g);
|
||||
}
|
||||
@ -545,31 +756,27 @@ void Steam_Matchmaking_Servers::RunCallbacks()
|
||||
|
||||
if (query_port == r.port && g.server.ip() == r.ip) {
|
||||
if (r.rules_response) {
|
||||
int number_rules = g.server.values().size();
|
||||
PRINT_DEBUG("rules: %lu\n", number_rules);
|
||||
auto rule = g.server.values().begin();
|
||||
for (int i = 0; i < number_rules; ++i) {
|
||||
PRINT_DEBUG("RULE %s %s\n", rule->first.c_str(), rule->second.c_str());
|
||||
r.rules_response->RulesResponded(rule->first.c_str(), rule->second.c_str());
|
||||
++rule;
|
||||
}
|
||||
|
||||
server_details_rules(&(g.server), &r);
|
||||
r.rules_response->RulesRefreshComplete();
|
||||
r.rules_response = NULL;
|
||||
}
|
||||
|
||||
if (r.players_response) {
|
||||
server_details_players(&(g.server), &r);
|
||||
r.players_response->PlayersRefreshComplete();
|
||||
r.players_response = NULL;
|
||||
}
|
||||
|
||||
if (r.ping_response) {
|
||||
gameserveritem_t server;
|
||||
server_details(&(g.server), &server);
|
||||
r.ping_response->ServerResponded(server);
|
||||
r.ping_response = NULL;
|
||||
}
|
||||
//TODO: players response
|
||||
}
|
||||
}
|
||||
|
||||
if (r.rules_response) r.rules_response->RulesRefreshComplete();
|
||||
//TODO: player response
|
||||
if (r.players_response) r.players_response->PlayersRefreshComplete();
|
||||
if (r.ping_response) r.ping_response->ServerFailedToRespond();
|
||||
}
|
||||
@ -577,12 +784,13 @@ void Steam_Matchmaking_Servers::RunCallbacks()
|
||||
|
||||
void Steam_Matchmaking_Servers::Callback(Common_Message *msg)
|
||||
{
|
||||
if (msg->has_gameserver()) {
|
||||
if (msg->has_gameserver() && msg->gameserver().type() != eFriendsServer) {
|
||||
PRINT_DEBUG("got SERVER %llu, offline:%u\n", msg->gameserver().id(), msg->gameserver().offline());
|
||||
if (msg->gameserver().offline()) {
|
||||
for (auto &g : gameservers) {
|
||||
if (g.server.id() == msg->gameserver().id()) {
|
||||
g.last_recv = std::chrono::high_resolution_clock::time_point();
|
||||
g.type = eLANServer;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@ -592,6 +800,7 @@ void Steam_Matchmaking_Servers::Callback(Common_Message *msg)
|
||||
g.last_recv = std::chrono::high_resolution_clock::now();
|
||||
g.server = msg->gameserver();
|
||||
g.server.set_ip(msg->source_ip());
|
||||
g.type = eLANServer;
|
||||
already = true;
|
||||
}
|
||||
}
|
||||
@ -601,9 +810,31 @@ void Steam_Matchmaking_Servers::Callback(Common_Message *msg)
|
||||
g.last_recv = std::chrono::high_resolution_clock::now();
|
||||
g.server = msg->gameserver();
|
||||
g.server.set_ip(msg->source_ip());
|
||||
g.type = eLANServer;
|
||||
gameservers.push_back(g);
|
||||
PRINT_DEBUG("SERVER ADDED\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (msg->has_gameserver() && msg->gameserver().type() == eFriendsServer) {
|
||||
bool addserver = true;
|
||||
for (auto &g : gameservers_friends) {
|
||||
if (g.source_id == msg->source_id()) {
|
||||
g.ip = msg->gameserver().ip();
|
||||
g.port = msg->gameserver().port();
|
||||
g.last_recv = std::chrono::high_resolution_clock::now();
|
||||
addserver = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (addserver) {
|
||||
struct Steam_Matchmaking_Servers_Gameserver_Friends gameserver_friend;
|
||||
gameserver_friend.source_id = msg->source_id();
|
||||
gameserver_friend.ip = msg->gameserver().ip();
|
||||
gameserver_friend.port = msg->gameserver().port();
|
||||
gameserver_friend.last_recv = std::chrono::high_resolution_clock::now();
|
||||
gameservers_friends.push_back(gameserver_friend);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -16,6 +16,7 @@
|
||||
<http://www.gnu.org/licenses/>. */
|
||||
|
||||
#include "base.h"
|
||||
#include <ssq/a2s.h>
|
||||
|
||||
#define SERVER_TIMEOUT 10.0
|
||||
#define DIRECT_IP_DELAY 0.05
|
||||
@ -31,9 +32,17 @@ struct Steam_Matchmaking_Servers_Direct_IP_Request {
|
||||
ISteamMatchmakingPingResponse *ping_response = NULL;
|
||||
};
|
||||
|
||||
struct Steam_Matchmaking_Servers_Gameserver_Friends {
|
||||
uint64 source_id;
|
||||
uint32 ip;
|
||||
uint16 port;
|
||||
std::chrono::high_resolution_clock::time_point last_recv;
|
||||
};
|
||||
|
||||
struct Steam_Matchmaking_Servers_Gameserver {
|
||||
Gameserver server;
|
||||
std::chrono::high_resolution_clock::time_point last_recv;
|
||||
EMatchMakingType type;
|
||||
};
|
||||
|
||||
struct Steam_Matchmaking_Request {
|
||||
@ -43,6 +52,7 @@ struct Steam_Matchmaking_Request {
|
||||
ISteamMatchmakingServerListResponse001 *old_callbacks;
|
||||
bool completed, cancelled, released;
|
||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers_filtered;
|
||||
EMatchMakingType type;
|
||||
};
|
||||
|
||||
class Steam_Matchmaking_Servers : public ISteamMatchmakingServers,
|
||||
@ -52,8 +62,10 @@ public ISteamMatchmakingServers001
|
||||
class Networking *network;
|
||||
|
||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver> gameservers;
|
||||
std::vector <struct Steam_Matchmaking_Servers_Gameserver_Friends> gameservers_friends;
|
||||
std::vector <struct Steam_Matchmaking_Request> requests;
|
||||
std::vector <struct Steam_Matchmaking_Servers_Direct_IP_Request> direct_ip_requests;
|
||||
HServerListRequest RequestServerList(AppId_t iApp, ISteamMatchmakingServerListResponse *pRequestServersResponse, EMatchMakingType type);
|
||||
void RequestOldServerList(AppId_t iApp, ISteamMatchmakingServerListResponse001 *pRequestServersResponse, EMatchMakingType type);
|
||||
public:
|
||||
Steam_Matchmaking_Servers(class Settings *settings, class Networking *network);
|
||||
@ -222,4 +234,6 @@ public:
|
||||
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);
|
||||
};
|
||||
|
@ -69,11 +69,28 @@ void set_details(PublishedFileId_t id, SteamUGCDetails_t *pDetails)
|
||||
if (settings->isModInstalled(id)) {
|
||||
pDetails->m_eResult = k_EResultOK;
|
||||
pDetails->m_nPublishedFileId = id;
|
||||
pDetails->m_eFileType = k_EWorkshopFileTypeCommunity;
|
||||
pDetails->m_nCreatorAppID = settings->get_local_game_id().AppID();
|
||||
pDetails->m_nConsumerAppID = settings->get_local_game_id().AppID();
|
||||
snprintf(pDetails->m_rgchTitle, sizeof(pDetails->m_rgchDescription), "%s", settings->getMod(id).title.c_str());
|
||||
//TODO
|
||||
snprintf(pDetails->m_rgchTitle, k_cchPublishedDocumentTitleMax, "%s", settings->getMod(id).title.c_str());
|
||||
pDetails->m_eFileType = settings->getMod(id).fileType;
|
||||
snprintf(pDetails->m_rgchDescription, k_cchPublishedDocumentDescriptionMax, "%s", settings->getMod(id).description.c_str());
|
||||
pDetails->m_ulSteamIDOwner = settings->get_local_steam_id().ConvertToUint64();
|
||||
pDetails->m_rtimeCreated = settings->getMod(id).timeCreated;
|
||||
pDetails->m_rtimeUpdated = settings->getMod(id).timeUpdated;
|
||||
pDetails->m_rtimeAddedToUserList = settings->getMod(id).timeAddedToUserList;
|
||||
pDetails->m_eVisibility = settings->getMod(id).visibility;
|
||||
pDetails->m_bBanned = settings->getMod(id).banned;
|
||||
pDetails->m_bAcceptedForUse = settings->getMod(id).acceptedForUse;
|
||||
pDetails->m_bTagsTruncated = settings->getMod(id).tagsTruncated;
|
||||
snprintf(pDetails->m_rgchTags, k_cchTagListMax, "%s", settings->getMod(id).tags.c_str());
|
||||
snprintf(pDetails->m_pchFileName, k_cchFilenameMax, "%s", settings->getMod(id).primaryFileName.c_str());
|
||||
pDetails->m_nFileSize = settings->getMod(id).primaryFileSize;
|
||||
pDetails->m_nPreviewFileSize = settings->getMod(id).previewFileSize;
|
||||
snprintf(pDetails->m_rgchURL, k_cchPublishedFileURLMax, "%s", settings->getMod(id).workshopItemURL.c_str());
|
||||
pDetails->m_unVotesUp = settings->getMod(id).votesUp;
|
||||
pDetails->m_unVotesDown = settings->getMod(id).votesDown;
|
||||
pDetails->m_flScore = settings->getMod(id).score;
|
||||
//pDetails->m_unNumChildren = settings->getMod(id).numChildren;
|
||||
} else {
|
||||
pDetails->m_nPublishedFileId = id;
|
||||
pDetails->m_eResult = k_EResultFail;
|
||||
@ -205,7 +222,18 @@ bool GetQueryUGCTagDisplayName( UGCQueryHandle_t handle, uint32 index, uint32 in
|
||||
bool GetQueryUGCPreviewURL( UGCQueryHandle_t handle, uint32 index, STEAM_OUT_STRING_COUNT(cchURLSize) char *pchURL, uint32 cchURLSize )
|
||||
{
|
||||
PRINT_DEBUG("Steam_UGC::GetQueryUGCPreviewURL\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
//TODO: escape simulator tries downloading this url and unsubscribes if it fails
|
||||
|
||||
auto request = std::find_if(ugc_queries.begin(), ugc_queries.end(), [&handle](struct UGC_query const& item) { return item.handle == handle; });
|
||||
if ((ugc_queries.end() != request) && !(index >= request->results.size())) {
|
||||
auto it = request->results.begin();
|
||||
uint32 it2 = (uint32)*it;
|
||||
PRINT_DEBUG("Steam_UGC:GetQueryUGCPreviewURL: %u %s\n", it2, settings->getMod(it2).previewURL.c_str());
|
||||
snprintf(pchURL, cchURLSize, "%s", settings->getMod(it2).previewURL.c_str());
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -600,13 +628,13 @@ bool RemoveItemPreview( UGCUpdateHandle_t handle, uint32 index )
|
||||
|
||||
bool AddContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid )
|
||||
{
|
||||
PRINT_DEBUG("Steam_UGC::AddContentDescriptor %llu %u\n", handle, index);
|
||||
PRINT_DEBUG("Steam_UGC::AddContentDescriptor %llu %u\n", handle, descid);
|
||||
return false;
|
||||
}
|
||||
|
||||
bool RemoveContentDescriptor( UGCUpdateHandle_t handle, EUGCContentDescriptorID descid )
|
||||
{
|
||||
PRINT_DEBUG("Steam_UGC::RemoveContentDescriptor %llu %u\n", handle, index);
|
||||
PRINT_DEBUG("Steam_UGC::RemoveContentDescriptor %llu %u\n", handle, descid);
|
||||
return false;
|
||||
}
|
||||
|
||||
@ -743,8 +771,8 @@ bool GetItemInstallInfo( PublishedFileId_t nPublishedFileID, uint64 *punSizeOnDi
|
||||
return false;
|
||||
}
|
||||
|
||||
if (punSizeOnDisk) *punSizeOnDisk = 1000000;
|
||||
if (punTimeStamp) *punTimeStamp = 1554997000;
|
||||
if (punSizeOnDisk) *punSizeOnDisk = settings->getMod(nPublishedFileID).primaryFileSize;
|
||||
if (punTimeStamp) *punTimeStamp = settings->getMod(nPublishedFileID).timeCreated;
|
||||
if (pchFolder && cchFolderSize) {
|
||||
snprintf(pchFolder, cchFolderSize, "%s", settings->getMod(nPublishedFileID).path.c_str());
|
||||
}
|
||||
|
@ -375,6 +375,18 @@ bool BIsBehindNAT()
|
||||
void AdvertiseGame( CSteamID steamIDGameServer, uint32 unIPServer, uint16 usPortServer )
|
||||
{
|
||||
PRINT_DEBUG("AdvertiseGame\n");
|
||||
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());
|
||||
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
|
||||
|
BIN
files_example/steam_settings.EXAMPLE/account_avatar.EXAMPLE.jpg
Normal file
BIN
files_example/steam_settings.EXAMPLE/account_avatar.EXAMPLE.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
Binary file not shown.
After Width: | Height: | Size: 3.3 KiB |
@ -0,0 +1 @@
|
||||
Rename this to: disable_account_avatar.txt to disable avatar functionality.
|
@ -0,0 +1 @@
|
||||
Rename this to: disable_lan_only.txt to disable LAN only functionality.
|
@ -0,0 +1 @@
|
||||
Rename this to: disable_overlay_achievement_notification.EXAMPLE.txt to disable the achievement notifications.
|
@ -0,0 +1 @@
|
||||
Rename this to: disable_source_query.txt to not send server details for the server browser. Only works for game servers.
|
@ -0,0 +1 @@
|
||||
Rename this to: http_online.txt to enable external HTTP download functionality.
|
31
files_example/steam_settings.EXAMPLE/mods.EXAMPLE.json
Normal file
31
files_example/steam_settings.EXAMPLE/mods.EXAMPLE.json
Normal file
@ -0,0 +1,31 @@
|
||||
{
|
||||
"111111111": {
|
||||
"title": "Example Workshop Item",
|
||||
"description": "Example Workshop Item with all Details",
|
||||
"steam_id_owner": 11111111111111111,
|
||||
"time_created": 1554997000,
|
||||
"time_updated": 1554997000,
|
||||
"time_added": 1554997000,
|
||||
"tags": "Maps, exampleTag, exampleTag2",
|
||||
"primary_filename": "test.sav",
|
||||
"primary_filesize": 1000000,
|
||||
"preview_filename": "test.png",
|
||||
"preview_filesize": 1000000,
|
||||
"workshop_item_url": "https://steamcommunity.com/sharedfiles/filedetails/?id=111111111",
|
||||
"upvotes": 1,
|
||||
"downvotes": 0,
|
||||
"num_children": 0
|
||||
},
|
||||
|
||||
"222222222": {
|
||||
"title": "Example Workshop Item",
|
||||
"description": "Example Workshop Item with all Details"
|
||||
},
|
||||
|
||||
"333333333": {
|
||||
"title": "Example Workshop Item"
|
||||
},
|
||||
|
||||
"444444444": {
|
||||
}
|
||||
}
|
@ -0,0 +1 @@
|
||||
000000000000000000 Group Name Clan Tag
|
@ -1,4 +1,5 @@
|
||||
#include "steam_overlay.h"
|
||||
#include "steam_overlay_translations.h"
|
||||
|
||||
#ifdef EMU_OVERLAY
|
||||
|
||||
@ -377,7 +378,7 @@ void Steam_Overlay::FriendConnect(Friend _friend)
|
||||
if (id != 0)
|
||||
{
|
||||
auto& item = friends[_friend];
|
||||
item.window_title = std::move(_friend.name() + " playing " + std::to_string(_friend.appid()));
|
||||
item.window_title = std::move(_friend.name() + translationPlaying[current_language] + std::to_string(_friend.appid()));
|
||||
item.window_state = window_state_none;
|
||||
item.id = id;
|
||||
memset(item.chat_input, 0, max_chat_len);
|
||||
@ -416,20 +417,22 @@ void Steam_Overlay::AddMessageNotification(std::string const& message)
|
||||
void Steam_Overlay::AddAchievementNotification(nlohmann::json const& ach)
|
||||
{
|
||||
std::lock_guard<std::recursive_mutex> lock(notifications_mutex);
|
||||
int id = find_free_notification_id(notifications);
|
||||
if (id != 0)
|
||||
{
|
||||
Notification notif;
|
||||
notif.id = id;
|
||||
notif.type = notification_type_achievement;
|
||||
// Load achievement image
|
||||
notif.message = ach["displayName"].get<std::string>() + "\n" + ach["description"].get<std::string>();
|
||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
notifications.emplace_back(notif);
|
||||
have_notifications = true;
|
||||
if (!settings->disable_overlay_achievement_notification) {
|
||||
int id = find_free_notification_id(notifications);
|
||||
if (id != 0)
|
||||
{
|
||||
Notification notif;
|
||||
notif.id = id;
|
||||
notif.type = notification_type_achievement;
|
||||
// Load achievement image
|
||||
notif.message = ach["displayName"].get<std::string>() + "\n" + ach["description"].get<std::string>();
|
||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
notifications.emplace_back(notif);
|
||||
have_notifications = true;
|
||||
}
|
||||
else
|
||||
PRINT_DEBUG("No more free id to create a notification window\n");
|
||||
}
|
||||
else
|
||||
PRINT_DEBUG("No more free id to create a notification window\n");
|
||||
|
||||
std::string ach_name = ach.value("name", "");
|
||||
for (auto &a : achievements) {
|
||||
@ -453,7 +456,11 @@ void Steam_Overlay::AddInviteNotification(std::pair<const Friend, friend_window_
|
||||
notif.id = id;
|
||||
notif.type = notification_type_invite;
|
||||
notif.frd = &wnd_state;
|
||||
notif.message = wnd_state.first.name() + " invited you to join a game";
|
||||
|
||||
char tmp[TRANSLATION_BUFFER_SIZE];
|
||||
snprintf(tmp, sizeof(tmp), translationInvitedYouToJoinTheGame[current_language], wnd_state.first.name(), wnd_state.first.id());
|
||||
notif.message = tmp;
|
||||
|
||||
notif.start_time = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch());
|
||||
notifications.emplace_back(notif);
|
||||
have_notifications = true;
|
||||
@ -495,7 +502,7 @@ void Steam_Overlay::BuildContextMenu(Friend const& frd, friend_window_state& sta
|
||||
{
|
||||
bool close_popup = false;
|
||||
|
||||
if (ImGui::Button("Chat"))
|
||||
if (ImGui::Button(translationChat[current_language]))
|
||||
{
|
||||
state.window_state |= window_state_show;
|
||||
close_popup = true;
|
||||
@ -503,13 +510,20 @@ void Steam_Overlay::BuildContextMenu(Friend const& frd, friend_window_state& sta
|
||||
// If we have the same appid, activate the invite/join buttons
|
||||
if (settings->get_local_game_id().AppID() == frd.appid())
|
||||
{
|
||||
if (i_have_lobby && ImGui::Button("Invite###PopupInvite"))
|
||||
std::string translationInvite_tmp;
|
||||
std::string translationJoin_tmp;
|
||||
translationInvite_tmp.append(translationInvite[current_language]);
|
||||
translationInvite_tmp.append("##PopupInvite");
|
||||
translationJoin_tmp.append(translationJoin[current_language]);
|
||||
translationJoin_tmp.append("##PopupInvite");
|
||||
|
||||
if (i_have_lobby && ImGui::Button(translationInvite_tmp.c_str()))
|
||||
{
|
||||
state.window_state |= window_state_invite;
|
||||
has_friend_action.push(frd);
|
||||
close_popup = true;
|
||||
}
|
||||
if (state.joinable && ImGui::Button("Join###PopupJoin"))
|
||||
if (state.joinable && ImGui::Button(translationJoin_tmp.c_str()))
|
||||
{
|
||||
state.window_state |= window_state_join;
|
||||
has_friend_action.push(frd);
|
||||
@ -554,15 +568,15 @@ void Steam_Overlay::BuildFriendWindow(Friend const& frd, friend_window_state& st
|
||||
// Fill this with the chat box and maybe the invitation
|
||||
if (state.window_state & (window_state_lobby_invite | window_state_rich_invite))
|
||||
{
|
||||
ImGui::LabelText("##label", "%s invited you to join the game.", frd.name().c_str());
|
||||
ImGui::LabelText("##label", translationInvitedYouToJoinTheGame[current_language], frd.name().c_str(), frd.appid());
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Accept"))
|
||||
if (ImGui::Button(translationAccept[current_language]))
|
||||
{
|
||||
state.window_state |= window_state_join;
|
||||
this->has_friend_action.push(frd);
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Refuse"))
|
||||
if (ImGui::Button(translationRefuse[current_language]))
|
||||
{
|
||||
state.window_state &= ~(window_state_lobby_invite | window_state_rich_invite);
|
||||
}
|
||||
@ -591,7 +605,7 @@ void Steam_Overlay::BuildFriendWindow(Friend const& frd, friend_window_state& st
|
||||
// |------------------------------|
|
||||
float wnd_width = ImGui::GetWindowContentRegionWidth();
|
||||
ImGuiStyle &style = ImGui::GetStyle();
|
||||
wnd_width -= ImGui::CalcTextSize("Send").x + style.FramePadding.x * 2 + style.ItemSpacing.x + 1;
|
||||
wnd_width -= ImGui::CalcTextSize(translationSend[current_language]).x + style.FramePadding.x * 2 + style.ItemSpacing.x + 1;
|
||||
|
||||
ImGui::PushItemWidth(wnd_width);
|
||||
if (ImGui::InputText("##chat_line", state.chat_input, max_chat_len, ImGuiInputTextFlags_EnterReturnsTrue))
|
||||
@ -603,7 +617,7 @@ void Steam_Overlay::BuildFriendWindow(Friend const& frd, friend_window_state& st
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Send"))
|
||||
if (ImGui::Button(translationSend[current_language]))
|
||||
{
|
||||
send_chat_msg = true;
|
||||
}
|
||||
@ -677,7 +691,7 @@ void Steam_Overlay::BuildNotifications(int width, int height)
|
||||
case notification_type_invite:
|
||||
{
|
||||
ImGui::TextWrapped("%s", it->message.c_str());
|
||||
if (ImGui::Button("Join"))
|
||||
if (ImGui::Button(translationJoin[current_language]))
|
||||
{
|
||||
it->frd->second.window_state |= window_state_join;
|
||||
friend_actions_temp.push(it->frd->first);
|
||||
@ -727,6 +741,43 @@ void Steam_Overlay::CreateFonts()
|
||||
font_builder.AddText(x.title.c_str());
|
||||
font_builder.AddText(x.description.c_str());
|
||||
}
|
||||
for (int i = 0; i < TRANSLATION_NUMBER_OF_LANGUAGES; i++) {
|
||||
font_builder.AddText(translationChat[i]);
|
||||
font_builder.AddText(translationInvite[i]);
|
||||
font_builder.AddText(translationJoin[i]);
|
||||
font_builder.AddText(translationInvitedYouToJoinTheGame[i]);
|
||||
font_builder.AddText(translationAccept[i]);
|
||||
font_builder.AddText(translationRefuse[i]);
|
||||
font_builder.AddText(translationSend[i]);
|
||||
font_builder.AddText(translationSteamOverlay[i]);
|
||||
font_builder.AddText(translationUserPlaying[i]);
|
||||
font_builder.AddText(translationRenderer[i]);
|
||||
font_builder.AddText(translationShowAchievements[i]);
|
||||
font_builder.AddText(translationSettings[i]);
|
||||
font_builder.AddText(translationFriends[i]);
|
||||
font_builder.AddText(translationAchievementWindow[i]);
|
||||
font_builder.AddText(translationListOfAchievements[i]);
|
||||
font_builder.AddText(translationAchievements[i]);
|
||||
font_builder.AddText(translationHiddenAchievement[i]);
|
||||
font_builder.AddText(translationAchievedOn[i]);
|
||||
font_builder.AddText(translationNotAchieved[i]);
|
||||
font_builder.AddText(translationGlobalSettingsWindow[i]);
|
||||
font_builder.AddText(translationGlobalSettingsWindowDescription[i]);
|
||||
font_builder.AddText(translationUsername[i]);
|
||||
font_builder.AddText(translationLanguage[i]);
|
||||
font_builder.AddText(translationSelectedLanguage[i]);
|
||||
font_builder.AddText(translationRestartTheGameToApply[i]);
|
||||
font_builder.AddText(translationSave[i]);
|
||||
font_builder.AddText(translationWarning[i]);
|
||||
font_builder.AddText(translationWarningWarningWarning[i]);
|
||||
font_builder.AddText(translationWarningDescription1[i]);
|
||||
font_builder.AddText(translationWarningDescription2[i]);
|
||||
font_builder.AddText(translationWarningDescription3[i]);
|
||||
font_builder.AddText(translationWarningDescription4[i]);
|
||||
font_builder.AddText(translationSteamOverlayURL[i]);
|
||||
font_builder.AddText(translationClose[i]);
|
||||
font_builder.AddText(translationPlaying[i]);
|
||||
}
|
||||
|
||||
font_builder.AddRanges(Fonts->GetGlyphRangesDefault());
|
||||
|
||||
@ -799,31 +850,31 @@ void Steam_Overlay::OverlayProc()
|
||||
|
||||
bool show = true;
|
||||
|
||||
if (ImGui::Begin("SteamOverlay", &show, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus))
|
||||
if (ImGui::Begin(translationSteamOverlay[current_language], &show, ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoBringToFrontOnFocus))
|
||||
{
|
||||
ImGui::LabelText("##label", "Username: %s(%llu) playing %u",
|
||||
ImGui::LabelText("##label", translationUserPlaying[current_language],
|
||||
settings->get_local_name(),
|
||||
settings->get_local_steam_id().ConvertToUint64(),
|
||||
settings->get_local_game_id().AppID());
|
||||
ImGui::SameLine();
|
||||
|
||||
ImGui::LabelText("##label", "Renderer: %s", (_renderer == nullptr ? "Unknown" : _renderer->GetLibraryName().c_str()));
|
||||
ImGui::LabelText("##label", translationRenderer[current_language], (_renderer == nullptr ? "Unknown" : _renderer->GetLibraryName().c_str()));
|
||||
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("Show Achievements")) {
|
||||
if (ImGui::Button(translationShowAchievements[current_language])) {
|
||||
show_achievements = true;
|
||||
}
|
||||
|
||||
ImGui::SameLine();
|
||||
|
||||
if (ImGui::Button("Settings")) {
|
||||
if (ImGui::Button(translationSettings[current_language])) {
|
||||
show_settings = true;
|
||||
}
|
||||
|
||||
ImGui::Spacing();
|
||||
ImGui::Spacing();
|
||||
|
||||
ImGui::LabelText("##label", "Friends");
|
||||
ImGui::LabelText("##label", translationFriends[current_language]);
|
||||
|
||||
std::lock_guard<std::recursive_mutex> lock(overlay_mutex);
|
||||
if (!friends.empty())
|
||||
@ -851,9 +902,9 @@ void Steam_Overlay::OverlayProc()
|
||||
if (show_achievements && achievements.size()) {
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetFontSize() * 32, ImGui::GetFontSize() * 32), ImVec2(8192, 8192));
|
||||
bool show = show_achievements;
|
||||
if (ImGui::Begin("Achievement Window", &show)) {
|
||||
ImGui::Text("List of achievements");
|
||||
ImGui::BeginChild("Achievements");
|
||||
if (ImGui::Begin(translationAchievementWindow[current_language], &show)) {
|
||||
ImGui::Text(translationListOfAchievements[current_language]);
|
||||
ImGui::BeginChild(translationAchievements[current_language]);
|
||||
for (auto & x : achievements) {
|
||||
bool achieved = x.achieved;
|
||||
bool hidden = x.hidden && !achieved;
|
||||
@ -861,7 +912,7 @@ void Steam_Overlay::OverlayProc()
|
||||
ImGui::Separator();
|
||||
ImGui::Text("%s", x.title.c_str());
|
||||
if (hidden) {
|
||||
ImGui::Text("hidden achievement");
|
||||
ImGui::Text(translationHiddenAchievement[current_language]);
|
||||
} else {
|
||||
ImGui::TextWrapped("%s", x.description.c_str());
|
||||
}
|
||||
@ -871,9 +922,9 @@ void Steam_Overlay::OverlayProc()
|
||||
time_t unlock_time = (time_t)x.unlock_time;
|
||||
std::strftime(buffer, 80, "%Y-%m-%d at %H:%M:%S", std::localtime(&unlock_time));
|
||||
|
||||
ImGui::TextColored(ImVec4(0, 255, 0, 255), "achieved on %s", buffer);
|
||||
ImGui::TextColored(ImVec4(0, 255, 0, 255), translationAchievedOn[current_language], buffer);
|
||||
} else {
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "not achieved");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationNotAchieved[current_language]);
|
||||
}
|
||||
ImGui::Separator();
|
||||
}
|
||||
@ -884,37 +935,37 @@ void Steam_Overlay::OverlayProc()
|
||||
}
|
||||
|
||||
if (show_settings) {
|
||||
if (ImGui::Begin("Global Settings Window", &show_settings)) {
|
||||
ImGui::Text("These are global emulator settings and will apply to all games.");
|
||||
if (ImGui::Begin(translationGlobalSettingsWindow[current_language], &show_settings)) {
|
||||
ImGui::Text(translationGlobalSettingsWindowDescription[current_language]);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Username:");
|
||||
ImGui::Text(translationUsername[current_language]);
|
||||
ImGui::SameLine();
|
||||
ImGui::InputText("##username", username_text, sizeof(username_text), disable_forced ? ImGuiInputTextFlags_ReadOnly : 0);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
ImGui::Text("Language:");
|
||||
ImGui::Text(translationLanguage[current_language]);
|
||||
|
||||
if (ImGui::ListBox("##language", ¤t_language, valid_languages, sizeof(valid_languages) / sizeof(char *), 7)) {
|
||||
|
||||
}
|
||||
|
||||
ImGui::Text("Selected Language: %s", valid_languages[current_language]);
|
||||
ImGui::Text(translationSelectedLanguage[current_language], valid_languages[current_language]);
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
if (!disable_forced) {
|
||||
ImGui::Text("You may have to restart the game for these to apply.");
|
||||
if (ImGui::Button("Save")) {
|
||||
ImGui::Text(translationRestartTheGameToApply[current_language]);
|
||||
if (ImGui::Button(translationSave[current_language])) {
|
||||
save_settings = true;
|
||||
show_settings = false;
|
||||
}
|
||||
} else {
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextWrapped("Some steam_settings/force_*.txt files have been detected. Please delete them if you want this menu to work.");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
ImGui::TextWrapped(translationWarningDescription1[current_language]);
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -925,13 +976,13 @@ void Steam_Overlay::OverlayProc()
|
||||
if (url.size()) {
|
||||
bool show = true;
|
||||
if (ImGui::Begin(URL_WINDOW_NAME, &show)) {
|
||||
ImGui::Text("The game tried to get the steam overlay to open this url:");
|
||||
ImGui::Text(translationSteamOverlayURL[current_language]);
|
||||
ImGui::Spacing();
|
||||
ImGui::PushItemWidth(ImGui::CalcTextSize(url.c_str()).x + 20);
|
||||
ImGui::InputText("##url_copy", (char *)url.data(), url.size(), ImGuiInputTextFlags_ReadOnly);
|
||||
ImGui::PopItemWidth();
|
||||
ImGui::Spacing();
|
||||
if (ImGui::Button("Close") || !show)
|
||||
if (ImGui::Button(translationClose[current_language]) || !show)
|
||||
show_url = "";
|
||||
// ImGui::SetWindowSize(ImVec2(ImGui::CalcTextSize(url.c_str()).x + 10, 0));
|
||||
}
|
||||
@ -942,21 +993,21 @@ void Steam_Overlay::OverlayProc()
|
||||
if (show_warning) {
|
||||
ImGui::SetNextWindowSizeConstraints(ImVec2(ImGui::GetFontSize() * 32, ImGui::GetFontSize() * 32), ImVec2(8192, 8192));
|
||||
ImGui::SetNextWindowFocus();
|
||||
if (ImGui::Begin("WARNING", &show_warning)) {
|
||||
if (ImGui::Begin(translationWarning[current_language], &show_warning)) {
|
||||
if (appid == 0) {
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextWrapped("AppID is 0, please create a steam_appid.txt with the right appid and restart the game.");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
ImGui::TextWrapped(translationWarningDescription2[current_language]);
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
}
|
||||
if (local_save) {
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextWrapped("local_save.txt detected, the emu is saving locally to the game folder. Please delete it if you don't want this.");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
ImGui::TextWrapped(translationWarningDescription3[current_language]);
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
}
|
||||
if (warning_forced) {
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextWrapped("Some steam_settings/force_*.txt files have been detected. You will not be able to save some settings.");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), "WARNING WARNING WARNING");
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
ImGui::TextWrapped(translationWarningDescription4[current_language]);
|
||||
ImGui::TextColored(ImVec4(255, 0, 0, 255), translationWarningWarningWarning[current_language]);
|
||||
}
|
||||
}
|
||||
ImGui::End();
|
||||
@ -994,7 +1045,7 @@ void Steam_Overlay::Callback(Common_Message *msg)
|
||||
friend_info->second.window_state |= window_state_need_attention;
|
||||
}
|
||||
|
||||
AddMessageNotification(friend_info->first.name() + " says: " + steam_message.message());
|
||||
AddMessageNotification(friend_info->first.name() + ": " + steam_message.message());
|
||||
NotifyUser(friend_info->second);
|
||||
}
|
||||
}
|
||||
|
@ -61,7 +61,7 @@ struct Notification
|
||||
static constexpr float r = 0.16;
|
||||
static constexpr float g = 0.29;
|
||||
static constexpr float b = 0.48;
|
||||
static constexpr float max_alpha = 0.5f;
|
||||
static constexpr float max_alpha = 1.0f;
|
||||
|
||||
int id;
|
||||
uint8 type;
|
||||
|
3140
overlay_experimental/steam_overlay_translations.h
Normal file
3140
overlay_experimental/steam_overlay_translations.h
Normal file
File diff suppressed because it is too large
Load Diff
@ -1,36 +1,67 @@
|
||||
#!/bin/bash
|
||||
APP_NAME="bin/test_executable"
|
||||
APP_ID=480
|
||||
APP_PATH=$(dirname "$0")
|
||||
CONFIG_PATH=$(dirname "$0")
|
||||
#path to steam-runtime/run.sh
|
||||
STEAM_RUNTIME=""
|
||||
#!/bin/sh
|
||||
EXE="./hl2.sh"
|
||||
EXE_RUN_DIR="$(dirname ${0})"
|
||||
EXE_COMMAND_LINE="-steam -game cstrike"
|
||||
APP_ID=240
|
||||
STEAM_CLIENT_SO=steamclient.so
|
||||
STEAM_CLIENT64_SO=steamclient64.so
|
||||
#STEAM_RUNTIME="./steam_runtime/run.sh"
|
||||
|
||||
CUR_DIR=$(pwd)
|
||||
cd "$CONFIG_PATH"
|
||||
mkdir -p ~/.steam/sdk64
|
||||
mkdir -p ~/.steam/sdk32
|
||||
#make a backup of original files
|
||||
mv ~/.steam/steam.pid ~/.steam/steam.pid.orig || true
|
||||
mv ~/.steam/sdk64/steamclient.so ~/.steam/sdk64/steamclient.so.orig || true
|
||||
mv ~/.steam/sdk32/steamclient.so ~/.steam/sdk32/steamclient.so.orig || true
|
||||
#copy our files
|
||||
cp x86/steamclient.so ~/.steam/sdk32/steamclient.so
|
||||
cp x86_64/steamclient.so ~/.steam/sdk64/steamclient.so
|
||||
echo $BASHPID > ~/.steam/steam.pid
|
||||
cd "$APP_PATH"
|
||||
if [ -z "$STEAM_RUNTIME" ]
|
||||
then
|
||||
SteamAppPath="$APP_PATH" SteamAppId=$APP_ID SteamGameId=$APP_ID "$APP_NAME"
|
||||
else
|
||||
SteamAppPath="$APP_PATH" SteamAppId=$APP_ID SteamGameId=$APP_ID "$STEAM_RUNTIME" "$APP_NAME"
|
||||
if [ ! -d ~/.steam/sdk32 ]; then
|
||||
mkdir -p ~/.steam/sdk32
|
||||
fi
|
||||
if [ ! -d ~/.steam/sdk64 ]; then
|
||||
mkdir -p ~/.steam/sdk64
|
||||
fi
|
||||
|
||||
if [ ! -f ${STEAM_CLIENT_SO} ]; then
|
||||
echo "Couldn't find the requested STEAM_CLIENT_SO."
|
||||
exit
|
||||
fi
|
||||
if [ ! -f ${STEAM_CLIENT64_SO} ]; then
|
||||
echo "Couldn't find the requested STEAM_CLIENT64_SO."
|
||||
exit
|
||||
fi
|
||||
|
||||
# for system failure assume orig files are still good
|
||||
if [ -f ~/.steam/steam.pid.orig ]; then
|
||||
mv -f ~/.steam/steam.pid.orig ~/.steam/steam.pid
|
||||
fi
|
||||
if [ -f ~/.steam/sdk32/steamclient.so.orig ]; then
|
||||
mv -f ~/.steam/sdk32/steamclient.so.orig ~/.steam/sdk32/steamclient.so
|
||||
fi
|
||||
if [ -f ~/.steam/sdk64/steamclient.so.orig ]; then
|
||||
mv -f ~/.steam/sdk64/steamclient.so.orig ~/.steam/sdk64/steamclient.so
|
||||
fi
|
||||
|
||||
if [ -f ~/.steam/steam.pid ]; then
|
||||
mv -f ~/.steam/steam.pid ~/.steam/steam.pid.orig
|
||||
fi
|
||||
if [ -f ~/.steam/sdk32/steamclient.so ]; then
|
||||
mv -f ~/.steam/sdk32/steamclient.so ~/.steam/sdk32/steamclient.so.orig
|
||||
fi
|
||||
if [ -f ~/.steam/sdk64/steamclient.so ]; then
|
||||
mv -f ~/.steam/sdk64/steamclient.so ~/.steam/sdk64/steamclient.so.orig
|
||||
fi
|
||||
|
||||
cp ${STEAM_CLIENT_SO} ~/.steam/sdk32/steamclient.so
|
||||
cp ${STEAM_CLIENT64_SO} ~/.steam/sdk64/steamclient.so
|
||||
echo ${$} > ~/.steam/steam.pid
|
||||
|
||||
cd ${EXE_RUN_DIR}
|
||||
if [ -z ${STEAM_RUNTIME} ]; then
|
||||
SteamAppPath=${EXE_RUN_DIR} SteamAppId=${APP_ID} SteamGameId=${APP_ID} ${EXE} ${EXE_COMMAND_LINE}
|
||||
else
|
||||
SteamAppPath=${EXE_RUN_DIR} SteamAppId=${APP_ID} SteamGameId=${APP_ID} ${STEAM_RUNTIME} ${EXE} ${EXE_COMMAND_LINE}
|
||||
fi
|
||||
|
||||
if [ -f ~/.steam/steam.pid.orig ]; then
|
||||
mv -f ~/.steam/steam.pid.orig ~/.steam/steam.pid
|
||||
fi
|
||||
if [ -f ~/.steam/sdk32/steamclient.so.orig ]; then
|
||||
mv -f ~/.steam/sdk32/steamclient.so.orig ~/.steam/sdk32/steamclient.so
|
||||
fi
|
||||
if [ -f ~/.steam/sdk64/steamclient.so.orig ]; then
|
||||
mv -f ~/.steam/sdk64/steamclient.so.orig ~/.steam/sdk64/steamclient.so
|
||||
fi
|
||||
|
||||
cd "$CUR_DIR"
|
||||
#restore original
|
||||
rm -f ~/.steam/steam.pid
|
||||
rm -f ~/.steam/sdk64/steamclient.so
|
||||
rm -f ~/.steam/sdk32/steamclient.so
|
||||
mv ~/.steam/steam.pid.orig ~/.steam/steam.pid
|
||||
mv ~/.steam/sdk64/steamclient.so.orig ~/.steam/sdk64/steamclient.so || true
|
||||
mv ~/.steam/sdk32/steamclient.so.orig ~/.steam/sdk32/steamclient.so || true
|
||||
|
@ -1,4 +1,4 @@
|
||||
//====== Copyright © Valve Corporation, All rights reserved. =======
|
||||
//====== Copyright © Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: interface for game servers to steam stats and achievements
|
||||
//
|
||||
|
@ -1,4 +1,4 @@
|
||||
//====== Copyright © 1996-2014 Valve Corporation, All rights reserved. =======
|
||||
//====== Copyright © 1996-2014 Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: interface to Steam Inventory
|
||||
//
|
||||
|
@ -1,4 +1,4 @@
|
||||
//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. =======
|
||||
//====== Copyright © 1996-2008, Valve Corporation, All rights reserved. =======
|
||||
//
|
||||
// Purpose: interface to steam for retrieving list of game servers
|
||||
//
|
||||
|
2634
stb/stb_image_resize.h
Normal file
2634
stb/stb_image_resize.h
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
x
Reference in New Issue
Block a user