From bdeb1d2933bbea216a47816498287d0d6a514f7f Mon Sep 17 00:00:00 2001 From: Guffawaffle Date: Sun, 20 Sep 2026 12:10:36 -0500 Subject: [PATCH 1/5] Add opt-in Galactic Anomaly countdown below system name --- example_community_patch_settings_da.toml | 3 + example_community_patch_settings_de.toml | 3 + ...munity_patch_settings_en-GB-x-cockney.toml | 3 + ...mmunity_patch_settings_en-x-minionese.toml | 3 + example_community_patch_settings_en.toml | 3 + example_community_patch_settings_es.toml | 3 + example_community_patch_settings_fr.toml | 3 + example_community_patch_settings_nl.toml | 3 + example_community_patch_settings_ru.toml | 3 + example_community_patch_settings_tlh.toml | 3 + mods/src/config.cc | 2 + mods/src/config.h | 1 + mods/src/defaultconfig.h | 1 + .../patches/parts/galactic_anomaly_timer.cc | 314 ++++++++++++++++++ mods/src/patches/patches.cc | 2 + 15 files changed, 350 insertions(+) create mode 100644 mods/src/patches/parts/galactic_anomaly_timer.cc diff --git a/example_community_patch_settings_da.toml b/example_community_patch_settings_da.toml index bd067d2a8..d2c6c1fe5 100644 --- a/example_community_patch_settings_da.toml +++ b/example_community_patch_settings_da.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[=========================================================================================================================================]> [graphics] +# Vis den resterende tid for den galaktiske anomali under systemnavnet. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_de.toml b/example_community_patch_settings_de.toml index faa367211..5c13370f3 100644 --- a/example_community_patch_settings_de.toml +++ b/example_community_patch_settings_de.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[=========================================================================================================================================]> [graphics] +# Verbleibende Zeit der galaktischen Anomalie unter dem Systemnamen anzeigen. +galactic_anomaly_timer = false + # Subgroup: Anzeige # ----------------- diff --git a/example_community_patch_settings_en-GB-x-cockney.toml b/example_community_patch_settings_en-GB-x-cockney.toml index 72b77cb88..cb0cef86b 100644 --- a/example_community_patch_settings_en-GB-x-cockney.toml +++ b/example_community_patch_settings_en-GB-x-cockney.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[=============================================================================================================]> [graphics] +# Show the remaining Galactic Anomaly time below the system name. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_en-x-minionese.toml b/example_community_patch_settings_en-x-minionese.toml index ca5a5850f..29cd73ee6 100644 --- a/example_community_patch_settings_en-x-minionese.toml +++ b/example_community_patch_settings_en-x-minionese.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[============================================================]> [graphics] +# Show the remaining Galactic Anomaly time below the system name. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_en.toml b/example_community_patch_settings_en.toml index eec640425..45b5039e6 100644 --- a/example_community_patch_settings_en.toml +++ b/example_community_patch_settings_en.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[===========================================================================================================================]> [graphics] +# Show the remaining Galactic Anomaly time below the system name. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_es.toml b/example_community_patch_settings_es.toml index cd1fb5c77..476bbb5c0 100644 --- a/example_community_patch_settings_es.toml +++ b/example_community_patch_settings_es.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[====================================================================================================================]> [graphics] +# Mostrar el tiempo restante de la anomalía galáctica debajo del nombre del sistema. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_fr.toml b/example_community_patch_settings_fr.toml index f6f9541cd..d34d4f9ec 100644 --- a/example_community_patch_settings_fr.toml +++ b/example_community_patch_settings_fr.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[=======================================================================================================================================================]> [graphics] +# Afficher le temps restant de l’anomalie galactique sous le nom du système. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_nl.toml b/example_community_patch_settings_nl.toml index e3980b218..2de4ae223 100644 --- a/example_community_patch_settings_nl.toml +++ b/example_community_patch_settings_nl.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[==============================================================================================================================================================]> [graphics] +# Toon de resterende tijd van de galactische anomalie onder de systeemnaam. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_ru.toml b/example_community_patch_settings_ru.toml index eaf83d806..f5b6d47a2 100644 --- a/example_community_patch_settings_ru.toml +++ b/example_community_patch_settings_ru.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[===========================================================================================================================]> [graphics] +# Показывать оставшееся время галактической аномалии под названием системы. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/example_community_patch_settings_tlh.toml b/example_community_patch_settings_tlh.toml index 0ebcbb1b5..639d60fee 100644 --- a/example_community_patch_settings_tlh.toml +++ b/example_community_patch_settings_tlh.toml @@ -114,6 +114,9 @@ enable_experimental = false # <[==========================================================================]> [graphics] +# Show the remaining Galactic Anomaly time below the system name. +galactic_anomaly_timer = false + # Subgroup: Display # ----------------- diff --git a/mods/src/config.cc b/mods/src/config.cc index 2efae99ae..9785d8a65 100644 --- a/mods/src/config.cc +++ b/mods/src/config.cc @@ -1204,6 +1204,8 @@ void Config::Load() get_config_or_default(config, parsed, "graphics", "loader_image", DCG::loader_image, write_log); this->loader_logo_scale = get_config_or_default(config, parsed, "graphics", "loader_logo_scale", DCG::loader_logo_scale, write_log); + this->galactic_anomaly_timer = + get_config_or_default(config, parsed, "graphics", "galactic_anomaly_timer", DCG::galactic_anomaly_timer, write_log); this->loader_tip_enabled = get_config_or_default(config, parsed, "graphics", "loader_tip_enabled", DCG::loader_tip_enabled, write_log); diff --git a/mods/src/config.h b/mods/src/config.h index 37e73e307..e70b74c6c 100644 --- a/mods/src/config.h +++ b/mods/src/config.h @@ -282,6 +282,7 @@ class Config final std::string loader_image; float loader_logo_scale; bool loader_tip_enabled; + bool galactic_anomaly_timer; bool installLoadingScreenHooks; bool installTransitionScreenHooks; diff --git a/mods/src/defaultconfig.h b/mods/src/defaultconfig.h index 222e87d0d..7d9cd4523 100644 --- a/mods/src/defaultconfig.h +++ b/mods/src/defaultconfig.h @@ -31,6 +31,7 @@ namespace Control namespace Graphics { + constexpr bool galactic_anomaly_timer = false; constexpr bool borderless_fullscreen = true; constexpr bool allow_cursor = true; constexpr const char* zoom_label_player_detail = "native"; diff --git a/mods/src/patches/parts/galactic_anomaly_timer.cc b/mods/src/patches/parts/galactic_anomaly_timer.cc new file mode 100644 index 000000000..6b906c399 --- /dev/null +++ b/mods/src/patches/parts/galactic_anomaly_timer.cc @@ -0,0 +1,314 @@ +#include "config.h" +#include "patches/screen_update_hook.h" + +#include +#include + +#include +#include +#include +#include + +namespace +{ +// All Unity work runs on ScreenManager's main-thread dispatcher. No additional detours. +struct Vector2 { + float x, y; +}; +struct Color { + float r, g, b, a; +}; + +Il2CppClass* Class(const char* assembly, const char* ns, const char* name) +{ + auto* a = il2cpp_domain_assembly_open(il2cpp_domain_get(), assembly); + auto* image = a ? il2cpp_assembly_get_image(a) : nullptr; + return image ? il2cpp_class_from_name(image, ns, name) : nullptr; +} + +const MethodInfo* Method(Il2CppClass* cls, const char* name, int count) +{ return cls ? il2cpp_class_get_method_from_name(cls, name, count) : nullptr; } + +// Unity has Type/string and generic overloads with the same argument count. +const MethodInfo* TypeMethod(Il2CppClass* cls, const char* name) +{ + void* iter = nullptr; + while (cls) { + while (auto* method = il2cpp_class_get_methods(cls, &iter)) { + if (method->is_generic || std::strcmp(method->name, name) || method->parameters_count != 1) + continue; + auto* param = il2cpp_class_from_type(il2cpp_method_get_param(method, 0)); + if (param && !std::strcmp(il2cpp_class_get_namespace(param), "System") + && !std::strcmp(il2cpp_class_get_name(param), "Type")) + return method; + } + cls = il2cpp_class_get_parent(cls); + iter = nullptr; + } + return nullptr; +} + +bool Invoke(const MethodInfo* method, void* target, void** args, Il2CppObject** result = nullptr) +{ + if (!method) + return false; + Il2CppException* exception = nullptr; + auto* value = il2cpp_runtime_invoke(method, target, args, &exception); + if (exception) + return false; + if (result) + *result = value; + return true; +} + +Il2CppObject* Get(Il2CppObject* object, const char* name) +{ + Il2CppObject* result = nullptr; + if (object) + Invoke(Method(object->klass, name, 0), object, nullptr, &result); + return result; +} + +template bool Value(Il2CppObject* object, const char* name, T& value) +{ + auto* boxed = Get(object, name); + uint32_t alignment = 0; + if (!boxed || !il2cpp_class_is_valuetype(boxed->klass) + || il2cpp_class_value_size(boxed->klass, &alignment) != sizeof(T)) + return false; + std::memcpy(&value, il2cpp_object_unbox(boxed), sizeof(T)); + return true; +} + +bool Set(Il2CppObject* object, const char* name, void* value) +{ + void* args[] = {value}; + return object && Invoke(Method(object->klass, name, 1), object, args); +} + +Il2CppObject* Field(Il2CppObject* object, const char* name) +{ + auto* field = object ? il2cpp_class_get_field_from_name(object->klass, name) : nullptr; + if (!field || il2cpp_type_is_byref(il2cpp_field_get_type(field))) + return nullptr; + auto* cls = il2cpp_class_from_type(il2cpp_field_get_type(field)); + if (!cls || il2cpp_class_is_valuetype(cls)) + return nullptr; + Il2CppObject* result = nullptr; + il2cpp_field_get_value(object, field, &result); + return result; +} + +Il2CppObject* WithType(const MethodInfo* method, Il2CppObject* target, Il2CppClass* type) +{ + if (!type) + return nullptr; + void* args[] = {il2cpp_type_get_object(il2cpp_class_get_type(type))}; + Il2CppObject* result = nullptr; + Invoke(method, target, args, &result); + return result; +} + +Il2CppClass* UnityObject() +{ + static auto* cls = Class("UnityEngine.CoreModule", "UnityEngine", "Object"); + return cls; +} + +bool Alive(Il2CppObject* object) +{ + if (!object) + return false; + void* args[] = {object}; + Il2CppObject* result = nullptr; + static auto* method = Method(UnityObject(), "op_Implicit", 1); + return Invoke(method, nullptr, args, &result) && result && *static_cast(il2cpp_object_unbox(result)); +} + +struct Root { + Il2CppGCHandle handle{}; + Il2CppObject* get() const + { return handle ? il2cpp_gchandle_get_target(handle) : nullptr; } + void reset(Il2CppObject* value = nullptr) + { + if (handle) + il2cpp_gchandle_free(handle); + handle = value ? il2cpp_gchandle_new(value, false) : 0; + } +}; + +Root navigation, panel, label; + +void Clear() +{ + if (Alive(panel.get())) { + bool active = false; + Set(panel.get(), "SetActive", &active); + void* args[] = {panel.get()}; + Invoke(Method(UnityObject(), "Destroy", 1), nullptr, args); + } + label.reset(); + panel.reset(); + navigation.reset(); +} + +Il2CppObject* Find(Il2CppClass* type) +{ + static auto* method = TypeMethod(UnityObject(), "FindObjectOfType"); + return WithType(method, nullptr, type); +} + +Il2CppObject* Component(Il2CppObject* object, Il2CppClass* type) +{ return object ? WithType(TypeMethod(object->klass, "GetComponent"), object, type) : nullptr; } + +bool Rect(Il2CppObject* transform, Vector2 anchor, Vector2 pivot, Vector2 size, Vector2 position) +{ + return Set(transform, "set_anchorMin", &anchor) && Set(transform, "set_anchorMax", &anchor) + && Set(transform, "set_pivot", &pivot) && Set(transform, "set_sizeDelta", &size) + && Set(transform, "set_anchoredPosition", &position); +} + +Il2CppObject* NewObject(const char* name, Il2CppObject* parent, Root& root) +{ + static auto* go = Class("UnityEngine.CoreModule", "UnityEngine", "GameObject"); + static auto* rt = Class("UnityEngine.CoreModule", "UnityEngine", "RectTransform"); + if (!go || !rt) + return nullptr; + auto* object = il2cpp_object_new(go); + root.reset(object); + void* args[] = {il2cpp_string_new(name)}; + if (!Invoke(Method(go, ".ctor", 1), object, args)) + return nullptr; + bool active = false; + if (!Set(object, "SetActive", &active)) + return nullptr; + auto* transform = WithType(TypeMethod(go, "AddComponent"), object, rt); + bool worldPositionStays = false; + void* parentArgs[] = {parent, &worldPositionStays}; + if (!transform || !Invoke(Method(transform->klass, "SetParent", 2), transform, parentArgs)) + return nullptr; + return transform; +} + +bool Create(Il2CppObject* nav) +{ + // Use the actual system-name label as the anchor and font source. A second line + // avoids moving bookmarks, clipping long names, or altering native layout/animations. + auto* names = Field(Field(nav, "_factionInformationHelper"), "_systemName"); + int count = 0; + if (!Value(names, "get_Count", count) || count < 1) + return false; + int index = 0; + void* args[] = {&index}; + Il2CppObject* name = nullptr; + if (!Invoke(Method(names->klass, "get_Item", 1), names, args, &name) || !Alive(name)) + return false; + auto* parent = Get(name, "get_transform"); + static auto* tmp = Class("Unity.TextMeshPro", "TMPro", "TextMeshProUGUI"); + auto* source = Component(name, tmp); + auto* font = Get(source, "get_font"); + if (!parent || !font) + return false; + + auto* transform = NewObject("CommunityMod_AnomalyTimer", parent, panel); + if (!transform || !Rect(transform, {1, 0}, {1, 1}, {160, 30}, {0, -5})) + return false; + static auto* image = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); + auto* background = WithType(TypeMethod(panel.get()->klass, "AddComponent"), panel.get(), image); + Color bg{0.06f, 0.10f, 0.14f, 0.85f}; + bool no = false; + if (!background || !Set(background, "set_color", &bg) || !Set(background, "set_raycastTarget", &no)) + return false; + + Root textObject; + auto* textTransform = NewObject("Countdown", transform, textObject); + auto* text = + WithType(TypeMethod(textObject.get() ? textObject.get()->klass : nullptr, "AddComponent"), textObject.get(), tmp); + label.reset(text); + bool ok = textTransform && text && Rect(textTransform, {0.5f, 0.5f}, {0.5f, 0.5f}, {152, 28}, {0, 0}); + float fontSize = 22; + int alignment = 0x202; // TMP: Center (514). + Color color{0.95f, 0.83f, 0.89f, 1}; + ok = ok && Set(text, "set_font", font) && Set(text, "set_fontSize", &fontSize) + && Set(text, "set_alignment", &alignment) && Set(text, "set_color", &color) + && Set(text, "set_raycastTarget", &no) && Set(text, "set_enableWordWrapping", &no); + bool yes = true; + ok = ok && Set(textObject.get(), "SetActive", &yes); + if (!ok && Alive(textObject.get())) { + void* destroyArgs[] = {textObject.get()}; + Invoke(Method(UnityObject(), "Destroy", 1), nullptr, destroyArgs); + } + textObject.reset(); // The parent hierarchy now owns this child. + return ok; +} + +void Update() +{ + static auto next = std::chrono::steady_clock::time_point{}; + auto now = std::chrono::steady_clock::now(); + if (now < next) + return; + next = now + std::chrono::milliseconds(250); + + if (!Config::Get().galactic_anomaly_timer) { + Clear(); + return; + } + if (!Alive(navigation.get())) { + Clear(); + static auto* cls = Class("Assembly-CSharp", "Digit.Prime.Navigation.UI", "HudNavigationViewController"); + navigation.reset(Find(cls)); + } + auto* nav = navigation.get(); + bool show = false; + std::int64_t ticks = 0; + if (Alive(nav) && Value(nav, "get_isActiveAndEnabled", show) && show && Value(nav, "CanShowGalacticAnomaly", show) + && show) { + auto* address = Get(Get(nav, "get_CanvasContext"), "get_ViewingAddress"); + std::int64_t system = -1; + static auto* managerClass = Class("Assembly-CSharp", "Digit.Prime.GalacticAnomalies", "GalacticAnomaliesManager"); + auto* manager = Find(managerClass); + Il2CppObject* anomaly = nullptr; + void* args[] = {&system}; + show = manager && Value(address, "get_System", system) && system > 0 + && Invoke(Method(managerClass, "GetSystemGalacticAnomalies", 1), manager, args, &anomaly) + && Value(anomaly, "get_IsActive", show) && show + && Value(Get(anomaly, "get_EndTimeTimerDataContext"), "get_RemainingTime", ticks) && ticks > 0; + } else { + show = false; + } + if (show && (!Alive(panel.get()) || !Alive(label.get()))) { + // Release old UI without releasing the current navigation reference. + auto* current = nav; + Clear(); + navigation.reset(current); + if (!Create(current)) { + static bool warned = false; + if (!warned) { + spdlog::warn("Galactic anomaly countdown: HUD creation failed; leaving the native HUD unchanged"); + warned = true; + } + Clear(); + next = now + std::chrono::seconds(5); + return; + } + } + if (!Alive(panel.get())) + return; + if (show) { + auto seconds = ticks / 10000000 + (ticks % 10000000 != 0); + auto text = seconds >= 3600 ? fmt::format("{}h {:02}m {:02}s", seconds / 3600, seconds / 60 % 60, seconds % 60) + : fmt::format("{:02}m {:02}s", seconds / 60, seconds % 60); + show = Set(label.get(), "set_text", il2cpp_string_new(text.c_str())); + } + Set(panel.get(), "SetActive", &show); +} +} // namespace + +void InstallGalacticAnomalyTimer() +{ + if (install_screen_manager_update_hook()) { + register_screen_manager_update_callback(Update); + spdlog::info("Galactic anomaly countdown enabled (below system name)"); + } +} diff --git a/mods/src/patches/patches.cc b/mods/src/patches/patches.cc index 9579b9692..f54820870 100644 --- a/mods/src/patches/patches.cc +++ b/mods/src/patches/patches.cc @@ -39,6 +39,7 @@ void InstallSyncPatches(); void InstallObjectTrackers(); void InstallLoadingScreenHooks(); void InstallTransitionScreenHooks(); +void InstallGalacticAnomalyTimer(); void InstallLoadingTipHooks(); void InstallFocusSearchHooks(); void InstallCargoFormatHooks(); @@ -142,6 +143,7 @@ __int64 il2cpp_init_hook(auto original, const char* domain_name) {"ObjectTracker", {InstallObjectTrackers, &cfg.installObjectTracker}}, {"LoadingScreen", {InstallLoadingScreenHooks, &cfg.installLoadingScreenHooks}}, {"TransitionScreen", {InstallTransitionScreenHooks, &cfg.installTransitionScreenHooks}}, + {"GalacticAnomalyTimer", {InstallGalacticAnomalyTimer, &cfg.galactic_anomaly_timer}}, {"LoadingTip", {InstallLoadingTipHooks, &cfg.loader_tip_enabled}}, {"FocusSearch", {InstallFocusSearchHooks, &cfg.installFocusSearchHooks}}, {"CargoFormat", {InstallCargoFormatHooks, &cfg.installCargoFormatHooks}}, From 8bb4ac796bdafa6443d5f3256dea0b9a72322c4d Mon Sep 17 00:00:00 2001 From: Guffawaffle Date: Sun, 20 Sep 2026 12:19:04 -0500 Subject: [PATCH 2/5] Move anomaly countdown below the upper-right action buttons --- example_community_patch_settings_da.toml | 2 +- example_community_patch_settings_de.toml | 2 +- ...munity_patch_settings_en-GB-x-cockney.toml | 2 +- ...mmunity_patch_settings_en-x-minionese.toml | 2 +- example_community_patch_settings_en.toml | 2 +- example_community_patch_settings_es.toml | 2 +- example_community_patch_settings_fr.toml | 2 +- example_community_patch_settings_nl.toml | 2 +- example_community_patch_settings_ru.toml | 2 +- example_community_patch_settings_tlh.toml | 2 +- .../patches/parts/galactic_anomaly_timer.cc | 20 +++++++++++-------- 11 files changed, 22 insertions(+), 18 deletions(-) diff --git a/example_community_patch_settings_da.toml b/example_community_patch_settings_da.toml index d2c6c1fe5..940dd1eab 100644 --- a/example_community_patch_settings_da.toml +++ b/example_community_patch_settings_da.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[=========================================================================================================================================]> [graphics] -# Vis den resterende tid for den galaktiske anomali under systemnavnet. +# Vis den resterende tid for den galaktiske anomali under Help All / Engage / Claim. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_de.toml b/example_community_patch_settings_de.toml index 5c13370f3..4e31bb2de 100644 --- a/example_community_patch_settings_de.toml +++ b/example_community_patch_settings_de.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[=========================================================================================================================================]> [graphics] -# Verbleibende Zeit der galaktischen Anomalie unter dem Systemnamen anzeigen. +# Verbleibende Zeit der galaktischen Anomalie unter Helfen / Starten / Abholen anzeigen. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_en-GB-x-cockney.toml b/example_community_patch_settings_en-GB-x-cockney.toml index cb0cef86b..7dbceff86 100644 --- a/example_community_patch_settings_en-GB-x-cockney.toml +++ b/example_community_patch_settings_en-GB-x-cockney.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[=============================================================================================================]> [graphics] -# Show the remaining Galactic Anomaly time below the system name. +# Show the remaining Galactic Anomaly time below Help All / Engage / Claim. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_en-x-minionese.toml b/example_community_patch_settings_en-x-minionese.toml index 29cd73ee6..cac22a734 100644 --- a/example_community_patch_settings_en-x-minionese.toml +++ b/example_community_patch_settings_en-x-minionese.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[============================================================]> [graphics] -# Show the remaining Galactic Anomaly time below the system name. +# Show the remaining Galactic Anomaly time below Help All / Engage / Claim. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_en.toml b/example_community_patch_settings_en.toml index 45b5039e6..5a5b76578 100644 --- a/example_community_patch_settings_en.toml +++ b/example_community_patch_settings_en.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[===========================================================================================================================]> [graphics] -# Show the remaining Galactic Anomaly time below the system name. +# Show the remaining Galactic Anomaly time below Help All / Engage / Claim. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_es.toml b/example_community_patch_settings_es.toml index 476bbb5c0..b8603dff4 100644 --- a/example_community_patch_settings_es.toml +++ b/example_community_patch_settings_es.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[====================================================================================================================]> [graphics] -# Mostrar el tiempo restante de la anomalía galáctica debajo del nombre del sistema. +# Mostrar el tiempo restante de la anomalía galáctica debajo de Ayudar / Participar / Reclamar. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_fr.toml b/example_community_patch_settings_fr.toml index d34d4f9ec..fd6144354 100644 --- a/example_community_patch_settings_fr.toml +++ b/example_community_patch_settings_fr.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[=======================================================================================================================================================]> [graphics] -# Afficher le temps restant de l’anomalie galactique sous le nom du système. +# Afficher le temps restant de l’anomalie galactique sous les boutons Aider / Participer / Récupérer. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_nl.toml b/example_community_patch_settings_nl.toml index 2de4ae223..6285e3259 100644 --- a/example_community_patch_settings_nl.toml +++ b/example_community_patch_settings_nl.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[==============================================================================================================================================================]> [graphics] -# Toon de resterende tijd van de galactische anomalie onder de systeemnaam. +# Toon de resterende tijd van de galactische anomalie onder Help All / Engage / Claim. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_ru.toml b/example_community_patch_settings_ru.toml index f5b6d47a2..94126b6da 100644 --- a/example_community_patch_settings_ru.toml +++ b/example_community_patch_settings_ru.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[===========================================================================================================================]> [graphics] -# Показывать оставшееся время галактической аномалии под названием системы. +# Показывать оставшееся время галактической аномалии под кнопками помощи, участия и наград. galactic_anomaly_timer = false diff --git a/example_community_patch_settings_tlh.toml b/example_community_patch_settings_tlh.toml index 639d60fee..959fe10c7 100644 --- a/example_community_patch_settings_tlh.toml +++ b/example_community_patch_settings_tlh.toml @@ -114,7 +114,7 @@ enable_experimental = false # <[==========================================================================]> [graphics] -# Show the remaining Galactic Anomaly time below the system name. +# Show the remaining Galactic Anomaly time below Help All / Engage / Claim. galactic_anomaly_timer = false diff --git a/mods/src/patches/parts/galactic_anomaly_timer.cc b/mods/src/patches/parts/galactic_anomaly_timer.cc index 6b906c399..c77ffa550 100644 --- a/mods/src/patches/parts/galactic_anomaly_timer.cc +++ b/mods/src/patches/parts/galactic_anomaly_timer.cc @@ -192,8 +192,9 @@ Il2CppObject* NewObject(const char* name, Il2CppObject* parent, Root& root) bool Create(Il2CppObject* nav) { - // Use the actual system-name label as the anchor and font source. A second line - // avoids moving bookmarks, clipping long names, or altering native layout/animations. + // Keep the native system-name font, but place the timer under the upper-right + // Help All / Engage / Claim drawer. Parenting to the drawer follows its scale + // and visibility without changing any native button positions. auto* names = Field(Field(nav, "_factionInformationHelper"), "_systemName"); int count = 0; if (!Value(names, "get_Count", count) || count < 1) @@ -203,15 +204,18 @@ bool Create(Il2CppObject* nav) Il2CppObject* name = nullptr; if (!Invoke(Method(names->klass, "get_Item", 1), names, args, &name) || !Alive(name)) return false; - auto* parent = Get(name, "get_transform"); - static auto* tmp = Class("Unity.TextMeshPro", "TMPro", "TextMeshProUGUI"); - auto* source = Component(name, tmp); - auto* font = Get(source, "get_font"); + static auto* drawerClass = Class("Assembly-CSharp", "Digit.Prime.HUD", "HudAllianceAndNewsViewController"); + auto* drawer = Find(drawerClass); + auto* chest = Get(Field(drawer, "_chestPromotion"), "get_transform"); + auto* parent = Get(chest, "get_parent"); + static auto* tmp = Class("Unity.TextMeshPro", "TMPro", "TextMeshProUGUI"); + auto* source = Component(name, tmp); + auto* font = Get(source, "get_font"); if (!parent || !font) return false; auto* transform = NewObject("CommunityMod_AnomalyTimer", parent, panel); - if (!transform || !Rect(transform, {1, 0}, {1, 1}, {160, 30}, {0, -5})) + if (!transform || !Rect(transform, {0.5f, 0}, {0.5f, 1}, {160, 30}, {0, -40})) return false; static auto* image = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); auto* background = WithType(TypeMethod(panel.get()->klass, "AddComponent"), panel.get(), image); @@ -309,6 +313,6 @@ void InstallGalacticAnomalyTimer() { if (install_screen_manager_update_hook()) { register_screen_manager_update_callback(Update); - spdlog::info("Galactic anomaly countdown enabled (below system name)"); + spdlog::info("Galactic anomaly countdown enabled (below Help All / Engage / Claim)"); } } From dda5888de382f61953ddf6c97912cb3979fa27cb Mon Sep 17 00:00:00 2001 From: Guffawaffle Date: Sun, 20 Sep 2026 13:05:05 -0500 Subject: [PATCH 3/5] Frame the anomaly countdown and cache its manager --- .../patches/parts/galactic_anomaly_timer.cc | 92 ++++++++++++++++--- 1 file changed, 81 insertions(+), 11 deletions(-) diff --git a/mods/src/patches/parts/galactic_anomaly_timer.cc b/mods/src/patches/parts/galactic_anomaly_timer.cc index c77ffa550..60f275730 100644 --- a/mods/src/patches/parts/galactic_anomaly_timer.cc +++ b/mods/src/patches/parts/galactic_anomaly_timer.cc @@ -137,7 +137,7 @@ struct Root { } }; -Root navigation, panel, label; +Root navigation, panel, label, anomalyManager; void Clear() { @@ -150,6 +150,7 @@ void Clear() label.reset(); panel.reset(); navigation.reset(); + anomalyManager.reset(); } Il2CppObject* Find(Il2CppClass* type) @@ -190,6 +191,60 @@ Il2CppObject* NewObject(const char* name, Il2CppObject* parent, Root& root) return transform; } +Il2CppObject* GraphicSprite(Il2CppObject* image) +{ + // ImageSelector applies localized artwork through overrideSprite. + auto* sprite = Get(image, "get_overrideSprite"); + return sprite ? sprite : Get(image, "get_sprite"); +} + +Il2CppObject* NativeBackgroundSprite(Il2CppObject* nav) +{ + auto* button = Field(nav, "_galacticAnomaliesButtonWidget"); + auto* parent = Get(Get(button, "get_transform"), "get_parent"); + void* args[] = {il2cpp_string_new("ShortcutKeybindHint/Background")}; + Il2CppObject* background = nullptr; + if (!parent || !Invoke(Method(parent->klass, "Find", 1), parent, args, &background)) + return nullptr; + static auto* image = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); + return GraphicSprite(Component(background, image)); +} + +void Slice(Il2CppObject* image, Il2CppObject* sprite) +{ + if (!image || !sprite) + return; + int sliced = 1; + float spritePixels = 100; + if (!Value(sprite, "get_pixelsPerUnit", spritePixels) || spritePixels <= 0) + return; + float multiplier = 100 / spritePixels; + Set(image, "set_type", &sliced); + Set(image, "set_pixelsPerUnitMultiplier", &multiplier); +} + +Il2CppObject* Decoration(const char* name, Il2CppObject* parent, Vector2 size, Vector2 position, Color color, + Il2CppObject* sprite = nullptr) +{ + Root object; + auto* transform = NewObject(name, parent, object); + static auto* imageClass = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); + auto* image = + object.get() ? WithType(TypeMethod(object.get()->klass, "AddComponent"), object.get(), imageClass) : nullptr; + bool no = false, yes = true; + bool ok = transform && image && Rect(transform, {0.5f, 0.5f}, {0.5f, 0.5f}, size, position) + && Set(image, "set_color", &color) && Set(image, "set_raycastTarget", &no); + if (sprite) + ok = ok && Set(image, "set_sprite", sprite); + ok = ok && Set(object.get(), "SetActive", &yes); + if (!ok && Alive(object.get())) { + void* args[] = {object.get()}; + Invoke(Method(UnityObject(), "Destroy", 1), nullptr, args); + } + object.reset(); + return ok ? image : nullptr; +} + bool Create(Il2CppObject* nav) { // Keep the native system-name font, but place the timer under the upper-right @@ -215,21 +270,32 @@ bool Create(Il2CppObject* nav) return false; auto* transform = NewObject("CommunityMod_AnomalyTimer", parent, panel); - if (!transform || !Rect(transform, {0.5f, 0}, {0.5f, 1}, {160, 30}, {0, -40})) + if (!transform || !Rect(transform, {0.5f, 0}, {0.5f, 1}, {198, 38}, {0, -40})) return false; static auto* image = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); auto* background = WithType(TypeMethod(panel.get()->klass, "AddComponent"), panel.get(), image); - Color bg{0.06f, 0.10f, 0.14f, 0.85f}; + Color border{0.64f, 0.34f, 0.46f, 0.85f}; bool no = false; - if (!background || !Set(background, "set_color", &bg) || !Set(background, "set_raycastTarget", &no)) + if (!background || !Set(background, "set_color", &border) || !Set(background, "set_raycastTarget", &no)) + return false; + // Use the existing native key-hint silhouette for both layers, with a narrow + // inset creating the border. A missing sprite still yields a visible frame. + auto* rounded = NativeBackgroundSprite(nav); + if (rounded) { + Set(background, "set_sprite", rounded); + Slice(background, rounded); + } + auto* fill = Decoration("AnomalyFill", transform, {194, 34}, {0, 0}, {0.06f, 0.10f, 0.14f, 0.96f}, rounded); + if (!fill) return false; + Slice(fill, rounded); Root textObject; auto* textTransform = NewObject("Countdown", transform, textObject); auto* text = WithType(TypeMethod(textObject.get() ? textObject.get()->klass : nullptr, "AddComponent"), textObject.get(), tmp); label.reset(text); - bool ok = textTransform && text && Rect(textTransform, {0.5f, 0.5f}, {0.5f, 0.5f}, {152, 28}, {0, 0}); + bool ok = textTransform && text && Rect(textTransform, {0.5f, 0.5f}, {0.5f, 0.5f}, {190, 28}, {0, 0}); float fontSize = 22; int alignment = 0x202; // TMP: Center (514). Color color{0.95f, 0.83f, 0.89f, 1}; @@ -268,12 +334,16 @@ void Update() std::int64_t ticks = 0; if (Alive(nav) && Value(nav, "get_isActiveAndEnabled", show) && show && Value(nav, "CanShowGalacticAnomaly", show) && show) { - auto* address = Get(Get(nav, "get_CanvasContext"), "get_ViewingAddress"); - std::int64_t system = -1; - static auto* managerClass = Class("Assembly-CSharp", "Digit.Prime.GalacticAnomalies", "GalacticAnomaliesManager"); - auto* manager = Find(managerClass); - Il2CppObject* anomaly = nullptr; - void* args[] = {&system}; + auto* address = Get(Get(nav, "get_CanvasContext"), "get_ViewingAddress"); + std::int64_t system = -1; + static auto* managerClass = Class("Assembly-CSharp", "Digit.Prime.GalacticAnomalies", "GalacticAnomaliesManager"); + // Cache the Unity object, not its timer data. Unity's liveness check detects + // destruction even while the managed wrapper is retained by our GC handle. + if (!Alive(anomalyManager.get())) + anomalyManager.reset(Find(managerClass)); + auto* manager = anomalyManager.get(); + Il2CppObject* anomaly = nullptr; + void* args[] = {&system}; show = manager && Value(address, "get_System", system) && system > 0 && Invoke(Method(managerClass, "GetSystemGalacticAnomalies", 1), manager, args, &anomaly) && Value(anomaly, "get_IsActive", show) && show From da8f3b2b372a7db7834924603b080db16bf20fdf Mon Sep 17 00:00:00 2001 From: Guffawaffle Date: Wed, 23 Sep 2026 20:36:20 -0500 Subject: [PATCH 4/5] Keep anomaly timer invocation guards local to the feature --- .../patches/parts/galactic_anomaly_timer.cc | 66 ++++++++++--------- 1 file changed, 36 insertions(+), 30 deletions(-) diff --git a/mods/src/patches/parts/galactic_anomaly_timer.cc b/mods/src/patches/parts/galactic_anomaly_timer.cc index 60f275730..d59083ce5 100644 --- a/mods/src/patches/parts/galactic_anomaly_timer.cc +++ b/mods/src/patches/parts/galactic_anomaly_timer.cc @@ -2,6 +2,7 @@ #include "patches/screen_update_hook.h" #include +#include #include #include @@ -19,15 +20,27 @@ struct Color { float r, g, b, a; }; +// Keep optional timer metadata lookups local so this feature can stand alone. Il2CppClass* Class(const char* assembly, const char* ns, const char* name) { - auto* a = il2cpp_domain_assembly_open(il2cpp_domain_get(), assembly); - auto* image = a ? il2cpp_assembly_get_image(a) : nullptr; + auto* domain = il2cpp_domain_get(); + auto* a = domain ? il2cpp_domain_assembly_open(domain, assembly) : nullptr; + auto* image = a ? il2cpp_assembly_get_image(a) : nullptr; return image ? il2cpp_class_from_name(image, ns, name) : nullptr; } -const MethodInfo* Method(Il2CppClass* cls, const char* name, int count) -{ return cls ? il2cpp_class_get_method_from_name(cls, name, count) : nullptr; } +bool TryInvoke(const MethodInfo* method, void* target, void** args, Il2CppObject** result = nullptr) +{ + if (!method) + return false; + Il2CppException* exception = nullptr; + auto* value = il2cpp_runtime_invoke(method, target, args, &exception); + if (exception) + return false; + if (result) + *result = value; + return true; +} // Unity has Type/string and generic overloads with the same argument count. const MethodInfo* TypeMethod(Il2CppClass* cls, const char* name) @@ -48,24 +61,11 @@ const MethodInfo* TypeMethod(Il2CppClass* cls, const char* name) return nullptr; } -bool Invoke(const MethodInfo* method, void* target, void** args, Il2CppObject** result = nullptr) -{ - if (!method) - return false; - Il2CppException* exception = nullptr; - auto* value = il2cpp_runtime_invoke(method, target, args, &exception); - if (exception) - return false; - if (result) - *result = value; - return true; -} - Il2CppObject* Get(Il2CppObject* object, const char* name) { Il2CppObject* result = nullptr; if (object) - Invoke(Method(object->klass, name, 0), object, nullptr, &result); + TryInvoke(IL2CppClassHelper(object->klass).GetMethodInfo(name, 0), object, nullptr, &result); return result; } @@ -83,7 +83,7 @@ template bool Value(Il2CppObject* object, const char* name, T& valu bool Set(Il2CppObject* object, const char* name, void* value) { void* args[] = {value}; - return object && Invoke(Method(object->klass, name, 1), object, args); + return object && TryInvoke(IL2CppClassHelper(object->klass).GetMethodInfo(name, 1), object, args); } Il2CppObject* Field(Il2CppObject* object, const char* name) @@ -105,7 +105,7 @@ Il2CppObject* WithType(const MethodInfo* method, Il2CppObject* target, Il2CppCla return nullptr; void* args[] = {il2cpp_type_get_object(il2cpp_class_get_type(type))}; Il2CppObject* result = nullptr; - Invoke(method, target, args, &result); + TryInvoke(method, target, args, &result); return result; } @@ -121,8 +121,14 @@ bool Alive(Il2CppObject* object) return false; void* args[] = {object}; Il2CppObject* result = nullptr; - static auto* method = Method(UnityObject(), "op_Implicit", 1); - return Invoke(method, nullptr, args, &result) && result && *static_cast(il2cpp_object_unbox(result)); + static auto* method = IL2CppClassHelper(UnityObject()).GetMethodInfo("op_Implicit", 1); + if (!TryInvoke(method, nullptr, args, &result) || !result || !result->klass) + return false; + const auto* type = il2cpp_class_get_type(result->klass); + if (!type || type->byref || type->type != IL2CPP_TYPE_BOOLEAN) + return false; + auto* alive = static_cast(il2cpp_object_unbox(result)); + return alive && *alive; } struct Root { @@ -145,7 +151,7 @@ void Clear() bool active = false; Set(panel.get(), "SetActive", &active); void* args[] = {panel.get()}; - Invoke(Method(UnityObject(), "Destroy", 1), nullptr, args); + TryInvoke(IL2CppClassHelper(UnityObject()).GetMethodInfo("Destroy", 1), nullptr, args); } label.reset(); panel.reset(); @@ -178,7 +184,7 @@ Il2CppObject* NewObject(const char* name, Il2CppObject* parent, Root& root) auto* object = il2cpp_object_new(go); root.reset(object); void* args[] = {il2cpp_string_new(name)}; - if (!Invoke(Method(go, ".ctor", 1), object, args)) + if (!TryInvoke(IL2CppClassHelper(go).GetMethodInfo(".ctor", 1), object, args)) return nullptr; bool active = false; if (!Set(object, "SetActive", &active)) @@ -186,7 +192,7 @@ Il2CppObject* NewObject(const char* name, Il2CppObject* parent, Root& root) auto* transform = WithType(TypeMethod(go, "AddComponent"), object, rt); bool worldPositionStays = false; void* parentArgs[] = {parent, &worldPositionStays}; - if (!transform || !Invoke(Method(transform->klass, "SetParent", 2), transform, parentArgs)) + if (!transform || !TryInvoke(IL2CppClassHelper(transform->klass).GetMethodInfo("SetParent", 2), transform, parentArgs)) return nullptr; return transform; } @@ -204,7 +210,7 @@ Il2CppObject* NativeBackgroundSprite(Il2CppObject* nav) auto* parent = Get(Get(button, "get_transform"), "get_parent"); void* args[] = {il2cpp_string_new("ShortcutKeybindHint/Background")}; Il2CppObject* background = nullptr; - if (!parent || !Invoke(Method(parent->klass, "Find", 1), parent, args, &background)) + if (!parent || !TryInvoke(IL2CppClassHelper(parent->klass).GetMethodInfo("Find", 1), parent, args, &background)) return nullptr; static auto* image = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); return GraphicSprite(Component(background, image)); @@ -239,7 +245,7 @@ Il2CppObject* Decoration(const char* name, Il2CppObject* parent, Vector2 size, V ok = ok && Set(object.get(), "SetActive", &yes); if (!ok && Alive(object.get())) { void* args[] = {object.get()}; - Invoke(Method(UnityObject(), "Destroy", 1), nullptr, args); + TryInvoke(IL2CppClassHelper(UnityObject()).GetMethodInfo("Destroy", 1), nullptr, args); } object.reset(); return ok ? image : nullptr; @@ -257,7 +263,7 @@ bool Create(Il2CppObject* nav) int index = 0; void* args[] = {&index}; Il2CppObject* name = nullptr; - if (!Invoke(Method(names->klass, "get_Item", 1), names, args, &name) || !Alive(name)) + if (!TryInvoke(IL2CppClassHelper(names->klass).GetMethodInfo("get_Item", 1), names, args, &name) || !Alive(name)) return false; static auto* drawerClass = Class("Assembly-CSharp", "Digit.Prime.HUD", "HudAllianceAndNewsViewController"); auto* drawer = Find(drawerClass); @@ -306,7 +312,7 @@ bool Create(Il2CppObject* nav) ok = ok && Set(textObject.get(), "SetActive", &yes); if (!ok && Alive(textObject.get())) { void* destroyArgs[] = {textObject.get()}; - Invoke(Method(UnityObject(), "Destroy", 1), nullptr, destroyArgs); + TryInvoke(IL2CppClassHelper(UnityObject()).GetMethodInfo("Destroy", 1), nullptr, destroyArgs); } textObject.reset(); // The parent hierarchy now owns this child. return ok; @@ -345,7 +351,7 @@ void Update() Il2CppObject* anomaly = nullptr; void* args[] = {&system}; show = manager && Value(address, "get_System", system) && system > 0 - && Invoke(Method(managerClass, "GetSystemGalacticAnomalies", 1), manager, args, &anomaly) + && TryInvoke(IL2CppClassHelper(managerClass).GetMethodInfo("GetSystemGalacticAnomalies", 1), manager, args, &anomaly) && Value(anomaly, "get_IsActive", show) && show && Value(Get(anomaly, "get_EndTimeTimerDataContext"), "get_RemainingTime", ticks) && ticks > 0; } else { From 3c464eb4ed7d7412880eaee129544fc63bb303d8 Mon Sep 17 00:00:00 2001 From: Guffawaffle Date: Sun, 27 Sep 2026 16:16:52 -0500 Subject: [PATCH 5/5] Reuse existing helpers in anomaly timer --- .../patches/parts/galactic_anomaly_timer.cc | 43 +++++++++++-------- 1 file changed, 25 insertions(+), 18 deletions(-) diff --git a/mods/src/patches/parts/galactic_anomaly_timer.cc b/mods/src/patches/parts/galactic_anomaly_timer.cc index d59083ce5..7ed45ca32 100644 --- a/mods/src/patches/parts/galactic_anomaly_timer.cc +++ b/mods/src/patches/parts/galactic_anomaly_timer.cc @@ -1,5 +1,7 @@ #include "config.h" #include "patches/screen_update_hook.h" +#include "prime/Color.h" +#include "prime/Vector2.h" #include #include @@ -13,14 +15,8 @@ namespace { // All Unity work runs on ScreenManager's main-thread dispatcher. No additional detours. -struct Vector2 { - float x, y; -}; -struct Color { - float r, g, b, a; -}; - -// Keep optional timer metadata lookups local so this feature can stand alone. +// The shared class lookup dereferences missing assemblies. These optional UI +// classes can be absent after a client update, so check each lookup step. Il2CppClass* Class(const char* assembly, const char* ns, const char* name) { auto* domain = il2cpp_domain_get(); @@ -45,6 +41,8 @@ bool TryInvoke(const MethodInfo* method, void* target, void** args, Il2CppObject // Unity has Type/string and generic overloads with the same argument count. const MethodInfo* TypeMethod(Il2CppClass* cls, const char* name) { + // The shared filtered lookup cannot inspect is_generic and only searches + // one class. Keep the overload check here so a generic overload cannot win. void* iter = nullptr; while (cls) { while (auto* method = il2cpp_class_get_methods(cls, &iter)) { @@ -63,15 +61,24 @@ const MethodInfo* TypeMethod(Il2CppClass* cls, const char* name) Il2CppObject* Get(Il2CppObject* object, const char* name) { - Il2CppObject* result = nullptr; - if (object) - TryInvoke(IL2CppClassHelper(object->klass).GetMethodInfo(name, 0), object, nullptr, &result); - return result; + // Callers pass getter method names. Use the shared property helper for its + // virtual dispatch and exception handling, while accepting absent objects. + if (!object || std::strncmp(name, "get_", 4)) + return nullptr; + return IL2CppClassHelper(object->klass).GetProperty(name + 4).GetRaw(object); } template bool Value(Il2CppObject* object, const char* name, T& value) { - auto* boxed = Get(object, name); + // Use the shared property helper for getters. CanShowGalacticAnomaly is an + // ordinary method, so invoke it directly. Check either boxed result's size. + if (!object) + return false; + Il2CppObject* boxed = nullptr; + if (!std::strncmp(name, "get_", 4)) + boxed = Get(object, name); + else if (!TryInvoke(IL2CppClassHelper(object->klass).GetMethodInfo(name, 0), object, nullptr, &boxed)) + return false; uint32_t alignment = 0; if (!boxed || !il2cpp_class_is_valuetype(boxed->klass) || il2cpp_class_value_size(boxed->klass, &alignment) != sizeof(T)) @@ -168,7 +175,7 @@ Il2CppObject* Find(Il2CppClass* type) Il2CppObject* Component(Il2CppObject* object, Il2CppClass* type) { return object ? WithType(TypeMethod(object->klass, "GetComponent"), object, type) : nullptr; } -bool Rect(Il2CppObject* transform, Vector2 anchor, Vector2 pivot, Vector2 size, Vector2 position) +bool Rect(Il2CppObject* transform, vec2 anchor, vec2 pivot, vec2 size, vec2 position) { return Set(transform, "set_anchorMin", &anchor) && Set(transform, "set_anchorMax", &anchor) && Set(transform, "set_pivot", &pivot) && Set(transform, "set_sizeDelta", &size) @@ -229,7 +236,7 @@ void Slice(Il2CppObject* image, Il2CppObject* sprite) Set(image, "set_pixelsPerUnitMultiplier", &multiplier); } -Il2CppObject* Decoration(const char* name, Il2CppObject* parent, Vector2 size, Vector2 position, Color color, +Il2CppObject* Decoration(const char* name, Il2CppObject* parent, vec2 size, vec2 position, color tint, Il2CppObject* sprite = nullptr) { Root object; @@ -239,7 +246,7 @@ Il2CppObject* Decoration(const char* name, Il2CppObject* parent, Vector2 size, V object.get() ? WithType(TypeMethod(object.get()->klass, "AddComponent"), object.get(), imageClass) : nullptr; bool no = false, yes = true; bool ok = transform && image && Rect(transform, {0.5f, 0.5f}, {0.5f, 0.5f}, size, position) - && Set(image, "set_color", &color) && Set(image, "set_raycastTarget", &no); + && Set(image, "set_color", &tint) && Set(image, "set_raycastTarget", &no); if (sprite) ok = ok && Set(image, "set_sprite", sprite); ok = ok && Set(object.get(), "SetActive", &yes); @@ -280,7 +287,7 @@ bool Create(Il2CppObject* nav) return false; static auto* image = Class("UnityEngine.UI", "UnityEngine.UI", "Image"); auto* background = WithType(TypeMethod(panel.get()->klass, "AddComponent"), panel.get(), image); - Color border{0.64f, 0.34f, 0.46f, 0.85f}; + color border{0.64f, 0.34f, 0.46f, 0.85f}; bool no = false; if (!background || !Set(background, "set_color", &border) || !Set(background, "set_raycastTarget", &no)) return false; @@ -304,7 +311,7 @@ bool Create(Il2CppObject* nav) bool ok = textTransform && text && Rect(textTransform, {0.5f, 0.5f}, {0.5f, 0.5f}, {190, 28}, {0, 0}); float fontSize = 22; int alignment = 0x202; // TMP: Center (514). - Color color{0.95f, 0.83f, 0.89f, 1}; + color color{0.95f, 0.83f, 0.89f, 1}; ok = ok && Set(text, "set_font", font) && Set(text, "set_fontSize", &fontSize) && Set(text, "set_alignment", &alignment) && Set(text, "set_color", &color) && Set(text, "set_raycastTarget", &no) && Set(text, "set_enableWordWrapping", &no);