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 Lumaheim v0.2.0
BepInEx/plugins/Lumaheim/Lumaheim.dll
Decompiled 6 days agousing System; using System.Collections.Generic; using System.Globalization; using System.Reflection; using System.Runtime.CompilerServices; using BepInEx; using BepInEx.Configuration; using GUIFramework; using HarmonyLib; using TMPro; using UnityEngine; using UnityEngine.EventSystems; using UnityEngine.Events; using UnityEngine.PostProcessing; using UnityEngine.UI; using UnityStandardAssets.ImageEffects; using Valheim.SettingsGui; [assembly: AssemblyCompany("Gomisan")] [assembly: AssemblyFileVersion("0.2.0.0")] [assembly: AssemblyInformationalVersion("0.2.0")] [assembly: AssemblyDescription("Valheim graphics controls. Coded with the assistance of ChatGPT 6.0.")] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: AssemblyTitle("Lumaheim")] [assembly: CompilationRelaxations(8)] [assembly: AssemblyVersion("0.2.0.0")] namespace Lumaheim; public static class DepthOfFieldControls { public struct Scope { public bool Changed; public bool Near; public bool High; public float Distance; public float Range; public float Blur; public Transform Target; public BlurSampleCount Samples; } public static bool Applies(Component component) { if (Object.op_Implicit((Object)(object)component) && Object.op_Implicit((Object)(object)component.GetComponent<GameCamera>())) { return Object.op_Implicit((Object)(object)component.GetComponent<CameraEffects>()); } return false; } public static Scope Begin(DepthOfField effect, VideoValues values) { //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00f7: Unknown result type (might be due to invalid IL or missing references) Scope result = default(Scope); if (values.DofMode == 0) { return result; } result.Changed = true; result.Distance = effect.focalLength; result.Range = effect.focalSize; result.Blur = effect.maxBlurSize; result.Near = effect.nearBlur; result.High = effect.highResolution; result.Samples = effect.blurSampleCount; result.Target = effect.focalTransform; if (values.DofMode == 2) { effect.focalTransform = null; effect.focalLength = values.FocusDistance; } effect.focalSize = values.FocusRange; effect.maxBlurSize = Mathf.Clamp(result.Blur * values.BlurStrength, 0.1f, 10f); if (values.Foreground != 0) { effect.nearBlur = values.Foreground == 2; } if (values.Quality != 0) { effect.blurSampleCount = (BlurSampleCount)Mathf.Min(values.Quality - 1, 2); effect.highResolution = values.Quality == 4; } return result; } public static void End(DepthOfField effect, Scope state) { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)effect) && state.Changed) { effect.focalLength = state.Distance; effect.focalSize = state.Range; effect.maxBlurSize = state.Blur; effect.nearBlur = state.Near; effect.highResolution = state.High; effect.blurSampleCount = state.Samples; effect.focalTransform = state.Target; } } } [HarmonyPatch(typeof(DepthOfField), "OnRenderImage")] internal static class DepthRenderPatch { private static void Prefix(DepthOfField __instance, out DepthOfFieldControls.Scope __state) { __state = default(DepthOfFieldControls.Scope); if (Plugin.Session != null && DepthOfFieldControls.Applies((Component)(object)__instance)) { __state = DepthOfFieldControls.Begin(__instance, Plugin.Session.Current); } } private static void Finalizer(DepthOfField __instance, DepthOfFieldControls.Scope __state) { DepthOfFieldControls.End(__instance, __state); } } [HarmonyPatch(typeof(CameraEffects), "UpdateDOF")] internal static class AutofocusPatch { private static void Prefix(CameraEffects __instance, out bool __state) { __state = __instance.m_dofAutoFocus; if (Plugin.Session != null && DepthOfFieldControls.Applies((Component)(object)__instance) && Plugin.Session.Current.DofMode == 1) { __instance.m_dofAutoFocus = true; } } private static void Finalizer(CameraEffects __instance, bool __state) { if (Object.op_Implicit((Object)(object)__instance)) { __instance.m_dofAutoFocus = __state; } } } public static class Grading { private sealed class Entry { internal ColorGradingModel Source; internal readonly ColorGradingModel Model = new ColorGradingModel(); internal VideoValues Values; internal Settings SourceSettings; internal bool Invalid = true; } public struct Scope { internal ColorGradingModel Original; internal float PreviousGamma; } private static readonly Dictionary<ColorGradingComponent, Entry> Entries = new Dictionary<ColorGradingComponent, Entry>(); public static float ActiveGamma = 1f; public static Settings Compose(Settings settings, VideoValues values) { //IL_01f2: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_01ce: Unknown result type (might be due to invalid IL or missing references) //IL_01e3: Unknown result type (might be due to invalid IL or missing references) //IL_01ed: Expected O, but got Unknown //IL_01e8: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Expected O, but got Unknown ref BasicSettings basic = ref settings.basic; basic.postExposure += values.Exposure; settings.basic.temperature = Mathf.Clamp(settings.basic.temperature + values.Warmth, -100f, 100f); settings.basic.tint = Mathf.Clamp(settings.basic.tint + values.Tint, -100f, 100f); ref BasicSettings basic2 = ref settings.basic; basic2.contrast *= values.Contrast; ref BasicSettings basic3 = ref settings.basic; basic3.saturation *= values.Saturation; if (values.ShadowDetail != 0f || values.HighlightDetail != 0f) { Keyframe[] array = (Keyframe[])(object)new Keyframe[129]; for (int i = 0; i < array.Length; i++) { float num = (float)i / 128f; float x = settings.curves.master.Evaluate(num); float num2 = AdjustDetail(x, values.ShadowDetail, values.HighlightDetail); ref Keyframe reference = ref array[i]; reference = new Keyframe(num, num2); } for (int j = 0; j < array.Length; j++) { float inTangent = ((j > 0) ? ((((Keyframe)(ref array[j])).value - ((Keyframe)(ref array[j - 1])).value) * 128f) : 0f); float outTangent = ((j < 128) ? ((((Keyframe)(ref array[j + 1])).value - ((Keyframe)(ref array[j])).value) * 128f) : 0f); ((Keyframe)(ref array[j])).inTangent = inTangent; ((Keyframe)(ref array[j])).outTangent = outTangent; } settings.curves.master = new ColorGradingCurve(new AnimationCurve(array), 0f, false, new Vector2(0f, 1f)); } return settings; } public static float AdjustDetail(float x, float shadows, float highlights) { x = Mathf.Clamp01(x); if (x < 0.5f) { return x + 0.9f * (shadows / 100f) * x * (1f - 2f * x) * (1f - 2f * x); } return x - 0.9f * (highlights / 100f) * (1f - x) * (2f * x - 1f) * (2f * x - 1f); } public static Scope Begin(ColorGradingComponent component, VideoValues values) { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Unknown result type (might be due to invalid IL or missing references) if (values.IsColorDefault) { Release(component); return default(Scope); } if (!Entries.TryGetValue(component, out var value)) { value = new Entry(); Entries.Add(component, value); } ColorGradingModel model = ((PostProcessingComponent<ColorGradingModel>)(object)component).model; Settings settings = model.settings; if (!value.Invalid && value.Source == model && value.Values.Equals(values)) { ref Settings sourceSettings = ref value.SourceSettings; object obj = settings; if (((object)Unsafe.As<Settings, Settings>(ref sourceSettings)/*cast due to .constrained prefix*/).Equals(obj)) { goto IL_00ba; } } value.Model.settings = Compose(settings, values); value.Values = values; value.SourceSettings = settings; value.Source = model; value.Invalid = false; goto IL_00ba; IL_00ba: if (((PostProcessingModel)value.Model).enabled != ((PostProcessingModel)model).enabled) { ((PostProcessingModel)value.Model).enabled = ((PostProcessingModel)model).enabled; } Scope result = new Scope { Original = model, PreviousGamma = ActiveGamma }; ((PostProcessingComponent<ColorGradingModel>)(object)component).Init(((PostProcessingComponentBase)component).context, value.Model); ActiveGamma = values.Gamma; return result; } public static void End(ColorGradingComponent component, Scope scope) { if (scope.Original != null) { ((PostProcessingComponent<ColorGradingModel>)(object)component).Init(((PostProcessingComponentBase)component).context, scope.Original); ActiveGamma = scope.PreviousGamma; } } public static void Invalidate(ColorGradingModel model) { foreach (Entry value in Entries.Values) { if (value.Source == model) { value.Invalid = true; } } } private static void Dispose(Entry entry) { RenderTexture bakedLut = entry.Model.bakedLut; if (Object.op_Implicit((Object)(object)bakedLut)) { if ((Object)(object)RenderTexture.active == (Object)(object)bakedLut) { RenderTexture.active = null; } bakedLut.Release(); if (Application.isPlaying) { Object.Destroy((Object)(object)bakedLut); } else { Object.DestroyImmediate((Object)(object)bakedLut); } } } public static void Release(ColorGradingComponent component) { if (Entries.TryGetValue(component, out var value)) { Dispose(value); Entries.Remove(component); } } internal static void ReleaseAll() { foreach (Entry value in Entries.Values) { Dispose(value); } Entries.Clear(); ActiveGamma = 1f; } } [HarmonyPatch(typeof(ColorGradingComponent), "Prepare")] internal static class PreparePatch { private static void Prefix(ColorGradingComponent __instance, out Grading.Scope __state) { __state = default(Grading.Scope); if (Plugin.Session != null && ((PostProcessingComponentBase)__instance).context != null && Object.op_Implicit((Object)(object)((PostProcessingComponentBase)__instance).context.camera) && Object.op_Implicit((Object)(object)((Component)((PostProcessingComponentBase)__instance).context.camera).GetComponent<CameraEffects>())) { __state = Grading.Begin(__instance, Plugin.Session.Current); } } private static void Finalizer(ColorGradingComponent __instance, Grading.Scope __state) { Grading.End(__instance, __state); } } [HarmonyPatch(typeof(ColorGradingComponent), "GetGammaValue")] internal static class GammaPatch { private static void Postfix(ref Vector3 __result) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) __result /= Grading.ActiveGamma; } } [HarmonyPatch(typeof(ColorGradingModel), "OnValidate")] internal static class ValidatePatch { private static void Postfix(ColorGradingModel __instance) { Grading.Invalidate(__instance); } } [HarmonyPatch(typeof(ColorGradingComponent), "OnDisable")] internal static class ReleasePatch { private static void Prefix(ColorGradingComponent __instance) { Grading.Release(__instance); } } public sealed class GraphicsPage : MonoBehaviour { private readonly List<GameObject> created = new List<GameObject>(); private readonly List<Slider> sliders = new List<Slider>(); private readonly List<TMP_Text> values = new List<TMP_Text>(); private List<Slider> navigationSliders; private Button reset; private Selectable beforeControls; private Selectable afterControls; private readonly List<Button> actions = new List<Button>(); private TMP_Text status; private TMP_Text dofStatus; private Toggle accessibilityDof; private float nextDofStatus; private bool updating; private ContentSizeFitter listFitter; private bool ownsListFitter; private bool previousFitterEnabled; private FitMode previousVerticalFit; private static readonly string[] Titles = new string[14] { "Gamma", "Exposure", "Contrast", "Saturation", "Warmth", "Tint", "DOF mode", "Focus distance", "Focus range", "Blur strength", "Foreground blur", "DOF quality", "Shadow detail", "Highlight detail" }; private static readonly int[] DisplayOrder = new int[14] { 0, 1, 2, 3, 4, 5, 12, 13, 6, 7, 8, 9, 10, 11 }; private static readonly string[] Hints = new string[14] { "Brighten shadows and midtones. Default: 1.00", "Overall brightness in stops. +1 doubles exposure. Default: 0.00 EV", "Difference between light and dark. Default: 100%", "Colour intensity. 0% is monochrome. Default: 100%", "Cool blue to warm yellow. 0 preserves the current environment colour balance.", "Green to magenta correction. 0 preserves the current environment tint.", "Game leaves depth of field unchanged. Automatic uses native autofocus. Manual uses a fixed distance. Enable Depth of Field in Settings > Accessibility first.", "Manual focus distance from the camera, in metres. Only used in Manual mode.", "Width of the focused region in the game's effect units, not metres. Wider keeps more scenery sharp.", "Maximum blur relative to the game's camera setting. 100% preserves its blur radius; capped for the beta.", "Game preserves the camera's foreground blur. Off keeps near scenery free of foreground blur.", "Game preserves quality. High resolution costs more GPU time. Rendering backend is unchanged.", "Lift dark tones with positive values; deepen them with negative values. 0 is unchanged. Does not recover clipped detail.", "Soften bright tones with positive values; brighten them with negative values. 0 is unchanged. Does not recover clipped detail." }; public static GraphicsPage Attach(GraphicsSettings tab, GameObject template, Button buttonTemplate, List<Slider> nativeSliders) { GraphicsPage component = ((Component)tab).GetComponent<GraphicsPage>(); if (Object.op_Implicit((Object)(object)component)) { return component; } GraphicsPage graphicsPage = ((Component)tab).gameObject.AddComponent<GraphicsPage>(); try { graphicsPage.Build(template, buttonTemplate, nativeSliders); return graphicsPage; } catch { graphicsPage.Cleanup(); Object.Destroy((Object)(object)graphicsPage); throw; } } private GameObject Clone(GameObject template, Transform parent, int index, string name) { GameObject val = Object.Instantiate<GameObject>(template, parent, false); created.Add(val); ((Object)val).name = name; val.SetActive(false); val.transform.SetSiblingIndex(index); return val; } private void Build(GameObject template, Button buttonTemplate, List<Slider> nativeSliders) { //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_014d: Expected O, but got Unknown //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Expected O, but got Unknown //IL_042e: Unknown result type (might be due to invalid IL or missing references) //IL_0438: Expected O, but got Unknown //IL_02cc: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: Expected O, but got Unknown //IL_02ff: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0310: Unknown result type (might be due to invalid IL or missing references) //IL_04e3: Unknown result type (might be due to invalid IL or missing references) //IL_04ea: Expected O, but got Unknown //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_04f3: Unknown result type (might be due to invalid IL or missing references) //IL_04f4: Unknown result type (might be due to invalid IL or missing references) //IL_04fb: Unknown result type (might be due to invalid IL or missing references) //IL_050e: Unknown result type (might be due to invalid IL or missing references) //IL_052a: Unknown result type (might be due to invalid IL or missing references) //IL_0534: Expected O, but got Unknown //IL_05e3: Unknown result type (might be due to invalid IL or missing references) //IL_05ed: Expected O, but got Unknown if (!Object.op_Implicit((Object)(object)template) || !Object.op_Implicit((Object)(object)buttonTemplate) || nativeSliders == null) { throw new InvalidOperationException("Lumaheim: native graphics templates unavailable."); } navigationSliders = nativeSliders; Plugin.Session.Begin(); Transform parent = template.transform.parent; int num = template.transform.GetSiblingIndex() + 1; listFitter = ((Component)parent).GetComponent<ContentSizeFitter>(); ownsListFitter = !Object.op_Implicit((Object)(object)listFitter); if (ownsListFitter) { listFitter = ((Component)parent).gameObject.AddComponent<ContentSizeFitter>(); } previousVerticalFit = listFitter.verticalFit; previousFitterEnabled = ((Behaviour)listFitter).enabled; listFitter.verticalFit = (FitMode)2; ((Behaviour)listFitter).enabled = true; TMP_Text component = ((Component)template.transform.Find("Label")).GetComponent<TMP_Text>(); AddText(component, parent, num++, "Lumaheim", 26f, component.fontSize + 2f); AddText(component, parent, num++, "Tune your view. Preview live; OK saves, Back restores.", 22f, component.fontSize); AddText(component, parent, num++, "Share settings", 26f, component.fontSize); AddAction(buttonTemplate, parent, num++, "Copy settings code", new UnityAction(CopyCode)); AddAction(buttonTemplate, parent, num++, "Paste settings code", new UnityAction(PasteCode)); AddText(component, parent, num++, "Clipboard status", 60f, component.fontSize); status = created[created.Count - 1].GetComponent<TMP_Text>(); status.text = "Copy your current settings to share. Copy a received code, then choose Paste settings code here."; float[] array = new float[14] { 50f, -200f, 50f, 0f, -100f, -100f, 0f, 1f, 1f, 10f, 0f, 0f, -100f, -100f }; float[] array2 = new float[14] { 250f, 200f, 150f, 200f, 100f, 100f, 2f, 1000f, 200f, 400f, 2f, 4f, 100f, 100f }; for (int i = 0; i < Titles.Length; i++) { sliders.Add(null); values.Add(null); } int[] displayOrder = DisplayOrder; foreach (int num2 in displayOrder) { if (num2 == 6) { AddText(component, parent, num++, "Depth of field", 26f, component.fontSize); AddText(component, parent, num++, "DOF status", 66f, component.fontSize); dofStatus = created[created.Count - 1].GetComponent<TMP_Text>(); } int setting = num2; GameObject val = Clone(template, parent, num++, "Lumaheim." + Titles[num2]); Slider component2 = val.GetComponent<Slider>(); component2.onValueChanged = new SliderEvent(); component2.wholeNumbers = true; component2.minValue = array[num2]; component2.maxValue = array2[num2]; ((Selectable)component2).interactable = true; Navigation navigation = ((Selectable)component2).navigation; ((Navigation)(ref navigation)).mode = (Mode)4; ((Selectable)component2).navigation = navigation; ((Component)val.transform.Find("Label")).GetComponent<TMP_Text>().text = Titles[num2]; Transform val2 = val.transform.Find("Info"); TMP_Text component3 = ((Component)val2.Find("Value")).GetComponent<TMP_Text>(); ((Component)val2.Find("Warning")).gameObject.SetActive(false); SettingsTooltip[] componentsInChildren = val.GetComponentsInChildren<SettingsTooltip>(true); foreach (SettingsTooltip val3 in componentsInChildren) { val3.SetTexts(Titles[num2], Hints[num2]); } sliders[num2] = component2; values[num2] = component3; ((UnityEvent<float>)(object)component2.onValueChanged).AddListener((UnityAction<float>)delegate { if (!updating) { Changed(setting); } }); val.SetActive(true); } GameObject val4 = Clone(((Component)buttonTemplate).gameObject, parent, num++, "Lumaheim.Reset"); reset = val4.GetComponent<Button>(); reset.onClick = new ButtonClickedEvent(); ((Selectable)reset).interactable = true; TMP_Text[] componentsInChildren2 = val4.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val5 in componentsInChildren2) { val5.text = "Reset Lumaheim"; } SettingsTooltip[] componentsInChildren3 = val4.GetComponentsInChildren<SettingsTooltip>(true); foreach (SettingsTooltip val6 in componentsInChildren3) { val6.SetTexts("Reset Lumaheim", "Restore neutral colour settings and Game depth of field. OK saves; Back cancels."); } LayoutElement val7 = val4.GetComponent<LayoutElement>(); if (!Object.op_Implicit((Object)(object)val7)) { val7 = val4.AddComponent<LayoutElement>(); } val7.minHeight = 36f; val7.preferredHeight = 36f; RectTransform val8 = (RectTransform)val4.transform; Vector2 anchorMin = (val8.anchorMax = Vector2.zero); val8.anchorMin = anchorMin; val8.sizeDelta = new Vector2(300f, 36f); ((UnityEvent)reset.onClick).AddListener(new UnityAction(ResetValues)); val4.SetActive(true); actions.Add(reset); List<Slider> list = new List<Slider>(); int[] displayOrder2 = DisplayOrder; foreach (int index in displayOrder2) { list.Add(sliders[index]); } nativeSliders.InsertRange(0, list); Settings componentInParent = ((Component)this).GetComponentInParent<Settings>(); if (Object.op_Implicit((Object)(object)componentInParent)) { AccessibilitySettings componentInChildren = ((Component)componentInParent).GetComponentInChildren<AccessibilitySettings>(true); if (Object.op_Implicit((Object)(object)componentInChildren)) { ref Toggle reference = ref accessibilityDof; object? value = AccessTools.Field(typeof(AccessibilitySettings), "m_depthOfFieldToggle").GetValue(componentInChildren); reference = (Toggle)((value is Toggle) ? value : null); } } Refresh(); LayoutRebuilder.MarkLayoutForRebuild((RectTransform)parent); } private void AddText(TMP_Text template, Transform parent, int index, string text, float height, float size) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Expected O, but got Unknown //IL_0086: 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_008c: Unknown result type (might be due to invalid IL or missing references) //IL_0093: 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_00b7: Unknown result type (might be due to invalid IL or missing references) GameObject val = Clone(((Component)template).gameObject, parent, index, "Lumaheim." + text.Split(new char[1] { ' ' })[0]); TMP_Text component = val.GetComponent<TMP_Text>(); component.text = text; component.fontSize = size; component.enableAutoSizing = false; component.alignment = (TextAlignmentOptions)4097; ((Graphic)component).raycastTarget = false; ContentSizeFitter component2 = val.GetComponent<ContentSizeFitter>(); if (Object.op_Implicit((Object)(object)component2)) { ((Behaviour)component2).enabled = false; } RectTransform val2 = (RectTransform)val.transform; Vector2 anchorMin = (val2.anchorMax = Vector2.zero); val2.anchorMin = anchorMin; val2.pivot = new Vector2(0f, 0.5f); val2.sizeDelta = new Vector2(540f, height); LayoutElement val3 = val.GetComponent<LayoutElement>(); if (!Object.op_Implicit((Object)(object)val3)) { val3 = val.AddComponent<LayoutElement>(); } val3.minHeight = height; val3.preferredHeight = height; val.SetActive(true); } private void AddAction(Button template, Transform parent, int index, string title, UnityAction action) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Expected O, but got Unknown //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cb: Unknown result type (might be due to invalid IL or missing references) GameObject val = Clone(((Component)template).gameObject, parent, index, "Lumaheim." + title); Button component = val.GetComponent<Button>(); component.onClick = new ButtonClickedEvent(); ((UnityEvent)component.onClick).AddListener(action); ((Selectable)component).interactable = true; TMP_Text[] componentsInChildren = val.GetComponentsInChildren<TMP_Text>(true); foreach (TMP_Text val2 in componentsInChildren) { val2.text = title; } SettingsTooltip[] componentsInChildren2 = val.GetComponentsInChildren<SettingsTooltip>(true); foreach (SettingsTooltip val3 in componentsInChildren2) { val3.SetTexts(title, "Share visual settings using your clipboard. Pasted values preview only; OK saves, Back restores."); } RectTransform val4 = (RectTransform)val.transform; Vector2 anchorMin = (val4.anchorMax = Vector2.zero); val4.anchorMin = anchorMin; val4.sizeDelta = new Vector2(300f, 36f); LayoutElement val5 = val.GetComponent<LayoutElement>(); if (!Object.op_Implicit((Object)(object)val5)) { val5 = val.AddComponent<LayoutElement>(); } LayoutElement obj = val5; float minHeight = (val5.preferredHeight = 36f); obj.minHeight = minHeight; actions.Add(component); val.SetActive(true); } public void CopyCode() { try { GUIUtility.systemCopyBuffer = SettingsCode.Encode(Plugin.Session.Current); status.text = "Settings code copied. Paste it into your forum post."; } catch (Exception e) { status.text = "Clipboard unavailable. Your settings are unchanged."; Plugin.Report(e); } } public void PasteCode() { try { if (!SettingsCode.TryDecode(GUIUtility.systemCopyBuffer, out var videoValues)) { status.text = "Invalid or unsupported Lumaheim code. Nothing changed."; return; } Plugin.Session.Preview(videoValues); Refresh(); status.text = "Code previewed. OK saves; Back restores. Native DOF toggle unchanged."; } catch (Exception e) { status.text = "Clipboard unavailable. Your settings are unchanged."; Plugin.Report(e); } } private static float Scale(int i) { return (i >= 4 && i != 8 && i != 9) ? 1 : 100; } private void Changed(int setting) { float[] array = Plugin.Session.Current.ToArray(); array[setting] = sliders[setting].value / Scale(setting); Plugin.Session.Preview(VideoValues.FromArray(array)); Refresh(); } public void ResetValues() { Plugin.Session.Preview(VideoValues.Default); Refresh(); } private void Refresh() { updating = true; VideoValues current = Plugin.Session.Current; float[] array = current.ToArray(); for (int i = 0; i < sliders.Count; i++) { sliders[i].SetValueWithoutNotify(array[i] * Scale(i)); if (i == 6) { values[i].text = (new string[3] { "Game", "Automatic", "Manual" })[current.DofMode]; } else if (i == 10) { values[i].text = (new string[3] { "Game", "Off", "On" })[current.Foreground]; } else if (i == 11) { values[i].text = (new string[5] { "Game", "Low", "Medium", "High", "High res" })[current.Quality]; } else if (i == 7) { values[i].text = array[i].ToString("0", CultureInfo.InvariantCulture) + " m"; } else if (i == 0 || i == 8) { values[i].text = array[i].ToString("0.00", CultureInfo.InvariantCulture); } else if (i == 1) { values[i].text = array[i].ToString("+0.00;-0.00;0.00", CultureInfo.InvariantCulture) + " EV"; } else if (i == 4 || i == 5 || i >= 12) { values[i].text = array[i].ToString("+0;-0;0", CultureInfo.InvariantCulture); } else { values[i].text = (array[i] * 100f).ToString("0", CultureInfo.InvariantCulture) + "%"; } } updating = false; RefreshDofStatus(); } internal void BindAccessibility(Toggle toggle) { accessibilityDof = toggle; RefreshDofStatus(); } private void OnEnable() { RefreshDofStatus(); } private void Update() { if (!(Time.unscaledTime < nextDofStatus)) { nextDofStatus = Time.unscaledTime + 0.2f; RefreshDofStatus(); } } private void RefreshDofStatus() { if (Object.op_Implicit((Object)(object)dofStatus) && Plugin.Session != null) { GameCamera instance = GameCamera.instance; DepthOfField val = (Object.op_Implicit((Object)(object)instance) ? ((Component)instance).GetComponent<DepthOfField>() : null); VideoValues current = Plugin.Session.Current; bool flag = Object.op_Implicit((Object)(object)accessibilityDof) && Plugin.Session.IsOpen; bool flag2 = (flag ? accessibilityDof.isOn : (Object.op_Implicit((Object)(object)val) && ((Behaviour)val).isActiveAndEnabled)); bool flag3 = Object.op_Implicit((Object)(object)val) && ((Component)val).gameObject.activeInHierarchy && flag2 && SystemInfo.SupportsRenderTextureFormat((RenderTextureFormat)1); for (int i = 6; i < 12; i++) { ((Selectable)sliders[i]).interactable = flag3 && (i == 6 || (current.DofMode != 0 && (i != 7 || current.DofMode == 2))); } RebuildNavigation(); if (!Object.op_Implicit((Object)(object)val)) { dofStatus.text = "Enter a world to adjust gameplay depth of field.\nIts on/off toggle is in Settings > Accessibility."; } else if (!flag3) { dofStatus.text = "Depth of Field is OFF or unavailable in Valheim.\nEnable Depth of Field in Settings > Accessibility. Saved slider values are retained."; } else if (flag && !((Behaviour)val).isActiveAndEnabled) { dofStatus.text = "Depth of Field is ON in Accessibility.\nClick OK to apply the native effect; adjustments are retained."; } else if (current.DofMode == 0) { dofStatus.text = "Game mode: custom DOF adjustments are inactive.\nSelect Automatic or Manual to preview the settings below."; } else if (current.DofMode == 1) { dofStatus.text = "DOF active: Automatic focus. Native transition speed.\nFocus distance below is used only in Manual mode."; } else { dofStatus.text = "DOF active: Manual focus at " + current.FocusDistance.ToString("0", CultureInfo.InvariantCulture) + " m.\nBlur is visible on scenery outside the focused region."; } } } public void ConnectReset() { //IL_002e: 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) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) if (Object.op_Implicit((Object)(object)reset) && sliders.Count == Titles.Length) { Navigation navigation = ((Selectable)sliders[0]).navigation; Selectable selectOnUp = ((Navigation)(ref navigation)).selectOnUp; Navigation navigation2 = ((Selectable)sliders[11]).navigation; Selectable selectOnDown = ((Navigation)(ref navigation2)).selectOnDown; if (!IsOwnControl(selectOnUp)) { beforeControls = selectOnUp; } if (!IsOwnControl(selectOnDown)) { afterControls = selectOnDown; } RebuildNavigation(); } } private bool IsOwnControl(Selectable control) { if (Object.op_Implicit((Object)(object)control)) { if (!sliders.Contains((Slider)(object)((control is Slider) ? control : null))) { return actions.Contains((Button)(object)((control is Button) ? control : null)); } return true; } return false; } private void RebuildNavigation() { //IL_00b5: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_0147: Unknown result type (might be due to invalid IL or missing references) //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_017c: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_0196: Unknown result type (might be due to invalid IL or missing references) //IL_011d: Unknown result type (might be due to invalid IL or missing references) if (!Object.op_Implicit((Object)(object)reset)) { return; } List<Selectable> list = new List<Selectable>(); foreach (Button action in actions) { if ((Object)(object)action != (Object)(object)reset) { list.Add((Selectable)(object)action); } } int[] displayOrder = DisplayOrder; foreach (int index in displayOrder) { if (((Selectable)sliders[index]).interactable) { list.Add((Selectable)(object)sliders[index]); } } list.Add((Selectable)(object)reset); for (int j = 0; j < list.Count; j++) { Navigation navigation = list[j].navigation; ((Navigation)(ref navigation)).mode = (Mode)4; ((Navigation)(ref navigation)).selectOnUp = ((j == 0) ? beforeControls : list[j - 1]); ((Navigation)(ref navigation)).selectOnDown = ((j == list.Count - 1) ? afterControls : list[j + 1]); Selectable selectOnLeft = (((Navigation)(ref navigation)).selectOnRight = null); ((Navigation)(ref navigation)).selectOnLeft = selectOnLeft; list[j].navigation = navigation; } if (Object.op_Implicit((Object)(object)beforeControls)) { Navigation navigation2 = beforeControls.navigation; ((Navigation)(ref navigation2)).selectOnDown = list[0]; beforeControls.navigation = navigation2; } if (Object.op_Implicit((Object)(object)afterControls)) { Navigation navigation3 = afterControls.navigation; ((Navigation)(ref navigation3)).selectOnUp = (Selectable)(object)reset; afterControls.navigation = navigation3; } EventSystem current2 = EventSystem.current; if (Object.op_Implicit((Object)(object)current2) && Object.op_Implicit((Object)(object)current2.currentSelectedGameObject)) { Slider component = current2.currentSelectedGameObject.GetComponent<Slider>(); if (Object.op_Implicit((Object)(object)component) && sliders.Contains(component) && !((Selectable)component).interactable) { current2.SetSelectedGameObject(((Component)reset).gameObject); } } } private void Cleanup() { //IL_00bd: Unknown result type (might be due to invalid IL or missing references) if (navigationSliders != null) { foreach (Slider slider in sliders) { navigationSliders.Remove(slider); } } foreach (GameObject item in created) { if (Object.op_Implicit((Object)(object)item)) { item.SetActive(false); Object.Destroy((Object)(object)item); } } created.Clear(); sliders.Clear(); values.Clear(); if (Object.op_Implicit((Object)(object)listFitter)) { listFitter.verticalFit = previousVerticalFit; ((Behaviour)listFitter).enabled = previousFitterEnabled; if (ownsListFitter) { Object.Destroy((Object)(object)listFitter); } } } private void OnDestroy() { Cleanup(); } } [HarmonyPatch(typeof(AccessibilitySettings), "Initialize")] internal static class AccessibilityInitializePatch { internal static void Notify(AccessibilitySettings source, Toggle toggle) { Settings componentInParent = ((Component)source).GetComponentInParent<Settings>(); Transform val = (Object.op_Implicit((Object)(object)componentInParent) ? ((Component)componentInParent).transform : ((Component)source).transform.root); GraphicsPage[] componentsInChildren = ((Component)val).GetComponentsInChildren<GraphicsPage>(true); foreach (GraphicsPage graphicsPage in componentsInChildren) { graphicsPage.BindAccessibility(toggle); } } private static void Postfix(AccessibilitySettings __instance, Toggle ___m_depthOfFieldToggle) { Notify(__instance, ___m_depthOfFieldToggle); } } [HarmonyPatch(typeof(AccessibilitySettings), "OnDepthOfFieldChanged")] internal static class AccessibilityDofChangedPatch { private static void Postfix(AccessibilitySettings __instance, Toggle ___m_depthOfFieldToggle) { AccessibilityInitializePatch.Notify(__instance, ___m_depthOfFieldToggle); } } [HarmonyPatch(typeof(GraphicsSettings), "Initialize")] internal static class PagePatch { private static void Postfix(GraphicsSettings __instance, GameObject ___m_qualitySliderPrefab, GuiButton ___m_testResolutionButton, List<Slider> ___m_dynamicQualitySliders) { try { GraphicsPage.Attach(__instance, ___m_qualitySliderPrefab, (Button)(object)___m_testResolutionButton, ___m_dynamicQualitySliders); } catch (Exception e) { Plugin.Report(e); } } } [HarmonyPatch(typeof(GraphicsSettings), "UpdateNavigation")] internal static class NavigationPatch { private static void Postfix(GraphicsSettings __instance) { GraphicsPage component = ((Component)__instance).GetComponent<GraphicsPage>(); if (Object.op_Implicit((Object)(object)component)) { component.ConnectReset(); } } } [BepInPlugin("com.gomisan.lumaheim", "Lumaheim", "0.2.0")] [BepInProcess("valheim.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Id = "com.gomisan.lumaheim"; public const string Version = "0.2.0"; internal static Plugin Instance; public static VideoSession Session; private ConfigEntry<float> gamma; private ConfigEntry<float> exposure; private ConfigEntry<float> contrast; private ConfigEntry<float> saturation; private Harmony harmony; private ConfigEntry<float>[] advanced; private void Awake() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_01dd: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: Expected O, but got Unknown if ((int)SystemInfo.graphicsDeviceType == 4) { return; } Instance = this; ((BaseUnityPlugin)this).Config.SaveOnConfigSet = false; gamma = Bind("Gamma", 1f, 0.5f, 2.5f, "Midtone brightness. Higher values brighten shadows and midtones. 1 is unchanged."); exposure = Bind("Exposure", 0f, -2f, 2f, "Exposure compensation in stops. +1 doubles exposure; 0 is unchanged."); contrast = Bind("Contrast", 1f, 0.5f, 1.5f, "Contrast multiplier. 1 preserves the game's contrast."); saturation = Bind("Saturation", 1f, 0f, 2f, "Colour intensity multiplier. 0 is monochrome; 1 preserves the game."); float[] array = VideoValues.Default.ToArray(); string[] array2 = new string[10] { "Warmth", "Tint", "DofMode", "FocusDistance", "FocusRange", "BlurStrength", "Foreground", "Quality", "ShadowDetail", "HighlightDetail" }; advanced = new ConfigEntry<float>[array2.Length]; float[] array3 = VideoValues.Default.ToArray(); array3[0] = gamma.Value; array3[1] = exposure.Value; array3[2] = contrast.Value; array3[3] = saturation.Value; for (int i = 0; i < array2.Length; i++) { advanced[i] = Bind(array2[i], array[i + 4], VideoValues.Minimum[i + 4], VideoValues.Maximum[i + 4], "Beta visual setting. DOF mode: 0=Game, 1=Automatic, 2=Manual. Native DOF toggle remains authoritative."); array3[i + 4] = advanced[i].Value; } Session = new VideoSession(VideoValues.FromArray(array3)); harmony = new Harmony("com.gomisan.lumaheim"); try { harmony.PatchAll(typeof(Plugin).Assembly); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Lumaheim 0.2.0: native Graphics controls ready."); } catch (Exception ex) { harmony.UnpatchSelf(); ((BaseUnityPlugin)this).Logger.LogError((object)("Lumaheim could not attach to this Valheim version: " + ex)); } } private ConfigEntry<float> Bind(string name, float value, float min, float max, string description) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected O, but got Unknown return ((BaseUnityPlugin)this).Config.Bind<float>("Video", name, value, new ConfigDescription(description, (AcceptableValueBase)(object)new AcceptableValueRange<float>(min, max), new object[0])); } internal static void Save() { if (Session == null || !Session.IsOpen) { return; } VideoValues current = Session.Current; if (Object.op_Implicit((Object)(object)Instance)) { try { Instance.gamma.Value = current.Gamma; Instance.exposure.Value = current.Exposure; Instance.contrast.Value = current.Contrast; Instance.saturation.Value = current.Saturation; float[] array = current.ToArray(); for (int i = 0; i < Instance.advanced.Length; i++) { Instance.advanced[i].Value = array[i + 4]; } ((BaseUnityPlugin)Instance).Config.Save(); } catch (Exception ex) { ((BaseUnityPlugin)Instance).Logger.LogError((object)("Could not save Lumaheim settings: " + ex)); } } Session.Commit(); } internal static void Report(Exception e) { if (Object.op_Implicit((Object)(object)Instance)) { ((BaseUnityPlugin)Instance).Logger.LogError((object)e); } } private void OnDestroy() { if (harmony != null) { harmony.UnpatchSelf(); } Grading.ReleaseAll(); if (Session != null) { Session.Cancel(); } Instance = null; } } [HarmonyPatch(typeof(Settings), "ApplyAndClose")] internal static class SavePatch { private static void Prefix() { Plugin.Save(); } } [HarmonyPatch(typeof(Settings), "OnBack")] internal static class CancelPatch { private static void Prefix() { if (Plugin.Session != null) { Plugin.Session.Cancel(); } } } [HarmonyPatch(typeof(Settings), "OnDestroy")] internal static class ClosePatch { private static void Prefix() { if (Plugin.Session != null) { Plugin.Session.Cancel(); } } } public struct VideoValues { public float Gamma; public float Exposure; public float Contrast; public float Saturation; public float Warmth; public float Tint; public float ShadowDetail; public float HighlightDetail; public int DofMode; public int Foreground; public int Quality; public float FocusDistance; public float FocusRange; public float BlurStrength; public static readonly float[] Minimum = new float[14] { 0.5f, -2f, 0.5f, 0f, -100f, -100f, 0f, 1f, 0.01f, 0.1f, 0f, 0f, -100f, -100f }; public static readonly float[] Maximum = new float[14] { 2.5f, 2f, 1.5f, 2f, 100f, 100f, 2f, 1000f, 2f, 4f, 2f, 4f, 100f, 100f }; public static VideoValues Default => new VideoValues { Gamma = 1f, Contrast = 1f, Saturation = 1f, FocusDistance = 50f, FocusRange = 0.05f, BlurStrength = 1f }; public bool IsColorDefault { get { if (Gamma == 1f && Exposure == 0f && Contrast == 1f && Saturation == 1f && Warmth == 0f && Tint == 0f && ShadowDetail == 0f) { return HighlightDetail == 0f; } return false; } } public bool IsDefault { get { if (IsColorDefault) { return DofMode == 0; } return false; } } public float[] ToArray() { return new float[14] { Gamma, Exposure, Contrast, Saturation, Warmth, Tint, DofMode, FocusDistance, FocusRange, BlurStrength, Foreground, Quality, ShadowDetail, HighlightDetail }; } public static VideoValues FromArray(float[] a) { return new VideoValues { Gamma = a[0], Exposure = a[1], Contrast = a[2], Saturation = a[3], Warmth = a[4], Tint = a[5], DofMode = (int)a[6], FocusDistance = a[7], FocusRange = a[8], BlurStrength = a[9], Foreground = (int)a[10], Quality = (int)a[11], ShadowDetail = ((a.Length > 12) ? a[12] : 0f), HighlightDetail = ((a.Length > 13) ? a[13] : 0f) }; } public static float Clamp(float value, float min, float max, float fallback) { if (!float.IsNaN(value) && !float.IsInfinity(value)) { return Math.Max(min, Math.Min(max, value)); } return fallback; } public VideoValues Sanitize() { float[] array = ToArray(); float[] array2 = Default.ToArray(); for (int i = 0; i < array.Length; i++) { array[i] = Clamp(array[i], Minimum[i], Maximum[i], array2[i]); } return FromArray(array); } } public static class SettingsCode { public static string Encode(VideoValues values) { float[] array = values.Sanitize().ToArray(); string[] array2 = new string[array.Length]; for (int i = 0; i < array.Length; i++) { array2[i] = array[i].ToString("R", CultureInfo.InvariantCulture); } return "LUMA2:" + string.Join(";", array2); } public static bool TryDecode(string code, out VideoValues values) { values = VideoValues.Default; if (code == null || code.Length > 512) { return false; } code = code.Trim(); bool flag = code.StartsWith("LUMA1:", StringComparison.Ordinal); if (!flag && !code.StartsWith("LUMA2:", StringComparison.Ordinal)) { return false; } string[] array = code.Substring(6).Split(new char[1] { ';' }); if (array.Length != (flag ? 12 : 14)) { return false; } float[] array2 = new float[array.Length]; for (int i = 0; i < array2.Length; i++) { if (!float.TryParse(array[i], NumberStyles.Float, CultureInfo.InvariantCulture, out array2[i]) || float.IsNaN(array2[i]) || float.IsInfinity(array2[i]) || array2[i] < VideoValues.Minimum[i] || array2[i] > VideoValues.Maximum[i]) { return false; } } int[] array3 = new int[3] { 6, 10, 11 }; foreach (int num in array3) { if (array2[num] != (float)(int)array2[num]) { return false; } } values = VideoValues.FromArray(array2); return true; } } public sealed class VideoSession { public VideoValues Saved { get; private set; } public VideoValues Current { get; private set; } public bool IsOpen { get; private set; } public VideoSession(VideoValues saved) { Saved = (Current = saved.Sanitize()); } public void Begin() { if (!IsOpen) { Current = Saved; IsOpen = true; } } public void Preview(VideoValues values) { if (IsOpen) { Current = values.Sanitize(); } } public void Commit() { if (IsOpen) { Saved = Current; IsOpen = false; } } public void Cancel() { Current = Saved; IsOpen = false; } }