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 SteadyFrame v1.3.1
SteadyFrame.dll
Decompiled 5 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using SteadyFrame; using SteadyFrame.Core; using SteadyFrame.Housekeeping; using SteadyFrame.SceneStreaming; using SteadyFrame.Terrain; using SteadyFrame.Transitions; using SteadyFrame.Transitions.ObjectLoading; using SteadyFrame.Vegetation; using Unity.Collections; using UnityEngine; using UnityEngine.Rendering; using ValheimMods.Shared; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("SteadyFrameDiagnostics")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("SteadyFrame")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.3.1.0")] [assembly: AssemblyInformationalVersion("1.3.1+24ce96994953df6fa3721ebd878bf87486a95c96")] [assembly: AssemblyProduct("SteadyFrame")] [assembly: AssemblyTitle("SteadyFrame")] [assembly: AssemblyVersion("1.3.1.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 ValheimMods.Shared { internal static class GpuGrass { private sealed class AuditPatch { public string Name; public Vector3 Position; public int Id; public int Slot; public int Capacity; public int Count; public int Kind; public Vector4 Sphere; public Vector4[] Rows; } private sealed class Audit { public int IdTop; public int Kinds; public int Capacity; public int VisibleCapacity; public int Pending = 7; public int Failed; public long Regrowths; public long Frame; public readonly List<AuditPatch> Patches = new List<AuditPatch>(); public readonly HashSet<int> FreeIds = new HashSet<int>(); public long[] Totals; public uint[] Bases; public string[] KindNames; public PatchGpu[] Table; public Vector4[] ObjectToWorld; public Vector4[] WorldToObject; public uint[] Draw; public uint[] Visible; public uint[] Args; } private sealed class ByReference<T> : IEqualityComparer<T> where T : class { internal static readonly ByReference<T> Instance = new ByReference<T>(); public bool Equals(T x, T y) { return x == y; } public int GetHashCode(T obj) { return RuntimeHelpers.GetHashCode(obj); } } private sealed class Patch { public bool Grass; public Kind Kind; public int Id = -1; public int Member = -1; public int Slot = -1; public int Capacity; public int Uploaded; public bool Dirty = true; public bool StateDirty = true; public Vector3 Center; public float Radius; } private sealed class Kind { public Mesh Mesh; public Material Original; public Material Copy; public ShadowCastingMode Shadows; public int Layer; public int Index; public MaterialPropertyBlock Block; public long Total; public int Base; public readonly List<Patch> Members = new List<Patch>(); public bool BoundsDirty = true; public Bounds Bounds; public KindKey Key; public string Name; public float Extent; public bool Gone; public bool Retired; } private struct PatchGpu { public Vector4 Sphere; public Vector4 Position; public float LodMax; public uint Flags; public uint Count; public uint Slot; public uint Kind; public uint Pad0; public uint Pad1; public uint Pad2; } private readonly struct KindKey : IEquatable<KindKey> { private readonly Mesh _mesh; private readonly Material _material; private readonly int _shadows; private readonly int _layer; public KindKey(Mesh mesh, Material material, ShadowCastingMode shadows, int layer) { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected I4, but got Unknown _mesh = mesh; _material = material; _shadows = (int)shadows; _layer = layer; } public bool Equals(KindKey o) { if (_mesh == o._mesh && _material == o._material && _shadows == o._shadows) { return _layer == o._layer; } return false; } public override bool Equals(object o) { if (o is KindKey o2) { return Equals(o2); } return false; } public override int GetHashCode() { return ((RuntimeHelpers.GetHashCode(_mesh) * 397) ^ RuntimeHelpers.GetHashCode(_material)) * 31 + _shadows * 7 + _layer; } } [HarmonyPatch(typeof(InstanceRenderer), "CustomUpdate")] private static class Patch_CustomUpdate { private static bool Prefix(InstanceRenderer __instance) { return Before(__instance); } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(Graphics), "DrawMeshInstanced", new Type[9] { typeof(Mesh), typeof(int), typeof(Material), typeof(Matrix4x4[]), typeof(int), typeof(MaterialPropertyBlock), typeof(ShadowCastingMode), typeof(bool), typeof(int) }, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = 0; foreach (CodeInstruction item in list) { if (CodeInstructionExtensions.Calls(item, methodInfo)) { num++; } } if (num != 2) { throw new InvalidOperationException($"InstanceRenderer.CustomUpdate has {num} DrawMeshInstanced calls (expected 2)"); } List<CodeInstruction> list2 = new List<CodeInstruction>(list.Count + 2); foreach (CodeInstruction item2 in list) { if (CodeInstructionExtensions.Calls(item2, methodInfo)) { CodeInstruction val = new CodeInstruction(OpCodes.Ldarg_0, (object)null); CodeInstructionExtensions.MoveLabelsTo(item2, val); list2.Add(val); item2.opcode = OpCodes.Call; item2.operand = AccessTools.Method(typeof(GpuGrass), "Draw", (Type[])null, (Type[])null); } list2.Add(item2); } return list2; } } [HarmonyPatch(typeof(MonoUpdatersExtra), "CustomUpdate")] private static class Patch_Pass { private static void Prefix(List<IMonoUpdater> source) { if (source == InstanceRenderer.Instances) { BeginPass(); } } private static void Postfix(List<IMonoUpdater> source, float deltaTime) { if (source == InstanceRenderer.Instances) { EndPass(deltaTime); } } private static IEnumerable<CodeInstruction> Transpiler(IEnumerable<CodeInstruction> instructions) { MethodInfo addRange = AccessTools.Method(typeof(List<IMonoUpdater>), "AddRange", (Type[])null, (Type[])null); List<CodeInstruction> list = new List<CodeInstruction>(instructions); List<CodeInstruction> list2 = list.FindAll((CodeInstruction ins) => CodeInstructionExtensions.Calls(ins, addRange)); if (list2.Count != 1) { _log.LogWarning((object)$"MonoUpdatersExtra.CustomUpdate has {list2.Count} AddRange calls (expected 1): every renderer keeps its turn"); return list; } list2[0].opcode = OpCodes.Call; list2[0].operand = AccessTools.Method(typeof(GpuGrass), "AddToPass", (Type[])null, (Type[])null); return list; } } [HarmonyPatch(typeof(InstanceRenderer), "OnEnable")] private static class Patch_OnEnable { private static void Postfix(InstanceRenderer __instance) { Born(__instance); } } [HarmonyPatch(typeof(InstanceRenderer), "OnDisable")] private static class Patch_OnDisable { private static void Postfix(InstanceRenderer __instance) { Forget(__instance); } } [HarmonyPatch(typeof(InstanceRenderer), "Clear")] private static class Patch_Clear { private static void Postfix(InstanceRenderer __instance) { Touch(__instance); } } [HarmonyPatch(typeof(InstanceRenderer), "SetInstance")] private static class Patch_SetInstance { private static void Postfix(InstanceRenderer __instance) { Touch(__instance); } } [HarmonyPatch(typeof(InstanceRenderer), "SetInstances")] private static class Patch_SetInstances { private static void Postfix(InstanceRenderer __instance) { Touch(__instance); } } [HarmonyPatch(typeof(InstanceRenderer), "SetInstancesBillboard")] private static class Patch_SetBillboard { private static void Postfix(InstanceRenderer __instance) { Touch(__instance); } } private sealed class TerrainCopy { public int Width; public int MaskWidth; public float Scale; public float Half; public Vector3 Position; public float[] Heights; public float[] Ocean; public Color32[] Mask; public Biome[] Corners; } private sealed class BuildKind { public Kind Kind; public int Index; public int Amount; public Vector3 Scale; public float Extent; public float LodMin; public float LodMax; public uint Flags; public Biome Biome; public bool InForest; public bool OnCleared; public bool OnUncleared; public bool SnapToWater; public bool TerrainTilt; public float ForestMin; public float ForestMax; public float FractalScale; public float FractalOffset; public float FractalMin; public float FractalMax; public float MinAlt; public float MaxAlt; public float MinNormal; public float MaxNormal; public float MinOcean; public float MaxOcean; public float MinVegetation; public float MaxVegetation; public float RandomOffset; public float ScaleMin; public float ScaleMax; } private sealed class BuildJob { public object Owner; public Vector2Int Cell; public float Size; public float Water; public BuildKind[] Kinds; public readonly TerrainCopy[] Maps = new TerrainCopy[4]; public readonly List<Patch> Replaces = new List<Patch>(); public Vector4[] Rows; public int[] First; public int[] Count; public Vector3[] Min; public Vector3[] Max; public Exception Error; } private sealed class BuiltPatch { public Vector2Int Cell; public BuildJob Job; public readonly List<Patch> Drawn = new List<Patch>(); public BuildKind[] Kinds; public int[] First; public int[] Count; public Vector4[] Rows; public float Size; } private struct BuildRandom { private uint _x; private uint _y; private uint _z; private uint _w; public BuildRandom(int seed) { _x = (uint)seed; _y = _x * 1812433253 + 1; _z = _y * 1812433253 + 1; _w = _z * 1812433253 + 1; } private uint Next() { uint num = _x ^ (_x << 11); _x = _y; _y = _z; _z = _w; return _w = _w ^ (_w >> 19) ^ num ^ (num >> 8); } public float Range(float min, float max) { float num = (float)(Next() & 0x7FFFFF) * 1.192093E-07f; return min * num + (1f - num) * max; } public int Range(int min, int max) { if (max > min) { return min + (int)(Next() % (uint)(max - min)); } return min; } } [HarmonyPatch(typeof(ClutterSystem), "GenerateVegPatch")] private static class Patch_Build { private static void Prefix(ClutterSystem __instance) { if (_buildOn && __instance == _buildFor && !__instance.m_menuHack) { RefreshKinds(__instance); BuildKind[] buildKinds = _buildKinds; foreach (BuildKind buildKind in buildKinds) { __instance.m_clutter[buildKind.Index].m_enabled = false; } _holding = true; } } private static void Postfix(ClutterSystem __instance, object __result, Vector2Int patchID, float size) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0044: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) if (_holding && __result != null) { BuildJob buildJob = new BuildJob { Owner = __result, Cell = patchID, Size = size, Water = __instance.m_waterLevel, Kinds = _buildKinds }; BuiltPatch value = new BuiltPatch { Cell = patchID, Job = buildJob }; Built[__result] = value; BuiltCells[patchID] = value; Waiting.Enqueue(buildJob); } } private static void Finalizer(ClutterSystem __instance) { if (_holding) { _holding = false; BuildKind[] buildKinds = _buildKinds; foreach (BuildKind buildKind in buildKinds) { __instance.m_clutter[buildKind.Index].m_enabled = true; } } } } [HarmonyPatch(typeof(ClutterSystem), "FreePatch")] private static class Patch_FreePatch { private static void Prefix(object patch) { Freed(patch); } } [HarmonyPatch(typeof(Heightmap), "Regenerate")] private static class Patch_Regenerate { private static void Postfix(Heightmap __instance) { Forget(__instance); } } [HarmonyPatch(typeof(Heightmap), "PaintCleared")] private static class Patch_PaintCleared { private static void Postfix(Heightmap __instance) { Forget(__instance); } } [HarmonyPatch(typeof(Heightmap), "OnDisable")] private static class Patch_HeightmapOff { private static void Postfix(Heightmap __instance) { Forget(__instance); } } private const float AuditEvery = 20f; private const int AuditLogged = 8; private static float _nextAudit = 40f; private static Audit _audit; private const int Version = 5; private const string Slot = "ValheimMods.Shared.GpuGrass"; private const string HarmonyId = "ValheimMods.Shared.GpuGrass"; private const string SteadyFrameGuid = "ru.ivest.steadyframe"; private const int RunsAt = 5; private static ManualLogSource _log; private static Func<bool?>[] _opinions; private static bool _wanted; private static readonly FieldRef<InstanceRenderer, int> InstanceCount = AccessTools.FieldRefAccess<InstanceRenderer, int>("m_instanceCount"); private static readonly FieldRef<InstanceRenderer, Matrix4x4[]> Matrices = AccessTools.FieldRefAccess<InstanceRenderer, Matrix4x4[]>("m_instances"); private static readonly FieldRef<InstanceRenderer, float> LodCount = AccessTools.FieldRefAccess<InstanceRenderer, float>("m_lodCount"); private static readonly FieldRef<InstanceRenderer, bool> FirstFrame = AccessTools.FieldRefAccess<InstanceRenderer, bool>("m_firstFrame"); private static readonly Dictionary<InstanceRenderer, Patch> Patches = new Dictionary<InstanceRenderer, Patch>(4096, ByReference<InstanceRenderer>.Instance); private static readonly Dictionary<KindKey, Kind> Kinds = new Dictionary<KindKey, Kind>(); private static readonly List<Kind> KindList = new List<Kind>(); private static readonly Stack<int> FreeKinds = new Stack<int>(); private static readonly Dictionary<Material, bool> GrassMaterials = new Dictionary<Material, bool>(ByReference<Material>.Instance); private const int MinClass = 4; private const int Classes = 7; private const int StartSlots = 524288; private static readonly Stack<int>[] Free = new Stack<int>[7]; private static int _top; private static int _capacity; private static GraphicsBuffer _objectToWorld; private static GraphicsBuffer _worldToObject; private static GraphicsBuffer _visible; private static GraphicsBuffer _invertRecords; private static int _visibleCapacity; private static int _invertRecordCapacity; private const int MaxPatches = 16384; private const int MaxKinds = 256; private static GraphicsBuffer _patches; private static GraphicsBuffer _state; private static GraphicsBuffer _draw; private static GraphicsBuffer _args; private static GraphicsBuffer _kindBase; private static readonly Stack<int> FreeIds = new Stack<int>(); private static int _idTop; private static readonly PatchGpu[] OnePatch = new PatchGpu[1]; private static readonly Vector2[] OneState = (Vector2[])(object)new Vector2[1]; private static readonly uint[] ArgsData = new uint[1280]; private static readonly uint[] KindBases = new uint[256]; private static bool _kindsDirty = true; private static bool _activeLast; private static bool _lean; private const int SliceOf = 64; private static readonly HashSet<IMonoUpdater> LeftToGame = new HashSet<IMonoUpdater>(ByReference<IMonoUpdater>.Instance); private static readonly List<IMonoUpdater> PassList = new List<IMonoUpdater>(4096); private static readonly HashSet<IMonoUpdater> InPass = new HashSet<IMonoUpdater>(ByReference<IMonoUpdater>.Instance); private static readonly List<InstanceRenderer> Changed = new List<InstanceRenderer>(4096); private static int _sliceAt; private static readonly Vector4[] Planes = (Vector4[])(object)new Vector4[6]; private static int _cull; private static int _expand; private static int _invert; private static int _copy; private static readonly Vector4[] Rows = (Vector4[])(object)new Vector4[3072]; private static int _inverts; private static uint[] _invertData = new uint[4096]; private static bool _ready; private static bool _tried; private static int _layer = -1; private static readonly int GrassFirst = Shader.PropertyToID("_GrassFirst"); private static long _uploads; private static long _uploadedInstances; private static long _frames; private static long _regrowths; private static long _overflow; private static uint _lastDrawn; private static bool _readbackPending; private static float _nextReport; internal static bool BuildPaused = false; private const float BuildBudgetMs = 0.25f; private const float BuildBacklogBudgetMs = 2f; private const int BuildBacklog = 64; private const int MostPerKind = 1023; private static readonly Dictionary<object, BuiltPatch> Built = new Dictionary<object, BuiltPatch>(4096, ByReference<object>.Instance); private static readonly Dictionary<Vector2Int, BuiltPatch> BuiltCells = new Dictionary<Vector2Int, BuiltPatch>(4096); private static readonly Dictionary<Vector2s, TerrainCopy> Copies = new Dictionary<Vector2s, TerrainCopy>(); private static readonly Queue<BuildJob> Waiting = new Queue<BuildJob>(); private static readonly Queue<BuildJob> ToBuild = new Queue<BuildJob>(); private static readonly Queue<BuildJob> Finished = new Queue<BuildJob>(); private static readonly List<BuildKind> KindsNow = new List<BuildKind>(); private static BuildKind[] _buildKinds; private static int _buildKindsFrame = -1; private static bool _buildOn; private static bool _buildLast; private static bool _holding; private static bool _buildBroken; private static bool _foreign; private static ClutterSystem _buildFor; private static ClutterSystem _foreignChecked; private static Thread _worker; private static readonly FieldRef<Heightmap, List<float>> HmHeights = AccessTools.FieldRefAccess<Heightmap, List<float>>("m_heights"); private static readonly FieldRef<Heightmap, Texture2D> HmMask = AccessTools.FieldRefAccess<Heightmap, Texture2D>("m_paintMask"); private static readonly FieldRef<Heightmap, float[]> HmOcean = AccessTools.FieldRefAccess<Heightmap, float[]>("m_oceanDepth"); private static readonly FieldRef<Heightmap, BiomeSector[]> HmCorners = AccessTools.FieldRefAccess<Heightmap, BiomeSector[]>("m_cornerBiomes"); private static readonly FieldRef<ClutterSystem, Quality> Quality = AccessTools.FieldRefAccess<ClutterSystem, Quality>("m_quality"); private static Vector4[] _buildRows = (Vector4[])(object)new Vector4[12288]; private static readonly float[] Weights = new float[10]; private static List<object[]> Offers => SharedElection.Offers("ValheimMods.Shared.GpuGrass"); internal static bool AnyActive { get { if (AppDomain.CurrentDomain.GetData("ValheimMods.Shared.GpuGrass.active") is Func<bool> func) { return func(); } return false; } } private static bool Wanted => _wanted; private static bool Active { get { if (_ready) { return Wanted; } return false; } } private static bool GameLogicToo => GrassCheck.GameLogicToo; private static void AuditIfDue() { //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_0204: Unknown result type (might be due to invalid IL or missing references) //IL_0217: Unknown result type (might be due to invalid IL or missing references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) //IL_0293: Unknown result type (might be due to invalid IL or missing references) //IL_02fc: Unknown result type (might be due to invalid IL or missing references) //IL_0301: Unknown result type (might be due to invalid IL or missing references) //IL_030e: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_031c: Unknown result type (might be due to invalid IL or missing references) //IL_0323: Unknown result type (might be due to invalid IL or missing references) //IL_032a: Unknown result type (might be due to invalid IL or missing references) //IL_032f: Unknown result type (might be due to invalid IL or missing references) //IL_0341: Unknown result type (might be due to invalid IL or missing references) //IL_0348: Unknown result type (might be due to invalid IL or missing references) //IL_034f: Unknown result type (might be due to invalid IL or missing references) //IL_0356: Unknown result type (might be due to invalid IL or missing references) //IL_035d: Unknown result type (might be due to invalid IL or missing references) //IL_0362: Unknown result type (might be due to invalid IL or missing references) //IL_0374: Unknown result type (might be due to invalid IL or missing references) //IL_037b: Unknown result type (might be due to invalid IL or missing references) //IL_0382: Unknown result type (might be due to invalid IL or missing references) //IL_0389: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_0395: Unknown result type (might be due to invalid IL or missing references) if (!SteadyFramePlugin.Cfg.VerifyGpuGrassBuffers.On || _audit != null || (Time.time < _nextAudit && !GrassSnapshot.TakeAudit())) { return; } _nextAudit = Time.time + 20f; Audit a = new Audit { IdTop = _idTop, Kinds = KindList.Count, Capacity = _capacity, VisibleCapacity = _visibleCapacity, Regrowths = _regrowths, Frame = Time.frameCount, Totals = new long[KindList.Count], Bases = new uint[KindList.Count], KindNames = new string[KindList.Count] }; for (int i = 0; i < KindList.Count; i++) { a.Totals[i] = KindList[i].Total; a.Bases[i] = KindBases[i]; a.KindNames[i] = (((Object)(object)KindList[i].Mesh != (Object)null) ? ((Object)KindList[i].Mesh).name : "?"); } foreach (int freeId in FreeIds) { a.FreeIds.Add(freeId); } foreach (KeyValuePair<InstanceRenderer, Patch> patch in Patches) { Patch value = patch.Value; if (!value.Grass) { continue; } InstanceRenderer key = patch.Key; AuditPatch auditPatch = new AuditPatch { Name = (((Object)(object)key != (Object)null) ? ((Object)key).name : "(destroyed)"), Position = (((Object)(object)key != (Object)null) ? ((Component)key).transform.position : Vector3.zero), Id = value.Id, Slot = value.Slot, Capacity = value.Capacity, Count = value.Uploaded, Kind = value.Kind.Index, Sphere = new Vector4(value.Center.x, value.Center.y, value.Center.z, value.Radius) }; if ((Object)(object)key != (Object)null && !value.Dirty && InstanceCount.Invoke(key) == value.Uploaded) { Matrix4x4[] array = Matrices.Invoke(key); auditPatch.Rows = (Vector4[])(object)new Vector4[value.Uploaded * 3]; for (int j = 0; j < value.Uploaded; j++) { Matrix4x4 val = array[j]; auditPatch.Rows[j * 3] = new Vector4(val.m00, val.m01, val.m02, val.m03); auditPatch.Rows[j * 3 + 1] = new Vector4(val.m10, val.m11, val.m12, val.m13); auditPatch.Rows[j * 3 + 2] = new Vector4(val.m20, val.m21, val.m22, val.m23); } } a.Patches.Add(auditPatch); } foreach (BuiltPatch value2 in Built.Values) { foreach (Patch item in value2.Drawn) { AddBuilt(a, item); } if (value2.Job == null) { continue; } foreach (Patch replace in value2.Job.Replaces) { AddBuilt(a, replace); } } _audit = a; Read(_patches, a, delegate(PatchGpu[] d) { a.Table = d; }); Read<Vector4>(_objectToWorld, a, (Action<Vector4[]>)delegate(Vector4[] d) { a.ObjectToWorld = d; }); Read<Vector4>(_worldToObject, a, (Action<Vector4[]>)delegate(Vector4[] d) { a.WorldToObject = d; }); Read(_draw, a, delegate(uint[] d) { a.Draw = d; }); Read(_visible, a, delegate(uint[] d) { a.Visible = d; }); Read(_args, a, delegate(uint[] d) { a.Args = d; }); Read<uint>(_kindBase, a, delegate { }); } private static void AddBuilt(Audit a, Patch p) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001d: 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_0090: Unknown result type (might be due to invalid IL or missing references) a.Patches.Add(new AuditPatch { Name = "(built off the main thread)", Position = p.Center, Id = p.Id, Slot = p.Slot, Capacity = p.Capacity, Count = p.Uploaded, Kind = p.Kind.Index, Sphere = new Vector4(p.Center.x, p.Center.y, p.Center.z, p.Radius) }); } private static void Read<T>(GraphicsBuffer buffer, Audit a, Action<T[]> store) where T : struct { //IL_0031: Unknown result type (might be due to invalid IL or missing references) if (buffer == null) { Arrived(a, failed: true); return; } AsyncGPUReadback.Request(buffer, (Action<AsyncGPUReadbackRequest>)delegate(AsyncGPUReadbackRequest req) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) if (!((AsyncGPUReadbackRequest)(ref req)).hasError) { store(((AsyncGPUReadbackRequest)(ref req)).GetData<T>(0).ToArray()); } Arrived(a, ((AsyncGPUReadbackRequest)(ref req)).hasError); }); } private static void Arrived(Audit a, bool failed) { if (failed) { a.Failed++; } if (--a.Pending > 0) { return; } if (_audit == a) { _audit = null; } if (a.Failed > 0) { SteadyFramePlugin.Log.LogInfo((object)$"[grass] GPU buffers check at frame {a.Frame}: {a.Failed} reads failed, skipped"); return; } try { Check(a); } catch (Exception arg) { SteadyFramePlugin.Log.LogError((object)$"[grass] GPU buffers check failed: {arg}"); } } private static void Check(Audit a) { //IL_01cb: Unknown result type (might be due to invalid IL or missing references) //IL_01d0: Unknown result type (might be due to invalid IL or missing references) //IL_01e1: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_01f7: Unknown result type (might be due to invalid IL or missing references) //IL_01fc: Unknown result type (might be due to invalid IL or missing references) //IL_032e: Unknown result type (might be due to invalid IL or missing references) //IL_0333: Unknown result type (might be due to invalid IL or missing references) //IL_0344: Unknown result type (might be due to invalid IL or missing references) //IL_0349: Unknown result type (might be due to invalid IL or missing references) //IL_035a: Unknown result type (might be due to invalid IL or missing references) //IL_035f: Unknown result type (might be due to invalid IL or missing references) //IL_0361: Unknown result type (might be due to invalid IL or missing references) //IL_0363: Unknown result type (might be due to invalid IL or missing references) //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_0367: Unknown result type (might be due to invalid IL or missing references) //IL_0369: Unknown result type (might be due to invalid IL or missing references) //IL_036b: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038b: Unknown result type (might be due to invalid IL or missing references) //IL_0390: Unknown result type (might be due to invalid IL or missing references) //IL_020f: Unknown result type (might be due to invalid IL or missing references) //IL_021c: Unknown result type (might be due to invalid IL or missing references) //IL_0289: Unknown result type (might be due to invalid IL or missing references) //IL_0298: Unknown result type (might be due to invalid IL or missing references) //IL_02a7: Unknown result type (might be due to invalid IL or missing references) //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Unknown result type (might be due to invalid IL or missing references) //IL_03fe: Unknown result type (might be due to invalid IL or missing references) //IL_0405: Unknown result type (might be due to invalid IL or missing references) //IL_040c: Unknown result type (might be due to invalid IL or missing references) //IL_0418: Unknown result type (might be due to invalid IL or missing references) //IL_041f: Unknown result type (might be due to invalid IL or missing references) //IL_0426: Unknown result type (might be due to invalid IL or missing references) //IL_042d: Unknown result type (might be due to invalid IL or missing references) //IL_0432: Unknown result type (might be due to invalid IL or missing references) //IL_043b: Unknown result type (might be due to invalid IL or missing references) //IL_0442: Unknown result type (might be due to invalid IL or missing references) //IL_0449: Unknown result type (might be due to invalid IL or missing references) //IL_0450: Unknown result type (might be due to invalid IL or missing references) //IL_0455: Unknown result type (might be due to invalid IL or missing references) //IL_045e: Unknown result type (might be due to invalid IL or missing references) //IL_0465: Unknown result type (might be due to invalid IL or missing references) //IL_046c: Unknown result type (might be due to invalid IL or missing references) //IL_0473: Unknown result type (might be due to invalid IL or missing references) //IL_0478: Unknown result type (might be due to invalid IL or missing references) //IL_048d: Unknown result type (might be due to invalid IL or missing references) //IL_0491: Unknown result type (might be due to invalid IL or missing references) //IL_0496: Unknown result type (might be due to invalid IL or missing references) //IL_049b: Unknown result type (might be due to invalid IL or missing references) //IL_04a0: Unknown result type (might be due to invalid IL or missing references) //IL_0243: Unknown result type (might be due to invalid IL or missing references) //IL_0252: Unknown result type (might be due to invalid IL or missing references) //IL_04f7: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) Dictionary<string, (int count, StringBuilder text)> problems = new Dictionary<string, (int, StringBuilder)>(); Dictionary<int, AuditPatch> dictionary = new Dictionary<int, AuditPatch>(); long num = 0L; long num2 = 0L; Vector3 val5 = default(Vector3); foreach (AuditPatch patch in a.Patches) { dictionary[patch.Id] = patch; num += patch.Count; PatchGpu patchGpu = a.Table[patch.Id]; uint num3 = (uint)Math.Max(patch.Slot, 0); if ((patchGpu.Flags & 1) == 0 || patchGpu.Count != patch.Count || patchGpu.Slot != num3 || patchGpu.Kind != patch.Kind) { Problem("table", $"{Describe(patch)}: GPU has flags {patchGpu.Flags} count {patchGpu.Count} slot {patchGpu.Slot} kind {patchGpu.Kind}"); } if (patch.Count > 0 && (patch.Slot < 0 || patch.Count > patch.Capacity || patch.Slot + patch.Capacity > a.Capacity)) { Problem("table", $"{Describe(patch)}: allocation out of bounds (buffer {a.Capacity})"); } if (patch.Count == 0 || patch.Slot < 0) { continue; } for (int i = 0; i < patch.Count; i++) { int num4 = (patch.Slot + i) * 3; Vector4 val = a.ObjectToWorld[num4]; Vector4 val2 = a.ObjectToWorld[num4 + 1]; Vector4 val3 = a.ObjectToWorld[num4 + 2]; if (patch.Rows != null) { num2++; if (val != patch.Rows[i * 3] || val2 != patch.Rows[i * 3 + 1] || val3 != patch.Rows[i * 3 + 2]) { Problem("rows", $"{Describe(patch)}, instance {i}: GPU position ({val.w:F2}, {val2.w:F2}, {val3.w:F2}), " + $"game ({patch.Rows[i * 3].w:F2}, {patch.Rows[i * 3 + 1].w:F2}, {patch.Rows[i * 3 + 2].w:F2})"); } } Vector4 w = a.WorldToObject[num4]; Vector4 w2 = a.WorldToObject[num4 + 1]; Vector4 w3 = a.WorldToObject[num4 + 2]; InverseError(val, val2, val3, w, w2, w3, out var linear, out var offset); Vector3 val4 = new Vector3(val.w, val2.w, val3.w); float magnitude = ((Vector3)(ref val4)).magnitude; if (!(linear < 0.001f) || !(offset < 1E-05f * (1f + magnitude))) { Problem("inverse", $"{Describe(patch)}, instance {i}: world-to-object x object-to-world off identity by {linear:G3} (3x3), {offset:G3} m (offset)"); } ((Vector3)(ref val5))..ctor(val.w, val2.w, val3.w); val4 = new Vector3(val.x, val2.x, val3.x); float magnitude2 = ((Vector3)(ref val4)).magnitude; val4 = new Vector3(val.y, val2.y, val3.y); float magnitude3 = ((Vector3)(ref val4)).magnitude; val4 = new Vector3(val.z, val2.z, val3.z); float num5 = Mathf.Max(magnitude2, Mathf.Max(magnitude3, ((Vector3)(ref val4)).magnitude)); val4 = val5 - Vector4.op_Implicit(patch.Sphere); if (((Vector3)(ref val4)).magnitude > patch.Sphere.w + 0.01f || !(num5 < 20f) || !(num5 > 0.01f)) { Problem("sanity", $"{Describe(patch)}, instance {i}: at {val5:F2}, scale {num5:G3}, sphere {patch.Sphere:F1}"); } } } List<AuditPatch> list = new List<AuditPatch>(); foreach (AuditPatch patch2 in a.Patches) { if (patch2.Slot >= 0) { list.Add(patch2); } } list.Sort((AuditPatch x, AuditPatch y) => x.Slot.CompareTo(y.Slot)); for (int num6 = 1; num6 < list.Count; num6++) { if (list[num6 - 1].Slot + list[num6 - 1].Capacity > list[num6].Slot) { Problem("slots", Describe(list[num6 - 1]) + " overlaps " + Describe(list[num6])); } } for (int num7 = 0; num7 < a.IdTop; num7++) { if (!dictionary.ContainsKey(num7) && (a.Table[num7].Flags & 1) != 0) { Problem("table", $"id {num7} (free {a.FreeIds.Contains(num7)}) has no live patch but is active: count {a.Table[num7].Count} slot {a.Table[num7].Slot} kind {a.Table[num7].Kind}"); } } long[] array = new long[a.Kinds]; long num8 = 0L; for (int num9 = 0; num9 < a.IdTop; num9++) { uint num10 = a.Draw[num9 * 4]; uint num11 = a.Draw[num9 * 4 + 1]; uint num12 = a.Draw[num9 * 4 + 2]; if (num11 == 0) { continue; } PatchGpu patchGpu2 = a.Table[num9]; AuditPatch value; string text = (dictionary.TryGetValue(num9, out value) ? Describe(value) : $"id {num9} (no live patch)"); if (patchGpu2.Kind >= a.Kinds) { Problem("draws", $"{text}: kind {patchGpu2.Kind} of {a.Kinds}"); continue; } array[patchGpu2.Kind] += num11; if (num10 != patchGpu2.Slot || num11 > patchGpu2.Count) { Problem("draws", $"{text}: record slot {num10} count {num11}, table slot {patchGpu2.Slot} count {patchGpu2.Count}"); } long num13 = a.Bases[patchGpu2.Kind]; long num14 = num13 + a.Totals[patchGpu2.Kind]; if (num12 < num13 || num12 + num11 > num14 || num12 + num11 > a.Visible.Length) { Problem("draws", $"{text}: places {num12}..{num12 + num11} outside its kind's {num13}..{num14} (visible list {a.Visible.Length})"); continue; } for (uint num15 = 0u; num15 < num11; num15++) { num8++; if (a.Visible[num12 + num15] != num10 + num15) { Problem("visible", $"{text}: visible[{num12 + num15}] = {a.Visible[num12 + num15]}, expected {num10 + num15}"); break; } } } for (int num16 = 0; num16 < a.Kinds; num16++) { uint num17 = a.Args[num16 * 5 + 1]; if (num17 != array[num16] || num17 > a.Totals[num16]) { Problem("args", $"kind {num16} ({a.KindNames[num16]}): draws {num17} instances, records sum {array[num16]}, total {a.Totals[num16]}"); } } string text2 = $"frame {a.Frame}: {a.Patches.Count} patches, {num} instances ({num2} rows compared), " + $"{a.Kinds} kinds, slots {a.Capacity} (grown {a.Regrowths}), {num8} visible entries"; if (problems.Count == 0) { SteadyFramePlugin.Cfg.VerifyGpuGrassBuffers.Agreed(); SteadyFramePlugin.Log.LogInfo((object)("[grass] GPU buffers check " + text2 + ": consistent")); return; } StringBuilder stringBuilder = new StringBuilder(text2); foreach (KeyValuePair<string, (int, StringBuilder)> item in problems) { stringBuilder.Append($"\n {item.Key}: {item.Value.Item1}").Append(item.Value.Item2); } SteadyFramePlugin.Cfg.VerifyGpuGrassBuffers.Diverged(stringBuilder.ToString()); string Describe(AuditPatch p) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) return $"patch id {p.Id} '{p.Name}' at {p.Position:F1}, kind {p.Kind} ({a.KindNames[p.Kind]}), slot {p.Slot} cap {p.Capacity}, count {p.Count}"; } void Problem(string kind, string detail) { if (!problems.TryGetValue(kind, out (int, StringBuilder) value2)) { value2 = (0, new StringBuilder()); } if (value2.Item1 < 8) { value2.Item2.Append("\n ").Append(detail); } problems[kind] = (value2.Item1 + 1, value2.Item2); } } private static void InverseError(Vector4 r0, Vector4 r1, Vector4 r2, Vector4 w0, Vector4 w1, Vector4 w2, out float linear, out float offset) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_001c: 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) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_004f: 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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Unknown result type (might be due to invalid IL or missing references) //IL_008a: 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_0091: Unknown result type (might be due to invalid IL or missing references) Matrix4x4 val = default(Matrix4x4); Matrix4x4 val2 = default(Matrix4x4); ((Matrix4x4)(ref val)).SetRow(0, r0); ((Matrix4x4)(ref val)).SetRow(1, r1); ((Matrix4x4)(ref val)).SetRow(2, r2); ((Matrix4x4)(ref val)).SetRow(3, new Vector4(0f, 0f, 0f, 1f)); ((Matrix4x4)(ref val2)).SetRow(0, w0); ((Matrix4x4)(ref val2)).SetRow(1, w1); ((Matrix4x4)(ref val2)).SetRow(2, w2); ((Matrix4x4)(ref val2)).SetRow(3, new Vector4(0f, 0f, 0f, 1f)); Matrix4x4 val3 = val2 * val; linear = (offset = 0f); for (int i = 0; i < 3; i++) { for (int j = 0; j < 3; j++) { linear = Mathf.Max(linear, Mathf.Abs(((Matrix4x4)(ref val3))[i, j] - ((i == j) ? 1f : 0f))); } offset = Mathf.Max(offset, Mathf.Abs(((Matrix4x4)(ref val3))[i, 3])); } } internal static void Offer(string guid, Func<bool?> wanted, Func<bool> runs = null) { Offers.Add(new object[6] { 5, guid, new Action(Install), wanted, true, runs ?? ((Func<bool>)(() => true)) }); } internal static void Elect() { List<object[]> offers = Offers; if (offers.Count != 0 && AppDomain.CurrentDomain.GetData("ValheimMods.Shared.GpuGrass.elected") == null) { if (Chainloader.PluginInfos.ContainsKey("ru.ivest.steadyframe") && !offers.Exists((object[] o) => (string)o[1] == "ru.ivest.steadyframe")) { AppDomain.CurrentDomain.SetData("ValheimMods.Shared.GpuGrass.elected", "none"); Logger.CreateLogSource("GPU grass").LogInfo((object)"An older SteadyFrame draws the grass on the GPU itself; left to it."); } else { SharedElection.Elect("ValheimMods.Shared.GpuGrass", 5, WithChecks); } } } private static bool WithChecks(object[] offer, object[] best) { if ((bool)offer[4]) { return !(bool)best[4]; } return false; } private static void Install() { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown if (SharedElection.HandedOn("ValheimMods.Shared.GpuGrass", typeof(GpuGrass), 5, WithChecks)) { return; } _log = Logger.CreateLogSource("GPU grass"); _opinions = Offers.ConvertAll((object[] o) => (Func<bool?>)o[3]).ToArray(); Harmony val = new Harmony("ValheimMods.Shared.GpuGrass"); try { Type[] array = new Type[13] { typeof(Patch_CustomUpdate), typeof(Patch_Pass), typeof(Patch_OnEnable), typeof(Patch_OnDisable), typeof(Patch_Clear), typeof(Patch_SetInstance), typeof(Patch_SetInstances), typeof(Patch_SetBillboard), typeof(Patch_Build), typeof(Patch_FreePatch), typeof(Patch_Regenerate), typeof(Patch_PaintCleared), typeof(Patch_HeightmapOff) }; foreach (Type type in array) { val.CreateClassProcessor(type).Patch(); } } catch (Exception ex) { val.UnpatchSelf(); _log.LogWarning((object)("The grass is left to the game: " + ex.Message)); return; } AppDomain.CurrentDomain.SetData("ValheimMods.Shared.GpuGrass.active", (Func<bool>)(() => Active)); AppDomain.CurrentDomain.SetData("ValheimMods.Shared.GpuGrass.around", new Func<Vector3, float, object[]>(BuiltAround)); _log.LogInfo((object)$"The grass can be drawn on the GPU (version {5}; this copy: {typeof(GpuGrass).Assembly.GetName().Name})."); } private static bool Opinion() { bool flag = false; Func<bool?>[] opinions = _opinions; foreach (Func<bool?> func in opinions) { bool? flag2 = null; try { flag2 = func(); } catch { } if (flag2 == false) { return false; } flag |= flag2 == true; } return flag; } internal static Material CopyOf(InstanceRenderer r) { if (!Patches.TryGetValue(r, out var value) || !value.Grass) { return null; } return value.Kind.Copy; } private static bool Init() { //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Expected O, but got Unknown //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00c2: Expected O, but got Unknown //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Expected O, but got Unknown //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: Expected O, but got Unknown //IL_011f: Unknown result type (might be due to invalid IL or missing references) string text = GrassBundle.Load(); if (text != null) { GrassBundle.Unload(); _log.LogWarning((object)("[grass] GPU drawing unavailable (" + text + "); grass drawn the game's way.")); return false; } for (int i = 0; i < 7; i++) { Free[i] = new Stack<int>(); } ComputeShader kernels = GrassBundle.Kernels; _cull = kernels.FindKernel("Cull"); _expand = kernels.FindKernel("Expand"); _invert = kernels.FindKernel("Invert"); _copy = kernels.FindKernel("Copy"); _patches = new GraphicsBuffer((Target)16, 16384, Marshal.SizeOf<PatchGpu>()); _patches.SetData((Array)new PatchGpu[16384]); _state = new GraphicsBuffer((Target)16, 16384, 8); _draw = new GraphicsBuffer((Target)16, 16384, 16); _args = new GraphicsBuffer((Target)256, 1280, 4); _kindBase = new GraphicsBuffer((Target)16, 256, 4); _layer = LayerMask.NameToLayer("InstanceRenderer"); Grow(524288); _log.LogInfo((object)$"[grass] GPU drawing ready ({SystemInfo.graphicsDeviceType})"); return true; } internal static void ResetState() { //IL_0180: Unknown result type (might be due to invalid IL or missing references) _ready = false; _tried = false; GraphicsBuffer[] array = (GraphicsBuffer[])(object)new GraphicsBuffer[9] { _objectToWorld, _worldToObject, _visible, _invertRecords, _patches, _state, _draw, _args, _kindBase }; foreach (GraphicsBuffer obj in array) { if (obj != null) { obj.Release(); } } _objectToWorld = (_worldToObject = (_visible = (_invertRecords = (_patches = (_state = (_draw = (_args = (_kindBase = null)))))))); foreach (Kind kind in KindList) { if ((Object)(object)kind.Copy != (Object)null) { Object.Destroy((Object)(object)kind.Copy); } } Patches.Clear(); Kinds.Clear(); KindList.Clear(); FreeKinds.Clear(); GrassMaterials.Clear(); FreeIds.Clear(); _idTop = (_top = (_capacity = (_visibleCapacity = (_invertRecordCapacity = (_inverts = (_sliceAt = 0)))))); _kindsDirty = true; if (Built.Count > 0 && (Object)(object)ClutterSystem.instance != (Object)null) { ClutterSystem.instance.ResetGrass(Vector3.zero, float.MaxValue); } _activeLast = (_lean = (_buildLast = (_buildOn = false))); LeftToGame.Clear(); Changed.Clear(); PassList.Clear(); InPass.Clear(); ClearBuilt(onCard: false); GrassBundle.Unload(); GrassCheck.ResetState(); GrassSnapshot.ResetState(); } private static void Grow(int capacity) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Expected O, but got Unknown //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Expected O, but got Unknown GraphicsBuffer objectToWorld = _objectToWorld; GraphicsBuffer worldToObject = _worldToObject; int capacity2 = _capacity; _capacity = capacity; _objectToWorld = new GraphicsBuffer((Target)16, capacity * 3, 16); _worldToObject = new GraphicsBuffer((Target)16, capacity * 3, 16); if (objectToWorld != null) { ComputeShader kernels = GrassBundle.Kernels; kernels.SetInt("_CopyCount", capacity2 * 3); kernels.SetBuffer(_copy, "_CopySource", objectToWorld); kernels.SetBuffer(_copy, "_CopyDest", _objectToWorld); kernels.Dispatch(_copy, Math.Min(4096, (capacity2 * 3 + 255) / 256), 1, 1); kernels.SetBuffer(_copy, "_CopySource", worldToObject); kernels.SetBuffer(_copy, "_CopyDest", _worldToObject); kernels.Dispatch(_copy, Math.Min(4096, (capacity2 * 3 + 255) / 256), 1, 1); objectToWorld.Release(); worldToObject.Release(); } Shader.SetGlobalBuffer("_GrassObjectToWorld", _objectToWorld); Shader.SetGlobalBuffer("_GrassWorldToObject", _worldToObject); } private static int ClassOf(int count) { int i; for (i = 0; 1 << i + 4 < count; i++) { } return i; } private static void Allocate(Patch p, int count) { int num = ClassOf(count); int num2 = 1 << num + 4; if (Free[num].Count > 0) { p.Slot = Free[num].Pop(); p.Capacity = num2; return; } if (_top + num2 > _capacity) { _regrowths++; Grow(_capacity * 2); } p.Slot = _top; p.Capacity = num2; _top += num2; } private static void Deallocate(Patch p) { if (p.Slot >= 0) { Free[ClassOf(p.Capacity)].Push(p.Slot); } p.Slot = -1; p.Capacity = 0; } private static bool IsGrass(Material m) { if (!GrassMaterials.TryGetValue(m, out var value)) { value = (Object)(object)m.shader != (Object)null && ((Object)m.shader).name == "Custom/Grass"; GrassMaterials[m] = value; } return value; } private static bool Before(InstanceRenderer r) { //IL_00cb: Unknown result type (might be due to invalid IL or missing references) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) if (!_ready) { return true; } if (!Patches.TryGetValue(r, out var value)) { value = Register(r); Patches.Add(r, value); if (!value.Grass) { LeftToGame.Add((IMonoUpdater)(object)r); } } if (!value.Grass) { return true; } if (value.Kind.Gone) { return false; } int num = InstanceCount.Invoke(r); if (value.Dirty || num != value.Uploaded) { if ((Object)(object)r.m_mesh == (Object)null) { return false; } Upload(value, r, num); } if (!Active) { return true; } if (value.StateDirty) { OneState[0] = new Vector2(LodCount.Invoke(r), FirstFrame.Invoke(r) ? 1f : 0f); _state.SetData((Array)OneState, 0, value.Id, 1); value.StateDirty = false; } return GameLogicToo; } private static Patch Register(InstanceRenderer r) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) Patch patch = new Patch(); if ((Object)(object)r.m_mesh == (Object)null || (Object)(object)r.m_material == (Object)null || !IsGrass(r.m_material)) { return patch; } Kind kind = KindFor(r.m_mesh, r.m_material, r.m_shadowCasting); if (kind != null) { Join(patch, kind); } return patch; } private static Kind KindFor(Mesh mesh, Material material, ShadowCastingMode shadows) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: 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) //IL_00bc: 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) //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Expected O, but got Unknown //IL_00f7: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Expected O, but got Unknown KindKey key = new KindKey(mesh, material, shadows, _layer); if (Kinds.TryGetValue(key, out var value)) { return value; } if (FreeKinds.Count == 0 && KindList.Count == 256) { _overflow++; return null; } Kind obj = new Kind { Mesh = mesh, Original = material, Shadows = shadows, Layer = _layer, Index = ((FreeKinds.Count > 0) ? FreeKinds.Pop() : KindList.Count), Key = key, Name = ((Object)mesh).name }; Bounds bounds = mesh.bounds; Vector3 extents = ((Bounds)(ref bounds)).extents; obj.Extent = ((Vector3)(ref extents)).magnitude; obj.Copy = new Material(material) { shader = GrassBundle.Shader, name = ((Object)material).name + " (GPU grass)" }; obj.Block = new MaterialPropertyBlock(); value = obj; value.Copy.CopyPropertiesFromMaterial(material); Kinds.Add(key, value); if (value.Index == KindList.Count) { KindList.Add(value); } else { KindList[value.Index] = value; } return value; } private static bool Join(Patch p, Kind k) { if (FreeIds.Count > 0) { p.Id = FreeIds.Pop(); } else { if (_idTop >= 16384) { _overflow++; return false; } p.Id = _idTop++; } p.Grass = true; p.Kind = k; p.Member = k.Members.Count; k.Members.Add(p); return true; } private static void Upload(Patch p, InstanceRenderer r, int total) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_0072: 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) //IL_0087: 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_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00bb: Unknown result type (might be due to invalid IL or missing references) //IL_00c0: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ca: 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) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_00ee: Unknown result type (might be due to invalid IL or missing references) //IL_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fc: 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_010a: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011f: Unknown result type (might be due to invalid IL or missing references) //IL_0126: Unknown result type (might be due to invalid IL or missing references) //IL_012d: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0150: Unknown result type (might be due to invalid IL or missing references) //IL_0157: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Unknown result type (might be due to invalid IL or missing references) //IL_0171: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_0186: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) //IL_0195: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01a2: Unknown result type (might be due to invalid IL or missing references) //IL_01a4: Unknown result type (might be due to invalid IL or missing references) //IL_01a9: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) Matrix4x4[] array = Matrices.Invoke(r); Bounds bounds = r.m_mesh.bounds; Vector3 val = ((Bounds)(ref bounds)).extents; float magnitude = ((Vector3)(ref val)).magnitude; Vector3 val2 = default(Vector3); ((Vector3)(ref val2))..ctor(9999999f, 9999999f, 9999999f); Vector3 val3 = default(Vector3); ((Vector3)(ref val3))..ctor(-9999999f, -9999999f, -9999999f); Vector3 val5 = default(Vector3); for (int i = 0; i < total; i++) { Matrix4x4 val4 = array[i]; ((Vector3)(ref val5))..ctor(val4.m03, val4.m13, val4.m23); Vector3 lossyScale = ((Matrix4x4)(ref val4)).lossyScale; float num = Mathf.Max(Mathf.Max(lossyScale.x, lossyScale.y), lossyScale.z) * magnitude; val2 = Vector3.Min(val2, val5 - Vector3.one * num); val3 = Vector3.Max(val3, val5 + Vector3.one * num); Rows[i * 3] = new Vector4(val4.m00, val4.m01, val4.m02, val4.m03); Rows[i * 3 + 1] = new Vector4(val4.m10, val4.m11, val4.m12, val4.m13); Rows[i * 3 + 2] = new Vector4(val4.m20, val4.m21, val4.m22, val4.m23); } Vector3 val6 = (val2 + val3) * 0.5f; Vector4[] rows = Rows; val = val3 - val6; Store(p, rows, 0, total, val6, ((Vector3)(ref val)).magnitude, ((Component)r).transform.position, r.m_lodMinDistance, r.m_lodMaxDistance, FlagsOf(r)); } private static uint FlagsOf(InstanceRenderer r) { return (uint)(1 | (r.m_frustumCull ? 2 : 0) | (r.m_useLod ? 4 : 0) | (r.m_useXZLodDistance ? 8 : 0)); } private static void Store(Patch p, Vector4[] rows, int firstRow, int total, Vector3 center, float radius, Vector3 at, float lodMin, float lodMax, uint flags) { //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_012e: Unknown result type (might be due to invalid IL or missing references) //IL_0133: 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_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0148: 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_0156: Unknown result type (might be due to invalid IL or missing references) if (total > 0 && (p.Slot < 0 || total > p.Capacity)) { Deallocate(p); Allocate(p, total); } if (total > 0) { _objectToWorld.SetData((Array)rows, firstRow, p.Slot * 3, total * 3); if (_inverts * 4 + 4 > _invertData.Length) { Array.Resize(ref _invertData, _invertData.Length * 2); } _invertData[_inverts * 4] = (uint)p.Slot; _invertData[_inverts * 4 + 1] = (uint)total; _inverts++; } p.Center = center; p.Radius = radius; p.Kind.Total += total - p.Uploaded; p.Kind.BoundsDirty = true; _kindsDirty = true; p.Uploaded = total; p.Dirty = false; _uploads++; _uploadedInstances += total; OnePatch[0] = new PatchGpu { Sphere = new Vector4(p.Center.x, p.Center.y, p.Center.z, p.Radius), Position = new Vector4(at.x, at.y, at.z, lodMin), LodMax = lodMax, Flags = flags, Count = (uint)total, Slot = (uint)Math.Max(p.Slot, 0), Kind = (uint)p.Kind.Index }; _patches.SetData((Array)OnePatch, 0, p.Id, 1); } private static void Forget(InstanceRenderer r) { if (_ready && Patches.TryGetValue(r, out var value)) { Patches.Remove(r); if (!value.Grass) { LeftToGame.Remove((IMonoUpdater)(object)r); } else { ForgetPatch(value); } } } private static void ForgetPatch(Patch p) { OnePatch[0] = default(PatchGpu); _patches.SetData((Array)OnePatch, 0, p.Id, 1); FreeIds.Push(p.Id); Deallocate(p); Kind kind = p.Kind; kind.Total -= p.Uploaded; Patch patch = kind.Members[kind.Members.Count - 1]; kind.Members[p.Member] = patch; patch.Member = p.Member; kind.Members.RemoveAt(kind.Members.Count - 1); kind.BoundsDirty = true; _kindsDirty = true; } private static void Touch(InstanceRenderer r) { if (Patches.TryGetValue(r, out var value) && value.Grass) { if (!value.Dirty && _activeLast) { Changed.Add(r); } value.Dirty = true; } } private static void Born(InstanceRenderer r) { if (_activeLast) { Changed.Add(r); } } public static void Draw(Mesh mesh, int submesh, Material material, Matrix4x4[] matrices, int count, MaterialPropertyBlock props, ShadowCastingMode shadows, bool receive, int layer, InstanceRenderer self) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) Patch value = null; if (!Active || !Patches.TryGetValue(self, out value) || !value.Grass) { Graphics.DrawMeshInstanced(mesh, submesh, material, matrices, count, props, shadows, receive, layer); } else if (GrassCheck.Frame) { GrassCheck.DrawGame(mesh, material, value.Kind.Copy, matrices, count, shadows, receive, layer); } } private static void BeginPass() { _lean = false; _wanted = Opinion(); if (!Wanted) { if (_tried) { ResetState(); } _activeLast = false; _buildOn = false; return; } if (!_tried) { _tried = true; _ready = Init(); } bool active = Active; if (active && !_activeLast) { foreach (Patch value in Patches.Values) { value.StateDirty = true; } } BuildPass(active); _lean = active && _activeLast && !GameLogicToo; _activeLast = active; if (_lean) { GatherPass(); } else { Changed.Clear(); } if (active) { GrassCheck.BeginPass(); } } private static void GatherPass() { //IL_0108: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Expected O, but got Unknown PassList.Clear(); InPass.Clear(); foreach (IMonoUpdater item in LeftToGame) { PassList.Add(item); InPass.Add(item); } foreach (InstanceRenderer item2 in Changed) { if ((Object)(object)item2 != (Object)null && ((Behaviour)item2).isActiveAndEnabled && InPass.Add((IMonoUpdater)(object)item2)) { PassList.Add((IMonoUpdater)(object)item2); } } Changed.Clear(); List<IMonoUpdater> instances = InstanceRenderer.Instances; for (int num = ((instances.Count != 0) ? (instances.Count / 64 + 1) : 0); num > 0; num--) { if (_sliceAt >= instances.Count) { _sliceAt = 0; } InstanceRenderer val = (InstanceRenderer)instances[_sliceAt++]; if ((!Patches.TryGetValue(val, out var value) || (value.Grass && (value.Dirty || InstanceCount.Invoke(val) != value.Uploaded))) && InPass.Add((IMonoUpdater)(object)val)) { PassList.Add((IMonoUpdater)(object)val); } } } public static void AddToPass(List<IMonoUpdater> container, IEnumerable<IMonoUpdater> source) { IEnumerable<IMonoUpdater> collection; if (!_lean || source != InstanceRenderer.Instances) { collection = source; } else { IEnumerable<IMonoUpdater> passList = PassList; collection = passList; } container.AddRange(collection); } private static void Ensure(ref GraphicsBuffer buffer, ref int capacity, int needed, int stride, string global) { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Expected O, but got Unknown if (buffer == null || capacity < needed) { GraphicsBuffer obj = buffer; if (obj != null) { obj.Release(); } capacity = Math.Max(needed, Math.Max(capacity * 2, 1024)); buffer = new GraphicsBuffer((Target)16, capacity, stride); if (global != null) { Shader.SetGlobalBuffer(global, buffer); } } } private static void EndPass(float deltaTime) { //IL_0303: Unknown result type (might be due to invalid IL or missing references) //IL_0315: Unknown result type (might be due to invalid IL or missing references) //IL_0327: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_0343: Unknown result type (might be due to invalid IL or missing references) //IL_0359: Unknown result type (might be due to invalid IL or missing references) //IL_035e: Unknown result type (might be due to invalid IL or missing references) //IL_0376: Unknown result type (might be due to invalid IL or missing references) //IL_037d: Unknown result type (might be due to invalid IL or missing references) //IL_0384: Unknown result type (might be due to invalid IL or missing references) //IL_038c: Unknown result type (might be due to invalid IL or missing references) //IL_05ac: Unknown result type (might be due to invalid IL or missing references) //IL_05b1: Unknown result type (might be due to invalid IL or missing references) //IL_05b7: Unknown result type (might be due to invalid IL or missing references) //IL_05d3: Unknown result type (might be due to invalid IL or missing references) //IL_04a1: Unknown result type (might be due to invalid IL or missing references) //IL_04ab: Unknown result type (might be due to invalid IL or missing references) //IL_04b0: Unknown result type (might be due to invalid IL or missing references) //IL_04b2: Unknown result type (might be due to invalid IL or missing references) //IL_04bc: Unknown result type (might be due to invalid IL or missing references) //IL_04c1: Unknown result type (might be due to invalid IL or missing references) //IL_06a3: Unknown result type (might be due to invalid IL or missing references) //IL_0621: Unknown result type (might be due to invalid IL or missing references) //IL_0623: Unknown result type (might be due to invalid IL or missing references) //IL_04e5: Unknown result type (might be due to invalid IL or missing references) //IL_04e9: Unknown result type (might be due to invalid IL or missing references) //IL_04ee: Unknown result type (might be due to invalid IL or missing references) //IL_04fa: Unknown result type (might be due to invalid IL or missing references) //IL_04ff: Unknown result type (might be due to invalid IL or missing references) //IL_0504: Unknown result type (might be due to invalid IL or missing references) //IL_0509: Unknown result type (might be due to invalid IL or missing references) //IL_050b: Unknown result type (might be due to invalid IL or missing references) //IL_050f: Unknown result type (might be due to invalid IL or missing references) //IL_0514: Unknown result type (might be due to invalid IL or missing references) //IL_0520: Unknown result type (might be due to invalid IL or missing references) //IL_0525: 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_052f: Unknown result type (might be due to invalid IL or missing references) //IL_054c: Unknown result type (might be due to invalid IL or missing references) //IL_054e: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_055a: Unknown result type (might be due to invalid IL or missing references) //IL_055f: Unknown result type (might be due to invalid IL or missing references) //IL_0561: Unknown result type (might be due to invalid IL or missing references) //IL_0563: Unknown result type (might be due to invalid IL or missing references) //IL_0568: Unknown result type (might be due to invalid IL or missing references) //IL_056d: Unknown result type (might be due to invalid IL or missing references) if (!_ready) { return; } ComputeShader kernels = GrassBundle.Kernels; if (_inverts > 0) { Ensure(ref _invertRecords, ref _invertRecordCapacity, _inverts, 16, null); _invertRecords.SetData((Array)_invertData, 0, 0, _inverts * 4); kernels.SetBuffer(_invert, "_Records", _invertRecords); kernels.SetBuffer(_invert, "_ObjectToWorld", _objectToWorld); kernels.SetBuffer(_invert, "_WorldToObject", _worldToObject); kernels.SetInt("_RecordCount", _inverts); kernels.Dispatch(_invert, _inverts, 1, 1); _inverts = 0; } if (!Active || _idTop == 0) { return; } Camera mainCamera = Utils.GetMainCamera(); Plane[] mainCameraFrustumPlanes = Utils.GetMainCameraFrustumPlanes(); if ((Object)(object)mainCamera == (Object)null || mainCameraFrustumPlanes == null) { return; } _frames++; int count = KindList.Count; if (_kindsDirty) { long num = 0L; for (int i = 0; i < count; i++) { KindList[i].Base = (int)num; KindBases[i] = (uint)num; num += KindList[i].Total; } _kindBase.SetData((Array)KindBases, 0, 0, count); Ensure(ref _visible, ref _visibleCapacity, (int)Math.Max(num, 1L), 4, "_GrassVisible"); _kindsDirty = false; } for (int j = 0; j < count; j++) { Kind kind = KindList[j]; if (!kind.Gone && ((Object)(object)kind.Mesh == (Object)null || (Object)(object)kind.Original == (Object)null)) { kind.Gone = true; _log.LogInfo((object)("[grass] the mesh or material of grass '" + kind.Name + "' was destroyed (another mod's grass?); " + $"its {kind.Members.Count} patches are no longer drawn")); } if (kind.Gone) { if (!kind.Retired && kind.Members.Count == 0) { Kinds.Remove(kind.Key); if ((Object)(object)kind.Copy != (Object)null) { Object.Destroy((Object)(object)kind.Copy); } kind.Retired = true; FreeKinds.Push(kind.Index); } Array.Clear(ArgsData, j * 5, 5); } else { Mesh mesh = kind.Mesh; ArgsData[j * 5] = mesh.GetIndexCount(0); ArgsData[j * 5 + 1] = 0u; ArgsData[j * 5 + 2] = mesh.GetIndexStart(0); ArgsData[j * 5 + 3] = mesh.GetBaseVertex(0); ArgsData[j * 5 + 4] = 0u; } } _args.SetData((Array)ArgsData, 0, 0, count * 5); for (int k = 0; k < 6; k++) { Planes[k] = new Vector4(((Plane)(ref mainCameraFrustumPlanes[k])).normal.x, ((Plane)(ref mainCameraFrustumPlanes[k])).normal.y, ((Plane)(ref mainCameraFrustumPlanes[k])).normal.z, ((Plane)(ref mainCameraFrustumPlanes[k])).distance); } Vector3 position = ((Component)mainCamera).transform.position; kernels.SetVectorArray("_Planes", Planes); kernels.SetVector("_Camera", new Vector4(position.x, position.y, position.z, deltaTime)); kernels.SetInt("_PatchCount", _idTop); kernels.SetBuffer(_cull, "_Patches", _patches); kernels.SetBuffer(_cull, "_State", _state); kernels.SetBuffer(_cull, "_Draw", _draw); kernels.SetBuffer(_cull, "_Args", _args); kernels.SetBuffer(_cull, "_KindBase", _kindBase); kernels.Dispatch(_cull, (_idTop + 63) / 64, 1, 1); kernels.SetBuffer(_expand, "_Draw", _draw); kernels.SetBuffer(_expand, "_Visible", _visible); kernels.Dispatch(_expand, _idTop, 1, 1); foreach (Kind kind2 in KindList) { if (kind2.Total == 0L || kind2.Gone) { continue; } if (kind2.BoundsDirty) { Vector3 val = Vector3.one * float.MaxValue; Vector3 val2 = Vector3.one * float.MinValue; foreach (Patch member in kind2.Members) { if (member.Uploaded != 0) { val = Vector3.Min(val, member.Center - Vector3.one * member.Radius); val2 = Vector3.Max(val2, member.Center + Vector3.one * member.Radius); } } kind2.Bounds = new Bounds((val + val2) * 0.5f, val2 - val); kind2.BoundsDirty = false; } kind2.Copy.CopyPropertiesFromMaterial(kind2.Original); kind2.Block.SetInteger(GrassFirst, kind2.Base); RenderParams val3 = new RenderParams(kind2.Copy); ((RenderParams)(ref val3)).worldBounds = kind2.Bounds; ((RenderParams)(ref val3)).matProps = kind2.Block; ((RenderParams)(ref val3)).shadowCastingMode = kind2.Shadows; ((RenderParams)(ref val3)).receiveShadows = true; ((RenderParams)(ref val3)).layer = kind2.Layer; ((RenderParams)(ref val3)).camera = (GrassCheck.Frame ? GrassCheck.Gpu : null); ((RenderParams)(ref val3)).lightProbeUsage = (LightProbeUsage)1; ((RenderParams)(ref val3)).reflectionProbeUsage = (ReflectionProbeUsage)1; ((RenderParams)(ref val3)).motionVectorMode = (MotionVectorGenerationMode)0; RenderParams val4 = val3; Graphics.RenderMeshIndirect(ref val4, kind2.Mesh, _args, 1, kind2.Index); } AuditIfDue(); if (_readbackPending || !(Time.realtimeSinceStartup >= _nextReport)) { return; } _readbackPending = true; AsyncGPUReadback.Request(_args, count * 20, 0, (Action<AsyncGPUReadbackRequest>)delegate(AsyncGPUReadbackRequest req) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0018: Unknown result type (might be due to invalid IL or missing references) _readbackPending = false; if (!((AsyncGPUReadbackRequest)(ref req)).hasError) { NativeArray<uint> data = ((AsyncGPUReadbackRequest)(ref req)).GetData<uint>(0); uint num2 = 0u; for (int l = 0; l < data.Length / 5; l++) { num2 += data[l * 5 + 1]; } _lastDrawn = num2; } }); } internal static void LateTick() { if (_ready) { bool frame = GrassCheck.Frame; GrassCheck.LateUpdate(); GrassSnapshot.LateUpdate(Active, frame); if (!(Time.realtimeSinceStartup < _nextReport) && (GameLogicToo || GrassCheck.BuffersCheck)) { _nextReport = Time.realtimeSinceStartup + 600f; _log.LogInfo((object)(string.Format("[grass] GPU drawing {0}: patches {1} in {2} kinds, ", Active ? "on" : "off", _idTop - FreeIds.Count, KindList.Count - FreeKinds.Count) + $"slots {_top}/{_capacity} (grown {_regrowths}), uploads {_uploads} ({_uploadedInstances} instances), " + $"{_lastDrawn} instances drawn in the last sampled frame, {_frames} frames, over limits {_overflow}")); } } } private static void BuildPass(bool on) { //IL_007e: Unknown result type (might be due to invalid IL or missing references) ClutterSystem instance = ClutterSystem.instance; if (instance != _buildFor) { ClearBuilt(onCard: true); _buildFor = instance; _buildLast = false; } bool flag = on && !GameLogicToo && !BuildPaused && !_buildBroken && (Object)(object)instance != (Object)null && !instance.m_menuHack && !ForeignBuild(instance); if (flag != _buildLast) { _buildLast = flag; if (!flag && Built.Count > 0 && (Object)(object)instance != (Object)null) { instance.ResetGrass(Vector3.zero, float.MaxValue); } } _buildOn = flag; if (on && (Waiting.Count > 0 || Built.Count > 0)) { PumpBuild(); } } private static bool ForeignBuild(ClutterSystem cs) { if (_foreignChecked == cs) { return _foreign; } _foreignChecked = cs; HashSet<string> hashSet = new HashSet<string>(); MethodBase[] array = new MethodBase[3] { AccessTools.Method(typeof(ClutterSystem), "GenerateVegPatch", (Type[])null, (Type[])null), AccessTools.Method(typeof(InstanceRenderer), "AddInstance", new Type[3] { typeof(Vector3), typeof(Quaternion), typeof(float) }, (Type[])null), AccessTools.Method(typeof(InstanceRenderer), "AddInstance", new Type[1] { typeof(Matrix4x4) }, (Type[])null) }; foreach (MethodBase methodBase in array) { Patches val = ((methodBase == null) ? null : Harmony.GetPatchInfo(methodBase)); if (val == null) { continue; } foreach (string owner in val.Owners) { if (owner != "ValheimMods.Shared.GpuGrass" && !owner.StartsWith("farlands.stand")) { hashSet.Add(owner); } } } _foreign = hashSet.Count > 0; if (_foreign) { _log.LogWarning((object)("[grass] patches are left to the game's build: " + string.Join(", ", hashSet) + " patch it")); } return _foreign; } private static void PumpBuild() { float num = ((Waiting.Count + ToBuild.Count + Finished.Count > 64) ? 2f : 0.25f); long started = Stopwatch.GetTimestamp(); while (Waiting.Count > 0 && Spent() < (double)num) { BuildJob buildJob = Waiting.Dequeue(); if (Current(buildJob)) { Prepare(buildJob); if (_worker == null) { _worker = new Thread(WorkerLoop) { IsBackground = true, Name = "GPU grass build", Priority = ThreadPriority.BelowNormal }; _worker.Start(); } lock (ToBuild) { ToBuild.Enqueue(buildJob); Monitor.Pulse(ToBuild); } } } do { BuildJob buildJob2; lock (Finished) { if (Finished.Count == 0) { break; } buildJob2 = Finished.Dequeue(); } if (buildJob2.Error != null && !_buildBroken) { _buildBroken = true; _log.LogWarning((object)$"[grass] building a patch failed, patches are the game's again: {buildJob2.Error}"); } if (Current(buildJob2)) { Apply(buildJob2); } } while (Spent() < (double)num); double Spent() { return (double)(Stopwatch.GetTimestamp() - started) * 1000.0 / (double)Stopwatch.Frequency; } } private static bool Current(BuildJob job) { if (Built.TryGetValue(job.Owner, out var value)) { return value.Job == job; } return false; } private static void Apply(BuildJob job) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007e: 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_008d: 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_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: 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_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00f4: Unknown result type (might be due to invalid IL or missing references) //IL_0120: Unknown result type (might be due to invalid IL or missing references) //IL_0125: Unknown result type (might be due to invalid IL or missing references) BuiltPatch builtPatch = Built[job.Owner]; builtPatch.Job = null; if (job.Error == null) { for (int i = 0; i < job.Kinds.Length; i++) { int num = job.Count[i]; BuildKind buildKind = job.Kinds[i]; if (num != 0 && !buildKind.Kind.Gone) { Patch patch = new Patch(); if (Join(patch, buildKind.Kind)) { Vector3 val = (job.Min[i] + job.Max[i]) * 0.5f; Vector3 val2 = job.Max[i] - val; float magnitude = ((Vector3)(ref val2)).magnitude; Store(patch, job.Rows, job.First[i] * 3, num, val, magnitude, new Vector3((float)((Vector2Int)(ref job.Cell)).x * job.Size, 0f, (float)((Vector2Int)(ref job.Cell)).y * job.Size), buildKind.LodMin, buildKind.LodMax, buildKind.Flags); OneState[0] = new Vector2(0f, 1f); _state.SetData((Array)OneState, 0, patch.Id, 1); patch.StateDirty = false; builtPatch.Drawn.Add(patch); } } } } if (job.Error == null) { builtPatch.Kinds = job.Kinds; builtPatch.First = job.First; builtPatch.Count = job.Count; builtPatch.Rows = job.Rows; builtPatch.Size = job.Size; } foreach (Patch replace in job.Replaces) { ForgetPatch(replace); } job.Rows = null; } private static object[] BuiltAround(Vector3 point, float radius) { //IL_004a: 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_00d9: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Unknown result type (might be due to invalid IL or missing references) //IL_00ef: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0100: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012c: 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_0148: Unknown result type (might be due to invalid IL or missing references) //IL_0156: Unknown result type (might be due to invalid IL or missing references) //IL_0164: Unknown result type (might be due to invalid IL or missing references) //IL_0172: Unknown result type (might be due to invalid IL or missing references) //IL_0180: Unknown result type (might be due to invalid IL or missing references) //IL_018e: Unknown result type (might be due to invalid IL or missing references) //IL_019c: Unknown result type (might be due to invalid IL or missing references) //IL_01aa: Unknown result type (might be due to invalid IL or missing references) //IL_01c2: Unknown result type (might be due to invalid IL or missing references) //IL_01c4: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) List<object> list = new List<object>(); foreach (BuiltPatch value in Built.Values) { if (value.Rows == null) { continue; } float num = radius + value.Size; float num2 = (float)((Vector2Int)(ref value.Cell)).x * value.Size - point.x; float num3 = (float)((Vector2Int)(ref value.Cell)).y * value.Size - point.z; if (num2 * num2 + num3 * num3 > num * num) { continue; } for (int i = 0; i < value.Kinds.Length; i++) { int num4 = value.Count[i]; Kind kind = value.Kinds[i].Kind; if (num4 != 0 && !kind.Gone) { Matrix4x4[] array = (Matrix4x4[])(object)new Matrix4x4[num4]; int num5 = 0; int num6 = value.First[i] * 3; while (num5 < num4) { Vector4 val = value.Rows[num6]; Vector4 val2 = value.Rows[num6 + 1]; Vector4 val3 = value.Rows[num6 + 2]; array[num5] = new Matrix4x4 { m00 = val.x, m01 = val.y, m02 = val.z, m03 = val.w, m10 = val2.x, m11 = val2.y, m12 = val2.z, m13 = val2.w, m20 = val3.x, m21 = val3.y, m22 = val3.z, m23 = val3.w, m33 = 1f }; num5++; num6 += 3; } list.Add(new object[4] { kind.Mesh, kind.Original, kind.Shadows, array }); } } } return list.ToArray(); } private static void Freed(object owner) { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Unknown result type (might be due to invalid IL or missing references) if (!Built.TryGetValue(owner, out var value)) { return; } Built.Remove(owner); int num; if (BuiltCells.TryGetValue(value.Cell, out var value2)) { num = ((value2 != value) ? 1 : 0); if (num != 0) { goto IL_004e; } } else { num = 0; } BuiltCells.Remove(value.Cell); goto IL_004e; IL_004e: if (num != 0 && value2.Job != null) { value2.Job.Replaces.AddRange(value.Drawn); if (value.Job != null) { value2.Job.Replaces.AddRange(value.Job.Replaces); } } else { foreach (Patch item in value.Drawn) { ForgetPatch(item); } if (value.Job != null) { foreach (Patch replace in value.Job.Replaces) { ForgetPatch(replace); } } } value.Job = null; } private static void ClearBuilt(bool onCard) { if (onCard && _ready) { foreach (BuiltPatch value in Built.Values) { foreach (Patch item in value.Drawn) { ForgetPatch(item); } if (value.Job == null) { continue; } foreach (Patch replace in value.Job.Replaces) { ForgetPatch(replace); } } } Built.Clear(); BuiltCells.Clear(); Copies.Clear(); Waiting.Clear(); lock (ToBuild) { ToBuild.Clear(); } lock (Finished) { Finished.Clear(); } _buildKindsFrame = -1; } private static void RefreshKinds(ClutterSystem cs) { //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) //IL_011c: Unknown result type (might be due to invalid IL or missing references) //IL_0130: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Invalid comparison between Unknown and I4 //IL_013f: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Invalid comparison between Unknown and I4 if (_buildKindsFrame == Time.frameCount) { return; } _buildKindsFrame = Time.frameCount; KindsNow.Clear(); Quality val = Quality.Invoke(cs); float num = cs.m_distance - cs.m_grassPatchSize / 2f; for (int i = 0; i < cs.m_clutter.Count; i++) { Clutter val2 = cs.m_clutter[i]; if (!val2.m_enabled || !val2.m_instanced || (Object)(object)val2.m_prefab == (Object)null) { continue; } InstanceRenderer component = val2.m_prefab.GetComponent<InstanceRenderer>(); if (!((Object)(object)component == (Object)null) && !((Object)(object)component.m_mesh == (Object)null) && !((Object)(object)component.m_material == (Object)null) && IsGrass(component.m_material)) { Kind kind = KindFor(component.m_mesh, component.m_material, component.m_shadowCasting); if (kind != null && !kind.Gone) { KindsNow.Add(new BuildKind { Kind = kind, Index = i, Scale = component.m_scale, Extent = kind.Extent, Biome = val2.m_biome, Amount = (int)((float)(((int)val == 1) ? (val2.m_amount / 4) : (((int)val == 2) ? (val2.m_amount / 2) : val2.m_amount)) * cs.m_amountScale), LodMin = component.m_lodMinDistance, LodMax = Mathf.Min(component.m_lodMaxDistance, num), Flags = FlagsOf(component), InForest = val2.m_inForest, ForestMin = val2.m_forestTresholdMin, ForestMax = val2.m_forestTresholdMax, FractalScale = val2.m_fractalScale, FractalOffset = val2.m_fractalOffset, FractalMin = val2.m_fractalTresholdMin, FractalMax = val2.m_fractalTresholdMax, MinAlt = val2.m_minAlt, MaxAlt = val2.m_maxAlt, MinNormal = Mathf.Cos(MathF.PI / 180f * val2.m_maxTilt), MaxNormal = Mathf.Cos(MathF.PI / 180f * val2.m_minTilt), MinOcean = val2.m_minOceanDepth, MaxOcean = val2.m_maxOceanDepth, MinVegetation = val2.m_minVegetation, MaxVegetation = val2.m_maxVegetation, OnCleared = val2.m_onCleared, OnUncleared = val2.m_onUncleared, SnapToWater = val2.m_snapToWater, TerrainTilt = val2.m_terrainTilt, RandomOffset = val2.m_randomOffset, ScaleMin = val2.m_scaleMin, ScaleMax = val2.m_scaleMax }); } } } _buildKinds = KindsNow.ToArray(); } private static void Prepare(BuildJob job) { //IL_0047: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Unknown result type (might be due to invalid IL or missing references) float num = job.Size / 2f; float num2 = (float)((Vector2Int)(ref job.Cell)).x * job.Size; float num3 = (float)((Vector2Int)(ref job.Cell)).y * job.Size; job.Maps[0] = CopyAt(new Vector3(num2 - num, 0f, num3 - num)); job.Maps[1] = CopyAt(new Vector3(num2 + num, 0f, num3 - num)); job.Maps[2] = CopyAt(new Vector3(num2 - num, 0f, num3 + num)); job.Maps[3] = CopyAt(new Vector3(num2 + num, 0f, num3 + num)); } private static TerrainCopy CopyAt(Vector3 point) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_013a: Expected I4, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Expected I4, but got Unknown //IL_014c: Unknown result type (might be due to invalid IL or missing references) //IL_0152: Expected I4, but got Unknown //IL_0158: Unknown result type (might be due to invalid IL or missing references) //IL_015e: Expected I4, but got Unknown //IL_016b: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(point); if (Copies.TryGetValue(zone, out var value)) { return value; } foreach (Heightmap allHeightmap in Heightmap.GetAllHeightmaps()) { if (!allHeightmap.IsDistantLod && allHeightmap.IsPointInside(point, 0f)) { Texture2D val = HmMask.Invoke(allHeightmap); List<float> list = HmHeights.Invoke(allHeightmap); if ((Object)(object)val == (Object)null || list.Count == 0) { return null; } BiomeSector[] array = HmCorners.Invoke(allHeightmap); TerrainCopy terrainCopy = new TerrainCopy(); terrainCopy.Width = allHeightmap.m_width; terrainCopy.Scale = allHeightmap.m_scale; terrainCopy.Half = (float)allHeightmap.m_width * allHeightmap.m_scale * 0.5f; terrainCopy.Position = ((Component)allHeightmap).transform.position; terrainCopy.Heights = list.ToArray(); terrainCopy.Mask = val.GetPixels32(); terrainCopy.MaskWidth = ((Texture)val).width; terrainCopy.Ocean = (float[])HmOcean.Invoke(allHeightmap).Clone(); terrainCopy.Corners = (Biome[])(object)new Biome[4] { (Biome)(int)array[0].Biome, (Biome)(int)array[1].Biome, (Biome)(int)array[2].Biome, (Biome)(int)array[3].Biome }; value = terrainCopy; Copies[zone] = value; return value; } } return null; } private static void Forget(Heightmap h) { //IL_0020: 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 (!h.IsDistantLod && Copies.Count > 0) { Copies.Remove(ZoneSystem.GetZone(((Component)h).transform.position)); } } private static void WorkerLoop() { while (true) { BuildJob buildJob; lock (ToBuild) { while (ToBuild.Count == 0) { Monitor.Wait(ToBuild); } buildJob = ToBuild.Dequeue(); } try { Build(buildJob); } catch (Exception error) { buildJob.Error = error; } lock (Finished) { Finished.Enqueue(buildJob); } } } private static TerrainCopy MapAt(BuildJob job, float x, float z) { TerrainCopy[] maps = job.Maps; foreach (TerrainCopy terrainCopy in maps) { if (terrainCopy != null && x >= terrainCopy.Position.x - terrainCopy.Half && x <= terrainCopy.Position.x + terrainCopy.Half && z >= terrainCopy.Position.z - terrainCopy.Half && z <= terrainCopy.Position.z + terrainCopy.Half) { return terrainCopy; } } return null; } private static float CornerPull(float x, float y, float rx, float ry) { float num = (float)((double)x - (double)rx); float num2 = (float)((double)y - (double)ry); float num3 = (float)(1.4140000343322754 - (double)(float)Math.Sqrt((float)((double)num * (double)num + (double)num2 * (double)num2))); return (float)((double)num3 * (double)num3 * (double)num3); } private static Biome BiomeOf(TerrainCopy m, float px, float pz) { //IL_0149: Unknown result type (might be due to invalid IL or missing references) Biome[] corners = m.Corners; if ((int)corners[0] == (int)corners[1] && (int)corners[0] == (int)corners[2] && (int)corners[0] == (int)corners[3]) { return corners[0]; } float num = (float)m.Width * m.Scale; float x = (px - m.Position.x) / num + 0.5f; float y = (pz - m.Position.z) / num + 0.5f; Array.Clear(Weights, 0, Weights.Length); Weights[BiomeHelpers.ToIndex(corners[0])] += CornerPull(x, y, 0f, 0f); Weights[BiomeHelpers.ToIndex(corners[1])] += CornerPull(x, y, 1f, 0f); Weights[BiomeHelpers.ToIndex(corners[2])] += CornerPull(x, y, 0f, 1f); Weights[BiomeHelpers.ToIndex(corners[3])] += CornerPull(x, y, 1f, 1f); int num2 = 0; float num3 = -99999f; for (int i = 1; i < Weights.Length; i++) { if (Weights[i] > num3) { num2 = i; num3 = Weights[i]; } } return BiomeHelpers.ToBiome((BiomeIndex)(byte)num2); } private static void GroundOf(TerrainCopy m, float px, float pz, out float y, out Vector3 normal) { //IL_013c: Unknown result type (might be due to invalid IL or missing references) //IL_0141: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) float num = (px - m.Position.x) / m.Scale + (float)m.Width * 0.5f; float num2 = (pz - m.Position.z) / m.Scale + (float)m.Width * 0.5f; int num3 = Mathf.Clamp((int)Math.Floor(num), 0, m.Width - 1); int num4 = Mathf.Clamp((int)Math.Floor(num2), 0, m.Width - 1); float num5 = num - (float)num3; float num6 = num2 - (float)num4; int num7 = m.Width + 1; float num8 = m.Heights[num4 * num7 + num3]; float num9 = m.Heights[num4 * num7 + num3 + 1]; float num10 = m.Heights[(num4 + 1) * num7 + num3]; float num11 = m.Heights[(num4 + 1) * num7 + num3 + 1]; float num12; float num13; if (num5 + num6 <= 1f) { num12 = num9 - num8; num13 = num10 - num8; y = num8 + num12 * num5 + num13 * num6; } else { num12 = num11 - num10; num13 = num11 - num9; y = num11 + num12 * (num5 - 1f) + num13 * (num6 - 1f); } y += m.Position.y; Vector3 val = new Vector3(0f - num12, m.Scale, 0f - num13); normal = ((Vector3)(ref val)).normalized; } private static Color32 PixelOf(TerrainCopy m, float px, float pz) { //IL_0081: Unknown result type (might be due to invalid IL or missing references) int num = (m.Width + 1) / 2; int num2 = Mathf.Clamp((int)Math.Floor((px - m.Position.x) / m.Scale + 0.5f + (float)num), 0, m.MaskWidth - 1); int num3 = Mathf.Clamp((int)Math.Floor((pz - m.Position.z) / m.Scale + 0.5f + (float)num), 0, m.MaskWidth - 1); return m.Mask[num3 * m.MaskWidth + num2]; } private static void Build(BuildJob job) { //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_07ac: Unknown result type (might be due to invalid IL or missing references) //IL_07ae: Unknown result type (might be due to invalid IL or missing references) //IL_07bb: Unknown result type (might be due to invalid IL or missing references) //IL_07bd: 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_00b3: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_00c4: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00c9: Unknown result type (might be due to invalid IL or missing references) //IL_0244: Unknown result type (might be due to invalid IL or missing references) //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_01f6: Unknown result type (might be due to invalid IL or missing references) //IL_01fd: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) //IL_0210: Unknown result type (might be due to invalid IL or missing references) //IL_0262: Unknown result type (might be due to invalid IL or missing references) //IL_0269: Unknown result type (might be due to invalid IL or missing references) //IL_027b: Unknown result type (might be due to invalid IL or missing references) //IL_0282: Unknown result type (might be due to invalid IL or missing