From 03c76299c3a5d87776393d6f1a6cc6eaedefcaf5 Mon Sep 17 00:00:00 2001 From: Chris F Date: Sun, 23 Oct 2022 21:38:20 +0200 Subject: [PATCH 1/2] Version 1.4 rework --- mod-structure/1.4/Assemblies/HeatMap.dll | Bin 0 -> 20480 bytes .../English/Keyed/FALCHM_LanguageData.xml | 47 +- src/HeatMap/HeatMap.cs | 551 +++++++++++------- src/HeatMap/HeatMap.csproj | 220 +------ src/HeatMap/HeatMapHelper.cs | 133 +++++ src/HeatMap/HeatMapKeyBindings.cs | 16 + src/HeatMap/Main.cs | 347 ----------- src/HeatMap/MapInterface_Detour.cs | 32 - src/HeatMap/MapTemperature_Detour.cs | 92 +++ src/HeatMap/PlaySettings_Detour.cs | 23 - src/HeatMap/Properties/AssemblyInfo.cs | 5 +- src/HeatMap/packages.config | 5 - 12 files changed, 632 insertions(+), 839 deletions(-) create mode 100644 mod-structure/1.4/Assemblies/HeatMap.dll create mode 100644 src/HeatMap/HeatMapHelper.cs create mode 100644 src/HeatMap/HeatMapKeyBindings.cs delete mode 100644 src/HeatMap/Main.cs delete mode 100644 src/HeatMap/MapInterface_Detour.cs create mode 100644 src/HeatMap/MapTemperature_Detour.cs delete mode 100644 src/HeatMap/PlaySettings_Detour.cs delete mode 100644 src/HeatMap/packages.config diff --git a/mod-structure/1.4/Assemblies/HeatMap.dll b/mod-structure/1.4/Assemblies/HeatMap.dll new file mode 100644 index 0000000000000000000000000000000000000000..27d6293142c17feae752592cefe60bd666acf9af GIT binary patch literal 20480 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 + Override vanilla overlay + Use Heat Map's overlay instead of the vanilla overlay. +(default: on) + + Only overlay indoor areas + Only show the overlay for indoors areas. +(default: on) + Opacity of overlay - Reduce this value to make the overlay more transparent. + Reduce this value to make the overlay more transparent. +(default: 30%) Overlay update delay - Number of ticks delay between overlay updates while game is unpaused. Lower numbers provide smoother updates, but may affect performance on low end machines. + Number of ticks delay between widget and temperature text updates while game is unpaused. Lower numbers provide smoother updates, but may affect performance on low end machines. +(default: 100) Show outdoor thermometer - Displays a widget in the top right hand corner of the UI showing current outdoor temperature. + Displays a widget in the top right hand corner of the UI showing current outdoor temperature. +(default: on) Opacity of thermometer - Reduce this value to make the outdoor temperature thermometer background color more transparent. + Reduce this value to make the outdoor temperature thermometer background color more transparent. +(default: 30%) Lock thermometer position - Locks the thermometer widget in place, disabling shift-click dragging. + Locks the thermometer widget in place, disabling shift-click dragging. +(default: off) Right margin of thermometer - Changes the margin between the thermometer widget and the right of the screen. The widget can be dragged using shift-click while ingame. + Changes the margin between the thermometer widget and the right of the screen. The widget can be dragged using shift-click while ingame. +(default: 70) Top margin of thermometer - Changes the margin between the thermometer widget and the top of the screen. The widget can be dragged using shift-click while ingame. + Changes the margin between the thermometer widget and the top of the screen. The widget can be dragged using shift-click while ingame. +(default: 8) - Outdoor temperature. -Click to toggle heat map overlay. -Shift-click and drag to move the widget, the position can be locked in the mod settings. -This widget can be disabled in mod settings. - Show Heat Map + Show temperature over rooms + When overlay is on, this will also display the room temperature over the centre of the room. +(default: on) Use custom range When off, the colour gradient automatically maps to the human comfort range as defined by the game. -When on, allows you to set a custom boundary for the blue and red ends of the gradient, in current temperature units +When on, allows you to set a custom boundary for the blue and red ends of the gradient, in current temperature units +(default: off) Custom range min Blue end of gradient. Temperatures below this will be blue. Use current temperature units @@ -38,6 +52,9 @@ When on, allows you to set a custom boundary for the blue and red ends of the gr Custom range max Red end of gradient. Temperatures above this will be red. Use current temperature units - Show temperature over rooms - When overlay is on, this will also display the room temperature over the centre of the room. + Outdoor temperature. +Click to toggle heat map overlay. +Shift-click and drag to move the widget, the position can be locked in the mod settings. +This widget can be disabled in mod settings. + Show Heat Map diff --git a/src/HeatMap/HeatMap.cs b/src/HeatMap/HeatMap.cs index c3479f7..0558235 100644 --- a/src/HeatMap/HeatMap.cs +++ b/src/HeatMap/HeatMap.cs @@ -1,215 +1,336 @@ -using System; -using RimWorld; -using UnityEngine; -using Verse; - -namespace HeatMap -{ - public class HeatMap : ICellBoolGiver - { - public HeatMap() - { - if (Main.Instance.ShouldUseCustomRange()) - CreateCustomMap(); - else - CreateComfortMap(); - } - - public void CreateCustomMap() - { - _mappedTemperatureRange = new IntRange( - Main.Instance.GetCustomRangeMin(), Main.Instance.GetCustomRangeMax()); - - var mappedColorCount = _mappedTemperatureRange.max - _mappedTemperatureRange.min; - _mappedColors = new Color[mappedColorCount]; - - var delta = 2f / (mappedColorCount - 1); - var channelR = -1f; - var channelG = 0f; - var channelB = 1f; - var greenRising = true; - - for (var i = 0; i < mappedColorCount - 1; i++) - { - var realR = Math.Min(channelR, 1f); - realR = Math.Max(realR, 0f); - - var realG = Math.Min(channelG, 1f); - realG = Math.Max(realG, 0f); - - var realB = Math.Min(channelB, 1f); - realB = Math.Max(realB, 0f); - - _mappedColors[i] = new Color(realR, realG, realB); - - if (channelG >= 1f) - greenRising = false; - - channelR += delta; - channelG += greenRising ? delta : -delta; - channelB -= delta; - } - - // Force high end to be red (or else if the temperature range is an even number, - // the green channel will not go down to zero in above loop). - _mappedColors[mappedColorCount - 1] = Color.red; - } - - public void CreateComfortMap() - { - var minComfortTemp = (int)ThingDefOf.Human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMin) + 3; - var maxComfortTemp = (int)ThingDefOf.Human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMax) - 3; - - // Narrow down the green range to a quarter scale, to make boundary temps stand out more. - - var comfortDoubleRange = (maxComfortTemp - minComfortTemp) * 2; - _mappedTemperatureRange = new IntRange( - minComfortTemp - comfortDoubleRange, maxComfortTemp + comfortDoubleRange); - - var mappedColorCount = _mappedTemperatureRange.max - _mappedTemperatureRange.min; - _mappedColors = new Color[mappedColorCount]; - - var channelDelta = 1f / comfortDoubleRange; - var channelR = -2f; - var channelG = 0f; - var channelB = 2f; - var greenRising = true; - - var mappingTemperature = _mappedTemperatureRange.min; - for (var i = 0; i < mappedColorCount - 1; i++, mappingTemperature++) - { - var realR = Math.Min(channelR, 1f); - realR = Math.Max(realR, 0f); - - var realG = Math.Min(channelG, 1f); - realG = Math.Max(realG, 0f); - - var realB = Math.Min(channelB, 1f); - realB = Math.Max(realB, 0f); - - _mappedColors[i] = new Color(realR, realG, realB); - - if (channelG >= 2f) - greenRising = false; - - var delta = channelDelta; - if (mappingTemperature >= minComfortTemp - 1 && - mappingTemperature <= maxComfortTemp) - { - delta *= 4; - } - - channelR += delta; - channelG += greenRising ? delta : -delta; - channelB -= delta; - } - - // Force high end to be red (or else if the temperature range is an even number, - // the green channel will not go down to zero in above loop). - _mappedColors[mappedColorCount - 1] = Color.red; - } - - public CellBoolDrawer Drawer - { - get - { - if (_drawerInt == null) - { - var map = Find.CurrentMap; - _drawerInt = new CellBoolDrawer(this, map.Size.x, map.Size.z, - Main.Instance.GetConfiguredOpacity()); - } - return _drawerInt; - } - } - - public bool GetCellBool(int index) - { - var map = Find.CurrentMap; - if (map.fogGrid.IsFogged(index)) - return false; - - var room = map.cellIndices.IndexToCell(index).GetRoom(map); - - if (room != null && !room.PsychologicallyOutdoors) - { - _nextColor = GetColorForTemperature(room.Temperature); - return true; - } - - return false; - } - - public int GetIndexForTemperature(float temperature) - { - // These two checks are probably not needed due to array index boundary checks - // below, but too worried to remove them now. - if (temperature <= _mappedTemperatureRange.min) - { - return 0; - } - - if (temperature >= _mappedTemperatureRange.max) - { - return _mappedColors.Length - 1; - } - - var colorMapIndex = (int)temperature - _mappedTemperatureRange.min; - if (colorMapIndex <= 0) - { - return 0; - } - - if (colorMapIndex >= _mappedColors.Length) - { - return _mappedColors.Length - 1; - } - - return colorMapIndex; - - } - - public Color GetColorForTemperature(float temperature) - { - return _mappedColors[GetIndexForTemperature(temperature)]; - } - - public Color GetCellExtraColor(int index) - { - return _nextColor; - } - - public Color Color => Color.white; - - public void Update(int updateDelay) - { - if (Main.Instance.ShowHeatMap) - { - Drawer.MarkForDraw(); - var tick = Find.TickManager.TicksGame; - if (tick >= _nextUpdateTick) - { - Drawer.SetDirty(); - _nextUpdateTick = tick + updateDelay; - } - Drawer.CellBoolDrawerUpdate(); - } - } - - public void Reset() - { - _drawerInt = null; - _nextUpdateTick = 0; - } - - private CellBoolDrawer _drawerInt; - - private IntRange _mappedTemperatureRange; - - private Color[] _mappedColors; - - private Color _nextColor; - - private int _nextUpdateTick; - } -} \ No newline at end of file +using HugsLib.Settings; +using HugsLib.Utils; +using RimWorld; +using RimWorld.Planet; +using System.Collections.Generic; +using System.Reflection; +using UnityEngine; +using Verse; + +namespace HeatMap +{ + public class HeatMap : HugsLib.ModBase + { + internal new ModLogger Logger => base.Logger; + + internal static HeatMap Instance { get; private set; } + + public override string ModIdentifier => "HeatMap"; + + public RoomTemperatureDisplayer TemperatureDisplayer { get; } = new RoomTemperatureDisplayer(); + + private const float _boxSize = 62f; + private bool _draggingThermometer = false; + private float _dragThermometerRight = 0f; + private float _dragThermometerTop = 0f; + + private readonly Dictionary _temperatureTextureCache = new Dictionary(); + + private SettingHandle _overrideVanillaOverlay; + private SettingHandle _showIndoorsOnly; + private SettingHandle _opacity; + private SettingHandle _updateDelay; + + private SettingHandle _showOutdoorThermometer; + private SettingHandle _outdoorThermometerOpacity; + private SettingHandle _outdoorThermometerFixed; + private SettingHandle _outdoorThermometerRight; + private SettingHandle _outdoorThermometerTop; + + private SettingHandle _showTemperatureOverRooms; + + private SettingHandle _useCustomRange; + private SettingHandle _customRangeMin; + private SettingHandle _customRangeMax; + + + public bool OverrideVanillaOverlay => + _overrideVanillaOverlay; + public bool ShowIndoorsOnly => + _showIndoorsOnly; + public float OverlayOpacity => + _opacity / 100f; + public bool ShouldUseCustomRange => + _useCustomRange; + public int CustomRangeMin => + _customRangeMin; + public int CustomRangeMax => + _customRangeMax; + + + public HeatMap() + { + Instance = this; + } + + public void UpdateOutdoorThermometer() + { + if (!_showOutdoorThermometer) + return; + + var right = Mathf.Clamp(_draggingThermometer ? _dragThermometerRight : _outdoorThermometerRight, _boxSize, UI.screenWidth); + var top = Mathf.Clamp(_draggingThermometer ? _dragThermometerTop : _outdoorThermometerTop, 0, UI.screenHeight - _boxSize); + var outRect = new Rect(UI.screenWidth - right, top, _boxSize, _boxSize); + if (TutorSystem.AdaptiveTrainingEnabled && Find.PlaySettings.showLearningHelper) + { + if (typeof(LearningReadout).GetField("windowRect", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(Find.Tutor.learningReadout) is Rect helpRect + && helpRect.Overlaps(outRect) == true) + outRect.x = helpRect.x - _boxSize - 5f; + } + + if (!_outdoorThermometerFixed && Event.current.isMouse) + { + switch (Event.current.type) + { + case EventType.MouseDown: + if (Mouse.IsOver(outRect) && Event.current.modifiers == EventModifiers.Shift) + { + Event.current.Use(); + + _dragThermometerRight = _outdoorThermometerRight.Value; + _dragThermometerTop = _outdoorThermometerTop.Value; + + _draggingThermometer = true; + } + break; + case EventType.MouseDrag: + if (_draggingThermometer) + { + Event.current.Use(); + + _dragThermometerRight -= Event.current.delta.x; + _dragThermometerRight = Mathf.Clamp(_dragThermometerRight, _boxSize, UI.screenWidth); + _dragThermometerTop += Event.current.delta.y; + _dragThermometerTop = Mathf.Clamp(_dragThermometerTop, 0, UI.screenHeight - _boxSize); + //outRect = new Rect(outRect.x - _dragThermometerRight, outRect.y + _dragThermometerTop, _boxSize, _boxSize); // repositioning is processed on next update + } + break; + case EventType.MouseUp: + if (_draggingThermometer) + { + Event.current.Use(); + + _outdoorThermometerRight.Value = _dragThermometerRight; + _outdoorThermometerTop.Value = _dragThermometerTop; + + _draggingThermometer = false; + } + break; + } + } + + var temperature = Find.CurrentMap.mapTemperature.OutdoorTemp; + var textureIndex = HeatMapHelper.GetIndexForTemperature(temperature); + if (!_temperatureTextureCache.ContainsKey(textureIndex)) + { + var backColor = HeatMapHelper.GetColorForTemperature(temperature); + backColor.a = _outdoorThermometerOpacity / 100f; + _temperatureTextureCache[textureIndex] = SolidColorMaterials.NewSolidColorTexture(backColor); + } + GUI.DrawTexture(outRect, _temperatureTextureCache[textureIndex]); + GUI.DrawTexture(outRect, Resources.DisplayBoder); + + var temperatureForDisplay = temperature.ToStringTemperature("F0"); + Text.Font = GameFont.Medium; + Text.Anchor = TextAnchor.MiddleCenter; + GUI.color = Color.white; + Widgets.Label(outRect, temperatureForDisplay); + + if (Widgets.ButtonInvisible(outRect)) + Find.PlaySettings.showTemperatureOverlay = !Find.PlaySettings.showTemperatureOverlay; + + TooltipHandler.TipRegion(outRect, "FALCHM.ThermometerTooltip".Translate()); + + Text.Anchor = TextAnchor.UpperLeft; + } + + public override void OnGUI() + { + if (Current.ProgramState != ProgramState.Playing + || Find.CurrentMap == null + || WorldRendererUtility.WorldRenderedNow) + return; + + UpdateOutdoorThermometer(); + if (Find.PlaySettings.showTemperatureOverlay && _showTemperatureOverRooms) + { + TemperatureDisplayer.Update(_updateDelay); + TemperatureDisplayer.OnGUI(); + } + + if (Event.current.type != EventType.KeyDown || Event.current.keyCode == KeyCode.None) + return; + + if (HeatMapKeyBingings.ToggleHeatMap.JustPressed) + { + if (WorldRendererUtility.WorldRenderedNow) + return; + + Find.PlaySettings.showTemperatureOverlay = !Find.PlaySettings.showTemperatureOverlay; + } + } + + public override void WorldLoaded() + { + ResetAll(); + } + + public override void DefsLoaded() + { + _overrideVanillaOverlay = Settings.GetHandle( + "overrideVanillaOverlay", + "FALCHM.OverrideVanillaOverlay".Translate(), + "FALCHM.OverrideVanillaOverlayDesc".Translate(), + true); + _overrideVanillaOverlay.ValueChanged += + val => ResetAll(); + + _showIndoorsOnly = Settings.GetHandle( + "showRoomsOnly", + "FALCHM.ShowIndoorsOnly".Translate(), + "FALCHM.ShowIndoorsOnlyDesc".Translate(), + true); + _showIndoorsOnly.ValueChanged += + val => ResetAll(); + + _opacity = Settings.GetHandle( + "opacity", "FALCHM.OverlayOpacity".Translate(), + "FALCHM.OverlayOpacityDesc".Translate(), 30, + Validators.IntRangeValidator(0, 100)); + _opacity.ValueChanged += + val => ResetAll(); + + _updateDelay = Settings.GetHandle("updateDelay", + "FALCHM.UpdateDelay".Translate(), + "FALCHM.UpdateDelayDesc".Translate(), + 100, + Validators.IntRangeValidator(1, 9999)); + + + _showOutdoorThermometer = Settings.GetHandle( + "showOutdoorThermometer", + "FALCHM.ShowOutDoorThermometer".Translate(), + "FALCHM.ShowOutDoorThermometerDesc".Translate(), + true); + + _outdoorThermometerOpacity = Settings.GetHandle( + "outdoorThermometerOpacity", + "FALCHM.ThermometerOpacity".Translate(), + "FALCHM.ThermometerOpacityDesc".Translate(), + 30, + Validators.IntRangeValidator(1, 100)); + _outdoorThermometerOpacity.ValueChanged += + val => _temperatureTextureCache.Clear(); + + _outdoorThermometerFixed = Settings.GetHandle( + "outdoorThermometerFixed", + "FALCHM.ThermometerFixed".Translate(), + "FALCHM.ThermometerFixedDesc".Translate(), + false); + + _outdoorThermometerRight = Settings.GetHandle( + "outdoorThermometerRight", + "FALCHM.ThermometerRight".Translate(), + "FALCHM.ThermometerRightDesc".Translate(), + 8f + _boxSize); + + _outdoorThermometerTop = Settings.GetHandle( + "outdoorThermometerTop", + "FALCHM.ThermometerTop".Translate(), + "FALCHM.ThermometerTopDesc".Translate(), + 8f); + + + _showTemperatureOverRooms = Settings.GetHandle( + "showTemperatureOverRooms", + "FALCHM.ShowTemperatureOverRooms".Translate(), + "FALCHM.ShowTemperatureOverRoomsDesc".Translate(), + true); + + + _useCustomRange = Settings.GetHandle( + "useCustomeRange", + "FALCHM.UseCustomeRange".Translate(), + "FALCHM.UseCustomeRangeDesc".Translate(), + false); + _useCustomRange.ValueChanged += + val => ResetAll(); + + + _customRangeMin = Settings.GetHandle("customRangeMin", "Unused", "Unused", 0); + _customRangeMax = Settings.GetHandle("customRangeMax", "Unused", "Unused", 40); + + _customRangeMin.VisibilityPredicate = () => false; + _customRangeMax.VisibilityPredicate = () => false; + + + var customRangeValidator = Validators.IntRangeValidator( + (int)GenTemperature.CelsiusTo(-100, Prefs.TemperatureMode), + (int)GenTemperature.CelsiusTo(100, Prefs.TemperatureMode)); + + var customRangeMin = Settings.GetHandle( + "customRangeMinPlaceholder", + "FALCHM.CustomRangeMin".Translate(), + $"{"FALCHM.CustomRangeMinDesc".Translate()} ({Prefs.TemperatureMode.ToStringHuman()})", + (int)GenTemperature.CelsiusTo(_customRangeMin, Prefs.TemperatureMode), + customRangeValidator); + + customRangeMin.Unsaved = true; + customRangeMin.VisibilityPredicate = () => _useCustomRange; + + var customRangeMax = Settings.GetHandle( + "customRangeMaxPlaceholder", + "FALCHM.CustomRangeMax".Translate(), + $"{"FALCHM.CustomRangeMaxDesc".Translate()} ({Prefs.TemperatureMode.ToStringHuman()})", + (int)GenTemperature.CelsiusTo(_customRangeMax, Prefs.TemperatureMode), + customRangeValidator); + + customRangeMax.Unsaved = true; + customRangeMax.VisibilityPredicate = () => _useCustomRange; + + + customRangeMin.ValueChanged += val => + { + if (customRangeMax <= customRangeMin) + customRangeMax.Value = customRangeMin + 1; + + _customRangeMin.Value = ConvertToCelcius(customRangeMin); + ResetAll(); + }; + + customRangeMax.ValueChanged += val => + { + if (customRangeMin >= customRangeMax) + customRangeMin.Value = customRangeMax - 1; + + _customRangeMax.Value = ConvertToCelcius(customRangeMax); + ResetAll(); + }; + } + + public void ResetAll() + { + HeatMapHelper.RegenerateColorMap(); + TemperatureDisplayer.Reset(); + _temperatureTextureCache.Clear(); + + Find.CurrentMap?.mapTemperature?.Drawer?.SetDirty(); + } + + private static int ConvertToCelcius(int value) + { + switch (Prefs.TemperatureMode) + { + default: + case TemperatureDisplayMode.Celsius: + return value; + + case TemperatureDisplayMode.Kelvin: + return value - 273; + + case TemperatureDisplayMode.Fahrenheit: + return (int)((value - 32) / 1.8f); + } + } + } +} diff --git a/src/HeatMap/HeatMap.csproj b/src/HeatMap/HeatMap.csproj index d9e7cce..2ab60b4 100644 --- a/src/HeatMap/HeatMap.csproj +++ b/src/HeatMap/HeatMap.csproj @@ -23,212 +23,16 @@ false - - ..\packages\Lib.Harmony.2.1.0\lib\net472\0Harmony.dll - - - ..\..\ThirdParty\Assembly-CSharp.dll - - - ..\packages\UnlimitedHugs.Rimworld.HugsLib.9.0.0\lib\net472\HugsLib.dll - - - - - - ..\..\ThirdParty\Unity.TextMeshPro.dll - - - False - ..\..\ThirdParty\UnityEngine.dll - - - ..\..\ThirdParty\UnityEngine.AccessibilityModule.dll - - - ..\..\ThirdParty\UnityEngine.AIModule.dll - - - ..\..\ThirdParty\UnityEngine.AndroidJNIModule.dll - - - ..\..\ThirdParty\UnityEngine.AnimationModule.dll - - - ..\..\ThirdParty\UnityEngine.ARModule.dll - - - ..\..\ThirdParty\UnityEngine.AssetBundleModule.dll - - - ..\..\ThirdParty\UnityEngine.AudioModule.dll - - - ..\..\ThirdParty\UnityEngine.ClothModule.dll - - - ..\..\ThirdParty\UnityEngine.ClusterInputModule.dll - - - ..\..\ThirdParty\UnityEngine.ClusterRendererModule.dll - - - ..\..\ThirdParty\UnityEngine.CoreModule.dll - - - ..\..\ThirdParty\UnityEngine.CrashReportingModule.dll - - - ..\..\ThirdParty\UnityEngine.DirectorModule.dll - - - ..\..\ThirdParty\UnityEngine.DSPGraphModule.dll - - - ..\..\ThirdParty\UnityEngine.GameCenterModule.dll - - - ..\..\ThirdParty\UnityEngine.GridModule.dll - - - ..\..\ThirdParty\UnityEngine.HotReloadModule.dll - - - ..\..\ThirdParty\UnityEngine.ImageConversionModule.dll - - - ..\..\ThirdParty\UnityEngine.IMGUIModule.dll - - - ..\..\ThirdParty\UnityEngine.InputLegacyModule.dll - - - ..\..\ThirdParty\UnityEngine.InputModule.dll - - - ..\..\ThirdParty\UnityEngine.JSONSerializeModule.dll - - - ..\..\ThirdParty\UnityEngine.LocalizationModule.dll - - - ..\..\ThirdParty\UnityEngine.ParticleSystemModule.dll - - - ..\..\ThirdParty\UnityEngine.PerformanceReportingModule.dll - - - ..\..\ThirdParty\UnityEngine.Physics2DModule.dll - - - ..\..\ThirdParty\UnityEngine.PhysicsModule.dll - - - ..\..\ThirdParty\UnityEngine.ProfilerModule.dll - - - ..\..\ThirdParty\UnityEngine.ScreenCaptureModule.dll - - - ..\..\ThirdParty\UnityEngine.SharedInternalsModule.dll - - - ..\..\ThirdParty\UnityEngine.SpriteMaskModule.dll - - - ..\..\ThirdParty\UnityEngine.SpriteShapeModule.dll - - - ..\..\ThirdParty\UnityEngine.StreamingModule.dll - - - ..\..\ThirdParty\UnityEngine.SubstanceModule.dll - - - ..\..\ThirdParty\UnityEngine.TerrainModule.dll - - - ..\..\ThirdParty\UnityEngine.TerrainPhysicsModule.dll - - - ..\..\ThirdParty\UnityEngine.TextCoreModule.dll - - - ..\..\ThirdParty\UnityEngine.TextRenderingModule.dll - - - ..\..\ThirdParty\UnityEngine.TilemapModule.dll - - - ..\..\ThirdParty\UnityEngine.TLSModule.dll - - - ..\..\ThirdParty\UnityEngine.UI.dll - - - ..\..\ThirdParty\UnityEngine.UIElementsModule.dll - - - ..\..\ThirdParty\UnityEngine.UIModule.dll - - - ..\..\ThirdParty\UnityEngine.UmbraModule.dll - - - ..\..\ThirdParty\UnityEngine.UNETModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityAnalyticsModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityConnectModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityTestProtocolModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityWebRequestAssetBundleModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityWebRequestAudioModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityWebRequestModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityWebRequestTextureModule.dll - - - ..\..\ThirdParty\UnityEngine.UnityWebRequestWWWModule.dll - - - ..\..\ThirdParty\UnityEngine.VehiclesModule.dll - - - ..\..\ThirdParty\UnityEngine.VFXModule.dll - - - ..\..\ThirdParty\UnityEngine.VideoModule.dll - - - ..\..\ThirdParty\UnityEngine.VRModule.dll - - - ..\..\ThirdParty\UnityEngine.WindModule.dll - - - ..\..\ThirdParty\UnityEngine.XRModule.dll - - - - + + + @@ -279,7 +83,23 @@ - + + 2.0.1 + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + 1.4.3525 + + + 2.2.2 + + + 9.0.1 + + + + diff --git a/src/HeatMap/HeatMapHelper.cs b/src/HeatMap/HeatMapHelper.cs new file mode 100644 index 0000000..53df5ed --- /dev/null +++ b/src/HeatMap/HeatMapHelper.cs @@ -0,0 +1,133 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace HeatMap +{ + public static class HeatMapHelper + { + internal static IntRange MappedTemperatureRange; + internal static Color[] MappedColors; + + public static void RegenerateColorMap() + { + if (HeatMap.Instance.ShouldUseCustomRange) + CreateCustomMap(); + else + CreateComfortMap(); + } + + private static void CreateCustomMap() + { + MappedTemperatureRange = new IntRange( + HeatMap.Instance.CustomRangeMin, HeatMap.Instance.CustomRangeMax); + + var mappedColorCount = MappedTemperatureRange.max - MappedTemperatureRange.min; + MappedColors = new Color[mappedColorCount]; + + var delta = 2f / (mappedColorCount - 1); + var channelR = -1f; + var channelG = 0f; + var channelB = 1f; + var greenRising = true; + + for (var i = 0; i < mappedColorCount - 1; i++) + { + var realR = Math.Min(channelR, 1f); + realR = Math.Max(realR, 0f); + + var realG = Math.Min(channelG, 1f); + realG = Math.Max(realG, 0f); + + var realB = Math.Min(channelB, 1f); + realB = Math.Max(realB, 0f); + + MappedColors[i] = new Color(realR, realG, realB); + + if (channelG >= 1f) + greenRising = false; + + channelR += delta; + channelG += greenRising ? delta : -delta; + channelB -= delta; + } + + // Force high end to be red (or else if the temperature range is an even number, + // the green channel will not go down to zero in above loop). + MappedColors[mappedColorCount - 1] = Color.red; + } + + private static void CreateComfortMap() + { + var minComfortTemp = (int)ThingDefOf.Human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMin) + 3; + var maxComfortTemp = (int)ThingDefOf.Human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMax) - 3; + + // Narrow down the green range to a quarter scale, to make boundary temps stand out more. + + var comfortDoubleRange = (maxComfortTemp - minComfortTemp) * 2; + MappedTemperatureRange = new IntRange( + minComfortTemp - comfortDoubleRange, maxComfortTemp + comfortDoubleRange); + + var mappedColorCount = MappedTemperatureRange.max - MappedTemperatureRange.min; + MappedColors = new Color[mappedColorCount]; + + var channelDelta = 1f / comfortDoubleRange; + var channelR = -2f; + var channelG = 0f; + var channelB = 2f; + var greenRising = true; + + var mappingTemperature = MappedTemperatureRange.min; + for (var i = 0; i < mappedColorCount - 1; i++, mappingTemperature++) + { + var realR = Math.Min(channelR, 1f); + realR = Math.Max(realR, 0f); + + var realG = Math.Min(channelG, 1f); + realG = Math.Max(realG, 0f); + + var realB = Math.Min(channelB, 1f); + realB = Math.Max(realB, 0f); + + MappedColors[i] = new Color(realR, realG, realB); + + if (channelG >= 2f) + greenRising = false; + + var delta = channelDelta; + if (mappingTemperature >= minComfortTemp - 1 && + mappingTemperature <= maxComfortTemp) + { + delta *= 4; + } + + channelR += delta; + channelG += greenRising ? delta : -delta; + channelB -= delta; + } + + // Force high end to be red (or else if the temperature range is an even number, + // the green channel will not go down to zero in above loop). + MappedColors[mappedColorCount - 1] = Color.red; + } + + public static int GetIndexForTemperature(float temperature) + { + var colorMapIndex = (int)temperature - MappedTemperatureRange.min; + if (colorMapIndex < 0) + colorMapIndex = 0; + else if (colorMapIndex >= MappedColors.Length) + colorMapIndex = MappedColors.Length - 1; + return colorMapIndex; + } + public static Color GetColorForTemperature(float temperature) + { + return MappedColors[GetIndexForTemperature(temperature)]; + } + } +} diff --git a/src/HeatMap/HeatMapKeyBindings.cs b/src/HeatMap/HeatMapKeyBindings.cs new file mode 100644 index 0000000..6aada24 --- /dev/null +++ b/src/HeatMap/HeatMapKeyBindings.cs @@ -0,0 +1,16 @@ +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Verse; + +namespace HeatMap +{ + [DefOf] + public static class HeatMapKeyBingings + { + public static KeyBindingDef ToggleHeatMap; + } +} diff --git a/src/HeatMap/Main.cs b/src/HeatMap/Main.cs deleted file mode 100644 index eeeac9a..0000000 --- a/src/HeatMap/Main.cs +++ /dev/null @@ -1,347 +0,0 @@ -using HugsLib.Settings; -using HugsLib.Utils; -using RimWorld; -using RimWorld.Planet; -using System.Collections.Generic; -using System.Reflection; -using UnityEngine; -using Verse; - -namespace HeatMap -{ - [DefOf] - public static class HeatMapKeyBingings - { - public static KeyBindingDef ToggleHeatMap; - } - - public class Main : HugsLib.ModBase - { - public Main() - { - Instance = this; - } - - public void UpdateHeatMap() - { - if (_heatMap == null) - _heatMap = new HeatMap(); - - if (_opacity > 0) - _heatMap.Update(_updateDelay); - } - - public void UpdateOutdoorThermometer() - { - if (!_showOutdoorThermometer) - return; - - if (_heatMap == null) - return; - - var right = Mathf.Clamp(_draggingThermometer ? _dragThermometerRight : _outdoorThermometerRight, _boxSize, UI.screenWidth); - var top = Mathf.Clamp(_draggingThermometer ? _dragThermometerTop : _outdoorThermometerTop, 0, UI.screenHeight - _boxSize); - var outRect = new Rect(UI.screenWidth - right, top, _boxSize, _boxSize); - if (TutorSystem.AdaptiveTrainingEnabled && Find.PlaySettings.showLearningHelper) - { - if (typeof(LearningReadout).GetField("windowRect", BindingFlags.Instance | BindingFlags.NonPublic)?.GetValue(Find.Tutor.learningReadout) is Rect helpRect - && helpRect.Overlaps(outRect) == true) - outRect.x = helpRect.x - _boxSize - 5f; - } - - if (!_outdoorThermometerFixed && Event.current.isMouse) - { - switch (Event.current.type) - { - case EventType.MouseDown: - if (Mouse.IsOver(outRect) && Event.current.modifiers == EventModifiers.Shift) - { - Event.current.Use(); - - _dragThermometerRight = _outdoorThermometerRight.Value; - _dragThermometerTop = _outdoorThermometerTop.Value; - - _draggingThermometer = true; - } - break; - case EventType.MouseDrag: - if (_draggingThermometer) - { - Event.current.Use(); - - _dragThermometerRight -= Event.current.delta.x; - _dragThermometerRight = Mathf.Clamp(_dragThermometerRight, _boxSize, UI.screenWidth); - _dragThermometerTop += Event.current.delta.y; - _dragThermometerTop = Mathf.Clamp(_dragThermometerTop, 0, UI.screenHeight - _boxSize); - //outRect = new Rect(outRect.x - _dragThermometerRight, outRect.y + _dragThermometerTop, _boxSize, _boxSize); // repositioning is processed on next update - } - break; - case EventType.MouseUp: - if (_draggingThermometer) - { - Event.current.Use(); - - _outdoorThermometerRight.Value = _dragThermometerRight; - _outdoorThermometerTop.Value = _dragThermometerTop; - - _draggingThermometer = false; - } - break; - } - } - - var temperature = Find.CurrentMap.mapTemperature.OutdoorTemp; - var textureIndex = _heatMap.GetIndexForTemperature(temperature); - if (!_temperatureTextureCache.ContainsKey(textureIndex)) - { - var backColor = _heatMap.GetColorForTemperature(temperature); - backColor.a = _outdoorThermometerOpacity / 100f; - _temperatureTextureCache[textureIndex] = SolidColorMaterials.NewSolidColorTexture(backColor); - } - GUI.DrawTexture(outRect, _temperatureTextureCache[textureIndex]); - GUI.DrawTexture(outRect, Resources.DisplayBoder); - - var temperatureForDisplay = temperature.ToStringTemperature("F0"); - Text.Font = GameFont.Medium; - Text.Anchor = TextAnchor.MiddleCenter; - GUI.color = Color.white; - Widgets.Label(outRect, temperatureForDisplay); - - if (Widgets.ButtonInvisible(outRect)) - { - ShowHeatMap = !ShowHeatMap; - } - TooltipHandler.TipRegion(outRect, "FALCHM.ThermometerTooltip".Translate()); - - Text.Anchor = TextAnchor.UpperLeft; - } - - public override void OnGUI() - { - if (Current.ProgramState != ProgramState.Playing || - Find.CurrentMap == null || - WorldRendererUtility.WorldRenderedNow || - _heatMap == null) - { - return; - } - - UpdateOutdoorThermometer(); - if (ShowHeatMap && _showTemperatureOverRooms) - { - TemperatureDisplayer.Update(_updateDelay); - TemperatureDisplayer.OnGUI(); - } - - if (Event.current.type != EventType.KeyDown || Event.current.keyCode == KeyCode.None) - { - return; - } - - if (HeatMapKeyBingings.ToggleHeatMap.JustPressed) - { - if (WorldRendererUtility.WorldRenderedNow) - { - return; - } - ShowHeatMap = !ShowHeatMap; - } - } - - public override void WorldLoaded() - { - ResetAll(); - } - - public override void DefsLoaded() - { - _opacity = Settings.GetHandle( - "opacity", "FALCHM.OverlayOpacity".Translate(), - "FALCHM.OverlayOpacityDesc".Translate(), 30, - Validators.IntRangeValidator(0, 100)); - - _opacity.ValueChanged += val => { _heatMap?.Reset(); }; - - _updateDelay = Settings.GetHandle("updateDelay", - "FALCHM.UpdateDelay".Translate(), - "FALCHM.UpdateDelayDesc".Translate(), - 100, - Validators.IntRangeValidator(1, 9999)); - - - _showOutdoorThermometer = Settings.GetHandle( - "showOutdoorThermometer", - "FALCHM.ShowOutDoorThermometer".Translate(), - "FALCHM.ShowOutDoorThermometerDesc".Translate(), - true); - - _outdoorThermometerOpacity = Settings.GetHandle( - "outdoorThermometerOpacity", - "FALCHM.ThermometerOpacity".Translate(), - "FALCHM.ThermometerOpacityDesc".Translate(), - 30, - Validators.IntRangeValidator(1, 100)); - _outdoorThermometerOpacity.ValueChanged += val => { _temperatureTextureCache.Clear(); }; - - _outdoorThermometerFixed = Settings.GetHandle( - "outdoorThermometerFixed", - "FALCHM.ThermometerFixed".Translate(), - "FALCHM.ThermometerFixedDesc".Translate(), - false); - - _outdoorThermometerRight = Settings.GetHandle( - "outdoorThermometerRight", - "FALCHM.ThermometerRight".Translate(), - "FALCHM.ThermometerRightDesc".Translate(), - 8f + _boxSize); - - _outdoorThermometerTop = Settings.GetHandle( - "outdoorThermometerTop", - "FALCHM.ThermometerTop".Translate(), - "FALCHM.ThermometerTopDesc".Translate(), - 8f); - - - _showTemperatureOverRooms = Settings.GetHandle( - "showTemperatureOverRooms", - "FALCHM.ShowTemperatureOverRooms".Translate(), - "FALCHM.ShowTemperatureOverRoomsDesc".Translate(), - true); - - - _useCustomRange = Settings.GetHandle( - "useCustomeRange", - "FALCHM.UseCustomeRange".Translate(), - "FALCHM.UseCustomeRangeDesc".Translate(), - false); - _useCustomRange.ValueChanged += val => { ResetAll(); }; - - - _customRangeMin = Settings.GetHandle("customRangeMin", "Unused", "Unused", 0); - _customRangeMax = Settings.GetHandle("customRangeMax", "Unused", "Unused", 40); - - _customRangeMin.VisibilityPredicate = () => false; - _customRangeMax.VisibilityPredicate = () => false; - - - var customRangeValidator = Validators.IntRangeValidator( - (int)GenTemperature.CelsiusTo(-100, Prefs.TemperatureMode), - (int)GenTemperature.CelsiusTo(100, Prefs.TemperatureMode)); - - var customRangeMin = Settings.GetHandle( - "customRangeMinPlaceholder", - "FALCHM.CustomRangeMin".Translate(), - $"{"FALCHM.CustomRangeMinDesc".Translate()} ({Prefs.TemperatureMode.ToStringHuman()})", - (int)GenTemperature.CelsiusTo(_customRangeMin, Prefs.TemperatureMode), - customRangeValidator); - - customRangeMin.Unsaved = true; - customRangeMin.VisibilityPredicate = () => _useCustomRange; - - var customRangeMax = Settings.GetHandle( - "customRangeMaxPlaceholder", - "FALCHM.CustomRangeMax".Translate(), - $"{"FALCHM.CustomRangeMaxDesc".Translate()} ({Prefs.TemperatureMode.ToStringHuman()})", - (int)GenTemperature.CelsiusTo(_customRangeMax, Prefs.TemperatureMode), - customRangeValidator); - - customRangeMax.Unsaved = true; - customRangeMax.VisibilityPredicate = () => _useCustomRange; - - - customRangeMin.ValueChanged += val => - { - if (customRangeMax <= customRangeMin) - customRangeMax.Value = customRangeMin + 1; - - _customRangeMin.Value = ConvertToCelcius(customRangeMin); - ResetAll(); - }; - - - customRangeMax.ValueChanged += val => - { - if (customRangeMin >= customRangeMax) - customRangeMin.Value = customRangeMax - 1; - - _customRangeMax.Value = ConvertToCelcius(customRangeMax); - ResetAll(); - }; - } - - public bool ShouldUseCustomRange() - { - return _useCustomRange; - } - - public int GetCustomRangeMin() - { - return _customRangeMin; - } - - public int GetCustomRangeMax() - { - return _customRangeMax; - } - - public float GetConfiguredOpacity() - { - return _opacity / 100f; - } - - public void ResetAll() - { - _heatMap = null; - TemperatureDisplayer.Reset(); - _temperatureTextureCache.Clear(); - } - - private static int ConvertToCelcius(int value) - { - switch (Prefs.TemperatureMode) - { - case TemperatureDisplayMode.Celsius: - return value; - - case TemperatureDisplayMode.Kelvin: - return value - 273; - - default: - return (int)((value - 32) / 1.8f); - } - } - - internal new ModLogger Logger => base.Logger; - - internal static Main Instance { get; private set; } - - public override string ModIdentifier => "HeatMap"; - - public bool ShowHeatMap; - - public RoomTemperatureDisplayer TemperatureDisplayer { get; } = new RoomTemperatureDisplayer(); - - private HeatMap _heatMap; - private const float _boxSize = 62f; - private bool _draggingThermometer = false; - private float _dragThermometerRight = 0f; - private float _dragThermometerTop = 0f; - - private readonly Dictionary _temperatureTextureCache = new Dictionary(); - - private SettingHandle _opacity; - private SettingHandle _updateDelay; - - private SettingHandle _showOutdoorThermometer; - private SettingHandle _outdoorThermometerOpacity; - private SettingHandle _outdoorThermometerFixed; - private SettingHandle _outdoorThermometerRight; - private SettingHandle _outdoorThermometerTop; - - private SettingHandle _showTemperatureOverRooms; - - private SettingHandle _useCustomRange; - private SettingHandle _customRangeMin; - private SettingHandle _customRangeMax; - } -} diff --git a/src/HeatMap/MapInterface_Detour.cs b/src/HeatMap/MapInterface_Detour.cs deleted file mode 100644 index 0138a24..0000000 --- a/src/HeatMap/MapInterface_Detour.cs +++ /dev/null @@ -1,32 +0,0 @@ -using HarmonyLib; -using RimWorld; -using RimWorld.Planet; -using Verse; - -namespace HeatMap -{ - [HarmonyPatch(typeof(MapInterface), "MapInterfaceUpdate")] - public static class MapInterface_MapInterfaceUpdate_Detour - { - [HarmonyPostfix] - static void Postfix() - { - if (Find.CurrentMap == null || WorldRendererUtility.WorldRenderedNow) - { - return; - } - - Main.Instance.UpdateHeatMap(); - } - } - - [HarmonyPatch(typeof(MapInterface), "Notify_SwitchedMap")] - internal static class MapInterface_Notify_SwitchedMap_Detour - { - [HarmonyPostfix] - static void Postfix() - { - Main.Instance.ResetAll(); - } - } -} \ No newline at end of file diff --git a/src/HeatMap/MapTemperature_Detour.cs b/src/HeatMap/MapTemperature_Detour.cs new file mode 100644 index 0000000..251758d --- /dev/null +++ b/src/HeatMap/MapTemperature_Detour.cs @@ -0,0 +1,92 @@ +using HarmonyLib; +using RimWorld; +using System; +using System.Collections.Generic; +using System.Linq; +using System.Reflection; +using System.Reflection.Emit; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace HeatMap +{ + [HarmonyPatch(typeof(MapTemperature), "GetColorForTemperature")] + public static class MapTemperature_GetColorForTemperature_Patch + { + [HarmonyPrefix] + static bool Prefix(ref Color __result, float temperature) + { + // use vanilla overlay + if (!HeatMap.Instance.OverrideVanillaOverlay) + return true; // execute original + + // use HeatMap's overlay + __result = HeatMapHelper.GetColorForTemperature(temperature); + return false; // skip the original + } + } + + [HarmonyPatch(typeof(MapTemperature), "get_Drawer")] + public static class MapTemperature_get_Drawer_Patch + { + [HarmonyPostfix] + static void Postfix(ref CellBoolDrawer __result) + { + // check if opacity changed + var opacity = HeatMap.Instance.OverlayOpacity; + if (__result?.opacity != opacity) + { + // set drawer opacity + __result.opacity = opacity; + + // Material must be set to null to regenerate it, which applies the opacity + __result.material = null; + } + } + } + + [HarmonyPatch(typeof(MapTemperature), "GetCellBool")] + public static class MapTemperature_GetCellBool_Patch + { + [HarmonyTranspiler] + static IEnumerable Transpiler(IEnumerable instructions, ILGenerator generator) + { + var output = new List(); + foreach (var instruction in instructions) + { + // override everything past GetRooms + if (instruction.opcode == OpCodes.Call + && instruction.operand is MethodInfo methodInfo + && methodInfo.Name == nameof(GridsUtility.GetRoom)) + break; + + // keep everything before GetRooms + output.Add(instruction); + } + + // call static System.Boolean HeatMap.MapTemperature_GetCellBool_Patch::Check(Verse.IntVec3 intVec, Verse.Map map) + output.Add( + new CodeInstruction(OpCodes.Call, + typeof(MapTemperature_GetCellBool_Patch).GetMethod(nameof(MapTemperature_GetCellBool_Patch.CheckRoom), BindingFlags.Static | BindingFlags.NonPublic))); + // ret NULL + output.Add(new CodeInstruction(OpCodes.Ret)); + + // output the changed IL code + return output; + } + + /// + /// Checks if tile is valid and if it is outdoors, check if outdoors temperature should get an overlay + /// + /// + /// + /// + private static bool CheckRoom(IntVec3 intVec, Map map) + { + var room = intVec.GetRoom(map); + return room != null && (!room.PsychologicallyOutdoors || !HeatMap.Instance.ShowIndoorsOnly); + } + } +} diff --git a/src/HeatMap/PlaySettings_Detour.cs b/src/HeatMap/PlaySettings_Detour.cs deleted file mode 100644 index 0e99472..0000000 --- a/src/HeatMap/PlaySettings_Detour.cs +++ /dev/null @@ -1,23 +0,0 @@ -using HarmonyLib; -using RimWorld; -using Verse; - -namespace HeatMap -{ - [HarmonyPatch(typeof(PlaySettings), "DoPlaySettingsGlobalControls")] - public static class PlaySettings_Detour - { - [HarmonyPostfix] - static void PostFix(WidgetRow row, bool worldView) - { - if (worldView) - return; - - if (row == null || Resources.Icon == null) - return; - - row.ToggleableIcon(ref Main.Instance.ShowHeatMap, Resources.Icon, - "FALCHM.ShowHeatMap".Translate(), SoundDefOf.Mouseover_ButtonToggle); - } - } -} \ No newline at end of file diff --git a/src/HeatMap/Properties/AssemblyInfo.cs b/src/HeatMap/Properties/AssemblyInfo.cs index 6305ec1..e9ec3df 100644 --- a/src/HeatMap/Properties/AssemblyInfo.cs +++ b/src/HeatMap/Properties/AssemblyInfo.cs @@ -31,8 +31,9 @@ // You can specify all the values or you can default the Build and Revision Numbers // by using the '*' as shown below: // [assembly: AssemblyVersion("1.0.*")] -[assembly: AssemblyVersion("1.3.18.0")] -[assembly: AssemblyFileVersion("1.3.18.0")] +[assembly: AssemblyVersion("1.4.18.0")] +[assembly: AssemblyFileVersion("1.4.18.0")] + diff --git a/src/HeatMap/packages.config b/src/HeatMap/packages.config deleted file mode 100644 index e422788..0000000 --- a/src/HeatMap/packages.config +++ /dev/null @@ -1,5 +0,0 @@ - - - - - \ No newline at end of file From 851cb89ada46b1271e8378255e66d706837c3de9 Mon Sep 17 00:00:00 2001 From: Chris F Date: Sun, 23 Oct 2022 21:47:41 +0200 Subject: [PATCH 2/2] Added 1.4 as supported version in About.xml (totally forgot that) --- mod-structure/About/About.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/mod-structure/About/About.xml b/mod-structure/About/About.xml index 735b79a..6c2c4d2 100644 --- a/mod-structure/About/About.xml +++ b/mod-structure/About/About.xml @@ -5,6 +5,7 @@ Falconne Adds an overlay toggle button to show a temperature based colour gradient over indoor areas: green for the human comfort zone, getting bluer and redder for colder and hotter rooms respectively. +
  • 1.4
  • 1.3
  • 1.2
  • 1.1