Cleaned a bit hooks and added sanity checks.
parent
2365b50c38
commit
9b178146c4
@ -0,0 +1,241 @@
|
|||||||
|
#include <iostream>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <cstdint>
|
||||||
|
#include <fstream>
|
||||||
|
#include <iomanip>
|
||||||
|
|
||||||
|
#include <curl/curl.h>
|
||||||
|
#include <json/json.hpp>
|
||||||
|
|
||||||
|
class CurlGlobal
|
||||||
|
{
|
||||||
|
bool _init;
|
||||||
|
|
||||||
|
CurlGlobal() :_init(false) {}
|
||||||
|
|
||||||
|
~CurlGlobal() { cleanup(); }
|
||||||
|
|
||||||
|
public:
|
||||||
|
static CurlGlobal& Inst()
|
||||||
|
{
|
||||||
|
static CurlGlobal _this;
|
||||||
|
return _this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode init(long flags = CURL_GLOBAL_DEFAULT) { return curl_global_init(flags); }
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
if (_init)
|
||||||
|
{
|
||||||
|
curl_global_cleanup();
|
||||||
|
_init = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
class CurlEasy
|
||||||
|
{
|
||||||
|
CURL* _me;
|
||||||
|
bool _init;
|
||||||
|
std::string _buffer;
|
||||||
|
|
||||||
|
static int writer(char* data, size_t size, size_t nmemb,
|
||||||
|
CurlEasy* _this)
|
||||||
|
{
|
||||||
|
if (_this == nullptr)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
_this->_buffer.append(data, size * nmemb);
|
||||||
|
|
||||||
|
return size * nmemb;
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
CurlEasy() :_me(nullptr), _init(false) {}
|
||||||
|
~CurlEasy() { cleanup(); }
|
||||||
|
|
||||||
|
bool init()
|
||||||
|
{
|
||||||
|
_init = (_me = curl_easy_init()) != nullptr;
|
||||||
|
if (_init)
|
||||||
|
{
|
||||||
|
if (curl_easy_setopt(_me, CURLOPT_WRITEFUNCTION, writer) != CURLE_OK)
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (curl_easy_setopt(_me, CURLOPT_WRITEDATA, this) != CURLE_OK)
|
||||||
|
{
|
||||||
|
cleanup();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return _init;
|
||||||
|
}
|
||||||
|
|
||||||
|
void cleanup()
|
||||||
|
{
|
||||||
|
if (_init)
|
||||||
|
{
|
||||||
|
curl_easy_cleanup(_me);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode set_url(const std::string& url)
|
||||||
|
{
|
||||||
|
return curl_easy_setopt(_me, CURLOPT_URL, url.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode skip_verifypeer(bool skip = true)
|
||||||
|
{
|
||||||
|
return curl_easy_setopt(_me, CURLOPT_SSL_VERIFYPEER, skip ? 0L : 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode skip_verifhost(bool skip = true)
|
||||||
|
{
|
||||||
|
return curl_easy_setopt(_me, CURLOPT_SSL_VERIFYHOST, skip ? 0L : 1L);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode connect_only(bool connect = true)
|
||||||
|
{
|
||||||
|
return curl_easy_setopt(_me, CURLOPT_CONNECT_ONLY, connect ? 1L : 0L);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode perform()
|
||||||
|
{
|
||||||
|
_buffer.clear();
|
||||||
|
return curl_easy_perform(_me);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode recv(void* buffer, size_t buflen, size_t* read_len)
|
||||||
|
{
|
||||||
|
return curl_easy_recv(_me, buffer, buflen, read_len);
|
||||||
|
}
|
||||||
|
|
||||||
|
CURLcode get_html_code(long& code)
|
||||||
|
{
|
||||||
|
return curl_easy_getinfo(_me, CURLINFO_RESPONSE_CODE, &code);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string const& get_answer() const { return _buffer; }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Get all steam appid with their name: http://api.steampowered.com/ISteamApps/GetAppList/v2/
|
||||||
|
// Steam storefront webapi: https://wiki.teamfortress.com/wiki/User:RJackson/StorefrontAPI
|
||||||
|
// http://api.steampowered.com/ISteamUserStats/GetSchemaForGame/v2/?key=<key>&appid=<appid>
|
||||||
|
/*
|
||||||
|
{
|
||||||
|
"game" : {
|
||||||
|
"gameName" : "<name>",
|
||||||
|
"availableGameStats" : {
|
||||||
|
"achievements" : {
|
||||||
|
("<id>" : {
|
||||||
|
"name" : "achievement_name",
|
||||||
|
"displayName" : "achievement name on screen",
|
||||||
|
"hidden" : (0|1),
|
||||||
|
["description" : "<desc>",]
|
||||||
|
"icon" : "<url to icon when achievement is earned>",
|
||||||
|
"icongray" : "<url to icon when achievement is not earned>"
|
||||||
|
},
|
||||||
|
...)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// Get appid infos: http://store.steampowered.com/api/appdetails/?appids=218620
|
||||||
|
/*
|
||||||
|
"appid" : {
|
||||||
|
"success" : (true|false),
|
||||||
|
(success == true "data" : {
|
||||||
|
...
|
||||||
|
"name" : "<name>",
|
||||||
|
"steam_appid" : <appid>,
|
||||||
|
(OPT "dlc" : [<dlc id>, <dlc id>]),
|
||||||
|
"header_image" : "<miniature url>" <-- Use this in the overlay ?
|
||||||
|
(OPT "achievements" : {
|
||||||
|
"total" : <num of achievements>
|
||||||
|
}),
|
||||||
|
"background" : "<background url>" <-- Use this as the overlay background ?
|
||||||
|
(OPT "packages" : [<package id>, <package id>])
|
||||||
|
})
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifdef max
|
||||||
|
#undef max
|
||||||
|
#endif
|
||||||
|
//232090
|
||||||
|
int main()
|
||||||
|
{
|
||||||
|
CurlGlobal& cglobal = CurlGlobal::Inst();
|
||||||
|
cglobal.init();
|
||||||
|
|
||||||
|
CurlEasy easy;
|
||||||
|
if (easy.init())
|
||||||
|
{
|
||||||
|
std::string url;
|
||||||
|
std::string steam_apikey;
|
||||||
|
std::string app_id;
|
||||||
|
|
||||||
|
std::cout << "Enter the game appid: ";
|
||||||
|
std::cin >> app_id;
|
||||||
|
std::cout << "Enter your webapi key: ";
|
||||||
|
std::cin.clear();
|
||||||
|
std::cin.ignore(std::numeric_limits<std::streamsize>::max(), '\n');
|
||||||
|
std::cin >> steam_apikey;
|
||||||
|
|
||||||
|
url = "http://api.steampowered.com/ISteamUserStats/GetSchemaForGame/v2/?key=";
|
||||||
|
url += steam_apikey;
|
||||||
|
url += "&appid=";
|
||||||
|
url += app_id;
|
||||||
|
easy.set_url(url);
|
||||||
|
easy.perform();
|
||||||
|
try
|
||||||
|
{
|
||||||
|
std::ofstream ach_file("achievements.json", std::ios::trunc | std::ios::out);
|
||||||
|
nlohmann::json json = nlohmann::json::parse(easy.get_answer());
|
||||||
|
nlohmann::json output_json = nlohmann::json::array();
|
||||||
|
|
||||||
|
bool first = true;
|
||||||
|
int i = 0;
|
||||||
|
for (auto& item : json["game"]["availableGameStats"]["achievements"].items())
|
||||||
|
{
|
||||||
|
output_json[i]["name"] = item.value()["name"];
|
||||||
|
output_json[i]["displayName"] = item.value()["displayName"];
|
||||||
|
output_json[i]["hidden"] = item.value()["hidden"];
|
||||||
|
try
|
||||||
|
{
|
||||||
|
output_json[i]["description"] = item.value()["description"];
|
||||||
|
}
|
||||||
|
catch (...)
|
||||||
|
{
|
||||||
|
output_json[i]["description"] = "";
|
||||||
|
}
|
||||||
|
output_json[i]["icon"] = item.value()["icon"];
|
||||||
|
output_json[i]["icongray"] = item.value()["icongray"];
|
||||||
|
output_json[i]["time_earned"] = 0;
|
||||||
|
output_json[i]["earned"] = 0;
|
||||||
|
++i;
|
||||||
|
}
|
||||||
|
ach_file << std::setw(2) << output_json;
|
||||||
|
}
|
||||||
|
catch (std::exception& e)
|
||||||
|
{
|
||||||
|
std::cerr << "Failed to get infos: ";
|
||||||
|
long code;
|
||||||
|
if (easy.get_html_code(code) == CURLE_OK && code == 403)
|
||||||
|
{
|
||||||
|
std::cerr << "Error in webapi key";
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cerr << "Error while parsing json. Try to go at " << url << " and see what you can do to build your achivements.json";
|
||||||
|
}
|
||||||
|
std::cerr << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,157 @@
|
|||||||
|
#define _CRT_SECURE_NO_WARNINGS
|
||||||
|
|
||||||
|
#include <iostream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <string>
|
||||||
|
#include <sstream>
|
||||||
|
#include <vector>
|
||||||
|
#include <iomanip>
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
|
#include <json/json.hpp>
|
||||||
|
#include <steam_gameserver.h>
|
||||||
|
|
||||||
|
struct ClientCBS
|
||||||
|
{
|
||||||
|
STEAM_CALLBACK(ClientCBS, OnSteamInventoryDefinitionUpdate, SteamInventoryDefinitionUpdate_t);
|
||||||
|
STEAM_CALLBACK(ClientCBS, OnSteamInventoryResultReady , SteamInventoryResultReady_t);
|
||||||
|
};
|
||||||
|
|
||||||
|
bool definition_update = false;
|
||||||
|
|
||||||
|
std::vector<std::string> split(const std::string& s, char delimiter)
|
||||||
|
{
|
||||||
|
std::vector<std::string> tokens;
|
||||||
|
std::string token;
|
||||||
|
std::istringstream tokenStream(s);
|
||||||
|
while (std::getline(tokenStream, token, delimiter))
|
||||||
|
{
|
||||||
|
tokens.push_back(token);
|
||||||
|
}
|
||||||
|
return tokens;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientCBS::OnSteamInventoryResultReady(SteamInventoryResultReady_t* param)
|
||||||
|
{
|
||||||
|
switch (param->m_result)
|
||||||
|
{
|
||||||
|
case k_EResultOK: break;
|
||||||
|
case k_EResultPending: break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (param->m_handle)
|
||||||
|
{
|
||||||
|
SteamInventory()->DestroyResult(param->m_handle);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ClientCBS::OnSteamInventoryDefinitionUpdate(SteamInventoryDefinitionUpdate_t* param)
|
||||||
|
{
|
||||||
|
std::ofstream out("items.json", std::ios::out | std::ios::trunc);
|
||||||
|
nlohmann::json json = nlohmann::json::object();
|
||||||
|
SteamItemDef_t* items;
|
||||||
|
uint32 size = 0;
|
||||||
|
SteamInventory()->GetItemDefinitionIDs(nullptr, &size);
|
||||||
|
items = new SteamItemDef_t[size];
|
||||||
|
SteamInventory()->GetItemDefinitionIDs(items, &size);
|
||||||
|
|
||||||
|
definition_update = true;
|
||||||
|
|
||||||
|
std::cerr << "Creating json, please wait..." << std::endl;
|
||||||
|
|
||||||
|
for (int i = 0; i < size; ++i)
|
||||||
|
{
|
||||||
|
uint32 len;
|
||||||
|
len = 0;
|
||||||
|
if (SteamInventory()->GetItemDefinitionProperty(items[i], nullptr, nullptr, &len))
|
||||||
|
{
|
||||||
|
std::string buffer(len, '\0');
|
||||||
|
if (SteamInventory()->GetItemDefinitionProperty(items[i], nullptr, &buffer[0], &len))
|
||||||
|
{
|
||||||
|
buffer.pop_back();
|
||||||
|
std::vector<std::string> strs(std::move(split(buffer, ',')));
|
||||||
|
|
||||||
|
std::string key = std::to_string(items[i]);
|
||||||
|
|
||||||
|
for (auto j = strs.begin(); j != strs.end(); ++j)
|
||||||
|
{
|
||||||
|
len = 0;
|
||||||
|
if (SteamInventory()->GetItemDefinitionProperty(items[i], j->c_str(), nullptr, &len))
|
||||||
|
{
|
||||||
|
std::string buffer(len, '\0');
|
||||||
|
if (SteamInventory()->GetItemDefinitionProperty(items[i], j->c_str(), &buffer[0], &len))
|
||||||
|
{
|
||||||
|
buffer.pop_back();
|
||||||
|
if( *j == "quantity")
|
||||||
|
json[key][*j] = "0";
|
||||||
|
else
|
||||||
|
json[key][*j] = buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out << std::setw(2) << json;
|
||||||
|
|
||||||
|
delete[]items;
|
||||||
|
}
|
||||||
|
|
||||||
|
int main(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
uint32_t appid;
|
||||||
|
|
||||||
|
if (argc == 2)
|
||||||
|
{
|
||||||
|
appid = std::stoi(argv[1]);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::cout << "Enter the game appid: ";
|
||||||
|
std::cin >> appid;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ofstream steam_api("steam_appid.txt", std::ios::out | std::ios::trunc);
|
||||||
|
steam_api << appid;
|
||||||
|
steam_api.close();
|
||||||
|
|
||||||
|
if (SteamAPI_RestartAppIfNecessary(0))
|
||||||
|
{
|
||||||
|
std::cerr << "This app needs restart" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!SteamAPI_Init())
|
||||||
|
{
|
||||||
|
std::cerr << "SteamAPI_Init() failed" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto SUser = SteamUser();
|
||||||
|
|
||||||
|
if (!SUser->BLoggedOn())
|
||||||
|
{
|
||||||
|
std::cerr << "Steam user is not logged in" << std::endl;
|
||||||
|
return EXIT_FAILURE;
|
||||||
|
}
|
||||||
|
|
||||||
|
ClientCBS cbs;
|
||||||
|
|
||||||
|
int max_retry = 10;
|
||||||
|
while (!definition_update && max_retry-- > 0)
|
||||||
|
{
|
||||||
|
std::cerr << "Running LoadItemDefinitions" << std::endl;
|
||||||
|
bool ret = SteamInventory()->LoadItemDefinitions();
|
||||||
|
int retry = 0;
|
||||||
|
while (retry++ <= 100 && !definition_update)
|
||||||
|
{
|
||||||
|
SteamAPI_RunCallbacks();
|
||||||
|
std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SteamAPI_Shutdown();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
Loading…
Reference in New Issue