diff --git a/dll/item_db_loader.cpp b/dll/item_db_loader.cpp new file mode 100644 index 0000000..d3928b5 --- /dev/null +++ b/dll/item_db_loader.cpp @@ -0,0 +1,44 @@ +#include "item_db_loader.h" + +#include +#include "json.h" + +std::map> read_items_db(std::string const& items_db) +{ + std::map> items; + + std::ifstream items_file(items_db); + items_file.seekg(0, std::ios::end); + size_t size = items_file.tellg(); + std::string buffer(size, '\0'); + items_file.seekg(0); + items_file.read(&buffer[0], size); + items_file.close(); + + try + { + nemir::json_value val = nemir::parse_json(buffer); + if (val.type() == nemir::json_type::object) + { + for (auto& i : static_cast(val)) + { + SteamItemDef_t key = std::stoi(i.first); + if (i.second.type() == nemir::json_type::object) + { + for (auto& j : static_cast(i.second)) + { + items[key][j.first] = j.second; + } + } + } + } + } + catch (std::exception& e) + { + // Error while parsing json items db + PRINT_DEBUG(e.what()); + items.clear(); + } + + return items; +} \ No newline at end of file diff --git a/dll/item_db_loader.h b/dll/item_db_loader.h new file mode 100644 index 0000000..87105a3 --- /dev/null +++ b/dll/item_db_loader.h @@ -0,0 +1,8 @@ +#ifndef __ITEM_DB_LOADER_INCLUDED__ +#define __ITEM_DB_LOADER_INCLUDED__ + +#include "base.h" + +std::map> read_items_db(std::string const& items_db); + +#endif//__ITEM_DB_LOADER_INCLUDED__ \ No newline at end of file diff --git a/dll/json.h b/dll/json.h new file mode 100644 index 0000000..8a71d4e --- /dev/null +++ b/dll/json.h @@ -0,0 +1,29 @@ +/* Copyright (C) 2019 Nemirtingas + This file is part of the Goldberg Emulator + + Those utils are 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. + + Those utils are 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 + . +*/ + +#ifndef __JSON_INCLUDED__ +#define __JSON_INCLUDED__ + +#include "json_value.h" + +namespace nemir +{ + json_value parse_json(std::string const& buffer); +} + +#endif//__JSON_INCLUDED__ \ No newline at end of file diff --git a/dll/json_parser.cpp b/dll/json_parser.cpp new file mode 100644 index 0000000..28fa532 --- /dev/null +++ b/dll/json_parser.cpp @@ -0,0 +1,407 @@ +/* Copyright (C) 2019 Nemirtingas + This file is part of the Goldberg Emulator + + Those utils are 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. + + Those utils are 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 + . +*/ + +#include "json_value.h" + +#include +#include + +// This parser can easely be translated to pure C (if you really have to) + +#define OBJECT_START '{' +#define OBJECT_END '}' +#define ARRAY_START '[' +#define ARRAY_END ']' +#define VALUE_END ',' +#define STRING_START '"' +#define STRING_END '"' +#define NUMBER_COMMA '.' +#define KEY_VALUE_SEP ':' +#define TRUE_START 't' +#define FALSE_START 'f' +#define NULL_START 'n' +#define ESCAPE_CHR '\\' +#define NEGATIVE_CHAR '-' + +#define OBJECT_START_STR "{" +#define OBJECT_END_STR "}" +#define ARRAY_START_STR "[" +#define ARRAY_END_STR "]" +#define VALUE_END_STR "," +#define STRING_START_STR "\"" +#define STRING_END_STR "\"" +#define NUMBER_COMMA_STR "." +#define KEY_VALUE_SEP_STR ":" +#define ESCAPE_CHR_STR "\\" + +using str_it = std::string::const_iterator; + +namespace nemir +{ + + // s = buffer start, c = buffer current, e = buffer end + nemir::json_value parse_value(str_it& s, str_it& c, str_it& e); + + class parse_exception : public std::exception + { + std::string _w_str; + public: + parse_exception(std::string const& w) :_w_str(w) {} + virtual const char* what() const noexcept { return _w_str.c_str(); } + }; + + void throw_parse_exception(std::string const& w, str_it& s, str_it& c, str_it& e) + { + std::string what; + str_it begin, end; + if (c - s < 10) // check if we can get 10 chars before current position + begin = s; // debug string is buffer start, not current pos - 10 + else + begin = c - 10; + + if (e - c < 10) // check if we can get 10 chars after current position + end = e; // debug string is buffer end, not current pos + 10; + else + end = c + 10; + + std::string str_part(begin, end); + + std::replace_if(str_part.begin(), str_part.end(), iscntrl, ' '); + + throw parse_exception(w + " at pos " + std::to_string(c - s) + " " + str_part); + } + + // Is the current char an end of value char + // like a space, an end of array, an end of object or an end of object field + inline bool is_end_of_value(int32_t c) noexcept + { + if (isspace(c) || c == ARRAY_END || c == OBJECT_END || c == VALUE_END) + return true; + + return false; + } + + // A template func is better than passing a function pointer + // No pointer dereference to call the function + template + void buffer_seek(str_it& c, str_it& e, int32_t chr) noexcept + { + // if our current char != desired char + // and we are not at the end of the buffer + while (*c != chr && c != e) + { + // If its not a skippable char, exit + if (!func(*c)) + break; + // Go to the next char + ++c; + } + } + + // Skip all whitespaces + inline void ignore_spaces(str_it& c, str_it& e) noexcept + { + while (isspace(*c) && ++c != e); + } + +#define FIND_START(type, start) \ +template\ +inline void find_##type ## _start(str_it &s, str_it &c, str_it &e)\ +{\ + buffer_seek(c, e, start);\ + if( *c != start )\ + throw_parse_exception("Can't find " #type " start '" start ## _STR "'", s, c, e);\ + ++c;\ +} + +#define FIND_END(type, end) \ +template\ +inline void find_##type ## _stop(str_it &s, str_it &c, str_it &e)\ +{\ + buffer_seek(c, e, end);\ + if( *c != end )\ + throw_parse_exception("Can't find " #type " end '" end ## _STR "'", s, c, e);\ +} + + FIND_START(object, OBJECT_START) + FIND_START(array, ARRAY_START) + FIND_START(string, STRING_START) + FIND_START(key_value_sep, KEY_VALUE_SEP) + + FIND_END(object, OBJECT_END) + //FIND_END(array, ARRAY_END) + //FIND_END(string, STRING_END) + + std::string parse_string(str_it& s, str_it& c, str_it& e) + { + std::string res; + + find_string_start(s, c, e); + + bool is_escape = false; + while (c != e) + { + if (*c == ESCAPE_CHR && !is_escape) + is_escape = true; + else + { + if (is_escape) + { + switch (*c) + { + case '\\': res += '\\'; break; + case '"': res += '\"'; break; + case 't': res += '\t'; break; + case 'r': res += '\r'; break; + case 'n': res += '\n'; break; + case 'f': res += '\f'; break; + case 'b': res += '\b'; break; + default: throw_parse_exception(std::string("Can't translate escape char \\") + *c, s, c, e); + } + } + else if (*c == STRING_END) + { + ++c; + break; + } + else + res += *c; + is_escape = false; + } + ++c; + } + if (c == e) + throw_parse_exception("End of buffer encoutered while parsing string", s, c, e); + + //find_string_stop(s, c, e); + + return res; + } + + bool parse_boolean(str_it& s, str_it& c, str_it& e) + { + if (tolower(*c) == TRUE_START) + { + constexpr const char v[] = "true"; + bool ok = true; + for (auto i = std::begin(v); i != (std::end(v) - 1); ++i, ++c) + { + if (c == e) + throw_parse_exception("End of buffer encoutered while parsing boolean", s, c, e); + if (tolower(*c) != *i) + { + ok = false; + break; + } + } + if (!ok || !is_end_of_value(*c)) + throw_parse_exception("Error while parsing boolean 'true' value", s, c, e); + + return true; + } + else if (tolower(*c) == FALSE_START) + { + constexpr const char v[] = "false"; + bool ok = true; + for (auto i = std::begin(v); i != (std::end(v) - 1); ++i, ++c) + { + if (c == e) + throw_parse_exception("End of buffer encoutered while parsing boolean", s, c, e); + if (tolower(*c) != *i) + { + ok = false; + break; + } + } + if (!ok || !is_end_of_value(*c)) + throw_parse_exception("Error while parsing boolean 'false' value", s, c, e); + + return true; + } + else + { + throw_parse_exception("Error while parsing boolean value", s, c, e); + } + // This is never reached but gcc complains it reaches end of non-void function + return false; + } + + std::nullptr_t parse_null(str_it& s, str_it& c, str_it& e) + { + if (tolower(*c) != NULL_START) + throw_parse_exception("Error while parsing null value", s, c, e); + + constexpr const char v[] = "null"; + bool ok = true; + for (auto i = std::begin(v); i != (std::end(v) - 1); ++i, ++c) + { + if (c == e) + throw_parse_exception("End of buffer encoutered while parsing null", s, c, e); + if (tolower(*c) != *i) + { + ok = false; + break; + } + } + if (!ok || !is_end_of_value(*c)) + throw_parse_exception("Error while parsing null value", s, c, e); + + return nullptr; + } + + nemir::json_value::json_array parse_array(str_it& s, str_it& c, str_it& e) + { + nemir::json_value::json_array res; + + find_array_start(s, c, e); + + while (c != e) + { + ignore_spaces(c, e); + if (*c != ARRAY_END) + { + res.emplace_back(std::move(parse_value(s, c, e))); + ignore_spaces(c, e); // Ignore whitespace + } + // End of array + if (*c == ARRAY_END) + { + ++c; + break; + } + // End of array entry, restart to find another entry + if (*c == VALUE_END) + ++c; + else + throw_parse_exception("No end of value found while parsing array", s, c, e); + } + + return res; + } + + nemir::json_value::json_object parse_object(str_it& s, str_it& c, str_it& e) + { + nemir::json_value::json_object res; + + find_object_start(s, c, e); + + while (c != e) + { + ignore_spaces(c, e); + + if (*c != OBJECT_END) + { + // Must start with a string (the field key) + std::string key = parse_string(s, c, e); + find_key_value_sep_start(s, c, e); + ignore_spaces(c, e); + res.nodes()[key] = std::move(parse_value(s, c, e)); + ignore_spaces(c, e); // Ignore whitespace + } + + // End of object + if (*c == OBJECT_END) + { + ++c; + break; + } + // End of object entry, restart to find another entry + else if (*c == VALUE_END) + ++c; + // this node is over but we didn't find its end. + else + throw_parse_exception("Error while parsing json_object object/node end '" OBJECT_END_STR "/" VALUE_END_STR "' not found", s, c, e); + } + + return res; + } + + nemir::json_value parse_value(str_it& s, str_it& c, str_it& e) + { + if (isdigit(*c) || *c == NEGATIVE_CHAR) + { + // Number start position + str_it start = c; + if (*c == NEGATIVE_CHAR) + ++c; + bool number = false; + while (c != e) + { + // If its a digit, continue to parse number + if (isdigit(*c)) + ++c; + // If its a Number comma + else if (*c == NUMBER_COMMA) + { + // Check if we already encoutered a Number comma + if (number) + throw_parse_exception("Encoutered multiple commas while parsing value", s, c, e); + // Continue to parse number + number = true; + ++c; + } + else if (is_end_of_value(*c)) + { + if (number) + return nemir::json_value_number(stod(std::string(start, c))); + else + return nemir::json_value_integer(stoi(std::string(start, c))); + } + else + throw_parse_exception("End of number value not found", s, c, e); + } + throw_parse_exception("End of buffer encountered while parsing number value", s, c, e); + } + + switch (tolower(*c)) + { + // Check if value is a string + case STRING_START: return nemir::json_value_string(parse_string(s, c, e)); + // Check if value is true or false + case TRUE_START: case FALSE_START: return nemir::json_value_boolean(parse_boolean(s, c, e)); + // Check if value is null + case NULL_START: return nemir::json_value_null(parse_null(s, c, e)); + // Check if value is an array + case ARRAY_START: return std::move(nemir::json_value_array(parse_array(s, c, e))); + // Check if value is an object + case OBJECT_START: return nemir::json_value_object(parse_object(s, c, e)); + default: throw_parse_exception("Invalid value", s, c, e); + } + + return nemir::json_value(); // Will never reach, just to make compiler happy + } + + nemir::json_value parse_json(std::string const& buffer) + { + str_it s = buffer.begin(); // buffer start + str_it c = buffer.begin(); // buffer current + str_it e = buffer.end(); // buffer end + + ignore_spaces(c, e); + + if (*c == OBJECT_START) + return nemir::json_value_object(parse_object(s, c, e)); + + if (*c == ARRAY_START) + return nemir::json_value_array(parse_array(s, c, e)); + + throw_parse_exception("Error while parsing start of Json, must start with an object (" OBJECT_START_STR ") or array (" ARRAY_START_STR ")", s, c, e); + return nemir::json_value(); // Will never reach, just to make compiler happy + } + +} \ No newline at end of file diff --git a/dll/json_value.h b/dll/json_value.h new file mode 100644 index 0000000..43a7abe --- /dev/null +++ b/dll/json_value.h @@ -0,0 +1,381 @@ +/* Copyright (C) 2019 Nemirtingas + This file is part of the Goldberg Emulator + + Those utils are 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. + + Those utils are 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 + . +*/ + +#ifndef __JSON_VALUE_INCLUDED__ +#define __JSON_VALUE_INCLUDED_ + +#include +#include +#include +#include +#include + +#if 0 // Debug or not +#include +#define NEMIR_JSON_INLINE +#else +#define NEMIR_JSON_DISABLE_LOG +#define NEMIR_JSON_INLINE inline +#endif + +namespace nemir +{ + class json_object; + class json_array; + + class json_value_exception : public std::exception + { + std::string _w_str; + public: + json_value_exception(std::string const& w) :_w_str(w) {} + virtual const char* what() const noexcept { return _w_str.c_str(); } + }; + + enum class json_type + { + string, // std::string + integer,// int64_t + number, // double + array, // std::vector + object, // json_node + boolean,// bool + null // std::nullptr_t + }; + + constexpr const char* json_type_to_string(json_type t) + { + const char* strs[] = { + "string", + "integer", + "number", + "array", + "object", + "boolean", + "null" + }; + return strs[static_cast(t)]; + } + + class json_value_container + { + public: + virtual json_type type() const = 0; + virtual void* get(json_type) = 0; + virtual json_value_container* clone() = 0; + }; + + class json_value + { + std::shared_ptr container; + + protected: + NEMIR_JSON_INLINE void* get(json_type t) const + { + return container->get(t); + } + + public: + class json_object; + class json_array; + + template + struct json_value_type + { + private: + json_value_type(); + ~json_value_type(); + }; + + template<>struct json_value_type + { + constexpr static json_type type = json_type::string; + }; + template<>struct json_value_type + { + constexpr static json_type type = json_type::integer; + }; + template<>struct json_value_type + { + constexpr static json_type type = json_type::number; + }; + template<>struct json_value_type + { + constexpr static json_type type = json_type::array; + }; + template<>struct json_value_type + { + constexpr static json_type type = json_type::object; + }; + template<>struct json_value_type + { + constexpr static json_type type = json_type::boolean; + }; + template<>struct json_value_type + { + constexpr static json_type type = json_type::null; + }; + + template + class t_json_value : + public json_value_container + { + T val; + public: + using mytype = t_json_value; + +#ifndef NEMIR_JSON_DISABLE_LOG + virtual ~t_json_value() { std::cout << "~t_json_value()" << std::endl; } + NEMIR_JSON_INLINE t_json_value():val() { std::cout << " t_json_value()" << std::endl; } + NEMIR_JSON_INLINE t_json_value(T const& v):val(v) { std::cout << " t_json_value(T const&)" << std::endl; } + NEMIR_JSON_INLINE t_json_value(T&& v)noexcept:val( std::move(v)) { std::cout << " t_json_value(T&&)" << std::endl; } + NEMIR_JSON_INLINE t_json_value(mytype const& v):val(v.val) { std::cout << " t_json_value( mytype const& )" << std::endl; } + NEMIR_JSON_INLINE t_json_value(mytype&& v)noexcept:val(std::move(v.val)){ std::cout << " t_json_value( mytype&& )" << std::endl; } + virtual json_value_container* clone() + { + std::cout << "clone()" << std::endl; + return new mytype(*this); + } +#else + virtual ~t_json_value(){} + NEMIR_JSON_INLINE t_json_value() :val(){} + NEMIR_JSON_INLINE t_json_value(T const& v) :val(v){} + NEMIR_JSON_INLINE t_json_value(T&& v)noexcept :val(std::move(v)){} + NEMIR_JSON_INLINE t_json_value(mytype const& v) :val(v.val){} + NEMIR_JSON_INLINE t_json_value(mytype&& v)noexcept :val(std::move(v.val)){} + virtual json_value_container* clone() { return new mytype(*this); } +#endif + virtual json_type type() const { return json_value_type::type; } + virtual void* get(json_type t) + { + if (t != type()) + throw json_value_exception(std::string("Cannot convert json_type ") + json_type_to_string(type()) + " to " + json_type_to_string(t)); + return &val; + } + }; + + class json_object + { + std::map _nodes; + + public: + using iterator = std::map::iterator; +#ifndef NEMIR_JSON_DISABLE_LOG + NEMIR_JSON_INLINE ~json_object() { std::cout << "~json_object()" << std::endl; } + NEMIR_JSON_INLINE json_object() { std::cout << " json_object()" << std::endl; } + NEMIR_JSON_INLINE json_object(json_object const& c) :_nodes(c._nodes) { std::cout << " json_object(json_object const&)" << std::endl; } + NEMIR_JSON_INLINE json_object(json_object&& c) noexcept :_nodes(std::move(c._nodes)) { std::cout << " json_object(json_object &&)" << std::endl; } +#else + NEMIR_JSON_INLINE ~json_object() {} + NEMIR_JSON_INLINE json_object() {} + NEMIR_JSON_INLINE json_object(json_object const& c) : _nodes(c._nodes) {} + NEMIR_JSON_INLINE json_object(json_object&& c) noexcept :_nodes(std::move(c._nodes)) {} +#endif + + NEMIR_JSON_INLINE json_object& operator=(json_object const& c) + { + _nodes = c._nodes; + return *this; + } + + NEMIR_JSON_INLINE json_object& operator=(json_object&& c) noexcept + { + _nodes = std::move(c._nodes); + return *this; + } + + NEMIR_JSON_INLINE std::map& nodes() { return _nodes; } + NEMIR_JSON_INLINE iterator begin() { return _nodes.begin(); } + NEMIR_JSON_INLINE iterator end() { return _nodes.end(); } + NEMIR_JSON_INLINE iterator find(std::string const& key) { return _nodes.find(key); } + NEMIR_JSON_INLINE iterator find(const char* key) { return find(std::string(key)); } + NEMIR_JSON_INLINE iterator erase(iterator at) { return _nodes.erase(at); } + NEMIR_JSON_INLINE iterator erase(iterator first, iterator last) { return _nodes.erase(first, last); } + NEMIR_JSON_INLINE size_t erase(std::string const& key) { return _nodes.erase(key); } + + NEMIR_JSON_INLINE json_value& operator[](std::string const& key) + { + return _nodes[key]; + } + }; + + class json_array + { + std::vector _nodes; + + public: + using iterator = std::vector::iterator; +#ifndef NEMIR_JSON_DISABLE_LOG + NEMIR_JSON_INLINE ~json_array() { std::cout << "~json_array()" << std::endl; } + NEMIR_JSON_INLINE json_array() { std::cout << " json_array()" << std::endl; } + NEMIR_JSON_INLINE json_array(json_array const& c) :_nodes(c._nodes) { std::cout << " json_array(json_array const&)" << std::endl; } + NEMIR_JSON_INLINE json_array(json_array&& c) noexcept :_nodes(std::move(c._nodes)) { std::cout << " json_array(json_array &&)" << std::endl; } +#else + NEMIR_JSON_INLINE ~json_array() {} + NEMIR_JSON_INLINE json_array() {} + NEMIR_JSON_INLINE json_array(json_array const& c) : _nodes(c._nodes) {} + NEMIR_JSON_INLINE json_array(json_array&& c) noexcept :_nodes(std::move(c._nodes)) {} +#endif + + NEMIR_JSON_INLINE json_array& operator=(json_array const& c) + { + _nodes = c._nodes; + return *this; + } + + NEMIR_JSON_INLINE json_array& operator=(json_array&& c) noexcept + { + _nodes = std::move(c._nodes); + return *this; + } + + NEMIR_JSON_INLINE json_value& operator[](size_t key) { return _nodes[key]; } + NEMIR_JSON_INLINE std::vector& nodes() { return _nodes; } + NEMIR_JSON_INLINE iterator begin() { return _nodes.begin(); } + NEMIR_JSON_INLINE iterator end() { return _nodes.end(); } + + NEMIR_JSON_INLINE iterator erase(iterator at) { return _nodes.erase(at); } + NEMIR_JSON_INLINE iterator erase(iterator first, iterator last) { return _nodes.erase(first, last); } + NEMIR_JSON_INLINE iterator insert(iterator at, json_value const&value) { return _nodes.insert(at, value); } + NEMIR_JSON_INLINE iterator insert(iterator at, json_value &&value) { return _nodes.insert(at, std::move(value)); } + NEMIR_JSON_INLINE void push_back(json_value const& v){ _nodes.push_back(v); } + NEMIR_JSON_INLINE void push_back(json_value&& v){ _nodes.push_back(std::move(v)); } + + template + NEMIR_JSON_INLINE void emplace_back(Args&& ...args) + { + _nodes.emplace_back(std::move(args...)); + } + }; + + using json_type_string = std::string; + using json_type_integer = int64_t; + using json_type_number = double; + using json_type_array = json_array; + using json_type_object = json_object; + using json_type_boolean = bool; + using json_type_null = std::nullptr_t; + + // Default constructor, empty value + NEMIR_JSON_INLINE json_value(): container(new t_json_value) + {} + // Copy constructor, clone from derived class + NEMIR_JSON_INLINE json_value(json_value const& c): container(c.container->clone()) + {} + // Move constructor, move pointer + NEMIR_JSON_INLINE json_value(json_value&& c) noexcept : container(std::move(c.container)) + {} + + // Copy operator + NEMIR_JSON_INLINE json_value& operator=(json_value const& c) + { + container.reset(c.container->clone()); + return *this; + } + // Move operator + NEMIR_JSON_INLINE json_value& operator=(json_value&& c) noexcept + { + container.swap(c.container); + return *this; + } + + // Json value constuctor with copy t_json_value + template + NEMIR_JSON_INLINE json_value(t_json_value const& v) :container(new t_json_value(v)) + {} + // Json value constuctor with move t_json_value + template + NEMIR_JSON_INLINE json_value(t_json_value && v) noexcept: + container(new t_json_value(std::move(v))) + {} + +#define JSON_VALUE_CONSTRUCTOR_BY_VALUE(value_type, json_type) \ +NEMIR_JSON_INLINE json_value(value_type const &v) : container(new t_json_value(v)){}\ +NEMIR_JSON_INLINE json_value(value_type &&v): container(new t_json_value(std::move(v))){}\ +NEMIR_JSON_INLINE json_value& operator=(value_type const& v)\ +{\ + container.reset(new t_json_value(v));\ + return *this;\ +}\ +NEMIR_JSON_INLINE json_value& operator=(value_type && v)\ +{\ + container.reset(new t_json_value(std::move(v)));\ + return *this;\ +}\ +NEMIR_JSON_INLINE operator const value_type () { return static_cast(*reinterpret_cast(get(json_value_type::type))); } + +#define JSON_REFERENCE_OPERATOR(json_type)\ +NEMIR_JSON_INLINE operator json_type& () { return *reinterpret_cast(get(json_value_type::type)); } + + + NEMIR_JSON_INLINE json_value(const wchar_t*) = delete; + NEMIR_JSON_INLINE json_value& operator=(const wchar_t*) = delete; + + NEMIR_JSON_INLINE json_value(const char* v) : container(new t_json_value(v)) {} + NEMIR_JSON_INLINE json_value& operator=(const char* v) + { + container.reset(new t_json_value(v)); + return *this; + } + + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_string, json_type_string) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(int8_t, json_type_integer) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(int16_t, json_type_integer) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(int32_t, json_type_integer) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_integer, json_type_integer) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_number, json_type_number) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_array, json_type_array) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_object, json_type_object) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_null, json_type_null) + JSON_VALUE_CONSTRUCTOR_BY_VALUE(json_type_boolean, json_type_boolean) + + JSON_REFERENCE_OPERATOR(json_type_string) + JSON_REFERENCE_OPERATOR(json_type_integer) + JSON_REFERENCE_OPERATOR(json_type_number) + JSON_REFERENCE_OPERATOR(json_type_array) + JSON_REFERENCE_OPERATOR(json_type_object) + JSON_REFERENCE_OPERATOR(json_type_null) + JSON_REFERENCE_OPERATOR(json_type_boolean) + +#undef JSON_VALUE_CONSTRUCTION_BY_VALUE + + NEMIR_JSON_INLINE json_type type() const { return container->type(); } + + NEMIR_JSON_INLINE json_value& operator[](std::string const &key) + { + return static_cast(*this)[key]; + } + NEMIR_JSON_INLINE json_value& operator[](const char *key) + { + return static_cast(*this)[key]; + } + NEMIR_JSON_INLINE json_value& operator[](size_t key) + { + return static_cast(*this)[key]; + } + }; + + using json_value_string = json_value::t_json_value; + using json_value_integer = json_value::t_json_value; + using json_value_number = json_value::t_json_value; + using json_value_array = json_value::t_json_value; + using json_value_object = json_value::t_json_value; + using json_value_boolean = json_value::t_json_value; + using json_value_null = json_value::t_json_value; +} + +#endif//__JSON_VALUE_INCLUDED diff --git a/dll/steam_inventory.h b/dll/steam_inventory.h index 2b4d93e..2965d89 100644 --- a/dll/steam_inventory.h +++ b/dll/steam_inventory.h @@ -17,6 +17,8 @@ #include "base.h" +#include "item_db_loader.h" + struct Steam_Inventory_Requests { double timeout = 0.1; @@ -34,7 +36,6 @@ struct Steam_Inventory_Requests { } }; - class Steam_Inventory : public ISteamInventory001, public ISteamInventory002, @@ -46,6 +47,19 @@ public ISteamInventory std::vector inventory_requests; + // [Item ID][item attr] = item_value + std::map> items; + // Like typedefs + using item_iterator = std::map>::iterator; + using attr_iterator = std::map::iterator; + + // Set this to false when we have cached everything, + // reset to true if something changed in the item db. + // Could use inotify on linux + // Could use FindFirstChangeNotificationA + WaitForSingleObject + FindNextChangeNotification on Windows to monitor the db file + // Or find a server somewhere to hold the data for us then cache on local settings. + bool need_load_definitions = true; + struct Steam_Inventory_Requests *new_inventory_result(const SteamItemInstanceID_t *pInstanceIDs=NULL, uint32 unCountInstanceIDs=0) { static SteamInventoryResult_t result; @@ -75,7 +89,8 @@ struct Steam_Inventory_Requests *get_inventory_result(SteamInventoryResult_t res public: -Steam_Inventory(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks) +Steam_Inventory(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks): + items(read_items_db(Local_Storage::get_program_path() + PATH_SEPARATOR + "steam_items.json")) { this->settings = settings; this->callbacks = callbacks; @@ -122,7 +137,19 @@ bool GetResultItems( SteamInventoryResult_t resultHandle, if (!request) return false; if (!request->result_done()) return false; - if (punOutItemsArraySize) *punOutItemsArraySize = 0; + if (pOutItemsArray != nullptr) + { + for (auto& i : items) + { + pOutItemsArray->m_iDefinition = i.first; + pOutItemsArray->m_itemId = i.first; + pOutItemsArray->m_unQuantity = 1; + pOutItemsArray->m_unFlags = k_ESteamItemNoTrade; + ++pOutItemsArray; + } + } + + if (punOutItemsArraySize) *punOutItemsArraySize = items.size(); PRINT_DEBUG("GetResultItems good\n"); return true; } @@ -227,6 +254,17 @@ bool GetAllItems( SteamInventoryResult_t *pResultHandle ) *pResultHandle = request->inventory_result; return true; } + else + { + //Steam_Client::RegisterCallback : SteamInventoryResultReady_t + //Steam_Client::RegisterCallback : SteamInventoryDefinitionUpdate_t + //Steam_Client::RegisterCallback : DownloadItemResult_t + struct Steam_Inventory_Requests* request = new_inventory_result(); + struct SteamInventoryResultReady_t data; + data.m_handle = request->inventory_result; + data.m_result = k_EResultOK; + callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), request->timeout); + } return false; } @@ -488,6 +526,14 @@ STEAM_METHOD_DESC(LoadItemDefinitions triggers the automatic load and refresh of bool LoadItemDefinitions() { PRINT_DEBUG("LoadItemDefinitions\n"); + + if (need_load_definitions) + { + need_load_definitions = false; + SteamInventoryDefinitionUpdate_t data; + callbacks->addCBResult(data.k_iCallback, &data, sizeof(data)); + } + return true; } @@ -502,18 +548,24 @@ bool GetItemDefinitionIDs( STEAM_DESC(Size of array is passed in and actual size used is returned in this param) uint32 *punItemDefIDsArraySize ) { PRINT_DEBUG("GetItemDefinitionIDs\n"); - if (!punItemDefIDsArraySize) { + if (!punItemDefIDsArraySize) return false; - } PRINT_DEBUG("array_size %u\n", *punItemDefIDsArraySize); -/* - if (pItemDefIDs) { - *pItemDefIDs = 0; + + if (pItemDefIDs == nullptr) + { + *punItemDefIDsArraySize = items.size(); + return true; } -*/ - //*punItemDefIDsArraySize = 0; - return false; + + if (*punItemDefIDsArraySize < items.size()) + return false; + + for (auto& i : items) + *pItemDefIDs++ = i.first; + + return true; } @@ -530,6 +582,33 @@ bool GetItemDefinitionProperty( SteamItemDef_t iDefinition, const char *pchPrope STEAM_OUT_STRING_COUNT(punValueBufferSizeOut) char *pchValueBuffer, uint32 *punValueBufferSizeOut ) { PRINT_DEBUG("GetItemDefinitionProperty\n"); + + item_iterator item; + if( (item = items.find(iDefinition)) != items.end() ) + { + attr_iterator attr; + if(pchPropertyName != nullptr ) + { + // Try to get the property + if ((attr = item->second.find(pchPropertyName)) != items[iDefinition].end()) + { + std::string const& val = attr->second; + if (pchValueBuffer != nullptr) + // copy what we can + strncpy(pchValueBuffer, val.c_str(), *punValueBufferSizeOut); + + // Set punValueBufferSizeOut to the property size + *punValueBufferSizeOut = val.length() + 1; + } + // Property not found + else + { + *punValueBufferSizeOut = 0; + PRINT_DEBUG("Attr %s not found for item %d", pchPropertyName, iDefinition); + } + } + } + return true; }