Decompiled source of GrassRenderDistance v1.1.0

GrassRenderDistance.dll

Decompiled a week ago
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;

[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.6.2", FrameworkDisplayName = ".NET Framework 4.6.2")]
[assembly: AssemblyCompany("Mode-Smith")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.1.0.0")]
[assembly: AssemblyInformationalVersion("1.1.0+f8c0e8c5f6c813114015984e79e7df4a9c971cfa")]
[assembly: AssemblyProduct("GrassRenderDistance")]
[assembly: AssemblyTitle("GrassRenderDistance")]
[assembly: AssemblyVersion("1.1.0.0")]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
	[CompilerGenerated]
	[Embedded]
	internal sealed class EmbeddedAttribute : Attribute
	{
	}
}
namespace System.Runtime.CompilerServices
{
	[CompilerGenerated]
	[Embedded]
	[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
	internal sealed class RefSafetyRulesAttribute : Attribute
	{
		public readonly int Version;

		public RefSafetyRulesAttribute(int P_0)
		{
			Version = P_0;
		}
	}
}
namespace GrassRenderDistance
{
	[BepInPlugin("mode-smith.valheim.grassrenderdistance", "Grass Render Distance", "1.1.0")]
	public class GrassRenderDistancePlugin : BaseUnityPlugin
	{
		public const string PluginGuid = "mode-smith.valheim.grassrenderdistance";

		public const string PluginName = "Grass Render Distance";

		public const string PluginVersion = "1.1.0";

		internal static ManualLogSource Log;

		internal static ConfigEntry<float> GrassDistance;

		internal static ConfigEntry<bool> ScaleAllClutter;

		internal static float VanillaDistance = 40f;

		private Harmony _harmony;

		private void Awake()
		{
			//IL_0039: Unknown result type (might be due to invalid IL or missing references)
			//IL_0043: Expected O, but got Unknown
			Log = ((BaseUnityPlugin)this).Logger;
			GrassDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GrassDistance", 80f, new ConfigDescription("How far away (in meters) grass and other clutter is drawn. Vanilla is 40. Higher values cost more CPU/GPU - the number of grass patches grows with the square of this value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 300f), Array.Empty<object>()));
			ScaleAllClutter = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "ScaleAllClutter", true, "Also stretch the fade-out distance of every clutter type (small plants, saplings, flowers) by the same factor as GrassDistance, so they don't pop in closer than the grass. Turn off to only change grass distance.");
			GrassDistance.SettingChanged += delegate
			{
				Apply(ClutterSystem.instance);
			};
			ScaleAllClutter.SettingChanged += delegate
			{
				Apply(ClutterSystem.instance);
			};
			_harmony = Harmony.CreateAndPatchAll(typeof(GrassRenderDistancePlugin).Assembly, "mode-smith.valheim.grassrenderdistance");
		}

		private void OnDestroy()
		{
			Harmony harmony = _harmony;
			if (harmony != null)
			{
				harmony.UnpatchSelf();
			}
		}

		internal static void Apply(ClutterSystem clutter)
		{
			if (!((Object)(object)clutter == (Object)null))
			{
				clutter.m_distance = GrassDistance.Value;
				float num = (ScaleAllClutter.Value ? (GrassDistance.Value / VanillaDistance) : 1f);
				ClutterScaler.Apply(clutter, num);
				clutter.ClearAll();
				Log.LogInfo((object)$"Grass distance set to {clutter.m_distance} m (clutter fade scale x{num:0.##})");
			}
		}
	}
	internal static class ClutterScaler
	{
		private class RendererOriginal
		{
			public float Min;

			public float Max;
		}

		private static readonly Dictionary<InstanceRenderer, RendererOriginal> RendererOriginals = new Dictionary<InstanceRenderer, RendererOriginal>();

		private static readonly Dictionary<LODGroup, float[]> LodGroupOriginals = new Dictionary<LODGroup, float[]>();

		public static void Apply(ClutterSystem clutter, float scale)
		{
			float maxAllowed = clutter.m_distance - clutter.m_grassPatchSize / 2f;
			foreach (Clutter item in clutter.m_clutter)
			{
				if (!((Object)(object)item.m_prefab == (Object)null))
				{
					if (item.m_instanced)
					{
						ScaleInstanced(item, scale, maxAllowed);
					}
					else
					{
						ScaleLodGroups(item, scale);
					}
				}
			}
		}

		private static void ScaleInstanced(Clutter type, float scale, float maxAllowed)
		{
			InstanceRenderer component = type.m_prefab.GetComponent<InstanceRenderer>();
			if (!((Object)(object)component == (Object)null))
			{
				if (!RendererOriginals.TryGetValue(component, out var value))
				{
					value = new RendererOriginal
					{
						Min = component.m_lodMinDistance,
						Max = component.m_lodMaxDistance
					};
					RendererOriginals[component] = value;
				}
				component.m_lodMaxDistance = value.Max * scale;
				component.m_lodMinDistance = Mathf.Min(value.Min * scale, Mathf.Min(component.m_lodMaxDistance, maxAllowed));
				GrassRenderDistancePlugin.Log.LogInfo((object)($"  [instanced] {type.m_name}: useLod={component.m_useLod}, fade {value.Min:0.#}-{value.Max:0.#} m -> " + $"{component.m_lodMinDistance:0.#}-{Mathf.Min(component.m_lodMaxDistance, maxAllowed):0.#} m"));
			}
		}

		private static void ScaleLodGroups(Clutter type, float scale)
		{
			LODGroup[] componentsInChildren = type.m_prefab.GetComponentsInChildren<LODGroup>(true);
			if (componentsInChildren.Length == 0)
			{
				GrassRenderDistancePlugin.Log.LogInfo((object)("  [object]    " + type.m_name + ": no LODGroup, visible to full grass distance"));
				return;
			}
			LODGroup[] array = componentsInChildren;
			foreach (LODGroup val in array)
			{
				LOD[] lODs = val.GetLODs();
				if (!LodGroupOriginals.TryGetValue(val, out var value))
				{
					value = new float[lODs.Length];
					for (int j = 0; j < lODs.Length; j++)
					{
						value[j] = lODs[j].screenRelativeTransitionHeight;
					}
					LodGroupOriginals[val] = value;
				}
				for (int k = 0; k < lODs.Length && k < value.Length; k++)
				{
					lODs[k].screenRelativeTransitionHeight = value[k] / scale;
				}
				val.SetLODs(lODs);
				GrassRenderDistancePlugin.Log.LogInfo((object)($"  [object]    {type.m_name}: LODGroup cull height {value[^1]:0.###} -> " + $"{lODs[^1].screenRelativeTransitionHeight:0.###}"));
			}
		}
	}
	[HarmonyPatch(typeof(ClutterSystem), "Awake")]
	internal static class ClutterSystemAwakePatch
	{
		private static void Postfix(ClutterSystem __instance)
		{
			GrassRenderDistancePlugin.VanillaDistance = __instance.m_distance;
			GrassRenderDistancePlugin.Log.LogInfo((object)$"ClutterSystem created with vanilla distance {__instance.m_distance} m");
			GrassRenderDistancePlugin.Apply(__instance);
		}
	}
}