Added incomplete inventory support

Inventory is a file names steam_items.json and describes all needed properties for items. Please not that it needs to be json valid (you can test your file on some web json validator)
This commit is contained in:
Nemirtingas 2019-06-23 15:18:26 +02:00
parent 0543229b3e
commit 18d1aa98c9
6 changed files with 959 additions and 11 deletions

44
dll/item_db_loader.cpp Normal file
View File

@ -0,0 +1,44 @@
#include "item_db_loader.h"
#include <fstream>
#include "json.h"
std::map<SteamItemDef_t, std::map<std::string, std::string>> read_items_db(std::string const& items_db)
{
std::map<SteamItemDef_t, std::map<std::string, std::string>> 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<nemir::json_value::json_object&>(val))
{
SteamItemDef_t key = std::stoi(i.first);
if (i.second.type() == nemir::json_type::object)
{
for (auto& j : static_cast<nemir::json_value::json_object&>(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;
}

8
dll/item_db_loader.h Normal file
View File

@ -0,0 +1,8 @@
#ifndef __ITEM_DB_LOADER_INCLUDED__
#define __ITEM_DB_LOADER_INCLUDED__
#include "base.h"
std::map<SteamItemDef_t, std::map<std::string, std::string>> read_items_db(std::string const& items_db);
#endif//__ITEM_DB_LOADER_INCLUDED__

29
dll/json.h Normal file
View File

@ -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
<http://www.gnu.org/licenses/>.
*/
#ifndef __JSON_INCLUDED__
#define __JSON_INCLUDED__
#include "json_value.h"
namespace nemir
{
json_value parse_json(std::string const& buffer);
}
#endif//__JSON_INCLUDED__

407
dll/json_parser.cpp Normal file
View File

@ -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
<http://www.gnu.org/licenses/>.
*/
#include "json_value.h"
#include <exception>
#include <algorithm>
// 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<int(*func)(int)>
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<int(*func)(int)>\
inline void find_##type ## _start(str_it &s, str_it &c, str_it &e)\
{\
buffer_seek<func>(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<int(*func)(int)>\
inline void find_##type ## _stop(str_it &s, str_it &c, str_it &e)\
{\
buffer_seek<func>(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<isspace>(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<isprint>(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<isspace>(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<isspace>(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<isspace>(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
}
}

381
dll/json_value.h Normal file
View File

@ -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
<http://www.gnu.org/licenses/>.
*/
#ifndef __JSON_VALUE_INCLUDED__
#define __JSON_VALUE_INCLUDED_
#include <string>
#include <map>
#include <vector>
#include <memory>
#include <exception>
#if 0 // Debug or not
#include <iostream>
#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<json_value>
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<int>(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<json_value_container> container;
protected:
NEMIR_JSON_INLINE void* get(json_type t) const
{
return container->get(t);
}
public:
class json_object;
class json_array;
template<typename T>
struct json_value_type
{
private:
json_value_type();
~json_value_type();
};
template<>struct json_value_type<std::string>
{
constexpr static json_type type = json_type::string;
};
template<>struct json_value_type<int64_t>
{
constexpr static json_type type = json_type::integer;
};
template<>struct json_value_type<double>
{
constexpr static json_type type = json_type::number;
};
template<>struct json_value_type<json_array>
{
constexpr static json_type type = json_type::array;
};
template<>struct json_value_type<json_value::json_object>
{
constexpr static json_type type = json_type::object;
};
template<>struct json_value_type<bool>
{
constexpr static json_type type = json_type::boolean;
};
template<>struct json_value_type<std::nullptr_t>
{
constexpr static json_type type = json_type::null;
};
template<typename T>
class t_json_value :
public json_value_container
{
T val;
public:
using mytype = t_json_value<T>;
#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<T>::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<std::string, json_value> _nodes;
public:
using iterator = std::map<std::string, json_value>::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<std::string, json_value>& 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<json_value> _nodes;
public:
using iterator = std::vector<json_value>::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<json_value>& 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<typename ...Args>
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<json_type_null>)
{}
// 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<typename T>
NEMIR_JSON_INLINE json_value(t_json_value<T> const& v) :container(new t_json_value<T>(v))
{}
// Json value constuctor with move t_json_value
template<typename T>
NEMIR_JSON_INLINE json_value(t_json_value<T> && v) noexcept:
container(new t_json_value<T>(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<json_type>(v)){}\
NEMIR_JSON_INLINE json_value(value_type &&v): container(new t_json_value<json_type>(std::move(v))){}\
NEMIR_JSON_INLINE json_value& operator=(value_type const& v)\
{\
container.reset(new t_json_value<json_type>(v));\
return *this;\
}\
NEMIR_JSON_INLINE json_value& operator=(value_type && v)\
{\
container.reset(new t_json_value<json_type>(std::move(v)));\
return *this;\
}\
NEMIR_JSON_INLINE operator const value_type () { return static_cast<value_type>(*reinterpret_cast<json_type*>(get(json_value_type<json_type>::type))); }
#define JSON_REFERENCE_OPERATOR(json_type)\
NEMIR_JSON_INLINE operator json_type& () { return *reinterpret_cast<json_type*>(get(json_value_type<json_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<json_type_string>(v)) {}
NEMIR_JSON_INLINE json_value& operator=(const char* v)
{
container.reset(new t_json_value<json_type_string>(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<json_type_object&>(*this)[key];
}
NEMIR_JSON_INLINE json_value& operator[](const char *key)
{
return static_cast<json_type_object&>(*this)[key];
}
NEMIR_JSON_INLINE json_value& operator[](size_t key)
{
return static_cast<json_type_array&>(*this)[key];
}
};
using json_value_string = json_value::t_json_value<nemir::json_value::json_type_string >;
using json_value_integer = json_value::t_json_value<nemir::json_value::json_type_integer>;
using json_value_number = json_value::t_json_value<nemir::json_value::json_type_number >;
using json_value_array = json_value::t_json_value<nemir::json_value::json_type_array >;
using json_value_object = json_value::t_json_value<nemir::json_value::json_type_object >;
using json_value_boolean = json_value::t_json_value<nemir::json_value::json_type_boolean>;
using json_value_null = json_value::t_json_value<nemir::json_value::json_type_null >;
}
#endif//__JSON_VALUE_INCLUDED

View File

@ -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<struct Steam_Inventory_Requests> inventory_requests;
// [Item ID][item attr] = item_value
std::map<SteamItemDef_t, std::map<std::string, std::string>> items;
// Like typedefs
using item_iterator = std::map<SteamItemDef_t, std::map<std::string, std::string>>::iterator;
using attr_iterator = std::map<std::string, std::string>::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;
}