using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using UnityEngine;
using UnityEngine.InputSystem;
using UnityEngine.Rendering;
using UnityEngine.SceneManagement;
using VRShaderFix;
using VRShaderFix.utils;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")]
[assembly: AssemblyCompany("VRShaderFix")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyDescription("Replaces All Materials to use VR Compatiable Shader Version")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("VRShaderFix")]
[assembly: AssemblyTitle("VRShaderFix")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
[module: RefSafetyRules(11)]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)]
internal sealed class RefSafetyRulesAttribute : Attribute
{
public readonly int Version;
public RefSafetyRulesAttribute(int P_0)
{
Version = P_0;
}
}
}
public class ShaderFix : MonoBehaviour
{
[CompilerGenerated]
private sealed class <DelayedShaderFix>d__8 : IEnumerator<object>, IEnumerator, IDisposable
{
private int <>1__state;
private object <>2__current;
public ShaderFix <>4__this;
object IEnumerator<object>.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
object IEnumerator.Current
{
[DebuggerHidden]
get
{
return <>2__current;
}
}
[DebuggerHidden]
public <DelayedShaderFix>d__8(int <>1__state)
{
this.<>1__state = <>1__state;
}
[DebuggerHidden]
void IDisposable.Dispose()
{
<>1__state = -2;
}
private bool MoveNext()
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_002e: Expected O, but got Unknown
int num = <>1__state;
ShaderFix shaderFix = <>4__this;
switch (num)
{
default:
return false;
case 0:
<>1__state = -1;
<>2__current = (object)new WaitForSeconds(1f);
<>1__state = 1;
return true;
case 1:
<>1__state = -1;
Plugin.Logger.LogDebug((object)"Fixing Shaders");
shaderFix.ReplaceMaterialsFor<Renderer>((IEnumerable<Renderer>)Resources.FindObjectsOfTypeAll<Renderer>());
shaderFix.ReplaceMaterialsFor<SkinnedMeshRenderer>((IEnumerable<SkinnedMeshRenderer>)VRFixUtils.FindAllInLoadedScenes<SkinnedMeshRenderer>(Array.Empty<string>()));
shaderFix.ReplaceMaterialsFor<ParticleSystemRenderer>((IEnumerable<ParticleSystemRenderer>)VRFixUtils.FindAllInLoadedScenes<ParticleSystemRenderer>(Array.Empty<string>()));
shaderFix.ReplaceTerrainMaterials(Resources.FindObjectsOfTypeAll<Terrain>());
shaderFix.LogMissingShaders();
return false;
}
}
bool IEnumerator.MoveNext()
{
//ILSpy generated this explicit interface implementation from .override directive in MoveNext
return this.MoveNext();
}
[DebuggerHidden]
void IEnumerator.Reset()
{
throw new NotSupportedException();
}
}
private static readonly Dictionary<string, Shader> BaseGameHDRPShaders = new Dictionary<string, Shader>(StringComparer.OrdinalIgnoreCase);
private static readonly Dictionary<string, Shader> MissingShaders = new Dictionary<string, Shader>(StringComparer.OrdinalIgnoreCase);
public Dictionary<string, Shader> CustomShaders = new Dictionary<string, Shader>(StringComparer.OrdinalIgnoreCase);
public HashSet<string> CachedBlacklist { get; set; }
public void StartShaderFix()
{
//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)
if (Plugin.VRConfig.enableBlacklist.Value)
{
for (int i = 0; i < SceneManager.sceneCount; i++)
{
Scene sceneAt = SceneManager.GetSceneAt(i);
if (CachedBlacklist.Contains(((Scene)(ref sceneAt)).name))
{
Plugin.Logger.LogWarning((object)("Skipped Applying VR Shader Fix to scene '" + ((Scene)(ref sceneAt)).name + "' because is blacklisted in Config"));
return;
}
}
}
((MonoBehaviour)this).StartCoroutine(DelayedShaderFix());
}
[IteratorStateMachine(typeof(<DelayedShaderFix>d__8))]
private IEnumerator DelayedShaderFix()
{
//yield-return decompiler failed: Unexpected instruction in Iterator.Dispose()
return new <DelayedShaderFix>d__8(0)
{
<>4__this = this
};
}
private void ReplaceTerrainMaterials(IEnumerable<Terrain> terrains)
{
Dictionary<Material, Material> dictionary = new Dictionary<Material, Material>();
foreach (Terrain terrain in terrains)
{
Material materialTemplate = terrain.materialTemplate;
if (!IsValidOriginal(materialTemplate))
{
continue;
}
Shader val = ResolveShader(((Object)materialTemplate.shader).name);
if ((Object)(object)val == (Object)null)
{
continue;
}
if (!dictionary.TryGetValue(materialTemplate, out var value))
{
value = CreateVRMaterial(materialTemplate, val);
TerrainData terrainData = terrain.terrainData;
TerrainLayer[] terrainLayers = terrainData.terrainLayers;
value.shaderKeywords = materialTemplate.shaderKeywords;
value.renderQueue = materialTemplate.renderQueue;
value.SetInt("_LayerCount", terrainLayers.Length);
for (int i = 0; i < terrainData.alphamapTextures.Length; i++)
{
value.SetTexture($"_Control{i}", (Texture)(object)terrainData.alphamapTextures[i]);
}
for (int j = 0; j < terrainLayers.Length; j++)
{
TerrainLayer val2 = terrainLayers[j];
value.SetTexture($"_Splat{j}", (Texture)(object)val2.diffuseTexture);
value.SetTexture($"_Normal{j}", (Texture)(object)val2.normalMapTexture);
value.SetTexture($"_Mask{j}", (Texture)(object)val2.maskMapTexture);
}
dictionary[materialTemplate] = value;
}
terrain.materialTemplate = dictionary[materialTemplate];
terrain.terrainData.terrainLayers = terrain.terrainData.terrainLayers;
ForceDetailRefresh(terrain);
terrain.terrainData.RefreshPrototypes();
terrain.Flush();
}
}
private Shader ResolveShader(string shaderName)
{
if (CustomShaders.TryGetValue(shaderName, out var value))
{
return value;
}
if (BaseGameHDRPShaders.TryGetValue(shaderName, out var value2))
{
return value2;
}
if (!MissingShaders.ContainsKey(shaderName))
{
MissingShaders.Add(shaderName, Shader.Find(shaderName));
}
return VRFixUtils.FindClosestShader(shaderName, CustomShaders) ?? VRFixUtils.FindClosestShader(shaderName, BaseGameHDRPShaders);
}
private Material CreateVRMaterial(Material original, Shader shader)
{
//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_001d: Expected O, but got Unknown
Material val = new Material(shader)
{
name = ((Object)original).name + "_VR"
};
MaterialUtils.CopyMaterialProperties(original, val);
return val;
}
private bool IsValidOriginal(Material mat)
{
if ((Object)(object)mat == (Object)null)
{
return false;
}
string name = ((Object)mat).name;
int num = name.IndexOf(" (", StringComparison.Ordinal);
return !((num >= 0) ? name.Substring(0, num) : name).Contains("_VR", StringComparison.OrdinalIgnoreCase);
}
private void LogMissingShaders()
{
if (!Plugin.VRConfig.enableDebug.Value)
{
return;
}
foreach (KeyValuePair<string, Shader> missingShader in MissingShaders)
{
Plugin.Logger.LogWarning((object)"-------------------");
Plugin.Logger.LogError((object)("Missing VR Variant for Shader: " + ((Object)missingShader.Value).name));
}
}
private void ReplaceMaterialsFor<TRenderer>(IEnumerable<TRenderer> renderers) where TRenderer : Renderer
{
Dictionary<Material, Material> dictionary = new Dictionary<Material, Material>();
foreach (TRenderer renderer in renderers)
{
Material[] sharedMaterials = ((Renderer)renderer).sharedMaterials;
if (sharedMaterials == null)
{
continue;
}
for (int i = 0; i < sharedMaterials.Length; i++)
{
Material val = sharedMaterials[i];
if (!IsValidOriginal(val))
{
continue;
}
Shader val2 = ResolveShader(((Object)val.shader).name);
if (!((Object)(object)val2 == (Object)null))
{
if (!dictionary.TryGetValue(val, out var value))
{
value = (dictionary[val] = CreateVRMaterial(val, val2));
}
sharedMaterials[i] = value;
}
}
((Renderer)renderer).sharedMaterials = sharedMaterials;
((Renderer)renderer).materials = sharedMaterials;
}
}
public static void ForceDetailRefresh(Terrain terrain)
{
TerrainData terrainData = terrain.terrainData;
typeof(TerrainData).GetMethod("RefreshPrototypes", BindingFlags.Instance | BindingFlags.NonPublic)?.Invoke(terrainData, null);
for (int i = 0; i < terrainData.detailPrototypes.Length; i++)
{
int[,] detailLayer = terrainData.GetDetailLayer(0, 0, terrainData.detailWidth, terrainData.detailHeight, i);
terrainData.SetDetailLayer(0, 0, i, detailLayer);
}
}
public void CacheBaseGameShaders()
{
Plugin.Logger.LogInfo((object)"Scanning for base‑game HDRP + Shader Graph shaders...");
Shader[] array = Resources.FindObjectsOfTypeAll<Shader>();
foreach (Shader val in array)
{
if ((Object)(object)val == (Object)null)
{
continue;
}
string name = ((Object)val).name;
bool num = name.StartsWith("HDRP/", StringComparison.OrdinalIgnoreCase);
bool flag = name.StartsWith("Shader Graphs/", StringComparison.OrdinalIgnoreCase);
if (!num && !flag)
{
continue;
}
int instanceID = ((Object)val).GetInstanceID();
if (instanceID <= 0)
{
continue;
}
if (!BaseGameHDRPShaders.TryGetValue(name, out var value))
{
BaseGameHDRPShaders[name] = val;
Plugin.Logger.LogInfo((object)$"Cached base‑game shader: {name} (ID {instanceID})");
continue;
}
int instanceID2 = ((Object)value).GetInstanceID();
if (instanceID2 <= 0 || instanceID < instanceID2)
{
BaseGameHDRPShaders[name] = val;
Plugin.Logger.LogInfo((object)$"Updated base‑game shader: {name} → lower ID {instanceID} (was {instanceID2})");
}
}
Plugin.Logger.LogInfo((object)$"Captured {BaseGameHDRPShaders.Count} base‑game shaders.");
}
}
namespace VRShaderFix
{
[HarmonyPatch]
internal class Patches
{
[HarmonyPatch(typeof(RoundManager), "FinishGeneratingNewLevelClientRpc")]
[HarmonyPostfix]
public static void StartVRShaderFixViaPatch()
{
Plugin.Logger.LogDebug((object)"VR Shader Fix Applying");
Plugin.ShaderFixHost.StartShaderFix();
Plugin.Logger.LogDebug((object)"VR Shader Fix Applied");
}
[HarmonyPatch(typeof(StartOfRound), "OnShipLandedMiscEvents")]
[HarmonyPostfix]
public static void StartVRShaderFixViaPatchBackup2()
{
Plugin.Logger.LogDebug((object)"VR Shader Fix Backup Call");
Plugin.ShaderFixHost.StartShaderFix();
Plugin.Logger.LogDebug((object)"VR Shader Fix Backup Call End");
}
}
[BepInPlugin("TKronix.VRShaderFix", "VRShaderFix", "1.0.0.0")]
public class Plugin : BaseUnityPlugin
{
private const string GUID = "TKronix.VRShaderFix";
private const string NAME = "VRShaderFix";
private const string VERSION = "1.0.0.0";
private static int PressCount;
internal static ManualLogSource Logger { get; private set; }
public static ShaderFix ShaderFixHost { get; private set; }
internal static VRSFConfig VRConfig { get; private set; }
private void Awake()
{
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Expected O, but got Unknown
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
Logger = ((BaseUnityPlugin)this).Logger;
Logger.LogInfo((object)"Plugin loading");
VRConfig = new VRSFConfig(((BaseUnityPlugin)this).Config);
InputAction val = new InputAction("RunVRShaderFix", (InputActionType)1, "<Keyboard>/f1", (string)null, (string)null, (string)null);
InputAction val2 = new InputAction("RunVRShaderFix2", (InputActionType)1, "<Keyboard>/f2", (string)null, (string)null, (string)null);
val.performed += delegate
{
ShaderFixHost.StartShaderFix();
};
val2.performed += delegate
{
Hotkey2();
};
val.Disable();
val2.Disable();
if (VRConfig.enableDebug.Value)
{
val.Enable();
val2.Enable();
}
SceneManager.sceneLoaded += InitalizeVRShaderFix;
if (VRConfig.enableHarmonyPatches.Value)
{
new Harmony("TKronix.VRShaderFix").PatchAll(typeof(Patches));
Logger.LogInfo((object)"Plugin Harmony Patches Applied!");
}
Logger.LogInfo((object)"Plugin loaded!");
}
private void InitalizeVRShaderFix(Scene scene, LoadSceneMode mode)
{
//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_0027: Expected O, but got Unknown
if (!((Scene)(ref scene)).name.Equals("SampleSceneRelay", StringComparison.OrdinalIgnoreCase))
{
return;
}
GameObject val = new GameObject("VRShaderFixHost");
Object.DontDestroyOnLoad((Object)val);
ShaderFixHost = val.AddComponent<ShaderFix>();
ShaderFixHost.CacheBaseGameShaders();
AssetBundle val2 = LoadAssetBundle("vrmaterials");
Material[] array = val2.LoadAllAssets<Material>();
foreach (Material val3 in array)
{
if (!((Object)(object)val3 == (Object)null))
{
Logger.LogInfo((object)("Loaded Material: " + ((Object)val3).name));
ShaderFixHost.CustomShaders.Add(((Object)val3.shader).name, val3.shader);
}
}
ShaderFixHost.CachedBlacklist = (from s in VRConfig.blacklistedScenes.Value.Split(',')
select s.Trim() into s
where !string.IsNullOrEmpty(s)
select s).ToHashSet<string>(StringComparer.OrdinalIgnoreCase);
val2.Unload(false);
val2 = null;
SceneManager.sceneLoaded -= InitalizeVRShaderFix;
SceneManager.sceneLoaded += ApplyVRFixOnSceneLoad;
ShaderFixHost.StartShaderFix();
}
private void CheckScene(Scene scene, LoadSceneMode mode)
{
if (((Scene)(ref scene)).name.Equals("SampleSceneRelay", StringComparison.OrdinalIgnoreCase))
{
SceneManager.sceneLoaded += ApplyVRFixOnSceneLoad;
SceneManager.sceneLoaded -= CheckScene;
}
}
private void ApplyVRFixOnSceneLoad(Scene scene, LoadSceneMode mode)
{
if (VRConfig.enableLogSceneToConsole.Value)
{
string text = "Use name below for Blacklisting";
string name = ((Scene)(ref scene)).name;
int num = Mathf.Max(text.Length, name.Length) + 6;
string text2 = "╔" + new string('═', num) + "╗";
string text3 = "║" + Center(text, num) + "║";
string text4 = "║" + Center(name, num) + "║";
string text5 = "╚" + new string('═', num) + "╝";
Logger.LogInfo((object)text2);
Logger.LogInfo((object)text3);
Logger.LogInfo((object)text4);
Logger.LogInfo((object)text5);
}
if (((Scene)(ref scene)).name.Equals("MainMenu", StringComparison.OrdinalIgnoreCase))
{
SceneManager.sceneLoaded -= ApplyVRFixOnSceneLoad;
SceneManager.sceneLoaded += CheckScene;
}
else
{
ShaderFixHost.StartShaderFix();
}
}
private string Center(string text, int totalWidth)
{
int num = totalWidth - text.Length;
int num2 = num / 2;
int count = num - num2;
return new string(' ', num2) + text + new string(' ', count);
}
private AssetBundle LoadAssetBundle(string AssetBundle)
{
return AssetBundle.LoadFromFile(Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), AssetBundle));
}
private static void Hotkey2()
{
PressCount++;
if (PressCount == 1)
{
Object.FindObjectOfType<PreInitSceneScript>().ChooseLaunchOption(true);
}
if (PressCount == 2)
{
Object.FindObjectOfType<MenuManager>().StartHosting();
}
if (PressCount == 3)
{
StartOfRound.Instance.ChangeLevel(17);
}
if (PressCount == 4)
{
Object.FindObjectOfType<StartMatchLever>().StartGame();
}
}
}
internal class VRSFConfig
{
public readonly ConfigEntry<bool> enableBlacklist;
public readonly ConfigEntry<bool> enableLogSceneToConsole;
public readonly ConfigEntry<string> blacklistedScenes;
public readonly ConfigEntry<bool> enableHarmonyPatches;
public readonly ConfigEntry<bool> enableDebug;
public VRSFConfig(ConfigFile cfg)
{
enableLogSceneToConsole = cfg.Bind<bool>("Blacklist", "EnableLogSceneNameToConsole", false, "Enable or disable Logging of Scene Name to Console");
enableBlacklist = cfg.Bind<bool>("Blacklist", "EnableBlacklist", false, "Enable or disable the scene blacklist system");
blacklistedScenes = cfg.Bind<string>("Blacklist", "BlacklistedScenes", "ExampleSceneName1, ExampleSceneName2", "List of scene names to NOT replace shaders/materials on.\n(Separated by commas)");
enableHarmonyPatches = cfg.Bind<bool>("HarmonyPatches", "EnableHarmonyPatches", true, "Enable or disable the Harmony Patches");
enableDebug = cfg.Bind<bool>("Development", "EnableDevelopmentFeatures", false, "Enable or disable Dvelopment features \n(Ignore this its for Development Purposes Only nothing useful for Gameplay)");
}
}
}
namespace VRShaderFix.utils
{
public static class MaterialUtils
{
public static void CopyMaterialProperties(Material source, Material target)
{
//IL_0021: 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_0056: 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_007f: Expected I4, but got Unknown
//IL_0085: Unknown result type (might be due to invalid IL or missing references)
//IL_0095: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: 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)
if ((Object)(object)source == (Object)null || (Object)(object)target == (Object)null)
{
return;
}
target.renderQueue = source.renderQueue;
target.globalIlluminationFlags = source.globalIlluminationFlags;
CopyShaderKeywords(source, target);
Shader shader = source.shader;
int propertyCount = shader.GetPropertyCount();
for (int i = 0; i < propertyCount; i++)
{
string propertyName = shader.GetPropertyName(i);
ShaderPropertyType propertyType = shader.GetPropertyType(i);
if (!target.HasProperty(propertyName))
{
continue;
}
switch ((int)propertyType)
{
case 0:
target.SetColor(propertyName, source.GetColor(propertyName));
break;
case 1:
target.SetVector(propertyName, source.GetVector(propertyName));
break;
case 2:
case 3:
target.SetFloat(propertyName, source.GetFloat(propertyName));
break;
case 4:
{
Texture texture = source.GetTexture(propertyName);
target.SetTexture(propertyName, texture);
if ((Object)(object)texture != (Object)null)
{
target.SetTextureOffset(propertyName, source.GetTextureOffset(propertyName));
target.SetTextureScale(propertyName, source.GetTextureScale(propertyName));
}
break;
}
}
}
CopyMainTextureShortcuts(source, target);
}
private static void CopyShaderKeywords(Material source, Material target)
{
HashSet<string> hashSet = new HashSet<string>(source.shaderKeywords);
string[] shaderKeywords = target.shaderKeywords;
foreach (string item in shaderKeywords)
{
hashSet.Add(item);
}
target.shaderKeywords = hashSet.ToArray();
}
private static void CopyMainTextureShortcuts(Material source, Material target)
{
//IL_001c: 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)
if (target.HasProperty("_MainTex"))
{
target.mainTexture = source.mainTexture;
target.mainTextureOffset = source.mainTextureOffset;
target.mainTextureScale = source.mainTextureScale;
}
}
}
public static class VRFixUtils
{
private static readonly string[] DefaultExcludedScenes = new string[3] { "MainMenu", "DontDestroyOnLoad", "HideAndDontSave" };
public static List<T> FindAllInLoadedScenes<T>(params string[] excludedScenes) where T : Component
{
//IL_001f: 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)
if (excludedScenes == null || excludedScenes.Length == 0)
{
excludedScenes = DefaultExcludedScenes;
}
List<T> list = new List<T>();
int sceneCount = SceneManager.sceneCount;
for (int i = 0; i < sceneCount; i++)
{
Scene sceneAt = SceneManager.GetSceneAt(i);
if (((Scene)(ref sceneAt)).isLoaded && !excludedScenes.Contains(((Scene)(ref sceneAt)).name))
{
GameObject[] rootGameObjects = ((Scene)(ref sceneAt)).GetRootGameObjects();
foreach (GameObject val in rootGameObjects)
{
list.AddRange(val.GetComponentsInChildren<T>(true));
}
}
}
return list;
}
public static Shader FindClosestShader(string name, Dictionary<string, Shader> shaders)
{
Shader result = null;
int num = -1;
foreach (KeyValuePair<string, Shader> shader in shaders)
{
string key = shader.Key;
if ((key.StartsWith(name, StringComparison.OrdinalIgnoreCase) || name.StartsWith(key, StringComparison.OrdinalIgnoreCase)) && key.Length > num)
{
num = key.Length;
result = shader.Value;
}
}
return result;
}
}
}