Some cleanups.
Load items json only if there's an inventory request. Launch callbacks only when loading is done. Copy over original unformatted json.hppinventory_pr
parent
f56503fcd0
commit
59a9fcee0d
12
README.md
12
README.md
|
@ -16,18 +16,6 @@ If your game has an original steam_api(64).dll or libsteam_api.so older than may
|
|||
|
||||
For more information see: [The Release Readme](Readme_release.txt)
|
||||
|
||||
## How to add items to your steam inventory
|
||||
|
||||
Create a folder named steam_settings right beside steam_api.dll if there isn't one already. In that folder, create a file named items.json which will contain every item you want to have in your game.
|
||||
|
||||
An example can be found in steam_settings.EXAMPLE that works with Killing Floor 2.
|
||||
|
||||
The items.json syntax is simple, you SHOULD validate your .json file before trying to run your game or you won't have any item in your inventory. Just look for "online json validator" on your web brower to valide your file.
|
||||
|
||||
You can use https://steamdb.info/ to list items and attributes they have and put them into your .json.
|
||||
|
||||
Keep in mind that some item are not valid to have in your inventory. For example, in PayDay2 all items below item_id 50000 will make your game crash.
|
||||
|
||||
## Download Binaries
|
||||
|
||||
You can download the latest git builds for Linux and Windows on [the Gitlab pages website](https://mr_goldberg.gitlab.io/goldberg_emulator/) and the stable releases in the [release section](https://gitlab.com/Mr_Goldberg/goldberg_emulator/releases) of this repo.
|
||||
|
|
|
@ -65,6 +65,14 @@ If you want to set custom ips (or domains) which the emulator will send broadcas
|
|||
If the custom ips/domains are specific for one game only you can put the custom_broadcasts.txt in the steam_settings\ folder.
|
||||
An example is provided in steam_settings.EXAMPLE\custom_broadcasts.EXAMPLE.txt
|
||||
|
||||
Items or Inventory:
|
||||
Create a folder named steam_settings right beside steam_api.dll if there isn't one already. In that folder, create a file named items.json which will contain every item you want to have in your game.
|
||||
An example can be found in steam_settings.EXAMPLE that works with Killing Floor 2.
|
||||
The items.json syntax is simple, you SHOULD validate your .json file before trying to run your game or you won't have any item in your inventory. Just look for "online json validator" on your web brower to valide your file.
|
||||
You can use https://steamdb.info/ to list items and attributes they have and put them into your .json.
|
||||
Keep in mind that some item are not valid to have in your inventory. For example, in PayDay2 all items below item_id 50000 will make your game crash.
|
||||
|
||||
|
||||
Support for CPY steam_api(64).dll cracks: See the build in the experimental folder.
|
||||
|
||||
|
||||
|
|
|
@ -53,8 +53,10 @@ void read_items_db(std::string items_db, std::map<SteamItemDef_t, std::map<std::
|
|||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
PRINT_DEBUG("Error while parsing json: %s", e.what());
|
||||
PRINT_DEBUG("Error while parsing json: %s\n", e.what());
|
||||
}
|
||||
}
|
||||
|
||||
PRINT_DEBUG("Loaded json. Loaded %u items.\n", items->size());
|
||||
*is_loadedb = true;
|
||||
}
|
|
@ -291,6 +291,8 @@ Steam_Client::Steam_Client()
|
|||
}
|
||||
}
|
||||
|
||||
std::string items_db_file_path = (Local_Storage::get_game_settings_path() + "items.json");
|
||||
|
||||
network = new Networking(settings_server->get_local_steam_id(), appid, port, &custom_broadcasts);
|
||||
|
||||
callback_results_client = new SteamCallResults();
|
||||
|
@ -318,7 +320,7 @@ Steam_Client::Steam_Client()
|
|||
steam_music = new Steam_Music(callbacks_client);
|
||||
steam_musicremote = new Steam_MusicRemote();
|
||||
steam_HTMLsurface = new Steam_HTMLsurface(settings_client, network, callback_results_client, callbacks_client);
|
||||
steam_inventory = new Steam_Inventory(settings_client, callback_results_client, callbacks_client);
|
||||
steam_inventory = new Steam_Inventory(settings_client, callback_results_client, callbacks_client, run_every_runcb, items_db_file_path);
|
||||
steam_video = new Steam_Video();
|
||||
steam_parental = new Steam_Parental();
|
||||
steam_networking_sockets = new Steam_Networking_Sockets(settings_client, network, callback_results_client, callbacks_client, run_every_runcb);
|
||||
|
@ -335,7 +337,7 @@ Steam_Client::Steam_Client()
|
|||
steam_gameserverstats = new Steam_GameServerStats(settings_server, network, callback_results_server, callbacks_server);
|
||||
steam_gameserver_networking = new Steam_Networking(settings_server, network, callbacks_server, run_every_runcb);
|
||||
steam_gameserver_http = new Steam_HTTP(settings_server, network, callback_results_server, callbacks_server);
|
||||
steam_gameserver_inventory = new Steam_Inventory(settings_server, callback_results_server, callbacks_server);
|
||||
steam_gameserver_inventory = new Steam_Inventory(settings_server, callback_results_server, callbacks_server, run_every_runcb, items_db_file_path);
|
||||
steam_gameserver_ugc = new Steam_UGC(settings_server, callback_results_server, callbacks_server);
|
||||
steam_gameserver_apps = new Steam_Apps(settings_server, callback_results_server);
|
||||
steam_gameserver_networking_sockets = new Steam_Networking_Sockets(settings_server, network, callback_results_server, callbacks_server, run_every_runcb);
|
||||
|
|
|
@ -20,6 +20,8 @@
|
|||
|
||||
struct Steam_Inventory_Requests {
|
||||
double timeout = 0.1;
|
||||
bool done = false;
|
||||
bool full_query;
|
||||
|
||||
SteamInventoryResult_t inventory_result;
|
||||
std::chrono::system_clock::time_point time_created;
|
||||
|
@ -27,7 +29,7 @@ struct Steam_Inventory_Requests {
|
|||
std::vector<SteamItemInstanceID_t> instance_ids;
|
||||
|
||||
bool result_done() {
|
||||
return std::chrono::duration_cast<std::chrono::duration<double>>(std::chrono::system_clock::now() - time_created).count() > timeout;
|
||||
return done;
|
||||
}
|
||||
|
||||
uint32 timestamp() {
|
||||
|
@ -43,30 +45,30 @@ class Steam_Inventory :
|
|||
class Settings *settings;
|
||||
class SteamCallResults *callback_results;
|
||||
class SteamCallBacks *callbacks;
|
||||
class RunEveryRunCB *run_every_runcb;
|
||||
|
||||
std::vector<struct Steam_Inventory_Requests> inventory_requests;
|
||||
|
||||
static std::once_flag items_loading;
|
||||
static std::atomic_bool items_loaded;
|
||||
static std::map<SteamItemDef_t, std::map<std::string, std::string>> items;
|
||||
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;
|
||||
std::atomic_bool items_loaded;
|
||||
std::string items_db_file;
|
||||
std::once_flag load_items_flag;
|
||||
bool call_definition_update;
|
||||
bool definition_update_called;
|
||||
bool full_update_called;
|
||||
|
||||
struct Steam_Inventory_Requests* new_inventory_result(const SteamItemInstanceID_t* pInstanceIDs = NULL, uint32 unCountInstanceIDs = 0)
|
||||
struct Steam_Inventory_Requests* new_inventory_result(bool full_query=true, const SteamItemInstanceID_t* pInstanceIDs = NULL, uint32 unCountInstanceIDs = 0)
|
||||
{
|
||||
static SteamInventoryResult_t result;
|
||||
++result;
|
||||
|
||||
struct Steam_Inventory_Requests request;
|
||||
request.inventory_result = result;
|
||||
request.full_query = full_query;
|
||||
if (pInstanceIDs && unCountInstanceIDs) {
|
||||
for (int i = 0; i < unCountInstanceIDs; ++i)
|
||||
request.instance_ids.push_back(pInstanceIDs[i]);
|
||||
|
@ -89,19 +91,34 @@ struct Steam_Inventory_Requests *get_inventory_result(SteamInventoryResult_t res
|
|||
|
||||
public:
|
||||
|
||||
Steam_Inventory(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks)
|
||||
static void run_every_runcb_cb(void *object)
|
||||
{
|
||||
std::call_once(items_loading, [&]()
|
||||
{
|
||||
std::string items_db_file(Local_Storage::get_game_settings_path() + "items.json");
|
||||
PRINT_DEBUG("Items file path: %s\n", items_db_file.c_str());
|
||||
std::thread items_load_thread(read_items_db, items_db_file, &items, &items_loaded);
|
||||
items_load_thread.detach();
|
||||
});
|
||||
PRINT_DEBUG("Steam_Inventory::run_every_runcb\n");
|
||||
|
||||
Steam_Inventory *obj = (Steam_Inventory *)object;
|
||||
obj->RunCallbacks();
|
||||
}
|
||||
|
||||
Steam_Inventory(class Settings *settings, class SteamCallResults *callback_results, class SteamCallBacks *callbacks, class RunEveryRunCB *run_every_runcb, std::string items_db_file_path)
|
||||
{
|
||||
items_db_file = items_db_file_path;
|
||||
PRINT_DEBUG("Items file path: %s\n", items_db_file.c_str());
|
||||
items_loaded = false;
|
||||
|
||||
this->settings = settings;
|
||||
this->callbacks = callbacks;
|
||||
this->callback_results = callback_results;
|
||||
this->run_every_runcb = run_every_runcb;
|
||||
this->run_every_runcb->add(&Steam_Inventory::run_every_runcb_cb, this);
|
||||
|
||||
call_definition_update = false;
|
||||
definition_update_called = false;
|
||||
full_update_called = false;
|
||||
}
|
||||
|
||||
~Steam_Inventory()
|
||||
{
|
||||
this->run_every_runcb->remove(&Steam_Inventory::run_every_runcb_cb, this);
|
||||
}
|
||||
|
||||
// INVENTORY ASYNC RESULT MANAGEMENT
|
||||
|
@ -147,16 +164,29 @@ bool GetResultItems( SteamInventoryResult_t resultHandle,
|
|||
if (pOutItemsArray != nullptr)
|
||||
{
|
||||
uint32 max_items = *punOutItemsArraySize;
|
||||
// We end if we reached the end of items or the end of buffer
|
||||
for( auto i = items.begin(); i != items.end() && max_items; ++i, --max_items )
|
||||
{
|
||||
pOutItemsArray->m_iDefinition = i->first;
|
||||
pOutItemsArray->m_itemId = i->first;
|
||||
pOutItemsArray->m_unQuantity = 1;
|
||||
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
||||
++pOutItemsArray;
|
||||
|
||||
if (request->full_query) {
|
||||
// We end if we reached the end of items or the end of buffer
|
||||
for( auto i = items.begin(); i != items.end() && max_items; ++i, --max_items )
|
||||
{
|
||||
pOutItemsArray->m_iDefinition = i->first;
|
||||
pOutItemsArray->m_itemId = i->first;
|
||||
pOutItemsArray->m_unQuantity = 1;
|
||||
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
||||
++pOutItemsArray;
|
||||
}
|
||||
*punOutItemsArraySize = std::min(*punOutItemsArraySize, static_cast<uint32>(items.size()));
|
||||
} else {
|
||||
for (auto &itemid : request->instance_ids) {
|
||||
if (!max_items) break;
|
||||
pOutItemsArray->m_iDefinition = itemid;
|
||||
pOutItemsArray->m_itemId = itemid;
|
||||
pOutItemsArray->m_unQuantity = 1;
|
||||
pOutItemsArray->m_unFlags = k_ESteamItemNoTrade;
|
||||
++pOutItemsArray;
|
||||
--max_items;
|
||||
}
|
||||
}
|
||||
*punOutItemsArraySize = std::min(*punOutItemsArraySize, static_cast<uint32>(items.size()));
|
||||
}
|
||||
else if (punOutItemsArraySize != nullptr)
|
||||
{
|
||||
|
@ -248,48 +278,10 @@ bool GetAllItems( SteamInventoryResult_t *pResultHandle )
|
|||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
struct Steam_Inventory_Requests* request = new_inventory_result();
|
||||
|
||||
// Can't call LoadItemDefinitions because it sends a SteamInventoryResultReady_t.
|
||||
if( need_load_definitions )
|
||||
{
|
||||
if (items_loaded)
|
||||
{
|
||||
need_load_definitions = false;
|
||||
SteamInventoryDefinitionUpdate_t data = {};
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
}
|
||||
}
|
||||
if (!definition_update_called) call_definition_update = true;
|
||||
|
||||
if (!need_load_definitions)
|
||||
{
|
||||
{
|
||||
// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems
|
||||
// successfully returns a result which is newer / fresher than the last
|
||||
// known result.
|
||||
//TODO: should this always be returned for each get all item calls?
|
||||
struct SteamInventoryFullUpdate_t data;
|
||||
data.m_handle = request->inventory_result;
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), request->timeout);
|
||||
}
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
if (pResultHandle != nullptr)
|
||||
*pResultHandle = request->inventory_result;
|
||||
}
|
||||
else
|
||||
{
|
||||
struct SteamInventoryResultReady_t data;
|
||||
data.m_handle = request->inventory_result;
|
||||
data.m_result = k_EResultPending;
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data), request->timeout);
|
||||
|
||||
if (pResultHandle != nullptr)
|
||||
*pResultHandle = request->inventory_result;
|
||||
}
|
||||
if (pResultHandle != nullptr)
|
||||
*pResultHandle = request->inventory_result;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
@ -309,14 +301,7 @@ bool GetItemsByID( SteamInventoryResult_t *pResultHandle, STEAM_ARRAY_COUNT( unC
|
|||
PRINT_DEBUG("GetItemsByID\n");
|
||||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
if (pResultHandle) {
|
||||
struct Steam_Inventory_Requests *request = new_inventory_result(pInstanceIDs, unCountInstanceIDs);
|
||||
{
|
||||
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);
|
||||
}
|
||||
|
||||
struct Steam_Inventory_Requests *request = new_inventory_result(false, pInstanceIDs, unCountInstanceIDs);
|
||||
*pResultHandle = request->inventory_result;
|
||||
return true;
|
||||
}
|
||||
|
@ -393,14 +378,7 @@ bool DeserializeResult( SteamInventoryResult_t *pOutResultHandle, STEAM_BUFFER_C
|
|||
std::lock_guard<std::recursive_mutex> lock(global_mutex);
|
||||
//TODO
|
||||
if (pOutResultHandle) {
|
||||
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);
|
||||
}
|
||||
|
||||
struct Steam_Inventory_Requests *request = new_inventory_result(false);
|
||||
*pOutResultHandle = request->inventory_result;
|
||||
return true;
|
||||
}
|
||||
|
@ -551,32 +529,12 @@ STEAM_METHOD_DESC(LoadItemDefinitions triggers the automatic load and refresh of
|
|||
bool LoadItemDefinitions()
|
||||
{
|
||||
PRINT_DEBUG("LoadItemDefinitions\n");
|
||||
|
||||
if (need_load_definitions)
|
||||
{
|
||||
if (!items_loaded)
|
||||
{
|
||||
SteamInventoryResultReady_t data;
|
||||
data.m_result = k_EResultPending;
|
||||
data.m_handle = new_inventory_result()->inventory_result;
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
}
|
||||
else
|
||||
{
|
||||
need_load_definitions = false;
|
||||
{
|
||||
SteamInventoryDefinitionUpdate_t data = {};
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
}
|
||||
{
|
||||
SteamInventoryResultReady_t data = {};
|
||||
data.m_result = k_EResultOK;
|
||||
data.m_handle = new_inventory_result()->inventory_result;
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
}
|
||||
}
|
||||
if (!definition_update_called) {
|
||||
call_definition_update = true;
|
||||
}
|
||||
|
||||
//real steam launches a SteamInventoryResultReady_t which is why I create a new inventory result
|
||||
new_inventory_result(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -817,4 +775,52 @@ bool SubmitUpdateProperties( SteamInventoryUpdateHandle_t handle, SteamInventory
|
|||
PRINT_DEBUG("SubmitUpdateProperties\n");
|
||||
}
|
||||
|
||||
void RunCallbacks()
|
||||
{
|
||||
if (call_definition_update || inventory_requests.size()) {
|
||||
std::call_once(load_items_flag, [&]() {
|
||||
std::thread items_load_thread(read_items_db, items_db_file, &items, &items_loaded);
|
||||
items_load_thread.detach();
|
||||
});
|
||||
}
|
||||
|
||||
if (items_loaded) {
|
||||
if (call_definition_update) {
|
||||
//call this callback even when 0 items?
|
||||
SteamInventoryDefinitionUpdate_t data = {};
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
call_definition_update = false;
|
||||
definition_update_called = true;
|
||||
}
|
||||
|
||||
std::chrono::system_clock::time_point now = std::chrono::system_clock::now();
|
||||
|
||||
for (auto & r : inventory_requests) {
|
||||
if (!r.done && std::chrono::duration_cast<std::chrono::duration<double>>(now - r.time_created).count() > r.timeout) {
|
||||
if (r.full_query) {
|
||||
if (!full_update_called) {
|
||||
// SteamInventoryFullUpdate_t callbacks are triggered when GetAllItems
|
||||
// successfully returns a result which is newer / fresher than the last
|
||||
// known result.
|
||||
//TODO: should this always be returned for each get all item calls?
|
||||
struct SteamInventoryFullUpdate_t data;
|
||||
data.m_handle = r.inventory_result;
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
full_update_called = true;
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
struct SteamInventoryResultReady_t data;
|
||||
data.m_handle = r.inventory_result;
|
||||
data.m_result = k_EResultOK;
|
||||
callbacks->addCBResult(data.k_iCallback, &data, sizeof(data));
|
||||
}
|
||||
|
||||
r.done = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
};
|
34503
json/json.hpp
34503
json/json.hpp
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue