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);
}
}
}
}