revise randomizerEnumStrings, include fmt compatibility (#7148)

prefer switch over map, avoids static initializer & reduces code size by over a megabyte
This commit is contained in:
Philip Dubé
2026-09-05 19:59:44 +00:00
committed by GitHub
parent 73a739b7a4
commit 495a2b17db
10 changed files with 81 additions and 102 deletions
@@ -11,8 +11,7 @@
#include "soh/Enhancements/randomizer/static_data.h"
#include "soh/Enhancements/randomizer/item.h"
#include "soh/Enhancements/randomizer/dungeon.h"
#include "soh/Enhancements/randomizer/randomizerEnums/RandomizerGet.h"
#include "soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h"
#include "soh/Enhancements/randomizer/randomizerEnumStrings.h"
#include "soh/util.h"
#include "soh/SohGui/ImGuiUtils.h"
#include "soh/OTRGlobals.h"
@@ -1368,13 +1367,24 @@ void DrawFlagArrayWithTooltips(const std::string& name, T& flags, Colors color,
ImGui::PopID();
}
static const char* GetFlagDescription(const FlagTable& flagTable, uint16_t index) {
if (flagTable.flagTableType == RANDOMIZER_INF) {
std::string_view name = EnumToString(static_cast<RandomizerInf>(index));
return name.empty() ? "" : name.data();
}
auto it = flagTable.flagDescriptions.find(index);
return it != flagTable.flagDescriptions.end() ? it->second : "";
}
// Draw a flag bitfield as a grid of checkboxes
void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& flags) {
ImGui::PushID((std::to_string(row) + flagTable.name).c_str());
for (int32_t flagIndex = 15; flagIndex >= 0; flagIndex--) {
ImGui::SameLine();
ImGui::PushID(flagIndex);
bool hasDescription = !!flagTable.flagDescriptions.contains(row * 16 + flagIndex);
uint16_t index = static_cast<uint16_t>(row * 16 + flagIndex);
const char* desc = GetFlagDescription(flagTable, index);
bool hasDescription = desc[0] != '\0';
uint32_t bitMask = 1 << flagIndex;
ImVec4 themeColor = ColorValues.at(THEME_COLOR);
ImVec4 colorDark = { themeColor.x * 0.4f, themeColor.y * 0.4f, themeColor.z * 0.4f, themeColor.z };
@@ -1396,9 +1406,7 @@ void DrawFlagTableArray16(const FlagTable& flagTable, uint16_t row, uint16_t& fl
PopStyleCheckbox();
if (ImGui::IsItemHovered()) {
ImGui::BeginTooltip();
uint16_t index = row * 16 + flagIndex;
if (hasDescription) {
const char* desc = flagTable.flagDescriptions.at(index);
ImGui::Text("0x%02X: %s", index, UIWidgets::WrappedText(desc, 60).c_str());
} else {
ImGui::Text("0x%02X: %s (Bit %d)", index, flagTable.name, flagIndex);
@@ -1470,8 +1478,7 @@ static void DrawFlagTableSearchResults(const FlagTable& flagTable, ImGuiTextFilt
for (int32_t flagIndex = 15; flagIndex >= 0; flagIndex--) {
uint16_t index = static_cast<uint16_t>(row * 16 + flagIndex);
auto descIt = flagTable.flagDescriptions.find(index);
const char* desc = descIt != flagTable.flagDescriptions.end() ? descIt->second : "";
const char* desc = GetFlagDescription(flagTable, index);
std::string searchable = spdlog::fmt_lib::format("0x{:02X} {}", index, desc);
if (!filter.PassFilter(searchable.c_str())) {
continue;
@@ -1480,7 +1487,7 @@ static void DrawFlagTableSearchResults(const FlagTable& flagTable, ImGuiTextFilt
hasMatches = true;
ImGui::PushID(index);
bool hasDescription = descIt != flagTable.flagDescriptions.end();
bool hasDescription = desc[0] != '\0';
uint32_t bitMask = 1 << flagIndex;
ImVec4 themeColor = ColorValues.at(THEME_COLOR);
ImVec4 colorDark = { themeColor.x * 0.4f, themeColor.y * 0.4f, themeColor.z * 0.4f, themeColor.z };
@@ -359,14 +359,8 @@ const std::vector<FlagTable> flagTables = {
{ 0x24, "Market Crowd Text Randomizer" },
{ 0x30, "Entered the Market" },
} },
{ "Randomizer Inf Flags",
RANDOMIZER_INF,
(RAND_INF_MAX + 15) / 16,
{
#define RANDO_ENUM_ITEM(rand_inf) { rand_inf, #rand_inf },
#include "soh/Enhancements/randomizer/randomizerEnums/RandomizerInf.h"
#undef RANDO_ENUM_ITEM
} },
// Randomizer Inf flags are described by their enum name, see GetFlagDescription.
{ "Randomizer Inf Flags", RANDOMIZER_INF, (RAND_INF_MAX + 15) / 16, {} },
};
const std::vector<std::string> state1 = {
+4 -5
View File
@@ -5,6 +5,7 @@
#include "../debugger/performanceTimer.h"
#include "soh/OTRGlobals.h"
#include "randomizer.h"
#include "randomizerEnumStrings.h"
#include "dungeon.h"
#include "SeedContext.h"
#include "randomizer.h"
@@ -322,8 +323,7 @@ bool Logic::HasItem(RandomizerGet itemName) {
default:
break;
}
SPDLOG_ERROR("HasItem reached `return false;`. Missing case for RandomizerGet of {}",
static_cast<uint32_t>(itemName));
SPDLOG_ERROR("HasItem reached `return false;`. Missing case for RandomizerGet of {}", itemName);
assert(false);
return false;
}
@@ -486,7 +486,7 @@ bool Logic::ItemUseAllowed(RandomizerGet itemName) {
case SCENE_FISHING_POND:
return itemName == RG_FISHING_POLE;
default:
SPDLOG_INFO("ItemUseAllowed reached `default` with item {} in Scene {}.", static_cast<uint32_t>(itemName),
SPDLOG_INFO("ItemUseAllowed reached `default` with item {} in Scene {}.", itemName,
static_cast<uint32_t>(RegionTable(CurrentRegionKey)->scene));
return true;
}
@@ -676,8 +676,7 @@ bool Logic::CanUse(RandomizerGet itemName) {
return true;
default:
SPDLOG_INFO("CanUse reached `default` for {}. using HasItem is a minor Optimisation.",
static_cast<uint32_t>(itemName));
SPDLOG_INFO("CanUse reached `default` for {}. using HasItem is a minor Optimisation.", itemName);
return true;
}
}
+5 -16
View File
@@ -1,6 +1,7 @@
#include <libultraship/bridge/consolevariablebridge.h>
#include "option.h"
#include "randomizerEnumStrings.h"
#include "static_data.h"
#include "soh/SohGui/SohMenu.h"
#include "soh/Enhancements/Lang/Lang.h"
@@ -70,18 +71,6 @@ RandomizerSettingKey Option::GetKey() const {
#pragma region Lang
#define RANDO_ENUM_ITEM(enum) { enum, #enum },
std::unordered_map<RandomizerSettingKey, std::string> settingNames = {
#include "randomizerEnums/RandomizerSettingKey.h"
};
std::unordered_map<RandomizerTrick, std::string> trickNames = {
#include "randomizerEnums/RandomizerTrick.h"
};
#undef RANDO_ENUM_ITEM
const static std::string namePostfix = ".name";
const static std::string descriptionPostfix = ".description";
@@ -92,13 +81,13 @@ const static std::string empty = "";
const static std::string error = "[ERROR]";
static const std::string& MakeSettingName(RandomizerSettingKey key) {
std::string settingNamePart = settingNames[key].substr(4);
std::string settingNamePart(EnumToString(key).substr(4));
std::transform(settingNamePart.begin(), settingNamePart.end(), settingNamePart.begin(), ::tolower);
return Lang::Translate((settingPrefix + settingNamePart + namePostfix).c_str());
}
static const std::string& MakeSettingDescription(RandomizerSettingKey key) {
std::string settingNamePart = settingNames[key].substr(4);
std::string settingNamePart(EnumToString(key).substr(4));
std::transform(settingNamePart.begin(), settingNamePart.end(), settingNamePart.begin(), ::tolower);
auto result = Lang::TryTranslate((settingPrefix + settingNamePart + descriptionPostfix).c_str());
if (std::holds_alternative<std::reference_wrapper<const std::string>>(result)) {
@@ -112,13 +101,13 @@ static const std::string& MakeSettingDescription(RandomizerSettingKey key) {
}
static const std::string& MakeTrickName(RandomizerTrick key) {
std::string trickNamePart = trickNames[key].substr(3);
std::string trickNamePart(EnumToString(key).substr(3));
std::transform(trickNamePart.begin(), trickNamePart.end(), trickNamePart.begin(), ::tolower);
return Lang::Translate((trickPrefix + trickNamePart + namePostfix).c_str());
}
static const std::string& MakeTrickDescription(RandomizerTrick key) {
std::string trickNamePart = trickNames[key].substr(3);
std::string trickNamePart(EnumToString(key).substr(3));
std::transform(trickNamePart.begin(), trickNamePart.end(), trickNamePart.begin(), ::tolower);
return Lang::Translate((trickPrefix + trickNamePart + descriptionPostfix).c_str());
}
@@ -0,0 +1,12 @@
// Deliberately has no include guard: define RANDO_ENUM_BEGIN/ITEM/END and include this to
// expand every enum again.
#include "randomizerEnums/LogicVal.h"
#include "randomizerEnums/RandomizerCheck.h"
#include "randomizerEnums/RandomizerGet.h"
#include "randomizerEnums/RandomizerHintTextKey.h"
#include "randomizerEnums/RandomizerInf.h"
#include "randomizerEnums/RandomizerMiscEnums.h"
#include "randomizerEnums/RandomizerOptions.h"
#include "randomizerEnums/RandomizerRegion.h"
#include "randomizerEnums/RandomizerSettingKey.h"
#include "randomizerEnums/RandomizerTrick.h"
@@ -1,35 +1,26 @@
#include "randomizerEnumStrings.h"
// Redefine enum macros to generate string->enum maps for every enum.
#define RANDO_ENUM_BEGIN(EnumName) \
template <> const std::unordered_map<std::string_view, EnumName>& GetStringToEnumMap<EnumName>() { \
static const std::unordered_map<std::string_view, EnumName> map = [] { \
std::unordered_map<std::string_view, EnumName> m;
static std::string NameOrValue(std::string_view name, std::string_view enumName, long long value) {
if (!name.empty()) {
return std::string(name);
}
return std::string(enumName) + '(' + std::to_string(value) + ')';
}
#define RANDO_ENUM_ITEM(name, ...) m.emplace(#name, name);
#define RANDO_ENUM_BEGIN(EnumName) \
std::string_view EnumToString(EnumName value) { \
switch (value) {
#define RANDO_ENUM_END(EnumName) \
return m; \
} \
(); \
return map; \
#define RANDO_ENUM_ITEM(name, ...) \
case name: \
return #name;
#define RANDO_ENUM_END(EnumName) \
} \
return {}; \
} \
std::string format_as(EnumName value) { \
return NameOrValue(EnumToString(value), #EnumName, (long long)value); \
}
#undef RANDO_ENUM_BEGIN
#undef RANDO_ENUM_ITEM
#undef RANDO_ENUM_END
// Redefine enum macros to generate enum->string maps for every enum.
#define RANDO_ENUM_BEGIN(EnumName) \
template <> const std::unordered_map<EnumName, std::string_view>& GetEnumToStringMap<EnumName>() { \
static const std::unordered_map<EnumName, std::string_view> map = [] { \
std::unordered_map<EnumName, std::string_view> m;
#define RANDO_ENUM_ITEM(name, ...) m.emplace(name, #name);
#define RANDO_ENUM_END(EnumName) \
return m; \
} \
(); \
return map; \
}
#include "randomizerEnumList.h"
@@ -1,29 +1,23 @@
#pragma once
#include <unordered_map>
#include <string>
#include <string_view>
#include <optional>
template <typename T> const std::unordered_map<std::string_view, T>& GetStringToEnumMap();
#include "randomizerEnums.h"
template <typename T> std::optional<T> StringToEnum(const std::string_view& str) {
const auto& map = GetStringToEnumMap<T>();
auto it = map.find(str);
if (it != map.end()) {
return it->second;
} else {
return std::nullopt;
}
}
template <typename T> const std::unordered_map<T, std::string_view>& GetEnumToStringMap();
template <typename T> std::optional<std::string_view> EnumToString(const T& value) {
const auto& map = GetEnumToStringMap<T>();
auto it = map.find(value);
if (it != map.end()) {
return it->second;
} else {
return std::nullopt;
}
}
// EnumToString gives an item's name, or an empty view for a value that isn't one of them. A
// name is a view over a string literal, so data() is NUL terminated and safe for %s.
//
// format_as is the hook fmt looks for: SPDLOG_ERROR("{}", RC_LINKS_POCKET) logs
// "RC_LINKS_POCKET" rather than a number, and a value with no name logs as
// "RandomizerCheck(...)". fmt finds it by argument dependent lookup, so including this
// header is all a caller has to do.
#define RANDO_ENUM_BEGIN(EnumName) \
std::string_view EnumToString(EnumName value); \
std::string format_as(EnumName value);
#define RANDO_ENUM_ITEM(...)
#define RANDO_ENUM_END(...)
#include "randomizerEnumList.h"
#undef RANDO_ENUM_BEGIN
#undef RANDO_ENUM_ITEM
#undef RANDO_ENUM_END
@@ -10,16 +10,7 @@
// clang-format on
#endif
#include "randomizerEnums/LogicVal.h"
#include "randomizerEnums/RandomizerCheck.h"
#include "randomizerEnums/RandomizerGet.h"
#include "randomizerEnums/RandomizerHintTextKey.h"
#include "randomizerEnums/RandomizerInf.h"
#include "randomizerEnums/RandomizerMiscEnums.h"
#include "randomizerEnums/RandomizerOptions.h"
#include "randomizerEnums/RandomizerRegion.h"
#include "randomizerEnums/RandomizerSettingKey.h"
#include "randomizerEnums/RandomizerTrick.h"
#include "randomizerEnumList.h"
// Clean up only the defaults we defined.
#ifdef RANDO_ENUM__CLEANUP
+2 -1
View File
@@ -7,6 +7,7 @@
#include "soh/Enhancements/randomizer/dungeon.h"
#include "soh/Enhancements/randomizer/logic.h"
#include "soh/Enhancements/randomizer/randomizer.h"
#include "soh/Enhancements/randomizer/randomizerEnumStrings.h"
extern "C" {
#include "variables.h"
@@ -326,7 +327,7 @@ void SetStartingItems() {
Item_Give(NULL, ITEM_LETTER_RUTO);
break;
default:
SPDLOG_ERROR("[SetStartingItems] Unhandled value for bottleKey {}: {}", (int)bottleKey, bottle);
SPDLOG_ERROR("[SetStartingItems] Unhandled value for bottleKey {}: {}", bottleKey, bottle);
assert(false);
break;
}
@@ -4,6 +4,7 @@
#include "soh/OTRGlobals.h"
#include "soh/Enhancements/randomizer/randomizer_check_tracker.h"
#include "soh/Enhancements/randomizer/randomizer.h"
#include "soh/Enhancements/randomizer/randomizerEnumStrings.h"
static bool isResultOfHandling = false;
@@ -41,7 +42,7 @@ void Anchor::HandlePacket_SetCheckStatus(nlohmann::json payload) {
RandomizerCheck rc = payload.at("rc").get<RandomizerCheck>();
if (rc < 0 || rc >= RC_MAX) {
SPDLOG_ERROR("[Anchor] SET_CHECK_STATUS: rc {} out of range", (int)rc);
SPDLOG_ERROR("[Anchor] SET_CHECK_STATUS: {} out of range", rc);
return;
}
RandomizerCheckStatus status = payload.at("status").get<RandomizerCheckStatus>();