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 PerformantGrass v1.0.0
PerformantGrass.dll
Decompiled 4 days agousing 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.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("PerformantGrass")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("PerformantGrass")] [assembly: AssemblyTitle("PerformantGrass")] [assembly: AssemblyVersion("1.0.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 PerformantGrass { [BepInPlugin("com.dreich.performantgrass", "Performant Grass", "1.0.0")] public class PerformantGrass : BaseUnityPlugin { public const string Guid = "com.dreich.performantgrass"; public const string Name = "Performant Grass"; public const string Version = "1.0.0"; internal static ManualLogSource Log; internal static ConfigEntry<bool> Enabled; internal static ConfigEntry<int> MaxCachedPatches; internal static ConfigEntry<float> GrassDistance; internal static ConfigEntry<bool> LogStats; private float nextStats; private void Awake() { //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Expected O, but got Unknown //IL_00f0: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Enabled = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enabled", true, "Remember where grass was placed so walking back into an area doesn't have to work it all out again."); MaxCachedPatches = ((BaseUnityPlugin)this).Config.Bind<int>("General", "MaxCachedPatches", 1500, new ConfigDescription("How many 8x8 m grass patches to remember. Each one is a few kilobytes; the oldest are forgotten first.", (AcceptableValueBase)(object)new AcceptableValueRange<int>(100, 20000), Array.Empty<object>())); GrassDistance = ((BaseUnityPlugin)this).Config.Bind<float>("General", "GrassDistance", 0f, new ConfigDescription("How far away grass is drawn, in meters. 0 = the game's own distance (40). Higher values show more grass but cost more: the number of grass patches grows with the square of the distance.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 150f), Array.Empty<object>())); GrassDistance.SettingChanged += delegate { GrassCache.ApplyDistance(ClutterSystem.instance, rebuild: true); }; LogStats = ((BaseUnityPlugin)this).Config.Bind<bool>("Diagnostics", "LogStats", false, "Every 30 seconds, write how many grass patches were rebuilt from memory and how many had to be worked out from scratch."); new Harmony("com.dreich.performantgrass").PatchAll(); } private void Update() { if (LogStats.Value && !(Time.time < nextStats)) { nextStats = Time.time + 30f; GrassCache.ReportStats(); } } } internal static class GrassCache { private sealed class InstancedPart { public GameObject Prefab; public Matrix4x4[] Matrices; } private sealed class LoosePart { public GameObject Prefab; public Vector3 Position; public Quaternion Rotation; } private sealed class CachedPatch { public Vector2Int Id; public Vector3 Center; public Quality Quality; public float AmountScale; public readonly List<InstancedPart> Instanced = new List<InstancedPart>(); public readonly List<LoosePart> Loose = new List<LoosePart>(); public LinkedListNode<Vector2Int> Node; } private static readonly Type PatchDataType = AccessTools.Inner(typeof(ClutterSystem), "PatchData"); private static readonly FieldInfo PatchCenter = AccessTools.Field(PatchDataType, "center"); private static readonly FieldInfo PatchObjects = AccessTools.Field(PatchDataType, "m_objects"); private static readonly MethodInfo AllocatePatch = AccessTools.Method(typeof(ClutterSystem), "AllocatePatch", (Type[])null, (Type[])null); private static readonly FieldRef<ClutterSystem, Quality> QualityField = AccessTools.FieldRefAccess<ClutterSystem, Quality>("m_quality"); private static readonly FieldRef<ClutterSystem, GameObject> GrassRootField = AccessTools.FieldRefAccess<ClutterSystem, GameObject>("m_grassRoot"); private static readonly FieldRef<InstanceRenderer, Matrix4x4[]> InstancesField = AccessTools.FieldRefAccess<InstanceRenderer, Matrix4x4[]>("m_instances"); private static readonly FieldRef<InstanceRenderer, int> InstanceCountField = AccessTools.FieldRefAccess<InstanceRenderer, int>("m_instanceCount"); private static readonly Dictionary<Vector2Int, CachedPatch> cache = new Dictionary<Vector2Int, CachedPatch>(); private static readonly LinkedList<Vector2Int> order = new LinkedList<Vector2Int>(); private static readonly Dictionary<string, GameObject> prefabsByName = new Dictionary<string, GameObject>(); private static ClutterSystem prefabsFor; private static int fromCache; private static int fromScratch; internal static bool WasReplayed; private static float gameDistance = -1f; internal static bool Ready { get { if (PatchDataType != null && PatchCenter != null && PatchObjects != null) { return AllocatePatch != null; } return false; } } internal static void ApplyDistance(ClutterSystem system, bool rebuild) { if ((Object)(object)system == (Object)null || system.m_menuHack) { return; } if (gameDistance < 0f) { gameDistance = system.m_distance; } float num = ((PerformantGrass.GrassDistance.Value > 0f) ? Mathf.Max(10f, PerformantGrass.GrassDistance.Value) : gameDistance); if (!Mathf.Approximately(system.m_distance, num)) { system.m_distance = num; if (rebuild) { system.ClearAll(); } } } internal static void AdjustLod(ClutterSystem system, object patchData) { if (patchData == null || PatchObjects == null || !(PatchObjects.GetValue(patchData) is List<GameObject> list)) { return; } float num = ((gameDistance > 0f) ? (system.m_distance / gameDistance) : 1f); float num2 = system.m_distance - system.m_grassPatchSize / 2f; foreach (GameObject item in list) { InstanceRenderer val = (((Object)(object)item != (Object)null) ? item.GetComponent<InstanceRenderer>() : null); if (!((Object)(object)val == (Object)null) && val.m_useLod) { GameObject val2 = PrefabFor(system, item); InstanceRenderer val3 = (((Object)(object)val2 != (Object)null) ? val2.GetComponent<InstanceRenderer>() : null); if (!((Object)(object)val3 == (Object)null)) { val.m_lodMinDistance = val3.m_lodMinDistance * num; val.m_lodMaxDistance = Mathf.Min(val3.m_lodMaxDistance * num, num2); } } } } internal static void Clear() { cache.Clear(); order.Clear(); prefabsByName.Clear(); prefabsFor = null; } internal static bool Has(ClutterSystem system, Vector2Int id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) CachedPatch patch; if (PerformantGrass.Enabled.Value && Ready) { return TryGet(system, id, out patch); } return false; } private static bool TryGet(ClutterSystem system, Vector2Int id, out CachedPatch patch) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Invalid comparison between Unknown and I4 //IL_003b: Unknown result type (might be due to invalid IL or missing references) if (!cache.TryGetValue(id, out patch)) { return false; } if ((int)patch.Quality == (int)QualityField.Invoke(system) && Mathf.Approximately(patch.AmountScale, system.m_amountScale)) { return true; } Forget(id); patch = null; return false; } private static void Forget(Vector2Int id) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Unknown result type (might be due to invalid IL or missing references) if (cache.TryGetValue(id, out var value)) { order.Remove(value.Node); cache.Remove(id); } } internal static void Invalidate(ClutterSystem system, Vector3 center, float radius) { //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_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003e: 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_0051: 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) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0083: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: Unknown result type (might be due to invalid IL or missing references) float num = system.m_grassPatchSize / 2f; List<Vector2Int> list = new List<Vector2Int>(); foreach (CachedPatch value in cache.Values) { Vector3 center2 = value.Center; if (!(center2.x + num < center.x - radius) && !(center2.x - num > center.x + radius) && !(center2.z + num < center.z - radius) && !(center2.z - num > center.z + radius)) { list.Add(value.Id); } } foreach (Vector2Int item in list) { Forget(item); } } internal static object Replay(ClutterSystem system, Vector2Int id) { //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_00b3: 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_0103: Unknown result type (might be due to invalid IL or missing references) //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) if (!PerformantGrass.Enabled.Value || !Ready || !TryGet(system, id, out var patch)) { return null; } GameObject val = GrassRootField.Invoke(system); if ((Object)(object)val == (Object)null) { return null; } object obj = AllocatePatch.Invoke(system, null); PatchCenter.SetValue(obj, patch.Center); List<GameObject> list = (List<GameObject>)PatchObjects.GetValue(obj); float num = system.m_distance - system.m_grassPatchSize / 2f; foreach (InstancedPart item in patch.Instanced) { if ((Object)(object)item.Prefab == (Object)null) { continue; } GameObject val2 = Object.Instantiate<GameObject>(item.Prefab, patch.Center, Quaternion.identity, val.transform); InstanceRenderer component = val2.GetComponent<InstanceRenderer>(); if ((Object)(object)component != (Object)null) { if (component.m_lodMaxDistance > num) { component.m_lodMaxDistance = num; } Matrix4x4[] matrices = item.Matrices; foreach (Matrix4x4 val3 in matrices) { component.AddInstance(val3); } } list.Add(val2); } foreach (LoosePart item2 in patch.Loose) { if (!((Object)(object)item2.Prefab == (Object)null)) { list.Add(Object.Instantiate<GameObject>(item2.Prefab, item2.Position, item2.Rotation, val.transform)); } } order.Remove(patch.Node); order.AddLast(patch.Node); fromCache++; return obj; } internal static void Capture(ClutterSystem system, Vector2Int id, object patchData) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_0193: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Unknown result type (might be due to invalid IL or missing references) //IL_013f: 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_0151: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Unknown result type (might be due to invalid IL or missing references) fromScratch++; if (!PerformantGrass.Enabled.Value || !Ready || patchData == null || system.m_menuHack || !(PatchObjects.GetValue(patchData) is List<GameObject> list)) { return; } CachedPatch cachedPatch = new CachedPatch { Id = id, Center = (Vector3)PatchCenter.GetValue(patchData), Quality = QualityField.Invoke(system), AmountScale = system.m_amountScale }; foreach (GameObject item in list) { if (!((Object)(object)item == (Object)null)) { GameObject val = PrefabFor(system, item); if ((Object)(object)val == (Object)null) { return; } InstanceRenderer component = item.GetComponent<InstanceRenderer>(); if ((Object)(object)component != (Object)null) { int num = InstanceCountField.Invoke(component); Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[num]; Array.Copy(InstancesField.Invoke(component), array, num); cachedPatch.Instanced.Add(new InstancedPart { Prefab = val, Matrices = array }); } else { cachedPatch.Loose.Add(new LoosePart { Prefab = val, Position = item.transform.position, Rotation = item.transform.rotation }); } } } Forget(id); cachedPatch.Node = order.AddLast(id); cache[id] = cachedPatch; int value = PerformantGrass.MaxCachedPatches.Value; while (cache.Count > value && order.First != null) { Forget(order.First.Value); } } private static GameObject PrefabFor(ClutterSystem system, GameObject instance) { if ((Object)(object)prefabsFor != (Object)(object)system) { prefabsByName.Clear(); prefabsFor = system; foreach (Clutter item in system.m_clutter) { if ((Object)(object)item.m_prefab != (Object)null) { prefabsByName[((Object)item.m_prefab).name] = item.m_prefab; } } } string text = ((Object)instance).name; int num = text.IndexOf("(Clone)", StringComparison.Ordinal); if (num >= 0) { text = text.Substring(0, num); } if (!prefabsByName.TryGetValue(text.Trim(), out var value)) { return null; } return value; } internal static void ReportStats() { PerformantGrass.Log.LogInfo((object)("Grass patches in the last 30 s: " + fromCache + " rebuilt from memory, " + fromScratch + " worked out from scratch. Patches remembered: " + cache.Count + ".")); fromCache = 0; fromScratch = 0; } } [HarmonyPatch(typeof(ClutterSystem), "Awake")] internal static class ClutterAwakePatch { private static void Postfix(ClutterSystem __instance) { GrassCache.Clear(); if (!__instance.m_menuHack) { GrassCache.ApplyDistance(__instance, rebuild: false); } if (!GrassCache.Ready) { PerformantGrass.Log.LogWarning((object)"The grass system's internals have changed; grass caching is turned off."); } } } [HarmonyPatch(typeof(ClutterSystem), "OnDestroy")] internal static class ClutterDestroyPatch { private static void Postfix() { GrassCache.Clear(); } } [HarmonyPatch(typeof(ClutterSystem), "ApplySettings")] internal static class ClutterSettingsPatch { private static void Postfix() { GrassCache.Clear(); } } [HarmonyPatch(typeof(ClutterSystem), "ResetGrass")] internal static class ClutterResetPatch { private static void Prefix(ClutterSystem __instance, Vector3 center, float radius) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) GrassCache.Invalidate(__instance, center, radius); } } [HarmonyPatch(typeof(ClutterSystem), "GeneratePatch")] internal static class ClutterGeneratePatchPatch { private static void Prefix(ClutterSystem __instance, Vector2Int p, ref bool generated, out bool __state) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) __state = generated; if (GrassCache.Has(__instance, p)) { generated = false; } } private static void Postfix(ref bool generated, bool __state) { if (GrassCache.WasReplayed) { generated = __state; } GrassCache.WasReplayed = false; } } [HarmonyPatch(typeof(ClutterSystem), "GenerateVegPatch")] internal static class ClutterGenerateVegPatchPatch { private static bool Prefix(ClutterSystem __instance, Vector2Int patchID, ref object __result, out bool __state) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) object obj = GrassCache.Replay(__instance, patchID); __state = obj != null; GrassCache.WasReplayed = __state; if (!__state) { return true; } __result = obj; return false; } private static void Postfix(ClutterSystem __instance, Vector2Int patchID, object __result, bool __state) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) if (!__state) { GrassCache.Capture(__instance, patchID, __result); } if (!__instance.m_menuHack) { GrassCache.AdjustLod(__instance, __result); } } } }