Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion example_community_patch_settings_en.toml
Original file line number Diff line number Diff line change
Expand Up @@ -240,9 +240,16 @@ system_zoom_preset_4 = 2750.0
# Zoom preset F5 for system view
system_zoom_preset_5 = 5000.0

# This controls the maximum zoom distance in System View. Default is 2500. Higher values increase label distance
# Maximum zoom-out distance in System View. Mod default is 5000. Higher values increase label distance.
zoom = 5000.0

# Maximum zoom-out distance in The Haven, in camera distance units (like zoom above).
# Higher values extend the native range; 0.0 keeps the native range. Default is 4000.0.
# Uses the normal scroll/pinch controls; this sets the range, not the current zoom.
# Expanded Haven zoom also keeps road surfaces separated from the ground at every zoom level.
# Requires [patches].havenzoomhooks; independent of the System View zoomhooks switch.
haven_zoom = 4000.0

# <[=====================================================]>
#
# **** * *
Expand Down Expand Up @@ -296,6 +303,9 @@ transitionscreenhooks = true
uiscalehooks = true
zoomhooks = true

# Compatibility switch for Haven zoom hooks. Use graphics.haven_zoom = 0.0 for native behavior.
havenzoomhooks = true

# <[==================================================================================================================================]>
#
# * * * * **** * * *
Expand Down
8 changes: 8 additions & 0 deletions mods/src/config.cc
Original file line number Diff line number Diff line change
Expand Up @@ -942,6 +942,8 @@ void Config::Load()
this->installUiScaleHooks =
get_config_or_default(config, parsed, "patches", "uiscalehooks", DCP::uiscalehooks, write_config);
this->installZoomHooks = get_config_or_default(config, parsed, "patches", "zoomhooks", DCP::zoomhooks, write_config);
this->installHavenZoomHooks =
get_config_or_default(config, parsed, "patches", "havenzoomhooks", DCP::havenzoomhooks, write_config);
this->installBuffFixHooks =
get_config_or_default(config, parsed, "patches", "bufffixhooks", DCP::bufffixhooks, write_config);
this->installToastBannerHooks =
Expand Down Expand Up @@ -1019,6 +1021,12 @@ void Config::Load()
this->ui_scale_viewer =
get_config_or_default(config, parsed, "graphics", "ui_scale_viewer", DCG::ui_scale_viewer, write_config);
this->zoom = get_config_or_default(config, parsed, "graphics", "zoom", DCG::zoom, write_config);
this->haven_zoom = get_config_or_default(config, parsed, "graphics", "haven_zoom", DCG::haven_zoom, write_config);
if (!std::isfinite(this->haven_zoom) || this->haven_zoom < 0.0f) {
spdlog::warn("Invalid haven_zoom {}; using {}", this->haven_zoom, DCG::haven_zoom);
this->haven_zoom = DCG::haven_zoom;
parsed["graphics"].as_table()->insert_or_assign("haven_zoom", this->haven_zoom);
}
this->fr_scale = get_config_or_default(config, parsed, "graphics", "fr_scale", DCG::fr_scale, write_config);
this->zoom_label_player.detail =
get_fleet_label_detail(config, parsed, "zoom_label_player_detail", DCG::zoom_label_player_detail, write_config);
Expand Down
2 changes: 2 additions & 0 deletions mods/src/config.h
Original file line number Diff line number Diff line change
Expand Up @@ -173,6 +173,7 @@ class Config final
float ui_scale_ship;
float ui_scale_viewer;
float zoom;
float haven_zoom;
float fr_scale;
FleetLabelProfile zoom_label_player;
FleetLabelProfile zoom_label_non_player;
Expand Down Expand Up @@ -269,6 +270,7 @@ class Config final

bool installUiScaleHooks;
bool installZoomHooks;
bool installHavenZoomHooks;
bool installBuffFixHooks;
bool installToastBannerHooks;
bool installPanHooks;
Expand Down
2 changes: 2 additions & 0 deletions mods/src/defaultconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ namespace Graphics
constexpr auto ui_scale_viewer = 1.2;
constexpr bool use_presets_as_default = true;
constexpr auto zoom = 5000;
constexpr auto haven_zoom = 4000.0;
constexpr auto fr_scale = 2.0;
constexpr bool loader_enabled = true; // replace LoginSequence background
constexpr bool loader_transition = true; // replace TVC/SlideShow backgrounds
Expand Down Expand Up @@ -90,6 +91,7 @@ namespace Patches
constexpr bool toastbannerhooks = true;
constexpr bool uiscalehooks = true;
constexpr bool zoomhooks = true;
constexpr bool havenzoomhooks = true;
constexpr bool miscpatches = true;
constexpr bool giftsbulkclaimhooks = true;
constexpr bool dailyfactionbulkclaimhooks = true;
Expand Down
148 changes: 148 additions & 0 deletions mods/src/patches/parts/haven_road_depth.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,148 @@
#include <il2cpp/method_contract.h>
#include <il2cpp/runtime.h>
#include <spdlog/spdlog.h>
#include <str_utils.h>

#include <algorithm>
#include <array>
#include <chrono>
#include <cmath>
#include <string>

namespace
{
struct RoadDepthApi {
Il2CppClass *renderer = nullptr;
const MethodInfo *find = nullptr, *children = nullptr, *materials = nullptr;
const MethodInfo *name = nullptr, *shader = nullptr, *has = nullptr, *get = nullptr, *set = nullptr;

RoadDepthApi()
{
auto cls = [](const char *n) {
return il2cpp_get_class_helper("UnityEngine.CoreModule", "UnityEngine", n).get_cls();
};
auto *game_object = cls("GameObject"), *material = cls("Material");
renderer = cls("Renderer");
find = method_contract::Resolve(game_object, "Find", true, "UnityEngine.GameObject", {"System.String"});
children = method_contract::Resolve(game_object, "GetComponentsInChildren", false, "UnityEngine.Component[]",
{"System.Type", "System.Boolean"});
materials = method_contract::Resolve(renderer, "get_sharedMaterials", false, "UnityEngine.Material[]", {});
name = method_contract::Resolve(cls("Object"), "get_name", false, "System.String", {});
shader = method_contract::Resolve(material, "get_shader", false, "UnityEngine.Shader", {});
has = method_contract::Resolve(material, "HasProperty", false, "System.Boolean", {"System.String"});
get = method_contract::Resolve(material, "GetFloat", false, "System.Single", {"System.String"});
set = method_contract::Resolve(material, "SetFloat", false, "System.Void", {"System.String", "System.Single"});
}

bool Valid() const
{ return renderer && find && children && materials && name && shader && has && get && set; }
};

Il2CppObject *Invoke(const MethodInfo *method, Il2CppObject *object, void **args = nullptr)
{
Il2CppObject *result = nullptr;
return Il2CppRuntime::TryInvoke(method, object, args, &result) ? result : nullptr;
}

std::string Name(RoadDepthApi &api, Il2CppObject *object)
{
auto *value = object ? reinterpret_cast<Il2CppString *>(Invoke(api.name, object)) : nullptr;
return value && value->length <= 256 ? to_string(value) : std::string{};
}

bool IsRoad(const std::string &name)
{
for (const char *prefix :
{"mat_PB_3101101_asphalt_", "mat_PB_3101201_asphalt_", "mat_PB_3101301_asphalt_", "mat_PB_3101401_asphalt_",
"mat_PB_3101501_asphalt_", "mat_PB_3101601_asphalt_", "mat_PB_3101701_asphalt_"}) {
if (name.starts_with(prefix))
return true;
}
return false;
}

bool ReadDepth(RoadDepthApi &api, Il2CppObject *material, Il2CppString *property, float &value)
{
void *args[] = {property};
bool present = false;
if (!Il2CppRuntime::TryBoolean(Invoke(api.has, material, args), present) || !present)
return false;
auto *boxed = Invoke(api.get, material, args);
if (!boxed || !method_contract::Type(il2cpp_class_get_type(boxed->klass), "System.Single"))
return false;
value = *static_cast<float *>(il2cpp_object_unbox(boxed));
return std::isfinite(value);
}
} // namespace

// Called only by the qualified, enabled Haven camera path. The small bias stays
// on at every zoom level, keeping nearly coplanar road surfaces above the ground.
// All scene objects are resolved afresh; no Unity pointers or GC handles are retained.
void ApplyHavenRoadDepthBias()
{
using Clock = std::chrono::steady_clock;
static auto next = Clock::time_point{};
if (Clock::now() < next)
return;
next = Clock::now() + std::chrono::seconds(1);
static RoadDepthApi api;
if (!api.Valid()) {
static bool warned = false;
if (!warned) {
spdlog::warn("[HavenZoom] road material API unavailable; keeping native road depth");
warned = true;
}
return;
}
void *root_args[] = {il2cpp_string_new("StarbaseRoot/StarbaseManager/StarbasePlanetaryVisualsHolder")};
auto *root = Invoke(api.find, nullptr, root_args);
if (!root)
return;
bool include_inactive = true;
void *child_args[] = {il2cpp_type_get_object(il2cpp_class_get_type(api.renderer)), &include_inactive};
auto *renderers = reinterpret_cast<Il2CppArraySize *>(Invoke(api.children, root, child_args));
if (!renderers || renderers->max_length > 4096)
return;
for (uintptr_t i = 0; i < renderers->max_length; ++i) {
auto *renderer = reinterpret_cast<Il2CppObject *>(renderers->vector[i]);
if (!renderer)
continue;
auto *materials = reinterpret_cast<Il2CppArraySize *>(Invoke(api.materials, renderer));
if (!materials || materials->max_length > 16)
continue;
for (uintptr_t j = 0; j < materials->max_length; ++j) {
auto *material = reinterpret_cast<Il2CppObject *>(materials->vector[j]);
const auto name = Name(api, material);
if (!material || !IsRoad(name) || Name(api, Invoke(api.shader, material)) != "Custom/LitMSAE")
continue;
const std::array<Il2CppString *, 2> properties = {il2cpp_string_new("_OffsetFactor"),
il2cpp_string_new("_OffsetUnits")};
std::array<float, 2> before{};
if (!ReadDepth(api, material, properties[0], before[0]) || !ReadDepth(api, material, properties[1], before[1]))
continue;
bool changed = false, verified = true;
for (unsigned k = 0; k < 2; ++k) {
// Preserve an already stronger native bias.
float target = std::min(before[k], -1.0f);
if (target == before[k])
continue;
void *args[] = {properties[k], &target};
if (!Il2CppRuntime::TryInvoke(api.set, material, args)) {
verified = false;
continue;
}
changed = true;
float after = 0.0f;
verified = ReadDepth(api, material, properties[k], after) && after == target && verified;
}
if (changed) {
spdlog::debug("[HavenZoom] road depth bias {}: verified={}", name, verified);
static bool reported = false;
if (verified && !reported) {
spdlog::info("[HavenZoom] corrected road surface depth for expanded Haven zoom");
reported = true;
}
}
}
}
}
Loading
Loading