Decompiled source of Valheim Universal Upscaler GUI v1.1.1

patchers\ValheimUpscalerPatcher.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using Mono.Cecil;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ValheimUpscalerPatcher;

public static class Patcher
{
	public static IEnumerable<string> TargetDLLs => new string[0];

	public static void Initialize()
	{
		try
		{
			DeployFiles();
		}
		catch (Exception ex)
		{
			Console.WriteLine("[ValheimUpscalerPatcher] Initialize error: " + ex);
		}
	}

	public static void Patch(AssemblyDefinition assembly)
	{
	}

	private static void DeployFiles()
	{
		string text = AppDomain.CurrentDomain.BaseDirectory;
		if (string.IsNullOrEmpty(text))
		{
			text = Directory.GetCurrentDirectory();
		}
		string path = Path.Combine(text, "version.dll");
		if (File.Exists(path))
		{
			try
			{
				File.Delete(path);
			}
			catch
			{
			}
		}
		string path2 = Path.Combine(text, "BepInEx");
		if (!Directory.Exists(path2))
		{
			string[] commandLineArgs = Environment.GetCommandLineArgs();
			for (int i = 0; i < commandLineArgs.Length; i++)
			{
				if (commandLineArgs[i] == "--doorstop-target-assembly" && i + 1 < commandLineArgs.Length)
				{
					string path3 = commandLineArgs[i + 1];
					path2 = Path.GetDirectoryName(Path.GetDirectoryName(path3));
					break;
				}
			}
		}
		string text2 = null;
		string[] array;
		if (Directory.Exists(path2))
		{
			string[] files = Directory.GetFiles(path2, "dxgi.dll", SearchOption.AllDirectories);
			array = files;
			foreach (string path4 in array)
			{
				string directoryName = Path.GetDirectoryName(path4);
				if (!directoryName.Equals(text, StringComparison.OrdinalIgnoreCase))
				{
					text2 = directoryName;
					break;
				}
			}
		}
		if (string.IsNullOrEmpty(text2) || !Directory.Exists(text2))
		{
			return;
		}
		string[] array2 = new string[9] { "dxgi.dll", "OptiScaler.ini", "amd_fidelityfx_dx12.dll", "amd_fidelityfx_framegeneration_dx12.dll", "amd_fidelityfx_upscaler_dx12.dll", "libxess.dll", "libxess_fg.dll", "fakenvapi.dll", "fakenvapi.ini" };
		array = array2;
		foreach (string text3 in array)
		{
			string text4 = Path.Combine(text2, text3);
			string text5 = Path.Combine(text, text3);
			if (!File.Exists(text4))
			{
				continue;
			}
			try
			{
				if (!File.Exists(text5))
				{
					File.Copy(text4, text5, overwrite: true);
					Console.WriteLine("[ValheimUpscalerPatcher] Auto-deployed: " + text3);
				}
			}
			catch (Exception ex)
			{
				Console.WriteLine("[ValheimUpscalerPatcher] Deploy error for " + text3 + ": " + ex.Message);
			}
		}
	}
}

plugins\ValheimUpscalerUI.dll

Decompiled 6 hours ago
using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.UI;
using Valheim.SettingsGui;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace ValheimUpscalerUI;

[BepInPlugin("com.valheim.upscalerui", "Valheim Upscaler Settings UI", "1.1.1")]
public class UpscalerUIPlugin : BaseUnityPlugin
{
	public static UpscalerUIPlugin Instance;

	public static ConfigEntry<int> QualityPresetConfig;

	public static ConfigEntry<int> BackendConfig;

	public static ConfigEntry<bool> FrameGenConfig;

	public static ConfigEntry<float> SharpnessConfig;

	public static ConfigEntry<KeyCode> MenuHotkeyConfig;

	private Harmony _harmony;

	private bool _showQuickMenu = false;

	private Rect _quickMenuRect = new Rect(40f, 40f, 420f, 440f);

	private void Awake()
	{
		//IL_00bc: Unknown result type (might be due to invalid IL or missing references)
		//IL_00c6: Expected O, but got Unknown
		Instance = this;
		QualityPresetConfig = ((BaseUnityPlugin)this).Config.Bind<int>("GraphicsSettings", "QualityPreset", 2, "0: Off, 1: Native (100%), 2: Quality (67%), 3: Balanced (58%), 4: Performance (50%), 5: Ultra Performance (33%)");
		BackendConfig = ((BaseUnityPlugin)this).Config.Bind<int>("GraphicsSettings", "Backend", 1, "0: FSR 3.1, 1: FSR 4 (RDNA4), 2: XeSS, 3: DLSS");
		FrameGenConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("GraphicsSettings", "FrameGeneration", false, "Frame Generation enabled");
		SharpnessConfig = ((BaseUnityPlugin)this).Config.Bind<float>("GraphicsSettings", "Sharpness", 0.5f, "Upscaler sharpness (0.0 to 1.0)");
		MenuHotkeyConfig = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Input", "MenuHotkey", (KeyCode)288, "Hotkey to toggle the quick Upscaler overlay menu");
		AutoDeployNativeFiles();
		_harmony = new Harmony("com.valheim.upscalerui");
		_harmony.PatchAll();
		Debug.Log((object)"[ValheimUpscalerUI] In-Game Upscaler UI Mod loaded successfully.");
	}

	private void AutoDeployNativeFiles()
	{
		try
		{
			string directoryName = Path.GetDirectoryName(Application.dataPath);
			if (string.IsNullOrEmpty(directoryName))
			{
				return;
			}
			string path = Path.Combine(directoryName, "version.dll");
			if (File.Exists(path))
			{
				try
				{
					File.Delete(path);
					Debug.Log((object)"[ValheimUpscalerUI] Removed conflicting version.dll to avoid Dx12 hook collision.");
				}
				catch
				{
				}
			}
			string directoryName2 = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location);
			if (string.IsNullOrEmpty(directoryName2) || !Directory.Exists(directoryName2))
			{
				return;
			}
			string[] array = new string[9] { "dxgi.dll", "OptiScaler.ini", "amd_fidelityfx_dx12.dll", "amd_fidelityfx_framegeneration_dx12.dll", "amd_fidelityfx_upscaler_dx12.dll", "libxess.dll", "libxess_fg.dll", "fakenvapi.dll", "fakenvapi.ini" };
			bool flag = false;
			string[] array2 = array;
			foreach (string text in array2)
			{
				string text2 = Path.Combine(directoryName2, text);
				if (!File.Exists(text2))
				{
					string text3 = Path.Combine(directoryName2, "native", text);
					string text4 = Path.Combine(directoryName2, "runtimes", text);
					if (File.Exists(text3))
					{
						text2 = text3;
					}
					else if (File.Exists(text4))
					{
						text2 = text4;
					}
				}
				if (!File.Exists(text2))
				{
					continue;
				}
				string text5 = Path.Combine(directoryName, text);
				if (!File.Exists(text5))
				{
					try
					{
						File.Copy(text2, text5, overwrite: true);
						flag = true;
						Debug.Log((object)("[ValheimUpscalerUI] Auto-deployed to game root: " + text));
					}
					catch (Exception ex)
					{
						Debug.LogWarning((object)("[ValheimUpscalerUI] Failed to auto-deploy " + text + ": " + ex.Message));
					}
				}
			}
			if (flag)
			{
				Debug.Log((object)"[ValheimUpscalerUI] All native upscaler runtimes successfully deployed automatically!");
			}
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[ValheimUpscalerUI] Error in AutoDeployNativeFiles: " + ex));
		}
	}

	private void Start()
	{
		ApplyAllSettings();
	}

	private void Update()
	{
		//IL_0006: Unknown result type (might be due to invalid IL or missing references)
		if (Input.GetKeyDown(MenuHotkeyConfig.Value))
		{
			_showQuickMenu = !_showQuickMenu;
			if (_showQuickMenu)
			{
				Cursor.lockState = (CursorLockMode)0;
				Cursor.visible = true;
			}
		}
	}

	private void OnGUI()
	{
		//IL_001b: Unknown result type (might be due to invalid IL or missing references)
		//IL_0027: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Expected O, but got Unknown
		//IL_0037: Unknown result type (might be due to invalid IL or missing references)
		//IL_003c: Unknown result type (might be due to invalid IL or missing references)
		if (_showQuickMenu)
		{
			GUI.skin = null;
			_quickMenuRect = GUILayout.Window(998822, _quickMenuRect, new WindowFunction(DrawQuickMenuWindow), "Настройки Valheim Upscaler (FSR / XeSS / DLSS)", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		}
	}

	private void DrawQuickMenuWindow(int windowId)
	{
		//IL_02ae: Unknown result type (might be due to invalid IL or missing references)
		GUILayout.BeginVertical((GUILayoutOption[])(object)new GUILayoutOption[0]);
		GUILayout.Label("Видеокарта: " + SystemInfo.graphicsDeviceName, (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.ExpandWidth(true) });
		GUILayout.Space(5f);
		GUILayout.Label("<b>Пресет масштабирования (Качество):</b>", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		string[] array = new string[6] { "Выкл", "Нативное (100%)", "Качество (67%)", "Баланс (58%)", "Производ. (50%)", "Ультра (33%)" };
		int value = QualityPresetConfig.Value;
		int num = GUILayout.SelectionGrid(value, array, 3, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (num != value)
		{
			ApplyQualityPreset(num);
		}
		GUILayout.Space(10f);
		GUILayout.Label("<b>Технология апскейла (Backend):</b>", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		string[] array2 = new string[4] { "AMD FSR 3.1", "AMD FSR 4 (FP8)", "Intel XeSS", "NVIDIA DLSS" };
		int value2 = BackendConfig.Value;
		int num2 = GUILayout.SelectionGrid(value2, array2, 2, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (num2 != value2)
		{
			ApplyBackend(num2);
		}
		GUILayout.Space(10f);
		bool value3 = FrameGenConfig.Value;
		bool flag = GUILayout.Toggle(value3, "  Генерация кадров (Frame Generation)", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (flag != value3)
		{
			ApplyFrameGen(flag);
		}
		GUILayout.Space(10f);
		GUILayout.Label("Резкость (Sharpness): " + (SharpnessConfig.Value * 100f).ToString("F0") + "%", (GUILayoutOption[])(object)new GUILayoutOption[0]);
		float num3 = GUILayout.HorizontalSlider(SharpnessConfig.Value, 0f, 1f, (GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (Math.Abs(num3 - SharpnessConfig.Value) > 0.02f)
		{
			ApplySharpness(num3);
		}
		GUILayout.Space(15f);
		GUILayout.BeginHorizontal((GUILayoutOption[])(object)new GUILayoutOption[0]);
		if (GUILayout.Button("Применить все", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			ApplyAllSettings();
		}
		if (GUILayout.Button("Закрыть (F7)", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(30f) }))
		{
			_showQuickMenu = false;
		}
		GUILayout.EndHorizontal();
		GUILayout.EndVertical();
		GUI.DragWindow(new Rect(0f, 0f, 10000f, 25f));
	}

	public static void ApplyQualityPreset(int presetIndex)
	{
		QualityPresetConfig.Value = presetIndex;
		try
		{
			Type type = AccessTools.TypeByName("ValheimUpscaler.Inject.InjectPlugin");
			Type type2 = AccessTools.TypeByName("ValheimUpscaler.Inject.InjectState");
			if (presetIndex == 0)
			{
				if (type2 != null)
				{
					MethodInfo methodInfo = AccessTools.Method(type2, "SetInjectionEnabled", new Type[2]
					{
						typeof(bool),
						typeof(string)
					}, (Type[])null);
					if (methodInfo != null)
					{
						methodInfo.Invoke(null, new object[2] { false, "in-game-ui" });
					}
				}
				if (type != null)
				{
					FieldInfo fieldInfo = AccessTools.Field(type, "ConfigCustomResolutionPreset");
					object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
					if (obj != null)
					{
						PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "Value");
						if (propertyInfo != null)
						{
							propertyInfo.SetValue(obj, false, null);
						}
					}
				}
				Debug.Log((object)"[ValheimUpscalerUI] Upscaler disabled (Native game rendering).");
				return;
			}
			if (type2 != null)
			{
				MethodInfo methodInfo = AccessTools.Method(type2, "SetInjectionEnabled", new Type[2]
				{
					typeof(bool),
					typeof(string)
				}, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(null, new object[2] { true, "in-game-ui" });
				}
			}
			if (type != null)
			{
				FieldInfo fieldInfo = AccessTools.Field(type, "ConfigCustomResolutionPreset");
				object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
				if (obj != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "Value");
					if (propertyInfo != null)
					{
						propertyInfo.SetValue(obj, true, null);
					}
				}
				FieldInfo fieldInfo2 = AccessTools.Field(type, "ConfigDLSSMode");
				object obj2 = ((fieldInfo2 != null) ? fieldInfo2.GetValue(null) : null);
				if (obj2 != null)
				{
					int value = 2;
					switch (presetIndex)
					{
					case 1:
						value = 0;
						break;
					case 2:
						value = 2;
						break;
					case 3:
						value = 3;
						break;
					case 4:
						value = 4;
						break;
					case 5:
						value = 5;
						break;
					}
					Type enumType = obj2.GetType().GetGenericArguments()[0];
					object value2 = Enum.ToObject(enumType, value);
					PropertyInfo propertyInfo = AccessTools.Property(obj2.GetType(), "Value");
					if (propertyInfo != null)
					{
						propertyInfo.SetValue(obj2, value2, null);
					}
				}
			}
			Debug.Log((object)("[ValheimUpscalerUI] Applied Quality Preset index: " + presetIndex));
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[ValheimUpscalerUI] Error applying quality preset: " + ex));
		}
	}

	public static void ApplyBackend(int backendIndex)
	{
		BackendConfig.Value = backendIndex;
		try
		{
			string text = "fsr31";
			switch (backendIndex)
			{
			case 1:
				text = "fsr4";
				break;
			case 2:
				text = "xess";
				break;
			case 3:
				text = "dlss";
				break;
			}
			Type type = AccessTools.TypeByName("ValheimUpscaler.Inject.BackendSelector");
			Type type2 = AccessTools.TypeByName("ValheimUpscaler.Inject.InjectPlugin");
			switch (backendIndex)
			{
			case 1:
			{
				if (!(type2 != null))
				{
					break;
				}
				FieldInfo fieldInfo = AccessTools.Field(type2, "ConfigBackend");
				object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
				if (obj != null)
				{
					Type enumType = obj.GetType().GetGenericArguments()[0];
					object value2 = Enum.ToObject(enumType, 2);
					PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "Value");
					if (propertyInfo != null)
					{
						propertyInfo.SetValue(obj, value2, null);
					}
				}
				break;
			}
			case 3:
			{
				if (!(type2 != null))
				{
					break;
				}
				FieldInfo fieldInfo = AccessTools.Field(type2, "ConfigBackend");
				object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
				if (obj != null)
				{
					Type enumType = obj.GetType().GetGenericArguments()[0];
					object value3 = Enum.ToObject(enumType, 1);
					PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "Value");
					if (propertyInfo != null)
					{
						propertyInfo.SetValue(obj, value3, null);
					}
				}
				break;
			}
			default:
			{
				if (!(type2 != null))
				{
					break;
				}
				FieldInfo fieldInfo = AccessTools.Field(type2, "ConfigBackend");
				object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
				if (obj != null)
				{
					Type enumType = obj.GetType().GetGenericArguments()[0];
					object value = Enum.ToObject(enumType, 0);
					PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "Value");
					if (propertyInfo != null)
					{
						propertyInfo.SetValue(obj, value, null);
					}
				}
				break;
			}
			}
			if (type != null)
			{
				PropertyInfo propertyInfo2 = AccessTools.Property(type, "SelectedBackend");
				if (propertyInfo2 != null)
				{
					propertyInfo2.SetValue(null, text, null);
				}
				MethodInfo methodInfo = AccessTools.Method(type, "Apply", new Type[0], (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(null, null);
				}
			}
			UpdateOptiScalerIniBackend(backendIndex, text);
			Debug.Log((object)("[ValheimUpscalerUI] Applied Backend: " + text + " (index " + backendIndex + ")"));
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[ValheimUpscalerUI] Error applying backend: " + ex));
		}
	}

	public static void ApplyFrameGen(bool enabled)
	{
		FrameGenConfig.Value = enabled;
		try
		{
			Type type = AccessTools.TypeByName("ValheimUpscaler.Inject.InjectPlugin");
			if (type != null)
			{
				FieldInfo fieldInfo = AccessTools.Field(type, "ConfigEnableFG");
				object obj = ((fieldInfo != null) ? fieldInfo.GetValue(null) : null);
				if (obj != null)
				{
					PropertyInfo propertyInfo = AccessTools.Property(obj.GetType(), "Value");
					if (propertyInfo != null)
					{
						propertyInfo.SetValue(obj, enabled, null);
					}
				}
			}
			UpdateIniKey("[FrameGen]", "Enabled", enabled ? "true" : "false");
			Debug.Log((object)("[ValheimUpscalerUI] Applied Frame Generation: " + enabled));
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[ValheimUpscalerUI] Error applying frame generation: " + ex));
		}
	}

	public static void ApplySharpness(float sharpness)
	{
		SharpnessConfig.Value = Mathf.Clamp01(sharpness);
		try
		{
			Type type = AccessTools.TypeByName("ValheimUpscaler.Inject.UpscalerNative");
			if (type != null)
			{
				MethodInfo methodInfo = AccessTools.Method(type, "SetSharpness", new Type[1] { typeof(float) }, (Type[])null);
				if (methodInfo != null)
				{
					methodInfo.Invoke(null, new object[1] { SharpnessConfig.Value });
				}
			}
			UpdateIniKey("[Sharpness]", "Sharpness", SharpnessConfig.Value.ToString("F2", CultureInfo.InvariantCulture));
			UpdateIniKey("[Sharpness]", "OverrideSharpness", "true");
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[ValheimUpscalerUI] Error applying sharpness: " + ex));
		}
	}

	public static void ApplyAllSettings()
	{
		ApplyBackend(BackendConfig.Value);
		ApplyQualityPreset(QualityPresetConfig.Value);
		ApplyFrameGen(FrameGenConfig.Value);
		ApplySharpness(SharpnessConfig.Value);
	}

	private static void UpdateOptiScalerIniBackend(int backendIndex, string backendCode)
	{
		string newValue = backendCode;
		switch (backendIndex)
		{
		case 1:
			newValue = "fsr31";
			UpdateIniKey("[FSR]", "UpscalerIndex", "0");
			break;
		case 0:
			newValue = "fsr31";
			UpdateIniKey("[FSR]", "UpscalerIndex", "1");
			break;
		}
		UpdateIniKey("[Upscalers]", "Dx12Upscaler", newValue);
	}

	private static void UpdateIniKey(string targetSection, string targetKey, string newValue)
	{
		List<string> list = new List<string>();
		string directoryName = Path.GetDirectoryName(Application.dataPath);
		list.Add(Path.Combine(directoryName, "OptiScaler.ini"));
		string folderPath = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData);
		string item = Path.Combine(folderPath, "r2modmanPlus-local\\Valheim\\profiles\\Default\\OptiScaler.ini");
		list.Add(item);
		foreach (string item2 in list)
		{
			try
			{
				if (!File.Exists(item2))
				{
					continue;
				}
				string[] array = File.ReadAllLines(item2);
				bool flag = false;
				bool flag2 = false;
				for (int i = 0; i < array.Length; i++)
				{
					string text = array[i].Trim();
					if (text.StartsWith("[") && text.EndsWith("]"))
					{
						flag = text.Equals(targetSection, StringComparison.OrdinalIgnoreCase);
					}
					else if (flag && text.StartsWith(targetKey + "=", StringComparison.OrdinalIgnoreCase))
					{
						array[i] = targetKey + "=" + newValue;
						flag2 = true;
						break;
					}
				}
				if (flag2)
				{
					File.WriteAllLines(item2, array);
				}
			}
			catch
			{
			}
		}
	}
}
[HarmonyPatch(typeof(GraphicsSettings), "InitializeUI")]
public static class GraphicsSettings_InitializeUI_Patch
{
	public static GameObject CustomPresetRow;

	public static GameObject CustomBackendRow;

	public static GameObject CustomFgRow;

	public static GameObject CustomSharpnessRow;

	public static TMP_Dropdown PresetDropdown;

	public static TMP_Dropdown BackendDropdown;

	public static Toggle FgToggle;

	public static Slider SharpnessSlider;

	public static TMP_Text SharpnessValueText;

	public static void Postfix(GraphicsSettings __instance)
	{
		//IL_061f: Unknown result type (might be due to invalid IL or missing references)
		//IL_0624: Unknown result type (might be due to invalid IL or missing references)
		try
		{
			if ((Object)(object)CustomPresetRow != (Object)null && (Object)(object)CustomPresetRow.gameObject != (Object)null)
			{
				return;
			}
			FieldInfo fieldInfo = AccessTools.Field(typeof(GraphicsSettings), "m_resolutionRoot");
			GameObject val = (GameObject)((fieldInfo != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val == (Object)null)
			{
				return;
			}
			Transform parent = val.transform.parent;
			if ((Object)(object)parent == (Object)null)
			{
				return;
			}
			int num = val.transform.GetSiblingIndex() + 1;
			CustomPresetRow = Object.Instantiate<GameObject>(val, parent);
			((Object)CustomPresetRow).name = "UpscalerPresetRow";
			CustomPresetRow.SetActive(true);
			CustomPresetRow.transform.SetSiblingIndex(num);
			PresetDropdown = PrepareRowDropdown(CustomPresetRow, "Масштабирование (Разрешение)", new List<string> { "Масштаб: Выключено (100% Native)", "Масштаб: Нативное (DLAA / FSR Native)", "Масштаб: Качество (Quality - 67%)", "Масштаб: Баланс (Balanced - 58%)", "Масштаб: Быстродействие (Performance - 50%)", "Масштаб: Ультра быстродействие (33%)" }, UpscalerUIPlugin.QualityPresetConfig.Value, delegate(int presetIndex)
			{
				UpscalerUIPlugin.ApplyQualityPreset(presetIndex);
			});
			CustomBackendRow = Object.Instantiate<GameObject>(val, parent);
			((Object)CustomBackendRow).name = "UpscalerBackendRow";
			CustomBackendRow.SetActive(true);
			CustomBackendRow.transform.SetSiblingIndex(num + 1);
			BackendDropdown = PrepareRowDropdown(CustomBackendRow, "Технология масштабирования", new List<string> { "Технология: AMD FSR 3.1", "Технология: AMD FSR 4 (RDNA4 / FP8)", "Технология: Intel XeSS", "Технология: NVIDIA DLSS" }, UpscalerUIPlugin.BackendConfig.Value, delegate(int backendIndex)
			{
				UpscalerUIPlugin.ApplyBackend(backendIndex);
			});
			FieldInfo fieldInfo2 = AccessTools.Field(typeof(GraphicsSettings), "m_qualityTogglePrefab");
			GameObject val2 = (GameObject)((fieldInfo2 != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val2 != (Object)null)
			{
				CustomFgRow = Object.Instantiate<GameObject>(val2, parent);
				((Object)CustomFgRow).name = "UpscalerFgRow";
				CustomFgRow.SetActive(true);
				CustomFgRow.transform.SetSiblingIndex(num + 2);
				TMP_Text componentInChildren = CustomFgRow.GetComponentInChildren<TMP_Text>(true);
				if ((Object)(object)componentInChildren != (Object)null)
				{
					componentInChildren.text = "Генерация кадров (Frame Generation)";
				}
				FgToggle = CustomFgRow.GetComponentInChildren<Toggle>(true);
				if ((Object)(object)FgToggle != (Object)null)
				{
					((UnityEventBase)FgToggle.onValueChanged).RemoveAllListeners();
					FgToggle.isOn = UpscalerUIPlugin.FrameGenConfig.Value;
					((UnityEvent<bool>)(object)FgToggle.onValueChanged).AddListener((UnityAction<bool>)delegate(bool isOn)
					{
						UpscalerUIPlugin.ApplyFrameGen(isOn);
					});
				}
			}
			FieldInfo fieldInfo3 = AccessTools.Field(typeof(GraphicsSettings), "m_qualitySliderPrefab");
			GameObject val3 = (GameObject)((fieldInfo3 != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val3 != (Object)null)
			{
				CustomSharpnessRow = Object.Instantiate<GameObject>(val3, parent);
				((Object)CustomSharpnessRow).name = "UpscalerSharpnessRow";
				CustomSharpnessRow.SetActive(true);
				CustomSharpnessRow.transform.SetSiblingIndex(num + 3);
				Transform val4 = CustomSharpnessRow.transform.Find("Label");
				TMP_Text val5 = (((Object)(object)val4 != (Object)null) ? ((Component)val4).GetComponent<TMP_Text>() : null);
				if ((Object)(object)val5 != (Object)null)
				{
					val5.text = "Резкость (Sharpness)";
				}
				Transform val6 = CustomSharpnessRow.transform.Find("Info/Value");
				SharpnessValueText = (((Object)(object)val6 != (Object)null) ? ((Component)val6).GetComponent<TMP_Text>() : null);
				if ((Object)(object)SharpnessValueText != (Object)null)
				{
					SharpnessValueText.text = (UpscalerUIPlugin.SharpnessConfig.Value * 100f).ToString("F0") + "%";
				}
				SharpnessSlider = CustomSharpnessRow.GetComponentInChildren<Slider>(true);
				if ((Object)(object)SharpnessSlider != (Object)null)
				{
					SharpnessSlider.minValue = 0f;
					SharpnessSlider.maxValue = 100f;
					SharpnessSlider.wholeNumbers = true;
					((UnityEventBase)SharpnessSlider.onValueChanged).RemoveAllListeners();
					SharpnessSlider.value = Mathf.Round(UpscalerUIPlugin.SharpnessConfig.Value * 100f);
					((UnityEvent<float>)(object)SharpnessSlider.onValueChanged).AddListener((UnityAction<float>)delegate(float num5)
					{
						float sharpness = num5 / 100f;
						UpscalerUIPlugin.ApplySharpness(sharpness);
						if ((Object)(object)SharpnessValueText != (Object)null)
						{
							SharpnessValueText.text = num5.ToString("F0") + "%";
						}
					});
				}
			}
			FieldInfo fieldInfo4 = AccessTools.Field(typeof(GraphicsSettings), "m_listRoot");
			RectTransform val7 = (RectTransform)((fieldInfo4 != null) ? /*isinst with value type is only supported in some contexts*/: null);
			FieldInfo fieldInfo5 = AccessTools.Field(typeof(GraphicsSettings), "m_verticalLayoutGroup");
			VerticalLayoutGroup val8 = (VerticalLayoutGroup)((fieldInfo5 != null) ? /*isinst with value type is only supported in some contexts*/: null);
			if ((Object)(object)val7 != (Object)null && (Object)(object)val8 != (Object)null)
			{
				float num2 = 0f;
				for (int num3 = 0; num3 < ((Transform)val7).childCount; num3++)
				{
					Transform child = ((Transform)val7).GetChild(num3);
					RectTransform val9 = (RectTransform)(object)((child is RectTransform) ? child : null);
					if ((Object)(object)val9 != (Object)null && ((Component)val9).gameObject.activeSelf)
					{
						float num4 = num2;
						Rect rect = val9.rect;
						num2 = num4 + (((Rect)(ref rect)).height + ((HorizontalOrVerticalLayoutGroup)val8).spacing);
					}
				}
				val7.SetSizeWithCurrentAnchors((Axis)1, num2);
				LayoutRebuilder.ForceRebuildLayoutImmediate(val7);
			}
			Debug.Log((object)"[ValheimUpscalerUI] In-game Settings -> Graphics rows successfully initialized.");
		}
		catch (Exception ex)
		{
			Debug.LogError((object)("[ValheimUpscalerUI] Error injecting in-game settings rows: " + ex));
		}
	}

	private static TMP_Dropdown PrepareRowDropdown(GameObject rowGo, string labelText, List<string> options, int initialValue, UnityAction<int> onChange)
	{
		TMP_Dropdown componentInChildren = rowGo.GetComponentInChildren<TMP_Dropdown>(true);
		if ((Object)(object)componentInChildren == (Object)null)
		{
			return null;
		}
		TMP_Text[] componentsInChildren = rowGo.GetComponentsInChildren<TMP_Text>(true);
		TMP_Text[] array = componentsInChildren;
		foreach (TMP_Text val in array)
		{
			if (!val.transform.IsChildOf(((Component)componentInChildren).transform))
			{
				val.text = labelText;
				break;
			}
		}
		Button[] componentsInChildren2 = rowGo.GetComponentsInChildren<Button>(true);
		Button[] array2 = componentsInChildren2;
		foreach (Button val2 in array2)
		{
			if (!((Component)val2).transform.IsChildOf(((Component)componentInChildren).transform))
			{
				((Component)val2).gameObject.SetActive(false);
			}
		}
		Toggle[] componentsInChildren3 = rowGo.GetComponentsInChildren<Toggle>(true);
		Toggle[] array3 = componentsInChildren3;
		foreach (Toggle val3 in array3)
		{
			if (!((Component)val3).transform.IsChildOf(((Component)componentInChildren).transform))
			{
				((Component)val3).gameObject.SetActive(false);
			}
		}
		((UnityEventBase)componentInChildren.onValueChanged).RemoveAllListeners();
		componentInChildren.ClearOptions();
		componentInChildren.AddOptions(options);
		componentInChildren.value = initialValue;
		((UnityEvent<int>)(object)componentInChildren.onValueChanged).AddListener(onChange);
		return componentInChildren;
	}
}
[HarmonyPatch(typeof(GraphicsSettings), "UpdateSettingAvailability")]
public static class GraphicsSettings_UpdateSettingAvailability_Patch
{
	public static void Postfix(GraphicsSettings __instance)
	{
		try
		{
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.CustomPresetRow != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.CustomPresetRow.SetActive(true);
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.CustomBackendRow != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.CustomBackendRow.SetActive(true);
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.CustomFgRow != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.CustomFgRow.SetActive(true);
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.CustomSharpnessRow != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.CustomSharpnessRow.SetActive(true);
			}
		}
		catch
		{
		}
	}
}
[HarmonyPatch(typeof(GraphicsSettings), "UpdateUI")]
public static class GraphicsSettings_UpdateUI_Patch
{
	public static void Postfix(GraphicsSettings __instance)
	{
		try
		{
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.PresetDropdown != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.PresetDropdown.SetValueWithoutNotify(UpscalerUIPlugin.QualityPresetConfig.Value);
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.BackendDropdown != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.BackendDropdown.SetValueWithoutNotify(UpscalerUIPlugin.BackendConfig.Value);
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.FgToggle != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.FgToggle.SetIsOnWithoutNotify(UpscalerUIPlugin.FrameGenConfig.Value);
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.SharpnessSlider != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.SharpnessSlider.SetValueWithoutNotify(Mathf.Round(UpscalerUIPlugin.SharpnessConfig.Value * 100f));
			}
			if ((Object)(object)GraphicsSettings_InitializeUI_Patch.SharpnessValueText != (Object)null)
			{
				GraphicsSettings_InitializeUI_Patch.SharpnessValueText.text = (UpscalerUIPlugin.SharpnessConfig.Value * 100f).ToString("F0") + "%";
			}
		}
		catch
		{
		}
	}
}