using System; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using UnityEngine; using UnityEngine.Rendering; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")] [assembly: AssemblyVersion("0.0.0.0")] namespace DSPSwarmDrawFix; public enum NearSailsMode { Off, Auto, Always } [BepInPlugin("me.gp.dspswarmdrawfix", "DSPSwarmDrawFix", "1.2.0")] public class SwarmDrawFixPlugin : BaseUnityPlugin { internal static ManualLogSource Log; internal static ConfigEntry NearMode; internal static readonly FieldRef SwarmBuffer = AccessTools.FieldRefAccess("swarmBuffer"); internal static readonly FieldRef SwarmInfoBuffer = AccessTools.FieldRefAccess("swarmInfoBuffer"); internal static readonly FieldRef OrbitColorsBuffer = AccessTools.FieldRefAccess("sailOrbitColorsBuffer"); internal static readonly FieldRef BulletBuffer = AccessTools.FieldRefAccess("bulletBuffer"); internal static readonly FieldRef SizeInMat = AccessTools.FieldRefAccess("sizeInMat"); private void Awake() { //IL_0030: 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) Log = ((BaseUnityPlugin)this).Logger; NearMode = ((BaseUnityPlugin)this).Config.Bind("Rendering", "NearSails", NearSailsMode.Auto, "Near sails: the solid mesh drawn within 2500 units instead of a flat sprite.\nThe game culls them on the GPU through an append buffer and an indirect draw, which D3DMetal does not handle, so this mod instances the whole swarm instead — cost then scales with sail count.\nAuto: only draw when the camera is close enough to a sail orbit for anything to be in range. Off: never draw them. Always: 1.1.0 behaviour, costly on large swarms."); Harmony val = new Harmony("me.gp.dspswarmdrawfix"); val.PatchAll(typeof(SwarmDrawPatch)); val.PatchAll(typeof(NearDrawPatch)); Log.LogInfo((object)$"DSPSwarmDrawFix active: far sails as indexed triangles, near sails {NearMode.Value}"); } private void OnDestroy() { SwarmDrawPatch.ReleaseBuffers(); NearDrawPatch.ReleaseBuffers(); } } internal static class Prop { internal static readonly int SwarmBuffer = Shader.PropertyToID("_SwarmBuffer"); internal static readonly int SwarmInfoBuffer = Shader.PropertyToID("_SwarmInfoBuffer"); internal static readonly int NodeBuffer = Shader.PropertyToID("_NodeBuffer"); internal static readonly int OrbitColor = Shader.PropertyToID("_OrbitColor"); internal static readonly int NearIdBuffer = Shader.PropertyToID("_NearIdBuffer"); internal static readonly int BulletBuffer = Shader.PropertyToID("_BulletBuffer"); internal static readonly int SunPosition = Shader.PropertyToID("_SunPosition"); internal static readonly int SunPositionMap = Shader.PropertyToID("_SunPosition_Map"); internal static readonly int LocalRot = Shader.PropertyToID("_LocalRot"); internal static readonly int GameTick = Shader.PropertyToID("_GameTick"); internal static readonly int Stride = Shader.PropertyToID("_Stride"); internal static readonly int DistScalePoint = Shader.PropertyToID("_DistScalePoint"); internal static readonly int RenderPlace = Shader.PropertyToID("_Global_DS_RenderPlace"); internal static readonly int EditorMaskS = Shader.PropertyToID("_Global_DS_EditorMaskS"); internal static readonly int GameMaskS = Shader.PropertyToID("_Global_DS_GameMaskS"); } internal struct SwarmFrame { internal Vector3 SunPos; internal Vector3 SunPosMap; internal Vector4 LocalRot; internal uint Tick; internal static SwarmFrame Build(DysonSwarm sw) { //IL_000a: 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_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_0036: 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_0083: 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_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00f0: 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_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_0101: Invalid comparison between Unknown and I4 //IL_0098: 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_009e: 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_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_00ab: 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_00b5: 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_00e9: 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_0110: Unknown result type (might be due to invalid IL or missing references) //IL_0115: 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_012d: Unknown result type (might be due to invalid IL or missing references) SwarmFrame result = new SwarmFrame { SunPos = Vector3.zero, SunPosMap = Vector3.zero, LocalRot = new Vector4(0f, 0f, 0f, 1f), Tick = (uint)(GameMain.gameTick & 0xFFFFFFFFu) }; if (sw.starData == null || sw.gameData == null) { return result; } PlanetData localPlanet = sw.gameData.localPlanet; Player mainPlayer = sw.gameData.mainPlayer; VectorLF3 val = sw.starData.uPosition - mainPlayer.uPosition; if (localPlanet != null) { val = Maths.QInvRotateLF(localPlanet.runtimeRotation, val); val += VectorLF3.op_Implicit(mainPlayer.position); result.LocalRot = new Vector4(localPlanet.runtimeRotation.x, localPlanet.runtimeRotation.y, localPlanet.runtimeRotation.z, localPlanet.runtimeRotation.w); } result.SunPos = VectorLF3.op_Implicit(val); if ((int)DysonSphere.renderPlace == 1) { result.SunPosMap = VectorLF3.op_Implicit((sw.starData.uPosition - UIStarmap.viewTargetStatic) * 0.00025); } return result; } internal void ApplyTo(Material mat) { //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_001d: 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_0033: Unknown result type (might be due to invalid IL or missing references) mat.SetVector(Prop.SunPosition, Vector4.op_Implicit(SunPos)); mat.SetVector(Prop.SunPositionMap, Vector4.op_Implicit(SunPosMap)); mat.SetVector(Prop.LocalRot, LocalRot); mat.SetInt(Prop.GameTick, (int)Tick); } internal static int LayerForRenderPlace() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Invalid comparison between Unknown and I4 if ((int)DysonSphere.renderPlace == 1) { return 20; } if ((int)DysonSphere.renderPlace == 2) { return 21; } return 16; } } internal static class SwarmDrawPatch { private const int ChunkSails = 5460; private static GraphicsBuffer quadIndexBuffer; private static bool failedOnce; internal static void ReleaseBuffers() { GraphicsBuffer obj = quadIndexBuffer; if (obj != null) { obj.Release(); } quadIndexBuffer = null; } private static GraphicsBuffer GetIndexBuffer() { //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_007c: Expected O, but got Unknown if (quadIndexBuffer != null && quadIndexBuffer.IsValid()) { return quadIndexBuffer; } int num = 16380; int[] array = new int[num * 6]; for (int i = 0; i < num; i++) { int num2 = i * 4; int num3 = i * 6; array[num3] = num2; array[num3 + 1] = num2 + 1; array[num3 + 2] = num2 + 2; array[num3 + 3] = num2; array[num3 + 4] = num2 + 2; array[num3 + 5] = num2 + 3; } quadIndexBuffer = new GraphicsBuffer((Target)2, array.Length, 4); quadIndexBuffer.SetData((Array)array); return quadIndexBuffer; } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSwarm), "DrawPost")] private static bool DrawPostPrefix(DysonSwarm __instance) { try { ReplacementDrawPost(__instance); return false; } catch (Exception arg) { if (!failedOnce) { failedOnce = true; SwarmDrawFixPlugin.Log.LogError((object)$"DrawPost replacement threw, falling back to vanilla: {arg}"); } return true; } } private static void ReplacementDrawPost(DysonSwarm sw) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0013: Invalid comparison between Unknown and I4 //IL_003a: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 SwarmFrame swarmFrame = SwarmFrame.Build(sw); Camera val = Camera.main; if ((int)DysonSphere.renderPlace == 1) { UIStarmap starmap = UIRoot.instance.uiGame.starmap; if ((Object)(object)starmap != (Object)null) { val = starmap.screenCamera; } } else if ((int)DysonSphere.renderPlace == 2) { UIDysonEditor dysonEditor = UIRoot.instance.uiGame.dysonEditor; if ((Object)(object)dysonEditor != (Object)null) { val = dysonEditor.screenCamera; } } if ((Object)(object)val != (Object)null) { float num = SwarmDrawFixPlugin.SizeInMat.Invoke(sw) * (float)Screen.height * 0.4f; float num2 = 1f / Mathf.Tan(val.fieldOfView * ((float)Math.PI / 180f) * 0.5f) * num; sw.sailFarMaterial.SetFloat(Prop.DistScalePoint, num2); } ComputeBuffer val2 = SwarmDrawFixPlugin.SwarmBuffer.Invoke(sw); Material sailFarMaterial = sw.sailFarMaterial; sailFarMaterial.SetInt(Prop.Stride, 5460); sailFarMaterial.SetBuffer(Prop.SwarmBuffer, val2); sailFarMaterial.SetBuffer(Prop.SwarmInfoBuffer, SwarmDrawFixPlugin.SwarmInfoBuffer.Invoke(sw)); sailFarMaterial.SetBuffer(Prop.NodeBuffer, sw.dysonSphere.nrdBuffer); sailFarMaterial.SetBuffer(Prop.OrbitColor, SwarmDrawFixPlugin.OrbitColorsBuffer.Invoke(sw)); swarmFrame.ApplyTo(sailFarMaterial); sailFarMaterial.SetPass(0); if (sw.sailCursor > 0 && val2 != null) { int num3 = (sw.sailCursor + 5460 - 1) / 5460; Graphics.DrawProceduralNow((MeshTopology)0, GetIndexBuffer(), 98280, num3); } ComputeBuffer val3 = SwarmDrawFixPlugin.BulletBuffer.Invoke(sw); if (val3 != null) { sw.bulletMaterial.SetBuffer(Prop.BulletBuffer, val3); sw.bulletMaterial.SetPass(0); Graphics.DrawProceduralNow((MeshTopology)2, sw.bulletCursor * 8, 1); } } } internal static class NearDrawPatch { private const float NearThreshold = 2500f; private static ComputeBuffer identityBuffer; private static bool failedOnce; internal static void ReleaseBuffers() { ComputeBuffer obj = identityBuffer; if (obj != null) { obj.Release(); } identityBuffer = null; } private static ComputeBuffer GetIdentityBuffer(int minCount) { //IL_0040: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Expected O, but got Unknown if (identityBuffer != null && identityBuffer.IsValid() && identityBuffer.count >= minCount) { return identityBuffer; } int num = Mathf.NextPowerOfTwo(minCount); ComputeBuffer obj = identityBuffer; if (obj != null) { obj.Release(); } identityBuffer = new ComputeBuffer(num, 4, (ComputeBufferType)0); int[] array = new int[num]; for (int i = 0; i < num; i++) { array[i] = i; } identityBuffer.SetData((Array)array); return identityBuffer; } [HarmonyPrefix] [HarmonyPatch(typeof(DysonSwarm), "DrawModel")] private static bool DrawModelPrefix(DysonSwarm __instance, ERenderPlace place, int editorMask, int gameMask) { try { ReplacementDrawModel(__instance, editorMask, gameMask); return false; } catch (Exception arg) { if (!failedOnce) { failedOnce = true; SwarmDrawFixPlugin.Log.LogError((object)$"DrawModel replacement threw, falling back to vanilla: {arg}"); } return true; } } private static bool AnySailCanBeNear(DysonSwarm sw, Camera camera) { //IL_0017: 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_0027: 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_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_0041: Unknown result type (might be due to invalid IL or missing references) SailOrbit[] orbits = sw.orbits; if (orbits == null) { return false; } VectorLF3 val = sw.gameData.mainPlayer.uPosition + VectorLF3.op_Implicit(((Component)camera).transform.position) - sw.starData.uPosition; float num = (float)((VectorLF3)(ref val)).magnitude; for (int i = 1; i < sw.orbitCursor; i++) { if (orbits[i].enabled && orbits[i].count > 0 && Mathf.Abs(num - orbits[i].radius) <= 2500f) { return true; } } return false; } private static void ReplacementDrawModel(DysonSwarm sw, int editorMask, int gameMask) { //IL_00f6: Unknown result type (might be due to invalid IL or missing references) //IL_0100: Expected I4, but got Unknown //IL_0127: Unknown result type (might be due to invalid IL or missing references) //IL_013b: Unknown result type (might be due to invalid IL or missing references) //IL_0140: Unknown result type (might be due to invalid IL or missing references) NearSailsMode value = SwarmDrawFixPlugin.NearMode.Value; if (value == NearSailsMode.Off || (Object)(object)Configs.builtin.solarSailMesh == (Object)null || sw.starData == null || sw.gameData == null || sw.sailCursor <= 1) { return; } Camera main = Camera.main; if (!((Object)(object)main == (Object)null) && (value != NearSailsMode.Auto || AnySailCanBeNear(sw, main))) { ComputeBuffer val = SwarmDrawFixPlugin.SwarmBuffer.Invoke(sw); if (val != null) { SwarmFrame swarmFrame = SwarmFrame.Build(sw); Material sailNearMaterial = sw.sailNearMaterial; sailNearMaterial.SetBuffer(Prop.NearIdBuffer, GetIdentityBuffer(sw.sailCursor)); sailNearMaterial.SetBuffer(Prop.SwarmBuffer, val); sailNearMaterial.SetBuffer(Prop.SwarmInfoBuffer, SwarmDrawFixPlugin.SwarmInfoBuffer.Invoke(sw)); sailNearMaterial.SetBuffer(Prop.NodeBuffer, sw.dysonSphere.nrdBuffer); sailNearMaterial.SetBuffer(Prop.OrbitColor, SwarmDrawFixPlugin.OrbitColorsBuffer.Invoke(sw)); swarmFrame.ApplyTo(sailNearMaterial); sailNearMaterial.SetInt(Prop.RenderPlace, (int)DysonSphere.renderPlace); sailNearMaterial.SetInt(Prop.EditorMaskS, editorMask); sailNearMaterial.SetInt(Prop.GameMaskS, gameMask); Graphics.DrawMeshInstancedProcedural(Configs.builtin.solarSailMesh, 0, sailNearMaterial, new Bounds(Vector3.zero, new Vector3(100000f, 100000f, 100000f)), sw.sailCursor, (MaterialPropertyBlock)null, (ShadowCastingMode)0, false, SwarmFrame.LayerForRenderPlace(), (Camera)null, (LightProbeUsage)1, (LightProbeProxyVolume)null); } } } }