Refactor API calls to use FFIResult

Also create a `successReg` and `failReg` for every async function. Report error string to `failReg`.
This commit is contained in:
Tyler Hallada 2020-10-18 20:53:41 -04:00
parent c42b29af5d
commit 055905bffc
5 changed files with 241 additions and 235 deletions

View File

@ -1,45 +1,50 @@
#include "bindings.h" #include "bindings.h"
bool Init(RE::StaticFunctionTag*) bool Init(RE::StaticFunctionTag*) {
{
logger::info("Entered Init"); logger::info("Entered Init");
bool result = init(); bool result = init();
if (result) { if (result) {
logger::info("Init successful"); logger::info("Init successful");
return true; return true;
} } else {
else {
logger::error("Init failed"); logger::error("Init failed");
return false; return false;
} }
} }
std::string GenerateApiKey(RE::StaticFunctionTag*) std::string GenerateApiKey(RE::StaticFunctionTag*) {
{
logger::info("Entered GenerateApiKey"); logger::info("Entered GenerateApiKey");
char *api_key = generate_api_key(); char *api_key = generate_api_key();
logger::info(FMT_STRING("GenerateApiKey api_key: {}"), api_key); logger::info(FMT_STRING("GenerateApiKey api_key: {}"), api_key);
return api_key; return api_key;
} }
bool StatusCheckImpl(RE::BSFixedString api_url, RE::TESQuest* quest) void StatusCheckImpl(RE::BSFixedString api_url, RE::TESQuest* quest) {
{
logger::info("Entered StatusCheckImpl"); logger::info("Entered StatusCheckImpl");
if (!quest) { if (!quest) {
logger::error("StatusCheck quest is null!"); logger::error("StatusCheck quest is null!");
return false; return;
} }
SKSE::RegistrationMap<bool> successReg = SKSE::RegistrationMap<bool>();
SKSE::RegistrationMap<bool> regMap = SKSE::RegistrationMap<bool>(); successReg.Register(quest, RE::BSFixedString("OnStatusCheckSuccess"));
regMap.Register(quest, RE::BSFixedString("OnStatusCheck")); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnStatusCheckFail"));
logger::info(FMT_STRING("StatusCheck api_url: {}"), api_url); logger::info(FMT_STRING("StatusCheck api_url: {}"), api_url);
bool result = status_check(api_url.c_str()); FFIResult<bool> result = status_check(api_url.c_str());
logger::info(FMT_STRING("StatusCheck result: {}"), result ? "true" : "false"); if (result.IsOk()) {
regMap.SendEvent(result); bool success = result.AsOk();
regMap.Unregister(quest); logger::info(FMT_STRING("StatusCheck success: {}"), success);
return result; successReg.SendEvent(success);
} else {
const char* error = result.AsErr();
logger::error(FMT_STRING("StatusCheck failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error));
}
successReg.Unregister(quest);
failReg.Unregister(quest);
return;
} }
bool StatusCheck(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::TESQuest* quest) { bool StatusCheck(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::TESQuest* quest) {

View File

@ -2,31 +2,32 @@
#include "NativeFunctions.h" #include "NativeFunctions.h"
int CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest) void CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest) {
{
logger::info("Entered CreateInteriorRefListImpl"); logger::info("Entered CreateInteriorRefListImpl");
if (!quest) { if (!quest) {
logger::error("LoadInteriorRefList quest is null!"); logger::error("CreateInteriorRefListImpl quest is null!");
return -1; return;
} }
SKSE::RegistrationMap<int> regMap = SKSE::RegistrationMap<int>(); SKSE::RegistrationMap<int> successReg = SKSE::RegistrationMap<int>();
regMap.Register(quest, RE::BSFixedString("OnCreateInteriorRefList")); successReg.Register(quest, RE::BSFixedString("OnCreateInteriorRefListSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnCreateInteriorRefListFail"));
RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty"); RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty");
logger::info(FMT_STRING("ClearCell lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID()); logger::info(FMT_STRING("CreateInteriorRefListImpl lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID());
if (!cell) { if (!cell) {
logger::error("ClearCell cell is null!"); logger::error("CreateInteriorRefListImpl cell is null!");
regMap.SendEvent(-1); failReg.SendEvent("Could not find Cell with the editor ID: BREmpty");
regMap.Unregister(quest); successReg.Unregister(quest);
return -1; failReg.Unregister(quest);
return;
} }
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton(); RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
std::vector<RefRecord> ref_records; std::vector<RawInteriorRef> raw_interior_refs;
for (auto entry = cell->references.begin(); entry != cell->references.end(); ++entry) for (auto entry = cell->references.begin(); entry != cell->references.end(); ++entry) {
{
RE::TESObjectREFR * ref = (*entry).get(); RE::TESObjectREFR * ref = (*entry).get();
const char * name = ref->GetName(); const char * name = ref->GetName();
logger::info(FMT_STRING("CreateInteriorRefList ref: {}"), name); logger::info(FMT_STRING("CreateInteriorRefList ref: {}"), name);
@ -70,14 +71,13 @@ int CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_k
ref_mod_index = (ref_form_id >> 12) & 0xfff; ref_mod_index = (ref_form_id >> 12) & 0xfff;
const RE::TESFile * ref_file = data_handler->LookupLoadedLightModByIndex(ref_mod_index); const RE::TESFile * ref_file = data_handler->LookupLoadedLightModByIndex(ref_mod_index);
ref_file_name = _strdup(ref_file->fileName); ref_file_name = _strdup(ref_file->fileName);
} } else {
else {
const RE::TESFile * ref_file = data_handler->LookupLoadedModByIndex(ref_mod_index); const RE::TESFile * ref_file = data_handler->LookupLoadedModByIndex(ref_mod_index);
ref_file_name = _strdup(ref_file->fileName); ref_file_name = _strdup(ref_file->fileName);
} }
} }
ref_records.push_back({ raw_interior_refs.push_back({
base_file_name, base_file_name,
base_local_form_id, base_local_form_id,
ref_file_name, ref_file_name,
@ -93,18 +93,25 @@ int CreateInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_k
} }
} }
int interior_ref_list_id = create_interior_ref_list(api_url.c_str(), api_key.c_str(), shop_id, &ref_records[0], ref_records.size()); FFIResult<int32_t> result = create_interior_ref_list(api_url.c_str(), api_key.c_str(), shop_id, &raw_interior_refs[0], raw_interior_refs.size());
logger::info(FMT_STRING("CreateInteriorRefList result: {}"), interior_ref_list_id); if (result.IsOk()) {
regMap.SendEvent(interior_ref_list_id); int32_t interior_ref_list_id = result.AsOk();
regMap.Unregister(quest); logger::info(FMT_STRING("CreateInteriorRefList success: {}"), interior_ref_list_id);
return interior_ref_list_id; successReg.SendEvent(interior_ref_list_id);
} else {
const char* error = result.AsErr();
logger::error(FMT_STRING("CreateInteriorRefList failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error));
}
successReg.Unregister(quest);
failReg.Unregister(quest);
} }
bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest) { bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESQuest* quest) {
logger::info("Entered CreateInteriorRefList"); logger::info("Entered CreateInteriorRefList");
if (!quest) { if (!quest) {
logger::error("LoadInteriorRefList quest is null!"); logger::error("CreateInteriorRefList quest is null!");
return false; return false;
} }
@ -113,8 +120,7 @@ bool CreateInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE
return true; return true;
} }
bool ClearCell(RE::StaticFunctionTag*) bool ClearCell(RE::StaticFunctionTag*) {
{
logger::info("Entered ClearCell"); logger::info("Entered ClearCell");
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton(); RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
@ -127,8 +133,7 @@ bool ClearCell(RE::StaticFunctionTag*)
} }
// Destroy existing references // Destroy existing references
for (auto entry = cell->references.begin(); entry != cell->references.end();) for (auto entry = cell->references.begin(); entry != cell->references.end();) {
{
RE::TESObjectREFR * ref = (*entry).get(); RE::TESObjectREFR * ref = (*entry).get();
RE::FormID form_id = ref->GetFormID(); RE::FormID form_id = ref->GetFormID();
logger::info(FMT_STRING("ClearCell ref form_id: {:x}"), (uint32_t)form_id); logger::info(FMT_STRING("ClearCell ref form_id: {:x}"), (uint32_t)form_id);
@ -141,16 +146,14 @@ bool ClearCell(RE::StaticFunctionTag*)
uint32_t local_form_id = is_light ? ref->GetFormID() & 0xfff : form_id & 0xFFFFFF; uint32_t local_form_id = is_light ? ref->GetFormID() & 0xfff : form_id & 0xFFFFFF;
if (!data_handler->LookupForm<RE::TESObjectREFR>(local_form_id, file->fileName)) { if (!data_handler->LookupForm<RE::TESObjectREFR>(local_form_id, file->fileName)) {
logger::info(FMT_STRING("ClearCell ref was not in mod file! {:x} {}"), local_form_id, ref->GetName()); logger::info(FMT_STRING("ClearCell ref was not in mod file! {:x} {}"), local_form_id, ref->GetName());
} } else {
else {
logger::info(FMT_STRING("ClearCell ref in mod file {:x} {}"), local_form_id, ref->GetName()); logger::info(FMT_STRING("ClearCell ref in mod file {:x} {}"), local_form_id, ref->GetName());
} }
} else { } else {
logger::info(FMT_STRING("ClearCell ref not in ANY file! {:x} {}"), (uint32_t)form_id, ref->GetName()); logger::info(FMT_STRING("ClearCell ref not in ANY file! {:x} {}"), (uint32_t)form_id, ref->GetName());
} }
++entry; ++entry;
} } else {
else {
logger::info(FMT_STRING("ClearCell ref is a temp ref, deleting {:x} {}"), (uint32_t)form_id, ref->GetName()); logger::info(FMT_STRING("ClearCell ref is a temp ref, deleting {:x} {}"), (uint32_t)form_id, ref->GetName());
ref->Disable(); // disabling first is required to prevent CTD on unloading cell ref->Disable(); // disabling first is required to prevent CTD on unloading cell
ref->SetDelete(true); ref->SetDelete(true);
@ -161,13 +164,12 @@ bool ClearCell(RE::StaticFunctionTag*)
return true; return true;
} }
bool LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) void LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {
{
logger::info("Entered LoadInteriorRefListImpl"); logger::info("Entered LoadInteriorRefListImpl");
if (!quest) { if (!quest) {
logger::error("LoadInteriorRefList quest is null!"); logger::error("LoadInteriorRefListImpl quest is null!");
return false; return;
} }
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton(); RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
@ -178,28 +180,30 @@ bool LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_ke
REL::Relocation<func_t2> MoveTo_Native(RE::Offset::TESObjectREFR::MoveTo); REL::Relocation<func_t2> MoveTo_Native(RE::Offset::TESObjectREFR::MoveTo);
RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty"); RE::TESObjectCELL * cell = RE::TESObjectCELL::LookupByEditorID<RE::TESObjectCELL>("BREmpty");
logger::info(FMT_STRING("LoadInteriorRefList lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID()); logger::info(FMT_STRING("LoadInteriorRefListImpl lookup cell override name: {} id: {:x}"), cell->GetName(), (uint32_t)cell->GetFormID());
if (!cell) { if (!cell) {
logger::error("LoadInteriorRefList cell is null!"); logger::error("LoadInteriorRefListImpl cell is null!");
return false; return;
} }
if (target_ref) { if (target_ref) {
FFIResult<RefRecordVec> result = get_interior_ref_list(api_url.c_str(), api_key.c_str(), interior_ref_list_id); FFIResult<RawInteriorRefVec> result = get_interior_ref_list(api_url.c_str(), api_key.c_str(), interior_ref_list_id);
// Placing the refs must be done on the main thread otherwise calling MoveTo causes a crash // Placing the refs must be done on the main thread otherwise calling MoveTo causes a crash
auto task = SKSE::GetTaskInterface(); auto task = SKSE::GetTaskInterface();
task->AddTask([result, target_ref, quest, cell, data_handler, a_vm, MoveTo_Native, PlaceAtMe_Native]() { task->AddTask([result, target_ref, quest, cell, data_handler, a_vm, MoveTo_Native, PlaceAtMe_Native]() {
SKSE::RegistrationMap<bool> regMap = SKSE::RegistrationMap<bool>(); SKSE::RegistrationMap<bool> successReg = SKSE::RegistrationMap<bool>();
regMap.Register(quest, RE::BSFixedString("OnLoadInteriorRefList")); successReg.Register(quest, RE::BSFixedString("OnLoadInteriorRefListSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnLoadInteriorRefListFail"));
if (result.IsOk()) { if (result.IsOk()) {
logger::info("LoadInteriorRefList get_interior_ref_list result: OK"); logger::info("LoadInteriorRefList get_interior_ref_list result: OK");
RefRecordVec vec = result.AsOk(); RawInteriorRefVec vec = result.AsOk();
logger::info(FMT_STRING("LoadInteriorRefList vec len: {:d}, cap: {:d}"), vec.len, vec.cap); logger::info(FMT_STRING("LoadInteriorRefList vec len: {:d}, cap: {:d}"), vec.len, vec.cap);
for (int i = 0; i < vec.len; i++) { for (int i = 0; i < vec.len; i++) {
RefRecord ref = vec.ptr[i]; RawInteriorRef ref = vec.ptr[i];
logger::info(FMT_STRING("LoadInteriorRefList ref base_mod_name: {}, base_local_form_id: {:x}"), ref.base_mod_name, ref.base_local_form_id); logger::info(FMT_STRING("LoadInteriorRefList ref base_mod_name: {}, base_local_form_id: {:x}"), ref.base_mod_name, ref.base_local_form_id);
logger::info(FMT_STRING("LoadInteriorRefList ref position {:.2f} {:.2f} {:.2f}, angle: {:.2f} {:.2f} {:.2f}, scale: {:d}"), ref.position_x, ref.position_y, ref.position_z, ref.angle_x, ref.angle_y, ref.angle_z, ref.scale); logger::info(FMT_STRING("LoadInteriorRefList ref position {:.2f} {:.2f} {:.2f}, angle: {:.2f} {:.2f} {:.2f}, scale: {:d}"), ref.position_x, ref.position_y, ref.position_z, ref.angle_x, ref.angle_y, ref.angle_z, ref.scale);
if (strcmp(ref.base_mod_name, "Skyrim.esm") == 0 && ref.base_local_form_id == 7) { if (strcmp(ref.base_mod_name, "Skyrim.esm") == 0 && ref.base_local_form_id == 7) {
@ -214,8 +218,7 @@ bool LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_ke
game_ref = data_handler->LookupForm<RE::TESObjectREFR>(ref.ref_local_form_id, ref.ref_mod_name); game_ref = data_handler->LookupForm<RE::TESObjectREFR>(ref.ref_local_form_id, ref.ref_mod_name);
if (game_ref) { if (game_ref) {
logger::info(FMT_STRING("LoadInteriorRefList lookup ref name: {}, form_id: {:x}"), game_ref->GetName(), (uint32_t)game_ref->GetFormID()); logger::info(FMT_STRING("LoadInteriorRefList lookup ref name: {}, form_id: {:x}"), game_ref->GetName(), (uint32_t)game_ref->GetFormID());
} } else {
else {
logger::info(FMT_STRING("LoadInteriorRefList lookup ref not found, ref_mod_name: {}, ref_local_form_id: {:x}"), ref.ref_mod_name, ref.ref_local_form_id); logger::info(FMT_STRING("LoadInteriorRefList lookup ref not found, ref_mod_name: {}, ref_local_form_id: {:x}"), ref.ref_mod_name, ref.ref_local_form_id);
} }
} }
@ -230,34 +233,33 @@ bool LoadInteriorRefListImpl(RE::BSFixedString api_url, RE::BSFixedString api_ke
game_ref = PlaceAtMe_Native(a_vm, 0, target_ref, form, 1, false, false); game_ref = PlaceAtMe_Native(a_vm, 0, target_ref, form, 1, false, false);
if (!game_ref) { if (!game_ref) {
logger::error("LoadInteriorRefList failed to place new ref in cell!"); logger::error("LoadInteriorRefList failed to place new ref in cell!");
regMap.SendEvent(false); failReg.SendEvent("Failed to place a new ref into the cell");
regMap.Unregister(quest); successReg.Unregister(quest);
return false; failReg.Unregister(quest);
return;
} }
} }
MoveTo_Native(game_ref, game_ref->CreateRefHandle(), cell, cell->worldSpace, position, angle); MoveTo_Native(game_ref, game_ref->CreateRefHandle(), cell, cell->worldSpace, position, angle);
game_ref->data.angle = angle; // set angle directly to fix bug with MoveTo in an unloaded target cell game_ref->data.angle = angle; // set angle directly to fix bug with MoveTo in an unloaded target cell
} }
} } else {
else {
const char * error = result.AsErr(); const char * error = result.AsErr();
logger::error(FMT_STRING("LoadInteriorRefList get_interior_ref_list error: {}"), error); logger::error(FMT_STRING("LoadInteriorRefList get_interior_ref_list error: {}"), error);
regMap.SendEvent(false); failReg.SendEvent(RE::BSFixedString(error));
regMap.Unregister(quest); successReg.Unregister(quest);
return false; failReg.Unregister(quest);
return;
} }
regMap.SendEvent(true); successReg.SendEvent(true);
regMap.Unregister(quest); successReg.Unregister(quest);
failReg.Unregister(quest);
}); });
} else {
logger::error("LoadInteriorRefListImpl target_ref is null!");
return;
} }
else {
logger::error("LoadInteriorRefList target_ref is null!");
return false;
}
return true;
} }
bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) { bool LoadInteriorRefList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t interior_ref_list_id, RE::TESObjectREFR* target_ref, RE::TESQuest* quest) {

View File

@ -34,12 +34,10 @@ bool ClearMerchandiseImpl(RE::TESObjectREFR* merchant_chest, RE::TESObjectREFR*
ref->Disable(); // disabling first is required to prevent CTD on unloading cell ref->Disable(); // disabling first is required to prevent CTD on unloading cell
ref->SetDelete(true); ref->SetDelete(true);
cell->references.erase(*entry++); // prevents slowdowns after many runs of ClearMerchandise cell->references.erase(*entry++); // prevents slowdowns after many runs of ClearMerchandise
} } else {
else {
++entry; ++entry;
} }
} } else {
else {
++entry; ++entry;
} }
} }
@ -47,21 +45,21 @@ bool ClearMerchandiseImpl(RE::TESObjectREFR* merchant_chest, RE::TESObjectREFR*
if (ref->IsDisabled() && ref->IsMarkedForDeletion() && ref->IsDeleted()) { if (ref->IsDisabled() && ref->IsMarkedForDeletion() && ref->IsDeleted()) {
logger::info("ClearMerchandise ref is probably an item from old LoadMerchandise, clearing from cell now"); logger::info("ClearMerchandise ref is probably an item from old LoadMerchandise, clearing from cell now");
cell->references.erase(*entry++); cell->references.erase(*entry++);
} } else {
else {
logger::info("ClearMerchandise ref has no base, skipping"); logger::info("ClearMerchandise ref has no base, skipping");
++entry; ++entry;
} }
} }
} }
} else { } else {
logger::error("ClearMerchandise merchant_chest or merchant_shelf is null!"); logger::error("ClearMerchandiseImpl merchant_chest or merchant_shelf is null!");
return false; return false;
} }
return true; return true;
} }
bool LoadMerchandiseImpl( void LoadMerchandiseImpl(
RE::BSFixedString api_url, RE::BSFixedString api_url,
RE::BSFixedString api_key, RE::BSFixedString api_key,
uint32_t merchandise_list_id, uint32_t merchandise_list_id,
@ -73,8 +71,8 @@ bool LoadMerchandiseImpl(
RE::BGSKeyword* toggle_keyword, RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword, RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword, RE::BGSKeyword* prev_keyword,
int page) int page
{ ) {
logger::info("Entered LoadMerchandiseImpl"); logger::info("Entered LoadMerchandiseImpl");
logger::info(FMT_STRING("LoadMerchandise page: {:d}"), page); logger::info(FMT_STRING("LoadMerchandise page: {:d}"), page);
@ -88,58 +86,66 @@ bool LoadMerchandiseImpl(
if (!merchant_shelf) { if (!merchant_shelf) {
logger::error("LoadMerchandise merchant_shelf is null!"); logger::error("LoadMerchandise merchant_shelf is null!");
return false; return;
} }
RE::TESObjectCELL * cell = merchant_shelf->GetParentCell(); RE::TESObjectCELL * cell = merchant_shelf->GetParentCell();
RE::TESObjectREFR * toggle_ref = merchant_shelf->GetLinkedRef(toggle_keyword); RE::TESObjectREFR * toggle_ref = merchant_shelf->GetLinkedRef(toggle_keyword);
if (!toggle_ref) { if (!toggle_ref) {
logger::error("LoadMerchandise toggle_ref is null!"); logger::error("LoadMerchandise toggle_ref is null!");
return false; return;
} }
RE::TESObjectREFR * merchant_chest = merchant_shelf->GetLinkedRef(chest_keyword); RE::TESObjectREFR * merchant_chest = merchant_shelf->GetLinkedRef(chest_keyword);
if (!merchant_chest) { if (!merchant_chest) {
logger::error("LoadMerchandise merchant_chest is null!"); logger::error("LoadMerchandise merchant_chest is null!");
return false; return;
} }
FFIResult<MerchRecordVec> result = get_merchandise_list(api_url.c_str(), api_key.c_str(), merchandise_list_id); FFIResult<RawMerchandiseVec> result = get_merchandise_list(api_url.c_str(), api_key.c_str(), merchandise_list_id);
// Placing the refs must be done on the main thread otherwise disabling & deleting refs in ClearMerchandiseImpl causes a crash // Placing the refs must be done on the main thread otherwise disabling & deleting refs in ClearMerchandiseImpl causes a crash
auto task = SKSE::GetTaskInterface(); auto task = SKSE::GetTaskInterface();
task->AddTask([result, merchant_chest, merchant_shelf, placeholder_static, shelf_keyword, item_keyword, prev_keyword, next_keyword, page, toggle_ref, cell, data_handler, a_vm, extra_linked_ref_vtbl, MoveTo_Native, PlaceAtMe_Native]() { task->AddTask([result, merchant_chest, merchant_shelf, placeholder_static, shelf_keyword, item_keyword, prev_keyword, next_keyword, page, toggle_ref, cell, data_handler, a_vm, extra_linked_ref_vtbl, MoveTo_Native, PlaceAtMe_Native]() {
// Since this method is running asyncronously in a thread, set up a callback on the trigger ref that will receive an event with the result // Since this method is running asyncronously in a thread, set up a callback on the trigger ref that will receive an event with the result
SKSE::RegistrationMap<bool> regMap = SKSE::RegistrationMap<bool>(); SKSE::RegistrationMap<bool> successReg = SKSE::RegistrationMap<bool>();
regMap.Register(toggle_ref, RE::BSFixedString("OnLoadMerchandise")); successReg.Register(toggle_ref, RE::BSFixedString("OnLoadMerchandiseSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(toggle_ref, RE::BSFixedString("OnLoadMerchandiseFail"));
if (result.IsOk()) { if (result.IsOk()) {
logger::info("LoadMerchandise get_merchandise_list result OK"); logger::info("LoadMerchandise get_merchandise_list result OK");
MerchRecordVec vec = result.AsOk(); RawMerchandiseVec vec = result.AsOk();
logger::info(FMT_STRING("LoadMerchandise vec len: {:d}, cap: {:d}"), vec.len, vec.cap); logger::info(FMT_STRING("LoadMerchandise vec len: {:d}, cap: {:d}"), vec.len, vec.cap);
int max_page = std::ceil((float)(vec.len - 1) / (float)9); int max_page = std::ceil((float)(vec.len - 1) / (float)9);
if (vec.len > 0 && page > max_page) { if (vec.len > 0 && page > max_page) {
logger::info(FMT_STRING("LoadMerchandise page {:d} is greater than max_page {:d}, doing nothing"), page, max_page); logger::info(FMT_STRING("LoadMerchandise page {:d} is greater than max_page {:d}, doing nothing"), page, max_page);
regMap.SendEvent(true); successReg.SendEvent(true);
regMap.Unregister(toggle_ref); successReg.Unregister(toggle_ref);
return true; failReg.Unregister(toggle_ref);
return;
} }
if (!ClearMerchandiseImpl(merchant_chest, merchant_shelf, placeholder_static, shelf_keyword, item_keyword)) {
ClearMerchandiseImpl(merchant_chest, merchant_shelf, placeholder_static, shelf_keyword, item_keyword); logger::error("LoadMerchandise ClearMerchandiseImpl returned a fail code");
failReg.SendEvent(RE::BSFixedString("Failed to clear existing merchandise from shelf"));
successReg.Unregister(toggle_ref);
failReg.Unregister(toggle_ref);
return;
}
logger::info(FMT_STRING("LoadMerchandise current shelf page is: {:d}"), merchant_shelf->extraList.GetCount()); logger::info(FMT_STRING("LoadMerchandise current shelf page is: {:d}"), merchant_shelf->extraList.GetCount());
for (int i = 0; i < vec.len; i++) { for (int i = 0; i < vec.len; i++) {
MerchRecord rec = vec.ptr[i]; RawMerchandise merch = vec.ptr[i];
logger::info(FMT_STRING("LoadMerchandise item: {:d}"), i); logger::info(FMT_STRING("LoadMerchandise item: {:d}"), i);
if (i < (page - 1) * 9 || i >= (page - 1) * 9 + 9) { if (i < (page - 1) * 9 || i >= (page - 1) * 9 + 9) {
continue; continue;
} }
RE::TESForm * form = data_handler->LookupForm(rec.local_form_id, rec.mod_name); RE::TESForm * form = data_handler->LookupForm(merch.local_form_id, merch.mod_name);
if (!form) { // form is not found, might be in an uninstalled mod if (!form) { // form is not found, might be in an uninstalled mod
logger::warn(FMT_STRING("LoadMerchandise not spawning ref for form that could not be found in installed mods: {} {:d}"), rec.mod_name, rec.local_form_id); logger::warn(FMT_STRING("LoadMerchandise not spawning ref for form that could not be found in installed mods: {} {:d}"), merch.mod_name, merch.local_form_id);
continue; continue;
} }
logger::info(FMT_STRING("LoadMerchandise lookup form name: {}, form_id: {:x}, form_type: {:x}"), form->GetName(), (uint32_t)form->GetFormID(), (uint32_t)form->GetFormType()); logger::info(FMT_STRING("LoadMerchandise lookup form name: {}, form_id: {:x}, form_type: {:x}"), form->GetName(), (uint32_t)form->GetFormID(), (uint32_t)form->GetFormType());
@ -165,7 +171,7 @@ bool LoadMerchandiseImpl(
// This extra count stored on the placeholder_ref indicates the quanity of the merchandise item it is linked to // This extra count stored on the placeholder_ref indicates the quanity of the merchandise item it is linked to
RE::ExtraCount * extra_page_num = (RE::ExtraCount*)RE::BSExtraData::Create(sizeof(RE::ExtraCount), RE::Offset::ExtraCount::Vtbl.address()); RE::ExtraCount * extra_page_num = (RE::ExtraCount*)RE::BSExtraData::Create(sizeof(RE::ExtraCount), RE::Offset::ExtraCount::Vtbl.address());
extra_page_num->count = rec.quantity; extra_page_num->count = merch.quantity;
placeholder_ref->extraList.Add(extra_page_num); placeholder_ref->extraList.Add(extra_page_num);
float scale = 1; float scale = 1;
@ -200,29 +206,21 @@ bool LoadMerchandiseImpl(
// TODO: make page size and buy_activator positions configurable per "shelf" type (where is config stored?) // TODO: make page size and buy_activator positions configurable per "shelf" type (where is config stored?)
if (i % 9 == 0) { if (i % 9 == 0) {
ref_position = RE::NiPoint3(shelf_position.x + 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 110 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x + 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 110 + z_imbalance);
} } else if (i % 9 == 1) {
else if (i % 9 == 1) {
ref_position = RE::NiPoint3(shelf_position.x + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 110 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 110 + z_imbalance);
} } else if (i % 9 == 2) {
else if (i % 9 == 2) {
ref_position = RE::NiPoint3(shelf_position.x - 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 110 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x - 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 110 + z_imbalance);
} } else if (i % 9 == 3) {
else if (i % 9 == 3) {
ref_position = RE::NiPoint3(shelf_position.x + 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 65 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x + 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 65 + z_imbalance);
} } else if (i % 9 == 4) {
else if (i % 9 == 4) {
ref_position = RE::NiPoint3(shelf_position.x + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 65 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 65 + z_imbalance);
} } else if (i % 9 == 5) {
else if (i % 9 == 5) {
ref_position = RE::NiPoint3(shelf_position.x - 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 65 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x - 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 65 + z_imbalance);
} } else if (i % 9 == 6) {
else if (i % 9 == 6) {
ref_position = RE::NiPoint3(shelf_position.x + 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 20 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x + 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 20 + z_imbalance);
} } else if (i % 9 == 7) {
else if (i % 9 == 7) {
ref_position = RE::NiPoint3(shelf_position.x + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 20 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 20 + z_imbalance);
} } else if (i % 9 == 8) {
else if (i % 9 == 8) {
ref_position = RE::NiPoint3(shelf_position.x - 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 20 + z_imbalance); ref_position = RE::NiPoint3(shelf_position.x - 40 + x_imbalance, shelf_position.y + y_imbalance, shelf_position.z + 20 + z_imbalance);
} }
MoveTo_Native(ref, ref->CreateRefHandle(), cell, cell->worldSpace, ref_position - RE::NiPoint3(10000, 10000, 10000), ref_angle); MoveTo_Native(ref, ref->CreateRefHandle(), cell, cell->worldSpace, ref_position - RE::NiPoint3(10000, 10000, 10000), ref_angle);
@ -255,42 +253,42 @@ bool LoadMerchandiseImpl(
RE::TESObjectREFR * next_ref = merchant_shelf->GetLinkedRef(next_keyword); RE::TESObjectREFR * next_ref = merchant_shelf->GetLinkedRef(next_keyword);
if (!next_ref) { if (!next_ref) {
logger::error("LoadMerchandise next_ref is null!"); logger::error("LoadMerchandise next_ref is null!");
regMap.SendEvent(false); failReg.SendEvent("Could not find the shelf's next button");
regMap.Unregister(toggle_ref); successReg.Unregister(toggle_ref);
return false; failReg.Unregister(toggle_ref);
return;
} }
RE::TESObjectREFR * prev_ref = merchant_shelf->GetLinkedRef(prev_keyword); RE::TESObjectREFR * prev_ref = merchant_shelf->GetLinkedRef(prev_keyword);
if (!prev_ref) { if (!prev_ref) {
logger::error("LoadMerchandise prev_ref is null!"); logger::error("LoadMerchandise prev_ref is null!");
regMap.SendEvent(false); failReg.SendEvent("Could not find the shelf's previous button");
regMap.Unregister(toggle_ref); successReg.Unregister(toggle_ref);
return false; failReg.Unregister(toggle_ref);
return;
} }
toggle_ref->SetDisplayName("Clear merchandise", true); toggle_ref->SetDisplayName("Clear merchandise", true);
if (page == max_page) { if (page == max_page) {
next_ref->SetDisplayName("(No next page)", true); next_ref->SetDisplayName("(No next page)", true);
} } else {
else {
next_ref->SetDisplayName(fmt::format("Advance to page {:d}", page + 1).c_str(), true); next_ref->SetDisplayName(fmt::format("Advance to page {:d}", page + 1).c_str(), true);
} }
if (page == 1) { if (page == 1) {
prev_ref->SetDisplayName("(No previous page)", true); prev_ref->SetDisplayName("(No previous page)", true);
} } else {
else {
prev_ref->SetDisplayName(fmt::format("Back to page {:d}", page - 1).c_str(), true); prev_ref->SetDisplayName(fmt::format("Back to page {:d}", page - 1).c_str(), true);
} }
} } else {
else {
const char * error = result.AsErr(); const char * error = result.AsErr();
logger::error(FMT_STRING("LoadMerchandise get_merchandise_list error: {}"), error); logger::error(FMT_STRING("LoadMerchandise get_merchandise_list error: {}"), error);
regMap.SendEvent(false); failReg.SendEvent(RE::BSFixedString(error));
regMap.Unregister(toggle_ref); successReg.Unregister(toggle_ref);
return false; failReg.Unregister(toggle_ref);
return;
} }
regMap.SendEvent(true); successReg.SendEvent(true);
regMap.Unregister(toggle_ref); successReg.Unregister(toggle_ref);
failReg.Unregister(toggle_ref);
}); });
return true;
} }
bool ToggleMerchandise( bool ToggleMerchandise(
@ -305,8 +303,8 @@ bool ToggleMerchandise(
RE::BGSKeyword* item_keyword, RE::BGSKeyword* item_keyword,
RE::BGSKeyword* toggle_keyword, RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword, RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword) RE::BGSKeyword* prev_keyword
{ ) {
if (!merchant_shelf) { if (!merchant_shelf) {
logger::error("ToggleMerchandise merchant_shelf is null!"); logger::error("ToggleMerchandise merchant_shelf is null!");
return false; return false;
@ -345,8 +343,7 @@ bool ToggleMerchandise(
next_ref->SetDisplayName("Load merchandise", true); next_ref->SetDisplayName("Load merchandise", true);
prev_ref->SetDisplayName("Load merchandise", true); prev_ref->SetDisplayName("Load merchandise", true);
return true; return true;
} } else {
else {
// Load merchandise // Load merchandise
int page = merchant_shelf->extraList.GetCount(); int page = merchant_shelf->extraList.GetCount();
std::thread thread(LoadMerchandiseImpl, api_url, api_key, merchandise_list_id, merchant_shelf, placeholder_static, shelf_keyword, chest_keyword, item_keyword, toggle_keyword, next_keyword, prev_keyword, page); std::thread thread(LoadMerchandiseImpl, api_url, api_key, merchandise_list_id, merchant_shelf, placeholder_static, shelf_keyword, chest_keyword, item_keyword, toggle_keyword, next_keyword, prev_keyword, page);
@ -367,8 +364,8 @@ bool LoadNextMerchandise(
RE::BGSKeyword* item_keyword, RE::BGSKeyword* item_keyword,
RE::BGSKeyword* toggle_keyword, RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword, RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword) RE::BGSKeyword* prev_keyword
{ ) {
if (!merchant_shelf) { if (!merchant_shelf) {
logger::error("LoadNextMerchandise merchant_shelf is null!"); logger::error("LoadNextMerchandise merchant_shelf is null!");
return false; return false;
@ -398,8 +395,8 @@ bool LoadPrevMerchandise(
RE::BGSKeyword* item_keyword, RE::BGSKeyword* item_keyword,
RE::BGSKeyword* toggle_keyword, RE::BGSKeyword* toggle_keyword,
RE::BGSKeyword* next_keyword, RE::BGSKeyword* next_keyword,
RE::BGSKeyword* prev_keyword) RE::BGSKeyword* prev_keyword
{ ) {
if (!merchant_shelf) { if (!merchant_shelf) {
logger::error("LoadPrevMerchandise merchant_shelf is null!"); logger::error("LoadPrevMerchandise merchant_shelf is null!");
return false; return false;
@ -431,8 +428,7 @@ bool ReplaceMerch3D(RE::StaticFunctionTag*, RE::TESObjectREFR* merchant_shelf, R
RE::TESObjectCELL * cell = merchant_shelf->GetParentCell(); RE::TESObjectCELL * cell = merchant_shelf->GetParentCell();
RE::FormID placeholder_form_id = placeholder_static->GetFormID(); RE::FormID placeholder_form_id = placeholder_static->GetFormID();
RE::FormID shelf_form_id = merchant_shelf->GetFormID(); RE::FormID shelf_form_id = merchant_shelf->GetFormID();
for (auto entry = cell->references.begin(); entry != cell->references.end(); ++entry) for (auto entry = cell->references.begin(); entry != cell->references.end(); ++entry) {
{
RE::TESObjectREFR * ref = (*entry).get(); RE::TESObjectREFR * ref = (*entry).get();
RE::TESBoundObject * base = ref->GetBaseObject(); RE::TESBoundObject * base = ref->GetBaseObject();
if (base) { if (base) {
@ -447,8 +443,7 @@ bool ReplaceMerch3D(RE::StaticFunctionTag*, RE::TESObjectREFR* merchant_shelf, R
if (linked_ref->Is3DLoaded()) { if (linked_ref->Is3DLoaded()) {
logger::info("ReplaceMerch3D replaceing placeholder 3D with linked item 3D"); logger::info("ReplaceMerch3D replaceing placeholder 3D with linked item 3D");
ref->Set3D(linked_ref->GetCurrent3D()); ref->Set3D(linked_ref->GetCurrent3D());
} } else {
else {
logger::info("ReplaceMerch3D linked item ref 3D is not loaded yet, returning false"); logger::info("ReplaceMerch3D linked item ref 3D is not loaded yet, returning false");
return false; return false;
} }
@ -472,30 +467,28 @@ RE::TESForm * BuyMerchandise(RE::StaticFunctionTag*, RE::TESObjectREFR * merchan
return owner; return owner;
} }
// Return code: void CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest) {
// -2: No changes to save, no create request was made
// -1: Error occured
// >= 0: ID of created MerchandiseList returned by API
int CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest)
{
logger::info("Entered CreateMerchandiseListImpl"); logger::info("Entered CreateMerchandiseListImpl");
RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton(); RE::TESDataHandler * data_handler = RE::TESDataHandler::GetSingleton();
std::vector<MerchRecord> merch_records; std::vector<RawMerchandise> merch_records;
if (!merchant_chest) { if (!merchant_chest) {
logger::error("CreateMerchandiseList merchant_chest is null!"); logger::error("CreateMerchandiseListImpl merchant_chest is null!");
return -1; return;
} }
SKSE::RegistrationMap<int> regMap = SKSE::RegistrationMap<int>(); SKSE::RegistrationMap<bool, int> successReg = SKSE::RegistrationMap<bool, int>();
regMap.Register(merchant_chest, RE::BSFixedString("OnCreateMerchandise")); successReg.Register(merchant_chest, RE::BSFixedString("OnCreateMerchandiseSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(merchant_chest, RE::BSFixedString("OnCreateMerchandiseFail"));
RE::InventoryChanges * inventory_changes = merchant_chest->GetInventoryChanges(); RE::InventoryChanges * inventory_changes = merchant_chest->GetInventoryChanges();
if (inventory_changes == nullptr) { if (inventory_changes == nullptr) {
logger::info("CreateMerchandiseList container empty, nothing to save"); logger::info("CreateMerchandiseList container empty, nothing to save");
regMap.SendEvent(-2); successReg.SendEvent(false, -1);
regMap.Unregister(merchant_chest); successReg.Unregister(merchant_chest);
return -2; failReg.Unregister(merchant_chest);
return;
} }
RE::BSSimpleList<RE::InventoryEntryData*>* entries = inventory_changes->entryList; RE::BSSimpleList<RE::InventoryEntryData*>* entries = inventory_changes->entryList;
@ -505,6 +498,7 @@ int CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_k
RE::InventoryEntryData * entry_data = *entry; RE::InventoryEntryData * entry_data = *entry;
RE::TESBoundObject * base = entry_data->GetObject(); RE::TESBoundObject * base = entry_data->GetObject();
if (base) { if (base) {
// Iterating through the entries extraList for debug logging info
RE::BSSimpleList<RE::ExtraDataList*> * x_lists = entry_data->extraLists; RE::BSSimpleList<RE::ExtraDataList*> * x_lists = entry_data->extraLists;
if (x_lists) { if (x_lists) {
const char * entry_name = entry_data->extraLists->front()->GetDisplayName(base); const char * entry_name = entry_data->extraLists->front()->GetDisplayName(base);
@ -562,11 +556,18 @@ int CreateMerchandiseListImpl(RE::BSFixedString api_url, RE::BSFixedString api_k
count++; count++;
} }
int merchandise_list_id = create_merchandise_list(api_url.c_str(), api_key.c_str(), shop_id, &merch_records[0], merch_records.size()); FFIResult<int32_t> result = create_merchandise_list(api_url.c_str(), api_key.c_str(), shop_id, &merch_records[0], merch_records.size());
logger::info(FMT_STRING("CreateMerchandiseList create_merchandise_list result: {:d}"), merchandise_list_id); if (result.IsOk()) {
regMap.SendEvent(merchandise_list_id); int32_t merchandise_list_id = result.AsOk();
regMap.Unregister(merchant_chest); logger::info(FMT_STRING("CreateMerchandiseList success: {}"), merchandise_list_id);
return merchandise_list_id; successReg.SendEvent(true, merchandise_list_id);
} else {
const char* error = result.AsErr();
logger::error(FMT_STRING("CreateMerchandiseList failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error));
}
successReg.Unregister(merchant_chest);
failReg.Unregister(merchant_chest);
} }
bool CreateMerchandiseList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest) { bool CreateMerchandiseList(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t shop_id, RE::TESObjectREFR* merchant_chest) {

View File

@ -1,25 +1,30 @@
#include "bindings.h" #include "bindings.h"
int CreateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) void CreateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
{
logger::info("Entered CreateOwnerImpl"); logger::info("Entered CreateOwnerImpl");
if (!quest) { if (!quest) {
logger::error("CreateOwner quest is null!"); logger::error("CreateOwnerImpl quest is null!");
return -1; return;
} }
SKSE::RegistrationMap<int> regMap = SKSE::RegistrationMap<int>(); SKSE::RegistrationMap<int> successReg = SKSE::RegistrationMap<int>();
regMap.Register(quest, RE::BSFixedString("OnCreateOwner")); successReg.Register(quest, RE::BSFixedString("OnCreateOwnerSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnCreateOwnerFail"));
logger::info(FMT_STRING("CreateOwner api_url: {}"), api_url); logger::info(FMT_STRING("CreateOwner api_url: {}, api_key: {}, name: {}, mod_version: {}"), api_url, api_key, name, mod_version);
logger::info(FMT_STRING("CreateOwner api_key: {}"), api_key); FFIResult<RawOwner> result = create_owner(api_url.c_str(), api_key.c_str(), name.c_str(), mod_version);
logger::info(FMT_STRING("CreateOwner name: {}"), name); if (result.IsOk()) {
logger::info(FMT_STRING("CreateOwner mod_version: {}"), mod_version); RawOwner owner = result.AsOk();
int owner_id = create_owner(api_url.c_str(), api_key.c_str(), name.c_str(), mod_version); logger::info(FMT_STRING("CreateOwner success: {}"), owner.id);
logger::info(FMT_STRING("CreateOwner result: {}"), owner_id); successReg.SendEvent(owner.id);
regMap.SendEvent(owner_id); } else {
regMap.Unregister(quest); RE::BSFixedString error = result.AsErr();
return owner_id; logger::info(FMT_STRING("CreateOwner failure: {}"), error);
failReg.SendEvent(error);
}
successReg.Unregister(quest);
failReg.Unregister(quest);
} }
bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) { bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
@ -34,30 +39,35 @@ bool CreateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedS
return true; return true;
} }
int UpdateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) void UpdateOwnerImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
{
logger::info("Entered UpdateOwnerImpl"); logger::info("Entered UpdateOwnerImpl");
if (!quest) { if (!quest) {
logger::error("UpdateOwner quest is null!"); logger::error("UpdateOwnerImpl quest is null!");
return -1; return;
} }
SKSE::RegistrationMap<int> regMap = SKSE::RegistrationMap<int>(); SKSE::RegistrationMap<int> successReg = SKSE::RegistrationMap<int>();
regMap.Register(quest, RE::BSFixedString("OnUpdateOwner")); successReg.Register(quest, RE::BSFixedString("OnUpdateOwnerSuccess"));
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnUpdateOwnerFail"));
logger::info(FMT_STRING("UpdateOwner api_url: {}"), api_url); logger::info(FMT_STRING("UpdateOwner api_url: {}, api_key: {}, name: {}, mod_version: {}"), api_url, api_key, name, mod_version);
logger::info(FMT_STRING("UpdateOwner api_key: {}"), api_key); FFIResult<RawOwner> result = update_owner(api_url.c_str(), api_key.c_str(), id, name.c_str(), mod_version);
logger::info(FMT_STRING("UpdateOwner name: {}"), name); if (result.IsOk()) {
logger::info(FMT_STRING("UpdateOwner mod_version: {}"), mod_version); RawOwner owner = result.AsOk();
int owner_id = update_owner(api_url.c_str(), api_key.c_str(), id, name.c_str(), mod_version); logger::info(FMT_STRING("UpdateOwner success: {}"), owner.id);
logger::info(FMT_STRING("UpdateOwner result: {}"), owner_id); successReg.SendEvent(owner.id);
regMap.SendEvent(owner_id); } else {
regMap.Unregister(quest); RE::BSFixedString error = result.AsErr();
return owner_id; logger::info(FMT_STRING("UpdateOwner failure: {}"), error);
failReg.SendEvent(error);
}
successReg.Unregister(quest);
failReg.Unregister(quest);
} }
bool UpdateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) { bool UpdateOwner(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, uint32_t mod_version, RE::TESQuest* quest) {
logger::info("Entered CreateOwner"); logger::info("Entered UpdateOwner");
if (!quest) { if (!quest) {
logger::error("UpdateOwner quest is null!"); logger::error("UpdateOwner quest is null!");
return false; return false;

View File

@ -1,10 +1,9 @@
#include "bindings.h" #include "bindings.h"
void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
{
logger::info("Entered CreateShopImpl"); logger::info("Entered CreateShopImpl");
if (!quest) { if (!quest) {
logger::error("CreateShop quest is null!"); logger::error("CreateShopImpl quest is null!");
return; return;
} }
@ -13,19 +12,15 @@ void CreateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, RE::BS
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnCreateShopFail")); failReg.Register(quest, RE::BSFixedString("OnCreateShopFail"));
logger::info(FMT_STRING("CreateShop api_url: {}"), api_url); logger::info(FMT_STRING("CreateShop api_url: {}, api_key: {}, name: {}, description: {}"), api_url, api_key, name, description);
logger::info(FMT_STRING("CreateShop api_key: {}"), api_key); FFIResult<RawShop> result = create_shop(api_url.c_str(), api_key.c_str(), name.c_str(), description.c_str());
logger::info(FMT_STRING("CreateShop name: {}"), name);
logger::info(FMT_STRING("CreateShop description: {}"), description);
FFIResult<ShopRecord> result = create_shop(api_url.c_str(), api_key.c_str(), name.c_str(), description.c_str());
if (result.IsOk()) { if (result.IsOk()) {
ShopRecord shop = result.AsOk(); RawShop shop = result.AsOk();
logger::info(FMT_STRING("CreateShop result Ok: {:d}"), shop.id); logger::info(FMT_STRING("CreateShop success: {}"), shop.id);
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description)); successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description));
} } else {
else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("CreateShop result Err: {}"), error); logger::error(FMT_STRING("CreateShop failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error)); failReg.SendEvent(RE::BSFixedString(error));
} }
successReg.Unregister(quest); successReg.Unregister(quest);
@ -44,11 +39,10 @@ bool CreateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedSt
return true; return true;
} }
void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::BSFixedString name, RE::BSFixedString description, RE::TESQuest* quest) {
{
logger::info("Entered UpdateShopImpl"); logger::info("Entered UpdateShopImpl");
if (!quest) { if (!quest) {
logger::error("UpdateShop quest is null!"); logger::error("UpdateShopImpl quest is null!");
return; return;
} }
@ -57,19 +51,15 @@ void UpdateShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32
SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>(); SKSE::RegistrationMap<RE::BSFixedString> failReg = SKSE::RegistrationMap<RE::BSFixedString>();
failReg.Register(quest, RE::BSFixedString("OnUpdateShopFail")); failReg.Register(quest, RE::BSFixedString("OnUpdateShopFail"));
logger::info(FMT_STRING("UpdateShop api_url: {}"), api_url); logger::info(FMT_STRING("UpdateShop api_url: {}, api_key: {}, name: {}, description: {}"), api_url, api_key, name, description);
logger::info(FMT_STRING("UpdateShop api_key: {}"), api_key); FFIResult<RawShop> result = update_shop(api_url.c_str(), api_key.c_str(), id, name.c_str(), description.c_str());
logger::info(FMT_STRING("UpdateShop name: {}"), name);
logger::info(FMT_STRING("UpdateShop description: {}"), description);
FFIResult<ShopRecord> result = update_shop(api_url.c_str(), api_key.c_str(), id, name.c_str(), description.c_str());
if (result.IsOk()) { if (result.IsOk()) {
ShopRecord shop = result.AsOk(); RawShop shop = result.AsOk();
logger::info(FMT_STRING("UpdateShop result Ok: {:d}"), shop.id); logger::info(FMT_STRING("UpdateShop success: {}"), shop.id);
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description)); successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description));
} } else {
else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("UpdateShop result Err: {}"), error); logger::error(FMT_STRING("UpdateShop failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error)); failReg.SendEvent(RE::BSFixedString(error));
} }
successReg.Unregister(quest); successReg.Unregister(quest);
@ -88,11 +78,10 @@ bool UpdateShop(RE::StaticFunctionTag*, RE::BSFixedString api_url, RE::BSFixedSt
return true; return true;
} }
void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::TESQuest* quest) void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t id, RE::TESQuest* quest) {
{
logger::info("Entered GetShopImpl"); logger::info("Entered GetShopImpl");
if (!quest) { if (!quest) {
logger::error("GetShop quest is null!"); logger::error("GetShopImpl quest is null!");
return; return;
} }
@ -103,15 +92,14 @@ void GetShopImpl(RE::BSFixedString api_url, RE::BSFixedString api_key, uint32_t
logger::info(FMT_STRING("GetShop api_url: {}"), api_url); logger::info(FMT_STRING("GetShop api_url: {}"), api_url);
logger::info(FMT_STRING("GetShop api_key: {}"), api_key); logger::info(FMT_STRING("GetShop api_key: {}"), api_key);
FFIResult<ShopRecord> result = get_shop(api_url.c_str(), api_key.c_str(), id); FFIResult<RawShop> result = get_shop(api_url.c_str(), api_key.c_str(), id);
if (result.IsOk()) { if (result.IsOk()) {
ShopRecord shop = result.AsOk(); RawShop shop = result.AsOk();
logger::info(FMT_STRING("GetShop result Ok: {:d}"), shop.id); logger::info(FMT_STRING("GetShop success: {}"), shop.id);
successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description)); successReg.SendEvent(shop.id, RE::BSFixedString(shop.name), RE::BSFixedString(shop.description));
} } else {
else {
const char* error = result.AsErr(); const char* error = result.AsErr();
logger::error(FMT_STRING("GetShop result Err: {}"), error); logger::error(FMT_STRING("GetShop failure: {}"), error);
failReg.SendEvent(RE::BSFixedString(error)); failReg.SendEvent(RE::BSFixedString(error));
} }
successReg.Unregister(quest); successReg.Unregister(quest);