Cleaned up Item recieve code and removed old AP mappings

This commit is contained in:
Jerom Venneker
2025-05-23 00:34:27 +02:00
parent b24abb4ae4
commit 108cc3b24d
11 changed files with 33 additions and 2002 deletions

View File

@@ -71,3 +71,4 @@ DEFINE_HOOK(OnAssetAltChange, ());
DEFINE_HOOK(OnKaleidoUpdate, ());
DEFINE_HOOK(OnRandomizerItemGivenHooks, (uint32_t rc));
DEFINE_HOOK(OnArchipelagoItemRecieved, (uint32_t rc));

View File

@@ -307,3 +307,8 @@ void GameInteractor_ExecuteOnKaleidoUpdate() {
void GameInteractor_ExecuteOnRandomizerItemGivenHooks(uint32_t rc) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnRandomizerItemGivenHooks>(rc);
}
// MARK: Archipelago
void GameInteractor_ExecuteOnArchipelagoItemRecieved(uint32_t rc) {
GameInteractor::Instance->ExecuteHooks<GameInteractor::OnArchipelagoItemRecieved>(rc);
}

View File

@@ -84,6 +84,9 @@ void GameInteractor_ExecuteOnKaleidoUpdate();
// Mark: - Randomizer
void GameInteractor_ExecuteOnRandomizerItemGivenHooks(uint32_t rc);
// Mark: - Archipelago
void GameInteractor_ExecuteOnArchipelagoItemRecieved(uint32_t rc);
#ifdef __cplusplus
}
#endif

View File

@@ -346,9 +346,9 @@ void Context::SetSpoilerLoaded(const bool spoilerLoaded) {
mSpoilerLoaded = spoilerLoaded;
}
void Context::AddRecievedArchipelagoItem(const std::string& ap_item_id) {
mAPrecieveQueue.emplace(ap_item_id);
std::string logMessage = "[LOG] Item Pushed: " + ap_item_id;
void Context::AddRecievedArchipelagoItem(const RandomizerGet item) {
mAPrecieveQueue.emplace(item);
std::string logMessage = "[LOG] Item Pushed: " + item;
ArchipelagoConsole_SendMessage(logMessage.c_str());
}
@@ -360,13 +360,11 @@ GetItemEntry Context::GetArchipelagoGIEntry() {
}
// get the first item from the archipelago queue
std::string recieved_ap_item = mAPrecieveQueue.front();
RandomizerGet item_id = StaticData::itemNameToEnum[recieved_ap_item];
//RandomizerGet item_id = StaticData::APitemToSoh[recieved_ap_item];
RandomizerGet item_id = mAPrecieveQueue.front();
assert(item_id != RG_NONE);
Item& item = StaticData::RetrieveItem(item_id);
SPDLOG_TRACE("Found item! {}, {}", recieved_ap_item, (int)item_id);
SPDLOG_TRACE("Found item! {}, {}", item.GetName().GetEnglish(), (int)item_id);
GetItemEntry item_entry = item.GetGIEntry_Copy();
mAPrecieveQueue.pop();
return item_entry; // todo: add custom text maybe?

View File

@@ -107,7 +107,7 @@ class Context {
*/
RandoOptionLACSCondition LACSCondition() const;
GetItemEntry GetFinalGIEntry(RandomizerCheck rc, bool checkObtainability = true, GetItemID ogItemId = GI_NONE);
void AddRecievedArchipelagoItem(const std::string& ap_item_id);
void AddRecievedArchipelagoItem(const RandomizerGet item);
GetItemEntry GetArchipelagoGIEntry();
void ParseSpoiler(const char* spoilerFileName);
void ParseHashIconIndexesJson(nlohmann::json spoilerFileJson);
@@ -189,6 +189,6 @@ class Context {
std::string mHash;
std::string mSeedString;
uint32_t mFinalSeed = 0;
std::queue<std::string> mAPrecieveQueue = {};
std::queue<RandomizerGet> mAPrecieveQueue = {};
};
} // namespace Rando

View File

@@ -16,7 +16,6 @@
#include "soh/Notification/Notification.h"
#include "soh/SaveManager.h"
#include "soh/Enhancements/randomizer/ShuffleFairies.h"
#include "soh/Network/Archipelago/Archipelago.h"
#include "soh/Network/Archipelago/ArchipelagoConsoleWindow.h"
extern "C" {
@@ -223,11 +222,11 @@ static std::queue<RandomizerCheck> randomizerQueuedChecks;
static RandomizerCheck randomizerQueuedCheck = RC_UNKNOWN_CHECK;
static GetItemEntry randomizerQueuedItemEntry = GET_ITEM_NONE;
void ArchipelagoOnRecieveItem(const std::string& ap_item_name) {
std::string logMessage = "[LOG] Receive item handler called: " + ap_item_name;
ArchipelagoConsole_SendMessage(logMessage.c_str());
void ArchipelagoOnRecieveItem(const int32_t item) {
std::string logMessage = "[LOG] Receive item handler called: " + item;
ArchipelagoConsole_SendMessage(logMessage.c_str(), true);
randomizerQueuedChecks.push(RC_ARCHIPELAGO_RECIEVED_ITEM);
Rando::Context::GetInstance()->AddRecievedArchipelagoItem(ap_item_name);
Rando::Context::GetInstance()->AddRecievedArchipelagoItem(static_cast<RandomizerGet>(item));
}
void RandomizerOnFlagSetHandler(int16_t flagType, int16_t flag) {
@@ -2443,7 +2442,7 @@ void RandomizerRegisterHooks() {
GameInteractor::Instance->UnregisterGameHook<GameInteractor::OnVanillaBehavior>(
shuffleFreestandingOnVanillaBehaviorHook);
ArchipelagoClient::GetInstance().RemoveItemRecievedCallback(ArchipelagoOnRecieveItem);
onFlagSetHook = 0;
onSceneFlagSetHook = 0;
@@ -2525,6 +2524,11 @@ void RandomizerRegisterHooks() {
RandomizerOnKaleidoscopeUpdateHandler);
onCuccoOrChickenHatchHook = GameInteractor::Instance->RegisterGameHook<GameInteractor::OnCuccoOrChickenHatch>(
RandomizerOnCuccoOrChickenHatch);
// TODO Implement propeerly when we can read what kind of game we're playing from the save file
#define IS_ARCHIPELAGO true
COND_HOOK(GameInteractor::OnArchipelagoItemRecieved, IS_ARCHIPELAGO, ArchipelagoOnRecieveItem);
if (RAND_GET_OPTION(RSK_FISHSANITY) != RO_FISHSANITY_OFF) {
OTRGlobals::Instance->gRandoContext->GetFishsanity()->InitializeFromSave();
@@ -2559,7 +2563,5 @@ void RandomizerRegisterHooks() {
if (RAND_GET_OPTION(RSK_SHUFFLE_FAIRIES)) {
ShuffleFairies_RegisterHooks();
}
ArchipelagoClient::GetInstance().AddItemRecievedCallback(ArchipelagoOnRecieveItem);
});
}

View File

@@ -2907,94 +2907,7 @@ void Settings::ParseJson(nlohmann::json spoilerFileJson) {
}
void Settings::ParseArchipelago(const std::map<std::string, int>& slot_data) {
for(const auto& slot_it : slot_data) {
const std::string& APname = slot_it.first;
int value = slot_it.second;
// remap value if needed
if(APname == "open_forest") {
if(value == 0) { // open and closed options swapped
value = 2;
} else if (value == 2) {
value = 0;
}
}
if(APname == "open_kakoriko") {
if(value == 2) {
value = 0; // closed
} else {
value = 1; // count the "zelda" option as open
}
}
else if(APname == "open_door_of_time") {
if(value == 1) {
value = 2; // AP doesn't have the song only option
}
}
else if(APname == "zora_fountain") {
if(value == 0) { // open and closed options swapped
value = 2;
} else if (value == 2) {
value = 0;
}
}
else if(APname == "bridge") {
if(value == 0) { // always open and vanilla are swapped
value = 1;
} else if (value == 1) {
value = 0;
} else if (value == 6) { // no support for ap hearts option
value = 1; // revert to always open so its at least beatable
} else if (value == 5) {
value++; // Token option is one over, because AP doesn't have dungeon blue warp count as option
}
}
else if(APname == "shopsanity_prices") {
value = 1; // default shopsanity to cheap ballanced for now
}
else if(APname == "start_with_consumables") { // just setting this shouldn't magically work I think
if(value == 1) {
const RandomizerSettingKey stick_index = StaticData::optionNameToEnum["Start with Stick Ammo"];
mContext->GetOption(stick_index).Set(mOptions[stick_index].GetValueFromText("Yes"));
const RandomizerSettingKey nut_index = StaticData::optionNameToEnum["Start with Stick Ammo"];
mContext->GetOption(nut_index).Set(mOptions[nut_index].GetValueFromText("Yes"));
} else {
const RandomizerSettingKey stick_index = StaticData::optionNameToEnum["Start with Stick Ammo"];
mContext->GetOption(stick_index).Set(mOptions[stick_index].GetValueFromText("No"));
const RandomizerSettingKey nut_index = StaticData::optionNameToEnum["Start with Stick Ammo"];
mContext->GetOption(nut_index).Set(mOptions[nut_index].GetValueFromText("No"));
}
}
const std::string& setting_name = std::string(StaticData::APsettingToHoSsetting[APname]);
const RandomizerSettingKey index = StaticData::optionNameToEnum[setting_name];
mContext->GetOption(index).Set(value);
std::string logMessage = "[LOG] Parsed Setting " + APname + ": (" + std::to_string((int)index) + ", " + std::to_string(value) + ")";
ArchipelagoConsole_SendMessage(logMessage.c_str());
}
// maybe we have to set a couple of settings manually, if ap doesn't set them
{
//const RandomizerSettingKey index = StaticData::optionNameToEnum["Starting Age"];
//mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Random"));
}
{
const RandomizerSettingKey index = StaticData::optionNameToEnum["Ganon's Trials"];
mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Set Number"));
}
{
const RandomizerSettingKey index = StaticData::optionNameToEnum["Logic"];
mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Glitchless"));
}
{
const RandomizerSettingKey index = StaticData::optionNameToEnum["Starting Hearts"];
mContext->GetOption(index).Set(2);
}
{
const RandomizerSettingKey index = StaticData::optionNameToEnum["Token Shuffle"];
mContext->GetOption(index).Set(mOptions[index].GetValueFromText("Off"));
}
//const RandomizerSettingKey index = StaticData::optionNameToEnum["Sleeping Waterfall"];
//mContext->GetOption(index).Set(0);
// This is going to be completely redone since switching to apclientpp
}
void Settings::AssignContext(std::shared_ptr<Context> ctx) {

View File

@@ -1,7 +1,6 @@
#include <unordered_map>
#include "static_data.h"
#include <spdlog/spdlog.h>
#include "soh/Network/Archipelago/ArchipelagoMappings.h"
namespace Rando {
@@ -306,109 +305,4 @@ std::unordered_map<u32, RandomizerHint> StaticData::grottoChestParamsToHint{
std::array<HintText, RHT_MAX> StaticData::hintTextTable = {};
const std::unordered_map<std::string_view, RandomizerGet>generate_APitemToSoh_mapping() {
std::unordered_map<std::string_view, RandomizerGet> mapping;
for(const auto& pairing : ap_item_mapping_pairs) {
mapping[pairing.first] = pairing.second;
}
return mapping;
}
const std::unordered_map<std::string_view, RandomizerCheck>generate_APcheckToSoh_mapping() {
std::unordered_map<std::string_view, RandomizerCheck> mapping;
for(const auto& pairing : ap_check_mapping_pairs) {
mapping[pairing.first] = pairing.second;
}
return mapping;
}
const std::unordered_map<RandomizerCheck, std::string_view>generate_SohcheckToAP_mapping() {
std::unordered_map<RandomizerCheck, std::string_view> mapping;
for(const auto& pairing : ap_check_mapping_pairs) {
mapping[pairing.second] = pairing.first;
}
return mapping;
}
std::unordered_map<std::string_view, RandomizerGet> StaticData::APitemToSoh = generate_APitemToSoh_mapping();
std::unordered_map<std::string_view, RandomizerCheck> StaticData::APcheckToSoh = generate_APcheckToSoh_mapping();
std::unordered_map<RandomizerCheck, std::string_view> StaticData::SohCheckToAP = generate_SohcheckToAP_mapping();
std::unordered_map<std::string_view, std::string_view> StaticData::APsettingToHoSsetting = {
{ "open_forest", "Closed Forest" },
{ "open_kakoriko", "Kakariko Gate" },
{ "open_door_of_time", "Door of Time" },
{ "zora_fountain", "Zora's Fountain" },
{ "gerudo_fortress", "Fortress Carpenters" },
{ "bridge", "Rainbow Bridge" }, // TODO underlying options may not overlap
{ "bridge_stones", "Bridge Stone Count" },
{ "bridge_medallions", "Bridge Medallion Count" },
{ "bridge_rewards", "Bridge Reward Count" },
{ "bridge_tokens", "Bridge Token Count" },
{ "bridge_hearts", "NOT_SUPPORTED" },
{ "shuffle_ganon_bosskey", "Ganon's Boss Key" },
{ "ganon_bosskey_medallions", "GCBK Medallion Count" },
{ "ganon_bosskey_stones", "GCBK Stone Count" },
{ "ganon_bosskey_rewards", "GCBK Reward Count" },
{ "ganon_bosskey_tokens", "GCBK Token Count" },
{ "ganon_bosskey_hearts", "NOT_SUPPORTED" },
{ "trials", "Ganon's Trials Count" },
{ "triforce_hunt", "Triforce Hunt" },
{ "triforce_goal", "Triforce Hunt Required Pieces" },
{ "extra_triforce_percentage", "CUSTOM_IMPLEMENTATION" }, // TODO calc "Triforce Hunt Required Pieces" from percentage, Actually not really required to make the game run I think
{ "shopsanity", "Shop Shuffle" },
{ "shop_slots", "Shops Item Count" },
{ "shopsanity_prices", "Shops Prices" }, // Item Prizes not in slot data, anything above starting wallet will be lowered to max 99
{ "tokensanity", "Token Shuffle" },
{ "dungeon_shortcuts", "NOT_SUPPORTED" }, // TODO could be implemented manually through
{ "mq_dungeons_mode", "NOT_SUPORTED" }, // Not sure if we can figure this one out
{ "mq_dungeons_count", "NOT_SUPPORTED" }, // Slot data doesn't expose the master quest dungeons used
{ "shuffle_interior_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data
{ "shuffle_grotto_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data
{ "shuffle_dungeon_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data
{ "shuffle_overworld_entrances", "NOT_SUPPORTED" }, // Mapping not in Slot Data
{ "shuffle_bosses", "NOT_SUPPORTED" }, // Mapping not in Slot Data
{ "key_rings", "Key Rings" }, // slot data not exposed when set to random, however may not matter if you just can just recieve the key ring, may only be needed for logic
{ "enhance_map_compass", "NOT_SUPPORTED" }, // Can't find it in rando settings, may be a qol setting
{ "shuffle_mapcompass", "Maps/Compasses" }, // NOT REQUIRED
{ "shuffle_smallkeys", "Small Key Shuffle" }, // NOT REQUIRED
{ "shuffle_hideoutkeys", "Gerudo Fortress Keys" }, // NOT REQUIRED
{ "shuffle_bosskeys", "Boss Key Shuffle" }, // NOT REQUIRED
{ "logic_rules", "Logic" }, // NOT REQUIRED
{ "logic_no_night_tokens_without_suns_song", "Night Skulltula's Expect Sun's Song" }, // NOT REQUIRED
{ "warp_songs", "NOT_SUPORTED" }, // slot data not exposed
{ "shuffle_song_items", "Shuffle Songs" }, // NOT REQUIRED
{ "shuffle_medigoron_carpet_salesman", "NOT_SUPPORTED" }, // NOT REQURIED, , Should set "Shuffle Merchants" option (This option also sets granny)
{ "shuffle_frog_song_rupees", "Shuffle Frog Song Rupees" }, // NOT REQUIRED
{ "shuffle_scrubs", "Scrubs Shuffle" }, // NOT REQUIRED
{ "shuffle_child_trade", "NOT_SUPPORTED" }, // NOT REQUIRED
{ "shuffle_freestanding_items", "NOT_SUPPORTED" }, // NOT REQUIRED
{ "shuffle_pots", "Shuffle Pots" }, // NOT REQUIRED
{ "shuffle_crates", "MAYBE_SUPPORTED_TODO" }, // Maybe Requred, TODO TEST
{ "shuffle_cows", "Shuffle Cows" }, // NOT REQUIRED
{ "shuffle_beehives", "Shuffle Beehives" }, // NOT REQUIRED
{ "shuffle_kokiri_sword", "Shuffle Kokiri Sword" }, // NOT REQUIRED
{ "shuffle_ocarinas", "Shuffle Ocarinas" }, // NOT REQUIRED
{ "shuffle_gerudo_card", "Shuffle Gerudo Membership Card" }, //NOT REQUIRED
{ "shuffle_beans", "NOT_SUPPORTED" }, // NOT REQUIRED, Should set "Shuffle Merchants" option (This option also sets granny)
{ "starting_age", "Selected Starting Age" }, // should this also set "Seelcted Starting Age"
{ "bombchus_in_logic", "NOT_SUPPORTED" }, // NOT REQUIRED, Probably Implemented as a trick
{ "spawn_positions", "NOT_SUPPORTED" },
{ "owl_drops", "NOT_SUPPORTRED" },
{ "no_epona_race", "Skip Epona Race" },
{ "skip_some_minigame_phases", "NOT_IMPLEMENTED" }, // should be under quality of life options
{ "complete_mask_quest", "Complete Mask Quest" },
{ "free_scarecrow", "Skip Scarecrow's Song" },
{ "plant_beans", "NOT_SUPPORTRED" },
{ "chicken_count", "Cuccos to return" },
{ "big_poe_count", "Big Poe Target Count" },
{ "fae_torch_count", "NOT_SUPPORTED" },
{ "blue_fire_arrows", "Blue Fire Arrows" },
{ "damage_multiplier", "Damage Multiplier" },
{ "deadly_bonks", "NOT_SUPPORTED" },
{ "starting_tod", "NOT_SUPPORTED" },
{ "junk_ice_traps", "Ice Traps" }, // NOT REQUIRED
{ "start_with_consumables", "CUSTOM_IMPLEMENTATION" }, // might be able to just set "Start with Stick Ammo" and "Start with Nut Ammo", TODO check starting consumables
{ "adult_trade_start", "NOT_SUPPORTED" }
};
} // namespace Rando

View File

@@ -11,6 +11,7 @@
#include "soh/Enhancements/randomizer/randomizerTypes.h"
#include "soh/Enhancements/randomizer/static_data.h"
#include "soh/Enhancements/game-interactor/GameInteractor.h"
#include "soh/Enhancements/game-interactor/GameInteractor_Hooks.h"
#include "soh/ShipInit.hpp"
ArchipelagoClient::ArchipelagoClient() {
@@ -23,7 +24,7 @@ ArchipelagoClient::ArchipelagoClient() {
CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("Connected"), 0);
// call poll every frame
GameInteractor::Instance->RegisterGameHook<GameInteractor::OnGameFrameUpdate>([](){ArchipelagoClient::GetInstance().Poll();});
COND_HOOK(GameInteractor::OnGameFrameUpdate, true, [](){ArchipelagoClient::GetInstance().Poll();})
}
ArchipelagoClient& ArchipelagoClient::GetInstance() {
@@ -132,14 +133,9 @@ void ArchipelagoClient::RemoveItemRecievedCallback(std::function<void(const std:
}
void ArchipelagoClient::OnItemReceived(int64_t recieved_item_id, bool notify_player) {
// call each callback
const std::string item_name = apClient->get_item_name(recieved_item_id, AP_Client_consts::AP_GAME_NAME);
ArchipelagoClient& ap_client = ArchipelagoClient::GetInstance();
if(ap_client.ItemRecievedCallback) {
std::string logMessage = "[LOG] Item recieved: " + item_name + ". Notify: " + std::to_string(notify_player);
ArchipelagoConsole_SendMessage(logMessage.c_str());
ap_client.ItemRecievedCallback.operator()(item_name); // somehow passing it through the itemname breaks it????
}
const RandomizerGet item = Rando::StaticData::itemNameToEnum[item_name];
GameInteractor_ExecuteOnArchipelagoItemRecieved(static_cast<int32_t>(item));
}
void ArchipelagoClient::SendGameWon() {

File diff suppressed because it is too large Load Diff

View File

@@ -57,12 +57,12 @@ void ArchipelagoSettingsWindow::DrawElement() {
}
ImGui::SameLine();
if (UIWidgets::Button("Link up", UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.0, 0.0)))) {
CVarSetInteger("ArchipelagoConnected", 1);
CVarSetInteger(CVAR_REMOTE_ARCHIPELAGO("Connected"), 1);
}
ImGui::SameLine();
if (UIWidgets::Button("Give Blue Rupee",
UIWidgets::ButtonOptions().Color(THEME_COLOR).Size(ImVec2(0.0, 0.0)))) {
ArchipelagoClient::GetInstance().OnItemReceived(66077, true);
ArchipelagoClient::GetInstance().OnItemReceived(16711816, true);
}
}
};