Decompiled source of DSPSwarmDrawFix v1.2.0

DSPSwarmDrawFix.dll

Decompiled a month ago
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<NearSailsMode> NearMode;

	internal static readonly FieldRef<DysonSwarm, ComputeBuffer> SwarmBuffer = AccessTools.FieldRefAccess<DysonSwarm, ComputeBuffer>("swarmBuffer");

	internal static readonly FieldRef<DysonSwarm, ComputeBuffer> SwarmInfoBuffer = AccessTools.FieldRefAccess<DysonSwarm, ComputeBuffer>("swarmInfoBuffer");

	internal static readonly FieldRef<DysonSwarm, ComputeBuffer> OrbitColorsBuffer = AccessTools.FieldRefAccess<DysonSwarm, ComputeBuffer>("sailOrbitColorsBuffer");

	internal static readonly FieldRef<DysonSwarm, ComputeBuffer> BulletBuffer = AccessTools.FieldRefAccess<DysonSwarm, ComputeBuffer>("bulletBuffer");

	internal static readonly FieldRef<DysonSwarm, float> SizeInMat = AccessTools.FieldRefAccess<DysonSwarm, float>("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<NearSailsMode>("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);
			}
		}
	}
}