mirror of
https://gitlab.com/Mr_Goldberg/goldberg_emulator.git
synced 2024-06-15 00:54:04 +00:00
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:
parent
0543229b3e
commit
18d1aa98c9
44
dll/item_db_loader.cpp
Normal file
44
dll/item_db_loader.cpp
Normal 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
8
dll/item_db_loader.h
Normal 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
29
dll/json.h
Normal 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
407
dll/json_parser.cpp
Normal 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
381
dll/json_value.h
Normal 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
|
|
@ -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;
|
||||
}
|
||||
|
||||
|
||||
|
|
Loading…
Reference in New Issue
Block a user