Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of ShadowTrim v0.1.0
ShadowTrim.dll
Decompiled 3 days agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using System.Text; using BepInEx; using BepInEx.Configuration; using HarmonyLib; using Unity.Profiling; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyVersion("0.0.0.0")] namespace ShadowTrim; [BepInPlugin("j1ga.shadowtrim", "ShadowTrim", "0.1.0")] public class ShadowTrimPlugin : BaseUnityPlugin { private sealed class BenchSide { public double Frames; public double Seconds; public double Casters; public double CasterFrames; } private sealed class LayerCount { public int Casting; public int Trimmed; } private sealed class Changed { public Renderer R; public ShadowCastingMode Mode; } [HarmonyPatch(typeof(Piece), "Awake")] private static class Piece_Awake_Patch { private static void Postfix(Piece __instance) { ShadowTrimPlugin instance = Instance; if ((Object)(object)instance != (Object)null && instance._flatOn && (Object)(object)__instance != (Object)null) { instance._queue.Add(__instance); } } } [HarmonyPatch(typeof(Piece), "OnDestroy")] private static class Piece_OnDestroy_Patch { private static void Postfix(Piece __instance) { ShadowTrimPlugin instance = Instance; if ((Object)(object)instance != (Object)null && (Object)(object)__instance != (Object)null) { instance._flatPieces.Remove(((Object)__instance).GetInstanceID()); } } } private sealed class PresetValues { public float Buildings; public float Decor; public float Small; public float Items; public string Other; } private const float BenchPhase = 5f; private const float BenchSettle = 1f; private const int BenchPhases = 8; private const string SecGeneral = "01 General"; private const string SecDistance = "02 Shadow distance by layer"; private const string SecFlat = "03 Flat on the ground"; public const string Guid = "j1ga.shadowtrim"; public const string Name = "ShadowTrim"; public const string Version = "0.1.0"; private const double FlatBudgetMs = 1.0; private const string PresetNormal = "Normal"; private const string PresetLow = "Low"; private const string PresetCustom = "Custom"; private bool _benching; private ConfigEntry<bool> _cfgEnabled; private ConfigEntry<float> _cfgBuildings; private ConfigEntry<float> _cfgDecor; private ConfigEntry<float> _cfgSmall; private ConfigEntry<float> _cfgItems; private ConfigEntry<string> _cfgOther; private ConfigEntry<bool> _cfgFlat; private ConfigEntry<float> _cfgFlatGap; private ConfigEntry<float> _cfgFlatTop; private readonly HashSet<string> _warned = new HashSet<string>(); internal static ShadowTrimPlugin Instance; private Harmony _harmony; private readonly HashSet<string> _failed = new HashSet<string>(); private readonly List<Piece> _queue = new List<Piece>(); private readonly List<Piece> _later = new List<Piece>(); private readonly List<Changed> _changed = new List<Changed>(); private readonly HashSet<int> _flatPieces = new HashSet<int>(); private int _queueCursor; private float _nextLater; private bool _flatDirty = true; private bool _flatOn; private readonly Stopwatch _sw = new Stopwatch(); private static readonly List<MeshRenderer> s_renderers = new List<MeshRenderer>(); private float _nextPrune; private Light _sun; private float[] _applied; private bool _layersDirty = true; private float _nextSunCheck; private static readonly PresetValues s_normal = new PresetValues { Buildings = 60f, Decor = 40f, Small = 30f, Items = 25f, Other = "" }; private static readonly PresetValues s_low = new PresetValues { Buildings = 35f, Decor = 25f, Small = 20f, Items = 15f, Other = "static_solid=60,Default=60" }; private ConfigEntry<string> _cfgPreset; private bool _applyingPreset; private bool FlatWanted { get { if (Active) { return _cfgFlat.Value; } return false; } } private bool Active { get { if (_cfgEnabled != null) { return _cfgEnabled.Value; } return false; } } private Light Sun { get { EnvMan instance = EnvMan.instance; if (!((Object)(object)instance != (Object)null)) { return null; } return instance.m_dirLight; } } private void StartBench(ConsoleEventArgs args) { if (_benching) { Say(args, "A benchmark is already running."); return; } if ((Object)(object)Sun == (Object)null) { Say(args, "No sun here (indoors or in a dungeon); nothing to measure."); return; } Terminal term = args?.Context; Say(args, "ShadowTrim benchmark: " + 40f.ToString("0") + " s, switching every " + 5f.ToString("0") + " s. Stand still and keep the camera where it is."); ((MonoBehaviour)this).StartCoroutine(Bench(term)); } private IEnumerator Bench(Terminal term) { _benching = true; BenchSide on = new BenchSide(); BenchSide off = new BenchSide(); ProfilerRecorder casters = default(ProfilerRecorder); try { casters = ProfilerRecorder.StartNew(ProfilerCategory.Render, "Shadow Casters Count", 1, (ProfilerRecorderOptions)24); } catch (Exception) { } float[] trimmed = Distances(); try { for (int phase = 0; phase < 8; phase++) { bool trim = phase % 2 == 1; ApplyBench(trim, trimmed); BenchSide side = (trim ? on : off); float t0 = Time.unscaledTime; while (Time.unscaledTime - t0 < 5f) { yield return null; if (!(Time.unscaledTime - t0 < 1f)) { side.Frames += 1.0; side.Seconds += Time.unscaledDeltaTime; if (((ProfilerRecorder)(ref casters)).Valid) { side.Casters += ((ProfilerRecorder)(ref casters)).LastValue; side.CasterFrames += 1.0; } } } } } finally { if (((ProfilerRecorder)(ref casters)).Valid) { ((ProfilerRecorder)(ref casters)).Dispose(); } FlipFlat(_flatOn); _layersDirty = true; _sun = null; _benching = false; } string r = "ShadowTrim benchmark:\n" + BenchLine("game's shadows", off) + "\n" + BenchLine("ShadowTrim", on); if (off.Frames > 0.0 && on.Frames > 0.0) { double num = off.Seconds / off.Frames * 1000.0; double num2 = on.Seconds / on.Frames * 1000.0; string text = r; r = text + "\nFrame time " + ((num - num2 >= 0.0) ? "-" : "+") + Math.Abs(num - num2).ToString("0.00") + " ms (" + ((num - num2) / num * 100.0).ToString("0.0") + "% faster)"; } Log(r.Replace("\n", " | ")); if ((Object)(object)term != (Object)null) { term.AddString(r); } } private static string BenchLine(string name, BenchSide s) { if (s.Frames <= 0.0) { return " " + name + ": no frames"; } double num = s.Seconds / s.Frames * 1000.0; string text = " " + name + ": " + num.ToString("0.00") + " ms (" + (1000.0 / num).ToString("0") + " fps)"; if (s.CasterFrames > 0.0) { text = text + ", " + (s.Casters / s.CasterFrames).ToString("0") + " shadow casters"; } return text; } private void ApplyBench(bool trim, float[] trimmed) { Light sun = Sun; if ((Object)(object)sun != (Object)null) { if (trim && trimmed != null) { sun.layerShadowCullDistances = trimmed; } else { Clear(sun); } } _sun = sun; _applied = (trim ? trimmed : null); FlipFlat(trim); } private void RegisterCommands() { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //IL_0020: Unknown result type (might be due to invalid IL or missing references) new ConsoleCommand("shadowtrim", "ShadowTrim. 'shadowtrim' switches it on and off to compare; 'shadowtrim status' counts the shadows around you; 'shadowtrim bench' measures the gain where you stand", (ConsoleEvent)delegate(ConsoleEventArgs args) { RunCommand(args); }, false, false, false, false, false, false, (ConsoleOptionsFetcher)null, false, false, false); } private static void Say(ConsoleEventArgs args, string text) { if (args != null && (Object)(object)args.Context != (Object)null) { args.Context.AddString(text); } } private void RunCommand(ConsoleEventArgs args) { try { string text = ((args.Length > 1) ? args[1].ToLowerInvariant() : ""); switch (text) { case "status": Say(args, Status()); break; case "bench": StartBench(args); break; case "on": case "off": case "": { bool flag = ((text == "") ? (!_cfgEnabled.Value) : (text == "on")); _cfgEnabled.Value = flag; Say(args, "ShadowTrim " + (flag ? "on" : "off") + ". 'shadowtrim status' counts the shadows around you."); break; } default: Say(args, "shadowtrim [on|off|status|bench]"); break; } } catch (Exception ex) { Say(args, "shadowtrim failed: " + ex.Message); } } private string Status() { //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) StringBuilder stringBuilder = new StringBuilder(); Light sun = Sun; stringBuilder.Append("ShadowTrim ").Append("0.1.0").Append(Active ? ": on" : ": off") .Append(", the game's shadow distance ") .Append(QualitySettings.shadowDistance.ToString("0")) .Append(" m") .Append(((Object)(object)sun == (Object)null) ? ", no sun here" : "") .Append('\n'); Camera main = Camera.main; if ((Object)(object)main == (Object)null) { stringBuilder.Append("No camera."); return stringBuilder.ToString(); } Vector3 position = ((Component)main).transform.position; float shadowDistance = QualitySettings.shadowDistance; Dictionary<int, LayerCount> dictionary = new Dictionary<int, LayerCount>(); int num = 0; int num2 = 0; Renderer[] array = Object.FindObjectsByType<Renderer>((FindObjectsSortMode)0); foreach (Renderer val in array) { if ((Object)(object)val == (Object)null || !val.enabled || !((Component)val).gameObject.activeInHierarchy || (!(val is MeshRenderer) && !(val is SkinnedMeshRenderer)) || (int)val.shadowCastingMode == 0) { continue; } Bounds bounds = val.bounds; float num3 = Vector3.Distance(position, ((Bounds)(ref bounds)).center); if (!(num3 > shadowDistance)) { int layer = ((Component)val).gameObject.layer; if (!dictionary.TryGetValue(layer, out var value)) { value = (dictionary[layer] = new LayerCount()); } value.Casting++; num++; if (Active && num3 > EffectiveDistance(layer)) { value.Trimmed++; num2++; } } } stringBuilder.Append("Shadow casters within ").Append(shadowDistance.ToString("0")).Append(" m: ") .Append(num); if (Active) { stringBuilder.Append(", of them past their layer's distance (no shadow): ").Append(num2); } stringBuilder.Append('\n'); List<KeyValuePair<int, LayerCount>> list = new List<KeyValuePair<int, LayerCount>>(dictionary); list.Sort((KeyValuePair<int, LayerCount> a, KeyValuePair<int, LayerCount> b) => b.Value.Casting.CompareTo(a.Value.Casting)); foreach (KeyValuePair<int, LayerCount> item in list) { string value2 = LayerMask.LayerToName(item.Key); if (string.IsNullOrEmpty(value2)) { value2 = "layer " + item.Key; } stringBuilder.Append(" ").Append(value2).Append(": ") .Append(item.Value.Casting); float num4 = EffectiveDistance(item.Key); if (Active && num4 < shadowDistance) { stringBuilder.Append(", shadow to ").Append(num4.ToString("0")).Append(" m, ") .Append(item.Value.Trimmed) .Append(" past it"); } stringBuilder.Append('\n'); } FlatCounts(out var pieces, out var renderers); stringBuilder.Append("Flat on the ground: ").Append(_flatOn ? (pieces + " pieces (" + renderers + " renderers) cast no shadow") : "off"); if (_flatOn && _queue.Count - _queueCursor + _later.Count > 0) { stringBuilder.Append(", ").Append(_queue.Count - _queueCursor + _later.Count).Append(" still to look at"); } return stringBuilder.ToString(); } private void BindConfig() { _cfgEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("01 General", "Enabled", true, "Off: every shadow as in the game. The console command 'shadowtrim' switches it too, to compare on the spot."); _cfgBuildings = ((BaseUnityPlugin)this).Config.Bind<float>("02 Shadow distance by layer", "Buildings", 60f, "Building pieces (layer 'piece'): walls, floors, roofs, beams, stations. Metres from the camera; 0 = the game's own shadow distance (Graphics settings). The object is still drawn and still darkened by other shadows - only its own shadow ends there."); _cfgDecor = ((BaseUnityPlugin)this).Config.Bind<float>("02 Shadow distance by layer", "Decor", 40f, "Pieces you can walk through (layer 'piece_nonsolid'): banners, rugs, item stands, small decor. Metres from the camera; 0 = the game's own shadow distance (Graphics settings). The object is still drawn and still darkened by other shadows - only its own shadow ends there."); _cfgSmall = ((BaseUnityPlugin)this).Config.Bind<float>("02 Shadow distance by layer", "SmallObjects", 30f, "Small world objects (layer 'Default_small'): bushes, pickables, small stones and branches. Metres from the camera; 0 = the game's own shadow distance (Graphics settings). The object is still drawn and still darkened by other shadows - only its own shadow ends there."); _cfgItems = ((BaseUnityPlugin)this).Config.Bind<float>("02 Shadow distance by layer", "Items", 25f, "Dropped items and floating logs (layer 'item'). Metres from the camera; 0 = the game's own shadow distance (Graphics settings). The object is still drawn and still darkened by other shadows - only its own shadow ends there."); _cfgOther = ((BaseUnityPlugin)this).Config.Bind<string>("02 Shadow distance by layer", "OtherLayers", "", "Any other layer, as layer=metres separated by commas, e.g. static_solid=80,character=50. 'shadowtrim status' lists the layers that cast shadows around you and how many objects each has."); _cfgFlat = ((BaseUnityPlugin)this).Config.Bind<bool>("03 Flat on the ground", "Enabled", true, "Pieces lying flat on the ground (floors, path stones, rugs) stop casting a shadow: it falls into the ground right under them and cannot be seen anyway."); _cfgFlatGap = ((BaseUnityPlugin)this).Config.Bind<float>("03 Flat on the ground", "MaxGapBelow", 0.3f, "How far above the lowest ground under it a piece's underside may be and still count as lying on the ground, in metres. A floor over a dip or on posts is left alone."); _cfgFlatTop = ((BaseUnityPlugin)this).Config.Bind<float>("03 Flat on the ground", "MaxHeightAbove", 0.6f, "How far above the highest ground under it a piece's top may reach, in metres. Taller pieces cast a visible shadow beside themselves and are left alone."); _cfgEnabled.SettingChanged += delegate { _layersDirty = true; _flatDirty = true; }; _cfgBuildings.SettingChanged += delegate { _layersDirty = true; }; _cfgDecor.SettingChanged += delegate { _layersDirty = true; }; _cfgSmall.SettingChanged += delegate { _layersDirty = true; }; _cfgItems.SettingChanged += delegate { _layersDirty = true; }; _cfgOther.SettingChanged += delegate { _layersDirty = true; }; _cfgFlat.SettingChanged += delegate { _flatDirty = true; }; _cfgFlatGap.SettingChanged += delegate { _flatDirty = true; }; _cfgFlatTop.SettingChanged += delegate { _flatDirty = true; }; BindPreset(); } private Dictionary<string, float> LayerSettings() { Dictionary<string, float> dictionary = new Dictionary<string, float>(StringComparer.OrdinalIgnoreCase); dictionary["piece"] = _cfgBuildings.Value; dictionary["piece_nonsolid"] = _cfgDecor.Value; dictionary["Default_small"] = _cfgSmall.Value; dictionary["item"] = _cfgItems.Value; string[] array = (_cfgOther.Value ?? "").Split(',', ';'); foreach (string text in array) { string text2 = text.Trim(); if (text2.Length != 0) { int num = text2.IndexOf('='); if (num <= 0 || !float.TryParse(text2.Substring(num + 1).Trim(), NumberStyles.Float, CultureInfo.InvariantCulture, out var result)) { WarnOnce("other:" + text2, "OtherLayers: '" + text2 + "' is not layer=metres; ignored."); } else { dictionary[text2.Substring(0, num).Trim()] = result; } } } return dictionary; } private void WarnOnce(string key, string text) { if (_warned.Add(key)) { Warn(text); } } private void Awake() { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Expected O, but got Unknown Instance = this; BindConfig(); _harmony = new Harmony("j1ga.shadowtrim"); _harmony.PatchAll(typeof(ShadowTrimPlugin).Assembly); RegisterCommands(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"ShadowTrim 0.1.0 loaded."); } private void OnDestroy() { try { RestoreLayers(); RestoreFlat(); if (_harmony != null) { _harmony.UnpatchSelf(); } } catch (Exception ex) { ((BaseUnityPlugin)this).Logger.LogWarning((object)("OnDestroy: " + ex.Message)); } } private void Update() { try { UpdateLayers(); } catch (Exception e) { Fail("layers", e); } try { UpdateFlat(); } catch (Exception e2) { Fail("flat pieces", e2); } } private void Fail(string where, Exception e) { if (_failed.Add(where)) { ((BaseUnityPlugin)this).Logger.LogError((object)(where + ": " + e)); } } internal void Log(string s) { ((BaseUnityPlugin)this).Logger.LogInfo((object)s); } internal void Warn(string s) { ((BaseUnityPlugin)this).Logger.LogWarning((object)s); } private void UpdateFlat() { if (Time.unscaledTime >= _nextPrune) { _nextPrune = Time.unscaledTime + 30f; _changed.RemoveAll((Changed ch) => (Object)(object)ch.R == (Object)null); } if (_flatDirty) { _flatDirty = false; RestoreFlat(); _flatOn = FlatWanted; if (_flatOn) { QueueAll(); } } if (!_flatOn) { return; } if (_later.Count > 0 && Time.unscaledTime >= _nextLater) { _nextLater = Time.unscaledTime + 2f; _queue.AddRange(_later); _later.Clear(); } if (_queueCursor >= _queue.Count) { if (_queue.Count > 0) { _queue.Clear(); _queueCursor = 0; } return; } _sw.Reset(); _sw.Start(); while (_queueCursor < _queue.Count && _sw.Elapsed.TotalMilliseconds < 1.0) { Look(_queue[_queueCursor++]); } if (_queueCursor >= _queue.Count) { _queue.Clear(); _queueCursor = 0; } } private void QueueAll() { FieldInfo fieldInfo = AccessTools.Field(typeof(Piece), "s_allPieces"); List<Piece> list = ((fieldInfo != null) ? (fieldInfo.GetValue(null) as List<Piece>) : null); if (list != null) { _queue.AddRange(list); } } private void Look(Piece piece) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) //IL_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0218: Invalid comparison between Unknown and I4 //IL_0234: Unknown result type (might be due to invalid IL or missing references) //IL_0239: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)piece == (Object)null) { return; } ZNetView component = ((Component)piece).GetComponent<ZNetView>(); if ((Object)(object)component == (Object)null || !component.IsValid() || _flatPieces.Contains(((Object)piece).GetInstanceID())) { return; } s_renderers.Clear(); ((Component)piece).GetComponentsInChildren<MeshRenderer>(true, s_renderers); bool flag = false; Bounds val = default(Bounds); for (int i = 0; i < s_renderers.Count; i++) { MeshRenderer val2 = s_renderers[i]; if (!((Object)(object)val2 == (Object)null) && ((Renderer)val2).enabled && ((Component)val2).gameObject.activeInHierarchy && (int)((Renderer)val2).shadowCastingMode != 0) { if (!flag) { val = ((Renderer)val2).bounds; flag = true; } else { ((Bounds)(ref val)).Encapsulate(((Renderer)val2).bounds); } } } if (!flag) { return; } float gMin = float.MaxValue; float gMax = float.MinValue; Vector3 center = ((Bounds)(ref val)).center; Vector3 extents = ((Bounds)(ref val)).extents; if (!Ground(center.x, center.z, ref gMin, ref gMax) || !Ground(center.x - extents.x, center.z - extents.z, ref gMin, ref gMax) || !Ground(center.x + extents.x, center.z - extents.z, ref gMin, ref gMax) || !Ground(center.x - extents.x, center.z + extents.z, ref gMin, ref gMax) || !Ground(center.x + extents.x, center.z + extents.z, ref gMin, ref gMax)) { _later.Add(piece); } else { if (((Bounds)(ref val)).min.y - gMin > _cfgFlatGap.Value || ((Bounds)(ref val)).max.y - gMax > _cfgFlatTop.Value) { return; } for (int j = 0; j < s_renderers.Count; j++) { MeshRenderer val3 = s_renderers[j]; if (!((Object)(object)val3 == (Object)null) && (int)((Renderer)val3).shadowCastingMode != 0 && (int)((Renderer)val3).shadowCastingMode != 3) { _changed.Add(new Changed { R = (Renderer)(object)val3, Mode = ((Renderer)val3).shadowCastingMode }); ((Renderer)val3).shadowCastingMode = (ShadowCastingMode)0; } } _flatPieces.Add(((Object)piece).GetInstanceID()); } } private static bool Ground(float x, float z, ref float gMin, ref float gMax) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) float num = default(float); if (!Heightmap.GetHeight(new Vector3(x, 0f, z), ref num)) { return false; } if (num < gMin) { gMin = num; } if (num > gMax) { gMax = num; } return true; } private void RestoreFlat() { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _changed.Count; i++) { Changed changed = _changed[i]; if ((Object)(object)changed.R != (Object)null && (int)changed.R.shadowCastingMode == 0) { changed.R.shadowCastingMode = changed.Mode; } } _changed.Clear(); _flatPieces.Clear(); _queue.Clear(); _later.Clear(); _queueCursor = 0; } private void FlipFlat(bool off) { //IL_0029: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < _changed.Count; i++) { Changed changed = _changed[i]; if ((Object)(object)changed.R != (Object)null) { changed.R.shadowCastingMode = (ShadowCastingMode)((!off) ? ((int)changed.Mode) : 0); } } } private void FlatCounts(out int pieces, out int renderers) { _changed.RemoveAll((Changed ch) => (Object)(object)ch.R == (Object)null); renderers = _changed.Count; HashSet<int> hashSet = new HashSet<int>(); for (int num = 0; num < _changed.Count; num++) { Piece componentInParent = ((Component)_changed[num].R).GetComponentInParent<Piece>(); if ((Object)(object)componentInParent != (Object)null) { hashSet.Add(((Object)componentInParent).GetInstanceID()); } } pieces = hashSet.Count; } private void UpdateLayers() { if (!_layersDirty && Time.unscaledTime < _nextSunCheck) { return; } _nextSunCheck = Time.unscaledTime + 0.5f; Light sun = Sun; if (!_layersDirty && (Object)(object)sun == (Object)(object)_sun) { return; } _layersDirty = false; if ((Object)(object)_sun != (Object)null && (Object)(object)_sun != (Object)(object)sun) { Clear(_sun); } _sun = sun; if ((Object)(object)sun == (Object)null) { _applied = null; return; } float[] array = (Active ? Distances() : null); if (array == null) { Clear(sun); _applied = null; } else { sun.layerShadowCullDistances = array; _applied = array; } } private float[] Distances() { float[] array = new float[32]; bool flag = false; foreach (KeyValuePair<string, float> item in LayerSettings()) { int num = LayerMask.NameToLayer(item.Key); if (num < 0) { WarnOnce("layer:" + item.Key, "There is no layer '" + item.Key + "' in this game; its distance is ignored."); continue; } float num2 = item.Value; if (num2 < 0f || float.IsNaN(num2)) { num2 = 0f; } array[num] = num2; if (num2 > 0f) { flag = true; } } if (!flag) { return null; } return array; } private static void Clear(Light l) { if ((Object)(object)l != (Object)null) { l.layerShadowCullDistances = new float[32]; } } private void RestoreLayers() { if ((Object)(object)_sun != (Object)null) { Clear(_sun); } _sun = null; _applied = null; } private float EffectiveDistance(int layer) { float shadowDistance = QualitySettings.shadowDistance; if (_applied == null || layer < 0 || layer >= _applied.Length || _applied[layer] <= 0f) { return shadowDistance; } return Mathf.Min(shadowDistance, _applied[layer]); } private void BindPreset() { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Expected O, but got Unknown _cfgPreset = ((BaseUnityPlugin)this).Config.Bind<string>("01 General", "Preset", "Normal", new ConfigDescription("Normal: the defaults (buildings 60 m, decor 40, small objects 30, items 25). Low: for weak PCs (buildings 35 m, decor 25, small objects 20, items 15, rocks and other objects 60) - shadows appear closer, there are fewer of them. Custom: the distances below as you set them; changing any of them switches to Custom by itself.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Normal", "Low", "Custom" }), new object[0])); PresetValues presetValues = PresetFor(_cfgPreset.Value); if (presetValues != null && !Matches(presetValues)) { _cfgPreset.Value = "Custom"; } _cfgPreset.SettingChanged += delegate { ApplyPreset(); }; EventHandler eventHandler = delegate { if (!_applyingPreset) { PresetValues presetValues2 = PresetFor(_cfgPreset.Value); if (presetValues2 != null && !Matches(presetValues2)) { _cfgPreset.Value = "Custom"; } } }; _cfgBuildings.SettingChanged += eventHandler; _cfgDecor.SettingChanged += eventHandler; _cfgSmall.SettingChanged += eventHandler; _cfgItems.SettingChanged += eventHandler; _cfgOther.SettingChanged += eventHandler; } private static PresetValues PresetFor(string name) { if (string.Equals(name, "Normal", StringComparison.OrdinalIgnoreCase)) { return s_normal; } if (string.Equals(name, "Low", StringComparison.OrdinalIgnoreCase)) { return s_low; } return null; } private bool Matches(PresetValues p) { if (_cfgBuildings.Value == p.Buildings && _cfgDecor.Value == p.Decor && _cfgSmall.Value == p.Small && _cfgItems.Value == p.Items) { return string.Equals((_cfgOther.Value ?? "").Replace(" ", ""), p.Other, StringComparison.OrdinalIgnoreCase); } return false; } private void ApplyPreset() { PresetValues presetValues = PresetFor(_cfgPreset.Value); if (presetValues != null && !Matches(presetValues)) { _applyingPreset = true; try { _cfgBuildings.Value = presetValues.Buildings; _cfgDecor.Value = presetValues.Decor; _cfgSmall.Value = presetValues.Small; _cfgItems.Value = presetValues.Items; _cfgOther.Value = presetValues.Other; } finally { _applyingPreset = false; } _layersDirty = true; } } }