From 2f1321ced74d0aa092a85c6fb3377dc17bedfc71 Mon Sep 17 00:00:00 2001 From: Dot-Aemeath <336854054+Dot-Aemeath@users.noreply.github.com> Date: Sun, 18 Oct 2026 13:23:26 +0800 Subject: [PATCH 1/3] =?UTF-8?q?fix:=20=E7=8B=AC=E7=AB=8B=E6=8E=A7=E5=88=B6?= =?UTF-8?q?=E5=A4=A9=E6=B0=94=E5=90=8C=E6=AD=A5=E9=99=8D=E6=B0=B4=E5=A3=B0?= =?UTF-8?q?=E9=9F=B3=E5=B9=B6=E4=BF=9D=E7=95=99=E9=9B=A8=E6=99=AF?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- README.md | 8 ++- README_EN.md | 8 ++- .../CombinedEnvironmentStatePolicyTests.cs | 50 +++++++++++++++++++ RealTimeWeatherMod/ChillEnvPlugin.cs | 4 +- .../Core/GameEnvironmentRuntime.cs | 43 +++++++++++----- .../Patches/ModSettingsIntegration.cs | 14 +++++- .../Core/CombinedEnvironmentStatePolicy.cs | 12 ++--- 7 files changed, 112 insertions(+), 27 deletions(-) diff --git a/README.md b/README.md index 580da50..d8ae8dc 100644 --- a/README.md +++ b/README.md @@ -82,7 +82,9 @@ 开启彩蛋功能后,系统可能会随机或者在满足特定条件后主动开启某些风景效果。 ### 声音效果 -开启独立的环境音效托管开关 `EnableAmbientSounds`(默认关闭)后,系统会按条件管理声音效果。 +开启 `Automation.EnableAmbientSounds`(默认关闭)后,系统会按条件托管做饭、空调和蝉鸣;关闭时沿用原有托管清理与用户接管规则,不是全局静音。 + +雨声由独立的 `Automation.EnablePrecipitationSounds` 控制(默认开启,旧配置缺少此项时保留原有雨声行为)。设为 `false` 后,天气同步仍切换小雨、大雨、雷雨画面,但会静音对应雨声,不影响角色语音、动作声、其他环境音或雪景。可在设置面板切换,下次天气同步生效;修改配置文件后按 F7 重载并同步。两项开关可以独立组合,手动雨景操作仍由游戏控制。 ### TODO @@ -134,8 +136,10 @@ [Automation] ## 启用季节性景色彩蛋自动托管 EnableSeasonalEasterEggs = true -## 启用环境音效自动托管 +## 启用做饭、空调、蝉鸣环境音效自动托管(不控制雨声) EnableAmbientSounds = false +## 天气同步时开启降水声音;false 保留雨景并静音雨声,下次天气同步生效 +EnablePrecipitationSounds = true ## 跟随游戏内实际雨景,阻止角色自动开窗;已开窗时,小雨 30–90 秒、雨 3–8 秒、雷雨 1–4 秒后请求关窗,等待现有动作完成 CloseWindowWhenRaining = true diff --git a/README_EN.md b/README_EN.md index 7b0b911..9a43f11 100644 --- a/README_EN.md +++ b/README_EN.md @@ -96,7 +96,9 @@ When seasonal easter eggs are enabled, some scenery effects may be activated ran ### Sound Effects -When the separate EnableAmbientSounds switch is enabled (off by default), ambient sound effects are managed according to their conditions. +`Automation.EnableAmbientSounds` (off by default) automates cooking, air conditioner and cicada sounds according to their conditions. Disabling it retains the existing ownership and cleanup rules; it is not a global mute. + +`Automation.EnablePrecipitationSounds` separately controls rain audio. It defaults to `true`, preserving rain audio for existing configs without this key. Set it to `false` to keep synchronized light, heavy and thunderstorm rain visuals while muting their sounds, without affecting character voices, action sounds, other ambient audio or snow. The settings-panel toggle takes effect on the next weather sync; after editing the config file, press F7 to reload and sync. Both switches are independent. Manual rain controls retain the game's behavior. ### TODO @@ -147,8 +149,10 @@ After first run, config is generated at `BepInEx/config/chillwithyou.envsync.cfg [Automation] ## Enable automatic seasonal scenery easter eggs EnableSeasonalEasterEggs = true -## Enable automatic ambient sound management +## Automate cooking, air conditioner and cicada sounds (does not control rain audio) EnableAmbientSounds = false +## Play precipitation sounds during weather sync; false keeps rain visuals and mutes rain audio on the next sync +EnablePrecipitationSounds = true ## Follow active in-game rain; block opening and request closing after 30–90s in light rain, 3–8s in rain, or 1–4s in thunderstorms, allowing existing actions to finish CloseWindowWhenRaining = true diff --git a/RealTimeWeatherMod.Tests/Core/CombinedEnvironmentStatePolicyTests.cs b/RealTimeWeatherMod.Tests/Core/CombinedEnvironmentStatePolicyTests.cs index b1650d6..5447e46 100644 --- a/RealTimeWeatherMod.Tests/Core/CombinedEnvironmentStatePolicyTests.cs +++ b/RealTimeWeatherMod.Tests/Core/CombinedEnvironmentStatePolicyTests.cs @@ -5,6 +5,56 @@ namespace RealTimeWeatherMod.Tests.Core { public class CombinedEnvironmentStatePolicyTests { + [Theory] + [InlineData(false, false, false, true, false)] + [InlineData(false, true, true, true, true)] + [InlineData(true, true, true, false, true)] + [InlineData(true, false, true, false, true)] + [InlineData(true, true, false, false, true)] + [InlineData(true, false, false, false, false)] + public void SilentRain_OpensOrKeepsWindow_AndMutesStoredOrLiveSound( + bool windowActive, bool soundActive, bool liveSoundActive, + bool changeWindow, bool changeSound) + { + Assert.Equal(changeWindow, CombinedEnvironmentStatePolicy.NeedsWindowChange(windowActive, true)); + Assert.Equal(changeSound, CombinedEnvironmentStatePolicy.NeedsSoundChange( + true, soundActive, liveSoundActive, false)); + Assert.Equal(!changeWindow && !changeSound, CombinedEnvironmentStatePolicy.IsInTargetState( + windowActive, true, soundActive, liveSoundActive, true, targetSoundState: false)); + } + + [Fact] + public void SilentRain_Stopping_ClosesWindowWithoutMutingAgain() + { + Assert.True(CombinedEnvironmentStatePolicy.NeedsWindowChange(true, false)); + Assert.False(CombinedEnvironmentStatePolicy.NeedsSoundChange(true, false, false, false)); + Assert.False(CombinedEnvironmentStatePolicy.IsInTargetState( + true, true, false, false, false, targetSoundState: false)); + Assert.True(CombinedEnvironmentStatePolicy.IsInTargetState( + false, true, false, false, false, targetSoundState: false)); + } + + [Fact] + public void EnablingRainSounds_WhenWindowAlreadyOpen_ChangesOnlySound() + { + Assert.False(CombinedEnvironmentStatePolicy.NeedsWindowChange(true, true)); + Assert.True(CombinedEnvironmentStatePolicy.NeedsSoundChange(true, false, false, true)); + Assert.False(CombinedEnvironmentStatePolicy.IsInTargetState( + true, true, false, false, true, targetSoundState: true)); + Assert.True(CombinedEnvironmentStatePolicy.IsInTargetState( + true, true, true, true, true, targetSoundState: true)); + } + + [Theory] + [InlineData(true)] + [InlineData(false)] + public void ViewOnlyScenery_DoesNotRequireSound_WithEitherSoundTarget(bool soundTarget) + { + Assert.True(CombinedEnvironmentStatePolicy.IsInTargetState( + true, false, false, false, true, targetSoundState: soundTarget)); + Assert.False(CombinedEnvironmentStatePolicy.NeedsSoundChange(false, false, false, soundTarget)); + } + [Fact] public void Closing_WhenOnlySoundRemains_ChangesOnlySound() { diff --git a/RealTimeWeatherMod/ChillEnvPlugin.cs b/RealTimeWeatherMod/ChillEnvPlugin.cs index 54a56b7..0b20218 100644 --- a/RealTimeWeatherMod/ChillEnvPlugin.cs +++ b/RealTimeWeatherMod/ChillEnvPlugin.cs @@ -46,6 +46,7 @@ public class ChillEnvPlugin : BaseUnityPlugin internal static ConfigEntry Cfg_EnableEasterEggs; internal static ConfigEntry Cfg_EnableAmbientSounds; + internal static ConfigEntry Cfg_EnablePrecipitationSounds; internal static ConfigEntry Cfg_CloseWindowWhenRaining; // 调试配置 @@ -130,7 +131,8 @@ private void InitConfig() Cfg_DetailedTimeSegments = Config.Bind("UI", "DetailedTimeSegments", true, "开启12小时制时,显示详细时段(凌晨/清晨/上午等)"); Cfg_EnableEasterEggs = Config.Bind("Automation", "EnableSeasonalEasterEggs", true, "启用季节性景色彩蛋自动托管"); - Cfg_EnableAmbientSounds = Config.Bind("Automation", "EnableAmbientSounds", false, "启用环境音效自动托管"); + Cfg_EnableAmbientSounds = Config.Bind("Automation", "EnableAmbientSounds", false, "启用做饭、空调、蝉鸣环境音效自动托管(不控制雨声)"); + Cfg_EnablePrecipitationSounds = Config.Bind("Automation", "EnablePrecipitationSounds", true, "天气同步时开启小雨、大雨、雷雨声音;关闭时只保留雨景,不影响其他音效;下次天气同步生效"); Cfg_CloseWindowWhenRaining = Config.Bind( "Automation", "CloseWindowWhenRaining", diff --git a/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs b/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs index 7f9c87f..eed4ade 100644 --- a/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs +++ b/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs @@ -155,25 +155,31 @@ internal bool TryApplySceneryState( bool targetState, EnvironmentApplyMode mode) { + bool mutePrecipitation = IsPrecipitation(environmentType) && + !(ChillEnvPlugin.Cfg_EnablePrecipitationSounds?.Value ?? true); + bool targetSoundState = targetState && !mutePrecipitation; if (TryGetController(environmentType, out var controller)) { - if (TryIsControllerInTargetState(controller, targetState, out var isInTargetState)) + if (TryIsControllerInTargetState(controller, targetState, targetSoundState, out var isInTargetState)) { - if (isInTargetState || TrySetControllerCombinedState(controller, targetState)) + if (isInTargetState || TrySetControllerCombinedState(controller, targetState, targetSoundState)) { return true; } } - if (mode == EnvironmentApplyMode.Interactive) + if (mode == EnvironmentApplyMode.Interactive && !mutePrecipitation) { return TrySimulateMainIconClick(environmentType); } } - if (mode == EnvironmentApplyMode.EarlyStartup) + // The main icon toggles BOTH view and sound, so it cannot represent silent rain. + // Use the direct window path and reconcile live sound if a controller exists. + if (mode == EnvironmentApplyMode.EarlyStartup || mutePrecipitation) { - return TryApplySceneryStateDirect(environmentType, targetState); + return TryApplySceneryStateDirect(environmentType, targetState, targetSoundState) && + (!mutePrecipitation || TrySetAmbientSoundState(environmentType, false, out _)); } if (TryIsWindowActive(environmentType, out var isActive) && isActive == targetState) @@ -184,6 +190,13 @@ internal bool TryApplySceneryState( return TrySimulateMainIconClick(environmentType); } + private static bool IsPrecipitation(EnvironmentType environmentType) + { + return environmentType == EnvironmentType.LightRain || + environmentType == EnvironmentType.HeavyRain || + environmentType == EnvironmentType.ThunderRain; + } + internal ModEnvironment? GetActiveRain() { if (TryIsWindowActive(EnvironmentType.ThunderRain, out var thunder) && thunder) @@ -535,7 +548,8 @@ internal bool TryGetRuntimeServices( } } - private bool TryApplySceneryStateDirect(EnvironmentType environmentType, bool targetState) + private bool TryApplySceneryStateDirect( + EnvironmentType environmentType, bool targetState, bool targetSoundState) { if (!TryGetRuntimeServices(out _, out var windowViewService, out var environmentDataService) || !EnsureDirectSceneryMetadata(windowViewService, environmentDataService) || @@ -570,12 +584,12 @@ private bool TryApplySceneryStateDirect(EnvironmentType environmentType, bool ta environmentType.ToString(), out var ambientEnumValue) && TryGetDirectSoundActive(environmentDataService, ambientEnumValue, out var isSoundActive) && - isSoundActive != targetState) + isSoundActive != targetSoundState) { - TryInvoke( + return TryInvoke( _setMuteMethod, environmentDataService, - new object[] { ambientEnumValue, !targetState }, + new object[] { ambientEnumValue, !targetSoundState }, "[环境运行时] 启动期环境音状态写入失败"); } @@ -652,6 +666,7 @@ private bool TryGetDirectSoundActive( private bool TryIsControllerInTargetState( EnvironmentController controller, bool targetState, + bool targetSoundState, out bool isInTargetState) { isInTargetState = false; @@ -670,11 +685,13 @@ private bool TryIsControllerInTargetState( hasSound, soundActive, liveSoundActive, - targetState); + targetState, + targetSoundState); return true; } - private bool TrySetControllerCombinedState(EnvironmentController controller, bool targetState) + private bool TrySetControllerCombinedState( + EnvironmentController controller, bool targetState, bool targetSoundState) { if (!TryGetControllerCombinedState( controller, @@ -693,7 +710,7 @@ private bool TrySetControllerCombinedState(EnvironmentController controller, boo hasSound, soundActive, liveSoundActive, - targetState); + targetSoundState); if (!needsWindowChange && !needsSoundChange) { return true; @@ -705,7 +722,7 @@ private bool TrySetControllerCombinedState(EnvironmentController controller, boo MethodInfo changeMuteMethod = needsSoundChange ? AccessTools.Method( controller.GetType(), - targetState ? "MuteDeactivate" : "MuteActivate") + targetSoundState ? "MuteDeactivate" : "MuteActivate") : null; if ((needsWindowChange && changeWindowMethod == null) || (needsSoundChange && changeMuteMethod == null)) diff --git a/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs b/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs index cb9f8e7..a99f606 100644 --- a/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs +++ b/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs @@ -147,7 +147,8 @@ private bool TryRegisterSettings() regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_UI", "Show Weather on UI", "UIに天気を表示", "日期栏天气" }); regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_DETAIL", "Detailed Segments", "詳細セグメント", "详细时段" }); regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_EGG", "Seasonal Scenery", "季節の景色", "季节性景色" }); - regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_AMBIENT", "Ambient Sounds", "環境音", "环境音效" }); + regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_AMBIENT", "Ambient Sound Automation", "環境音の自動管理", "环境音效托管" }); + regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_PRECIPITATION_SOUND", "Precipitation Sounds (Weather Sync)", "降水音(天気同期)", "降水声音(天气同步)" }); regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_RAIN_WINDOW", "Close Window in Rain", "雨天に窓を閉める", "下雨自动关窗" }); regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_CITY", "City (Seniverse)", "都市(Seniverse)", "城市 (心知天气)" }); regTransMethod.Invoke(managerInstance, new object[] { "ENV_SYNC_PROVIDER", "Weather Provider", "天気提供元", "天气数据源" }); @@ -239,7 +240,7 @@ private bool TryRegisterSettings() ChillEnvPlugin.Instance.Config.Save(); }); - string labelAmbient = hasTranslation ? "ENV_SYNC_AMBIENT" : "环境音效"; + string labelAmbient = hasTranslation ? "ENV_SYNC_AMBIENT" : "环境音效托管"; AddToggleSafe(managerInstance, managerType, labelAmbient, ChillEnvPlugin.Cfg_EnableAmbientSounds.Value, @@ -249,6 +250,15 @@ private bool TryRegisterSettings() ChillEnvPlugin.Instance.Config.Save(); }); + AddToggleSafe(managerInstance, managerType, + hasTranslation ? "ENV_SYNC_PRECIPITATION_SOUND" : "降水声音(天气同步)", + ChillEnvPlugin.Cfg_EnablePrecipitationSounds.Value, + (value) => + { + ChillEnvPlugin.Cfg_EnablePrecipitationSounds.Value = value; + ChillEnvPlugin.Instance.Config.Save(); + }); + AddToggleSafe(managerInstance, managerType, hasTranslation ? "ENV_SYNC_RAIN_WINDOW" : "下雨自动关窗", ChillEnvPlugin.Cfg_CloseWindowWhenRaining.Value, diff --git a/RealTimeWeatherMod/Pure/Core/CombinedEnvironmentStatePolicy.cs b/RealTimeWeatherMod/Pure/Core/CombinedEnvironmentStatePolicy.cs index de3e873..07fe8ff 100644 --- a/RealTimeWeatherMod/Pure/Core/CombinedEnvironmentStatePolicy.cs +++ b/RealTimeWeatherMod/Pure/Core/CombinedEnvironmentStatePolicy.cs @@ -7,14 +7,12 @@ internal static bool IsInTargetState( bool hasSound, bool soundActive, bool liveSoundActive, - bool targetState) + bool targetState, + bool? targetSoundState = null) { - if (targetState) - { - return windowActive && (!hasSound || soundActive); - } - - return !windowActive && (!hasSound || (!soundActive && !liveSoundActive)); + // Omitted sound targets retain the original coupled view/sound behavior. + return !NeedsWindowChange(windowActive, targetState) && + !NeedsSoundChange(hasSound, soundActive, liveSoundActive, targetSoundState ?? targetState); } internal static bool NeedsWindowChange(bool windowActive, bool targetState) From ad6be12dbcf5be614766a0f111f235881e2899f2 Mon Sep 17 00:00:00 2001 From: Small-tailqwq <56996438+Small-tailqwq@users.noreply.github.com> Date: Mon, 19 Oct 2026 23:03:55 +0800 Subject: [PATCH 2/3] =?UTF-8?q?fix:=20=E5=88=87=E6=8D=A2=E9=99=8D=E6=B0=B4?= =?UTF-8?q?=E5=A3=B0=E9=9F=B3=E5=90=8E=E7=AB=8B=E5=8D=B3=E6=9B=B4=E6=96=B0?= =?UTF-8?q?=E5=BD=93=E5=89=8D=E9=9B=A8=E5=A3=B0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 设置面板保存开关后按当前雨景同步声音,保留雨景和既有同步保护。 Co-Authored-By: GPT-6 --- README.md | 4 ++-- README_EN.md | 4 ++-- RealTimeWeatherMod/ChillEnvPlugin.cs | 2 +- .../Core/GameEnvironmentRuntime.cs | 23 +++++++++++++++++++ .../Patches/ModSettingsIntegration.cs | 1 + 5 files changed, 29 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index d8ae8dc..222c48f 100644 --- a/README.md +++ b/README.md @@ -84,7 +84,7 @@ ### 声音效果 开启 `Automation.EnableAmbientSounds`(默认关闭)后,系统会按条件托管做饭、空调和蝉鸣;关闭时沿用原有托管清理与用户接管规则,不是全局静音。 -雨声由独立的 `Automation.EnablePrecipitationSounds` 控制(默认开启,旧配置缺少此项时保留原有雨声行为)。设为 `false` 后,天气同步仍切换小雨、大雨、雷雨画面,但会静音对应雨声,不影响角色语音、动作声、其他环境音或雪景。可在设置面板切换,下次天气同步生效;修改配置文件后按 F7 重载并同步。两项开关可以独立组合,手动雨景操作仍由游戏控制。 +雨声由独立的 `Automation.EnablePrecipitationSounds` 控制(默认开启,旧配置缺少此项时保留原有雨声行为)。设为 `false` 后,天气同步仍切换小雨、大雨、雷雨画面,但会静音对应雨声,不影响角色语音、动作声、其他环境音或雪景。天气同步开启时,在设置面板切换会立即更新当前雨声,无需刷新天气;过场或鲸鱼覆盖期间仍遵循同步保护。修改配置文件后按 F7 重载并同步。两项开关可以独立组合,手动雨景操作仍由游戏控制。 ### TODO @@ -138,7 +138,7 @@ EnableSeasonalEasterEggs = true ## 启用做饭、空调、蝉鸣环境音效自动托管(不控制雨声) EnableAmbientSounds = false -## 天气同步时开启降水声音;false 保留雨景并静音雨声,下次天气同步生效 +## 天气同步时开启降水声音;false 保留雨景并静音雨声,设置面板切换立即更新当前雨声 EnablePrecipitationSounds = true ## 跟随游戏内实际雨景,阻止角色自动开窗;已开窗时,小雨 30–90 秒、雨 3–8 秒、雷雨 1–4 秒后请求关窗,等待现有动作完成 CloseWindowWhenRaining = true diff --git a/README_EN.md b/README_EN.md index 9a43f11..60b5e9b 100644 --- a/README_EN.md +++ b/README_EN.md @@ -98,7 +98,7 @@ When seasonal easter eggs are enabled, some scenery effects may be activated ran `Automation.EnableAmbientSounds` (off by default) automates cooking, air conditioner and cicada sounds according to their conditions. Disabling it retains the existing ownership and cleanup rules; it is not a global mute. -`Automation.EnablePrecipitationSounds` separately controls rain audio. It defaults to `true`, preserving rain audio for existing configs without this key. Set it to `false` to keep synchronized light, heavy and thunderstorm rain visuals while muting their sounds, without affecting character voices, action sounds, other ambient audio or snow. The settings-panel toggle takes effect on the next weather sync; after editing the config file, press F7 to reload and sync. Both switches are independent. Manual rain controls retain the game's behavior. +`Automation.EnablePrecipitationSounds` separately controls rain audio. It defaults to `true`, preserving rain audio for existing configs without this key. Set it to `false` to keep synchronized light, heavy and thunderstorm rain visuals while muting their sounds, without affecting character voices, action sounds, other ambient audio or snow. With weather sync enabled, the settings-panel toggle updates current rain audio immediately without refreshing weather; cutscene and whale overrides still take priority. After editing the config file, press F7 to reload and sync. Both switches are independent. Manual rain controls retain the game's behavior. ### TODO @@ -151,7 +151,7 @@ After first run, config is generated at `BepInEx/config/chillwithyou.envsync.cfg EnableSeasonalEasterEggs = true ## Automate cooking, air conditioner and cicada sounds (does not control rain audio) EnableAmbientSounds = false -## Play precipitation sounds during weather sync; false keeps rain visuals and mutes rain audio on the next sync +## Play precipitation sounds during weather sync; false keeps rain visuals and mutes rain audio; panel changes update current rain audio immediately EnablePrecipitationSounds = true ## Follow active in-game rain; block opening and request closing after 30–90s in light rain, 3–8s in rain, or 1–4s in thunderstorms, allowing existing actions to finish CloseWindowWhenRaining = true diff --git a/RealTimeWeatherMod/ChillEnvPlugin.cs b/RealTimeWeatherMod/ChillEnvPlugin.cs index 0b20218..efc2c1d 100644 --- a/RealTimeWeatherMod/ChillEnvPlugin.cs +++ b/RealTimeWeatherMod/ChillEnvPlugin.cs @@ -132,7 +132,7 @@ private void InitConfig() Cfg_EnableEasterEggs = Config.Bind("Automation", "EnableSeasonalEasterEggs", true, "启用季节性景色彩蛋自动托管"); Cfg_EnableAmbientSounds = Config.Bind("Automation", "EnableAmbientSounds", false, "启用做饭、空调、蝉鸣环境音效自动托管(不控制雨声)"); - Cfg_EnablePrecipitationSounds = Config.Bind("Automation", "EnablePrecipitationSounds", true, "天气同步时开启小雨、大雨、雷雨声音;关闭时只保留雨景,不影响其他音效;下次天气同步生效"); + Cfg_EnablePrecipitationSounds = Config.Bind("Automation", "EnablePrecipitationSounds", true, "天气同步时开启小雨、大雨、雷雨声音;关闭时只保留雨景,不影响其他音效;天气同步开启时,设置面板切换立即更新当前雨声"); Cfg_CloseWindowWhenRaining = Config.Bind( "Automation", "CloseWindowWhenRaining", diff --git a/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs b/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs index eed4ade..afa5813 100644 --- a/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs +++ b/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs @@ -190,6 +190,29 @@ internal bool TryApplySceneryState( return TrySimulateMainIconClick(environmentType); } + internal void RefreshPrecipitationSounds() + { + if (!ChillEnvPlugin.Cfg_EnableWeatherSync.Value || + ChillEnvPlugin.IsInCutscene() || SceneryAutomationSystem.IsWhaleSystemTriggered) + { + return; + } + + bool soundsEnabled = ChillEnvPlugin.Cfg_EnablePrecipitationSounds.Value; + foreach (var environmentType in ModEnvironmentMap.SceneryEnvironments) + { + if (!IsPrecipitation(environmentType)) continue; + + // Preserve the current view, including rain that is still fading out. + if (!TryGetController(environmentType, out var controller) || + !TryGetControllerCombinedState(controller, out var windowActive, out _, out _, out _) || + !TrySetControllerCombinedState(controller, windowActive, windowActive && soundsEnabled)) + { + ChillEnvPlugin.Log?.LogWarning($"[环境运行时] 无法立即更新降水声音: {environmentType}"); + } + } + } + private static bool IsPrecipitation(EnvironmentType environmentType) { return environmentType == EnvironmentType.LightRain || diff --git a/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs b/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs index a99f606..d397bd9 100644 --- a/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs +++ b/RealTimeWeatherMod/Patches/ModSettingsIntegration.cs @@ -257,6 +257,7 @@ private bool TryRegisterSettings() { ChillEnvPlugin.Cfg_EnablePrecipitationSounds.Value = value; ChillEnvPlugin.Instance.Config.Save(); + Core.GameEnvironmentRuntime.Shared.RefreshPrecipitationSounds(); }); AddToggleSafe(managerInstance, managerType, From ca3811cffab97ddd1eb61d25e7a38fd05c8eebe0 Mon Sep 17 00:00:00 2001 From: Small-tailqwq <56996438+Small-tailqwq@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:36:50 +0800 Subject: [PATCH 3/3] =?UTF-8?q?fix:=20=E4=BF=AE=E5=A4=8D=E9=99=8D=E6=B0=B4?= =?UTF-8?q?=E5=A3=B0=E9=9F=B3=E5=9B=9E=E9=80=80=E4=B8=8E=E9=A2=84=E8=A7=88?= =?UTF-8?q?=E6=81=A2=E5=A4=8D?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: GPT-6 --- .../Core/GameEnvironmentRuntime.cs | 32 +++++++++++++------ .../Core/WeatherDebugControl.cs | 3 +- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs b/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs index afa5813..cd61f98 100644 --- a/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs +++ b/RealTimeWeatherMod/Core/GameEnvironmentRuntime.cs @@ -153,9 +153,10 @@ private bool InvokeBase(EnvironmentType target, EnvironmentApplyMode mode) internal bool TryApplySceneryState( EnvironmentType environmentType, bool targetState, - EnvironmentApplyMode mode) + EnvironmentApplyMode mode, + bool applyPrecipitationSoundSetting = true) { - bool mutePrecipitation = IsPrecipitation(environmentType) && + bool mutePrecipitation = applyPrecipitationSoundSetting && IsPrecipitation(environmentType) && !(ChillEnvPlugin.Cfg_EnablePrecipitationSounds?.Value ?? true); bool targetSoundState = targetState && !mutePrecipitation; if (TryGetController(environmentType, out var controller)) @@ -178,8 +179,9 @@ internal bool TryApplySceneryState( // Use the direct window path and reconcile live sound if a controller exists. if (mode == EnvironmentApplyMode.EarlyStartup || mutePrecipitation) { - return TryApplySceneryStateDirect(environmentType, targetState, targetSoundState) && - (!mutePrecipitation || TrySetAmbientSoundState(environmentType, false, out _)); + bool windowApplied = TryApplySceneryStateDirect(environmentType, targetState, targetSoundState); + bool soundApplied = !mutePrecipitation || TrySetAmbientSoundState(environmentType, false, out _); + return windowApplied && soundApplied; } if (TryIsWindowActive(environmentType, out var isActive) && isActive == targetState) @@ -204,12 +206,20 @@ internal void RefreshPrecipitationSounds() if (!IsPrecipitation(environmentType)) continue; // Preserve the current view, including rain that is still fading out. - if (!TryGetController(environmentType, out var controller) || - !TryGetControllerCombinedState(controller, out var windowActive, out _, out _, out _) || - !TrySetControllerCombinedState(controller, windowActive, windowActive && soundsEnabled)) + if (TryGetController(environmentType, out var controller) && + TryGetControllerCombinedState(controller, out var windowActive, out _, out _, out _) && + TrySetControllerCombinedState(controller, windowActive, windowActive && soundsEnabled)) { - ChillEnvPlugin.Log?.LogWarning($"[环境运行时] 无法立即更新降水声音: {environmentType}"); + continue; + } + + if (TryIsWindowActive(environmentType, out var fallbackWindowActive) && + TrySetAmbientSoundState(environmentType, fallbackWindowActive && soundsEnabled, out _)) + { + continue; } + + ChillEnvPlugin.Log?.LogWarning($"[环境运行时] 无法立即更新降水声音: {environmentType}"); } } @@ -809,7 +819,11 @@ private bool TryGetControllerCombinedState( FieldInfo ambientBehaviorField = AccessTools.Field( controller.GetType(), "_ambientSoundBehavior"); - object ambientBehavior = ambientBehaviorField?.GetValue(controller); + if (ambientBehaviorField == null) + { + return false; + } + object ambientBehavior = ambientBehaviorField.GetValue(controller); hasSound = ambientBehavior != null; if (!hasSound) { diff --git a/RealTimeWeatherMod/Core/WeatherDebugControl.cs b/RealTimeWeatherMod/Core/WeatherDebugControl.cs index 630c4ae..8f7bc85 100644 --- a/RealTimeWeatherMod/Core/WeatherDebugControl.cs +++ b/RealTimeWeatherMod/Core/WeatherDebugControl.cs @@ -101,7 +101,8 @@ internal static void StopManualPreview() runtime.TryApplyBaseImmediately(_previewBase.Value, EnvironmentApplyMode.Interactive); if (!ChillEnvPlugin.Cfg_EnableWeatherSync.Value) foreach (var pair in _previewScenery) - runtime.TryApplySceneryState(pair.Key, pair.Value, EnvironmentApplyMode.Interactive); + runtime.TryApplySceneryState(pair.Key, pair.Value, EnvironmentApplyMode.Interactive, + applyPrecipitationSoundSetting: false); } _previewBase = null; _previewScenery.Clear();