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 RealPortal v1.0.6
plugins/RealPortal.dll
Decompiled a day 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.Generic; using System.Diagnostics; using System.Globalization; 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 AmplifyOcclusion; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using RealPortal.Api; using RealPortal.Engine; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.LowLevel; using UnityEngine.PlayerLoop; using UnityEngine.PostProcessing; using UnityEngine.Rendering; using UnityStandardAssets.ImageEffects; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: InternalsVisibleTo("RealPortalLab")] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("RealPortal")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RealPortal")] [assembly: AssemblyTitle("RealPortal")] [assembly: AssemblyVersion("1.0.0.0")] namespace RealPortal { internal static class AreaRenderState { internal struct Values { public Quaternion LightRot; public float LightIntensity; public Color LightColor; public Color FogColor; public float FogDensity; public Color Ambient; public float CloudRain; public float CloudOpacity; public Vector4 SkyDir; public Vector4 SunDir; public Color SunFog; public Color SunCol; public Color AmbientGlobal; public float Wet; public float Aurora; public Vector4 Wind1; public Vector4 Wind2; public Vector4 WindForce; } private sealed class Snapshot { public EnvSetup Env; public float Wet; public Values V; } private static readonly int s_skyboxSunDir = Shader.PropertyToID("_SkyboxSunDir"); private static readonly int s_sunDir = Shader.PropertyToID("_SunDir"); private static readonly int s_sunFogColor = Shader.PropertyToID("_SunFogColor"); private static readonly int s_sunColor = Shader.PropertyToID("_SunColor"); private static readonly int s_ambientColor = Shader.PropertyToID("_AmbientColor"); private static readonly int s_wet = Shader.PropertyToID("_Wet"); private static readonly int s_aurora = Shader.PropertyToID("_AuroraStrength"); private static readonly int s_rain = Shader.PropertyToID("_Rain"); private static readonly int s_opacity = Shader.PropertyToID("_Opacity"); private static readonly int s_wind1 = Shader.PropertyToID("_GlobalWind1"); private static readonly int s_wind2 = Shader.PropertyToID("_GlobalWind2"); private static readonly int s_windForce = Shader.PropertyToID("_GlobalWindForce"); private static Values s_game; private static Values s_cur; private static Material s_clouds; private static bool s_open; private static int s_batch; internal static int LabWrites; internal static int LabSkipped; private static readonly List<Snapshot> s_snapshots = new List<Snapshot>(); private static int s_count; private static int s_snapshotBatch = -1; internal static bool Open => s_open; internal static ref readonly Values Game => ref s_game; internal static void Begin(EnvMan em) { //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) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) //IL_0123: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_015f: 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_0173: Unknown result type (might be due to invalid IL or missing references) //IL_0178: Unknown result type (might be due to invalid IL or missing references) //IL_0187: Unknown result type (might be due to invalid IL or missing references) //IL_018c: Unknown result type (might be due to invalid IL or missing references) Light dirLight = em.m_dirLight; s_game.LightRot = ((Component)dirLight).transform.rotation; s_game.LightIntensity = dirLight.intensity; s_game.LightColor = dirLight.color; s_game.FogColor = RenderSettings.fogColor; s_game.FogDensity = RenderSettings.fogDensity; s_game.Ambient = RenderSettings.ambientLight; s_clouds = (((Object)(object)em.m_clouds != (Object)null) ? ((Renderer)em.m_clouds).sharedMaterial : null); if ((Object)(object)s_clouds != (Object)null) { s_game.CloudRain = s_clouds.GetFloat(s_rain); s_game.CloudOpacity = s_clouds.GetFloat(s_opacity); } s_game.SkyDir = Shader.GetGlobalVector(s_skyboxSunDir); s_game.SunDir = Shader.GetGlobalVector(s_sunDir); s_game.SunFog = Shader.GetGlobalColor(s_sunFogColor); s_game.SunCol = Shader.GetGlobalColor(s_sunColor); s_game.AmbientGlobal = Shader.GetGlobalColor(s_ambientColor); s_game.Wet = Shader.GetGlobalFloat(s_wet); s_game.Aurora = Shader.GetGlobalFloat(s_aurora); s_game.Wind1 = Shader.GetGlobalVector(s_wind1); s_game.Wind2 = Shader.GetGlobalVector(s_wind2); s_game.WindForce = Shader.GetGlobalVector(s_windForce); s_cur = s_game; s_open = true; s_batch++; } internal static void Apply(EnvMan em, in Values to) { //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0031: 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_0044: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: 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_007f: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: 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_0170: Unknown result type (might be due to invalid IL or missing references) //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_019b: 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_0188: Unknown result type (might be due to invalid IL or missing references) //IL_01c6: Unknown result type (might be due to invalid IL or missing references) //IL_01cc: Unknown result type (might be due to invalid IL or missing references) //IL_01b3: Unknown result type (might be due to invalid IL or missing references) //IL_01f1: 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_01de: 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_0222: 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_0234: 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_0299: Unknown result type (might be due to invalid IL or missing references) //IL_02be: Unknown result type (might be due to invalid IL or missing references) //IL_02c4: Unknown result type (might be due to invalid IL or missing references) //IL_02ab: Unknown result type (might be due to invalid IL or missing references) //IL_02e9: Unknown result type (might be due to invalid IL or missing references) //IL_02ef: Unknown result type (might be due to invalid IL or missing references) //IL_02d6: 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) if (!s_open) { return; } int num = 0; Light val = (((Object)(object)em != (Object)null) ? em.m_dirLight : null); if ((Object)(object)val != (Object)null) { if (!Eq(s_cur.LightRot, to.LightRot)) { ((Component)val).transform.rotation = to.LightRot; num++; } if (s_cur.LightIntensity != to.LightIntensity) { val.intensity = to.LightIntensity; num++; } if (!Eq(s_cur.LightColor, to.LightColor)) { val.color = to.LightColor; num++; } } if (!Eq(s_cur.FogColor, to.FogColor)) { RenderSettings.fogColor = to.FogColor; num++; } if (s_cur.FogDensity != to.FogDensity) { RenderSettings.fogDensity = to.FogDensity; num++; } if (!Eq(s_cur.Ambient, to.Ambient)) { RenderSettings.ambientLight = to.Ambient; num++; } if ((Object)(object)s_clouds != (Object)null) { if (s_cur.CloudRain != to.CloudRain) { s_clouds.SetFloat(s_rain, to.CloudRain); num++; } if (s_cur.CloudOpacity != to.CloudOpacity) { s_clouds.SetFloat(s_opacity, to.CloudOpacity); num++; } } if (!Eq(s_cur.SkyDir, to.SkyDir)) { Shader.SetGlobalVector(s_skyboxSunDir, to.SkyDir); num++; } if (!Eq(s_cur.SunDir, to.SunDir)) { Shader.SetGlobalVector(s_sunDir, to.SunDir); num++; } if (!Eq(s_cur.SunFog, to.SunFog)) { Shader.SetGlobalColor(s_sunFogColor, to.SunFog); num++; } if (!Eq(s_cur.SunCol, to.SunCol)) { Shader.SetGlobalColor(s_sunColor, to.SunCol); num++; } if (!Eq(s_cur.AmbientGlobal, to.AmbientGlobal)) { Shader.SetGlobalColor(s_ambientColor, to.AmbientGlobal); num++; } if (s_cur.Wet != to.Wet) { Shader.SetGlobalFloat(s_wet, to.Wet); num++; } if (s_cur.Aurora != to.Aurora) { Shader.SetGlobalFloat(s_aurora, to.Aurora); num++; } if (!Eq(s_cur.Wind1, to.Wind1)) { Shader.SetGlobalVector(s_wind1, to.Wind1); num++; } if (!Eq(s_cur.Wind2, to.Wind2)) { Shader.SetGlobalVector(s_wind2, to.Wind2); num++; } if (!Eq(s_cur.WindForce, to.WindForce)) { Shader.SetGlobalVector(s_windForce, to.WindForce); num++; } s_cur = to; LabWrites += num; if (num == 0) { LabSkipped++; } } internal static void ToGame(EnvMan em) { if (s_open) { Apply(em, in s_game); } } internal static void End(EnvMan em) { if (s_open) { if ((Object)(object)em != (Object)null) { Apply(em, in s_game); } s_open = false; s_clouds = null; } } internal static bool Find(EnvSetup env, float wet, out Values v) { if (s_snapshotBatch == s_batch) { for (int i = 0; i < s_count; i++) { Snapshot snapshot = s_snapshots[i]; if (snapshot.Env == env && snapshot.Wet == wet) { v = snapshot.V; return true; } } } v = default(Values); return false; } internal static void Keep(EnvSetup env, float wet, in Values v) { if (s_snapshotBatch != s_batch) { s_snapshotBatch = s_batch; s_count = 0; } if (s_count == s_snapshots.Count) { s_snapshots.Add(new Snapshot()); } Snapshot snapshot = s_snapshots[s_count++]; snapshot.Env = env; snapshot.Wet = wet; snapshot.V = v; } private static bool Eq(Quaternion a, Quaternion b) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (a.x == b.x && a.y == b.y && a.z == b.z) { return a.w == b.w; } return false; } private static bool Eq(Color a, Color b) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (a.r == b.r && a.g == b.g && a.b == b.b) { return a.a == b.a; } return false; } private static bool Eq(Vector4 a, Vector4 b) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: 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_0022: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) if (a.x == b.x && a.y == b.y && a.z == b.z) { return a.w == b.w; } return false; } internal static void Clear() { s_snapshots.Clear(); s_count = 0; s_snapshotBatch = -1; } } internal static class BaseView { private sealed class Zone { public Vector2s Id; public int Index; public int Mark; public float MinY; public float MaxY; public bool HasGround; public readonly List<Renderer> Ground = new List<Renderer>(); public List<Item> Items = new List<Item>(); public List<Item> Next = new List<Item>(); public readonly List<ZDO> Snapshot = new List<ZDO>(); public int Cursor = -1; public int ListedVersion = int.MinValue; public float ListedAt = float.NegativeInfinity; public bool Near; public bool Ring; public bool InView; public bool Close; public float Distance; public void Reset(Vector2s id, int index) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Unknown result type (might be due to invalid IL or missing references) Id = id; Index = index; HasGround = false; Cursor = -1; ListedVersion = int.MinValue; ListedAt = float.NegativeInfinity; } public void Clear() { Ground.Clear(); Items.Clear(); Next.Clear(); Snapshot.Clear(); Cursor = -1; } } private struct Item { public Parts Parts; public bool Distant; } private sealed class Parts { public ZNetView View; public Transform Root; public Renderer[] Renderers; public sbyte[] Level; public short[] Group; public Vector3[] GroupAt; public float[] GroupSize; public float[][] Heights; public bool Mover; public float ListedAt; } private struct Lively { public ParticleSystemRenderer[] Renderers; public Transform Root; public int Index; public bool Distant; } private struct LightEntry { public Light Light; public int Index; public bool Distant; } internal static int LabBaseHidden; internal static int LabZones; internal static int LabZonesInView; internal static long LabListed; private const int ZoneSpan = 512; private const float ZoneMargin = 16f; private const float AboveGround = 96f; private const float BelowGround = 32f; private const int ListAtLeast = 8; private const int ClutterPerFrame = 256; private const double ListBudgetMs = 0.25; private const float ZoneRelist = 2f; private const float ViewRelist = 10f; private const float LodMargin = 0.75f; private const int Culled = -100; internal static readonly HashSet<Transform> Crossing = new HashSet<Transform>(); private static int[] s_zoneOf; private static readonly List<Zone> s_zones = new List<Zone>(); private static readonly Stack<Zone> s_pool = new Stack<Zone>(); private static readonly HashSet<Vector2s> s_set = new HashSet<Vector2s>(); private static int s_mark; private static int s_version = int.MinValue; private static int s_near = -1; private static int s_total = -1; private static bool s_classic; private static Vector2s s_me; private static float s_zonesAt; private static float s_listsAt; private static float s_sweepAt; private static float s_errorAt; private static readonly List<LightEntry> s_lights = new List<LightEntry>(); private static readonly List<Lively> s_lively = new List<Lively>(); private static List<Renderer> s_clutter = new List<Renderer>(); private static List<Renderer> s_clutterNext = new List<Renderer>(); private static int s_clutterCursor; private static Vector3 s_clutterFrom; private static bool s_clutterHas; private static readonly Dictionary<ZNetView, Parts> s_parts = new Dictionary<ZNetView, Parts>(); private static readonly Dictionary<ZNetView, ParticleSystemRenderer[]> s_particlesOf = new Dictionary<ZNetView, ParticleSystemRenderer[]>(); private static readonly Dictionary<LightLod, bool> s_lightDistant = new Dictionary<LightLod, bool>(); private static readonly List<Renderer> s_hidden = new List<Renderer>(); private static readonly List<Light> s_off = new List<Light>(); private static readonly Plane[] s_planes = (Plane[])(object)new Plane[6]; private static int[] s_level = new int[16]; private static readonly List<Renderer> s_renderers = new List<Renderer>(); private static readonly List<LODGroup> s_groups = new List<LODGroup>(); private static readonly List<ParticleSystemRenderer> s_particles = new List<ParticleSystemRenderer>(); private static readonly List<ZNetView> s_views = new List<ZNetView>(); private static readonly List<Vector3> s_points = new List<Vector3>(); private static readonly Dictionary<Renderer, int> s_lodOf = new Dictionary<Renderer, int>(); private static readonly List<ZNetView> s_gone = new List<ZNetView>(); private static readonly ParticleSystemRenderer[] s_noParticles = (ParticleSystemRenderer[])(object)new ParticleSystemRenderer[0]; private static readonly Stopwatch s_watch = new Stopwatch(); private static readonly FieldRef<ZDOMan, List<ZDO>[]> s_objectsBySector = AccessTools.FieldRefAccess<ZDOMan, List<ZDO>[]>("m_objectsBySector"); private static readonly FieldRef<Heightmap, MeshRenderer> s_heightmapRenderer = AccessTools.FieldRefAccess<Heightmap, MeshRenderer>("m_meshRenderer"); private static readonly FieldRef<HashSet<LightLod>> s_lodLights = AccessTools.StaticFieldRefAccess<HashSet<LightLod>>(AccessTools.Field(typeof(LightLod), "m_lights")); private static readonly FieldRef<LightLod, Light> s_lodLight = AccessTools.FieldRefAccess<LightLod, Light>("m_light"); private static readonly FieldRef<ClutterSystem, GameObject> s_grassRoot = AccessTools.FieldRefAccess<ClutterSystem, GameObject>("m_grassRoot"); private static readonly FieldRef<SmokeRenderer, Dictionary<Vector3Int, List<Smoke>>> s_smokeChunks = AccessTools.FieldRefAccess<SmokeRenderer, Dictionary<Vector3Int, List<Smoke>>>("m_chunkedSmoke"); private static readonly FieldRef<SmokeRenderer, Dictionary<Vector3Int, ParticleSystem>> s_smokeSystems = AccessTools.FieldRefAccess<SmokeRenderer, Dictionary<Vector3Int, ParticleSystem>>("m_chunkedParticleSystems"); internal static void Hide(PortalSystem sys, Camera cam, bool through) { if (s_hidden.Count > 0 || s_off.Count > 0) { Show(); } LabBaseHidden = 0; if (!WindowFlags.BaseHidesFar || (Object)(object)sys == (Object)null || (Object)(object)cam == (Object)null || Plugin.Enabled == null || !Plugin.Enabled.Value || (Object)(object)ZNet.instance == (Object)null || (Object)(object)ZoneSystem.instance == (Object)null || ZDOMan.instance == null || (Object)(object)ZNetScene.instance == (Object)null || GameCamera.InFreeFly() || (sys.Areas.Count == 0 && s_zones.Count == 0)) { if (s_zones.Count > 0 || s_clutter.Count > 0) { Forget(); } } else { if (through) { return; } try { RemoteAreas areas = sys.Areas; float unscaledTime = Time.unscaledTime; Zones(areas, unscaledTime); if (unscaledTime >= s_listsAt) { s_listsAt = unscaledTime + 1f; ListGround(); ListLights(); ListLively(areas); } ListClutter(); if (unscaledTime >= s_sweepAt) { s_sweepAt = unscaledTime + 10f; Sweep(); } View(cam); ListObjects(areas.AreasVersion, unscaledTime); Apply(cam); LabBaseHidden = s_hidden.Count + s_off.Count; } catch (Exception ex) { Show(); if (Time.unscaledTime >= s_errorAt) { s_errorAt = Time.unscaledTime + 10f; Plugin.Log.LogWarning((object)("Win.BaseHidesFar: hiding the far areas from the game camera failed: " + ex)); } } } } internal static void Show() { for (int i = 0; i < s_hidden.Count; i++) { Renderer val = s_hidden[i]; if ((Object)(object)val != (Object)null) { val.forceRenderingOff = false; } } s_hidden.Clear(); for (int j = 0; j < s_off.Count; j++) { Light val2 = s_off[j]; if ((Object)(object)val2 != (Object)null) { ((Behaviour)val2).enabled = true; } } s_off.Clear(); } internal static void Clear() { Forget(); s_parts.Clear(); s_particlesOf.Clear(); s_lightDistant.Clear(); } private static void Forget() { Show(); for (int num = s_zones.Count - 1; num >= 0; num--) { Drop(num); } s_lights.Clear(); s_lively.Clear(); s_clutter.Clear(); s_clutterNext.Clear(); s_clutterCursor = 0; s_clutterHas = false; s_version = int.MinValue; s_listsAt = 0f; LabZones = (LabZonesInView = 0); } private static int Index(int x, int y) { uint num = (uint)(x + 256); uint num2 = (uint)(y + 256); if (num >= 512 || num2 >= 512) { return -1; } return (int)(num2 * 512 + num); } private static Zone ZoneAt(int index) { int num = ((index >= 0 && s_zoneOf != null) ? (s_zoneOf[index] - 1) : (-1)); if (num < 0) { return null; } return s_zones[num]; } private static Zone ZoneAt(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_0007: Unknown result type (might be due to invalid IL or missing references) //IL_000d: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(point); return ZoneAt(Index(zone.x, zone.y)); } private static void Zones(RemoteAreas areas, float now) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0024: 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_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00de: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0154: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_015b: Unknown result type (might be due to invalid IL or missing references) //IL_0162: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) //IL_01e7: 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_024e: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0280: Unknown result type (might be due to invalid IL or missing references) ZNet instance = ZNet.instance; Vector2s zone = ZoneSystem.GetZone(instance.GetReferencePosition()); SimulationDistance syncedSimulationDistance = instance.GetSyncedSimulationDistance(); bool flag = areas.AreasVersion != s_version || zone != s_me || ((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance != s_near || ((SimulationDistance)(ref syncedSimulationDistance)).TotalSimulationDistance != s_total || ((SimulationDistance)(ref syncedSimulationDistance)).IsClassic != s_classic; if (!flag && now < s_zonesAt) { return; } s_zonesAt = now + 1f; if (flag) { s_listsAt = 0f; } s_version = areas.AreasVersion; s_me = zone; s_near = ((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance; s_total = ((SimulationDistance)(ref syncedSimulationDistance)).TotalSimulationDistance; s_classic = ((SimulationDistance)(ref syncedSimulationDistance)).IsClassic; s_set.Clear(); for (int i = 0; i < areas.Count; i++) { List<Vector2s> list = areas.AreaZones(i); for (int j = 0; j < list.Count; j++) { if (!NearHas(list[j])) { s_set.Add(list[j]); } } } if (s_zoneOf == null) { s_zoneOf = new int[262144]; } s_mark++; foreach (Vector2s item in s_set) { int num = Index(item.x, item.y); if (num >= 0) { Zone zone2 = ZoneAt(num); if (zone2 == null) { zone2 = ((s_pool.Count > 0) ? s_pool.Pop() : new Zone()); zone2.Reset(item, num); s_zones.Add(zone2); s_zoneOf[num] = s_zones.Count; } zone2.Mark = s_mark; zone2.Near = NearHas(item); zone2.Ring = RingHas(item); } } s_set.Clear(); ZoneSystem instance2 = ZoneSystem.instance; for (int num2 = s_zones.Count - 1; num2 >= 0; num2--) { Zone zone3 = s_zones[num2]; if (zone3.Mark != s_mark) { if (instance2.IsZoneLoaded(zone3.Id) && !NearHas(zone3.Id)) { zone3.Mark = s_mark; zone3.Near = false; zone3.Ring = RingHas(zone3.Id); } else { Drop(num2); } } } LabZones = s_zones.Count; } private static void Drop(int i) { Zone zone = s_zones[i]; s_zoneOf[zone.Index] = 0; int num = s_zones.Count - 1; if (i != num) { Zone zone2 = s_zones[num]; s_zones[i] = zone2; s_zoneOf[zone2.Index] = i + 1; } s_zones.RemoveAt(num); zone.Clear(); s_pool.Push(zone); } private static bool NearHas(Vector2s z) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(Mathf.Abs(z.x - s_me.x), Mathf.Abs(z.y - s_me.y)); if (num <= s_near) { if (!s_classic && num != 0) { return ZoneSystem.instance.ZonesWithinRadius(s_me, z, s_near, false); } return true; } return false; } private static bool RingHas(Vector2s z) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) int num = Mathf.Max(Mathf.Abs(z.x - s_me.x), Mathf.Abs(z.y - s_me.y)); if (num <= s_total) { if (!s_classic && num != 0) { return ZoneSystem.instance.ZonesWithinRadius(s_me, z, s_total, true); } return true; } return false; } private static bool GameHas(Vector2s z, bool distant) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) if (!NearHas(z)) { if (distant) { return RingHas(z); } return false; } return true; } private static void ListGround() { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0099: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ff: 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) for (int i = 0; i < s_zones.Count; i++) { Zone zone = s_zones[i]; zone.Ground.Clear(); zone.HasGround = false; } List<Heightmap> allHeightmaps = Heightmap.GetAllHeightmaps(); for (int j = 0; j < allHeightmaps.Count; j++) { Heightmap val = allHeightmaps[j]; if (!((Object)(object)val == (Object)null)) { Zone zone2 = ZoneAt(((Component)val).transform.position); MeshRenderer val2 = ((zone2 != null) ? s_heightmapRenderer.Invoke(val) : null); if (!((Object)(object)val2 == (Object)null)) { zone2.Ground.Add((Renderer)(object)val2); Bounds bounds = ((Renderer)val2).bounds; Spans(zone2, ((Bounds)(ref bounds)).min.y, ((Bounds)(ref bounds)).max.y); } } } List<WaterVolume> instances = WaterVolume.Instances; for (int k = 0; k < instances.Count; k++) { WaterVolume val3 = instances[k]; if (!((Object)(object)val3 == (Object)null) && !((Object)(object)val3.m_waterSurface == (Object)null)) { Zone zone3 = ZoneAt(((Component)val3).transform.position); if (zone3 != null) { zone3.Ground.Add((Renderer)(object)val3.m_waterSurface); float y = ((Component)val3.m_waterSurface).transform.position.y; Spans(zone3, y, y); } } } } private static void Spans(Zone z, float min, float max) { if (!z.HasGround) { z.HasGround = true; z.MinY = min; z.MaxY = max; } else { z.MinY = Mathf.Min(z.MinY, min); z.MaxY = Mathf.Max(z.MaxY, max); } } private static void ListLights() { //IL_005b: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) s_lights.Clear(); HashSet<LightLod> hashSet = s_lodLights.Invoke(); if (hashSet == null) { return; } if (s_lightDistant.Count > 4096) { s_lightDistant.Clear(); } foreach (LightLod item in hashSet) { if ((Object)(object)item == (Object)null) { continue; } Vector2s zone = ZoneSystem.GetZone(((Component)item).transform.position); int index = Index(zone.x, zone.y); if (ZoneAt(index) == null) { continue; } Light val = s_lodLight.Invoke(item); if (!((Object)(object)val == (Object)null)) { if (!s_lightDistant.TryGetValue(item, out var value)) { ZNetView componentInParent = ((Component)item).GetComponentInParent<ZNetView>(); value = (Object)(object)componentInParent != (Object)null && componentInParent.m_distant; s_lightDistant[item] = value; } s_lights.Add(new LightEntry { Light = val, Index = index, Distant = value }); } } } private static void ListLively(RemoteAreas areas) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: 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_0071: 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) //IL_012a: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_0131: Unknown result type (might be due to invalid IL or missing references) //IL_0138: Unknown result type (might be due to invalid IL or missing references) s_lively.Clear(); s_points.Clear(); float num = 0f; for (int i = 0; i < areas.Count; i++) { Vector2s val = areas.AreaZone(i); s_points.Add(ZoneSystem.GetZonePos(val)); List<Vector2s> list = areas.AreaZones(i); int num2 = 0; for (int j = 0; j < list.Count; j++) { num2 = Mathf.Max(num2, Mathf.Max(Mathf.Abs(list[j].x - val.x), Mathf.Abs(list[j].y - val.y))); } num = Mathf.Max(num, (float)(num2 + 1) * 64f * 1.4143f); } if (s_points.Count == 0) { return; } if (s_particlesOf.Count > 20000) { s_particlesOf.Clear(); } areas.InstancesNear(s_points, num, s_views, draining: true); for (int k = 0; k < s_views.Count; k++) { ZNetView val2 = s_views[k]; if ((Object)(object)val2 == (Object)null) { continue; } Vector2s zone = ZoneSystem.GetZone(((Component)val2).transform.position); int index = Index(zone.x, zone.y); if (ZoneAt(index) != null) { if (!s_particlesOf.TryGetValue(val2, out var value)) { ((Component)val2).GetComponentsInChildren<ParticleSystemRenderer>(true, s_particles); value = ((s_particles.Count > 0) ? s_particles.ToArray() : s_noParticles); s_particles.Clear(); s_particlesOf[val2] = value; } if (value.Length != 0) { ZDO zDO = val2.GetZDO(); s_lively.Add(new Lively { Renderers = value, Root = ((Component)val2).transform, Index = index, Distant = ((zDO != null) ? zDO.Distant : val2.m_distant) }); } } } s_views.Clear(); } private static void ListClutter() { //IL_006d: 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_0090: 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_00a7: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) ClutterSystem instance = ClutterSystem.instance; GameObject val = (((Object)(object)instance != (Object)null) ? s_grassRoot.Invoke(instance) : null); Player localPlayer = Player.m_localPlayer; if ((Object)(object)val == (Object)null || (Object)(object)localPlayer == (Object)null) { s_clutter.Clear(); s_clutterNext.Clear(); s_clutterCursor = 0; s_clutterHas = false; return; } Transform transform = val.transform; int childCount = transform.childCount; Vector3 position = ((Component)localPlayer).transform.position; float num = instance.m_distance + instance.m_grassPatchSize * 0.75f; bool num2 = s_clutterHas && Utils.DistanceXZ(position, s_clutterFrom) > instance.m_grassPatchSize; s_clutterFrom = position; s_clutterHas = true; if (num2) { int num3 = 0; for (int i = 0; i < s_clutter.Count; i++) { Renderer val2 = s_clutter[i]; if (!((Object)(object)val2 == (Object)null) && !(Utils.DistanceXZ(((Component)val2).transform.position, position) <= num)) { s_clutter[num3++] = val2; } } s_clutter.RemoveRange(num3, s_clutter.Count - num3); s_clutterNext.Clear(); s_clutterCursor = 0; } int num4 = Mathf.Min(childCount, s_clutterCursor + 256); InstanceRenderer val3 = default(InstanceRenderer); for (int j = s_clutterCursor; j < num4; j++) { Transform child = transform.GetChild(j); if (!((Component)child).TryGetComponent<InstanceRenderer>(ref val3) && !(Utils.DistanceXZ(child.position, position) <= num)) { ((Component)child).GetComponentsInChildren<Renderer>(true, s_renderers); s_clutterNext.AddRange(s_renderers); s_renderers.Clear(); } } s_clutterCursor = num4; if (num4 >= childCount) { List<Renderer> list = s_clutterNext; s_clutterNext = s_clutter; s_clutter = list; s_clutterNext.Clear(); s_clutterCursor = 0; } } private static void Sweep() { if (s_parts.Count > 4096) { foreach (KeyValuePair<ZNetView, Parts> s_part in s_parts) { if ((Object)(object)s_part.Key == (Object)null) { s_gone.Add(s_part.Key); } } for (int i = 0; i < s_gone.Count; i++) { s_parts.Remove(s_gone[i]); } s_gone.Clear(); } if (s_parts.Count > 60000) { s_parts.Clear(); } } private static void View(Camera cam) { //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: 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_00e5: 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_00f1: 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_010b: Unknown result type (might be due to invalid IL or missing references) //IL_010d: Unknown result type (might be due to invalid IL or missing references) GeometryUtility.CalculateFrustumPlanes(cam, s_planes); Vector3 position = ((Component)cam).transform.position; float shadowDistance = QualitySettings.shadowDistance; float num = ((WindowLayerCull.Radius > 0f) ? WindowLayerCull.Radius : float.MaxValue); int num2 = 0; Vector3 val = default(Vector3); Vector3 val2 = default(Vector3); for (int i = 0; i < s_zones.Count; i++) { Zone zone = s_zones[i]; Vector3 zonePos = ZoneSystem.GetZonePos(zone.Id); float num3 = (zone.HasGround ? (zone.MinY - 32f) : (-1000f)); float num4 = (zone.HasGround ? (zone.MaxY + 96f) : 3000f); ((Vector3)(ref val))..ctor(zonePos.x - 48f, num3, zonePos.z - 48f); ((Vector3)(ref val2))..ctor(zonePos.x + 48f, num4, zonePos.z + 48f); Vector3 val3 = Vector3.Max(val, Vector3.Min(val2, position)); float num5 = (zone.Distance = Vector3.Distance(position, val3)); zone.InView = num5 < shadowDistance || InFrustum(val, val2); zone.Close = num5 < num; if (zone.InView) { num2++; } } LabZonesInView = num2; } private static bool InFrustum(Vector3 min, Vector3 max) { //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) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_0050: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) Vector3 val = default(Vector3); for (int i = 0; i < s_planes.Length; i++) { Vector3 normal = ((Plane)(ref s_planes[i])).normal; ((Vector3)(ref val))..ctor((normal.x >= 0f) ? max.x : min.x, (normal.y >= 0f) ? max.y : min.y, (normal.z >= 0f) ? max.z : min.z); if (Vector3.Dot(normal, val) + ((Plane)(ref s_planes[i])).distance < 0f) { return false; } } return true; } private static void ListObjects(int version, float now) { //IL_00d7: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) s_watch.Restart(); int num = 0; List<ZDO>[] array = s_objectsBySector.Invoke(ZDOMan.instance); ZNetScene instance = ZNetScene.instance; while (true) { Zone zone = NextToList(version, now); if (zone == null) { break; } if (zone.Cursor < 0) { zone.Snapshot.Clear(); zone.Next.Clear(); List<ZDO> list = ((array != null && zone.Index < array.Length) ? array[zone.Index] : null); if (list != null) { zone.Snapshot.AddRange(list); } zone.Cursor = 0; } while (zone.Cursor < zone.Snapshot.Count) { if (num >= 8 && s_watch.Elapsed.TotalMilliseconds >= 0.25) { return; } ZDO val = zone.Snapshot[zone.Cursor++]; num++; if (val == null || val.GetSector() != zone.Id) { continue; } ZNetView val2 = instance.FindInstance(val); if (!((Object)(object)val2 == (Object)null)) { Parts parts = PartsOf(val2, now); if (parts.Renderers.Length != 0) { zone.Next.Add(new Item { Parts = parts, Distant = val.Distant }); LabListed++; } } } List<Item> items = zone.Items; zone.Items = zone.Next; zone.Next = items; zone.Next.Clear(); zone.Snapshot.Clear(); zone.Cursor = -1; zone.ListedVersion = version; zone.ListedAt = now; } } private static Zone NextToList(int version, float now) { Zone result = null; int num = int.MaxValue; float num2 = float.MaxValue; for (int i = 0; i < s_zones.Count; i++) { Zone zone = s_zones[i]; int num3; if (zone.Cursor >= 0) { num3 = 0; } else { if (!zone.Close || (zone.ListedVersion == version && !(now - zone.ListedAt >= 2f))) { continue; } num3 = (zone.InView ? 1 : 2); } if (num3 < num || (num3 == num && zone.Distance < num2)) { result = zone; num = num3; num2 = zone.Distance; } } return result; } private static Parts PartsOf(ZNetView v, float now) { if (s_parts.TryGetValue(v, out var value) && now - value.ListedAt < 10f) { return value; } if (value == null) { value = new Parts { View = v }; s_parts[v] = value; } value.ListedAt = now; Fill(value, v); return value; } private static void Fill(Parts p, ZNetView v) { //IL_0198: Unknown result type (might be due to invalid IL or missing references) //IL_019d: 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_01af: Unknown result type (might be due to invalid IL or missing references) //IL_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01c7: Unknown result type (might be due to invalid IL or missing references) //IL_01d3: Unknown result type (might be due to invalid IL or missing references) //IL_01df: Unknown result type (might be due to invalid IL or missing references) ((Component)v).GetComponentsInChildren<Renderer>(true, s_renderers); int count = s_renderers.Count; Character val = default(Character); Rigidbody val2 = default(Rigidbody); bool flag = ((Component)v).TryGetComponent<Character>(ref val) || ((Component)v).TryGetComponent<Rigidbody>(ref val2); if (!flag && !p.Mover && p.Renderers != null && SameRenderers(p.Renderers, s_renderers)) { s_renderers.Clear(); return; } if (p.Renderers == null || p.Renderers.Length != count) { p.Renderers = (Renderer[])(object)new Renderer[count]; p.Level = new sbyte[count]; p.Group = new short[count]; } s_renderers.CopyTo(p.Renderers); s_renderers.Clear(); p.Mover = flag; p.Root = (p.Mover ? ((Component)v).transform : null); for (int i = 0; i < count; i++) { p.Level[i] = -1; p.Group[i] = -1; } int num = 0; if (!p.Mover && count > 0) { ((Component)v).GetComponentsInChildren<LODGroup>(true, s_groups); for (int j = 0; j < s_groups.Count; j++) { if (num >= 32767) { break; } LODGroup val3 = s_groups[j]; if ((Object)(object)val3 == (Object)null || !val3.enabled) { continue; } LOD[] lODs = val3.GetLODs(); if (lODs.Length == 0) { continue; } if (p.GroupAt == null || p.GroupAt.Length <= num) { Array.Resize(ref p.GroupAt, num + 1); Array.Resize(ref p.GroupSize, num + 1); Array.Resize(ref p.Heights, num + 1); } Transform transform = ((Component)val3).transform; Vector3 lossyScale = transform.lossyScale; p.GroupAt[num] = transform.TransformPoint(val3.localReferencePoint); p.GroupSize[num] = val3.size * Mathf.Max(Mathf.Abs(lossyScale.x), Mathf.Max(Mathf.Abs(lossyScale.y), Mathf.Abs(lossyScale.z))); float[] array = ((p.Heights[num] != null && p.Heights[num].Length == lODs.Length) ? p.Heights[num] : new float[lODs.Length]); for (int k = 0; k < lODs.Length && k < 127; k++) { array[k] = lODs[k].screenRelativeTransitionHeight; Renderer[] renderers = lODs[k].renderers; if (renderers == null) { continue; } for (int l = 0; l < renderers.Length; l++) { if ((Object)(object)renderers[l] != (Object)null && !s_lodOf.ContainsKey(renderers[l])) { s_lodOf[renderers[l]] = (num << 8) | k; } } } p.Heights[num] = array; num++; } s_groups.Clear(); if (s_lodOf.Count > 0) { for (int m = 0; m < count; m++) { if ((Object)(object)p.Renderers[m] != (Object)null && s_lodOf.TryGetValue(p.Renderers[m], out var value)) { p.Group[m] = (short)(value >> 8); p.Level[m] = (sbyte)(value & 0xFF); } } s_lodOf.Clear(); } } if (p.GroupAt != null && p.GroupAt.Length != num) { Array.Resize(ref p.GroupAt, num); Array.Resize(ref p.GroupSize, num); Array.Resize(ref p.Heights, num); } } private static bool SameRenderers(Renderer[] had, List<Renderer> now) { if (had.Length != now.Count) { return false; } for (int i = 0; i < had.Length; i++) { if (had[i] != now[i]) { return false; } } return true; } private static void Apply(Camera cam) { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000b: 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) Vector3 position = ((Component)cam).transform.position; float tanHalf = Mathf.Tan(cam.fieldOfView * 0.5f * (MathF.PI / 180f)); float lodBias = QualitySettings.lodBias; int maximumLODLevel = QualitySettings.maximumLODLevel; for (int i = 0; i < s_zones.Count; i++) { Zone zone = s_zones[i]; if (!zone.Near && zone.InView) { for (int j = 0; j < zone.Ground.Count; j++) { Off(zone.Ground[j]); } if (zone.Close) { HideObjects(zone, position, tanHalf, lodBias, maximumLODLevel); } } } for (int k = 0; k < s_lights.Count; k++) { LightEntry lightEntry = s_lights[k]; Zone zone2 = ZoneAt(lightEntry.Index); if (zone2 != null && !zone2.Near && (!lightEntry.Distant || !zone2.Ring)) { Light light = lightEntry.Light; if ((Object)(object)light != (Object)null && ((Behaviour)light).enabled) { ((Behaviour)light).enabled = false; s_off.Add(light); } } } for (int l = 0; l < s_lively.Count; l++) { Lively lively = s_lively[l]; Zone zone3 = ZoneAt(lively.Index); if (zone3 != null && zone3.InView && !zone3.Near && (!lively.Distant || !zone3.Ring) && (Crossing.Count <= 0 || !((Object)(object)lively.Root != (Object)null) || !Crossing.Contains(lively.Root))) { ParticleSystemRenderer[] renderers = lively.Renderers; for (int m = 0; m < renderers.Length; m++) { Off((Renderer)(object)renderers[m]); } } } for (int n = 0; n < s_clutter.Count; n++) { Off(s_clutter[n]); } if (FarViewer.FarPuffs.Count > 0) { HidePuffs(); } } private static void HidePuffs() { //IL_00a4: Unknown result type (might be due to invalid IL or missing references) SmokeRenderer instance = SmokeRenderer.Instance; Dictionary<Vector3Int, List<Smoke>> dictionary = (((Object)(object)instance != (Object)null) ? s_smokeChunks.Invoke(instance) : null); Dictionary<Vector3Int, ParticleSystem> dictionary2 = (((Object)(object)instance != (Object)null) ? s_smokeSystems.Invoke(instance) : null); if (dictionary == null || dictionary2 == null) { return; } HashSet<Smoke> farPuffs = FarViewer.FarPuffs; ParticleSystemRenderer r = default(ParticleSystemRenderer); foreach (KeyValuePair<Vector3Int, List<Smoke>> item in dictionary) { List<Smoke> value = item.Value; if (value != null && value.Count != 0) { bool flag = true; for (int i = 0; i < value.Count && flag; i++) { flag = farPuffs.Contains(value[i]); } if (flag && dictionary2.TryGetValue(item.Key, out var value2) && (Object)(object)value2 != (Object)null && ((Component)value2).TryGetComponent<ParticleSystemRenderer>(ref r)) { Off((Renderer)(object)r); } } } } private static void HideObjects(Zone z, Vector3 eye, float tanHalf, float bias, int lowest) { //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Unknown result type (might be due to invalid IL or missing references) //IL_0106: Unknown result type (might be due to invalid IL or missing references) List<Item> items = z.Items; for (int i = 0; i < items.Count; i++) { Item item = items[i]; Parts parts = item.Parts; if ((Object)(object)parts.View == (Object)null) { continue; } Renderer[] renderers = parts.Renderers; if (parts.Mover) { if (!((Object)(object)parts.Root == (Object)null) && (Crossing.Count <= 0 || !Crossing.Contains(parts.Root)) && !GameHas(ZoneSystem.GetZone(parts.Root.position), item.Distant)) { for (int j = 0; j < renderers.Length; j++) { Off(renderers[j]); } } } else { if (item.Distant && z.Ring) { continue; } int num = ((parts.GroupAt != null) ? parts.GroupAt.Length : 0); if (s_level.Length < num) { s_level = new int[Mathf.NextPowerOfTwo(num)]; } for (int k = 0; k < num; k++) { s_level[k] = Pick(parts, k, eye, tanHalf, bias, lowest); } for (int l = 0; l < renderers.Length; l++) { int num2 = parts.Group[l]; if (num2 >= 0) { int num3 = s_level[num2]; if (num3 == -100 || Mathf.Abs(parts.Level[l] - num3) > 1) { continue; } } Off(renderers[l]); } } } } private static int Pick(Parts p, int g, Vector3 eye, float tanHalf, float bias, int lowest) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) float[] array = p.Heights[g]; int num = array.Length; float num2 = Vector3.Distance(eye, p.GroupAt[g]); float num3 = ((num2 > 0.001f && tanHalf > 0f) ? (p.GroupSize[g] / (2f * num2 * tanHalf) * bias) : float.MaxValue); for (int i = Mathf.Clamp(lowest, 0, num - 1); i < num; i++) { if (num3 >= array[i]) { return i; } } if (!(num3 >= array[num - 1] * 0.75f)) { return -100; } return num - 1; } private static void Off(Renderer r) { if (!((Object)(object)r == (Object)null) && !r.forceRenderingOff) { r.forceRenderingOff = true; s_hidden.Add(r); } } } internal static class DebugDump { private static readonly Color Magenta = new Color(1f, 0f, 1f, 1f); internal static string Write(PortalRenderer renderer, Camera main, List<PortalWindow> windows) { //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Expected O, but got Unknown //IL_00e1: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0107: 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_0124: Unknown result type (might be due to invalid IL or missing references) //IL_0128: Unknown result type (might be due to invalid IL or missing references) //IL_0161: Unknown result type (might be due to invalid IL or missing references) //IL_018c: 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_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: Unknown result type (might be due to invalid IL or missing references) //IL_01fe: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0275: Unknown result type (might be due to invalid IL or missing references) //IL_022e: Unknown result type (might be due to invalid IL or missing references) //IL_023a: Unknown result type (might be due to invalid IL or missing references) //IL_044f: Unknown result type (might be due to invalid IL or missing references) //IL_0371: Unknown result type (might be due to invalid IL or missing references) //IL_054d: Unknown result type (might be due to invalid IL or missing references) //IL_0552: 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_0576: Unknown result type (might be due to invalid IL or missing references) PortalWindow portalWindow = (from x in windows where x.Enabled && x.Partner != null orderby Vector3.Distance(x.Frame.Center, ((Component)main).transform.position) select x).FirstOrDefault(); if (portalWindow == null) { Plugin.Log.LogInfo((object)"Debug dump: no live portal window"); return null; } string text = Path.Combine(Paths.BepInExRootPath, "RealPortalDebug", DateTime.Now.ToString("yyyyMMdd_HHmmss")); Directory.CreateDirectory(text); int num = Mathf.Max(64, main.pixelWidth / 2); int num2 = Mathf.Max(64, main.pixelHeight / 2); RenderTexture val = new RenderTexture(num, num2, 24, (RenderTextureFormat)0) { antiAliasing = 1 }; val.Create(); StringBuilder stringBuilder = new StringBuilder(); try { Vector3 val2 = PortalRenderer.ViewPosition(portalWindow, ((Component)main).transform.position); object[] obj = new object[5] { ((Component)main).transform.position, null, null, null, null }; Quaternion rotation = ((Component)main).transform.rotation; obj[1] = ((Quaternion)(ref rotation)).eulerAngles; obj[2] = main.fieldOfView; obj[3] = main.nearClipPlane; obj[4] = main.actualRenderingPath; stringBuilder.AppendLine(string.Format("main camera {0} rot {1}, fov {2}, near {3}, path {4}", obj)); stringBuilder.AppendLine($"entry centre {portalWindow.Frame.Center} fwd {portalWindow.Frame.Forward}; exit centre {portalWindow.Partner.Frame.Center} fwd {portalWindow.Partner.Frame.Forward}"); stringBuilder.AppendLine($"window camera {val2}, {portalWindow.Partner.Frame.SignedDistance(val2):0.00} m from the exit plane"); if ((Object)(object)ZoneSystem.instance != (Object)null) { stringBuilder.AppendLine($"ground under window camera {ZoneSystem.instance.GetGroundHeight(val2):0.00}, liquid {Floating.GetLiquidLevel(val2, 1f, (LiquidType)10):0.00}"); } stringBuilder.AppendLine($"settings: path {renderer.Settings.RenderingPath}, clear {renderer.Settings.ClearFlags}, far {renderer.Settings.FarClip}, " + $"res {renderer.Settings.Resolution}, pixel lights {QualitySettings.pixelLightCount}"); renderer.RenderDebug(main, windows, portalWindow, val, main.cullingMask, null); Save(val, Path.Combine(text, "view.png"), out var _); WriteLive(renderer, main, windows, portalWindow, text, stringBuilder); stringBuilder.AppendLine(); stringBuilder.AppendLine("layers drawn in the window (pixels not magenta):"); for (int num3 = 0; num3 < 32; num3++) { string arg = LayerMask.LayerToName(num3); if ((main.cullingMask & (1 << num3)) != 0) { renderer.RenderDebug(main, windows, portalWindow, val, 1 << num3, Magenta); Read(val, out var tex2); int num4 = tex2.GetPixels32().Count((Color32 c) => c.r <= 250 || c.g >= 5 || c.b <= 250); if (num4 > 0) { File.WriteAllBytes(Path.Combine(text, $"layer_{num3:00}_{arg}.png"), ImageConversion.EncodeToPNG(tex2)); stringBuilder.AppendLine($" {num3,2} {arg,-20} {100f * (float)num4 / (float)(num * num2):0.0}%"); } Object.Destroy((Object)(object)tex2); } } stringBuilder.AppendLine(); stringBuilder.AppendLine("renderers within 40 m of the window camera on the camera side of the exit plane (should be clipped):"); foreach (string item in BehindExit(portalWindow, val2)) { stringBuilder.AppendLine(" " + item); } } catch (Exception ex) { stringBuilder.AppendLine("ERROR " + ex); } finally { val.Release(); Object.Destroy((Object)(object)val); } stringBuilder.AppendLine(); stringBuilder.AppendLine("window camera components and command buffers:"); Behaviour[] components = ((Component)renderer.Camera).GetComponents<Behaviour>(); foreach (Behaviour val3 in components) { stringBuilder.AppendLine($" component {((object)val3).GetType().FullName} enabled {val3.enabled}"); } foreach (CameraEvent value in Enum.GetValues(typeof(CameraEvent))) { CommandBuffer[] commandBuffers = renderer.Camera.GetCommandBuffers(value); foreach (CommandBuffer val5 in commandBuffers) { stringBuilder.AppendLine($" {(object)value}: {val5.name}"); } } File.WriteAllText(Path.Combine(text, "info.txt"), stringBuilder.ToString()); Plugin.Log.LogInfo((object)("Debug dump written to " + text)); return text; } internal static void LiveFrame(Camera main, List<PortalWindow> windows, string dir, int index) { //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown PortalWindow portalWindow = (from x in windows where x.Enabled && x.Partner != null && x.RenderedThisFrame && (Object)(object)x.Texture != (Object)null orderby Vector3.Distance(x.Frame.Center, ((Component)main).transform.position) select x).FirstOrDefault(); if (portalWindow != null) { RenderTexture val = new RenderTexture(((Texture)portalWindow.Texture).width, ((Texture)portalWindow.Texture).height, 0, (RenderTextureFormat)0); val.Create(); Graphics.Blit((Texture)(object)portalWindow.Texture, val); Save(val, Path.Combine(dir, $"window_frame{index}_f{Time.frameCount}.png"), out var _); val.Release(); Object.Destroy((Object)(object)val); } } private static void WriteLive(PortalRenderer renderer, Camera main, List<PortalWindow> windows, PortalWindow w, string dir, StringBuilder info) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_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) //IL_0099: Expected O, but got Unknown //IL_00d0: Unknown result type (might be due to invalid IL or missing references) //IL_010e: Unknown result type (might be due to invalid IL or missing references) if (!w.RenderedThisFrame || (Object)(object)w.Texture == (Object)null) { info.AppendLine("live window texture: not rendered this frame"); return; } RenderTexture texture = w.Texture; Rect textureRect = w.TextureRect; info.AppendLine($"live window texture {((Texture)texture).width}x{((Texture)texture).height} {texture.format}, screen rect {textureRect}"); RenderTexture val = new RenderTexture(((Texture)texture).width, ((Texture)texture).height, 24, (RenderTextureFormat)0) { antiAliasing = 1 }; val.Create(); try { Graphics.Blit((Texture)(object)texture, val); Save(val, Path.Combine(dir, "window_live.png"), out var tex); renderer.RenderDebug(main, windows, w, val, main.cullingMask, null, textureRect, 0f); Save(val, Path.Combine(dir, "window_noshadows.png"), out tex); renderer.RenderDebug(main, windows, w, val, main.cullingMask, null, textureRect, QualitySettings.shadowDistance); Save(val, Path.Combine(dir, "window_shadows.png"), out tex); } finally { val.Release(); Object.Destroy((Object)(object)val); } } private static IEnumerable<string> BehindExit(PortalWindow w, Vector3 camPos) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) PortalFrame exit = w.Partner.Frame; float camSide = Mathf.Sign(exit.SignedDistance(camPos)); return Object.FindObjectsByType<Renderer>((FindObjectsSortMode)0).Where(delegate(Renderer r) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001b: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) if (r.enabled && ((Component)r).gameObject.activeInHierarchy) { Bounds bounds = r.bounds; if (((Bounds)(ref bounds)).SqrDistance(camPos) < 1600f) { PortalFrame portalFrame = exit; bounds = r.bounds; return Mathf.Sign(portalFrame.SignedDistance(((Bounds)(ref bounds)).center)) == camSide; } } return false; }).OrderBy(delegate(Renderer r) { //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_000a: Unknown result type (might be due to invalid IL or missing references) Bounds bounds = r.bounds; return ((Bounds)(ref bounds)).SqrDistance(camPos); }) .Take(40) .Select(delegate(Renderer r) { //IL_0082: 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_008b: Unknown result type (might be due to invalid IL or missing references) string[] obj = new string[7] { NameOf(((Component)r).transform), " layer ", LayerMask.LayerToName(((Component)r).gameObject.layer), ", shader ", ((Object)(object)r.sharedMaterial != (Object)null && (Object)(object)r.sharedMaterial.shader != (Object)null) ? ((Object)r.sharedMaterial.shader).name : "none", ", ", null }; Bounds bounds = r.bounds; obj[6] = $"{Mathf.Sqrt(((Bounds)(ref bounds)).SqrDistance(camPos)):0.0} m"; return string.Concat(obj); }); } private static string NameOf(Transform t) { if (!((Object)(object)t.parent != (Object)null)) { return ((Object)t).name; } return ((Object)t.parent).name + "/" + ((Object)t).name; } private static void Read(RenderTexture rt, out Texture2D tex) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Expected O, but got Unknown //IL_003a: Unknown result type (might be due to invalid IL or missing references) RenderTexture active = RenderTexture.active; RenderTexture.active = rt; tex = new Texture2D(((Texture)rt).width, ((Texture)rt).height, (TextureFormat)3, false); tex.ReadPixels(new Rect(0f, 0f, (float)((Texture)rt).width, (float)((Texture)rt).height), 0, 0); tex.Apply(); RenderTexture.active = active; } private static void Save(RenderTexture rt, string path, out Texture2D tex) { Read(rt, out tex); File.WriteAllBytes(path, ImageConversion.EncodeToPNG(tex)); Object.Destroy((Object)(object)tex); } } [HarmonyPatch] internal static class FarDrain { internal static int LabQuietPokes; [HarmonyPrefix] [HarmonyPatch(typeof(TerrainModifier), "PokeHeightmaps")] private static bool PokeHeightmaps(TerrainModifier __instance, bool forcedDelay) { //IL_002a: Unknown result type (might be due to invalid IL or missing references) if (!FarFlags.DrainCalm || forcedDelay) { return true; } RemoteAreas remoteAreas = PortalSystem.Instance?.Areas; if (remoteAreas == null || !remoteAreas.UnloadsQuietly(((Component)__instance).transform.position)) { return true; } LabQuietPokes++; return false; } } internal static class FarHeightmaps { private const float GoneSeconds = 120f; private const float RefreshSeconds = 1f; internal static readonly Func<Vector3, Place> Hook = PlaceOf; private static Dictionary<int, float> s_unloading = new Dictionary<int, float>(); private static Dictionary<int, float> s_next = new Dictionary<int, float>(); private static readonly List<Vector2s> s_live = new List<Vector2s>(); private static int s_liveReach; private static int s_near; private static int s_whole; private static int s_areaNear; private static RemoteAreas s_areas; private static int s_version = -1; private static float s_refreshAt; private static int s_meFrame = -1; private static Vector2s s_me; internal static long LabNear; internal static long LabFar; internal static long LabUnloading; internal static void Switched() { HeightmapIdleModule.PlaceOf = ((FarFlags.HeightmapDrainSkip || FarFlags.FarRegenBudget) ? Hook : null); HeightmapIdleModule.ForgetPlaces(); } private static Place PlaceOf(Vector3 at) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_009d: 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_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_00e8: 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_0129: Unknown result type (might be due to invalid IL or missing references) bool heightmapDrainSkip = FarFlags.HeightmapDrainSkip; bool farRegenBudget = FarFlags.FarRegenBudget; ZNet instance = ZNet.instance; if ((heightmapDrainSkip || farRegenBudget) && !((Object)(object)instance == (Object)null) && !((Object)(object)ZoneSystem.instance == (Object)null)) { int frameCount = Time.frameCount; if (frameCount != s_meFrame) { s_meFrame = frameCount; s_me = ZoneSystem.GetZone(instance.GetReferencePosition()); } RemoteAreas remoteAreas = PortalSystem.Instance?.Areas; float time = Time.time; if (remoteAreas != s_areas || (remoteAreas != null && remoteAreas.AreasVersion != s_version) || !(time < s_refreshAt)) { Refresh(remoteAreas, instance, time); } Vector2s zone = ZoneSystem.GetZone(at); int num = Distance(zone, s_me); if (num <= s_near) { LabNear++; return (Place)0; } if (heightmapDrainSkip && num > s_whole && s_unloading.Count > 0 && s_unloading.ContainsKey(Key(zone)) && !Live(zone)) { LabUnloading++; return (Place)2; } if (!farRegenBudget || Simulated(remoteAreas, zone) || (FarFlags.VisibleNear && remoteAreas != null && remoteAreas.ShowsZone(zone))) { LabNear++; return (Place)0; } LabFar++; return (Place)1; } return (Place)0; } private static void Refresh(RemoteAreas areas, ZNet net, float now) { //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0152: 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_0174: Unknown result type (might be due to invalid IL or missing references) //IL_0179: 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_0102: Unknown result type (might be due to invalid IL or missing references) if (areas != s_areas) { s_unloading.Clear(); } s_areas = areas; s_version = areas?.AreasVersion ?? (-1); s_refreshAt = now + 1f; ZoneSystem instance = ZoneSystem.instance; s_next.Clear(); foreach (KeyValuePair<int, float> item in s_unloading) { if (now - item.Value < 120f && now >= item.Value && instance.IsZoneLoaded(Unkey(item.Key))) { s_next[item.Key] = item.Value; } } s_live.Clear(); if (areas != null) { for (int i = 0; i < areas.Count; i++) { if (!areas.AreaDraining(i)) { s_live.Add(areas.AreaZone(i)); continue; } List<Vector2s> list = areas.AreaZones(i); for (int j = 0; j < list.Count; j++) { s_next[Key(list[j])] = now; } } } Dictionary<int, float> dictionary = s_unloading; s_unloading = s_next; s_next = dictionary; s_next.Clear(); SimulationDistance syncedSimulationDistance = net.GetSyncedSimulationDistance(); s_near = ((SimulationDistance)(ref syncedSimulationDistance)).NearSimulationDistance + 1; s_whole = ((SimulationDistance)(ref syncedSimulationDistance)).TotalSimulationDistance + 1; SimulationDistance val = RemoteAreas.AreaDistance(); s_liveReach = ((SimulationDistance)(ref val)).TotalSimulationDistance; s_areaNear = ((SimulationDistance)(ref val)).NearSimulationDistance + 1; } private static bool Live(Vector2s zone) { //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < s_live.Count; i++) { if (Distance(zone, s_live[i]) <= s_liveReach) { return true; } } return false; } private static bool Simulated(RemoteAreas areas, Vector2s zone) { //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) if (areas == null) { return false; } for (int i = 0; i < areas.Count; i++) { if (areas.AreaSimulated(i) && Distance(zone, areas.AreaZone(i)) <= s_areaNear) { return true; } } return false; } private static int Distance(Vector2s a, Vector2s b) { //IL_0000: 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_0012: 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) return Math.Max(Math.Abs(a.x - b.x), Math.Abs(a.y - b.y)); } private static int Key(Vector2s zone) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) return (zone.x << 16) | (ushort)zone.y; } private static Vector2s Unkey(int key) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) return new Vector2s((short)(key >> 16), (short)key); } } internal static class FarEnvironment { private sealed class Flash { public Light[] Lights; public Renderer[] Renderers; } private sealed class Shadow { public float Until; public EnvSetup Env; public Matrix4x4 ToFar; public Vector3 Place; public FollowPlayer Follower; public readonly List<Mover> Movers = new List<Mover>(); public GameObject Go; public GameObject Original; public Place Owner; public ParticleSystem[] Systems; public bool Clone; public bool Wanted; public bool Fading; public float FadeUntil; } private sealed class Mover { public Transform T; public FollowPlayer Follower; public Vector3 Local; public readonly List<(ParticleSystem ps, ParticleSystemSimulationSpace space, Transform custom)> Systems = new List<(ParticleSystem, ParticleSystemSimulationSpace, Transform)>(); } private sealed class Storm { public Thunder T; public Matrix4x4 ToFar; public EnvSetup Env; public float Until; public float NextAt; public float ThunderAt = -1f; public Vector3 FlashAt; public readonly List<GameObject> Flashes = new List<GameObject>(); } private sealed class Place { public Vector3 At; public Matrix4x4 ToFar; public float SeenAt = -100f; public float CheckAt; public int Frame = -1; public long Period = long.MinValue; public bool Watched; public EnvSetup Override; public bool Sheltered; public EnvSetup Target; public EnvSetup From; public EnvSetup Mix; public EnvSetup MixFrom; public float BlendAt; public float T; public EnvSetup Systems; public bool Running; public bool Starting; public readonly List<Shadow> Shadows = new List<Shadow>(); public Storm Storm; } private sealed class WeatherClone { public GameObject Original; public GameObject Go; public float FreeAt; } private static readonly FieldRef<EnvMan, EnvSetup> s_current = AccessTools.FieldRefAccess<EnvMan, EnvSetup>("m_currentEnv"); private static readonly FieldRef<EnvMan, EnvSetup> s_next = AccessTools.FieldRefAccess<EnvMan, EnvSetup>("m_nextEnv"); private static readonly FieldRef<EnvMan, string> s_forceEnv = AccessTools.FieldRefAccess<EnvMan, string>("m_forceEnv"); private static readonly FieldRef<EnvMan, float> s_smoothDay = AccessTools.FieldRefAccess<EnvMan, float>("m_smoothDayFraction"); private static readonly Func<EnvMan, List<EnvEntry>, EnvSetup> s_select = AccessTools.MethodDelegate<Func<EnvMan, List<EnvEntry>, EnvSetup>>(AccessTools.Method(typeof(EnvMan), "SelectWeightedEnvironment", (Type[])null, (Type[])null), (object)null, true); private static readonly Func<EnvMan, string, EnvSetup> s_getEnv = AccessTools.MethodDelegate<Func<EnvMan, string, EnvSetup>>(AccessTools.Method(typeof(EnvMan), "GetEnv", (Type[])null, (Type[])null), (object)null, true); private static readonly int s_skyboxSunDir = Shader.PropertyToID("_SkyboxSunDir"); private static readonly int s_sunDir = Shader.PropertyToID("_SunDir"); private static readonly int s_sunFogColor = Shader.PropertyToID("_SunFogColor"); private static readonly int s_sunColor = Shader.PropertyToID("_SunColor"); private static readonly int s_ambientColor = Shader.PropertyToID("_AmbientColor"); private static readonly int s_wet = Shader.PropertyToID("_Wet"); private static readonly int s_aurora = Shader.PropertyToID("_AuroraStrength"); private static readonly int s_rain = Shader.PropertyToID("_Rain"); private static readonly int s_opacity = Shader.PropertyToID("_Opacity"); private static float s_day; private static float s_night; private static float s_morning; private static float s_evening; private static bool s_have; private static bool s_applied; private static Quaternion s_lightRot; private static float s_lightIntensity; private static Color s_lightColor; private static Color s_fogColor; private static Color s_ambient; private static Color s_sunFog; private static Color s_sunCol; private static Color s_ambientGlobal; private static float s_fogDensity; private static float s_wetValue; private static float s_auroraValue; private static float s_rainValue; private static float s_opacityValue; private static Vector4 s_skyDir; private static Vector4 s_sunDirValue; private static long s_cachePeriod = -1L; private static readonly Dictionary<Vector2s, EnvSetup> s_cache = new Dictionary<Vector2s, EnvSetup>(); private static string s_forcedName; private static EnvSetup s_forcedEnv; internal static string LabLastPick = ""; internal static string LabFarEnv; private static EnvSetup s_swapEnv; private static float s_labSetAt; internal static int LabSwaps; private static readonly FieldRef<EnvMan, GameObject[]> s_currentPSystems = AccessTools.FieldRefAccess<EnvMan, GameObject[]>("m_currentPSystems"); private static readonly FieldRef<EnvMan, float> s_instantTimer = AccessTools.FieldRefAccess<EnvMan, float>("m_forceInstantEnvSwitchTimer"); private static readonly List<Renderer> s_hidden = new List<Renderer>(); private static readonly List<Renderer> s_shown = new List<Renderer>(); private static readonly Dictionary<GameObject, Flash> s_flashParts = new Dictionary<GameObject, Flash>(); private static readonly List<GameObject> s_flashDrop = new List<GameObject>(); private static readonly FieldRef<EnvMan, GameObject> s_envObject = AccessTools.FieldRefAccess<EnvMan, GameObject>("m_currentEnvObject"); private static readonly List<GameObject> s_flashes = new List<GameObject>(); private static readonly List<Light> s_offLights = new List<Light>(); internal static bool InStrike; private static readonly Dictionary<GameObject, Renderer[]> s_renderers = new Dictionary<GameObject, Renderer[]>(); private static readonly int s_wind1 = Shader.PropertyToID("_GlobalWind1"); private static readonly int s_wind2 = Shader.PropertyToID("_GlobalWind2"); private static readonly int s_windForce = Shader.PropertyToID("_GlobalWindForce"); private static Vector4 s_wind1Value; private static Vector4 s_wind2Value; private static Vector4 s_windForceValue; private static bool s_windSet; private static readonly Dictionary<GameObject, Shadow> s_shadow = new Dictionary<GameObject, Shadow>(); private static readonly Dictionary<GameObject, (EnvSetup env, Matrix4x4 toFar, Vector3 place)> s_wanted = new Dictionary<GameObject, (EnvSetup, Matrix4x4, Vector3)>(); private static readonly List<GameObject> s_drop = new List<GameObject>(); private static readonly Dictionary<GlobalWind, GameObject[]> s_windChain = new Dictionary<GlobalWind, GameObject[]>(); private static readonly List<GameObject> s_chainScratch = new List<GameObject>(); private static readonly FieldRef<EnvMan, float> s_wetDuration = AccessTools.FieldRefAccess<EnvMan, float>("m_wetTransitionDuration"); private static readonly List<(Vector3 place, float wet, float seenAt)> s_farWet = new List<(Vector3, float, float)>(); private static readonly FieldInfo s_isWet = AccessTools.Field(typeof(EnvMan), "s_isWet"); private static readonly FieldInfo s_isCold = AccessTools.Field(typeof(EnvMan), "s_isCold"); private static readonly FieldInfo s_isFreezing = AccessTools.Field(typeof(EnvMan), "s_isFreezing"); private static readonly Dictionary<Thunder, Storm> s_storms = new Dictionary<Thunder, Storm>(); private static readonly List<Thunder> s_stormDrop = new List<Thunder>(); private static readonly List<Light> s_onLights = new List<Light>(); internal static int LabFarFlashes; internal static int LabFlashesShown; internal static int LabFarThunders; internal static EnvSetup Setting; private static readonly FieldRef<EnvMan, Vector4> s_windDir1 = AccessTools.FieldRefAccess<EnvMan, Vector4>("m_windDir1"); private static readonly FieldRef<EnvMan, Vector4> s_windDir2 = AccessTools.FieldRefAccess<EnvMan, Vector4>("m_windDir2"); private static readonly FieldRef<EnvMan, Vector4> s_windNow = AccessTools.FieldRefAccess<EnvMan, Vector4>("m_wind"); private static readonly Action<EnvMan, float> s_updateWindTransition = AccessTools.MethodDelegate<Action<EnvMan, float>>(AccessTools.Method(typeof(EnvMan), "UpdateWindTransition", new Type[1] { typeof(float) }, (Type[])null), (object)null, true); internal static string LabLastSet = ""; internal static string LabApplied; private static readonly Action<EnvMan, long, BiomeSector> s_updateEnvironment = AccessTools.MethodDelegate<Action<EnvMan, long, BiomeSector>>(AccessTools.Method(typeof(EnvMan), "UpdateEnvironment", new Type[2] { typeof(long), typeof(BiomeSector) }, (Type[])null), (object)null, true); private static readonly Func<EnvMan, BiomeSector> s_getBiome = AccessTools.MethodDelegate<Func<EnvMan, BiomeSector>>(AccessTools.Method(typeof(EnvMan), "GetBiome", Type.EmptyTypes, (Type[])null), (object)null, true); private static readonly Action<EnvMan, float> s_interpolate = AccessTools.MethodDelegate<Action<EnvMan, float>>(AccessTools.Method(typeof(EnvMan), "InterpolateEnvironment", new Type[1] { typeof(float) }, (Type[])null), (object)null, true); private static readonly Action<EnvMan, EnvSetup, float, float, float, float, float> s_setEnv = AccessTools.MethodDelegate<Action<EnvMan, EnvSetup, float, float, float, float, float>>(AccessTools.Method(typeof(EnvMan), "SetEnv", new Type[6] { typeof(EnvSetup), typeof(float), typeof(float), typeof(float), typeof(float), typeof(float) }, (Type[])null), (object)null, true); private static readonly List<Place> s_places = new List<Place>(); private static readonly List<WeatherClone> s_clones = new List<WeatherClone>(); private static readonly Dictionary<GameObject, bool> s_cloneable = new Dictionary<GameObject, bool>(); private static readonly Dictionary<GameObject, Place> s_handTo = new Dictionary<GameObject, Place>(); private static readonly Collider[] s_zoneHits = (Collider[])(object)new Collider[32]; private static int s_placeStates; private static bool s_parityRuns; private static bool s_placeSwapped; private static Place s_swapPlace; private static EnvSetup s_swapKeyEnv; private const int MaxClones = 16; private const float CloneKeep = 300f; private const float FadeMax = 20f; private const int ChecksPerFrame = 2; private static int s_checkFrame = -1; private static int s_checks; private static bool s_overrideWarned; internal static int LabPlaceOverrides; internal static int LabPlaceSheltered; internal static long LabPlaceBlends; internal static long LabWeatherClones; private static readonly FieldRef<EnvMan, long> s_envPeriod = AccessTools.FieldRefAccess<EnvMan, long>("m_environmentPeriod"); private static readonly FieldRef<RandEventSystem, RandomEvent> s_randomEvent = AccessTools.FieldRefAccess<RandEventSystem, RandomEvent>("m_randomEvent"); private static readonly FieldRef<RandEventSystem, RandomEvent> s_forcedEvent = AccessTools.FieldRefAccess<RandEventSystem, RandomEvent>("m_forcedEvent"); private static readonly int s_auroraCurrent = Shader.PropertyToID("_AuroraGradientCurrent"); private static readonly int s_auroraNext = Shader.PropertyToID("_AuroraGradientNext"); private static readonly int s_auroraBlend = Shader.PropertyToID("_AuroraGradientBlend"); private static bool s_auroraSet; private static Texture s_auroraGameCur; private static Texture s_auroraGameNext; private static Texture s_auroraCur; private static Texture s_auroraNextNow; private static float s_auroraGameBlend; private static float s_auroraBlendNow; internal static bool HasFarState { get { if (s_shadow.Count <= 0 && s_storms.Count <= 0 && s_farWet.Count <= 0) { return s_places.Count > 0; } return true; } } internal static float DayFraction { get { if (!((Object)(object)EnvMan.instance != (Object)null)) { return 0f; } return s_smoothDay.Invoke(EnvMan.instance); } } internal static EnvSetup Applied { get; private set; } internal static string GameEnvName { get { EnvMan instance = EnvMan.instance; return (((Object)(object)instance != (Object)null) ? s_current.Invoke(instance) : null)?.m_name; } } internal static bool OwnFlashing { get { for (int i = 0; i < s_flashes.Count; i++) { if ((Object)(object)s_flashes[i] != (Object)null) { return true; } } return false; } } internal static void Capture(float day, float night, float morning, float evening) { s_day = day; s_night = night; s_morning = morning; s_evening = evening; s_have = true; } internal static EnvSetup Pick(Vector3 pos) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) return Pick(pos, places: true); } private static EnvSetup Pick(Vector3 pos, bool places, Place view = null) { //IL_00e4: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Unknown result type (might be due to invalid IL or missing references) EnvMan instance = EnvMan.instance; if ((Object)(object)instance == (Object)null || WorldGenerator.instance == null || (Object)(object)ZNet.instance == (Object)null || instance.m_environmentDuration <= 0) { return null; } if (!string.IsNullOrEmpty(LabFarEnv)) { EnvSetup val = s_getEnv(instance, LabFarEnv); EnvSetup val2 = s_current.Invoke(instance); if (val == null || (val2 != null && !(val2.m_name != val.m_name))) { return null; } return val; } bool weatherParity = FarFlags.WeatherParity; if (!weatherParity) { if (!string.IsNullOrEmpty(instance.m_debugEnv) || !string.IsNullOrEmpty(s_forceEnv.Invoke(instance))) { return null; } } else if (!string.IsNullOrEmpty(instance.m_debugEnv) || ((Object)(object)Player.m_localPlayer != (Object)null && ((Character)Player.m_localPlayer).InIntro())) { return null; } long period = (long)ZNet.instance.GetTimeSeconds() / instance.m_environmentDuration; EnvSetup val3 = ZonePick(instance, pos, period); if (!weatherParity) { EnvSetup val4 = s_current.Invoke(instance); if (val3 == null || (val4 != null && val4.m_name == val3.m_name && s_next.Invoke(instance) == null)) { return null; } return val3; } Place place = ((places && s_placeStates > 0) ? (view ?? PlaceNear(pos)) : null); if (place != null && place.Override != null) { val3 = place.Override; } if (val3 == null) { return null; } if (place != null && place.From != null && place.Target == val3) { return val3; } bool forced; EnvSetup val5 = GameEnv(instance, out forced); if (val5 != null && val5.m_name == val3.m_name && (forced || s_next.Invoke(instance) == null)) { return null; } return val3; } private static EnvSetup ZonePick(EnvMan em, Vector3 pos, long period) { //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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) Vector2s zone = ZoneSystem.GetZone(pos); if (period != s_cachePeriod) { s_cachePeriod = period; s_cache.Clear(); } if (!s_cache.TryGetValue(zone, out var value)) { value = (s_cache[zone] = PickNow(em, pos, period)); } return value; } private static EnvSetup GameEnv(EnvMan em, out bool forced) { string text = s_forceEnv.Invoke(em); forced = !string.IsNullOrEmpty(text); if (!forced) { return s_current.Invoke(em); } if ((object)text != s_forcedName) { s_forcedName = text; s_forcedEnv = s_getEnv(em, text); } return s_forcedEnv; } private static EnvSetup PickNow(EnvMan em, Vector3 pos, long period) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) EnvSetup val = PickNowInner(em, pos, period); LabLastPick = string.Format("{0} for {1} period {2}", (val != null) ? val.m_name : "none", WorldGenerator.instance.GetBiomeSector(pos, false).Biome, period); return val; } private static EnvSetup PickNowInner(EnvMan em, Vector3 pos, long period) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_0065: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Unknown result type (might be due to invalid IL or missing references) //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0114: Unknown result type (might be due to invalid IL or missing references) BiomeSector biomeSector = WorldGenerator.instance.GetBiomeSector(pos, false); foreach (AltBiome altBiome in biomeSector.AltBiomes) { if (!string.IsNullOrEmpty(altBiome.m_forceEnvironment)) { return s_getEnv(em, altBiome.m_forceEnvironment); } } bool flag = WorldGenerator.IsAshlands(pos.x, pos.z); bool flag2 = WorldGenerator.IsDeepnorth(pos.x, pos.y); State state = Random.state; Random.InitState((int)period); EnvSetup result = null; List<EnvEntry> availableEnvironments = em.GetAvailableEnvironments(biomeSector); if (availableEnvironments != null && availableEnvironments.Count > 0) { result = s_select(em, availableEnvironments); foreach (EnvEntry item in availableEnvironments) { if (item.m_ashlandsOverride && flag) { result = item.m_env; } if (item.m_deepnorthOverride && flag2) { result = item.m_env; } } } Random.state = state; return result; } internal static void Apply(Vector3 camPos) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_000e: Unknown result type (might be due to invalid IL or missing references) if (WindowFlags.EnvGroups && !s_applied) { ApplyGrouped(camPos); } else { ApplyOne(camPos); } } private static void ApplyOne(Vector3 camPos) { //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0082: 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_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_00aa: 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_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00be: 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_00cd: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_0181: Unknown result type (might be due to invalid IL or missing references) //IL_017d: Unknown result type (might be due to invalid IL or missing references) EnvMan instance = EnvMan.instance; if (s_applied || !s_have || (Object)(object)instance == (Object)null || (Object)(object)instance.m_dirLight == (Object)null) { return; } Place place = (FarFlags.WeatherParity ? ViewPlace(camPos) : null); EnvSetup val = Pick(camPos, places: true, place); if (val == null && (place == null || !PlaceDiffers(instance, place))) { return; } Light dirLight = instance.m_dirLight; s_applied = true; s_lightRot = ((Component)dirLight).transform.rotation; s_lightIntensity = dirLight.intensity; s_lightColor = dirLight.color; s_fogColor = RenderSettings.fogColor; s_fogDensity = RenderSettings.fogDensity; s_ambient = RenderSettings.ambientLight; s_skyDir = Shader.GetGlobalVector(s_skyboxSunDir); s_sunDirValue = Shader.GetGlobalVector(s_sunDir); s_sunFog = Shader.GetGlobalColor(s_sunFogColor); s_sunCol = Shader.GetGlobalColor(s_sunColor); s_ambientGlobal = Shader.GetGlobalColor(s_ambientColor); s_wetValue = Shader.GetGlobalFloat(s_wet); s_auroraValue = Shader.GetGlobalFloat(s_aurora); Material val2 = (((Object)(object)instance.m_clouds != (Object)null) ? ((Renderer)instance.m_clouds).sharedMaterial : null); if ((Object)(object)val2 != (Object)null) { s_rainValue = val2.GetFloat(s_rain); s_opacityValue = val2.GetFloat(s_opacity); } bool weatherParity = FarFlags.WeatherParity; if (val == null) { SwapPlace(instance, null, place); return; } EnvSetup val3 = (weatherParity ? LookOf(place, val) : val); Set(instance, val3, WetAt(place?.At ?? camPos, val)); if (weatherParity) { Aurora(place, val); } LabApplied = val.m_name; Applied = val3; SetWind(instance, val3); if (weatherParity) { SwapPlace(instance, val, place); } else { SwapWeather(instance, val); } } private static void ApplyGrouped(Vector3 camPos) { //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_010b: Unknown result type (might be due to invalid IL or missing references) //IL_0107: Unknown result type (might be due to invalid IL or missing references) EnvMan instance = EnvMan.instance; if (!s_have || (Object)(object)instance == (Object)null || (Object)(object)instance.m_dirLight == (Object)null) { return; } bool weatherParity = FarFlags.WeatherParity; Place place = (weatherParity ? ViewPlace(camPos) : null); EnvSetup val = Pick(camPos, places: true, place); if (val == null) { AreaRenderState.ToGame(instance); AuroraBack(); if (place != null && PlaceDiffers(instance, place)) { if (!s_placeSwapped || s_swapPlace != place |
plugins/RealPortalEngine.dll
Decompiled a day 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.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Cryptography; using System.Security.Permissions; using System.Text; using System.Threading; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Unity.Collections; using Unity.Jobs; using Unity.Mathematics; using UnityEngine; using UnityEngine.Experimental.Rendering; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = "")] [assembly: AssemblyCompany("RealPortalEngine")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RealPortalEngine")] [assembly: AssemblyTitle("RealPortalEngine")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] namespace RealPortal { public static class Features { private static readonly Dictionary<string, Feature> s_byName = new Dictionary<string, Feature>(StringComparer.OrdinalIgnoreCase); private static ConfigFile s_config; public static IEnumerable<Feature> All => s_byName.Values; public static ConfigFile Config => s_config; public static event Action<Feature> Changed; public static Feature Register(string name, bool defaultOn, string description) { if (s_byName.TryGetValue(name, out var value)) { return value; } Feature feature = new Feature(name, defaultOn, description); s_byName.Add(name, feature); if (s_config != null) { feature.Bind(s_config); } return feature; } public static bool Get(string name) { if (s_byName.TryGetValue(name, out var value)) { return value.On; } return false; } public static bool Set(string name, bool on) { if (!s_byName.TryGetValue(name, out var value)) { return false; } value.Switch(on); return true; } internal static void BindConfig(ConfigFile config) { s_config = config; foreach (Feature value in s_byName.Values) { value.Bind(config); } } internal static void Raise(Feature f) { Features.Changed?.Invoke(f); } } public sealed class Feature { public readonly string Name; public readonly string Description; public bool On; private ConfigEntry<bool> _entry; public event Action<bool> Switched; internal Feature(string name, bool on, string description) { Name = name; On = on; Description = description; } internal void Bind(ConfigFile config) { if (_entry == null) { _entry = config.Bind<bool>("Engine", Name, On, Description); Switch(_entry.Value); _entry.SettingChanged += delegate { Switch(_entry.Value); }; } } internal void Switch(bool on) { if (_entry != null && _entry.Value != on) { _entry.Value = on; } if (On != on) { On = on; this.Switched?.Invoke(on); Features.Raise(this); } } public override string ToString() { return Name + "=" + (On ? "on" : "off"); } } } namespace RealPortal.Engine { [AttributeUsage(AttributeTargets.Class)] public sealed class EngineModuleAttribute : Attribute { } [BepInPlugin("valheim.realportal.engine", "Real Portal Engine", "0.1.2")] public class EnginePlugin : BaseUnityPlugin { public const string Guid = "valheim.realportal.engine"; public const string Name = "Real Portal Engine"; public const string Version = "0.1.2"; internal static ManualLogSource Log; internal static Harmony Harmony; private void Awake() { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Harmony = new Harmony("valheim.realportal.engine"); foreach (Type item in from t in typeof(EnginePlugin).Assembly.GetTypes() where t.GetCustomAttribute<EngineModuleAttribute>() != null orderby t.Name select t) { MethodInfo method = item.GetMethod("Install", BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic); try { method?.Invoke(null, new object[1] { Harmony }); Log.LogInfo((object)("module " + item.Name + " installed")); } catch (Exception ex) { Log.LogError((object)$"module {item.Name} failed to install, left out: {ex.InnerException ?? ex}"); } } Features.BindConfig(((BaseUnityPlugin)this).Config); Log.LogInfo((object)("features: " + string.Join(", ", Features.All.Select((Feature f) => f.ToString())))); } } [EngineModule] public static class AiStaggerModule { private sealed class FarEntry { internal int Wait; internal int Owed; internal long Seen; } private sealed class FarByReference : IEqualityComparer<IUpdateAI> { internal static readonly FarByReference Instance = new FarByReference(); public bool Equals(IUpdateAI a, IUpdateAI b) { return a == b; } public int GetHashCode(IUpdateAI o) { return RuntimeHelpers.GetHashCode(o); } } private delegate void HaveFriendsFn(BaseAI ai, float range, out Character hurtFriend, out Character friend); public sealed class Scheduler<T> where T : class { private sealed class Entry { internal int Phase; internal int PrevIndex = -1; internal long SeenStep = -1L; internal long LastSeq = -1L; internal long Epoch = -1L; } private sealed class ByReference : IEqualityComparer<T> { internal static readonly ByReference Instance = new ByReference(); public bool Equals(T a, T b) { return a == b; } public int GetHashCode(T o) { return RuntimeHelpers.GetHashCode(o); } } public const int Phases = 5; private const int RingSize = 8; private const int LookAhead = 4; private const int SweepSteps = 512; private const byte None = 0; private const byte OffSource = 1; private const byte OnSource = 2; private readonly byte[] m_src = new byte[8]; private readonly long[] m_at = new long[8]; private readonly long[] m_seq = new long[8]; private readonly Dictionary<T, Entry> m_entries = new Dictionary<T, Entry>(ByReference.Instance); private readonly int[] m_load = new int[5]; private readonly int[] m_count = new int[5]; private readonly List<T> m_stale = new List<T>(); private T[] m_prev = new T[64]; private T[] m_cur = new T[64]; private Entry[] m_prevE = new Entry[64]; private Entry[] m_curE = new Entry[64]; private int m_prevCount; private long m_step; private long m_epoch; private long m_lastWalk; private long m_onSources; private bool m_lastOn; private bool m_verify; public Action<T, long, long, long> Mismatched; public long Resets; public long Sources; public long Delivered; public long Walks; public long Created; public long VerifyChecks; public long VerifyMismatches; public int LastPass; public int MaxPass; public bool Verify { get { return m_verify; } set { if (value && !m_verify) { m_epoch++; } m_verify = value; } } public long StepCount => m_step; public int Tracked => m_entries.Count; public int[] Load => (int[])m_load.Clone(); public int PhaseOf(T item) { if (item == null || !m_entries.TryGetValue(item, out var value)) { return -1; } return value.Phase; } public void Reset() { Array.Clear(m_src, 0, 8); Array.Clear(m_at, 0, 8); Array.Clear(m_seq, 0, 8); m_entries.Clear(); Array.Clear(m_load, 0, 5); Array.Clear(m_count, 0, 5); m_stale.Clear(); Array.Clear(m_prev, 0, m_prev.Length); Array.Clear(m_prevE, 0, m_prevE.Length); Array.Clear(m_cur, 0, m_cur.Length); Array.Clear(m_curE, 0, m_curE.Length); m_prevCount = 0; m_lastWalk = m_step; m_epoch++; LastPass = 0; Resets++; } public int Step(bool tick, bool on, List<T> items, List<T> subset) { long num = ++m_step; int num2 = (int)(num & 7); m_at[num2] = num; m_src[num2] = (byte)(tick ? ((!on) ? 1 : 2) : 0); if (tick) { Sources++; if (on) { m_seq[num2] = ++m_onSources; } } if (on != m_lastOn) { m_lastOn = on; m_epoch++; } if (num % 512 == 0L) { Sweep(num); } subset.Clear(); int num3 = 0; for (int i = 0; i < 5; i++) { long num4 = num - i; int num5 = (int)(num4 & 7); if (num4 > 0 && m_at[num5] == num4 && m_src[num5] == 2) { num3 |= 1 << i; } } if (num3 == 0) { LastPass = 0; return 0; } Walk(num, num3, items, subset); LastPass = subset.Count; if (LastPass > MaxPass) { MaxPass = LastPass; } Delivered += LastPass; return LastPass; } private void Walk(long s, int due, List<T> items, List<T> subset) { Walks++; m_lastWalk = s; int count = items.Count; if (m_cur.Length < count) { int num = Math.Max(count, m_cur.Length * 2); m_cur = new T[num]; m_curE = new Entry[num]; } Array.Clear(m_count, 0, 5); int num2 = 0; for (int i = 0; i < count; i++) { T val = items[i]; Entry value = null; if (val != null) { if (num2 < m_prevCount && m_prev[num2] == val) { value = m_prevE[num2++]; } else { for (int j = num2 + 1; j < m_prevCount && j <= num2 + 4; j++) { if (m_prev[j] == val) { value = m_prevE[j]; num2 = j + 1; break; } } if (value == null) { if (m_entries.TryGetValue(val, out value)) { int prevIndex = value.PrevIndex; if (prevIndex >= num2 && prevIndex < m_prevCount && m_prev[prevIndex] == val) { num2 = prevIndex + 1; } } else { value = new Entry { Phase = Lightest() }; m_load[value.Phase]++; m_entries.Add(val, value); Created++; } } } } int num3 = value?.Phase ?? 0; m_count[num3]++; if (Verify && value != null && value.SeenStep != s - 1 && value.SeenStep != s) { value.LastSeq = -1L; } if (((due >> num3) & 1) != 0) { subset.Add(val); if (Verify && value != null) { Check(value, s, num3, val); } } if (value != null) { value.PrevIndex = i; value.SeenStep = s; } m_cur[i] = val; m_curE[i] = value; } T[] prev = m_prev; m_prev = m_cur; m_cur = prev; Entry[] prevE = m_prevE; m_prevE = m_curE; m_curE = prevE; Array.Clear(m_cur, 0, Math.Min(m_cur.Length, m_prevCount)); Array.Clear(m_curE, 0, Math.Min(m_curE.Length, m_prevCount)); m_prevCount = count; Array.Copy(m_count, m_load, 5); } private void Check(Entry e, long s, int phase, T item) { long num = s - phase; long num2 = m_seq[(int)(num & 7)]; if (e.Epoch == m_epoch && e.LastSeq >= 0) { VerifyChecks++; if (num2 != e.LastSeq + 1) { VerifyMismatches++; Mismatched?.Invoke(item, s, e.LastSeq, num2); } } e.LastSeq = num2; e.Epoch = m_epoch; } private int Lightest() { int num = 0; for (int i = 1; i < 5; i++) { if (m_load[i] < m_load[num]) { num = i; } } return num; } private void Sweep(long s) { m_stale.Clear(); foreach (KeyValuePair<T, Entry> entry in m_entries) { if (entry.Value.SeenStep < s - 512) { m_stale.Add(entry.Key); } } for (int i = 0; i < m_stale.Count; i++) { m_entries.Remove(m_stale[i]); } m_stale.Clear(); if (s - m_lastWalk > 512 && m_prevCount > 0) { Array.Clear(m_prev, 0, m_prevCount); Array.Clear(m_prevE, 0, m_prevCount); m_prevCount = 0; } } } internal static readonly Feature Stagger = Features.Register("AiStagger", defaultOn: false, "Creature AI ticks (20 Hz) are spread over all fixed steps by phase instead of all AIs in two steps out of five; each AI keeps the game's tick sequence and dt."); internal static readonly Feature FriendSkip = Features.Register("AiFriendScanSkip", defaultOn: true, "MonsterAI skips its once-a-second scans for friends when no item in the humanoid's inventory targets friends (the results would not be read)."); internal static readonly Feature Verify = Features.Register("AiVerify", defaultOn: false, "Lab: checks that every AI receives every AI tick exactly once under AiStagger, and runs the friend scans anyway while counting the skips AiFriendScanSkip would make."); private const float Tick = 0.05f; private const string Scope = "MonoUpdaters.FixedUpdate.BaseAI"; private const string LabOwners = "valheim.realportal.lab"; private const float ForeignCheckSeconds = 10f; public static long Passes; public static int MaxGamePass; public static long FriendScansRun; public static long FriendScansSkipped; public static long FriendWouldSkip; public static long FarTicks; public static long FarSkipped; public static long FarThinks; public static long FarFlushes; public static long FarPasses; public static long FarDropped; public static long FarHookErrors; public static Func<BaseAI, bool> IsFarSlow; public static int FarEvery = 4; private static readonly Scheduler<IUpdateAI> s_sched = new Scheduler<IUpdateAI>(); private static readonly List<IUpdateAI> s_subset = new List<IUpdateAI>(); private static FieldRef<MonoUpdaters, float> s_timer; private static FieldRef<MonoUpdaters, List<IUpdateAI>> s_container; private static MethodInfo s_fixedUpdate; private static MethodInfo s_updateAI; private static bool s_staggerPatched; private static bool s_staggerForeign; private static bool s_lastOn; private static bool s_broken; private static float s_nextStaggerCheck; private static MonoUpdaters s_owner; private static float s_probe; private const int MaxFarEvery = 8; private const long FarSweepSteps = 256L; private const float FarHookRetrySeconds = 10f; private static readonly Dictionary<IUpdateAI, FarEntry> s_far = new Dictionary<IUpdateAI, FarEntry>(FarByReference.Instance); private static readonly Stack<FarEntry> s_farPool = new Stack<FarEntry>(); private static readonly List<IUpdateAI> s_farStale = new List<IUpdateAI>(); private static readonly List<IUpdateAI>[] s_owed = NewGroups(); private static Func<BaseAI, bool> s_farHook; private static bool s_farPath; private static bool s_farOn; private static int s_farNext; private static long s_farSweptAt; private static Delegate s_farBroken; private static float s_farBrokenAt; private static FieldRef<Humanoid, Inventory> s_inventory; private static MethodBase[] s_friendWatch; private static MethodInfo s_selectBestAttack; private static bool s_friendPatched; private static bool s_friendForeign; private static float s_nextFriendCheck; private static readonly FieldInfo s_timerField = AccessTools.Field(typeof(MonoUpdaters), "m_updateAITimer"); private static readonly FieldInfo s_aiField = AccessTools.Field(typeof(MonoUpdaters), "m_ai"); private static readonly MethodInfo s_instancesGetter = AccessTools.PropertyGetter(typeof(BaseAI), "Instances"); private static readonly MethodInfo s_aiStep = AccessTools.DeclaredMethod(typeof(AiStaggerModule), "AiStep", (Type[])null, (Type[])null); private static readonly Dictionary<string, string> s_reported = new Dictionary<string, string>(); private static readonly FieldInfo s_labels = AccessTools.Field(typeof(CodeInstruction), "labels"); private static readonly FieldInfo s_blocks = AccessTools.Field(typeof(CodeInstruction), "blocks"); private static HaveFriendsFn s_haveFriends; private static readonly MethodInfo s_haveFriendsCall = AccessTools.DeclaredMethod(typeof(BaseAI), "HaveFriendsInRange", new Type[3] { typeof(float), typeof(Character).MakeByRefType(), typeof(Character).MakeByRefType() }, (Type[])null); private static readonly MethodInfo s_friendScan = AccessTools.DeclaredMethod(typeof(AiStaggerModule), "FriendScan", (Type[])null, (Type[])null); public static bool StaggerPatched => s_staggerPatched; public static bool StaggerForeign => s_staggerForeign; public static bool StaggerActive => s_lastOn; public static long Steps => s_sched.StepCount; public static long SourceTicks => s_sched.Sources; public static long Deliveries => s_sched.Delivered; public static int LastPass => s_sched.LastPass; public static int MaxPass => s_sched.MaxPass; public static long VerifyChecks => s_sched.VerifyChecks; public static long VerifyMismatches => s_sched.VerifyMismatches; public static long SchedulerResets => s_sched.Resets; public static bool FriendPatched => s_friendPatched; public static bool FriendForeign => s_friendForeign; public static bool FarActive => s_farOn; public static int FarTracked => s_far.Count; public static void ResetPeaks() { s_sched.MaxPass = 0; MaxGamePass = 0; } public static string Describe() { return $"AiStagger: patched {s_staggerPatched}, active {s_lastOn}, foreign {s_staggerForeign}, steps {s_sched.StepCount}, source ticks {s_sched.Sources}, " + string.Format("deliveries {0}, pass last/max {1}/{2} (game max {3}), phase load [{4}], ", s_sched.Delivered, s_sched.LastPass, s_sched.MaxPass, MaxGamePass, string.Join(",", s_sched.Load)) + $"verify {s_sched.VerifyChecks}/{s_sched.VerifyMismatches} mismatches, sessions {s_sched.Resets}; " + string.Format("far AIs: hook {0}, active {1}, every {2}, tracked {3}, ticks {4}, ", (IsFarSlow != null) ? "set" : "unset", s_farOn, FarEvery, s_far.Count, FarTicks) + $"skipped {FarSkipped}, thinks {FarThinks}, flushed {FarFlushes}, passes {FarPasses}, dropped {FarDropped}, hook errors {FarHookErrors}; " + $"AiFriendScanSkip: patched {s_friendPatched}, foreign {s_friendForeign}, run {FriendScansRun}, skipped {FriendScansSkipped}, would skip {FriendWouldSkip}"; } private static void Install(Harmony harmony) { try { InstallStagger(harmony); } catch (Exception ex) { s_staggerPatched = false; EnginePlugin.Log.LogError((object)("AiStagger: not installed, AI ticks stay as in the game: " + ex)); } try { InstallFriendSkip(harmony); } catch (Exception ex2) { s_friendPatched = false; EnginePlugin.Log.LogError((object)("AiFriendScanSkip: not installed, friend scans stay as in the game: " + ex2)); } Stagger.Switched += delegate { s_nextStaggerCheck = 0f; }; FriendSkip.Switched += delegate { s_nextFriendCheck = 0f; }; Verify.Switched += delegate(bool on) { s_sched.Verify = on; }; s_sched.Verify = Verify.On; } private static void InstallStagger(Harmony harmony) { //IL_00f7: 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_010a: Expected O, but got Unknown //IL_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown s_timer = AccessTools.FieldRefAccess<MonoUpdaters, float>("m_updateAITimer"); s_container = AccessTools.FieldRefAccess<MonoUpdaters, List<IUpdateAI>>("m_ai"); s_fixedUpdate = AccessTools.DeclaredMethod(typeof(MonoUpdaters), "FixedUpdate", (Type[])null, (Type[])null); s_updateAI = AccessTools.DeclaredMethod(typeof(MonoUpdatersExtra), "UpdateAI", (Type[])null, (Type[])null); if (s_fixedUpdate == null || s_updateAI == null) { EnginePlugin.Log.LogWarning((object)"AiStagger: MonoUpdaters.FixedUpdate or MonoUpdatersExtra.UpdateAI not found (game update?), left as in the game."); return; } try { MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(MonoUpdaters), "OnDestroy", (Type[])null, (Type[])null); if (methodInfo != null) { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeof(AiStaggerModule), "UpdatersDestroyed", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex) { EnginePlugin.Log.LogWarning((object)("AiStagger: MonoUpdaters.OnDestroy not patched (the next session still starts afresh): " + ex.Message)); } harmony.Patch((MethodBase)s_fixedUpdate, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AiStaggerModule), "FixedUpdateIL", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null); } private static void UpdatersDestroyed(MonoUpdaters __instance) { if (__instance == s_owner) { s_owner = null; s_sched.Reset(); s_subset.Clear(); ResetFar(); } } private static IEnumerable<CodeInstruction> FixedUpdateIL(IEnumerable<CodeInstruction> instructions, MethodBase original) { //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Expected O, but got Unknown //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Expected O, but got Unknown //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Expected O, but got Unknown //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int num = -1; int num2 = 0; object obj = null; for (int i = 0; i + 22 < list.Count; i++) { if (IsTimerBlock(list, i, out var end)) { num2++; num = i; obj = end; } } if (num2 != 1) { s_staggerPatched = false; ReportOnce("stagger", $"AiStagger: the AI timer block of MonoUpdaters.FixedUpdate was found {num2} times (changed by another mod or an update?), left as in the game.", warning: true); return list; } CodeInstruction[] array = (CodeInstruction[])(object)new CodeInstruction[4] { new CodeInstruction(OpCodes.Ldarg_0, (object)null), new CodeInstruction(list[num + 3].opcode, list[num + 3].operand), new CodeInstruction(OpCodes.Call, (object)s_aiStep), new CodeInstruction(OpCodes.Brtrue, obj) }; MoveMarks(s_labels, list[num], array[0]); MoveMarks(s_blocks, list[num], array[0]); list.InsertRange(num, array); s_staggerPatched = true; ReportOnce("stagger", "AiStagger: MonoUpdaters.FixedUpdate AI timer block wrapped.", warning: false); return list; } private static bool IsTimerBlock(List<CodeInstruction> c, int i, out object end) { end = null; if (!Is(c[i], OpCodes.Ldarg_0) || !Is(c[i + 1], OpCodes.Ldarg_0) || !LoadsField(c[i + 2], s_timerField) || !IsLocalOrArgLoad(c[i + 3]) || !Is(c[i + 4], OpCodes.Add) || !StoresField(c[i + 5], s_timerField) || !Is(c[i + 6], OpCodes.Ldarg_0) || !LoadsField(c[i + 7], s_timerField) || !IsR4(c[i + 8], 0.05f) || (!Is(c[i + 9], OpCodes.Blt_Un) && !Is(c[i + 9], OpCodes.Blt_Un_S)) || c[i + 9].operand == null || !Is(c[i + 10], OpCodes.Ldarg_0) || !LoadsField(c[i + 11], s_aiField) || !Calls(c[i + 12], s_instancesGetter) || !Is(c[i + 13], OpCodes.Ldstr) || !IsR4(c[i + 14], 0.05f) || !Calls(c[i + 15], s_updateAI) || !Is(c[i + 16], OpCodes.Ldarg_0) || !Is(c[i + 17], OpCodes.Ldarg_0) || !LoadsField(c[i + 18], s_timerField) || !IsR4(c[i + 19], 0.05f) || !Is(c[i + 20], OpCodes.Sub) || !StoresField(c[i + 21], s_timerField)) { return false; } object operand = c[i + 9].operand; if (!(s_labels?.GetValue(c[i + 22]) is IList list) || !list.Contains(operand)) { return false; } for (int j = i + 1; j <= i + 21; j++) { if (!Plain(c[j])) { return false; } } end = operand; return true; } private static bool Plain(CodeInstruction ci) { if (!(s_labels?.GetValue(ci) is ICollection { Count: not 0 })) { if (s_blocks?.GetValue(ci) is ICollection collection2) { return collection2.Count == 0; } return true; } return false; } private static void MoveMarks(FieldInfo field, CodeInstruction from, CodeInstruction to) { if (!(field?.GetValue(from) is IList list) || !(field.GetValue(to) is IList list2)) { return; } foreach (object item in list) { list2.Add(item); } list.Clear(); } private static bool Is(CodeInstruction ci, OpCode op) { return ci.opcode == op; } private static bool LoadsField(CodeInstruction ci, FieldInfo f) { if (f != null && ci.opcode == OpCodes.Ldfld) { return object.Equals(ci.operand, f); } return false; } private static bool StoresField(CodeInstruction ci, FieldInfo f) { if (f != null && ci.opcode == OpCodes.Stfld) { return object.Equals(ci.operand, f); } return false; } private static bool Calls(CodeInstruction ci, MethodInfo m) { if (m != null && (ci.opcode == OpCodes.Call || ci.opcode == OpCodes.Callvirt)) { return object.Equals(ci.operand, m); } return false; } private static bool IsR4(CodeInstruction ci, float v) { if (ci.opcode == OpCodes.Ldc_R4 && ci.operand is float num) { return num.Equals(v); } return false; } private static bool IsLocalOrArgLoad(CodeInstruction ci) { if (!(ci.opcode == OpCodes.Ldloc_0) && !(ci.opcode == OpCodes.Ldloc_1) && !(ci.opcode == OpCodes.Ldloc_2) && !(ci.opcode == OpCodes.Ldloc_3) && !(ci.opcode == OpCodes.Ldloc_S)) { return ci.opcode == OpCodes.Ldloc; } return true; } private static bool AiStep(MonoUpdaters updaters, float fixedDeltaTime) { if (s_broken) { return false; } if (updaters != s_owner) { if ((Object)(object)s_owner != (Object)null) { return false; } s_owner = updaters; s_sched.Reset(); s_subset.Clear(); ResetFar(); } float unscaledTime = Time.unscaledTime; if (unscaledTime >= s_nextStaggerCheck) { CheckStaggerForeign(unscaledTime); } bool flag = Stagger.On && !s_staggerForeign; if (flag != s_lastOn) { s_lastOn = flag; ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogInfo((object)(flag ? "AiStagger: AI ticks staggered by phase." : "AiStagger: AI ticks as in the game.")); } } FarStep(unscaledTime); ref float reference = ref s_timer.Invoke(updaters); s_probe = reference + fixedDeltaTime; bool flag2 = s_probe >= 0.05f; List<IUpdateAI> instances = BaseAI.Instances; if (flag2 && instances.Count > MaxGamePass) { MaxGamePass = instances.Count; } int num; try { num = s_sched.Step(flag2, flag, instances, s_subset); } catch (Exception ex) { s_broken = true; s_lastOn = false; s_subset.Clear(); ResetFar(); s_farOn = false; ManualLogSource log2 = EnginePlugin.Log; if (log2 != null) { log2.LogError((object)("AiStagger: scheduler failed, AI ticks as in the game for the rest of the session: " + ex)); } return false; } if (!flag) { if (num > 0) { Pass(updaters); } if (!s_farPath) { return false; } reference = s_probe; if (flag2) { s_subset.AddRange(instances); Pass(updaters); reference -= 0.05f; } return true; } reference = s_probe; if (num > 0) { Pass(updaters); } if (flag2) { reference -= 0.05f; } return true; } private static void Pass(MonoUpdaters updaters) { Passes++; List<IUpdateAI> list = s_container.Invoke(updaters); if (!s_farPath) { MonoUpdatersExtra.UpdateAI(list, s_subset, "MonoUpdaters.FixedUpdate.BaseAI", 0.05f); s_subset.Clear(); return; } Split(); MonoUpdatersExtra.UpdateAI(list, s_owed[1], "MonoUpdaters.FixedUpdate.BaseAI", 0.05f); s_owed[1].Clear(); for (int i = 2; i <= 8; i++) { List<IUpdateAI> list2 = s_owed[i]; if (list2.Count != 0) { FarPasses++; MonoUpdatersExtra.UpdateAI(list, list2, "MonoUpdaters.FixedUpdate.BaseAI", (float)i * 0.05f); list2.Clear(); } } } private static void FarStep(float now) { Func<BaseAI, bool> func = IsFarSlow; if (func != null && (object)func == s_farBroken && now - s_farBrokenAt < 10f) { func = null; } if (s_staggerForeign) { func = null; if (s_far.Count > 0) { ResetFar(); } } s_farHook = func; s_farPath = func != null || s_far.Count > 0; if (func != null != s_farOn) { s_farOn = func != null; ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogInfo((object)(s_farOn ? $"AiStagger: far AIs (Real Portal) think every {FarEvery} ticks." : "AiStagger: far AIs think every tick.")); } } if (s_far.Count > 0 && s_sched.StepCount - s_farSweptAt >= 256) { SweepFar(); } } private static void Split() { for (int i = 1; i <= 8; i++) { s_owed[i].Clear(); } Func<BaseAI, bool> hook = s_farHook; int num = ((FarEvery < 1) ? 1 : ((FarEvery > 8) ? 8 : FarEvery)); long stepCount = s_sched.StepCount; List<IUpdateAI> list = s_subset; for (int j = 0; j < list.Count; j++) { IUpdateAI val = list[j]; int num2 = 1; if (hook != null) { BaseAI val2 = (BaseAI)(object)((val is BaseAI) ? val : null); if (val2 != null && AskFar(ref hook, val2)) { FarTicks++; if (!s_far.TryGetValue(val, out var value)) { value = ((s_farPool.Count > 0) ? s_farPool.Pop() : new FarEntry()); s_farNext = (s_farNext + 1) % num; value.Wait = s_farNext + 1; value.Owed = 0; s_far.Add(val, value); } value.Seen = stepCount; value.Owed++; if (--value.Wait > 0) { FarSkipped++; continue; } value.Wait = num; num2 = value.Owed; value.Owed = 0; FarThinks++; goto IL_01b3; } } if (s_far.Count > 0 && val != null && s_far.TryGetValue(val, out var value2)) { num2 = value2.Owed + 1; s_far.Remove(val); s_farPool.Push(value2); FarFlushes++; } goto IL_01b3; IL_01b3: s_owed[(num2 < 1) ? 1 : ((num2 > 8) ? 8 : num2)].Add(val); } list.Clear(); } private static bool AskFar(ref Func<BaseAI, bool> hook, BaseAI ai) { try { return hook(ai); } catch (Exception arg) { FarHookErrors++; if ((object)s_farBroken != hook) { ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogWarning((object)$"AiStagger: Real Portal's IsFarSlow threw, far AIs think every tick until it is replaced (asked again every {10f:F0} s): {arg}"); } } s_farBroken = hook; s_farBrokenAt = Time.unscaledTime; hook = null; s_farHook = null; return false; } } private static void SweepFar() { long num = (s_farSweptAt = s_sched.StepCount); s_farStale.Clear(); foreach (KeyValuePair<IUpdateAI, FarEntry> item in s_far) { if (num - item.Value.Seen > 256) { s_farStale.Add(item.Key); } } for (int i = 0; i < s_farStale.Count; i++) { FarEntry farEntry = s_far[s_farStale[i]]; FarDropped += farEntry.Owed; s_far.Remove(s_farStale[i]); s_farPool.Push(farEntry); } s_farStale.Clear(); } private static void ResetFar() { foreach (KeyValuePair<IUpdateAI, FarEntry> item in s_far) { FarDropped += item.Value.Owed; s_farPool.Push(item.Value); } s_far.Clear(); for (int i = 1; i <= 8; i++) { s_owed[i].Clear(); } s_farStale.Clear(); } private static List<IUpdateAI>[] NewGroups() { List<IUpdateAI>[] array = new List<IUpdateAI>[9]; for (int i = 1; i <= 8; i++) { array[i] = new List<IUpdateAI>(); } return array; } private static void CheckStaggerForeign(float now) { s_nextStaggerCheck = now + 10f; string text = ""; bool flag; try { Patches patchInfo = Harmony.GetPatchInfo((MethodBase)s_fixedUpdate); Patches patchInfo2 = Harmony.GetPatchInfo((MethodBase)s_updateAI); flag = (patchInfo != null && (Foreign(patchInfo.Transpilers) || Foreign(patchInfo.ILManipulators))) || (patchInfo2 != null && (Foreign(patchInfo2.Prefixes) || Foreign(patchInfo2.Postfixes) || Foreign(patchInfo2.Transpilers) || Foreign(patchInfo2.Finalizers) || Foreign(patchInfo2.ILManipulators))); if (flag) { text = "another mod patches MonoUpdaters.FixedUpdate (IL) or MonoUpdatersExtra.UpdateAI"; } } catch (Exception ex) { flag = true; text = "reading Harmony patch info failed (" + ex.Message + ")"; } if (flag != s_staggerForeign) { ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogWarning((object)(flag ? ("AiStagger: " + text + ", AI ticks as in the game.") : "AiStagger: no foreign patches any more.")); } } s_staggerForeign = flag; } private static void InstallFriendSkip(Harmony harmony) { //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01bd: Unknown result type (might be due to invalid IL or missing references) //IL_01cb: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(BaseAI), "HaveFriendsInRange", new Type[3] { typeof(float), typeof(Character).MakeByRefType(), typeof(Character).MakeByRefType() }, (Type[])null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(BaseAI), "HaveFriendInRange", new Type[2] { typeof(List<Character>), typeof(float) }, (Type[])null); MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(BaseAI), "HaveHurtFriendInRange", new Type[2] { typeof(List<Character>), typeof(float) }, (Type[])null); MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(Humanoid), "EquipBestWeapon", (Type[])null, (Type[])null); s_selectBestAttack = AccessTools.DeclaredMethod(typeof(MonsterAI), "SelectBestAttack", (Type[])null, (Type[])null); if (methodInfo == null || methodInfo2 == null || methodInfo3 == null || methodInfo4 == null || s_selectBestAttack == null) { EnginePlugin.Log.LogWarning((object)"AiFriendScanSkip: a target method is missing (game update?), left as in the game."); return; } ParameterInfo[] parameters = s_selectBestAttack.GetParameters(); if (parameters.Length < 1 || parameters[0].ParameterType != typeof(Humanoid)) { EnginePlugin.Log.LogWarning((object)"AiFriendScanSkip: MonsterAI.SelectBestAttack has another signature (game update?), left as in the game."); return; } s_inventory = AccessTools.FieldRefAccess<Humanoid, Inventory>("m_inventory"); s_haveFriends = AccessTools.MethodDelegate<HaveFriendsFn>(methodInfo, (object)null, true); s_friendWatch = new MethodBase[4] { methodInfo, methodInfo2, methodInfo3, methodInfo4 }; harmony.Patch((MethodBase)s_selectBestAttack, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(typeof(AiStaggerModule), "SelectBestAttackIL", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null); } private static IEnumerable<CodeInstruction> SelectBestAttackIL(IEnumerable<CodeInstruction> instructions, MethodBase original) { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_009e: Expected O, but got Unknown List<CodeInstruction> list = new List<CodeInstruction>(instructions); int index = -1; int num = 0; for (int i = 0; i < list.Count; i++) { if (Calls(list[i], s_haveFriendsCall)) { num++; index = i; } } if (num != 1 || !Plain(list[index])) { s_friendPatched = false; ReportOnce("friend", $"AiFriendScanSkip: MonsterAI.SelectBestAttack calls HaveFriendsInRange {num} times or jumps onto the call (changed by another mod or an update?), left as in the game.", warning: true); return list; } list[index].opcode = OpCodes.Call; list[index].operand = s_friendScan; list.Insert(index, new CodeInstruction(OpCodes.Ldarg_1, (object)null)); s_friendPatched = true; ReportOnce("friend", "AiFriendScanSkip: MonsterAI.SelectBestAttack friend scan routed.", warning: false); return list; } private static void FriendScan(BaseAI ai, float range, out Character hurtFriend, out Character friend, Humanoid humanoid) { if (FriendSkip.On && (Object)(object)humanoid != (Object)null) { float unscaledTime = Time.unscaledTime; if (unscaledTime >= s_nextFriendCheck) { CheckFriendForeign(unscaledTime); } if (!s_friendForeign && !NeedsFriends(humanoid)) { if (!Verify.On) { FriendScansSkipped++; hurtFriend = null; friend = null; return; } FriendWouldSkip++; } } FriendScansRun++; s_haveFriends(ai, range, out hurtFriend, out friend); } private static bool NeedsFriends(Humanoid humanoid) { try { return ItemTargetsFriends(humanoid); } catch (Exception) { return true; } } private static bool ItemTargetsFriends(Humanoid humanoid) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Invalid comparison between Unknown and I4 //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 Inventory val = s_inventory.Invoke(humanoid); if (val == null) { return true; } List<ItemData> allItems = val.GetAllItems(); if (allItems == null) { return true; } for (int i = 0; i < allItems.Count; i++) { ItemData val2 = allItems[i]; if (val2?.m_shared == null) { return true; } AiTarget aiTargetType = val2.m_shared.m_aiTargetType; if ((int)aiTargetType == 2 || (int)aiTargetType == 1) { return true; } } return false; } private static void CheckFriendForeign(float now) { s_nextFriendCheck = now + 10f; bool flag = false; try { MethodBase[] array = s_friendWatch; for (int i = 0; i < array.Length; i++) { Patches patchInfo = Harmony.GetPatchInfo(array[i]); if (patchInfo != null && (Foreign(patchInfo.Prefixes) || Foreign(patchInfo.Postfixes) || Foreign(patchInfo.Transpilers) || Foreign(patchInfo.Finalizers) || Foreign(patchInfo.ILManipulators))) { flag = true; } } Patches patchInfo2 = Harmony.GetPatchInfo((MethodBase)s_selectBestAttack); if (patchInfo2 != null && (Foreign(patchInfo2.Transpilers) || Foreign(patchInfo2.ILManipulators))) { flag = true; } } catch (Exception) { flag = true; } if (flag != s_friendForeign) { ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogWarning((object)(flag ? "AiFriendScanSkip: another mod patches the friend scans, EquipBestWeapon or SelectBestAttack; scans run as in the game." : "AiFriendScanSkip: no foreign patches any more.")); } } s_friendForeign = flag; } private static bool Foreign(IEnumerable<Patch> patches) { if (patches == null) { return false; } foreach (Patch patch in patches) { if (patch.owner != "valheim.realportal.engine" && (patch.owner == null || !patch.owner.StartsWith("valheim.realportal.lab", StringComparison.Ordinal))) { return true; } } return false; } private static void ReportOnce(string key, string message, bool warning) { if (s_reported.TryGetValue(key, out var value) && value == message) { return; } s_reported[key] = message; if (warning) { ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogWarning((object)message); } } else { ManualLogSource log2 = EnginePlugin.Log; if (log2 != null) { log2.LogInfo((object)message); } } } } [EngineModule] internal static class AllocFixesModule { private sealed class IndexedKeys { private const int Max = 256; internal readonly string Prefix; private string[] _keys = new string[8]; internal IndexedKeys(string prefix) { Prefix = prefix; } internal string Get(int index) { if ((uint)index >= 256u) { return Prefix + index; } if (index >= _keys.Length) { Array.Resize(ref _keys, Math.Min(256, Math.Max(index + 1, _keys.Length * 2))); } return _keys[index] ?? (_keys[index] = Prefix + index); } } private sealed class ColliderPool { private const int Kept = 128; private const int MaxBuffer = 2048; private readonly string _site; private Collider[] _buffer = (Collider[])(object)new Collider[128]; private readonly Collider[][] _exact = new Collider[128][]; private Collider[] _handedOut; internal ColliderPool(string site) { _site = site; } internal Collider[] OverlapSphere(Vector3 position, float radius, int layerMask, QueryTriggerInteraction triggers) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_003a: 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_0056: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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) if (!s_overlap.On) { return Physics.OverlapSphere(position, radius, layerMask, triggers); } if (_handedOut != null) { Array.Clear(_handedOut, 0, _handedOut.Length); _handedOut = null; } int num = Physics.OverlapSphereNonAlloc(position, radius, _buffer, layerMask, triggers); if (num >= _buffer.Length) { Collider[] array = Physics.OverlapSphere(position, radius, layerMask, triggers); Grow(array.Length); return array; } Collider[] array2; if (num == 0) { array2 = Array.Empty<Collider>(); } else if (num < 128) { Collider[] obj = _exact[num] ?? (_exact[num] = (Collider[])(object)new Collider[num]); Collider[] array3 = obj; _handedOut = obj; array2 = array3; } else { array2 = (Collider[])(object)new Collider[num]; } Array.Copy(_buffer, array2, num); Array.Clear(_buffer, 0, num); if (s_verify.On) { return Verify(array2, Physics.OverlapSphere(position, radius, layerMask, triggers)); } return array2; } private void Grow(int count) { int num = _buffer.Length; while (num <= count && num < 2048) { num *= 2; } if (num > _buffer.Length) { _buffer = (Collider[])(object)new Collider[Math.Min(num, 2048)]; } else { Array.Clear(_buffer, 0, _buffer.Length); } } private Collider[] Verify(Collider[] ours, Collider[] game) { VerifyChecks++; bool flag = ours.Length == game.Length; int num = 0; while (flag && num < ours.Length) { flag = ours[num] == game[num]; num++; } if (flag) { return ours; } bool flag2 = ours.Length == game.Length && new HashSet<Object>((IEnumerable<Object>)(object)ours, ByReference.Instance).SetEquals((IEnumerable<Object>)(object)game); Mismatch(_site, flag2 ? $"the same {ours.Length} colliders in another order" : $"{ours.Length} vs {game.Length} colliders, not the same ones"); return game; } } private delegate int RaycastIntoFn(PhysicsScene scene, Ray ray, RaycastHit[] hits, float maxDistance, int mask, QueryTriggerInteraction triggers); private delegate int SphereCastIntoFn(PhysicsScene scene, Vector3 origin, float radius, Vector3 direction, RaycastHit[] hits, float maxDistance, int mask, QueryTriggerInteraction triggers); private sealed class HitPool { private const int Kept = 64; private const int MaxBuffer = 1024; private const float Tolerance = 1E-06f; private static readonly Comparison<RaycastHit> s_byDistance = (RaycastHit x, RaycastHit y) => ((RaycastHit)(ref x)).distance.CompareTo(((RaycastHit)(ref y)).distance); private readonly string _site; internal RaycastHit[] Buffer = (RaycastHit[])(object)new RaycastHit[64]; private readonly RaycastHit[][] _exact = new RaycastHit[64][]; internal HitPool(string site) { _site = site; } internal RaycastHit[] Take(int n) { if (n == 0) { return Array.Empty<RaycastHit>(); } RaycastHit[] array = (RaycastHit[])((n < 64) ? ((Array)(_exact[n] ?? (_exact[n] = (RaycastHit[])(object)new RaycastHit[n]))) : ((Array)new RaycastHit[n])); Array.Copy(Buffer, array, n); return array; } internal void Grow(int count) { int num = Buffer.Length; while (num <= count && num < 1024) { num *= 2; } if (num > Buffer.Length) { Buffer = (RaycastHit[])(object)new RaycastHit[Math.Min(num, 1024)]; } } internal RaycastHit[] Verify(RaycastHit[] ours, RaycastHit[] game) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0128: 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_0132: Unknown result type (might be due to invalid IL or missing references) //IL_0137: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: 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_01e0: Unknown result type (might be due to invalid IL or missing references) //IL_01ec: 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_021a: Unknown result type (might be due to invalid IL or missing references) //IL_0226: Unknown result type (might be due to invalid IL or missing references) //IL_0248: Unknown result type (might be due to invalid IL or missing references) //IL_0254: Unknown result type (might be due to invalid IL or missing references) //IL_0265: Unknown result type (might be due to invalid IL or missing references) //IL_0271: 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 references) //IL_028e: Unknown result type (might be due to invalid IL or missing references) VerifyChecks++; bool flag = ours.Length == game.Length; int num; for (int i = 0; flag && i < ours.Length; flag = (byte)num != 0, i++) { RaycastHit val = ours[i]; RaycastHit val2 = game[i]; if (((RaycastHit)(ref val)).colliderInstanceID == ((RaycastHit)(ref val2)).colliderInstanceID && ((RaycastHit)(ref val)).distance.Equals(((RaycastHit)(ref val2)).distance)) { Vector3 val3 = ((RaycastHit)(ref val)).point; if (((Vector3)(ref val3)).Equals(((RaycastHit)(ref val2)).point)) { val3 = ((RaycastHit)(ref val)).normal; if (((Vector3)(ref val3)).Equals(((RaycastHit)(ref val2)).normal)) { num = ((((RaycastHit)(ref val)).triangleIndex == ((RaycastHit)(ref val2)).triangleIndex) ? 1 : 0); continue; } } } num = 0; } if (flag) { return ours; } if (!SameColliders(ours, game)) { Mismatch(_site, $"{ours.Length} vs {game.Length} hits, not the same colliders"); return game; } RaycastHit[] array = (RaycastHit[])ours.Clone(); RaycastHit[] array2 = (RaycastHit[])game.Clone(); Array.Sort(array, s_byDistance); Array.Sort(array2, s_byDistance); float num2 = 0f; for (int j = 0; j < array.Length; j++) { RaycastHit val4 = array[j]; RaycastHit val5 = array2[j]; if (((RaycastHit)(ref val4)).colliderInstanceID != ((RaycastHit)(ref val5)).colliderInstanceID) { Mismatch(_site, $"the same {ours.Length} colliders, another order after the game's distance sort (hit {j})"); return game; } if (((RaycastHit)(ref val4)).distance == 0f != (((RaycastHit)(ref val5)).distance == 0f)) { Mismatch(_site, $"hit {j} starts inside the collider in one answer only (distance {((RaycastHit)(ref val4)).distance} vs {((RaycastHit)(ref val5)).distance})"); return game; } num2 = Math.Max(num2, Off(((RaycastHit)(ref val4)).distance, ((RaycastHit)(ref val5)).distance)); num2 = Math.Max(num2, Math.Max(Off(((RaycastHit)(ref val4)).point.x, ((RaycastHit)(ref val5)).point.x), Math.Max(Off(((RaycastHit)(ref val4)).point.y, ((RaycastHit)(ref val5)).point.y), Off(((RaycastHit)(ref val4)).point.z, ((RaycastHit)(ref val5)).point.z)))); num2 = Math.Max(num2, Math.Max(Off(((RaycastHit)(ref val4)).normal.x, ((RaycastHit)(ref val5)).normal.x), Math.Max(Off(((RaycastHit)(ref val4)).normal.y, ((RaycastHit)(ref val5)).normal.y), Off(((RaycastHit)(ref val4)).normal.z, ((RaycastHit)(ref val5)).normal.z)))); } if (num2 > 1f) { Drift(_site, $"{ours.Length} hits, values off by up to {num2:0.#}x the rounding band"); } else { Noise(_site, $"{ours.Length} hits: native order or rounding-level values only"); } return game; } private static float Off(float a, float b) { float num = 1E-06f * Math.Max(1f, Math.Max(Math.Abs(a), Math.Abs(b))); return Math.Abs(a - b) / num; } private static bool SameColliders(RaycastHit[] a, RaycastHit[] b) { if (a.Length != b.Length) { return false; } int[] array = new int[a.Length]; int[] array2 = new int[b.Length]; for (int i = 0; i < a.Length; i++) { array[i] = ((RaycastHit)(ref a[i])).colliderInstanceID; array2[i] = ((RaycastHit)(ref b[i])).colliderInstanceID; } Array.Sort(array); Array.Sort(array2); for (int j = 0; j < array.Length; j++) { if (array[j] != array2[j]) { return false; } } return true; } } private readonly struct SpawnKey : IEquatable<SpawnKey> { private readonly string _salt; private readonly GameObject _prefab; private readonly int _index; internal SpawnKey(string salt, GameObject prefab, int index) { _salt = salt; _prefab = prefab; _index = index; } public bool Equals(SpawnKey other) { if (_prefab == other._prefab && _index == other._index) { return string.Equals(_salt, other._salt); } return false; } public override bool Equals(object obj) { if (obj is SpawnKey other) { return Equals(other); } return false; } public override int GetHashCode() { return (((RuntimeHelpers.GetHashCode(_prefab) * 397) ^ _index) * 397) ^ (_salt?.GetHashCode() ?? 0); } } private sealed class ByReference : IEqualityComparer<Object> { internal static readonly ByReference Instance = new ByReference(); public bool Equals(Object x, Object y) { return x == y; } public int GetHashCode(Object obj) { return RuntimeHelpers.GetHashCode(obj); } } private static readonly Feature s_zdoKeys = Features.Register("AllocZdoKeys", defaultOn: true, "Cooking stations and mine rocks reuse their ZDO key strings (\"slot\" + i, \"Health\" + i) instead of building new ones every frame or check."); private static readonly Feature s_overlap = Features.Register("AllocOverlap", defaultOn: true, "Physics.OverlapSphere in MonsterAI.FindClosestConsumableItem and ItemDrop.AutoStackItems reuses arrays."); private static readonly Feature s_projectiles = Features.Register("AllocProjectile", defaultOn: true, "Projectiles' hit rays (RaycastAll every physics step) reuse arrays."); private static readonly Feature s_projectileSpheres = Features.Register("AllocProjectileSphere", defaultOn: false, "Lab, off until AllocVerify confirms it: with AllocProjectile, projectiles with a ray radius (SphereCastAll) also reuse arrays. Unity's non-allocating sphere cast may normalize the direction once more, so hits could differ by float rounding."); private static readonly Feature s_spawn = Features.Register("AllocSpawnSystem", defaultOn: true, "Spawn systems hash each spawner's timer key once instead of building the string every second."); private static readonly Feature s_heightmap = Features.Register("AllocHeightmap", defaultOn: true, "A new zone's terrain collision mesh takes its indices from the game's list instead of a 96 KB array copy."); private static readonly Feature s_turret = Features.Register("AllocTurret", defaultOn: true, "Ballistas compare ammo against cached prefab names instead of reading (allocating) every ammo type's name every physics step."); private static readonly Feature s_verify = Features.Register("AllocVerify", defaultOn: false, "Lab: also runs the game's own call next to each Alloc* replacement, uses its answer and logs any difference. Slower."); internal static long VerifyChecks; internal static long VerifyMismatches; internal static long VerifyDrift; internal static long VerifyNoise; private static readonly MethodInfo s_intToString = AccessTools.Method(typeof(int), "ToString", Type.EmptyTypes, (Type[])null); private static readonly MethodInfo s_concat2 = AccessTools.Method(typeof(string), "Concat", new Type[2] { typeof(string), typeof(string) }, (Type[])null); private static readonly MethodInfo s_concat3 = AccessTools.Method(typeof(string), "Concat", new Type[3] { typeof(string), typeof(string), typeof(string) }, (Type[])null); private static readonly MethodInfo s_format1 = AccessTools.Method(typeof(string), "Format", new Type[2] { typeof(string), typeof(object) }, (Type[])null); private static readonly MethodInfo s_stableHash = AccessTools.Method(typeof(StringExtensionMethods), "GetStableHashCode", new Type[1] { typeof(string) }, (Type[])null); private static readonly MethodInfo s_getName = AccessTools.PropertyGetter(typeof(Object), "name"); private static readonly MethodInfo s_listToArray = AccessTools.Method(typeof(List<int>), "ToArray", (Type[])null, (Type[])null); private static readonly MethodInfo s_setIndices = AccessTools.Method(typeof(Mesh), "SetIndices", new Type[3] { typeof(int[]), typeof(MeshTopology), typeof(int) }, (Type[])null); private static readonly MethodInfo s_overlap3 = AccessTools.Method(typeof(Physics), "OverlapSphere", new Type[3] { typeof(Vector3), typeof(float), typeof(int) }, (Type[])null); private static readonly MethodInfo s_raycastAll = AccessTools.Method(typeof(Physics), "RaycastAll", new Type[4] { typeof(Vector3), typeof(Vector3), typeof(float), typeof(int) }, (Type[])null); private static readonly MethodInfo s_sphereCastAll = AccessTools.Method(typeof(Physics), "SphereCastAll", new Type[5] { typeof(Vector3), typeof(float), typeof(Vector3), typeof(float), typeof(int) }, (Type[])null); private static readonly FieldInfo s_spawnPrefab = AccessTools.Field(typeof(SpawnData), "m_prefab"); private static readonly FieldInfo s_ammoField = AccessTools.Field(typeof(AmmoType), "m_ammo"); private static readonly Dictionary<string, int> s_reported = new Dictionary<string, int>(); private static readonly FieldInfo s_labels = AccessTools.Field(typeof(CodeInstruction), "labels"); private static IndexedKeys[] s_keySets = new IndexedKeys[0]; private static readonly ColliderPool s_consumablePool = new ColliderPool("MonsterAI.FindClosestConsumableItem"); private static readonly ColliderPool s_autoStackPool = new ColliderPool("ItemDrop.AutoStackItems"); private static readonly RaycastIntoFn s_raycastInto = Bind<RaycastIntoFn>(typeof(PhysicsScene), "Internal_RaycastNonAlloc"); private static readonly SphereCastIntoFn s_sphereCastInto = Bind<SphereCastIntoFn>(typeof(PhysicsScene), "Internal_SphereCastNonAlloc"); private static readonly HitPool s_rayPool = new HitPool("Projectile.FixedUpdate RaycastAll"); private static readonly HitPool s_spherePool = new HitPool("Projectile.FixedUpdate SphereCastAll"); private static readonly Dictionary<SpawnKey, int> s_spawnHashes = new Dictionary<SpawnKey, int>(); private static string s_saltFormat; private static readonly string[] s_salts = new string[16]; private static readonly Dictionary<Object, string> s_prefabNames = new Dictionary<Object, string>(ByReference.Instance); private static MethodInfo Ours(string name) { return AccessTools.DeclaredMethod(typeof(AllocFixesModule), name, (Type[])null, (Type[])null); } private static void Install(Harmony harmony) { Transpile(harmony, typeof(CookingStation), "GetSlot", "CookingStationKeys"); Transpile(harmony, typeof(CookingStation), "SetSlot", "CookingStationKeys"); Transpile(harmony, typeof(CookingStation), "IsEmpty", "CookingStationKeys"); Transpile(harmony, typeof(CookingStation), "GetFreeSlot", "CookingStationKeys"); Transpile(harmony, typeof(MineRock), "UpdateVisability", "MineRockKeys"); Transpile(harmony, typeof(MonsterAI), "FindClosestConsumableItem", "ConsumableOverlap"); Transpile(harmony, typeof(ItemDrop), "AutoStackItems", "AutoStackOverlap"); Transpile(harmony, typeof(Projectile), "FixedUpdate", "ProjectileRays"); Transpile(harmony, typeof(SpawnSystem), "UpdateSpawnList", "SpawnTimerKeys"); Transpile(harmony, typeof(SpawnSystem), "UpdateSpawning", "SpawnSalts"); Transpile(harmony, typeof(Heightmap), "RebuildCollisionMesh", "CollisionIndices"); Transpile(harmony, typeof(Turret), "UpdateVisualBolt", "TurretAmmoNames"); if (s_raycastInto == null || s_sphereCastInto == null) { EnginePlugin.Log.LogWarning((object)"AllocProjectile: Unity's PhysicsScene internals not found; projectile rays stay as in the game."); } s_spawn.Switched += delegate(bool on) { if (on) { s_spawnHashes.Clear(); } }; s_turret.Switched += delegate(bool on) { if (on) { s_prefabNames.Clear(); } }; } private static void Transpile(Harmony harmony, Type type, string method, string transpiler) { //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0050: Unknown result type (might be due to invalid IL or missing references) //IL_005e: Expected O, but got Unknown string text = type.Name + "." + method; try { MethodInfo methodInfo = AccessTools.DeclaredMethod(type, method, (Type[])null, (Type[])null); if (methodInfo == null) { EnginePlugin.Log.LogWarning((object)("AllocFixes: " + text + " not found, left as it is.")); return; } harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, (HarmonyMethod)null, new HarmonyMethod(Ours(transpiler)) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null); } catch (Exception arg) { EnginePlugin.Log.LogError((object)$"AllocFixes: {text} not patched: {arg}"); } } private static void Report(MethodBase original, string what, int n, int expected = 0) { string text = ((original != null) ? (original.DeclaringType?.Name + "." + original.Name) : "?") + ": " + what; if (!s_reported.TryGetValue(text, out var value) || value != n) { s_reported[text] = n; if (n == 0) { EnginePlugin.Log.LogWarning((object)("AllocFixes: " + text + ": not found (changed by another mod?), left as it is.")); } else if (expected > 0 && n != expected) { EnginePlugin.Log.LogWarning((object)($"AllocFixes: {text}: {n} calls where the game has {expected} (added by another mod or an update?); " + "each pooled array may serve one call site, so left as it is.")); } else { EnginePlugin.Log.LogInfo((object)$"AllocFixes: {text} x{n}"); } } } private static bool IsAddressLoad(CodeInstruction ci) { if (!(ci.opcode == OpCodes.Ldarga_S) && !(ci.opcode == OpCodes.Ldarga) && !(ci.opcode == OpCodes.Ldloca_S)) { return ci.opcode == OpCodes.Ldloca; } return true; } private static bool IsValueLoad(CodeInstruction ci) { OpCode opcode = ci.opcode; if (!(opcode == OpCodes.Ldloc_0) && !(opcode == OpCodes.Ldloc_1) && !(opcode == OpCodes.Ldloc_2) && !(opcode == OpCodes.Ldloc_3) && !(opcode == OpCodes.Ldloc_S) && !(opcode == OpCodes.Ldloc) && !(opcode == OpCodes.Ldarg_0) && !(opcode == OpCodes.Ldarg_1) && !(opcode == OpCodes.Ldarg_2) && !(opcode == OpCodes.Ldarg_3) && !(opcode == OpCodes.Ldarg_S)) { return opcode == OpCodes.Ldarg; } return true; } private static bool Unlabeled(CodeInstruction ci) { if (s_labels?.GetValue(ci) is ICollection collection) { return collection.Count == 0; } return true; } private static int Find(List<CodeInstruction> code, int start, params Func<CodeInstruction, bool>[] pattern) { for (int i = Math.Max(0, start); i + pattern.Length <= code.Count; i++) { int j; for (j = 0; j < pattern.Length && pattern[j](code[i + j]); j++) { } if (j == pattern.Length) { return i; } } return -1; } private static void Set(CodeInstruction ci, OpCode opcode, object operand) { ci.opcode = opcode; ci.operand = operand; } private static void Mismatch(string site, string detail) { VerifyMismatches++; if (VerifyMismatches <= 50) { EnginePlugin.Log.LogWarning((object)("AllocVerify: " + site + " differs from the game's own call: " + detail)); } } private static void Drift(string site, string detail) { VerifyDrift++; if (VerifyDrift <= 50) { EnginePlugin.Log.LogWarning((object)("AllocVerify: " + site + " hits the same colliders in the same order, but values differ: " + detail)); } } private static void Noise(string site, string detail) { VerifyNoise++; if (VerifyNoise <= 20) { EnginePlugin.Log.LogInfo((object)("AllocVerify: " + site + " differs only where the game cannot notice: " + detail)); } } private static IEnumerable<CodeInstruction> SwapCall(IEnumerable<CodeInstruction> code, MethodBase original, MethodInfo from, MethodInfo to) { List<CodeInstruction> list = new List<CodeInstruction>(code); int num = 0; if (from != null) { foreach (CodeInstruction item in list) { if (CodeInstructionExtensions.Calls(item, from)) { num++; } } } if (num == 1) { foreach (CodeInstruction item2 in list) { if (CodeInstructionExtensions.Calls(item2, from)) { Set(item2, OpCodes.Call, to); } } } Report(original, from?.Name + " -> " + to.Name, num, 1); return list; } private static IEnumerable<CodeInstruction> CookingStationKeys(IEnumerable<CodeInstruction> code, MethodBase original) { return CachedKeys(code, original, new string[2] { "slot", "slotstatus" }); } private static IEnumerable<CodeInstruction> MineRockKeys(IEnumerable<CodeInstruction> code, MethodBase original) { return CachedKeys(code, original, new string[1] { "Health" }); } private static IEnumerable<CodeInstruction> CachedKeys(IEnumerable<CodeInstruction> code, MethodBase original, string[] prefixes) { MethodInfo operand = Ours("ZdoKey"); List<CodeInstruction> list = new List<CodeInstruction>(code); int num = 0; int start = 0; while ((start = Find(list, start, (CodeInstruction ci) => ci.opcode == OpCodes.Ldstr && ci.operand is string value && Array.IndexOf(prefixes, value) >= 0, (CodeInstruction ci) => IsAddressLoad(ci) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_intToString) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_concat2) && Unlabeled(ci))) >= 0) { Set(list[start + 2], OpCodes.Ldind_I4, null); Set(list[start + 3], OpCodes.Call, operand); num++; start += 4; } Report(original, "cached ZDO keys", num); return list; } private static IndexedKeys KeysFor(string prefix) { IndexedKeys[] array = s_keySets; for (int i = 0; i < array.Length; i++) { if ((object)array[i].Prefix == prefix) { return array[i]; } } for (int j = 0; j < array.Length; j++) { if (array[j].Prefix == prefix) { return array[j]; } } IndexedKeys indexedKeys = new IndexedKeys(prefix); IndexedKeys[] array2 = new IndexedKeys[array.Length + 1]; Array.Copy(array, array2, array.Length); array2[array.Length] = indexedKeys; s_keySets = array2; return indexedKeys; } private static string ZdoKey(string prefix, int index) { if (!s_zdoKeys.On) { return prefix + index; } string text = KeysFor(prefix).Get(index); if (s_verify.On) { VerifyChecks++; string text2 = prefix + index; if (text2 != text) { Mismatch("ZDO key", "'" + text + "' vs '" + text2 + "'"); return text2; } } return text; } private static IEnumerable<CodeInstruction> ConsumableOverlap(IEnumerable<CodeInstruction> code, MethodBase original) { return SwapCall(code, original, s_overlap3, Ours("OverlapConsumable")); } private static IEnumerable<CodeInstruction> AutoStackOverlap(IEnumerable<CodeInstruction> code, MethodBase original) { return SwapCall(code, original, s_overlap3, Ours("OverlapAutoStack")); } private static Collider[] OverlapConsumable(Vector3 position, float radius, int layerMask) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return s_consumablePool.OverlapSphere(position, radius, layerMask, (QueryTriggerInteraction)0); } private static Collider[] OverlapAutoStack(Vector3 position, float radius, int layerMask) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) return s_autoStackPool.OverlapSphere(position, radius, layerMask, (QueryTriggerInteraction)0); } private static IEnumerable<CodeInstruction> ProjectileRays(IEnumerable<CodeInstruction> code, MethodBase original) { return SwapCall(SwapCall(code, original, s_raycastAll, Ours("ProjectileRaycastAll")), original, s_sphereCastAll, Ours("ProjectileSphereCastAll")); } private static T Bind<T>(Type type, string name) where T : Delegate { try { MethodInfo methodInfo = AccessTools.DeclaredMethod(type, name, (Type[])null, (Type[])null); return (methodInfo == null) ? null : ((T)Delegate.CreateDelegate(typeof(T), methodInfo, throwOnBindFailure: false)); } catch (Exception) { return null; } } private static RaycastHit[] ProjectileRaycastAll(Vector3 origin, Vector3 direction, float maxDistance, int layerMask) { //IL_0013: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) if (!s_projectiles.On || s_raycastInto == null) { return Physics.RaycastAll(origin, direction, maxDistance, layerMask); } float magnitude = ((Vector3)(ref direction)).magnitude; if (!(magnitude > float.Epsilon)) { return Array.Empty<RaycastHit>(); } Ray ray = default(Ray); ((Ray)(ref ray))..ctor(origin, direction / magnitude); int num = s_raycastInto(Physics.defaultPhysicsScene, ray, s_rayPool.Buffer, maxDistance, layerMask, (QueryTriggerInteraction)0); if (num >= s_rayPool.Buffer.Length) { RaycastHit[] array = Physics.RaycastAll(origin, direction, maxDistance, layerMask); s_rayPool.Grow(array.Length); return array; } RaycastHit[] array2 = s_rayPool.Take(num); if (s_verify.On) { return s_rayPool.Verify(array2, Physics.RaycastAll(origin, direction, maxDistance, layerMask)); } return array2; } private static RaycastHit[] ProjectileSphereCastAll(Vector3 origin, float radius, Vector3 direction, float maxDistance, int layerMask) { //IL_001f: 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_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0077: 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_00b0: 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) if (!s_projectiles.On || !s_projectileSpheres.On || s_sphereCastInto == null) { return Physics.SphereCastAll(origin, radius, direction, maxDistance, layerMask); } float magnitude = ((Vector3)(ref direction)).magnitude; if (!(magnitude > float.Epsilon)) { return Array.Empty<RaycastHit>(); } int num = s_sphereCastInto(Physics.defaultPhysicsScene, origin, radius, direction / magnitude, s_spherePool.Buffer, maxDistance, layerMask, (QueryTriggerInteraction)0); if (num >= s_spherePool.Buffer.Length) { RaycastHit[] array = Physics.SphereCastAll(origin, radius, direction, maxDistance, layerMask); s_spherePool.Grow(array.Length); return array; } RaycastHit[] array2 = s_spherePool.Take(num); if (s_verify.On) { return s_spherePool.Verify(array2, Physics.SphereCastAll(origin, radius, direction, maxDistance, layerMask)); } return array2; } private static IEnumerable<CodeInstruction> SpawnTimerKeys(IEnumerable<CodeInstruction> code, MethodBase original) { MethodInfo operand = Ours("SpawnTimerKey"); List<CodeInstruction> list = new List<CodeInstruction>(code); int num = 0; int start = 0; while ((start = Find(list, start, (CodeInstruction ci) => CodeInstructionExtensions.LoadsField(ci, s_spawnPrefab, false), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_getName) && Unlabeled(ci), (CodeInstruction ci) => IsAddressLoad(ci) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_intToString) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_concat3) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_stableHash) && Unlabeled(ci))) >= 0) { Set(list[start + 1], OpCodes.Nop, null); Set(list[start + 3], OpCodes.Ldind_I4, null); Set(list[start + 4], OpCodes.Nop, null); Set(list[start + 5], OpCodes.Call, operand); num++; start += 6; } Report(original, "spawn timer key hashes", num); return list; } private static IEnumerable<CodeInstruction> SpawnSalts(IEnumerable<CodeInstruction> code, MethodBase original) { MethodInfo operand = Ours("SpawnSalt"); List<CodeInstruction> list = new List<CodeInstruction>(code); int num = 0; int start = 0; while ((start = Find(list, start, (CodeInstruction ci) => ci.opcode == OpCodes.Ldstr, (CodeInstruction ci) => IsValueLoad(ci) && Unlabeled(ci), (CodeInstruction ci) => ci.opcode == OpCodes.Box && ci.operand is Type type && type == typeof(int) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_format1) && Unlabeled(ci))) >= 0) { Set(list[start + 2], OpCodes.Nop, null); Set(list[start + 3], OpCodes.Call, operand); num++; start += 4; } Report(original, "spawn salts", num); return list; } private static int SpawnTimerKey(string salt, GameObject prefab, int index) { if (!s_spawn.On || prefab == null || !Object.op_Implicit((Object)(object)prefab)) { return StringExtensionMethods.GetStableHashCode(salt + ((Object)prefab).name + index); } SpawnKey key = new SpawnKey(salt, prefab, index); if (!s_spawnHashes.TryGetValue(key, out var value)) { value = StringExtensionMethods.GetStableHashCode(salt + ((Object)prefab).name + index); if (s_spawnHashes.Count >= 4096) { s_spawnHashes.Clear(); } s_spawnHashes.Add(key, value); } else if (s_verify.On) { VerifyChecks++; int stableHashCode = StringExtensionMethods.GetStableHashCode(salt + ((Object)prefab).name + index); if (stableHashCode != value) { Mismatch("SpawnSystem timer key", $"{((Object)prefab).name} #{index}"); s_spawnHashes[key] = stableHashCode; return stableHashCode; } } return value; } private static string SpawnSalt(string format, int i) { if (!s_spawn.On || format == null || (uint)i >= s_salts.Length) { return string.Format(format, i); } if ((object)format != s_saltFormat) { if (format != s_saltFormat) { Array.Clear(s_salts, 0, s_salts.Length); } s_saltFormat = format; } string text = s_salts[i] ?? (s_salts[i] = string.Format(format, i)); if (s_verify.On) { VerifyChecks++; string text2 = string.Format(format, i); if (text2 != text) { Mismatch("SpawnSystem salt", "'" + text + "' vs '" + text2 + "'"); return text2; } } return text; } private static IEnumerable<CodeInstruction> CollisionIndices(IEnumerable<CodeInstruction> code, MethodBase original) { MethodInfo operand = Ours("SetCollisionIndices"); List<CodeInstruction> list = new List<CodeInstruction>(code); int num = 0; int start = 0; while ((start = Find(list, start, (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_listToArray), (CodeInstruction ci) => CodeInstructionExtensions.LoadsConstant(ci) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.LoadsConstant(ci) && Unlabeled(ci), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_setIndices) && Unlabeled(ci))) >= 0) { Set(list[start], OpCodes.Nop, null); Set(list[start + 3], OpCodes.Call, operand); num++; start += 4; } Report(original, "index uploads from the list", num); return list; } private static void SetCollisionIndices(Mesh mesh, List<int> indices, MeshTopology topology, int submesh) { //IL_001d: 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) if (!s_heightmap.On) { mesh.SetIndices(indices.ToArray(), topology, submesh); } else { mesh.SetIndices(indices, topology, submesh, true, 0); } } private static IEnumerable<CodeInstruction> TurretAmmoNames(IEnumerable<CodeInstruction> code, MethodBase original) { MethodInfo operand = Ours("AmmoPrefabName"); List<CodeInstruction> list = new List<CodeInstruction>(code); int num = 0; int start = 0; while ((start = Find(list, start, (CodeInstruction ci) => CodeInstructionExtensions.LoadsField(ci, s_ammoField, false), (CodeInstruction ci) => CodeInstructionExtensions.Calls(ci, s_getName) && Unlabeled(ci))) >= 0) { Set(list[start + 1], OpCodes.Call, operand); num++; start += 2; } Report(original, "cached ammo names", num); return list; } private static string AmmoPrefabName(Object prefab) { if (!s_turret.On || prefab == null || !Object.op_Implicit(prefab)) { return prefab.name; } if (!s_prefabNames.TryGetValue(prefab, out var value)) { value = prefab.name; if (s_prefabNames.Count >= 4096) { s_prefabNames.Clear(); } s_prefabNames.Add(prefab, value); } else if (s_verify.On) { VerifyChecks++; string name = prefab.name; if (name != value) { Mismatch("Turret ammo name", "'" + value + "' vs '" + name + "'"); s_prefabNames[prefab] = name; return name; } } return value; } } [EngineModule] public static class AreaIndexModule { private sealed class Rec { internal EffectArea Area; internal Transform Tr; internal GameObject Go; internal Collider[] Cols = Array.Empty<Collider>(); internal int State; internal int Slot = -1; internal bool Sampled; internal bool EverRigid; internal Matrix4x4 Pose; internal Bounds Raw; internal bool RawEmpty; internal Matrix4x4 GoodPose; internal Bounds GoodRaw; internal bool HasGood; internal Bounds PinRaw; internal Bounds Box; internal readonly List<long> Keys = new List<long>(); internal bool Huge; internal int AuditCount; internal float Due; internal int Stamp; internal bool Dead; } private struct Queued { internal Rec Rec; internal int Stamp; } private sealed class ByReference : IEqualityComparer<EffectArea> { internal static readonly ByReference Instance = new ByReference(); public bool Equals(EffectArea a, EffectArea b) { return a == b; } public int GetHashCode(EffectArea a) { return RuntimeHelpers.GetHashCode(a); } } internal static readonly Feature Index = Features.Register("AreaIndex", defaultOn: true, "EffectArea.IsPointInsideArea/GetBaseValue answer 'no area here' from a grid of the loaded effect areas instead of a physics overlap plus GetComponent per hit; any possible hit still runs the game's query."); internal static readonly Feature Verify = Features.Register("AreaIndexVerify", defaultOn: false, "Lab: after every 'no area' answer of AreaIndex the game's query runs too, its answer is used and any difference is counted and logged."); private const float CellSize = 32f; private const float StableSeconds = 1f; private const float LooseResampleSeconds = 10f; private const float LooseMargin = 8f; private const int PendingPerFrame = 128; private const int AuditPerFrame = 64; private const float AuditCycleSeconds = 4f; private const int AuditPerAnswer = 4; private const int DormantAuditPerFrame = 32; private const int SweepPerFrame = 16; private const int UnpinnedScanLimit = 256; private const int UnpinnedMatchLimit = 16; private const int MaxCellsPerArea = 64; private const float ForeignCheckSeconds = 10f; private const float ExtensionPeriod = 2f; private const string LabOwners = "valheim.realportal.lab"; private const int Pending = 0; private const int Pinned = 1; private const int Loose = 2; private const int Dormant = 3; public static long Queries; public static long Proven; public static long Fallbacks; public static long Unpins; public static long Audits; public static long Wakes; public static long Reshapes; public static long LateRegistered; public static long VerifyChecks; public static long VerifyMismatches; public static long StealthCalls; public static long StealthRefreshCalls; public static int StealthLights; private static readonly Dictionary<EffectArea, Rec> s_recs = new Dictionary<EffectArea, Rec>(ByReference.Instance); private static readonly Dictionary<long, List<Rec>> s_cells = new Dictionary<long, List<Rec>>(); private static readonly List<Rec> s_pinned = new List<Rec>(); private static readonly List<Rec> s_unpinned = new List<Rec>(); private static readonly List<Rec> s_dormant = new List<Rec>(); private static readonly List<Rec> s_huge = new List<Rec>(); private static readonly Queue<Queued> s_firstQ = new Queue<Queued>(); private static readonly Queue<Queued> s_stableQ = new Queue<Queued>(); private static readonly Queue<Queued> s_looseQ = new Queue<Queued>(); private static readonly List<Collider> s_cols = new List<Collider>(); private static readonly List<EffectArea> s_areaBuf = new List<EffectArea>(); private static readonly Stack<List<Rec>> s_freeLists = new Stack<List<Rec>>(); private static int s_frame = -1; private static int s_auditAt; private static int s_dormantAt; private static int s_sweepAt; private static int s_sweepAllAt; private static int s_answered; private static float s_lastUpkeep; private static float s_auditCredit; private static float s_dormantCredit; private static bool s_seeded; private static bool s_foreign; private static bool s_installed; private static bool s_broken; private static bool s_canDorm; private static bool s_extGated = true; private static float s_nextForeignCheck; private static MethodInfo s_inside; private static MethodInfo s_baseValue; private static MethodInfo s_getExtensions; private static FieldRef<CraftingStation, float> s_extTimer; private static int s_mismatchLogs; private static FieldRef<StealthSystem, float> s_lightUpdate; private static FieldRef<StealthSystem, Light[]> s_lights; private static long s_stealthRefreshTicks; private static long s_stealthPlainTicks; private static long s_stealthMaxTicks; private static float s_stampBefore; public static int Areas => s_recs.Count; public static int PinnedAreas => s_pinned.Count; public static int UnpinnedAreas => s_unpinned.Count; public static int DormantAreas => s_dormant.Count; public static int Cells => s_cells.Count; public static bool ForeignPatched => s_foreign; public static bool ExtensionsGated => s_extGated; public static double StealthRefreshMs { get { if (StealthRefreshCalls <= 0) { return 0.0; } return (double)s_stealthRefreshTicks * 1000.0 / (double)Stopwatch.Frequency / (double)StealthRefreshCalls; } } public static double StealthPlainMs { get { if (StealthCalls - StealthRefreshCalls <= 0) { return 0.0; } return (double)s_stealthPlainTicks * 1000.0 / (double)Stopwatch.Frequency / (double)(StealthCalls - StealthRefreshCalls); } } public static double StealthMaxMs => (double)s_stealthMaxTicks * 1000.0 / (double)Stopwatch.Frequency; public static string Describe() { return $"AreaIndex: on {Index.On}, foreign {s_foreign}, areas {s_recs.Count} (pinned {s_pinned.Count}, unpinned {s_unpinned.Count}, dormant {s_dormant.Count}, huge {s_huge.Count}), cells {s_cells.Count}, " + $"queries {Queries}, none answered {Proven}, to the game {Fallbacks}, audits {Audits}, unpins {Unpins}, wakes {Wakes}, reshapes {Reshapes} (gated {s_extGated}), late {LateRegistered}, verify {VerifyChecks}/{VerifyMismatches} mismatches; " + $"stealth light: calls {StealthCalls}, refreshes {StealthRefreshCalls}, lights {StealthLights}, refresh {StealthRefreshMs:F3} ms, plain {StealthPlainMs:F3} ms, max {StealthMaxMs:F3} ms"; } private static void Install(Harmony harmony) { //IL_021e: Unknown result type (might be due to invalid IL or missing references) //IL_022a: Unknown result type (might be due to invalid IL or missing references) //IL_0237: Expected O, but got Unknown //IL_0237: Expected O, but got Unknown //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_0251: Unknown result type (might be due to invalid IL or missing references) //IL_025e: Expected O, but got Unknown //IL_025e: Expected O, but got Unknown //IL_02d9: Unknown result type (might be due to invalid IL or missing references) //IL_02de: Unknown result type (might be due to invalid IL or missing references) //IL_02f0: Unknown result type (might be due to invalid IL or missing references) //IL_02f5: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Expected O, but got Unknown //IL_0304: Expected O, but got Unknown //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_016c: Expected O, but got Unknown //IL_0176: Unknown result type (might be due to invalid IL or missing references) //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_018f: Expected O, but got Unknown //IL_019d: 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_01b4: Unknown result type (might be due to invalid IL or missing references) //IL_01b9: Unknown result type (might be due to invalid IL or missing references) //IL_01c8: Expected O, but got Unknown //IL_01c8: Expected O, but got Unknown //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_01e9: Expected O, but got Unknown Type typeFromHandle = typeof(AreaIndexModule); s_inside = AccessTools.DeclaredMethod(typeof(EffectArea), "IsPointInsideArea", (Type[])null, (Type[])null); s_baseValue = AccessTools.DeclaredMethod(typeof(EffectArea), "GetBaseValue", (Type[])null, (Type[])null); MethodInfo methodInfo = AccessTools.DeclaredMethod(typeof(EffectArea), "Awake", (Type[])null, (Type[])null); MethodInfo methodInfo2 = AccessTools.DeclaredMethod(typeof(EffectArea), "OnDestroy", (Type[])null, (Type[])null); MethodInfo methodInfo3 = AccessTools.DeclaredMethod(typeof(EffectArea), "OnEnable", (Type[])null, (Type[])null); s_getExtensions = AccessTools.DeclaredMethod(typeof(CraftingStation), "GetExtensions", (Type[])null, (Type[])null); try { FieldInfo fieldInfo = AccessTools.DeclaredField(typeof(CraftingStation), "m_updateExtensionTimer"); if ((object)fieldInfo != null && fieldInfo.FieldType == typeof(float)) { s_extTimer = AccessTools.FieldRefAccess<CraftingStation, float>("m_updateExtensionTimer"); } } catch (Exception) { s_extTimer = null; } if (s_inside == null || s_baseValue == null || methodInfo == null || methodInfo2 == null) { EnginePlugin.Log.LogWarning((object)"AreaIndex: an EffectArea method is missing (game update?), effect area queries stay as in the game."); } else if (s_getExtensions == null || s_extTimer == null) { EnginePlugin.Log.LogWarning((object)"AreaIndex: CraftingStation.GetExtensions or m_updateExtensionTimer is missing (game update?), effect area queries stay as in the game."); } else { harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "AwakeAfter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)methodInfo2, new HarmonyMethod(typeFromHandle, "DestroyBefore", (Type[])null) { priority = 800 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)s_getExtensions, new HarmonyMethod(typeFromHandle, "ExtensionsBefore", (Type[])null) { priority = 800 }, new HarmonyMethod(typeFromHandle, "ExtensionsAfter", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); if (methodInfo3 != null) { try { harmony.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(typeFromHandle, "EnableAfter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); s_canDorm = true; } catch (Exception ex2) { EnginePlugin.Log.LogWarning((object)("AreaIndex: EffectArea.OnEnable not patched, inactive areas are tested like pending ones: " + ex2.Message)); } } harmony.Patch((MethodBase)s_inside, new HarmonyMethod(typeFromHandle, "InsideBefore", (Type[])null), new HarmonyMethod(typeFromHandle, "InsideAfter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); harmony.Patch((MethodBase)s_baseValue, new HarmonyMethod(typeFromHandle, "BaseValueBefore", (Type[])null), new HarmonyMethod(typeFromHandle, "BaseValueAfter", (Type[])null), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); s_installed = true; Index.Switched += delegate { StandDown(); }; } try { MethodInfo methodInfo4 = AccessTools.DeclaredMethod(typeof(StealthSystem), "GetLightLevel", (Type[])null, (Type[])null); s_lightUpdate = AccessTools.FieldRefAccess<StealthSystem, float>("m_lastLightListUpdate"); s_lights = AccessTools.FieldRefAccess<StealthSystem, Light[]>("m_allLights"); if (methodInfo4 != null) { harmony.Patch((MethodBase)methodInfo4, new HarmonyMethod(typeFromHandle, "LightBefore", (Type[])null) { priority = 800 }, new HarmonyMethod(typeFromHandle, "LightAfter", (Type[])null) { priority = 0 }, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } catch (Exception ex3) { EnginePlugin.Log.LogWarning((object)("AreaIndex: StealthSystem.GetLightLevel timing not installed: " + ex3.Message)); } } private static void AwakeAfter(EffectArea __instance) { if (s_broken) { return; } try { Register(__instance, late: false); } catch (Exception e) { Break(e); } } private static void DestroyBefore(EffectArea __instance) { if (s_broken) { return; } try { if (__instance != null && s_recs.TryGetValue(__instance, out var value)) { Drop(value); } } catch (Exception e) { Break(e); } } private static void EnableAfter(EffectArea __instance) { if (!s_seeded || s_broken) { return; } try { if (__instance != null && s_recs.TryGetValue(__instance, out var value)) { Wake(value); } } catch (Exception e) { Break(e); } } private static void ExtensionsBefore(CraftingStation __instance, out float __state) { __state = float.NaN; if (!s_seeded || s_broken) { return; } try { if (!s_extGated || !(s_extTimer.Invoke(__instance) < 2f)) { __state = RadiusOf(__instance.m_effectAreaCollider); } } catch (Exception e) { Break(e); } } private static void ExtensionsAfter(CraftingStation __instance, float __state) { if (float.IsNaN(__state) || !s_seeded || s_broken) { return; } try { Collider effectAreaCollider = __instance.m_effectAreaCollider; if ((Object)(object)effectAreaCollider == (Object)null || RadiusOf(effectAreaCollider).Equals(__state)) { return; } Reshapes++; s_areaBuf.Clear(); ((Component)effectAreaCollider).GetComponents<EffectArea>(s_areaBuf); for (int i = 0; i < s_areaBuf.Count; i++) { EffectArea val = s_areaBuf[i]; if (s_recs.TryGetValue(val, out var value)) { Wake(value); } else { Register(val, late: true); } } s_areaBuf.Clear(); } catch (Exception e) { s_areaBuf.Clear(); Break(e); } } private static float RadiusOf(Collider c) { if ((Object)(object)c == (Object)null) { return float.NaN; } SphereCollider val = (SphereCollider)(object)((c is SphereCollider) ? c : null); if (val != null) { return val.radius; } CapsuleCollider val2 = (CapsuleCollider)(object)((c is CapsuleCollider) ? c : null); if (val2 != null) { return val2.radius; } return float.NaN; } private static void Break(Exception e) { if (!s_broken) { s_broken = true; s_seeded = false; ManualLogSource log = EnginePlugin.Log; if (log != null) { log.LogError((object)("AreaIndex: index failed, effect area queries go to the game for the rest of the session: " + e)); } s_firstQ.Clear(); s_stableQ.Clear(); s_looseQ.Clear(); s_recs.Clear(); s_cells.Clear(); s_pinned.Clear(); s_unpinned.Clear(); s_dormant.Clear(); s_huge.Clear(); s_freeLists.Clear(); } } private static void StandDown() { s_seeded = false; s_firstQ.Clear(); s_stableQ.Clear(); s_looseQ.Clear(); } private static void Register(EffectArea area, bool late) { if (!((Object)(object)area == (Object)null) && !s_recs.ContainsKey(area)) { Rec rec = new Rec { Area = area, Tr = ((Component)area).transform, State = 0 }; s_recs.Add(area, rec); Add(s_unpinned, rec); if (late) { LateRegistered++; } if (s_seeded) { Queue(s_firstQ, rec, 0f); } } } private static void Drop(Rec r) { r.Dead = true; s_recs.Remove(r.Area); if (r.State == 1) { Unindex(r); } else if (r.State == 3) { RemoveAt(s_dormant, r); } else { RemoveAt(s_unpinned, r); } } private static void Wake(Rec r) { if (s_seeded && !r.Dead && (r.State != 0 || r.Sampled)) { if (r.State == 1) { Unindex(r); Add(s_unpinned, r); } else if (r.State == 3) { RemoveAt(s_dormant, r); Add(s_unpinned, r); } r.State = 0; r.Sampled = false; Wakes++; Queue(s_firstQ, r, 0f); } } private static void Sleep(Rec r) { r.State = 3; r.Stamp++; Add(s_dormant, r); } private static bool CanDorm(Rec r) { if (s_canDorm && r.Go != null && !r.Go.activeInHierarchy) { return ((Behaviour)r.Area).enabled; } return false; } private static void Repend(Rec r, Matrix4x4 pose, Bounds raw, bool empty, float now) { //IL_0012: 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) Unindex(r); Add(s_unpinned, r); Note(r, pose, raw, empty); Queue(s_stableQ, r, now + 1f); } private static void Note(Rec r, Matrix4x4 pose, Bounds raw, bool empty) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0020: 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_0027: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) r.Sampled = true; r.Pose = pose; r.Raw = raw; r.RawEmpty = empty; if (!empty) { r.GoodPose = pose; r.GoodRaw = raw; r.HasGood = true; } } private static void Queue(Queue<Queued> queue, Rec r, float due) { r.Due = due; r.Stamp++; queue.Enqueue(new Queued { Rec = r, Stamp = r.Stamp }); } private static void Sample(Rec r, out Matrix4x4 pose, out Bounds raw, out bool empty, out bool rigid) { //IL_0066: 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_0071: Unknown result type (might be due to invalid IL or missing references) //IL_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00c8: 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_00bd: Unknown result type (might be due to invalid IL or missing references) if (r.Go == null) { r.Go = ((Component)r.Area).gameObject; } s_cols.Clear(); ((Component)r.Area).GetComponents<Collider>(s_cols); if (!SameColliders(r.Cols, s_cols)) { r.Cols = s_cols.ToArray(); } s_cols.Clear(); pose = r.Tr.localToWorldMatrix; raw = default(Bounds); empty = true; rigid = false; Collider[] cols = r.Cols; foreach (Collider val in cols) { if ((Object)(object)val == (Object)null) { continue; } if ((Object)(object)val.attachedRigidbody != (Object)null) { rigid = true; } Bounds bounds = val.bounds; if (!IsEmpty(bounds)) { if (empty) { raw = bounds; empty = false; } else { ((Bounds)(ref raw)).Encapsulate(bounds); } } } } private static void Peek(Rec r, out Matrix4x4 pose, out Bounds raw, out bool empty) { //IL_0007: 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_0012: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) pose = r.Tr.localToWorldMatrix; raw = default(Bounds); empty = true; Collider[] cols = r.Cols; foreach (Collider val in cols) { if ((Object)(object)val == (Object)null) { continue; } Bounds bounds = val.bounds; if (!IsEmpty(bounds)) { if (empty) { raw = bounds; empty = false; } else { ((Bounds)(ref raw)).Encapsulate(bounds); } } } } private static bool RigidOutOfScene(Rec r) { return (Object)(object)((Component)r.Tr).GetComponentInParent<Rigidbody>(true) != (Object)null; } private static bool SameColliders(Collider[] have, List<Collider> now) { if (have.Length != now.Count) { return false; } for (int i = 0; i < have.Length; i++) { if (have[i] != now[i]) { return false; } } return true; } private static bool IsEmpty(Bounds b) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0061: Unknown result type (might be due to invalid IL or missing references) if (((Bounds)(ref b)).extents.x == 0f && ((Bounds)(ref b)).extents.y == 0f && ((Bounds)(ref b)).extents.z == 0f && ((Bounds)(ref b)).center.x == 0f && ((Bounds)(ref b)).center.y == 0f) { return ((Bounds)(ref b)).center.z == 0f; } return false; } private static void Maintain() { int frameCount = Time.frameCount; if (frameCount != s_frame) { s_frame = frameCount; float unscaledTime = Time.unscaledTime; if (!s_seeded) { Reseed(unscaledTime); } int budget = 128; Drain(s_firstQ, unscaledTime, ref budget); Drain(s_stableQ, unscaledTime, ref budget); Drain(s_looseQ, unscaledTime, ref budget); float num = unscaledTime - s_lastUpkeep; s_lastUpkeep = unscaledTime; if (!(num >= 0f)) { num = 0f; } else if (num > 1f) { num = 1f; } s_auditCredit = Math.Min(64f, s_auditCredit + (float)s_pinned.Count * num / 4f + (float)(4 * s_answered)); s_dormantCredit = Math.Min(32f, s_dormantCredit + (float)s_dormant.Count * num / 4f); s_answered = 0; AuditPinned(unscaledTime); AuditDormant(); Sweep(EffectArea.Instances, ref s_sweepAt); SweepAll(EffectArea.GetAllAreas(), ref s_sweepAllAt); } } private sta
plugins/RealPortal.Burst.dll
Decompiled a day agousing System; using System.CodeDom.Compiler; using System.ComponentModel; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using Unity.Burst; using Unity.Collections; using Unity.Collections.LowLevel.Unsafe; using Unity.Jobs; using Unity.Mathematics; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyVersion("0.0.0.0")] [CompilerGenerated] [EditorBrowsable(EditorBrowsableState.Never)] [GeneratedCode("Unity.MonoScriptGenerator.MonoScriptInfoGenerator", null)] internal class UnitySourceGeneratedAssemblyMonoScriptTypes_v1 { private struct MonoScriptData { public byte[] FilePathsData; public byte[] TypesData; public int TotalTypes; public int TotalFiles; public bool IsEditorOnly; } [MethodImpl(MethodImplOptions.AggressiveInlining)] private static MonoScriptData Get() { return new MonoScriptData { FilePathsData = new byte[186] { 0, 0, 0, 1, 0, 0, 0, 37, 92, 65, 115, 115, 101, 116, 115, 92, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 92, 66, 117, 114, 115, 116, 74, 111, 98, 115, 46, 99, 115, 0, 0, 0, 1, 0, 0, 0, 36, 92, 65, 115, 115, 101, 116, 115, 92, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 92, 80, 114, 111, 98, 101, 74, 111, 98, 46, 99, 115, 0, 0, 0, 2, 0, 0, 0, 40, 92, 65, 115, 115, 101, 116, 115, 92, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 92, 80, 114, 111, 120, 121, 67, 117, 108, 108, 74, 111, 98, 46, 99, 115, 0, 0, 0, 10, 0, 0, 0, 41, 92, 65, 115, 115, 101, 116, 115, 92, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 92, 80, 114, 111, 120, 121, 86, 105, 101, 119, 74, 111, 98, 115, 46, 99, 115 }, TypesData = new byte[463] { 0, 0, 0, 0, 26, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 66, 117, 114, 115, 116, 74, 111, 98, 115, 0, 0, 0, 0, 25, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 80, 114, 111, 98, 101, 74, 111, 98, 0, 0, 0, 0, 29, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 80, 114, 111, 120, 121, 67, 117, 108, 108, 74, 111, 98, 0, 0, 0, 0, 32, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 80, 114, 111, 120, 121, 67, 111, 109, 112, 97, 99, 116, 74, 111, 98, 0, 0, 0, 0, 25, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 73, 110, 115, 116, 0, 0, 0, 0, 26, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 82, 97, 110, 103, 101, 0, 0, 0, 0, 24, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 79, 117, 116, 0, 0, 0, 0, 29, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 84, 101, 109, 112, 108, 97, 116, 101, 0, 0, 0, 0, 28, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 86, 97, 114, 105, 97, 110, 116, 0, 0, 0, 0, 32, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 86, 97, 114, 105, 97, 110, 116, 80, 97, 114, 116, 0, 0, 0, 0, 25, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 80, 97, 114, 116, 0, 0, 0, 0, 26, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 86, 105, 101, 119, 67, 111, 110, 115, 116, 0, 0, 0, 0, 33, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 80, 114, 111, 120, 121, 86, 105, 101, 119, 67, 117, 108, 108, 74, 111, 98, 0, 0, 0, 0, 33, 82, 101, 97, 108, 80, 111, 114, 116, 97, 108, 46, 66, 117, 114, 115, 116, 124, 80, 114, 111, 120, 121, 86, 105, 101, 119, 69, 109, 105, 116, 74, 111, 98 }, TotalFiles = 4, TotalTypes = 14, IsEditorOnly = false }; } } namespace RealPortal.Burst; public static class BurstJobs { public const int ApiVersion = 3; public const int ModeBurst = 1; public const int ModeManaged = 2; public const int ProbeLength = 16; public static readonly string[] JobNames = new string[4] { "ProxyCullJob", "ProxyCompactJob", "ProxyViewCullJob", "ProxyViewEmitJob" }; public const int ProbeBatches = 16; public static int[] Probe() { //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) NativeArray<int> result = default(NativeArray<int>); result..ctor(16, (Allocator)3, (NativeArrayOptions)1); try { IJobExtensions.Run<ProbeJob>(new ProbeJob { Result = result }); return result.ToArray(); } finally { result.Dispose(); } } public static int[] ExpectedLayout() { return new int[15] { 3, UnsafeUtility.SizeOf<ProxyCullJob>(), UnsafeUtility.SizeOf<ProxyCompactJob>(), UnsafeUtility.SizeOf<ProxyViewCullJob>(), UnsafeUtility.SizeOf<ProxyViewEmitJob>(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }; } public static int[] ViewSizes() { return new int[7] { UnsafeUtility.SizeOf<ViewInst>(), UnsafeUtility.SizeOf<ViewRange>(), UnsafeUtility.SizeOf<ViewOut>(), UnsafeUtility.SizeOf<ViewTemplate>(), UnsafeUtility.SizeOf<ViewVariant>(), UnsafeUtility.SizeOf<ViewVariantPart>(), UnsafeUtility.SizeOf<ViewPart>() }; } public static int[] ProbeJobs() { //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0070: 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_0077: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: 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_00b6: 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_00be: 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_00d1: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: 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) NativeArray<float4> spheres = default(NativeArray<float4>); spheres..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<float4> planes = default(NativeArray<float4>); planes..ctor(6, (Allocator)3, (NativeArrayOptions)1); NativeArray<int> visible = default(NativeArray<int>); visible..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<int> batchCounts = default(NativeArray<int>); batchCounts..ctor(16, (Allocator)3, (NativeArrayOptions)1); NativeArray<int> visibleCount = default(NativeArray<int>); visibleCount..ctor(1, (Allocator)3, (NativeArrayOptions)1); try { ProxyCullJob obj = new ProxyCullJob { Spheres = spheres, Planes = planes, Visible = visible, BatchCounts = batchCounts, BatchSize = 0 }; JobHandle val = default(JobHandle); val = IJobForExtensions.ScheduleParallel<ProxyCullJob>(obj, 16, 1, val); ((JobHandle)(ref val)).Complete(); int num = 1; for (int i = 0; i < 16; i++) { if (num != 1) { break; } num = batchCounts[i]; } ProxyCompactJob obj2 = new ProxyCompactJob { Visible = visible, BatchCounts = batchCounts, VisibleCount = visibleCount, BatchSize = 0 }; val = default(JobHandle); val = IJobExtensions.Schedule<ProxyCompactJob>(obj2, val); ((JobHandle)(ref val)).Complete(); return new int[4] { num, visibleCount[0], ProbeViewCull(), ProbeViewEmit() }; } finally { spheres.Dispose(); planes.Dispose(); visible.Dispose(); batchCounts.Dispose(); visibleCount.Dispose(); } } private static int ProbeViewCull() { //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0063: 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_006b: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0074: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0086: 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_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00ba: Unknown result type (might be due to invalid IL or missing references) //IL_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: 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) NativeArray<int> val = default(NativeArray<int>); val..ctor(16, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewInst> page = default(NativeArray<ViewInst>); page..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewRange> ranges = default(NativeArray<ViewRange>); ranges..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewTemplate> val2 = default(NativeArray<ViewTemplate>); val2..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewVariant> variants = default(NativeArray<ViewVariant>); variants..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<byte> rowFlags = default(NativeArray<byte>); rowFlags..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<Vector4> planes = default(NativeArray<Vector4>); planes..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewOut> val3 = default(NativeArray<ViewOut>); val3..ctor(1, (Allocator)3, (NativeArrayOptions)1); try { ProxyViewCullJob obj = new ProxyViewCullJob { Page = page, Ranges = ranges, Templates = val2, LodSets = val2, Variants = variants, RowFlags = rowFlags, Planes = planes, Out = val3, Room = val, RangeBase = -1 }; JobHandle val4 = default(JobHandle); val4 = IJobParallelForExtensions.Schedule<ProxyViewCullJob>(obj, 16, 1, val4); ((JobHandle)(ref val4)).Complete(); return AllBurst(val); } finally { val.Dispose(); page.Dispose(); ranges.Dispose(); val2.Dispose(); variants.Dispose(); rowFlags.Dispose(); planes.Dispose(); val3.Dispose(); } } private static int ProbeViewEmit() { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_0087: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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) //IL_0092: Unknown result type (might be due to invalid IL or missing references) //IL_0099: 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_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a4: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: 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_00b6: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00cf: 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_00d7: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: 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_00f4: 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_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0111: 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_0119: 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_0127: Unknown result type (might be due to invalid IL or missing references) NativeArray<int> val = default(NativeArray<int>); val..ctor(16, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewInst> page = default(NativeArray<ViewInst>); page..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewRange> ranges = default(NativeArray<ViewRange>); ranges..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewOut> cull = default(NativeArray<ViewOut>); cull..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewVariant> variants = default(NativeArray<ViewVariant>); variants..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewVariantPart> variantParts = default(NativeArray<ViewVariantPart>); variantParts..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<ViewPart> parts = default(NativeArray<ViewPart>); parts..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<int> val2 = default(NativeArray<int>); val2..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<Matrix4x4> m = default(NativeArray<Matrix4x4>); m..ctor(1, (Allocator)3, (NativeArrayOptions)1); NativeArray<Vector4> s = default(NativeArray<Vector4>); s..ctor(1, (Allocator)3, (NativeArrayOptions)1); try { ProxyViewEmitJob obj = new ProxyViewEmitJob { Page = page, Ranges = ranges, Cull = cull, Variants = variants, VariantParts = variantParts, Parts = parts, BatchDraw = val2, Base = val2, Key = val2, M = m, S = s, Filled = val, Visible = val2, Casters = val2, SpecialCount = val2, Special = val2, RowDrawn = val2, RangeBase = -1 }; JobHandle val3 = default(JobHandle); val3 = IJobParallelForExtensions.Schedule<ProxyViewEmitJob>(obj, 16, 1, val3); ((JobHandle)(ref val3)).Complete(); return AllBurst(val); } finally { val.Dispose(); page.Dispose(); ranges.Dispose(); cull.Dispose(); variants.Dispose(); variantParts.Dispose(); parts.Dispose(); val2.Dispose(); m.Dispose(); s.Dispose(); } } private static int AllBurst(NativeArray<int> modes) { for (int i = 0; i < modes.Length; i++) { if (modes[i] != 1) { return modes[i]; } } return 1; } public static JobHandle ScheduleViewCull(NativeArray<byte> page, NativeArray<byte> ranges, NativeArray<byte> templates, NativeArray<byte> lodSets, NativeArray<byte> variants, NativeArray<byte> rowFlags, NativeArray<Vector4> planes, NativeArray<byte> outs, NativeArray<int> room, int rangeBase, int rangeCount, int casterPlanes, int maxLod, uint skip, Vector4 cam, Vector4 prevCam, Vector4 light, int flags, JobHandle dependsOn) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_006a: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b1: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bd: 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_00d2: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00e7: Unknown result type (might be due to invalid IL or missing references) //IL_00ec: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Unknown result type (might be due to invalid IL or missing references) //IL_0101: 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_010f: Unknown result type (might be due to invalid IL or missing references) //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_016a: 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) return IJobParallelForExtensions.Schedule<ProxyViewCullJob>(new ProxyViewCullJob { Page = page.Reinterpret<ViewInst>(1), Ranges = ranges.Reinterpret<ViewRange>(1), Templates = templates.Reinterpret<ViewTemplate>(1), LodSets = lodSets.Reinterpret<ViewTemplate>(1), Variants = variants.Reinterpret<ViewVariant>(1), RowFlags = rowFlags, Planes = planes, Out = outs.Reinterpret<ViewOut>(1), Room = room, RangeBase = rangeBase, CasterPlanes = casterPlanes, MaxLod = maxLod, Skip = skip, Cam = new Vector3(cam.x, cam.y, cam.z), K = cam.w, PrevCam = new Vector3(prevCam.x, prevCam.y, prevCam.z), PrevK = prevCam.w, Light = new Vector3(light.x, light.y, light.z), Margin = light.w, HasPrev = ((flags & 1) != 0), Animated = ((flags & 2) != 0), Shadows = ((flags & 4) != 0), CameraSideCasts = ((flags & 8) != 0) }, rangeCount, 1, dependsOn); } public static JobHandle ScheduleViewEmit(NativeArray<byte> page, NativeArray<byte> ranges, NativeArray<byte> cull, NativeArray<byte> variants, NativeArray<byte> variantParts, NativeArray<byte> parts, NativeArray<int> batchDraw, NativeArray<int> bases, NativeArray<int> key, NativeArray<Matrix4x4> m, NativeArray<Vector4> s, NativeArray<int> filled, NativeArray<int> visible, NativeArray<int> casters, NativeArray<int> specialCount, NativeArray<int> special, NativeArray<int> rowDrawn, int rangeBase, int rangeCount, int mask, int frame, bool obliqueClip, JobHandle dependsOn) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_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_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_003f: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004e: Unknown result type (might be due to invalid IL or missing references) //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_006d: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_0088: 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_0091: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a3: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00ac: Unknown result type (might be due to invalid IL or missing references) //IL_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00b5: 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_00be: 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_00ed: 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) return IJobParallelForExtensions.Schedule<ProxyViewEmitJob>(new ProxyViewEmitJob { Page = page.Reinterpret<ViewInst>(1), Ranges = ranges.Reinterpret<ViewRange>(1), Cull = cull.Reinterpret<ViewOut>(1), Variants = variants.Reinterpret<ViewVariant>(1), VariantParts = variantParts.Reinterpret<ViewVariantPart>(1), Parts = parts.Reinterpret<ViewPart>(1), BatchDraw = batchDraw, Base = bases, Key = key, M = m, S = s, Filled = filled, Visible = visible, Casters = casters, SpecialCount = specialCount, Special = special, RowDrawn = rowDrawn, RangeBase = rangeBase, Mask = mask, Frame = frame, ObliqueClip = obliqueClip }, rangeCount, 1, dependsOn); } public static int BatchCount(int length, int batchSize) { return length / batchSize + ((length % batchSize != 0) ? 1 : 0); } public static JobHandle ScheduleCull(NativeArray<float4> spheres, NativeArray<float4> planes, NativeArray<int> visible, NativeArray<int> batchCounts, NativeArray<int> visibleCount, int batchSize, JobHandle dependsOn) { //IL_0034: Unknown result type (might be due to invalid IL or missing references) //IL_0035: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_003d: 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_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_004d: 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_0066: 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_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Unknown result type (might be due to invalid IL or missing references) //IL_007e: Unknown result type (might be due to invalid IL or missing references) //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_008f: 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) //IL_0097: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) CheckCullArguments(spheres.Length, planes.Length, visible.Length, batchCounts.Length, visibleCount.Length, batchSize); JobHandle val = IJobForExtensions.ScheduleParallel<ProxyCullJob>(new ProxyCullJob { Spheres = spheres, Planes = planes, Visible = visible, BatchCounts = batchCounts, BatchSize = batchSize }, batchCounts.Length, 1, dependsOn); return IJobExtensions.Schedule<ProxyCompactJob>(new ProxyCompactJob { Visible = visible, BatchCounts = batchCounts, BatchSize = batchSize, VisibleCount = visibleCount }, val); } public static void CheckCullArguments(int spheres, int planes, int visible, int batchCounts, int visibleCount, int batchSize) { if (batchSize <= 0) { throw new ArgumentOutOfRangeException("batchSize", batchSize, "must be positive"); } if (planes != 6) { throw new ArgumentException($"planes must hold 6 planes, has {planes}"); } if (visible < spheres) { throw new ArgumentException($"visible must hold {spheres} indices, has {visible}"); } if (batchCounts != BatchCount(spheres, batchSize)) { throw new ArgumentException($"batchCounts must hold {BatchCount(spheres, batchSize)} counts, has {batchCounts}"); } if (visibleCount < 1) { throw new ArgumentException("visibleCount must hold 1 value"); } } } [BurstCompile(CompileSynchronously = true)] public struct ProbeJob : IJob { public NativeArray<int> Result; public void Execute() { Put(0, 1); MarkManaged(); Put(1, 3); Put(2, UnsafeUtility.SizeOf<ProxyCullJob>()); Put(3, UnsafeUtility.SizeOf<ProxyCompactJob>()); Put(4, UnsafeUtility.SizeOf<ProxyViewCullJob>()); Put(5, UnsafeUtility.SizeOf<ProxyViewEmitJob>()); } private void Put(int index, int value) { if (index < Result.Length) { Result[index] = value; } } [BurstDiscard] private void MarkManaged() { Put(0, 2); } } [BurstCompile(/*Could not decode attribute arguments.*/)] public struct ProxyCullJob : IJobFor { [ReadOnly] public NativeArray<float4> Spheres; [ReadOnly] public NativeArray<float4> Planes; [NativeDisableParallelForRestriction] public NativeArray<int> Visible; public NativeArray<int> BatchCounts; public int BatchSize; public void Execute(int batch) { //IL_0025: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005e: 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_006c: Unknown result type (might be due to invalid IL or missing references) //IL_00aa: 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_00b1: 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_00bc: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: 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_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: 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_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f8: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) if (BatchSize <= 0) { BatchCounts[batch] = 1; MarkManaged(batch); return; } float4 p = Planes[0]; float4 p2 = Planes[1]; float4 p3 = Planes[2]; float4 p4 = Planes[3]; float4 p5 = Planes[4]; float4 p6 = Planes[5]; int num = batch * BatchSize; int num2 = num + math.min(BatchSize, Spheres.Length - num); int num3 = 0; for (int i = num; i < num2; i++) { float4 val = Spheres[i]; float num4 = 0f - val.w; if (!(Distance(p, val) < num4) && !(Distance(p2, val) < num4) && !(Distance(p3, val) < num4) && !(Distance(p4, val) < num4) && !(Distance(p5, val) < num4) && !(Distance(p6, val) < num4)) { Visible[num + num3] = i; num3++; } } BatchCounts[batch] = num3; } [BurstDiscard] private void MarkManaged(int batch) { BatchCounts[batch] = 2; } private static float Distance(float4 p, float4 s) { //IL_0000: 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_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) return p.x * s.x + p.y * s.y + p.z * s.z + p.w; } } [BurstCompile(/*Could not decode attribute arguments.*/)] public struct ProxyCompactJob : IJob { public NativeArray<int> Visible; [ReadOnly] public NativeArray<int> BatchCounts; public NativeArray<int> VisibleCount; public int BatchSize; public void Execute() { if (BatchSize <= 0) { VisibleCount[0] = 1; MarkManaged(); return; } int num = 0; for (int i = 0; i < BatchCounts.Length; i++) { int num2 = i * BatchSize; int num3 = BatchCounts[i]; if (num2 != num) { for (int j = 0; j < num3; j++) { Visible[num + j] = Visible[num2 + j]; } } num += num3; } VisibleCount[0] = num; } [BurstDiscard] private void MarkManaged() { VisibleCount[0] = 2; } } public struct ViewInst { public Matrix4x4 Root; public Vector3 Center; public float Radius; public Vector3 LodRef; public float LodSize; public int Template; public int Variant; public int LodSet; public uint Flags; public int Row; } public struct ViewRange { public int Start; public int Count; public int Out; public int DistantOnly; } public struct ViewOut { public byte Vis; public byte Lod; public byte Prev; public byte Pad; public float Fade; } public struct ViewTemplate { public int Prefab; public int PartStart; public int PartCount; public int LodCount; public int FadeMode; public bool AnimateCrossFading; public bool LodFadeInOut; public float LodSize; public Vector3 LodLocalRef; public Matrix4x4 LodLocal; public Vector4 HeightsA; public Vector4 HeightsB; public Vector4 FadeA; public Vector4 FadeB; public float Height(int level) { if (level >= 4) { return ((Vector4)(ref HeightsB))[level - 4]; } return ((Vector4)(ref HeightsA))[level]; } public float FadeWidth(int level) { if (level >= 4) { return ((Vector4)(ref FadeB))[level - 4]; } return ((Vector4)(ref FadeA))[level]; } } public struct ViewVariant { public int Template; public int PartStart; public int PartCount; public int LodSet; public Vector3 Center; public Vector3 Extents; } public struct ViewVariantPart { public int Part; public int Batch; public int Mpb; public int LodMask; public int Run; } public struct ViewPart { public Matrix4x4 Local; public Vector3 Center; public Vector3 Extents; public int Batch; public int LodMask; public int Template; } internal static class ViewConst { public const uint Created = 1u; public const uint Distant = 8u; public const byte NoLevel = 254; public const byte Culled = byte.MaxValue; public const byte RowFading = 1; public const byte RowBorn = 2; public const int LodAll = 255; public const int CrossFade = 1; public const int ShadowsOff = 0; public const int TwoSided = 2; public const int ShadowsOnly = 3; } [BurstCompile(/*Could not decode attribute arguments.*/)] public struct ProxyViewCullJob : IJobParallelFor { [ReadOnly] public NativeArray<ViewInst> Page; [ReadOnly] public NativeArray<ViewRange> Ranges; [ReadOnly] public NativeArray<ViewTemplate> Templates; [ReadOnly] public NativeArray<ViewTemplate> LodSets; [ReadOnly] public NativeArray<ViewVariant> Variants; [ReadOnly] public NativeArray<byte> RowFlags; [ReadOnly] public NativeArray<Vector4> Planes; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<ViewOut> Out; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> Room; public int RangeBase; public int CasterPlanes; public int MaxLod; public Vector3 Cam; public Vector3 PrevCam; public Vector3 Light; public float K; public float PrevK; public float Margin; public bool HasPrev; public bool Animated; public bool Shadows; public bool CameraSideCasts; public uint Skip; public void Execute(int index) { //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0089: 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_00a9: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: 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_00cf: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: 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_00f5: Unknown result type (might be due to invalid IL or missing references) //IL_00fa: Unknown result type (might be due to invalid IL or missing references) //IL_012f: 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_01d5: Unknown result type (might be due to invalid IL or missing references) //IL_01dc: Unknown result type (might be due to invalid IL or missing references) //IL_021b: Unknown result type (might be due to invalid IL or missing references) //IL_0222: Unknown result type (might be due to invalid IL or missing references) if (RangeBase < 0) { Room[index] = 1; MarkManaged(index); return; } ViewRange viewRange = Ranges[RangeBase + index]; uint skip = Skip; int num = 0; for (int i = 0; i < viewRange.Count; i++) { ViewInst viewInst = Page[viewRange.Start + i]; ViewOut o = default(ViewOut); uint flags = viewInst.Flags; if ((flags & skip) == 0 && (viewRange.DistantOnly == 0 || (flags & 8) != 0)) { Vector3 center = viewInst.Center; float num2 = viewInst.Radius + Margin; Vector4 val = Planes[6]; if ((o.Vis = (byte)((val.x * center.x + val.y * center.y + val.z * center.z + val.w < 0f - num2) ? ((CameraSideCasts && Sweep(7, CasterPlanes, center, num2, Light)) ? 3 : 0) : (Inside(center, num2) ? 1 : ((Shadows && Sweep(7, CasterPlanes, center, num2, Light)) ? 2 : 0)))) != 0) { num += Variants[viewInst.Variant].PartCount; ViewTemplate td = ((viewInst.LodSet >= 0) ? LodSets[viewInst.LodSet] : Templates[viewInst.Template]); if (td.LodCount == 0) { o.Lod = (o.Prev = 254); } else { o.Lod = Select(in td, viewInst.LodSize, Vector3.Distance(Cam, viewInst.LodRef), K, out o.Fade); o.Prev = (HasPrev ? Select(in td, viewInst.LodSize, Vector3.Distance(PrevCam, viewInst.LodRef), PrevK, out var _) : o.Lod); o.Pad = (byte)(Special(in td, in o, (byte)(((uint)viewInst.Row < (uint)RowFlags.Length) ? RowFlags[viewInst.Row] : 0)) ? 1 : 0); } } } Out[viewRange.Out + i] = o; } Room[RangeBase + index] = num; } [BurstDiscard] private void MarkManaged(int index) { Room[index] = 2; } private bool Special(in ViewTemplate td, in ViewOut o, byte rowFlags) { if (td.LodFadeInOut && (rowFlags & 2) != 0) { return true; } if (td.FadeMode == 1 && td.AnimateCrossFading && Animated) { if ((rowFlags & 1) == 0) { return o.Prev != o.Lod; } return true; } if (td.FadeMode == 1 && o.Lod != byte.MaxValue) { return o.Fade > 0f; } return false; } private bool Inside(Vector3 c, float rad) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0017: Unknown result type (might be due to invalid IL or missing references) //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0032: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) for (int i = 0; i < 6; i++) { Vector4 val = Planes[i]; if (val.x * c.x + val.y * c.y + val.z * c.z + val.w < 0f - rad) { return false; } } return true; } private bool Sweep(int from, int count, Vector3 c, float r, Vector3 ray) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0069: 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_0078: Unknown result type (might be due to invalid IL or missing references) float num = 0f; float num2 = 1f; for (int i = from; i < from + count; i++) { Vector4 val = Planes[i]; float num3 = val.x * c.x + val.y * c.y + val.z * c.z + val.w + r; float num4 = val.x * ray.x + val.y * ray.y + val.z * ray.z; if (num4 == 0f) { if (num3 < 0f) { return false; } continue; } float num5 = (0f - num3) / num4; if (num4 > 0f) { if (num5 > num) { num = num5; } } else if (num5 < num2) { num2 = num5; } if (num > num2) { return false; } } return true; } private byte Select(in ViewTemplate td, float size, float d, float k, out float fade) { fade = 0f; float num = ((d > 1E-06f) ? (size * k / d) : float.MaxValue); int lodCount = td.LodCount; for (int i = ((MaxLod < lodCount - 1) ? MaxLod : (lodCount - 1)); i < lodCount; i++) { float num2 = td.Height(i); if (num < num2) { continue; } if (td.FadeMode == 1 && !td.AnimateCrossFading) { float num3 = ((i == 0) ? 1f : td.Height(i - 1)); float num4 = td.FadeWidth(i) * (num3 - num2); if (num4 > 0f && num < num2 + num4) { fade = (num - num2) / num4; } } return (byte)i; } return byte.MaxValue; } } [BurstCompile(/*Could not decode attribute arguments.*/)] public struct ProxyViewEmitJob : IJobParallelFor { [ReadOnly] public NativeArray<ViewInst> Page; [ReadOnly] public NativeArray<ViewRange> Ranges; [ReadOnly] public NativeArray<ViewOut> Cull; [ReadOnly] public NativeArray<ViewVariant> Variants; [ReadOnly] public NativeArray<ViewVariantPart> VariantParts; [ReadOnly] public NativeArray<ViewPart> Parts; [ReadOnly] public NativeArray<int> BatchDraw; [ReadOnly] public NativeArray<int> Base; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> Key; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<Matrix4x4> M; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<Vector4> S; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> Filled; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> Visible; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> Casters; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> SpecialCount; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> Special; [NativeDisableParallelForRestriction] [NativeDisableContainerSafetyRestriction] public NativeArray<int> RowDrawn; public int RangeBase; public int Mask; public int Frame; public bool ObliqueClip; public void Execute(int index) { //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_00fd: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_025c: Unknown result type (might be due to invalid IL or missing references) //IL_0261: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) if (RangeBase < 0) { Filled[index] = 1; MarkManaged(index); return; } int num = RangeBase + index; ViewRange viewRange = Ranges[num]; int num2 = Base[num]; int num3 = 0; int num4 = 0; int num5 = 0; int num6 = 0; Vector4 val = default(Vector4); for (int i = 0; i < viewRange.Count; i++) { ViewOut viewOut = Cull[viewRange.Out + i]; if (viewOut.Vis == 0) { continue; } if (viewOut.Vis == 1) { num4++; } else { num5++; } if (viewOut.Pad != 0) { Special[viewRange.Out + num6++] = i; continue; } ViewInst viewInst = Page[viewRange.Start + i]; ViewVariant viewVariant = Variants[viewInst.Variant]; ((Vector4)(ref val))..ctor(viewInst.Center.x, viewInst.Center.y, viewInst.Center.z, viewInst.Radius); bool flag = false; int j = viewVariant.PartStart; for (int num7 = viewVariant.PartStart + viewVariant.PartCount; j < num7; j++) { ViewVariantPart viewVariantPart = VariantParts[j]; if (viewOut.Lod != 254 && viewVariantPart.LodMask != 255 && (viewOut.Lod >= 8 || (viewVariantPart.LodMask & (1 << (int)viewOut.Lod)) == 0)) { continue; } int num8 = (((uint)viewVariantPart.Batch < (uint)BatchDraw.Length) ? BatchDraw[viewVariantPart.Batch] : (-1)); if (num8 < 0) { continue; } int num9 = num8 & 0xFF; int num10 = num8 >> 8; if (num9 >= 32 || (Mask & (1 << num9)) == 0) { continue; } int num11; if (viewOut.Vis == 1) { num11 = num10; } else { if (num10 == 0) { continue; } num11 = ((num10 == 2 && (viewOut.Vis == 2 || ObliqueClip)) ? 2 : 3); } int num12 = num2 + num3++; Key[num12] = viewVariantPart.Run * 4 + num11; M[num12] = viewInst.Root * Parts[viewVariantPart.Part].Local; S[num12] = val; flag = true; } if (flag && viewOut.Vis == 1 && (viewInst.Flags & 1) == 0 && (uint)viewInst.Row < (uint)RowDrawn.Length) { RowDrawn[viewInst.Row] = Frame; } } Filled[num] = num3; Visible[num] = num4; Casters[num] = num5; SpecialCount[num] = num6; } [BurstDiscard] private void MarkManaged(int index) { Filled[index] = 2; } }
patchers/RealPortal.Preloader.dll
Decompiled a day agousing System; using System.Collections.Generic; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx.Logging; using Mono.Cecil; using Mono.Cecil.Cil; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.0", FrameworkDisplayName = ".NET Framework 4")] [assembly: AssemblyCompany("RealPortal.Preloader")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("RealPortal.Preloader")] [assembly: AssemblyTitle("RealPortal.Preloader")] [assembly: AssemblyVersion("1.0.0.0")] namespace RealPortal.Preloader; public static class Patcher { private sealed class Plan { public TypeDefinition Zdo; public FieldDefinition Row; public readonly List<MethodDefinition> NoInline = new List<MethodDefinition>(); public readonly List<MethodDefinition> ResetsRow = new List<MethodDefinition>(); } public const string RowField = "rp_row"; private static ManualLogSource s_log; public static IEnumerable<string> TargetDLLs => new string[1] { "assembly_valheim.dll" }; private static ManualLogSource Log => s_log ?? (s_log = Logger.CreateLogSource("RealPortal.Preloader")); public static void Patch(AssemblyDefinition assembly) { try { Run(assembly.MainModule); } catch (Exception ex) { Log.LogError((object)("assembly_valheim: patching for the ZDO journal failed part way; the engine's self-check decides what it can use. " + ex)); } } private static void Run(ModuleDefinition module) { //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Expected O, but got Unknown //IL_01de: Unknown result type (might be due to invalid IL or missing references) //IL_01f3: Unknown result type (might be due to invalid IL or missing references) //IL_0208: Unknown result type (might be due to invalid IL or missing references) List<string> list = new List<string>(); Plan plan = Find(module, list); if (list.Count > 0) { Log.LogError((object)("assembly_valheim left UNTOUCHED: the ZDO journal's patch targets are not as expected (game update?): " + string.Join("; ", list.ToArray()) + ". The engine's journal runs on Harmony only, with rows in a dictionary; check its self-check line in the log.")); return; } List<string> list2 = new List<string>(); List<string> list3 = new List<string>(); if (plan.Row == null) { plan.Row = new FieldDefinition("rp_row", (FieldAttributes)6, module.TypeSystem.Int32); plan.Zdo.Fields.Add(plan.Row); list2.Add("added field ZDO.rp_row"); } else { list3.Add("field ZDO.rp_row"); } List<string> list4 = new List<string>(); List<string> list5 = new List<string>(); foreach (MethodDefinition item in plan.NoInline) { if (item.NoInlining && !item.AggressiveInlining) { list5.Add(Name(item)); continue; } item.NoInlining = true; item.AggressiveInlining = false; list4.Add(Name(item)); } if (list4.Count > 0) { list2.Add("NoInlining on " + string.Join(", ", list4.ToArray())); } if (list5.Count > 0) { list3.Add("NoInlining on " + string.Join(", ", list5.ToArray())); } List<string> list6 = new List<string>(); List<string> list7 = new List<string>(); foreach (MethodDefinition item2 in plan.ResetsRow) { if (StoresRow(item2)) { list7.Add(Name(item2)); continue; } ILProcessor iLProcessor = item2.Body.GetILProcessor(); Instruction val = item2.Body.Instructions[0]; iLProcessor.InsertBefore(val, iLProcessor.Create(OpCodes.Ldarg_0)); iLProcessor.InsertBefore(val, iLProcessor.Create(OpCodes.Ldc_I4_M1)); iLProcessor.InsertBefore(val, iLProcessor.Create(OpCodes.Stfld, (FieldReference)(object)plan.Row)); list6.Add(Name(item2)); } if (list6.Count > 0) { list2.Add("rp_row = -1 at the start of " + string.Join(", ", list6.ToArray())); } if (list7.Count > 0) { list3.Add("rp_row = -1 in " + string.Join(", ", list7.ToArray())); } if (list2.Count == 0) { Log.LogInfo((object)("assembly_valheim already patched for the ZDO journal, nothing changed (" + string.Join("; ", list3.ToArray()) + ")")); } else { Log.LogInfo((object)("assembly_valheim patched for the ZDO journal: " + string.Join("; ", list2.ToArray()) + ((list3.Count > 0) ? (" (already there: " + string.Join("; ", list3.ToArray()) + ")") : ""))); } } private static Plan Find(ModuleDefinition module, List<string> missing) { //IL_02a6: Unknown result type (might be due to invalid IL or missing references) //IL_02ac: Invalid comparison between Unknown and I4 Plan plan = new Plan(); TypeDefinition type = module.GetType("ZDO"); TypeDefinition type2 = module.GetType("ZDOMan"); TypeDefinition type3 = module.GetType("ZoneSystem"); TypeDefinition val = ((type3 != null) ? ((IEnumerable<TypeDefinition>)type3.NestedTypes).FirstOrDefault((Func<TypeDefinition, bool>)((TypeDefinition t) => ((MemberReference)t).Name == "SectorIndex")) : null); if (type == null) { missing.Add("type ZDO"); } if (type2 == null) { missing.Add("type ZDOMan"); } if (val == null || !((TypeReference)val).IsValueType) { missing.Add("struct ZoneSystem.SectorIndex"); } if (missing.Count > 0) { return plan; } plan.Zdo = type; string fullName = ((MemberReference)val).FullName; NoInline(type, "IncreaseDataRevision", new string[0]); NoInline(type, "IncreaseOwnerRevision", new string[0]); NoInline(type, "SetSector", new string[1] { fullName }); NoInline(type2, "AddToSector", new string[2] { "ZDO", fullName }); NoInline(type2, "InitialAddToSector", new string[2] { "ZDO", fullName }); NoInline(type2, "RemoveFromSector", new string[2] { "ZDO", fullName }); MethodDefinition val2 = Method(type, "Reset", new string[0], missing); if (val2 != null) { plan.ResetsRow.Add(val2); } List<MethodDefinition> list = ((IEnumerable<MethodDefinition>)type.Methods).Where((MethodDefinition m) => m.IsConstructor && !m.IsStatic).ToList(); if (list.Count == 0) { missing.Add("a ZDO instance constructor"); } foreach (MethodDefinition item in list) { if (!item.HasBody || item.Body.Instructions.Count == 0) { missing.Add("a body for " + Name(item)); } else { plan.ResetsRow.Add(item); } } FieldDefinition val3 = ((IEnumerable<FieldDefinition>)type.Fields).FirstOrDefault((Func<FieldDefinition, bool>)((FieldDefinition f) => ((MemberReference)f).Name == "rp_row")); if (val3 != null && (val3.IsStatic || !val3.IsPublic || (int)((FieldReference)val3).FieldType.MetadataType != 8)) { missing.Add("ZDO.rp_row exists but is not a public instance int (" + ((MemberReference)((FieldReference)val3).FieldType).FullName + ")"); } plan.Row = val3; return plan; void NoInline(TypeDefinition type4, string name, string[] parameters) { MethodDefinition val4 = Method(type4, name, parameters, missing); if (val4 != null) { plan.NoInline.Add(val4); } } } private static MethodDefinition Method(TypeDefinition type, string name, string[] parameters, List<string> missing) { string text = ((MemberReference)type).Name + "." + name + "(" + string.Join(", ", parameters) + ")"; List<MethodDefinition> list = ((IEnumerable<MethodDefinition>)type.Methods).Where((MethodDefinition m) => ((MemberReference)m).Name == name && !m.IsStatic && m.HasBody && (int)((MethodReference)m).ReturnType.MetadataType == 1 && ((MethodReference)m).Parameters.Count == parameters.Length && ((IEnumerable<ParameterDefinition>)((MethodReference)m).Parameters).Select((ParameterDefinition p) => ((MemberReference)((ParameterReference)p).ParameterType).FullName).SequenceEqual(parameters)).ToList(); if (list.Count == 1) { return list[0]; } missing.Add((list.Count == 0) ? (text + " not found") : (text + " ambiguous")); return null; } private static bool StoresRow(MethodDefinition m) { return ((IEnumerable<Instruction>)m.Body.Instructions).Any(delegate(Instruction i) { //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_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Invalid comparison between Unknown and I4 OpCode opCode = i.OpCode; if ((int)((OpCode)(ref opCode)).Code == 122) { object operand = i.Operand; FieldReference val = (FieldReference)((operand is FieldReference) ? operand : null); if (val != null && ((MemberReference)val).Name == "rp_row") { return ((MemberReference)((MemberReference)val).DeclaringType).FullName == "ZDO"; } } return false; }); } private static string Name(MethodDefinition m) { return ((MemberReference)m.DeclaringType).Name + "." + ((MemberReference)m).Name; } }