From 3b9366e71bea04fd354fe9ff80cc81541d7988de Mon Sep 17 00:00:00 2001 From: Mr_Goldberg Date: Sat, 15 Feb 2020 17:20:29 -0500 Subject: [PATCH] generate_game_infos improvements. now generates a DLC.txt and a steam_appid.txt and puts everything in a folder. appid and api key can be provided as arguments instead. --- generate_game_infos/generate_game_infos.cpp | 165 +++++- json/fifo_map.hpp | 547 ++++++++++++++++++++ 2 files changed, 693 insertions(+), 19 deletions(-) create mode 100644 json/fifo_map.hpp diff --git a/generate_game_infos/generate_game_infos.cpp b/generate_game_infos/generate_game_infos.cpp index 430bdd0..1501a46 100644 --- a/generate_game_infos/generate_game_infos.cpp +++ b/generate_game_infos/generate_game_infos.cpp @@ -8,6 +8,7 @@ #include #include +#include class CurlGlobal { @@ -230,6 +231,7 @@ public: std::string steam_apikey; std::string app_id; +std::string output_path; #if defined(WIN32) || defined(_WIN32) #include @@ -274,7 +276,7 @@ static void generate_achievements(CurlEasy &easy) easy.perform(); try { - std::ofstream ach_file("achievements.json", std::ios::trunc | std::ios::out); + std::ofstream ach_file(output_path + "/achievements.json", std::ios::trunc | std::ios::out); nlohmann::json json = nlohmann::json::parse(easy.get_answer()); nlohmann::json output_json = nlohmann::json::array(); @@ -299,7 +301,7 @@ static void generate_achievements(CurlEasy &easy) { std::string icon_path = "images/" + item.value()["name"].get() + ".jpg"; - std::ofstream achievement_icon(icon_path, std::ios::out | std::ios::trunc | std::ios::binary); + std::ofstream achievement_icon(output_path + "/" + icon_path, std::ios::out | std::ios::trunc | std::ios::binary); if (!achievement_icon) { std::cerr << "Cannot create achievement icon \"" << icon_path << "\"" << std::endl; @@ -316,7 +318,7 @@ static void generate_achievements(CurlEasy &easy) } { std::string icon_path = "images/" + item.value()["name"].get() + "_gray.jpg"; - std::ofstream achievement_icon(icon_path, std::ios::out | std::ios::trunc | std::ios::binary); + std::ofstream achievement_icon(output_path + "/" + icon_path, std::ios::out | std::ios::trunc | std::ios::binary); if (!achievement_icon) { std::cerr << "Cannot create achievement icon \"" << icon_path << "\"" << std::endl; @@ -350,6 +352,11 @@ static void generate_achievements(CurlEasy &easy) } } +template +using my_workaround_fifo_map = nlohmann::fifo_map, A>; +using fifo_json = nlohmann::basic_json; + + static void generate_items(CurlEasy& easy) { std::string url = "https://api.steampowered.com/IInventoryService/GetItemDefMeta/v1?key="; @@ -373,12 +380,12 @@ static void generate_items(CurlEasy& easy) easy.set_url(url); easy.perform(); - nlohmann::json item_json = nlohmann::json::object(); - nlohmann::json default_item_json = nlohmann::json::object(); + fifo_json item_json; + fifo_json default_item_json; json = nlohmann::json::parse(easy.get_answer()); - std::ofstream items_file("items.json", std::ios::trunc | std::ios::out); - std::ofstream default_items_file("default_items.json", std::ios::trunc | std::ios::out); + std::ofstream items_file(output_path + "/items.json", std::ios::trunc | std::ios::out); + std::ofstream default_items_file(output_path + "/default_items.json", std::ios::trunc | std::ios::out); for (auto &i : json) { @@ -434,14 +441,99 @@ static void generate_items(CurlEasy& easy) } } -int main() +static std::string get_appid_name(CurlEasy& easy, uint32_t appid) { - if (!create_directory("images")) - { - std::cerr << "Cannot create directory \"images\"" << std::endl; - return -1; + static std::map appid_names; + static bool done; + + if (!done) { + std::string url = "https://api.steampowered.com/ISteamApps/GetAppList/v2/"; + std::cout << "getting app list" << std::endl; + easy.set_url(url); + easy.perform(); + try + { + nlohmann::json json = nlohmann::json::parse(easy.get_answer()); + for (auto &app : json["applist"]["apps"]) { + appid_names[app["appid"].get()] = app["name"].get(); + } + + done = true; + } + 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 403 while getting app list"; + } + else + { + std::cerr << "Error while parsing json. With " << url << ""; + } + std::cerr << std::endl; + } } + if (done) { + if (!appid_names.count(appid)) { + std::cout << "getting app name: " << appid << std::endl; + std::string s_appid = std::to_string(appid); + std::string url = "https://store.steampowered.com/api/appdetails/?appids=" + s_appid; + easy.set_url(url); + easy.perform(); + nlohmann::json json = nlohmann::json::parse(easy.get_answer()); + appid_names[appid] = json[s_appid]["data"]["name"].get(); + } + + return appid_names[appid]; + } + + return ""; +} + +static void generate_dlcs(CurlEasy& easy) +{ + std::string base_url = "https://store.steampowered.com/api/appdetails/?appids="; + std::string url = base_url + app_id; + easy.set_url(url); + easy.perform(); + + try + { + nlohmann::json json = nlohmann::json::parse(easy.get_answer()); + std::list dlcs; + std::map dlc_names; + + for (auto& dlc : json[app_id]["data"]["dlc"]) + { + dlcs.push_back(dlc.get()); + } + + std::ofstream dlc_file(output_path + "/DLC.txt", std::ios::trunc | std::ios::out); + for (auto &dlc: dlcs) { + dlc_file << dlc << "=" << get_appid_name(easy, dlc) << std::endl; + } + } + 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 403 while getting dlcs"; + } + else + { + std::cerr << "Error while parsing json. With " << url << ""; + } + std::cerr << std::endl; + } +} + +int main(int argc, char **argv) +{ CurlGlobal& cglobal = CurlGlobal::Inst(); cglobal.init(); @@ -449,15 +541,50 @@ int main() if (easy.init()) { easy.skip_verifypeer(); - 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::max(), '\n'); - std::cin >> steam_apikey; + if (argc > 2) { + app_id = argv[2]; + steam_apikey = argv[1]; + } else { + std::cout << "Usage: " << argv[0] << " steam_api_key app_id " << std::endl; + 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::max(), '\n'); + std::cin >> steam_apikey; + } + + if (argc > 3) { + output_path = argv[3]; + } else { + output_path = app_id; + create_directory(output_path); + output_path += "/steam_settings"; + } + + if (!create_directory(output_path)) + { + std::cerr << "Cannot create directory: " << output_path << std::endl; + return -1; + } + + if (!create_directory(output_path + "/images")) + { + std::cerr << "Cannot create directory \"images\"" << std::endl; + return -1; + } + + { + std::ofstream appid_file(output_path + "/steam_appid.txt", std::ios::trunc | std::ios::out); + appid_file << app_id; + } + + std::cout << "Generating DLC.txt" << std::endl; + generate_dlcs(easy); + std::cout << "Generating achievements" << std::endl; generate_achievements(easy); + std::cout << "Generating items" << std::endl; generate_items(easy); } } - \ No newline at end of file diff --git a/json/fifo_map.hpp b/json/fifo_map.hpp new file mode 100644 index 0000000..7d28c74 --- /dev/null +++ b/json/fifo_map.hpp @@ -0,0 +1,547 @@ +/* +The code is licensed under the MIT License : + +Copyright (c) 2015-2017 Niels Lohmann. + +Permission is hereby granted, free of charge, to any person obtaining a copy of +this software and associated documentation files (the "Software"), to deal in +the Software without restriction, including without limitation the rights to +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is furnished to do +so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. +*/ + +#ifndef NLOHMANN_FIFO_MAP_HPP +#define NLOHMANN_FIFO_MAP_HPP + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/*! +@brief namespace for Niels Lohmann +@see https://github.com/nlohmann +*/ +namespace nlohmann +{ + +template +class fifo_map_compare +{ + public: + /// constructor given a pointer to a key storage + fifo_map_compare( + std::unordered_map* keys, + std::size_t timestamp = 1) + : + m_timestamp(timestamp), + m_keys(keys) + {} + + /*! + This function compares two keys with respect to the order in which they + were added to the container. For this, the mapping keys is used. + */ + bool operator()(const Key& lhs, const Key& rhs) const + { + // look up timestamps for both keys + const auto timestamp_lhs = m_keys->find(lhs); + const auto timestamp_rhs = m_keys->find(rhs); + + if (timestamp_lhs == m_keys->end()) + { + // timestamp for lhs not found - cannot be smaller than for rhs + return false; + } + + if (timestamp_rhs == m_keys->end()) + { + // timestamp for rhs not found - timestamp for lhs is smaller + return true; + } + + // compare timestamps + return timestamp_lhs->second < timestamp_rhs->second; + } + + void add_key(const Key& key) + { + m_keys->insert({key, m_timestamp++}); + } + + void remove_key(const Key& key) + { + m_keys->erase(key); + } + + private: + /// helper to access m_timestamp from fifo_map copy ctor, + /// must have same number of template args as fifo_map + template < + class MapKey, + class MapT, + class MapCompare, + class MapAllocator + > friend class fifo_map; + + private: + /// the next valid insertion timestamp + std::size_t m_timestamp = 1; + + /// pointer to a mapping from keys to insertion timestamps + std::unordered_map* m_keys = nullptr; +}; + + +template < + class Key, + class T, + class Compare = fifo_map_compare, + class Allocator = std::allocator> + > class fifo_map +{ + public: + using key_type = Key; + using mapped_type = T; + using value_type = std::pair; + using size_type = std::size_t; + using difference_type = std::ptrdiff_t; + using key_compare = Compare; + using allocator_type = Allocator; + using reference = value_type&; + using const_reference = const value_type&; + using pointer = typename std::allocator_traits::pointer; + using const_pointer = typename std::allocator_traits::const_pointer; + + using internal_map_type = std::map; + + using iterator = typename internal_map_type::iterator; + using const_iterator = typename internal_map_type::const_iterator; + using reverse_iterator = typename internal_map_type::reverse_iterator; + using const_reverse_iterator = typename internal_map_type::const_reverse_iterator; + + public: + /// default constructor + fifo_map() : m_keys(), m_compare(&m_keys), m_map(m_compare) {} + + /// copy constructor + fifo_map(const fifo_map &f) : m_keys(f.m_keys), m_compare(&m_keys, f.m_compare.m_timestamp), m_map(f.m_map.begin(), f.m_map.end(), m_compare) {} + + /// constructor for a range of elements + template + fifo_map(InputIterator first, InputIterator last) + : m_keys(), m_compare(&m_keys), m_map(m_compare) + { + for (auto it = first; it != last; ++it) + { + insert(*it); + } + } + + /// constructor for a list of elements + fifo_map(std::initializer_list init) : fifo_map() + { + for (auto x : init) + { + insert(x); + } + } + + + /* + * Element access + */ + + /// access specified element with bounds checking + T& at(const Key& key) + { + return m_map.at(key); + } + + /// access specified element with bounds checking + const T& at(const Key& key) const + { + return m_map.at(key); + } + + /// access specified element + T& operator[](const Key& key) + { + m_compare.add_key(key); + return m_map[key]; + } + + /// access specified element + T& operator[](Key&& key) + { + m_compare.add_key(key); + return m_map[key]; + } + + + /* + * Iterators + */ + + /// returns an iterator to the beginning + iterator begin() noexcept + { + return m_map.begin(); + } + + /// returns an iterator to the end + iterator end() noexcept + { + return m_map.end(); + } + + /// returns an iterator to the beginning + const_iterator begin() const noexcept + { + return m_map.begin(); + } + + /// returns an iterator to the end + const_iterator end() const noexcept + { + return m_map.end(); + } + + /// returns an iterator to the beginning + const_iterator cbegin() const noexcept + { + return m_map.cbegin(); + } + + /// returns an iterator to the end + const_iterator cend() const noexcept + { + return m_map.cend(); + } + + /// returns a reverse iterator to the beginning + reverse_iterator rbegin() noexcept + { + return m_map.rbegin(); + } + + /// returns a reverse iterator to the end + reverse_iterator rend() noexcept + { + return m_map.rend(); + } + + /// returns a reverse iterator to the beginning + const_reverse_iterator rbegin() const noexcept + { + return m_map.rbegin(); + } + + /// returns a reverse iterator to the end + const_reverse_iterator rend() const noexcept + { + return m_map.rend(); + } + + /// returns a reverse iterator to the beginning + const_reverse_iterator crbegin() const noexcept + { + return m_map.crbegin(); + } + + /// returns a reverse iterator to the end + const_reverse_iterator crend() const noexcept + { + return m_map.crend(); + } + + + /* + * Capacity + */ + + /// checks whether the container is empty + bool empty() const noexcept + { + return m_map.empty(); + } + + /// returns the number of elements + size_type size() const noexcept + { + return m_map.size(); + } + + /// returns the maximum possible number of elements + size_type max_size() const noexcept + { + return m_map.max_size(); + } + + + /* + * Modifiers + */ + + /// clears the contents + void clear() noexcept + { + m_map.clear(); + m_keys.clear(); + } + + /// insert value + std::pair insert(const value_type& value) + { + m_compare.add_key(value.first); + return m_map.insert(value); + } + + /// insert value + template + std::pair insert( P&& value ) + { + m_compare.add_key(value.first); + return m_map.insert(value); + } + + /// insert value with hint + iterator insert(const_iterator hint, const value_type& value) + { + m_compare.add_key(value.first); + return m_map.insert(hint, value); + } + + /// insert value with hint + iterator insert(const_iterator hint, value_type&& value) + { + m_compare.add_key(value.first); + return m_map.insert(hint, value); + } + + /// insert value range + template + void insert(InputIt first, InputIt last) + { + for (const_iterator it = first; it != last; ++it) + { + m_compare.add_key(it->first); + } + + m_map.insert(first, last); + } + + /// insert value list + void insert(std::initializer_list ilist) + { + for (auto value : ilist) + { + m_compare.add_key(value.first); + } + + m_map.insert(ilist); + } + + /// constructs element in-place + template + std::pair emplace(Args&& ... args) + { + typename fifo_map::value_type value(std::forward(args)...); + m_compare.add_key(value.first); + return m_map.emplace(std::move(value)); + } + + /// constructs element in-place with hint + template + iterator emplace_hint(const_iterator hint, Args&& ... args) + { + typename fifo_map::value_type value(std::forward(args)...); + m_compare.add_key(value.first); + return m_map.emplace_hint(hint, std::move(value)); + } + + /// remove element at position + iterator erase(const_iterator pos) + { + m_compare.remove_key(pos->first); + return m_map.erase(pos); + } + + /// remove elements in range + iterator erase(const_iterator first, const_iterator last) + { + for (const_iterator it = first; it != last; ++it) + { + m_compare.remove_key(it->first); + } + + return m_map.erase(first, last); + } + + /// remove elements with key + size_type erase(const key_type& key) + { + size_type res = m_map.erase(key); + + if (res > 0) + { + m_compare.remove_key(key); + } + + return res; + } + + /// swaps the contents + void swap(fifo_map& other) + { + std::swap(m_map, other.m_map); + std::swap(m_compare, other.m_compare); + std::swap(m_keys, other.m_keys); + } + + + /* + * Lookup + */ + + /// returns the number of elements matching specific key + size_type count(const Key& key) const + { + return m_map.count(key); + } + + /// finds element with specific key + iterator find(const Key& key) + { + return m_map.find(key); + } + + /// finds element with specific key + const_iterator find(const Key& key) const + { + return m_map.find(key); + } + + /// returns range of elements matching a specific key + std::pair equal_range(const Key& key) + { + return m_map.equal_range(key); + } + + /// returns range of elements matching a specific key + std::pair equal_range(const Key& key) const + { + return m_map.equal_range(key); + } + + /// returns an iterator to the first element not less than the given key + iterator lower_bound(const Key& key) + { + return m_map.lower_bound(key); + } + + /// returns an iterator to the first element not less than the given key + const_iterator lower_bound(const Key& key) const + { + return m_map.lower_bound(key); + } + + /// returns an iterator to the first element greater than the given key + iterator upper_bound(const Key& key) + { + return m_map.upper_bound(key); + } + + /// returns an iterator to the first element greater than the given key + const_iterator upper_bound(const Key& key) const + { + return m_map.upper_bound(key); + } + + + /* + * Observers + */ + + /// returns the function that compares keys + key_compare key_comp() const + { + return m_compare; + } + + + /* + * Non-member functions + */ + + friend bool operator==(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map == rhs.m_map; + } + + friend bool operator!=(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map != rhs.m_map; + } + + friend bool operator<(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map < rhs.m_map; + } + + friend bool operator<=(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map <= rhs.m_map; + } + + friend bool operator>(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map > rhs.m_map; + } + + friend bool operator>=(const fifo_map& lhs, const fifo_map& rhs) + { + return lhs.m_map >= rhs.m_map; + } + + private: + /// the keys + std::unordered_map m_keys; + /// the comparison object + Compare m_compare; + /// the internal data structure + internal_map_type m_map; +}; + +} + +// specialization of std::swap +namespace std +{ +template +inline void swap(nlohmann::fifo_map& m1, + nlohmann::fifo_map& m2) +{ + m1.swap(m2); +} +} + +#endif