Skip to content

feat(UI): Time of Day#1903

Closed
Dlizzio wants to merge 41 commits into
community-shaders:devfrom
Dlizzio:time-of-day
Closed

feat(UI): Time of Day#1903
Dlizzio wants to merge 41 commits into
community-shaders:devfrom
Dlizzio:time-of-day

Conversation

@Dlizzio
Copy link
Copy Markdown
Contributor

@Dlizzio Dlizzio commented Feb 18, 2026

Allows for feature specific time of day settings through the scene manager.

Skyrim Special Edition 2_27_2026 7_27_57 AM

Summary by CodeRabbit

  • New Features

    • Six-period Time of Day mode: per-period settings, activation, save/revert baselines, and runtime blending.
  • Behavior Changes

    • Per-feature per-period blending and dominant-period resolution; TOD coordinates with interior/exterior transitions; calendar-prioritized game time.
  • UI

    • Unified Scene Settings UI for Interior/Time of Day: shared add/edit dialogs, per-period columns, grouped entries, bulk actions, and font-relative sizing.
  • Documentation

    • Comprehensive Scene Settings Manager guide for modes, persistence, blending, UI, and mod-author guidance.
  • Quality

    • Improved validation, filtering, logging, and streamlined popup/state handling.

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Feb 18, 2026

📝 Walkthrough

Walkthrough

Adds Time of Day (TOD) support and blending: per-period SettingEntry, TOD lifecycle (activate/deactivate/update/blend), per-period persistence and overwrite discovery, new shared SceneSettings UI + TimeOfDayPanel, EM-based theme sizing, and calendar-preferred game-time retrieval.

Changes

Cohort / File(s) Summary
SceneSettingsManager core
src/SceneSettingsManager.h, src/SceneSettingsManager.cpp
Add TimeOfDayPeriod enum/constants and period on SettingEntry; period-aware Add/HasDuplicate/HasEntryForPeriod; TOD lifecycle APIs (Activate/Deactivate/Update/Apply/Save/Revert baselines), blending helpers, and integrations in LoadAll/Update/OnCellTransition.
Persistence & overwrite discovery
src/SceneSettingsManager.cpp
Serialize/deserialize per-period user entries; DiscoverOverwrites/DiscoverOverwritesInDir extended to scan per-period dirs and validate float invariants; Delete/Remove flows updated for per-period paths and baselines.
WeatherEditor — Time of Day UI
src/WeatherEditor/TimeOfDayPanel.h, src/WeatherEditor/TimeOfDayPanel.cpp
New TimeOfDayPanel: six-period UI, per-period add/edit/delete workflows, per-entry editors, pause/delete controls and confirmation popups; integrates with SceneSettingsManager.
WeatherEditor — Shared UI
src/WeatherEditor/SceneSettingsUI.h, src/WeatherEditor/SceneSettingsUI.cpp
New SceneSettingsUI utilities and persistent UI state (AddSettingState, PopupState): centralized add-setting dialog, value editors, grouped entry rendering, duplicate detection, and popup management shared by panels.
Editor integration
src/WeatherEditor/EditorWindow.cpp
Add "Time of Day" category and route category panels through SceneSettingsUI drawing paths.
Interior panel refactor
src/WeatherEditor/InteriorOnlyPanel.h, src/WeatherEditor/InteriorOnlyPanel.cpp
Refactor to use SceneSettingsUI helpers; remove per-panel add/entry APIs and consolidate popup/state to shared utilities.
Theme/layout constants
src/Menu/ThemeManager.h
Switch fixed pixel constants to font-relative EM multipliers via Constants::Em(float) and add TOD/layout constants (period cols, inactive alpha, thresholds, add-dialog sizes).
Utilities / Game time
src/WeatherEditor/WeatherUtils.cpp
GetCurrentGameTime now prefers calendar->gameHour (if valid) then sky->currentGameHour, with clamping and fallback to noon.
Docs
docs/development/scene-settings-manager.md
New developer documentation describing modes (Interior Only vs TOD), TOD blending/baselines, per-period persistence/discovery, UI workflows, and overwrite file format.
New UI modules / state
src/WeatherEditor/SceneSettingsUI.*, src/WeatherEditor/TimeOfDayPanel.*
Add UI modules and state for add dialogs, popups, filtering, duplicate checks, per-period UX wiring and confirmation flows.

Sequence Diagram(s)

sequenceDiagram
    participant UI as TimeOfDayPanel
    participant UIHelpers as SceneSettingsUI
    participant Manager as SceneSettingsManager
    participant Persist as FileStorage
    participant Feature as FeatureSystem

    UI->>UIHelpers: User adds/edits setting (feature,key,value,period)
    UIHelpers->>Manager: AddSetting(type, feature, key, value, period)
    Manager->>Manager: Validate type, period, float invariants
    Manager->>Persist: SaveUserSettings(type) [includes period metadata]
    Persist-->>Manager: Persisted ack
    UI->>Manager: Request current TOD state / dominant period
    Manager->>Manager: UpdateTimeOfDay() -> GetTimeOfDayFactors()
    Manager->>Manager: ApplyTimeOfDayBlended()
    Manager->>Feature: Apply blended values to features
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Possibly related PRs

Suggested reviewers

  • davo0411
  • doodlum

Poem

🐰🌅
I nibble dawn and tuck the night,
Six soft tabs tune the world's light.
I blend the hours and save the sight,
Overwrites pruned, baselines tight.
Hop — the scene wakes up just right.

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 27.27% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (2 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'feat(UI): Time of Day' clearly and concisely summarizes the main change—adding a Time of Day feature to the UI. It accurately reflects the substantial additions across SceneSettingsManager, UI components, and documentation.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 18, 2026

No actionable suggestions for changed features.

Dlizzio and others added 2 commits February 20, 2026 07:11
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Dlizzio and others added 4 commits February 23, 2026 15:36
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
@Dlizzio Dlizzio marked this pull request as ready for review February 24, 2026 02:31
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 4

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (2)
src/SceneSettingsManager.cpp (2)

239-312: ⚠️ Potential issue | 🟡 Minor

Reject TimeOfDay entries without a valid period

AddSetting accepts TimeOfDayPeriod::Count for TOD, which can create invisible entries that still trigger TOD activation. Add a guard to prevent invalid period input. As per coding guidelines: "Validate user input and prevent DirectX crashes from malformed configurations".

Suggested fix
 void SceneSettingsManager::AddSetting(SceneType type, const std::string& featureShortName, const std::string& settingKey, const json& value,
 	TimeOfDayPeriod period)
 {
+	if (type == SceneType::TimeOfDay && period == TimeOfDayPeriod::Count) {
+		logger::warn("[SceneSettings] Ignoring TOD entry without period: {}.{}", featureShortName, settingKey);
+		return;
+	}
 	if (HasDuplicateEntry(type, featureShortName, settingKey, EntrySource::User, period))
 		return;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 239 - 312, AddSetting currently
allows TimeOfDay entries with TimeOfDayPeriod::Count (an invalid sentinel) which
creates invisible/invalid entries; change AddSetting to validate input early: if
type == SceneType::TimeOfDay and period == TimeOfDayPeriod::Count then reject
(return) and optionally log or report an error; ensure this check happens before
calling HasDuplicateEntry/GetEntriesMut so no invalid entry is created or saved.

346-363: ⚠️ Potential issue | 🟠 Major

Delete-all skips TimeOfDay overwrite files in period subfolders

DeleteAllOverwrites uses the base directory even for TOD, so overwrite files under period subfolders remain on disk and will be reloaded later. This breaks expected behavior.

Suggested fix
 	for (const auto& entry : vec) {
-		if (entry.source == EntrySource::Overwrite && !entry.sourceFilename.empty())
-			std::filesystem::remove(overwritesPath / entry.sourceFilename, ec);
+		if (entry.source == EntrySource::Overwrite && !entry.sourceFilename.empty()) {
+			auto filePath = overwritesPath / entry.sourceFilename;
+			if (type == SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count)
+				filePath = overwritesPath / GetPeriodName(entry.period) / entry.sourceFilename;
+			std::filesystem::remove(filePath, ec);
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 346 - 363, DeleteAllOverwrites
currently only deletes files directly under GetOverwritesPath(type), so
TimeOfDay overwrite files stored in period subfolders are left on disk; update
DeleteAllOverwrites (which uses GetEntriesMut, EntrySource::Overwrite and
entry.sourceFilename) to remove matching files recursively for the TOD scene
type: obtain overwritesPath, and if type corresponds to TimeOfDay, iterate
std::filesystem::recursive_directory_iterator(overwritesPath) and delete any
file whose filename (or relative path if stored) matches entry.sourceFilename
(fall back to overwritesPath / entry.sourceFilename for non-TOD types or if
entry.sourceFilename already contains a subpath); leave the erase_if on the
entries vector, preserve setting of allOverwritesPausedMap[type] and the
ReapplyIfActive() call.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 793-799: The code uses lastAppliedTODFloats[shortName][key] which
default-inserts 0.0f, so the first blended value near zero gets skipped by the
kBlendEpsilon check; change the logic in the apply loop to detect whether an
entry already exists before doing the epsilon compare (e.g., use find/contains
on lastAppliedTODFloats for shortName and then for key, or initialize values to
a NaN sentinel and test std::isnan) and only perform the std::abs(cachedFloat -
result) < kBlendEpsilon comparison when a prior value is present; if there is no
prior value, set the cached value to result and push the key/result into
dirtyKeys unconditionally (or set sentinel/updated flag) so first-time ~0
results are applied.
- Around line 905-917: For TimeOfDay entries, ensure entries missing a period or
with an invalid period are skipped and a warning is logged: when type ==
SceneType::TimeOfDay, check item.contains("period") and call
GetPeriodFromName(item["period"].get<std::string>()); if the period is missing
or entry.period == TimeOfDayPeriod::Count, log a warning including
entry.featureShortName, entry.settingKey and the raw period value (so users can
fix malformed configs) and continue without pushing the entry; keep using
HasDuplicateEntry and EntrySource::User behavior unchanged for valid entries.
- Around line 779-811: Guard against NaN/Inf for all floats used in the TOD
blending path by adding std::isfinite checks (include <cmath>) after each
get<float>() call: in the block using baseline->get<float>() (baseVal) and for
pr.value->get<float>() and any factor values (f) read from
factors[pr.periodIdx]; if a value is not finite, replace it with a safe fallback
(e.g., 0.0f) before using it in the accumulation for result/coveredFactor so
shader-bound settings can't become NaN/Inf; keep existing comparisons with
lastAppliedTODFloats, kBlendEpsilon and dirtyKeys unchanged.

In `@src/WeatherEditor/TimeOfDayPanel.cpp`:
- Around line 172-201: The InputFloat handler for SettingType::Float must
validate the edited float before calling
manager->UpdateEntryValue/SaveUserSettings; currently a text edit can produce
NaN/Inf that gets persisted. After the ImGui::InputFloat returns true (or before
UpdateEntryValue is called), check the local float (val) with std::isfinite (or
!std::isnan && std::isfinite) and only call
manager->UpdateEntryValue(kSceneType, index, val, true) when the value is
finite; if it is not finite, reject the change (e.g., revert to a safe default
or skip the update) and do not call SaveUserSettings. Ensure the validation is
in the block handling SettingType::Float so malformed floats never reach
UpdateEntryValue/SaveUserSettings.

---

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 239-312: AddSetting currently allows TimeOfDay entries with
TimeOfDayPeriod::Count (an invalid sentinel) which creates invisible/invalid
entries; change AddSetting to validate input early: if type ==
SceneType::TimeOfDay and period == TimeOfDayPeriod::Count then reject (return)
and optionally log or report an error; ensure this check happens before calling
HasDuplicateEntry/GetEntriesMut so no invalid entry is created or saved.
- Around line 346-363: DeleteAllOverwrites currently only deletes files directly
under GetOverwritesPath(type), so TimeOfDay overwrite files stored in period
subfolders are left on disk; update DeleteAllOverwrites (which uses
GetEntriesMut, EntrySource::Overwrite and entry.sourceFilename) to remove
matching files recursively for the TOD scene type: obtain overwritesPath, and if
type corresponds to TimeOfDay, iterate
std::filesystem::recursive_directory_iterator(overwritesPath) and delete any
file whose filename (or relative path if stored) matches entry.sourceFilename
(fall back to overwritesPath / entry.sourceFilename for non-TOD types or if
entry.sourceFilename already contains a subpath); leave the erase_if on the
entries vector, preserve setting of allOverwritesPausedMap[type] and the
ReapplyIfActive() call.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 578f045 and 38f23a4.

📒 Files selected for processing (5)
  • src/SceneSettingsManager.cpp
  • src/SceneSettingsManager.h
  • src/WeatherEditor/EditorWindow.cpp
  • src/WeatherEditor/TimeOfDayPanel.cpp
  • src/WeatherEditor/TimeOfDayPanel.h

Comment thread src/SceneSettingsManager.cpp Outdated
Comment thread src/SceneSettingsManager.cpp Outdated
Comment thread src/SceneSettingsManager.cpp
Comment thread src/WeatherEditor/TimeOfDayPanel.cpp Outdated
@github-actions
Copy link
Copy Markdown

github-actions Bot commented Feb 24, 2026

✅ A pre-release build is available for this PR:
Download

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

347-364: ⚠️ Potential issue | 🟠 Major

DeleteAllOverwrites doesn't account for TOD period subfolders — files won't be deleted from disk.

RemoveSetting (line 298) and DiscoverOverwritesInDir (line 959) both route TOD overwrite files through period subfolders (e.g., TimeOfDay/Dawn/file.json), but DeleteAllOverwrites at line 355 always uses overwritesPath / entry.sourceFilename, which resolves to the wrong path for TOD entries. The in-memory entries are erased correctly, but the files persist on disk and will be rediscovered on the next load.

🐛 Proposed fix
 	auto& vec = GetEntriesMut(type);
 	for (const auto& entry : vec) {
-		if (entry.source == EntrySource::Overwrite && !entry.sourceFilename.empty())
-			std::filesystem::remove(overwritesPath / entry.sourceFilename, ec);
+		if (entry.source == EntrySource::Overwrite && !entry.sourceFilename.empty()) {
+			auto filepath = overwritesPath;
+			if (type == SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count)
+				filepath /= GetPeriodName(entry.period);
+			filepath /= entry.sourceFilename;
+			std::filesystem::remove(filepath, ec);
+		}
 	}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 347 - 364, DeleteAllOverwrites
removes in-memory overwrite entries but constructs the wrong filesystem path for
TimeOfDay (TOD) entries because it always uses GetOverwritesPath(type) /
entry.sourceFilename; update it to resolve the exact same on-disk path used by
RemoveSetting and DiscoverOverwritesInDir for TOD period subfolders.
Specifically, in SceneSettingsManager::DeleteAllOverwrites, when iterating
GetEntriesMut(type) and deleting files for entries with source ==
EntrySource::Overwrite, compute the file path the same way
RemoveSetting/DiscoverOverwritesInDir do for TOD (i.e., include the period
subfolder for SceneType::TimeOfDay) or call the same helper used by those
functions to build the path, then pass that resolved path to
std::filesystem::remove; keep the rest of the cleanup (std::erase_if,
allOverwritesPausedMap[type] = false, ReapplyIfActive()) unchanged.
🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

296-298: Consider breaking up the long ternary for readability.

Line 298 is hard to scan in one pass. A small helper or early if would clarify intent.

♻️ Suggested refactor
 		// For TimeOfDay overwrites, files are in period subfolders
 		auto basePath = GetOverwritesPath(type);
-		auto filepath = (type == SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count) ? basePath / GetPeriodName(entry.period) / entry.sourceFilename : basePath / entry.sourceFilename;
+		auto filepath = basePath;
+		if (type == SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count)
+			filepath /= GetPeriodName(entry.period);
+		filepath /= entry.sourceFilename;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 296 - 298, The ternary that builds
filepath is hard to read; refactor by computing basePath via
GetOverwritesPath(type) then use a small conditional to set filepath: if (type
== SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count) build
filepath by appending GetPeriodName(entry.period) and entry.sourceFilename to
basePath, otherwise set filepath to basePath / entry.sourceFilename; you can
also extract a helper like BuildOverwriteFilePath(type, entry) that encapsulates
this logic to improve clarity and reuse.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 404-408: UpdateEntryValue currently calls ApplyTimeOfDayBlended
but the hour-based throttle in ApplyTimeOfDayBlended (which compares current
hour to lastBlendedHour against kHourUpdateThreshold) prevents immediate
application when editing a TOD slider; before calling ApplyTimeOfDayBlended from
UpdateEntryValue (when type == SceneType::TimeOfDay and isTimeOfDayActive),
reset the sentinel lastBlendedHour to an out-of-range value (e.g., -1.0f) so the
throttle is bypassed and the new TOD value is applied immediately; locate the
lastBlendedHour variable and the call site in
UpdateEntryValue/ApplyTimeOfDayBlended to implement this change.
- Line 11: Remove the unused header include by deleting the line "#include
<numeric>" from SceneSettingsManager.cpp; ensure no other code in the file
references symbols from <numeric> so compilation is unaffected and run a build
to verify.

---

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 347-364: DeleteAllOverwrites removes in-memory overwrite entries
but constructs the wrong filesystem path for TimeOfDay (TOD) entries because it
always uses GetOverwritesPath(type) / entry.sourceFilename; update it to resolve
the exact same on-disk path used by RemoveSetting and DiscoverOverwritesInDir
for TOD period subfolders. Specifically, in
SceneSettingsManager::DeleteAllOverwrites, when iterating GetEntriesMut(type)
and deleting files for entries with source == EntrySource::Overwrite, compute
the file path the same way RemoveSetting/DiscoverOverwritesInDir do for TOD
(i.e., include the period subfolder for SceneType::TimeOfDay) or call the same
helper used by those functions to build the path, then pass that resolved path
to std::filesystem::remove; keep the rest of the cleanup (std::erase_if,
allOverwritesPausedMap[type] = false, ReapplyIfActive()) unchanged.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 296-298: The ternary that builds filepath is hard to read;
refactor by computing basePath via GetOverwritesPath(type) then use a small
conditional to set filepath: if (type == SceneType::TimeOfDay && entry.period !=
TimeOfDayPeriod::Count) build filepath by appending GetPeriodName(entry.period)
and entry.sourceFilename to basePath, otherwise set filepath to basePath /
entry.sourceFilename; you can also extract a helper like
BuildOverwriteFilePath(type, entry) that encapsulates this logic to improve
clarity and reuse.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 38f23a4 and 841dcc3.

📒 Files selected for processing (2)
  • src/SceneSettingsManager.cpp
  • src/WeatherEditor/TimeOfDayPanel.cpp
🚧 Files skipped from review as they are similar to previous changes (1)
  • src/WeatherEditor/TimeOfDayPanel.cpp

Comment thread src/SceneSettingsManager.cpp Outdated
Comment thread src/SceneSettingsManager.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

268-285: ⚠️ Potential issue | 🟡 Minor

Guard against TimeOfDay entries with invalid period.

If period == Count, the entry becomes invisible and later discarded on save/load. Skip and log to avoid ghost entries.
As per coding guidelines: “Validate user input and prevent DirectX crashes from malformed configurations.”

🛡️ Suggested fix
 void SceneSettingsManager::AddSetting(SceneType type, const std::string& featureShortName, const std::string& settingKey, const json& value,
 	TimeOfDayPeriod period)
 {
+	if (type == SceneType::TimeOfDay && period == TimeOfDayPeriod::Count) {
+		logger::warn("[SceneSettings] Skipping TOD entry with invalid period: {}.{}", featureShortName, settingKey);
+		return;
+	}
 	if (HasDuplicateEntry(type, featureShortName, settingKey, EntrySource::User, period))
 		return;
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 268 - 285, Add a guard in
SceneSettingsManager::AddSetting to skip creating entries when period ==
TimeOfDayPeriod::Count: at the top of AddSetting (before calling
HasDuplicateEntry/GetEntriesMut) check for that invalid enum value, log a
warning using the project's logging facility, and return early so no
SettingEntry is added, SaveUserSettings or ReapplyIfActive are invoked; keep
references to HasDuplicateEntry, GetEntriesMut, SaveUserSettings, and
ReapplyIfActive to help locate the correct spot to insert this validation.
🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

39-44: Optional: lock period-name table to kPeriodCount.

A tiny static_assert guards against future mismatches if the enum changes.

♻️ Suggested tweak
 const char* SceneSettingsManager::GetPeriodName(TimeOfDayPeriod period)
 {
 	static const char* names[] = { "Dawn", "Sunrise", "Day", "Sunset", "Dusk", "Night" };
+	static_assert(kPeriodCount == (sizeof(names) / sizeof(names[0])),
+		"Update period name table when kPeriodCount changes");
 	int idx = static_cast<int>(period);
 	return (idx >= 0 && idx < kPeriodCount) ? names[idx] : "Unknown";
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 39 - 44, Add a compile-time check
to guard the hard-coded names array length against changes to the
TimeOfDayPeriod enum: inside SceneSettingsManager::GetPeriodName, add a
static_assert that the number of entries in the local names array equals
kPeriodCount (referencing names and kPeriodCount) so any future enum change will
produce a build error if the table is not updated.

1-4: Conventional commit title + issue reference suggestion.

Consider adjusting the title to lowercase description (e.g., feat(ui): time of day) and, if there’s a tracking issue, add an “Implements #”/“Addresses #” reference in the PR description.
As per coding guidelines: “Conventional Commit Titles … lowercase description … Issue References (Fixes/Implements/Addresses/Related to #123).”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 1 - 4, Update the PR/commit title
to follow Conventional Commits (lowercase description, e.g., "feat(ui): time of
day") and add an issue reference in the PR description like "Implements #<id>"
or "Addresses #<id>"; locate the change related to SceneSettingsManager
(file/class SceneSettingsManager or the commit that added/modified
src/SceneSettingsManager.cpp) and amend the commit message or PR title
accordingly and add the appropriate issue line in the PR description before
merging.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 946-960: DeleteAllOverwrites currently only removes files from the
base overwrites directory and therefore misses TimeOfDay period subfolders;
update DeleteAllOverwrites to mirror DiscoverOverwrites behavior: if scene type
== SceneType::TimeOfDay iterate for i in 0..kPeriodCount, build each periodPath
= GetOverwritesPath(type) / GetPeriodName(static_cast<TimeOfDayPeriod>(i)) and
delete entries in each periodPath (reuse the same deletion logic used for base
dir), otherwise delete from GetOverwritesPath(type) as before so TOD period
files are removed.
- Around line 734-847: The float extraction calls in ApplyTimeOfDayBlended
(baseline->get<float>() and pr.value->get<float()>) can throw on
malformed/non-numeric JSON; before calling get<float>() validate types (e.g.,
json::is_number() or reuse DetectSettingType) and if baseline is not numeric
skip treating the key as a float (log a warning) and if a period value is
non-numeric treat that period as absent (skip its contribution or use 0.0f per
existing behavior) instead of calling get<float>(); update the float path in
SceneSettingsManager::ApplyTimeOfDayBlended to perform these checks around
baseVal and periodVal extraction and ensure dirtyKeys/featureFloats logic
remains consistent when skipping invalid entries.
- Around line 917-930: The TimeOfDay parsing block in SceneSettingsManager calls
item["period"].get<std::string>() without validating the JSON type, which can
throw; update the TimeOfDay branch to first check item["period"].is_string() (or
equivalent) and if not, log a warn via logger::warn referencing
entry.featureShortName and entry.settingKey and skip the entry, otherwise call
GetPeriodFromName on the string and keep the existing invalid-period check
(TimeOfDayPeriod::Count) and continue behavior; ensure you reference the same
symbols (SceneType::TimeOfDay, item["period"], GetPeriodFromName, entry.period)
so the change is localized.

---

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 268-285: Add a guard in SceneSettingsManager::AddSetting to skip
creating entries when period == TimeOfDayPeriod::Count: at the top of AddSetting
(before calling HasDuplicateEntry/GetEntriesMut) check for that invalid enum
value, log a warning using the project's logging facility, and return early so
no SettingEntry is added, SaveUserSettings or ReapplyIfActive are invoked; keep
references to HasDuplicateEntry, GetEntriesMut, SaveUserSettings, and
ReapplyIfActive to help locate the correct spot to insert this validation.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 39-44: Add a compile-time check to guard the hard-coded names
array length against changes to the TimeOfDayPeriod enum: inside
SceneSettingsManager::GetPeriodName, add a static_assert that the number of
entries in the local names array equals kPeriodCount (referencing names and
kPeriodCount) so any future enum change will produce a build error if the table
is not updated.
- Around line 1-4: Update the PR/commit title to follow Conventional Commits
(lowercase description, e.g., "feat(ui): time of day") and add an issue
reference in the PR description like "Implements #<id>" or "Addresses #<id>";
locate the change related to SceneSettingsManager (file/class
SceneSettingsManager or the commit that added/modified
src/SceneSettingsManager.cpp) and amend the commit message or PR title
accordingly and add the appropriate issue line in the PR description before
merging.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 841dcc3 and 64ad0f7.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp
Comment thread src/SceneSettingsManager.cpp
Comment thread src/SceneSettingsManager.cpp
Dlizzio and others added 3 commits February 23, 2026 20:38
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (3)
src/SceneSettingsManager.cpp (3)

239-285: ⚠️ Potential issue | 🟡 Minor

Block TOD entries with invalid period to avoid ghost records.
AddSetting() allows TimeOfDayPeriod::Count for TOD entries, which creates entries that save but never apply. Guard it and log a warning.

🔧 Proposed fix
 void SceneSettingsManager::AddSetting(SceneType type, const std::string& featureShortName, const std::string& settingKey, const json& value,
 	TimeOfDayPeriod period)
 {
+	if (type == SceneType::TimeOfDay && period == TimeOfDayPeriod::Count) {
+		logger::warn("[SceneSettings] Skipping TOD entry with invalid period: {}.{}", featureShortName, settingKey);
+		return;
+	}
 	if (HasDuplicateEntry(type, featureShortName, settingKey, EntrySource::User, period))
 		return;
As per coding guidelines: “Validate user input and prevent DirectX crashes from malformed configurations.”
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 239 - 285, AddSetting currently
allows creating TimeOfDay entries with an invalid period
(TimeOfDayPeriod::Count), producing saved but never-applied "ghost" records;
update SceneSettingsManager::AddSetting to validate the period when type ==
SceneType::TimeOfDay and reject TimeOfDayPeriod::Count (log a warning) before
calling HasDuplicateEntry or pushing the entry, so invalid TOD entries are
blocked and no ghost records are saved (use the existing logging facility and
return early on invalid period).

15-24: ⚠️ Potential issue | 🟡 Minor

Adjust PR title to conventional commit style and add issue link if any.
The current title uses uppercase scope/description. Suggest feat(ui): time of day and, if there’s a tracking issue, add “Implements #…/Related to #…”.

As per coding guidelines: “Conventional Commit Titles … Format: type(scope): description … lowercase description, no ending period” and “Issue References … ‘Implements #123’/‘Related to #123’ for features.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 15 - 24, Change the PR title to
follow Conventional Commits (e.g., use "feat(ui): time of day" — lowercase
description, no trailing period) and, if there is a tracking issue, append an
issue reference like "Implements `#123`" or "Related to `#123`"; this is independent
of the code in SceneSettingsManager::GetSceneTypeName in
src/SceneSettingsManager.cpp but do the PR title edit and add the issue link to
the PR/commit message accordingly.

918-948: ⚠️ Potential issue | 🟠 Major

Guard feature and setting fields with type checks to prevent JSON parse exceptions on malformed user config.

get<std::string>() throws on non-string values. Currently only existence is checked; add type validation and skip bad entries with warnings, matching the pattern already established for period field parsing (lines 937–941).

Proposed fix
-			entry.featureShortName = item["feature"].get<std::string>();
-			entry.settingKey = item["setting"].get<std::string>();
+			if (!item["feature"].is_string() || !item["setting"].is_string()) {
+				logger::warn("SceneSettingsManager: Entry has non-string feature/setting (feature type: {}, setting type: {}) — skipping",
+					item["feature"].type_name(), item["setting"].type_name());
+				continue;
+			}
+			entry.featureShortName = item["feature"].get<std::string>();
+			entry.settingKey = item["setting"].get<std::string>();

Without these checks, malformed JSON causes the entire settings file to fail loading instead of gracefully skipping the bad entry.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 918 - 948, The code currently
assumes item["feature"] and item["setting"] are strings and calls
get<std::string>() which will throw on malformed JSON; update the loop that
fills SettingEntry (in the GetEntriesMut/type handling) to first validate
item.contains("feature") && item["feature"].is_string() and
item.contains("setting") && item["setting"].is_string(), and if either check
fails call logger::warn with context including the offending item type (use
item["feature"].type_name() / item["setting"].type_name() where available) and
continue to skip the entry; keep the existing TimeOfDay period parsing
(GetPeriodFromName, TimeOfDayPeriod::Count) unchanged but ensure the earlier
string checks prevent exceptions when creating SettingEntry.featureShortName and
SettingEntry.settingKey.
🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

55-65: Verify SE/AE/VR safety for calendar/sky hour access.
Please confirm RE::Calendar::gameHour and RE::Sky::currentGameHour offsets are correct across SE/AE/VR and consider REL::RelocateMember() + runtime detection for version-safe access.

As per coding guidelines: “Warn about SE/AE/VR compatibility issues and suggest REL::RelocateMember() patterns for runtime compatibility” and “Ensure changes work across SE/AE/VR variants using runtime detection.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 55 - 65,
SceneSettingsManager::GetCurrentGameHour directly dereferences
calendar->gameHour and sky->currentGameHour which may have different offsets
across SE/AE/VR; update the accessor to use runtime-safe member relocation and
version detection (e.g., use REL::Module::IsEditor() / runtime variant checks or
existing runtime detection utilities) and REL::RelocateMember() to compute the
correct offsets for RE::Calendar::gameHour and RE::Sky::currentGameHour before
reading them; ensure you check the relocated pointer/float for null/validity and
fall back to the current 12.0f default if access fails, and keep the current
clamping logic in GetCurrentGameHour.

39-53: Make period parsing resilient to case differences.
GetPeriodFromName() requires exact casing, so user-edited JSON like “dawn” will be rejected. Consider normalizing case to make configs more forgiving.

As per coding guidelines: “Validate user input and prevent DirectX crashes from malformed configurations.”

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 39 - 53, GetPeriodFromName
currently does a case-sensitive comparison against GetPeriodName, so names like
"dawn" fail; make parsing case-insensitive by normalizing the input and the
compared period names to a common case (e.g., lowercase) before comparing.
Update SceneSettingsManager::GetPeriodFromName to transform the input
std::string (and/or the GetPeriodName() result) using a locale-independent ASCII
tolower conversion (or std::transform with ::tolower) and then compare against
the lowercased GetPeriodName(static_cast<TimeOfDayPeriod>(i)) for i in [0,
kPeriodCount), still returning TimeOfDayPeriod::Count on no match. Ensure you
reference TimeOfDayPeriod, GetPeriodFromName, GetPeriodName, and kPeriodCount
when making the change.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 738-859: The non-float branch in
SceneSettingsManager::ApplyTimeOfDayBlended copies period JSON values into
blendedValue without validating their types, which can cause json::type_error
when feature->LoadSettings() later calls .get<T>(); fix by checking each
pr.value's type against the baseline's type (from savedTimeOfDayBaseline) using
DetectSettingType(baseline) and the json type predicates (e.g.,
is_boolean/is_string/is_number_integer) before assigning blendedValue, fall back
to the baseline when the period value's type mismatches (and log a warning), and
keep lastAppliedTODOther/cache updates unchanged so only validated values are
applied to Feature::FindFeatureByShortName(...)->LoadSettings().

---

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 239-285: AddSetting currently allows creating TimeOfDay entries
with an invalid period (TimeOfDayPeriod::Count), producing saved but
never-applied "ghost" records; update SceneSettingsManager::AddSetting to
validate the period when type == SceneType::TimeOfDay and reject
TimeOfDayPeriod::Count (log a warning) before calling HasDuplicateEntry or
pushing the entry, so invalid TOD entries are blocked and no ghost records are
saved (use the existing logging facility and return early on invalid period).
- Around line 15-24: Change the PR title to follow Conventional Commits (e.g.,
use "feat(ui): time of day" — lowercase description, no trailing period) and, if
there is a tracking issue, append an issue reference like "Implements `#123`" or
"Related to `#123`"; this is independent of the code in
SceneSettingsManager::GetSceneTypeName in src/SceneSettingsManager.cpp but do
the PR title edit and add the issue link to the PR/commit message accordingly.
- Around line 918-948: The code currently assumes item["feature"] and
item["setting"] are strings and calls get<std::string>() which will throw on
malformed JSON; update the loop that fills SettingEntry (in the
GetEntriesMut/type handling) to first validate item.contains("feature") &&
item["feature"].is_string() and item.contains("setting") &&
item["setting"].is_string(), and if either check fails call logger::warn with
context including the offending item type (use item["feature"].type_name() /
item["setting"].type_name() where available) and continue to skip the entry;
keep the existing TimeOfDay period parsing (GetPeriodFromName,
TimeOfDayPeriod::Count) unchanged but ensure the earlier string checks prevent
exceptions when creating SettingEntry.featureShortName and
SettingEntry.settingKey.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 55-65: SceneSettingsManager::GetCurrentGameHour directly
dereferences calendar->gameHour and sky->currentGameHour which may have
different offsets across SE/AE/VR; update the accessor to use runtime-safe
member relocation and version detection (e.g., use REL::Module::IsEditor() /
runtime variant checks or existing runtime detection utilities) and
REL::RelocateMember() to compute the correct offsets for RE::Calendar::gameHour
and RE::Sky::currentGameHour before reading them; ensure you check the relocated
pointer/float for null/validity and fall back to the current 12.0f default if
access fails, and keep the current clamping logic in GetCurrentGameHour.
- Around line 39-53: GetPeriodFromName currently does a case-sensitive
comparison against GetPeriodName, so names like "dawn" fail; make parsing
case-insensitive by normalizing the input and the compared period names to a
common case (e.g., lowercase) before comparing. Update
SceneSettingsManager::GetPeriodFromName to transform the input std::string
(and/or the GetPeriodName() result) using a locale-independent ASCII tolower
conversion (or std::transform with ::tolower) and then compare against the
lowercased GetPeriodName(static_cast<TimeOfDayPeriod>(i)) for i in [0,
kPeriodCount), still returning TimeOfDayPeriod::Count on no match. Ensure you
reference TimeOfDayPeriod, GetPeriodFromName, GetPeriodName, and kPeriodCount
when making the change.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 64ad0f7 and b1fd6b8.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp
@Dlizzio Dlizzio marked this pull request as draft February 24, 2026 04:26
@Dlizzio Dlizzio marked this pull request as ready for review February 24, 2026 05:07
pre-commit-ci Bot and others added 2 commits February 24, 2026 05:08
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
@Dlizzio Dlizzio marked this pull request as draft February 24, 2026 07:06
@Dlizzio Dlizzio marked this pull request as ready for review February 24, 2026 11:11
Automated formatting by clang-format, prettier, and other hooks.
See https://pre-commit.ci for details.
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

300-320: ⚠️ Potential issue | 🟠 Major

Validate TimeOfDay period before inserting entries

AddSetting accepts period = TimeOfDayPeriod::Count (or other invalid cast values). Those entries are then skipped by blending, and they serialize without "period" (Line 957), creating ghost/inert entries and reload loss.

🛠️ Proposed fix
 void SceneSettingsManager::AddSetting(SceneType type, const std::string& featureShortName, const std::string& settingKey, const json& value,
 	TimeOfDayPeriod period)
 {
 	// TOD only supports float settings (smooth interpolation)
-	if (type == SceneType::TimeOfDay && DetectSettingType(value) != SettingType::Float) {
-		logger::warn("[SceneSettings] Rejecting non-float TOD setting: {}.{}", featureShortName, settingKey);
-		return;
-	}
+	if (type == SceneType::TimeOfDay) {
+		const int periodIdx = static_cast<int>(period);
+		if (period == TimeOfDayPeriod::Count || periodIdx < 0 || periodIdx >= kPeriodCount) {
+			logger::warn("[SceneSettings] Rejecting TOD setting with invalid period: {}.{}", featureShortName, settingKey);
+			return;
+		}
+		if (DetectSettingType(value) != SettingType::Float) {
+			logger::warn("[SceneSettings] Rejecting non-float TOD setting: {}.{}", featureShortName, settingKey);
+			return;
+		}
+	}

As per coding guidelines: "Include proper resource management and graceful degradation for DirectX 11 resources and user input validation to prevent crashes from malformed configurations."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 300 - 320, Add validation in
SceneSettingsManager::AddSetting to reject invalid TimeOfDayPeriod values (e.g.,
TimeOfDayPeriod::Count or any out-of-range/invalid cast) before creating or
pushing the SettingEntry: if type == SceneType::TimeOfDay and period is not a
valid TimeOfDayPeriod, log a warning (similar style to the existing
logger::warn) and return early; ensure you reference the TimeOfDayPeriod enum
for validation and avoid pushing into vec returned by GetEntriesMut or calling
HasDuplicateEntry for invalid periods so serialization and blending code (which
expects a valid period) won't produce ghost/inert entries.
🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

1-1: Optional: tighten PR metadata for traceability

Consider a conventional-commit style title like feat(ui): add time-of-day scene settings, and add an issue link in the PR body (e.g., Implements #<id> / Addresses #<id>).

As per coding guidelines: "**/*: provide suggestions for Conventional Commit Titles and Issue References for features/bugfixes."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR title and body to
follow conventional commits and include an issue reference: rename the PR title
to a conventional-commit style (for example "feat(ui): add time-of-day scene
settings") and add an issue link in the PR description like "Implements #<id>"
or "Addresses #<id>"; mention the affected file/class (SceneSettingsManager.cpp
/ SceneSettingsManager) in the PR body so reviewers can quickly map the change
to the code.

1007-1032: Keep TOD load behavior consistent with the float-only contract

AddSetting and overwrite discovery both reject non-float TOD entries, but LoadUserSettings currently accepts them. Consider filtering non-float TOD values here too, so malformed JSON can’t bypass the runtime contract.

♻️ Suggested hardening
 			if (type == SceneType::TimeOfDay) {
 				if (!item.contains("period")) {
 					logger::warn("SceneSettingsManager: TimeOfDay entry for feature '{}' key '{}' is missing 'period' — skipping to avoid ghost entry",
 						entry.featureShortName, entry.settingKey);
 					continue;
 				}
+				if (DetectSettingType(entry.value) != SettingType::Float) {
+					logger::warn("SceneSettingsManager: TimeOfDay entry for feature '{}' key '{}' has non-float value — skipping",
+						entry.featureShortName, entry.settingKey);
+					continue;
+				}
 				if (!item["period"].is_string()) {

As per coding guidelines: "Include proper resource management and graceful degradation for DirectX 11 resources and user input validation to prevent crashes from malformed configurations."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 1007 - 1032, LoadUserSettings
currently accepts TimeOfDay entries with non-float values; mirror the validation
used by AddSetting by checking the JSON "value" for TimeOfDay entries and
rejecting any non-numeric/ non-float values before pushing the entry. Inside the
block handling SceneType::TimeOfDay (alongside the existing period checks and
GetPeriodFromName/TimeOfDayPeriod::Count validation), verify
item.contains("value") and that item["value"].is_number() (or convertible to
float); if not, emit a logger::warn mentioning entry.featureShortName and
entry.settingKey and continue to skip the entry so HasDuplicateEntry /
vec.push_back(std::move(entry)) never receives malformed TOD values. Ensure this
keeps behavior consistent with AddSetting and other overwrite discovery paths.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 300-320: Add validation in SceneSettingsManager::AddSetting to
reject invalid TimeOfDayPeriod values (e.g., TimeOfDayPeriod::Count or any
out-of-range/invalid cast) before creating or pushing the SettingEntry: if type
== SceneType::TimeOfDay and period is not a valid TimeOfDayPeriod, log a warning
(similar style to the existing logger::warn) and return early; ensure you
reference the TimeOfDayPeriod enum for validation and avoid pushing into vec
returned by GetEntriesMut or calling HasDuplicateEntry for invalid periods so
serialization and blending code (which expects a valid period) won't produce
ghost/inert entries.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR title and body to follow conventional commits and
include an issue reference: rename the PR title to a conventional-commit style
(for example "feat(ui): add time-of-day scene settings") and add an issue link
in the PR description like "Implements #<id>" or "Addresses #<id>"; mention the
affected file/class (SceneSettingsManager.cpp / SceneSettingsManager) in the PR
body so reviewers can quickly map the change to the code.
- Around line 1007-1032: LoadUserSettings currently accepts TimeOfDay entries
with non-float values; mirror the validation used by AddSetting by checking the
JSON "value" for TimeOfDay entries and rejecting any non-numeric/ non-float
values before pushing the entry. Inside the block handling SceneType::TimeOfDay
(alongside the existing period checks and
GetPeriodFromName/TimeOfDayPeriod::Count validation), verify
item.contains("value") and that item["value"].is_number() (or convertible to
float); if not, emit a logger::warn mentioning entry.featureShortName and
entry.settingKey and continue to skip the entry so HasDuplicateEntry /
vec.push_back(std::move(entry)) never receives malformed TOD values. Ensure this
keeps behavior consistent with AddSetting and other overwrite discovery paths.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8995ea4 and 5668063.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

448-460: ⚠️ Potential issue | 🟠 Major

Validate TOD edit values before storing

UpdateEntryValue currently accepts any JSON for TOD entries, bypassing the float-only guard used in AddSetting/overwrite loading. Invalid edits can still enter blending state.

Suggested fix
 void SceneSettingsManager::UpdateEntryValue(SceneType type, size_t index, const json& newValue, bool deferSave)
 {
 	auto& vec = GetEntriesMut(type);
 	if (index >= vec.size())
 		return;

-	vec[index].value = newValue;
+	if (type == SceneType::TimeOfDay) {
+		if (!newValue.is_number()) {
+			logger::warn("[SceneSettings] Rejecting non-numeric TOD edit: {}.{}", vec[index].featureShortName, vec[index].settingKey);
+			return;
+		}
+		float v = newValue.get<float>();
+		if (!std::isfinite(v)) {
+			logger::warn("[SceneSettings] Rejecting non-finite TOD edit: {}.{}", vec[index].featureShortName, vec[index].settingKey);
+			return;
+		}
+		vec[index].value = v;
+	} else {
+		vec[index].value = newValue;
+	}

As per coding guidelines: "Include proper resource management and graceful degradation for DirectX 11 resources and user input validation to prevent crashes from malformed configurations"

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 448 - 460, UpdateEntryValue
currently writes arbitrary JSON into vec[index].value for SceneType::TimeOfDay
and can introduce non-float values into blending; before assigning newValue in
UpdateEntryValue (the block that sets vec[index].value and the subsequent
TimeOfDay branch), validate that newValue is a numeric float (match the same
guard used by AddSetting/overwrite loading), and if it fails, reject the update
(do not assign, do not call SaveUserSettings, do not touch lastBlendedHour or
call ApplyTimeOfDayBlended) and optionally log or return an error; keep the
existing behavior for non-TimeOfDay types and ensure the validation only
triggers when type == SceneType::TimeOfDay and vec[index].source ==
EntrySource::User or whenever user edits are allowed.
🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

1-1: Optional PR metadata polish: conventional title + issue link

Suggested title style: feat(ui): add time-of-day scene settings (lowercase scope/description).
If this implements a tracked issue, add Implements #<id> (or Addresses #<id>) in the PR body.

As per coding guidelines: "When reviewing PRs, please provide suggestions for Conventional Commit Titles ... [and] Issue References..."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR metadata: change the
PR title to follow Conventional Commits (e.g., "feat(ui): add time-of-day scene
settings") and, if this change implements or addresses a tracked issue, add an
issue reference like "Implements #<id>" or "Addresses #<id>" in the PR body;
locate this change alongside the SceneSettingsManager.cpp-related commit so the
PR title and body clearly reference the file and intent.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 914-917: The code treats malformed TOD period values as a numeric
zero by adding f to coveredFactor inside the pr.value->is_number() false branch;
instead, do not add f to coveredFactor for invalid samples so their weight falls
back to the baseline blend. In other words, in SceneSettingsManager where you
check pr.value->is_number() and currently call coveredFactor += f, remove that
increment (leave coveredFactor unchanged) so invalid entries are skipped and the
baseline blending logic receives their weight.
- Around line 1034-1039: Load path currently accepts any JSON number
(entry.value.is_number()), causing inconsistency with AddSetting which enforces
float-only TOD values; update the TimeOfDay loading code in SceneSettingsManager
to only accept floating-point numbers by replacing entry.value.is_number() with
entry.value.is_number_float(), and adjust the warn message to state "non-float
value" (so integers/unsigned are rejected the same way as AddSetting),
referencing the existing AddSetting behavior and the entry.value checks in this
load block.

---

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 448-460: UpdateEntryValue currently writes arbitrary JSON into
vec[index].value for SceneType::TimeOfDay and can introduce non-float values
into blending; before assigning newValue in UpdateEntryValue (the block that
sets vec[index].value and the subsequent TimeOfDay branch), validate that
newValue is a numeric float (match the same guard used by AddSetting/overwrite
loading), and if it fails, reject the update (do not assign, do not call
SaveUserSettings, do not touch lastBlendedHour or call ApplyTimeOfDayBlended)
and optionally log or return an error; keep the existing behavior for
non-TimeOfDay types and ensure the validation only triggers when type ==
SceneType::TimeOfDay and vec[index].source == EntrySource::User or whenever user
edits are allowed.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR metadata: change the PR title to follow Conventional
Commits (e.g., "feat(ui): add time-of-day scene settings") and, if this change
implements or addresses a tracked issue, add an issue reference like "Implements
#<id>" or "Addresses #<id>" in the PR body; locate this change alongside the
SceneSettingsManager.cpp-related commit so the PR title and body clearly
reference the file and intent.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 5668063 and 1d0e13f.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp Outdated
Comment thread src/SceneSettingsManager.cpp Outdated
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

1003-1011: ⚠️ Potential issue | 🟠 Major

Harden per-item parsing so one malformed entry doesn't abort the entire settings file load.

Lines 1008–1009 directly call .get<std::string>() on item["feature"] and item["setting"] without validating type first. If either field is not a string (e.g., "feature": 123), it throws and the outer catch at line 1050 fails the entire file load, skipping all remaining valid entries. The same function already implements the correct pattern for the "period" field (lines 1021–1023) using .is_string() checks with logging.

🛠️ Proposed fix
 		for (const auto& item : data) {
 			if (!item.contains("feature") || !item.contains("setting") || !item.contains("value"))
 				continue;
+			if (!item["feature"].is_string() || !item["setting"].is_string()) {
+				logger::warn("SceneSettingsManager: skipping entry with non-string feature/setting (feature type: {}, setting type: {})",
+					item.contains("feature") ? item["feature"].type_name() : "missing",
+					item.contains("setting") ? item["setting"].type_name() : "missing");
+				continue;
+			}
 
 			SettingEntry entry;
 			entry.featureShortName = item["feature"].get<std::string>();
 			entry.settingKey = item["setting"].get<std::string>();
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 1003 - 1011, The loop that builds
SettingEntry objects currently calls item["feature"].get<std::string>() and
item["setting"].get<std::string>() without type checks, which can throw and
abort the whole load; update the parsing in the for-loop that constructs
SettingEntry (the code that assigns entry.featureShortName and entry.settingKey)
to first verify item["feature"].is_string() and item["setting"].is_string(), log
a warning if either is missing or the wrong type (consistent with the existing
period handling), and skip that single item instead of throwing; keep assigning
entry.value and entry.paused as before and only push the entry when both string
checks pass.
🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

1-1: PR metadata polish: align title casing and add issue linkage if applicable.

Suggested title: feat(ui): add time-of-day scene settings
If this maps to a tracked issue, add Implements #<id> (or Addresses #<id>) in the PR body.

As per coding guidelines: "**/*: provide suggestions for Conventional Commit titles and Issue References when applicable."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR metadata to use the
suggested conventional commit title casing by renaming the PR title to
"feat(ui): add time-of-day scene settings" and, if this work maps to a tracked
issue, add an issue reference line (e.g., "Implements #<id>" or "Addresses
#<id>") in the PR body; this applies to the change touching SceneSettingsManager
(class/filename SceneSettingsManager.cpp) so include that context in the PR
description.

442-460: Keep TOD type invariants consistent in UpdateEntryValue.

AddSetting, overwrite discovery, and load all enforce float-only TOD values, but edit path currently accepts any JSON type. Add the same guard here to keep runtime behavior consistent.

♻️ Proposed fix
 void SceneSettingsManager::UpdateEntryValue(SceneType type, size_t index, const json& newValue, bool deferSave)
 {
 	auto& vec = GetEntriesMut(type);
 	if (index >= vec.size())
 		return;
+
+	if (type == SceneType::TimeOfDay && DetectSettingType(newValue) != SettingType::Float) {
+		logger::warn("[SceneSettings] Rejecting non-float TOD value edit: {}.{}", vec[index].featureShortName, vec[index].settingKey);
+		return;
+	}

 	vec[index].value = newValue;

As per coding guidelines: "Include proper resource management and graceful degradation for DirectX 11 resources and user input validation to prevent crashes from malformed configurations".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 442 - 460, UpdateEntryValue
currently accepts any JSON for SceneType::TimeOfDay which breaks the float-only
invariants enforced elsewhere; add a guard at the start of the TimeOfDay branch
in SceneSettingsManager::UpdateEntryValue to validate and normalize newValue to
float-only form: if newValue is a number convert/store as a float JSON, if it is
an array ensure every element is numeric and convert each to float, otherwise
reject the update (do not modify vec[index].value) and return; keep the existing
behavior of calling SaveUserSettings (via SaveUserSettings) when source is
EntrySource::User and deferSave is false, and preserve the existing time-of-day
post-update logic (reset lastBlendedHour, check isTimeOfDayActive, call
ApplyTimeOfDayBlended) only after successful validation/normalization.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 1003-1011: The loop that builds SettingEntry objects currently
calls item["feature"].get<std::string>() and item["setting"].get<std::string>()
without type checks, which can throw and abort the whole load; update the
parsing in the for-loop that constructs SettingEntry (the code that assigns
entry.featureShortName and entry.settingKey) to first verify
item["feature"].is_string() and item["setting"].is_string(), log a warning if
either is missing or the wrong type (consistent with the existing period
handling), and skip that single item instead of throwing; keep assigning
entry.value and entry.paused as before and only push the entry when both string
checks pass.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR metadata to use the suggested conventional commit title
casing by renaming the PR title to "feat(ui): add time-of-day scene settings"
and, if this work maps to a tracked issue, add an issue reference line (e.g.,
"Implements #<id>" or "Addresses #<id>") in the PR body; this applies to the
change touching SceneSettingsManager (class/filename SceneSettingsManager.cpp)
so include that context in the PR description.
- Around line 442-460: UpdateEntryValue currently accepts any JSON for
SceneType::TimeOfDay which breaks the float-only invariants enforced elsewhere;
add a guard at the start of the TimeOfDay branch in
SceneSettingsManager::UpdateEntryValue to validate and normalize newValue to
float-only form: if newValue is a number convert/store as a float JSON, if it is
an array ensure every element is numeric and convert each to float, otherwise
reject the update (do not modify vec[index].value) and return; keep the existing
behavior of calling SaveUserSettings (via SaveUserSettings) when source is
EntrySource::User and deferSave is false, and preserve the existing time-of-day
post-update logic (reset lastBlendedHour, check isTimeOfDayActive, call
ApplyTimeOfDayBlended) only after successful validation/normalization.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 1d0e13f and 6667bd7.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

1-1: Consider tightening PR metadata scope to match runtime changes

The title feat(UI): Time of Day undersells the large SceneSettingsManager runtime/persistence changes. A more precise option is feat(scene-settings): add time-of-day blending. If this maps to a tracked task, add an issue reference (e.g., Implements #<id>).

As per coding guidelines: "Conventional Commit Titles ... type(scope): description" and "Issue References ... Implements #123 / Addresses #123".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR/commit title and
metadata to follow Conventional Commits and accurately reflect the
runtime/persistence changes in SceneSettingsManager: change the title to
something like "feat(scene-settings): add time-of-day blending" and, if this
work maps to a tracked task, append an issue reference (e.g., "Implements
#<id>"). Ensure the scope uses "scene-settings" and the description mentions
"time-of-day blending" so it maps to changes in SceneSettingsManager (class/file
SceneSettingsManager.cpp) and related persistence/runtime updates.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 1018-1029: The code currently uses item.value("paused", false)
which throws if paused exists but isn't a boolean; update the logic around
SettingEntry assignment to first check item.contains("paused") and
item["paused"].is_boolean() (or use is_null/is_boolean as appropriate) before
calling entry.paused = item.value("paused", false); if the paused field exists
but is not a boolean, log a warning via logger::warn referencing the
feature/setting (same context as the existing skip log) and leave entry.paused
as the default false; keep the rest of the population (entry.featureShortName,
entry.settingKey, entry.value, entry.source) unchanged so only the paused
extraction is guarded.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR/commit title and metadata to follow Conventional Commits
and accurately reflect the runtime/persistence changes in SceneSettingsManager:
change the title to something like "feat(scene-settings): add time-of-day
blending" and, if this work maps to a tracked task, append an issue reference
(e.g., "Implements #<id>"). Ensure the scope uses "scene-settings" and the
description mentions "time-of-day blending" so it maps to changes in
SceneSettingsManager (class/file SceneSettingsManager.cpp) and related
persistence/runtime updates.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 6667bd7 and af9d40f.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp
@Dlizzio
Copy link
Copy Markdown
Contributor Author

Dlizzio commented Mar 2, 2026

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 2, 2026

✅ Actions performed

Reviews resumed.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

340-349: ⚠️ Potential issue | 🟠 Major

Handle filesystem delete outcomes correctly before dropping overwrite entries

Line 345 can log a false error when remove() returns false with no ec (already missing file), and Line 399–409 removes in-memory overwrite entries even if on-disk deletion fails. That can make files reappear on next startup without clear diagnosis.

🛠️ Suggested fix
@@
-		if (std::filesystem::remove(filepath, ec))
+		ec.clear();
+		if (std::filesystem::remove(filepath, ec))
 			logger::info("[SceneSettings] Deleted overwrite file: {}", filepath.string());
-		else
+		else if (ec)
 			logger::error("[SceneSettings] Failed to delete overwrite file: {} ({})", filepath.string(), ec.message());
+		else
+			logger::debug("[SceneSettings] Overwrite file already absent: {}", filepath.string());
@@
-	for (const auto& entry : vec) {
+	std::unordered_set<std::string> failedDeletes;
+	for (const auto& entry : vec) {
 		if (entry.source == EntrySource::Overwrite && !entry.sourceFilename.empty()) {
@@
-			std::filesystem::remove(filepath, ec);
+			ec.clear();
+			const bool removed = std::filesystem::remove(filepath, ec);
+			if (!removed && ec) {
+				logger::error("[SceneSettings] Failed to delete overwrite file: {} ({})", filepath.string(), ec.message());
+				failedDeletes.insert(entry.sourceFilename);
+			}
 		}
 	}
@@
-	std::erase_if(vec, [](const SettingEntry& e) {
-		return e.source == EntrySource::Overwrite;
+	std::erase_if(vec, [&](const SettingEntry& e) {
+		return e.source == EntrySource::Overwrite &&
+		       (e.sourceFilename.empty() || !failedDeletes.contains(e.sourceFilename));
 	});

Based on learnings: "file deletion error handling improvements ... with std::filesystem::remove error-code-based approaches are considered bug fixes rather than refactoring."

Also applies to: 399-409

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 340 - 349, The delete handling
currently treats any false return from std::filesystem::remove as an error and
then still drops the in-memory overwrite entry; change the logic in
SceneSettingsManager where it builds filepath (using GetOverwritesPath,
entry.sourceFilename, entry.period, TimeOfDayPeriod) to inspect the
std::error_code after remove: if remove succeeds or remove returns false with
ec.value()==0 (meaning the file simply did not exist) treat as success and log
info, but if ec indicates an actual error log an error and do NOT erase the
corresponding in-memory overwrite entry; apply the same check before the
in-memory removal loop (the block that currently removes overwrite entries
around the 399–409 area) so disk-delete failures keep the entry intact.
🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

1066-1066: Log accepted entry count instead of raw JSON item count

Line 1066 logs data.size(), even when many entries are skipped. Consider tracking loadedCount for more accurate diagnostics.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1066, The log at the logger::info call
currently reports data.size() and typeName which reflects the raw JSON input
count rather than the number of entries actually loaded; modify the loading
routine in SceneSettingsManager.cpp to maintain a loadedCount (increment when an
entry is successfully parsed/accepted) and replace data.size() with loadedCount
in the logger::info message so it reports the accepted/loaded entries for
typeName instead of the raw JSON item count.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 340-349: The delete handling currently treats any false return
from std::filesystem::remove as an error and then still drops the in-memory
overwrite entry; change the logic in SceneSettingsManager where it builds
filepath (using GetOverwritesPath, entry.sourceFilename, entry.period,
TimeOfDayPeriod) to inspect the std::error_code after remove: if remove succeeds
or remove returns false with ec.value()==0 (meaning the file simply did not
exist) treat as success and log info, but if ec indicates an actual error log an
error and do NOT erase the corresponding in-memory overwrite entry; apply the
same check before the in-memory removal loop (the block that currently removes
overwrite entries around the 399–409 area) so disk-delete failures keep the
entry intact.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1066: The log at the logger::info call currently reports data.size() and
typeName which reflects the raw JSON input count rather than the number of
entries actually loaded; modify the loading routine in SceneSettingsManager.cpp
to maintain a loadedCount (increment when an entry is successfully
parsed/accepted) and replace data.size() with loadedCount in the logger::info
message so it reports the accepted/loaded entries for typeName instead of the
raw JSON item count.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between af9d40f and e4c65c5.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
src/SceneSettingsManager.cpp (1)

397-414: ⚠️ Potential issue | 🟠 Major

Delete-all can desync memory from disk on I/O errors

At Line 412, overwrite entries are erased unconditionally even if file deletion failed earlier. That can leave undeleted files on disk which reappear on next load, while the current session loses control over them.

🛠️ Suggested fix
 void SceneSettingsManager::DeleteAllOverwrites(SceneType type)
 {
 	auto overwritesPath = GetOverwritesPath(type);
-	std::error_code ec;
-
 	auto& vec = GetEntriesMut(type);
-	for (const auto& entry : vec) {
-		if (entry.source == EntrySource::Overwrite && !entry.sourceFilename.empty()) {
-			// TOD overwrites live in per-period subfolders; use the same path
-			// construction as SaveOverwritesToDisk to ensure we hit the right file.
-			auto filepath = (type == SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count) ? overwritesPath / GetPeriodName(entry.period) / entry.sourceFilename : overwritesPath / entry.sourceFilename;
-			std::filesystem::remove(filepath, ec);
-		}
-	}
-
-	std::erase_if(vec, [](const SettingEntry& e) {
-		return e.source == EntrySource::Overwrite;
-	});
+	std::erase_if(vec, [&](const SettingEntry& entry) {
+		if (entry.source != EntrySource::Overwrite)
+			return false;
+
+		if (entry.sourceFilename.empty())
+			return true;
+
+		auto filepath = (type == SceneType::TimeOfDay && entry.period != TimeOfDayPeriod::Count)
+			? overwritesPath / GetPeriodName(entry.period) / entry.sourceFilename
+			: overwritesPath / entry.sourceFilename;
+
+		std::error_code ec;
+		std::filesystem::remove(filepath, ec);
+		if (ec) {
+			logger::error("[SceneSettings] Failed to delete overwrite file: {} ({}) — keeping entry",
+				filepath.string(), ec.message());
+			return false;  // keep entry active/visible if disk delete failed
+		}
+		return true;  // removed or already missing
+	});
 
 	allOverwritesPausedMap[type] = false;
 	ReapplyIfActive();
 }

Based on learnings: "file deletion error handling improvements ... are considered bug fixes rather than refactoring, as they address inadequate error handling and misleading log messages."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 397 - 414, DeleteAllOverwrites
currently removes SettingEntry items from memory regardless of whether
std::filesystem::remove succeeded, which can desync disk and memory; modify
SceneSettingsManager::DeleteAllOverwrites (and the loop using GetEntriesMut,
GetOverwritesPath, GetPeriodName and EntrySource::Overwrite) to check the
std::error_code ec after each std::filesystem::remove and only mark/collect
entries as successfully deleted when ec is clear (or when the file no longer
exists), log any failures, and after the loop erase only the entries that were
actually deleted (e.g., build a list of filenames/indices that succeeded and
pass a predicate to std::erase_if or remove them by those identifiers) so failed
deletions remain in memory for retry or user visibility.
🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

1-1: Consider tightening PR metadata to match repository convention

Current title is close; guideline-preferred style would be feat(ui): add time-of-day scene settings (lowercase scope/description).
If this maps to a tracked issue, consider adding Implements #<id> in the PR description.

As per coding guidelines: "**/*: provide suggestions for Conventional Commit titles and Issue References."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR title and description
to follow the repository's Conventional Commit style: change the title to the
recommended form, e.g. "feat(ui): add time-of-day scene settings" (lowercase
scope and description), and if this PR resolves a tracked issue include an
"Implements #<id>" line in the PR description referencing that issue ID.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Outside diff comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 397-414: DeleteAllOverwrites currently removes SettingEntry items
from memory regardless of whether std::filesystem::remove succeeded, which can
desync disk and memory; modify SceneSettingsManager::DeleteAllOverwrites (and
the loop using GetEntriesMut, GetOverwritesPath, GetPeriodName and
EntrySource::Overwrite) to check the std::error_code ec after each
std::filesystem::remove and only mark/collect entries as successfully deleted
when ec is clear (or when the file no longer exists), log any failures, and
after the loop erase only the entries that were actually deleted (e.g., build a
list of filenames/indices that succeeded and pass a predicate to std::erase_if
or remove them by those identifiers) so failed deletions remain in memory for
retry or user visibility.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR title and description to follow the repository's
Conventional Commit style: change the title to the recommended form, e.g.
"feat(ui): add time-of-day scene settings" (lowercase scope and description),
and if this PR resolves a tracked issue include an "Implements #<id>" line in
the PR description referencing that issue ID.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between e4c65c5 and f7b0362.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

1-1: PR metadata: tighten title + issue linkage.

Consider feat(ui): add time-of-day scene settings and add an issue keyword in the PR body (for example, Implements #<id>).

As per coding guidelines: "**/*: ... provide suggestions for Conventional Commit Titles ... and Issue References."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR title to follow
Conventional Commits (e.g., "feat(ui): add time-of-day scene settings") and edit
the PR body to include an issue reference using the suggested keyword format,
for example add a line "Implements #<id>" to link the PR to the issue; ensure
the commit/PR title and body match the repo's guideline for Conventional Commit
titles and include the issue number.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 470-481: The TimeOfDay branch in UpdateEntryValue
(SceneSettingsManager.cpp) accepts newValue.get<float>() without validating
finite-ness; change it to extract the float into a local (e.g., float tod =
newValue.get<float>()), check std::isfinite(tod) and if not finite log a warning
referencing vec[index].featureShortName and vec[index].settingKey and return,
otherwise assign vec[index].value = tod so only finite floats are stored; this
prevents NaN/Inf from entering the TOD blending state.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR title to follow Conventional Commits (e.g., "feat(ui):
add time-of-day scene settings") and edit the PR body to include an issue
reference using the suggested keyword format, for example add a line "Implements
#<id>" to link the PR to the issue; ensure the commit/PR title and body match
the repo's guideline for Conventional Commit titles and include the issue
number.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between f7b0362 and 8415d2d.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

1-1: PR metadata polish: conventional title + issue link suggestion.

Suggested title: feat(ui): add time-of-day scene settings
Also consider adding an issue reference in the PR body, e.g. Implements #<issue-number>.

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR metadata: change the
PR title to the conventional format suggested (e.g., "feat(ui): add time-of-day
scene settings") and add an issue reference in the PR description (e.g.,
"Implements #<issue-number>"); mention that this change implements the
SceneSettingsManager time-of-day feature (class/identifier SceneSettingsManager)
so reviewers can immediately link the PR to the feature and issue number.

1057-1057: Consider warning on invalid paused type instead of silently coercing to false.

Line 1057 is safe (no throw), but malformed configs become hard to diagnose without a warning.

As per coding guidelines: "Include proper resource management and graceful degradation for DirectX 11 resources and user input validation to prevent crashes from malformed configurations".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1057, When parsing the "paused" field
currently we silently coerce any non-boolean to false; change the logic in the
SceneSettingsManager parsing path that touches entry.paused and item so that if
item.contains("paused") and item["paused"].is_boolean() you assign
item["paused"].get<bool>(), but if item.contains("paused") and NOT is_boolean()
you emit a warning (use the module's logging facility e.g., SceneSettingsManager
or the existing logger used nearby) indicating the "paused" field has an invalid
type and leave entry.paused at its default rather than silently coercing; this
keeps behavior safe while surfacing malformed configs for diagnosis.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 300-315: In AddSetting, when handling SceneType::TimeOfDay (in
SceneSettingsManager::AddSetting), also validate that the provided json float
value is finite before accepting it: after verifying DetectSettingType(value) ==
SettingType::Float, parse/extract the float and reject NaN/Inf (log a warn
similar to the other checks and return) so TOD entries cannot be created with
non-finite values; mirror the same non-finite check logic used in
UpdateEntryValue to keep invariants consistent (use the same float-finiteness
test and message pattern).

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR metadata: change the PR title to the conventional format
suggested (e.g., "feat(ui): add time-of-day scene settings") and add an issue
reference in the PR description (e.g., "Implements #<issue-number>"); mention
that this change implements the SceneSettingsManager time-of-day feature
(class/identifier SceneSettingsManager) so reviewers can immediately link the PR
to the feature and issue number.
- Line 1057: When parsing the "paused" field currently we silently coerce any
non-boolean to false; change the logic in the SceneSettingsManager parsing path
that touches entry.paused and item so that if item.contains("paused") and
item["paused"].is_boolean() you assign item["paused"].get<bool>(), but if
item.contains("paused") and NOT is_boolean() you emit a warning (use the
module's logging facility e.g., SceneSettingsManager or the existing logger used
nearby) indicating the "paused" field has an invalid type and leave entry.paused
at its default rather than silently coercing; this keeps behavior safe while
surfacing malformed configs for diagnosis.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 8415d2d and 3c3f271.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

1-1: PR metadata polish: conventional title + issue linkage.

Suggested title: feat(ui): add time-of-day scene settings
Also consider adding an issue reference in the PR body (e.g., Implements #<id> / Addresses #<id>), if applicable.

As per coding guidelines: "When reviewing PRs, please provide suggestions for: Conventional Commit Titles ... Issue References ...".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR title to follow
Conventional Commits using the suggested title "feat(ui): add time-of-day scene
settings" and add an issue reference line (e.g., "Implements #<id>" or
"Addresses #<id>") in the PR body; ensure the PR description explicitly links to
the related issue and uses the conventional commit prefix "feat(ui):" so
reviewers and CI tooling can pick up the metadata.

596-610: Use active TOD entries for activation checks, not just non-empty vector.

hasEntries = !GetEntries(SceneType::TimeOfDay).empty() keeps TOD active (and updating) even when all TOD entries are paused or feature-paused.

Suggested fix
-	bool hasEntries = !GetEntries(SceneType::TimeOfDay).empty();
+	const auto& todEntries = GetEntries(SceneType::TimeOfDay);
+	bool hasEntries = std::any_of(todEntries.begin(), todEntries.end(),
+		[this](const SettingEntry& e) { return IsEntryActive(e); });
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 596 - 610, Replace the simplistic
hasEntries check with a test for actually active TOD entries (i.e., entries that
are not paused and not feature-paused) instead of
!GetEntries(SceneType::TimeOfDay).empty(); compute hasEntries by iterating
GetEntries(SceneType::TimeOfDay) and checking each entry’s active flags (e.g.,
!entry->IsPaused() && !entry->IsFeaturePaused() or equivalent methods) so the
existing branches that call RevertTimeOfDayBaseline, SaveTimeOfDayBaseline,
ApplyTimeOfDayBlended, DeactivateTimeOfDay and ActivateTimeOfDay only run when
there are truly active TOD entries.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1063: The code silently coerces non-boolean "paused" values to false;
update the logic around the entry.paused assignment so that if
item.contains("paused") and item["paused"].is_boolean() is false, you log a
warning (including the offending value/type and some context such as the entry
id or index) and then keep the safe fallback of false; locate the assignment to
entry.paused and add a conditional branch that logs the malformed type before
setting entry.paused = false (reference symbols: entry.paused and
item["paused"]).
- Around line 54-64: SceneSettingsManager::GetCurrentGameHour currently clamps
values to 24.0f, but callers expect times normalized to the half-open range
[0,24), so change the return logic in GetCurrentGameHour to wrap values into
[0,24) instead of clamping to 24.0f: after obtaining the raw hour
(calendar->gameHour->value or sky->currentGameHour), normalize it with a wrap
operation (e.g., ((hour % 24) + 24) % 24 or using std::fmod with +24 adjustment)
to ensure values equal to 24 become 0 and negative hours are corrected, then
return the normalized value; keep the existing use of calendar and sky to obtain
the raw hour.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR title to follow Conventional Commits using the suggested
title "feat(ui): add time-of-day scene settings" and add an issue reference line
(e.g., "Implements #<id>" or "Addresses #<id>") in the PR body; ensure the PR
description explicitly links to the related issue and uses the conventional
commit prefix "feat(ui):" so reviewers and CI tooling can pick up the metadata.
- Around line 596-610: Replace the simplistic hasEntries check with a test for
actually active TOD entries (i.e., entries that are not paused and not
feature-paused) instead of !GetEntries(SceneType::TimeOfDay).empty(); compute
hasEntries by iterating GetEntries(SceneType::TimeOfDay) and checking each
entry’s active flags (e.g., !entry->IsPaused() && !entry->IsFeaturePaused() or
equivalent methods) so the existing branches that call RevertTimeOfDayBaseline,
SaveTimeOfDayBaseline, ApplyTimeOfDayBlended, DeactivateTimeOfDay and
ActivateTimeOfDay only run when there are truly active TOD entries.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 3c3f271 and a75e466.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Comment thread src/SceneSettingsManager.cpp
Comment thread src/SceneSettingsManager.cpp
@Dlizzio
Copy link
Copy Markdown
Contributor Author

Dlizzio commented Mar 3, 2026

@coderabbitai resume

@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Mar 3, 2026

✅ Actions performed

Reviews resumed.

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

♻️ Duplicate comments (1)
src/SceneSettingsManager.cpp (1)

54-64: ⚠️ Potential issue | 🟡 Minor

Normalize game hour into [0, 24) instead of clamping to 24.0f.

At Line 60 and Line 63, clamping can return exactly 24.0f, while TOD period checks use half-open ranges (h < end). Wrapping avoids edge-case misclassification at midnight and matches the normalization intent in Line 73.

Suggested fix
 float SceneSettingsManager::GetCurrentGameHour()
 {
 	// Prefer calendar (ground truth), which the Weather Editor slider writes to.
 	// sky->currentGameHour may lag when timeScale is 0 (time paused).
+	auto normalizeHour = [](float h) {
+		if (!std::isfinite(h))
+			return 12.0f;
+		h = std::fmod(h, 24.0f);
+		if (h < 0.0f)
+			h += 24.0f;
+		return h;
+	};
+
 	auto calendar = globals::game::calendar ? globals::game::calendar : RE::Calendar::GetSingleton();
 	if (calendar && calendar->gameHour)
-		return std::clamp(calendar->gameHour->value, 0.0f, 24.0f);
+		return normalizeHour(calendar->gameHour->value);
 
 	auto sky = globals::game::sky;
-	return sky ? std::clamp(sky->currentGameHour, 0.0f, 24.0f) : 12.0f;
+	return sky ? normalizeHour(sky->currentGameHour) : 12.0f;
 }
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 54 - 64, GetCurrentGameHour
currently clamps calendar->gameHour->value and sky->currentGameHour to 24.0f
which allows a result of 24.0f; instead normalize into the half-open range
[0,24) by replacing the std::clamp calls with a wrap-normalization: read the raw
hour (calendar->gameHour->value or sky->currentGameHour), compute hour =
std::fmod(hour, 24.0f); if (hour < 0.0f) hour += 24.0f; if (hour == 24.0f) hour
= 0.0f; then return hour so midnight is 0 and never 24.
🧹 Nitpick comments (1)
src/SceneSettingsManager.cpp (1)

1-1: PR metadata tweak: align title/reference with repo convention.

Suggested title: feat(ui): add time-of-day scene settings
If this maps to an issue, add: Implements #<issue-number> in the PR description.

As per coding guidelines: "Conventional Commit Titles ... Style: lowercase description" and "Issue References ... 'Implements #123' for features."

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` at line 1, Update the PR metadata to follow the
repo's Conventional Commit style: change the PR title to "feat(ui): add
time-of-day scene settings" (all lowercase description) and, if this change
implements an issue, add "Implements #<issue-number>" to the PR description;
mention the SceneSettingsManager (and related class names) in the description so
the intent is clear.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 54-64: GetCurrentGameHour currently clamps
calendar->gameHour->value and sky->currentGameHour to 24.0f which allows a
result of 24.0f; instead normalize into the half-open range [0,24) by replacing
the std::clamp calls with a wrap-normalization: read the raw hour
(calendar->gameHour->value or sky->currentGameHour), compute hour =
std::fmod(hour, 24.0f); if (hour < 0.0f) hour += 24.0f; if (hour == 24.0f) hour
= 0.0f; then return hour so midnight is 0 and never 24.

---

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Line 1: Update the PR metadata to follow the repo's Conventional Commit style:
change the PR title to "feat(ui): add time-of-day scene settings" (all lowercase
description) and, if this change implements an issue, add "Implements
#<issue-number>" to the PR description; mention the SceneSettingsManager (and
related class names) in the description so the intent is clear.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a75e466 and 79cc17b.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (2)
src/SceneSettingsManager.cpp (2)

602-617: Only activate TOD when at least one entry is active.

hasEntries/empty-check includes paused entries, so TOD can run with no effective writes. Prefer “has active entries” gating.

Suggested patch
@@
-	bool hasEntries = !GetEntries(SceneType::TimeOfDay).empty();
+	const auto& todEntries = GetEntries(SceneType::TimeOfDay);
+	bool hasActiveEntries = std::any_of(todEntries.begin(), todEntries.end(),
+		[this](const SettingEntry& e) { return IsEntryActive(e); });
@@
-		if (hasEntries) {
+		if (hasActiveEntries) {
@@
-	} else if (isExterior && hasEntries && !isCurrentlyApplied) {
+	} else if (isExterior && hasActiveEntries && !isCurrentlyApplied) {
@@
-	if (isTimeOfDayActive || GetEntries(SceneType::TimeOfDay).empty())
+	const auto& todEntries = GetEntries(SceneType::TimeOfDay);
+	bool hasActiveEntries = std::any_of(todEntries.begin(), todEntries.end(),
+		[this](const SettingEntry& e) { return IsEntryActive(e); });
+	if (isTimeOfDayActive || !hasActiveEntries)
 		return;

Also applies to: 780-781

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 602 - 617, The current gating uses
hasEntries = !GetEntries(SceneType::TimeOfDay).empty() which counts
paused/inactive entries; change the checks to require at least one active
(non-paused) TOD entry by iterating GetEntries(SceneType::TimeOfDay) and testing
the entry active flag (e.g. entry->IsActive() or
!entry->IsPaused()/entry->enabled) instead of empty(), then use that boolean in
the existing branches (the block around
RevertTimeOfDayBaseline/SaveTimeOfDayBaseline/ApplyTimeOfDayBlended,
DeactivateTimeOfDay, and the ActivateTimeOfDay path); make the same replacement
for the other occurrence referenced (around lines 780-781).

1095-1100: Validate non-finite TOD values at ingestion, not only during blending.

TOD load/discovery currently enforces float type but not finite value. Reject/normalize here to keep invariants consistent with AddSetting/UpdateEntryValue.

Suggested patch
@@
-				// TOD only supports float settings — use DetectSettingType to match AddSetting/DiscoverOverwrites
+				// TOD only supports finite float settings — match AddSetting/UpdateEntryValue invariants
 				if (DetectSettingType(entry.value) != SettingType::Float) {
 					logger::warn("SceneSettingsManager: TimeOfDay entry for feature '{}' key '{}' has non-float value (type: {}) — skipping",
 						entry.featureShortName, entry.settingKey, entry.value.type_name());
 					continue;
 				}
+				float todValue = entry.value.get<float>();
+				if (!std::isfinite(todValue)) {
+					logger::warn("SceneSettingsManager: TimeOfDay entry for feature '{}' key '{}' has non-finite value — skipping",
+						entry.featureShortName, entry.settingKey);
+					continue;
+				}
+				entry.value = todValue;
@@
-			// TOD only supports float settings (smooth interpolation)
+			// TOD only supports finite float settings (smooth interpolation)
 			if (type == SceneType::TimeOfDay && DetectSettingType(settingValue) != SettingType::Float) {
 				logger::warn("[SceneSettings] Skipping overwrite '{}': non-float setting '{}' not allowed in Time of Day", filename, settingKey);
 				continue;
 			}
+			if (type == SceneType::TimeOfDay) {
+				float todValue = settingValue.get<float>();
+				if (!std::isfinite(todValue)) {
+					logger::warn("[SceneSettings] Skipping overwrite '{}': non-finite setting '{}' not allowed in Time of Day", filename, settingKey);
+					continue;
+				}
+				settingValue = todValue;
+			}
As per coding guidelines, "Include proper resource management and graceful degradation for DirectX 11 resources and user input validation to prevent crashes from malformed configurations".

Also applies to: 1208-1211

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.cpp` around lines 1095 - 1100, The TimeOfDay
ingestion currently only checks that entry.value is a float via
DetectSettingType and skips other types, but does not validate that the float is
finite; update the ingestion path that uses DetectSettingType /
SettingType::Float to also extract the float from entry.value and reject or
normalize non-finite values (NaN/inf) using std::isfinite before accepting the
entry (mirroring the invariants in AddSetting and UpdateEntryValue); apply the
same finite-value check to the other TOD handling block mentioned (the code
around the other occurrence at 1208-1211) and log a clear warning via
logger::warn when rejecting a non-finite TOD value.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/SceneSettingsManager.cpp`:
- Around line 602-617: The current gating uses hasEntries =
!GetEntries(SceneType::TimeOfDay).empty() which counts paused/inactive entries;
change the checks to require at least one active (non-paused) TOD entry by
iterating GetEntries(SceneType::TimeOfDay) and testing the entry active flag
(e.g. entry->IsActive() or !entry->IsPaused()/entry->enabled) instead of
empty(), then use that boolean in the existing branches (the block around
RevertTimeOfDayBaseline/SaveTimeOfDayBaseline/ApplyTimeOfDayBlended,
DeactivateTimeOfDay, and the ActivateTimeOfDay path); make the same replacement
for the other occurrence referenced (around lines 780-781).
- Around line 1095-1100: The TimeOfDay ingestion currently only checks that
entry.value is a float via DetectSettingType and skips other types, but does not
validate that the float is finite; update the ingestion path that uses
DetectSettingType / SettingType::Float to also extract the float from
entry.value and reject or normalize non-finite values (NaN/inf) using
std::isfinite before accepting the entry (mirroring the invariants in AddSetting
and UpdateEntryValue); apply the same finite-value check to the other TOD
handling block mentioned (the code around the other occurrence at 1208-1211) and
log a clear warning via logger::warn when rejecting a non-finite TOD value.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 79cc17b and a3c160d.

📒 Files selected for processing (1)
  • src/SceneSettingsManager.cpp

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
src/SceneSettingsManager.h (1)

17-20: PR metadata can be tightened for maintainability and traceability.

Consider a conventional title like feat(weather-editor): add time-of-day scene settings, and add an issue keyword in the PR description (e.g., Implements #<id> / Addresses #<id>).

As per coding guidelines: "**/*: provide suggestions for Conventional Commit Titles ... and Issue References ...".

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@src/SceneSettingsManager.h` around lines 17 - 20, Update the PR metadata to
follow our Conventional Commits and issue-tracking guideline: change the
PR/commit title to a conventional-style title such as "feat(weather-editor): add
time-of-day scene settings" and add an issue reference line in the PR
description like "Implements #<id>" (or "Addresses #<id>") so the change in
SceneSettingsManager (file/class SceneSettingsManager.h) is traceable and
matches the "`**/*`: provide suggestions for Conventional Commit Titles ... and
Issue References ..." rule.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Nitpick comments:
In `@src/SceneSettingsManager.h`:
- Around line 17-20: Update the PR metadata to follow our Conventional Commits
and issue-tracking guideline: change the PR/commit title to a conventional-style
title such as "feat(weather-editor): add time-of-day scene settings" and add an
issue reference line in the PR description like "Implements #<id>" (or
"Addresses #<id>") so the change in SceneSettingsManager (file/class
SceneSettingsManager.h) is traceable and matches the "`**/*`: provide
suggestions for Conventional Commit Titles ... and Issue References ..." rule.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between a3c160d and 6330433.

📒 Files selected for processing (2)
  • src/SceneSettingsManager.cpp
  • src/SceneSettingsManager.h

@Dlizzio Dlizzio closed this Mar 5, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants