diff --git a/HeatMap.xlsx b/HeatMap.xlsx new file mode 100644 index 0000000..19741e7 Binary files /dev/null and b/HeatMap.xlsx differ diff --git a/mod-structure/1.4/Assemblies/HeatMap.dll b/mod-structure/1.4/Assemblies/HeatMap.dll new file mode 100644 index 0000000..623e695 Binary files /dev/null and b/mod-structure/1.4/Assemblies/HeatMap.dll differ diff --git a/mod-structure/1.5/Assemblies/HeatMap.dll b/mod-structure/1.5/Assemblies/HeatMap.dll new file mode 100644 index 0000000..8e33c6d Binary files /dev/null and b/mod-structure/1.5/Assemblies/HeatMap.dll differ diff --git a/mod-structure/About/About.xml b/mod-structure/About/About.xml index 735b79a..b356590 100644 --- a/mod-structure/About/About.xml +++ b/mod-structure/About/About.xml @@ -5,6 +5,8 @@ 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.5
  • +
  • 1.4
  • 1.3
  • 1.2
  • 1.1
  • diff --git a/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml b/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml index 7f79ca7..50dd0f6 100644 --- a/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml +++ b/mod-structure/Languages/English/Keyed/FALCHM_LanguageData.xml @@ -1,43 +1,94 @@ + Override vanilla overlay + Use Heat Map's overlay instead of the vanilla overlay. +(default: {default}) + + Only overlay indoor areas + Only show the overlay for indoors areas. +(default: {default}) + Opacity of overlay - Reduce this value to make the overlay more transparent. + Reduce this value to make the overlay more transparent. +(default: {default}%) 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: {default}) 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: {default}) 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 colour more transparent. +(default: {default}%) Lock thermometer position - Locks the thermometer widget in place, disabling shift-click dragging. + Locks the thermometer widget in place, disabling shift-click dragging. +(default: {default}) 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: {default}) 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: {default}) - 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: {default}) + + Colour gradient hue {index} + Defines which colours will be used for the overlay's colour gradient. Colours are given as hue in degree. +(default: {default}) + +- Colours: +0°/360° = red +60° = yellow +120° = green +180° = cyan +240° = blue +300° = magenta + +Each degree of temperature between min/max (default: {min} to {max} °C) has a relative gradient step width of 1, except for the values between min/max comfort temperature (default: {comfortMin} to {comfortMax} °C), which have a step width of 4. +I.e. each degree of the comfort temperature range takes up four times as much on the colour gradient as one outside of the comfort levels. +For example when using default settings green will be applied to a smaller temperature range than red or blue. 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, custom temperature boundaries for the colour gradient can be set. +(default: {default}) Custom range min - Blue end of gradient. Temperatures below this will be blue. Use current temperature units + Lower temperature limit of the colour gradient. +Temperatures below this will be coloured using colour gradient hue 0, default: blue. +Uses current temperature units +(default: {default}) Custom range max - Red end of gradient. Temperatures above this will be red. Use current temperature units + Upper temperature limit of the colour gradient. +Temperatures above this will be coloured using colour gradient hue 4, default: red. +Uses current temperature units +(default: {default}) - Show temperature over rooms - When overlay is on, this will also display the room temperature over the centre of the room. + Custom comfort range min + Lower comfort temperature. +Between min-max comfort temperature the colour changes four times as quickly as outside these limits, making small changes more noticeable. +Uses current temperature units +(default: {default}) + + Custom comfort range max + Upper comfort temperature. +Between min-max comfort temperature the colour changes four times as quickly as outside these limits, making small changes more noticeable. +Uses current temperature units +(default: {default}) + + 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/ColorHelper.cs b/src/HeatMap/ColorHelper.cs new file mode 100644 index 0000000..5f9f6df --- /dev/null +++ b/src/HeatMap/ColorHelper.cs @@ -0,0 +1,106 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using UnityEngine; +using Verse; + +namespace HeatMap +{ + public class ColorHelper + { + /// + /// Calculate a color from a color gradient between two colors + /// + /// Gradient start color + /// Gradient end color + /// Position in color gradient; can be equal to return + /// Number of steps in the color gradient + /// Alpha-Channel + /// + public static Color Gradient(Color start, Color end, float pos, float steps, float a = 1f) + { + if (steps <= 0) + return new Color(end.r, end.g, end.b, a); + + pos %= steps + 1; + + var rMin = start.r; + var rMax = end.r; + var gMin = start.g; + var gMax = end.g; + var bMin = start.b; + var bMax = end.b; + + var rAverage = rMin + ((rMax - rMin) * pos / steps); + var gAverage = gMin + ((gMax - gMin) * pos / steps); + var bAverage = bMin + ((bMax - bMin) * pos / steps); + + return new Color(rAverage, gAverage, bAverage, a); + } + + /// + /// Creates a color gradient using and + /// + /// Colors to be used for the gradient with relative weighting factor; relatively higher factors will make the color be used for more steps + /// Steps with stepwidth; longer stepwidth advances through the gradient faster + /// Alpha-Channel + /// + public static List Gradient(IList> colors, IList steps, float a = 1f) + { + if (!(colors?.Count > 0)) + { + Log.Warning("Colors must have at least 1 element"); + return new List { Color.white }; + } + + if (!(steps?.Count > 0)) + { + Log.Warning("Steps must have at least 1 element"); + return new List { Color.white }; + } + + var stepsTotal = 0f; + foreach (var step in steps) + stepsTotal += step; + if (stepsTotal == 0) + { + Log.Warning("Steps total must be greater than 0"); + return new List { Color.white }; + } + + var total = 0f; + for (int i = 0; i < colors.Count - 1; i++) + total += colors[i].Item2; + + var offset = 0f; + var list = new List>(); + foreach (var item in colors) + { + list.Add(new Tuple(item.Item1, offset)); + offset += stepsTotal * (item.Item2 / total); + } + + var output = new List(); + var pos = 0f; + for (int i = 0, j = 0; i < list.Count - 1; i++) + { + var item = list[i]; + var next = list[i + 1]; + while (pos < next.Item2) + { + output.Add(Gradient( + item.Item1, + next.Item1, + pos - item.Item2, + next.Item2 - item.Item2, + a)); + pos += steps[j++]; + } + } + output.Add(colors.Last().Item1); + return output; + } + } +} diff --git a/src/HeatMap/HeatMap.cs b/src/HeatMap/HeatMap.cs index c3479f7..1084de3 100644 --- a/src/HeatMap/HeatMap.cs +++ b/src/HeatMap/HeatMap.cs @@ -1,215 +1,400 @@ -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; + + public const int GradientSteps = 5; + private readonly SettingHandle[] _gradientHue = new SettingHandle[GradientSteps]; + + private SettingHandle _useCustomRange; + private SettingHandle _customRangeMin; + private SettingHandle _customRangeMax; + private SettingHandle _customRangeComfortMin; + private SettingHandle _customRangeComfortMax; + + + 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 int CustomRangeComfortMin => + _customRangeComfortMin; + public int CustomRangeComfortMax => + _customRangeComfortMax; + + public Color GetGradientColor(int index) + { + if (index >= 0 && index < _gradientHue.Length) + return Color.HSVToRGB(_gradientHue[index] / 360f, 1f, 1f); + return Color.black; + } + + + 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(new NamedArgument(true, "default")), + true); + _overrideVanillaOverlay.ValueChanged += val => ResetAll(); + + _showIndoorsOnly = Settings.GetHandle( + "showRoomsOnly", + "FALCHM.ShowIndoorsOnly".Translate(), + "FALCHM.ShowIndoorsOnlyDesc".Translate(new NamedArgument(true, "default")), + true); + _showIndoorsOnly.ValueChanged += val => ResetAll(); + + _opacity = Settings.GetHandle( + "opacity", + "FALCHM.OverlayOpacity".Translate(), + "FALCHM.OverlayOpacityDesc".Translate(new NamedArgument(30, "default")), + 30, + Validators.IntRangeValidator(0, 100)); + _opacity.ValueChanged += val => ResetAll(); + + _updateDelay = Settings.GetHandle( + "updateDelay", + "FALCHM.UpdateDelay".Translate(), + "FALCHM.UpdateDelayDesc".Translate(new NamedArgument(100, "default")), + 100, + Validators.IntRangeValidator(1, 9999)); + + + _showOutdoorThermometer = Settings.GetHandle( + "showOutdoorThermometer", + "FALCHM.ShowOutDoorThermometer".Translate(), + "FALCHM.ShowOutDoorThermometerDesc".Translate(new NamedArgument(true, "default")), + true); + + _outdoorThermometerOpacity = Settings.GetHandle( + "outdoorThermometerOpacity", + "FALCHM.ThermometerOpacity".Translate(), + "FALCHM.ThermometerOpacityDesc".Translate(new NamedArgument(30, "default")), + 30, + Validators.IntRangeValidator(1, 100)); + _outdoorThermometerOpacity.ValueChanged += val => _temperatureTextureCache.Clear(); + + _outdoorThermometerFixed = Settings.GetHandle( + "outdoorThermometerFixed", + "FALCHM.ThermometerFixed".Translate(), + "FALCHM.ThermometerFixedDesc".Translate(new NamedArgument(false, "default")), + false); + + _outdoorThermometerRight = Settings.GetHandle( + "outdoorThermometerRight", + "FALCHM.ThermometerRight".Translate(), + "FALCHM.ThermometerRightDesc".Translate(new NamedArgument(8f + _boxSize, "default")), + 8f + _boxSize); + + _outdoorThermometerTop = Settings.GetHandle( + "outdoorThermometerTop", + "FALCHM.ThermometerTop".Translate(), + "FALCHM.ThermometerTopDesc".Translate(new NamedArgument(8f, "default")), + 8f); + + + _showTemperatureOverRooms = Settings.GetHandle( + "showTemperatureOverRooms", + "FALCHM.ShowTemperatureOverRooms".Translate(), + "FALCHM.ShowTemperatureOverRoomsDesc".Translate(new NamedArgument(true, "default")), + true); + + (var mappedRange, var minComfortTemp, var maxComfortTemp) = HeatMapHelper.GetComfortTemperatureRanges(); + + var gradientValidator = Validators.FloatRangeValidator(0f, 360f); + for (int i = 0; i < GradientSteps; i++) + { + _gradientHue[i] = Settings.GetHandle( + $"gradientHue{i}", + $"FALCHM.GradientHue".Translate(new NamedArgument(i, "index")), + $"FALCHM.GradientHueDesc".Translate( + new NamedArgument(240f - 60f * i, "default"), + new NamedArgument(mappedRange.min, "min"), + new NamedArgument(mappedRange.max, "max"), + new NamedArgument(minComfortTemp, "comfortMin"), + new NamedArgument(maxComfortTemp, "comfortMax")), + 240f - 60f * i, // 0° = red, 60° = yellow, 120° = green, 180° = cyan, 240° = blue, 300° = magenta; standard begins at blue (low) and ends at red (high) + gradientValidator); + _gradientHue[i].ValueChanged += val => ResetAll(); + } + + + _useCustomRange = Settings.GetHandle( + "useCustomeRange", + "FALCHM.UseCustomeRange".Translate(), + "FALCHM.UseCustomeRangeDesc".Translate(new NamedArgument(false, "default")), + false); + _useCustomRange.ValueChanged += val => ResetAll(); + + + _customRangeMin = Settings.GetHandle("customRangeMin", "Unused", "Unused", mappedRange.min); + _customRangeMin.VisibilityPredicate = () => false; + + _customRangeMax = Settings.GetHandle("customRangeMax", "Unused", "Unused", mappedRange.max); + _customRangeMax.VisibilityPredicate = () => false; + + _customRangeComfortMin = Settings.GetHandle("customRangeComfortMin", "Unused", "Unused", minComfortTemp); + _customRangeComfortMin.VisibilityPredicate = () => false; + + _customRangeComfortMax = Settings.GetHandle("customRangeComfortMax", "Unused", "Unused", maxComfortTemp); + _customRangeComfortMax.VisibilityPredicate = () => false; + + + var customRangeValidator = Validators.IntRangeValidator( + (int)GenTemperature.CelsiusTo(-273f, Prefs.TemperatureMode), + (int)GenTemperature.CelsiusTo(1000f, Prefs.TemperatureMode)); + + var customRangeMin = Settings.GetHandle( + "customRangeMinPlaceholder", + "FALCHM.CustomRangeMin".Translate(), + $"{"FALCHM.CustomRangeMinDesc".Translate(new NamedArgument(mappedRange.min, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})", + validator: customRangeValidator); + customRangeMin.Unsaved = true; + customRangeMin.VisibilityPredicate = () => _useCustomRange; + customRangeMin.Value = (int)GenTemperature.CelsiusTo(_customRangeMin, Prefs.TemperatureMode); + + var customRangeMax = Settings.GetHandle( + "customRangeMaxPlaceholder", + "FALCHM.CustomRangeMax".Translate(), + $"{"FALCHM.CustomRangeMaxDesc".Translate(new NamedArgument(mappedRange.max, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})", + validator: customRangeValidator); + customRangeMax.Unsaved = true; + customRangeMax.VisibilityPredicate = () => _useCustomRange; + customRangeMax.Value = (int)GenTemperature.CelsiusTo(_customRangeMax, Prefs.TemperatureMode); + + var customRangeComfortMin = Settings.GetHandle( + "customRangeComfortMinPlaceholder", + "FALCHM.CustomRangeComfortMin".Translate(), + $"{"FALCHM.CustomRangeComfortMinDesc".Translate(new NamedArgument(minComfortTemp, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})", + validator: customRangeValidator); + customRangeComfortMin.Unsaved = true; + customRangeComfortMin.VisibilityPredicate = () => _useCustomRange; + customRangeComfortMin.Value = (int)GenTemperature.CelsiusTo(_customRangeComfortMin, Prefs.TemperatureMode); + + var customRangeComfortMax = Settings.GetHandle( + "customRangeComfortMaxPlaceholder", + "FALCHM.CustomRangeComfortMax".Translate(), + $"{"FALCHM.CustomRangeComfortMaxDesc".Translate(new NamedArgument(maxComfortTemp, "default"))} ({Prefs.TemperatureMode.ToStringHuman()})", + validator: customRangeValidator); + customRangeComfortMax.Unsaved = true; + customRangeComfortMax.VisibilityPredicate = () => _useCustomRange; + customRangeComfortMax.Value = (int)GenTemperature.CelsiusTo(_customRangeComfortMax, Prefs.TemperatureMode); + + + 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(); + }; + customRangeComfortMin.ValueChanged += val => + { + _customRangeComfortMin.Value = ConvertToCelcius(customRangeComfortMin); + ResetAll(); + }; + customRangeComfortMax.ValueChanged += val => + { + _customRangeComfortMax.Value = ConvertToCelcius(customRangeComfortMax); + 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..9496dd9 100644 --- a/src/HeatMap/HeatMap.csproj +++ b/src/HeatMap/HeatMap.csproj @@ -23,212 +23,17 @@ 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 +84,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..01b5563 --- /dev/null +++ b/src/HeatMap/HeatMapHelper.cs @@ -0,0 +1,84 @@ +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() + { + var minComfortTemp = HeatMap.Instance.CustomRangeComfortMin; + var maxComfortTemp = HeatMap.Instance.CustomRangeComfortMax; + + MappedTemperatureRange = new IntRange(HeatMap.Instance.CustomRangeMin, HeatMap.Instance.CustomRangeMax); + MappedColors = CreateColorGradient(MappedTemperatureRange, minComfortTemp, maxComfortTemp); + } + + private static void CreateComfortMap() + { + (var mappedRange, var minComfortTemp, var maxComfortTemp) = GetComfortTemperatureRanges(); + + MappedTemperatureRange = mappedRange; + MappedColors = CreateColorGradient(MappedTemperatureRange, minComfortTemp, maxComfortTemp); + } + + private static Color[] CreateColorGradient(IntRange range, int minComfortTemp, int maxComfortTemp) + { + var mappedColorCount = MappedTemperatureRange.max - MappedTemperatureRange.min; + + var gradientColors = new List>(); + for (int i = 0; i < HeatMap.GradientSteps; i++) + gradientColors.Add(new Tuple(HeatMap.Instance.GetGradientColor(i), 1f)); + + var gradientSteps = new List(); + for (int i = 0, t = range.min; i < mappedColorCount; i++, t++) + gradientSteps.Add((t >= minComfortTemp - 1 && t <= maxComfortTemp) ? 4f : 1f); + + return ColorHelper.Gradient(gradientColors, gradientSteps).ToArray(); + } + + public static (IntRange mappedRange, int comfortTempMin, int comfortTempMax) GetComfortTemperatureRanges() + { + var human = ThingDefOf.Human; + var minComfortTemp = (int)human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMin) + 3; + var maxComfortTemp = (int)human.GetStatValueAbstract(StatDefOf.ComfyTemperatureMax) - 3; + + var comfortDoubleRange = (maxComfortTemp - minComfortTemp) * 2; + var mappedTemperatureRange = new IntRange( + minComfortTemp - comfortDoubleRange, maxComfortTemp + comfortDoubleRange); + + return (mappedTemperatureRange, minComfortTemp, maxComfortTemp); + } + + 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..f04daa5 100644 --- a/src/HeatMap/Properties/AssemblyInfo.cs +++ b/src/HeatMap/Properties/AssemblyInfo.cs @@ -31,8 +31,10 @@ // 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.5.19.0")] +[assembly: AssemblyFileVersion("1.5.19.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