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.Cryptography; using System.Text; using System.Text.RegularExpressions; using BepInEx; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using PluginConfig.API; using PluginConfig.API.Decorators; using PluginConfig.API.Fields; using UnityEngine; using UnityEngine.Rendering; [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("UltraBlood")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Recolors ULTRAKILL blood splatters and puddles to a custom color.")] [assembly: AssemblyFileVersion("0.2.1.0")] [assembly: AssemblyInformationalVersion("0.2.1+85b68089e57ba10d8fea52167845b88a2d6c1c17")] [assembly: AssemblyProduct("UltraBlood")] [assembly: AssemblyTitle("UltraBlood")] [assembly: AssemblyVersion("0.2.1.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [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; } } } namespace UltraBlood { internal static class BloodColorController { private const string BloodColorProperty = "_UltraBloodColor"; private static Material _replacementComposite; private static Material _originalComposite; private static bool _activeLogged; private static bool _failureLogged; private static bool _renderPassLogged; private static bool _statusReported; private static string _lastDiagFingerprint; private const float RainbowCycleSpeed = 0.35f; public static bool PuddleRecolorActive { get; private set; } public static void Refresh() { if (TryGetManager(out var bsm)) { ApplyToStainMaterials(bsm); } } public static void ApplyToStainMaterials(BloodsplatterManager bsm) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)bsm == (Object)null)) { if (UltraBloodConfig.Enabled && UltraBloodConfig.RecolorPuddles) { ReplaceComposite(bsm, CurrentColor()); } else { RestoreComposite(bsm); } if (UltraBloodConfig.DebugLogging) { LogStainMaterialsOnce(bsm); } } } public static void RestoreStainMaterials() { if (TryGetManager(out var bsm)) { RestoreComposite(bsm); } if ((Object)(object)_replacementComposite != (Object)null) { Object.Destroy((Object)(object)_replacementComposite); _replacementComposite = null; } } public static void NoteCompositeRenderPass() { if (!_renderPassLogged && UltraBloodConfig.DebugLogging && TryGetManager(out var bsm) && !((Object)(object)bsm.bloodCompositeMaterial == (Object)null)) { _renderPassLogged = true; Material bloodCompositeMaterial = bsm.bloodCompositeMaterial; bool flag = (Object)(object)_replacementComposite != (Object)null && bloodCompositeMaterial == _replacementComposite; string arg = (((Object)(object)bloodCompositeMaterial.shader != (Object)null) ? ((Object)bloodCompositeMaterial.shader).name : ""); Plugin.Log.LogInfo((object)$"[shader] composite render pass material id={((Object)bloodCompositeMaterial).GetInstanceID()} shader='{arg}' passIndex=1 isReplacement={flag}"); } } private static Color CurrentColor() { //IL_0007: 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_0057: 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_0023: Unknown result type (might be due to invalid IL or missing references) if (UltraBloodConfig.SolidCyanTest) { return Color.cyan; } if (UltraBloodConfig.EnemyBloodColorMatch) { return (Color)(((??)BloodParticles.LastEnemyColor) ?? UltraBloodConfig.BloodColor); } if (UltraBloodConfig.RainbowBlood) { return Color.HSVToRGB(Mathf.Repeat(Time.time * 0.35f, 1f), 0.9f, 1f); } return UltraBloodConfig.BloodColor; } public static void TickDynamicColor() { //IL_0015: 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_0025: 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_003c: Unknown result type (might be due to invalid IL or missing references) if (PuddleRecolorActive && !((Object)(object)_replacementComposite == (Object)null)) { Color val = CurrentColor(); _replacementComposite.SetColor("_UltraBloodColor", new Color(val.r, val.g, val.b, UltraBloodConfig.PuddleOpacity)); } } private static void ReplaceComposite(BloodsplatterManager bsm, Color color) { //IL_00a1: 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_00ad: 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_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_0097: Expected O, but got Unknown Shader compositeShader = ShaderBundle.CompositeShader; if ((Object)(object)compositeShader == (Object)null) { PuddleRecolorActive = false; if (!_failureLogged) { _failureLogged = true; Plugin.Log.LogError((object)($"[shader] puddle recoloring unavailable: {ShaderBundle.Status} ({ShaderBundle.StatusMessage}). " + "Running Unity " + Application.unityVersion + ". Leaving the vanilla composite in place.")); ReportStatus($"Puddle recoloring unavailable ({ShaderBundle.Status}). See the log.", ok: false); } return; } if ((Object)(object)_replacementComposite == (Object)null) { _replacementComposite = new Material(compositeShader) { name = "UltraBlood_CompositeBlood" }; } _replacementComposite.SetColor("_UltraBloodColor", new Color(color.r, color.g, color.b, UltraBloodConfig.PuddleOpacity)); Material bloodCompositeMaterial = bsm.bloodCompositeMaterial; if ((Object)(object)bloodCompositeMaterial != (Object)(object)_replacementComposite) { if ((Object)(object)bloodCompositeMaterial != (Object)null) { _originalComposite = bloodCompositeMaterial; } bsm.bloodCompositeMaterial = _replacementComposite; if (!_activeLogged) { _activeLogged = true; Material bloodCompositeMaterial2 = bsm.bloodCompositeMaterial; Plugin.Log.LogInfo((object)$"[shader] manager id={((Object)bsm).GetInstanceID()}"); Plugin.Log.LogInfo((object)string.Format("[shader] original composite id={0} name='{1}'", ((Object)(object)_originalComposite != (Object)null) ? ((Object)_originalComposite).GetInstanceID() : 0, ((Object)(object)_originalComposite != (Object)null) ? ((Object)_originalComposite).name : "null")); Plugin.Log.LogInfo((object)$"[shader] replacement composite id={((Object)_replacementComposite).GetInstanceID()} name='{((Object)_replacementComposite).name}' shader='{((Object)compositeShader).name}' passCount={compositeShader.passCount}"); Plugin.Log.LogInfo((object)$"[shader] manager field material id={(((Object)(object)bloodCompositeMaterial2 != (Object)null) ? ((Object)bloodCompositeMaterial2).GetInstanceID() : 0)} referencesReplacement={bloodCompositeMaterial2 == _replacementComposite}"); } } PuddleRecolorActive = true; ReportStatus("Puddle recoloring active.", ok: true); } private static void RestoreComposite(BloodsplatterManager bsm) { if ((Object)(object)_originalComposite != (Object)null && (Object)(object)bsm.bloodCompositeMaterial == (Object)(object)_replacementComposite) { bsm.bloodCompositeMaterial = _originalComposite; } PuddleRecolorActive = false; } private static void ReportStatus(string text, bool ok) { if (!_statusReported) { _statusReported = true; UltraBloodConfig.SetPuddleStatus(text, ok); } } private static void LogStainMaterialsOnce(BloodsplatterManager bsm) { //IL_0092: 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) string[] obj = new string[8] { ((Object)bsm).GetInstanceID().ToString(), MaterialId(bsm.stainMat), MaterialId(bsm.bloodCompositeMaterial), PuddleRecolorActive ? "active" : "inactive", UltraBloodConfig.Enabled ? "on" : "off", UltraBloodConfig.RecolorPuddles ? "puddles" : "nopuddles", UltraBloodConfig.SolidCyanTest ? "cyan" : "color", null }; Color val = CurrentColor(); obj[7] = ((Color)(ref val)).ToString("F2"); string text = string.Join("|", obj); if (!(text == _lastDiagFingerprint)) { _lastDiagFingerprint = text; LogMaterial("stainMat", bsm.stainMat); LogMaterial("bloodCompositeMaterial", bsm.bloodCompositeMaterial); } } private static string MaterialId(Material mat) { if (!((Object)(object)mat == (Object)null)) { return ((Object)mat).GetInstanceID().ToString(); } return "null"; } private static void LogMaterial(string label, Material mat) { //IL_0109: 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) //IL_0110: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Expected I4, but got Unknown //IL_0134: Unknown result type (might be due to invalid IL or missing references) //IL_0139: Unknown result type (might be due to invalid IL or missing references) //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)mat == (Object)null) { Plugin.Log.LogInfo((object)("[diagnostics] " + label + ": ")); return; } Shader shader = mat.shader; Plugin.Log.LogInfo((object)$"[diagnostics] === {label} === material='{((Object)mat).name}' id={((Object)mat).GetInstanceID()} renderQueue={mat.renderQueue}"); if ((Object)(object)shader == (Object)null) { Plugin.Log.LogInfo((object)"[diagnostics] shader="); return; } Plugin.Log.LogInfo((object)$"[diagnostics] shader='{((Object)shader).name}' id={((Object)shader).GetInstanceID()} passCount={shader.passCount}"); string[] shaderKeywords = mat.shaderKeywords; Plugin.Log.LogInfo((object)("[diagnostics] enabledKeywords=[" + ((shaderKeywords != null && shaderKeywords.Length != 0) ? string.Join(", ", shaderKeywords) : "none") + "]")); int propertyCount = shader.GetPropertyCount(); for (int i = 0; i < propertyCount; i++) { string propertyName = shader.GetPropertyName(i); ShaderPropertyType propertyType = shader.GetPropertyType(i); string arg; switch ((int)propertyType) { case 0: { Color color = mat.GetColor(propertyName); arg = ((Color)(ref color)).ToString("F3"); break; } case 1: { Vector4 vector = mat.GetVector(propertyName); arg = ((Vector4)(ref vector)).ToString("F3"); break; } case 2: case 3: arg = mat.GetFloat(propertyName).ToString("F3"); break; case 4: arg = DescribeTexture(mat.GetTexture(propertyName)); break; case 5: arg = mat.GetInt(propertyName).ToString(); break; default: arg = ""; break; } Plugin.Log.LogInfo((object)$"[diagnostics] {propertyName} <{propertyType}> = {arg}"); } } private static string DescribeTexture(Texture texture) { //IL_0026: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)texture == (Object)null) { return ""; } Texture2D val = (Texture2D)(object)((texture is Texture2D) ? texture : null); string text = ((val != null) ? $" {val.format}" : string.Empty); return $"'{((Object)texture).name}' ({((object)texture).GetType().Name} {texture.width}x{texture.height}{text})"; } private static bool TryGetManager(out BloodsplatterManager bsm) { bsm = null; try { return MonoSingleton.TryGetInstance(ref bsm) && (Object)(object)bsm != (Object)null; } catch (Exception) { return false; } } } internal static class BloodParticles { private sealed class Snapshot { public ParticleSystem System; public MinMaxGradient StartColor; public bool LifetimeEnabled; public MinMaxGradient Lifetime; public bool SpeedEnabled; public MinMaxGradient Speed; public bool TrailsEnabled; public MinMaxGradient TrailLifetime; public MinMaxGradient TrailOverTrail; public ParticleSystemRenderer Renderer; public Material OriginalMaterial; public Material PrivateMaterial; public string TintProperty; public Color RainbowColor; public Color? EnemyColor; } private static readonly Dictionary Snapshots = new Dictionary(); private static readonly HashSet LoggedFingerprints = new HashSet(); private static readonly Dictionary BloodEnemies = new Dictionary(); private static readonly Dictionary EnemyColors = new Dictionary(); private static readonly string[] TintProperties = new string[3] { "_Color", "_BaseColor", "_TintColor" }; private static readonly Dictionary EnemyPalette = new Dictionary { { (EnemyType)3, new Color(0.72f, 0.58f, 0.42f) }, { (EnemyType)13, new Color(0.8f, 0.64f, 0.6f) }, { (EnemyType)14, new Color(0.76f, 0.32f, 0.34f) }, { (EnemyType)15, new Color(0.44f, 0.52f, 0.3f) }, { (EnemyType)36, new Color(0.7f, 0.66f, 0.62f) }, { (EnemyType)5, new Color(0.82f, 0.84f, 0.9f) }, { (EnemyType)1, new Color(0.55f, 0.58f, 0.62f) }, { (EnemyType)6, new Color(0.9f, 0.55f, 0.15f) }, { (EnemyType)12, new Color(0.8f, 0.45f, 0.15f) }, { (EnemyType)7, new Color(0.75f, 0.16f, 0.16f) }, { (EnemyType)8, new Color(0.22f, 0.46f, 0.85f) }, { (EnemyType)22, new Color(0.22f, 0.46f, 0.85f) }, { (EnemyType)20, new Color(0.72f, 0.5f, 0.24f) }, { (EnemyType)31, new Color(0.88f, 0.86f, 0.82f) }, { (EnemyType)33, new Color(0.46f, 0.49f, 0.53f) }, { (EnemyType)34, new Color(0.4f, 0.43f, 0.47f) }, { (EnemyType)35, new Color(0.5f, 0.53f, 0.57f) }, { (EnemyType)0, new Color(0.85f, 0.84f, 0.8f) }, { (EnemyType)2, new Color(0.66f, 0.26f, 0.26f) }, { (EnemyType)4, new Color(0.8f, 0.68f, 0.42f) }, { (EnemyType)9, new Color(0.96f, 0.82f, 0.32f) }, { (EnemyType)10, new Color(0.26f, 0.26f, 0.3f) }, { (EnemyType)23, new Color(0.55f, 0.4f, 0.28f) }, { (EnemyType)24, new Color(0.5f, 0.36f, 0.25f) }, { (EnemyType)21, new Color(0.9f, 0.75f, 0.3f) }, { (EnemyType)11, new Color(0.6f, 0.58f, 0.55f) }, { (EnemyType)18, new Color(0.82f, 0.8f, 0.76f) }, { (EnemyType)16, new Color(0.92f, 0.86f, 0.62f) }, { (EnemyType)28, new Color(0.8f, 0.22f, 0.22f) }, { (EnemyType)19, new Color(0.7f, 0.46f, 0.42f) }, { (EnemyType)29, new Color(0.8f, 0.76f, 0.72f) }, { (EnemyType)17, new Color(0.78f, 0.66f, 0.6f) }, { (EnemyType)30, new Color(0.78f, 0.66f, 0.6f) }, { (EnemyType)26, new Color(0.7f, 0.74f, 0.78f) }, { (EnemyType)27, new Color(0.35f, 0.45f, 0.55f) }, { (EnemyType)32, new Color(0.5f, 0.5f, 0.52f) }, { (EnemyType)38, new Color(0.9f, 0.78f, 0.35f) }, { (EnemyType)41, new Color(0.22f, 0.22f, 0.26f) } }; public static Color? LastEnemyColor { get; private set; } public static void NoteEnemy(Bloodsplatter splatter, EnemyIdentifier eid) { if (!((Object)(object)splatter == (Object)null)) { int instanceID = ((Object)splatter).GetInstanceID(); if ((Object)(object)eid != (Object)null) { BloodEnemies[instanceID] = eid; } else { BloodEnemies.Remove(instanceID); } } } public static void Register(Bloodsplatter splatter) { //IL_0046: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)splatter == (Object)null || !UltraBloodConfig.Enabled || !UltraBloodConfig.RecolorSplatters) { return; } GameObject gameObject = ((Component)splatter).gameObject; if ((Object)(object)gameObject == (Object)null || IsExcludedVariant(splatter.bloodSplatterType)) { return; } Color? enemyColor = EnemyColorFor(splatter); HashSet visited = new HashSet(); RegisterHierarchy(gameObject, visited, enemyColor); Plugin.RunDelayed(gameObject, delegate { if (!((Object)(object)splatter == (Object)null) && !((Object)(object)((Component)splatter).gameObject == (Object)null)) { HashSet visited2 = new HashSet(); RegisterHierarchy(((Component)splatter).gameObject, visited2, EnemyColorFor(splatter)); } }); } public static void ReapplyAll() { Prune(); bool flag = UltraBloodConfig.Enabled && UltraBloodConfig.RecolorSplatters; foreach (Snapshot value in Snapshots.Values) { if (!((Object)(object)value.System == (Object)null)) { if (flag) { ApplyColor(value); } else { Restore(value); } } } } public static void RestoreAll() { foreach (Snapshot value in Snapshots.Values) { if ((Object)(object)value.System != (Object)null) { Restore(value); } } } private static void RegisterHierarchy(GameObject root, HashSet visited, Color? enemyColor) { ParticleSystem[] componentsInChildren = root.GetComponentsInChildren(true); if (componentsInChildren != null) { ParticleSystem[] array = componentsInChildren; for (int i = 0; i < array.Length; i++) { RegisterSystem(array[i], visited, root, enemyColor); } } } private static void RegisterSystem(ParticleSystem ps, HashSet visited, GameObject root, Color? enemyColor) { //IL_0056: 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_005c: 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) if ((Object)(object)ps == (Object)null || !visited.Add(((Object)ps).GetInstanceID())) { return; } int instanceID = ((Object)ps).GetInstanceID(); if (!Snapshots.TryGetValue(instanceID, out var value)) { value = Capture(ps); Snapshots[instanceID] = value; LogOnce(ps, root); } value.EnemyColor = enemyColor; ApplyColor(value); SubEmittersModule subEmitters = ps.subEmitters; int num = SafeSubEmitterCount(subEmitters); for (int i = 0; i < num; i++) { ParticleSystem val = SafeGetSubEmitter(subEmitters, i); if ((Object)(object)val != (Object)null) { RegisterSystem(val, visited, root, enemyColor); } } } private static Snapshot Capture(ParticleSystem ps) { //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_0019: 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_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_002d: 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_0043: 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) //IL_004e: 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_0064: 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_006f: 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_008f: 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_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00a1: Unknown result type (might be due to invalid IL or missing references) Snapshot snapshot = new Snapshot { System = ps, RainbowColor = RandomVividColor() }; MainModule main = ps.main; snapshot.StartColor = ((MainModule)(ref main)).startColor; ColorOverLifetimeModule colorOverLifetime = ps.colorOverLifetime; snapshot.LifetimeEnabled = ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled; snapshot.Lifetime = ((ColorOverLifetimeModule)(ref colorOverLifetime)).color; ColorBySpeedModule colorBySpeed = ps.colorBySpeed; snapshot.SpeedEnabled = ((ColorBySpeedModule)(ref colorBySpeed)).enabled; snapshot.Speed = ((ColorBySpeedModule)(ref colorBySpeed)).color; TrailModule trails = ps.trails; snapshot.TrailsEnabled = ((TrailModule)(ref trails)).enabled; if (((TrailModule)(ref trails)).enabled) { snapshot.TrailLifetime = ((TrailModule)(ref trails)).colorOverLifetime; snapshot.TrailOverTrail = ((TrailModule)(ref trails)).colorOverTrail; } ParticleSystemRenderer component = ((Component)ps).GetComponent(); if ((Object)(object)component != (Object)null) { snapshot.Renderer = component; snapshot.OriginalMaterial = ((Renderer)component).sharedMaterial; snapshot.TintProperty = FindRedDominantTintProperty(((Renderer)component).sharedMaterial); } return snapshot; } private static void ApplyColor(Snapshot snap) { //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_0019: 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_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_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_0040: 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_0049: 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_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_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_006d: 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_0085: 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_008f: 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_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_00a3: 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_0129: Unknown result type (might be due to invalid IL or missing references) //IL_0146: Unknown result type (might be due to invalid IL or missing references) //IL_014d: 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) ParticleSystem system = snap.System; if ((Object)(object)system == (Object)null) { return; } Color target = TargetFor(snap); MainModule main = system.main; ((MainModule)(ref main)).startColor = Recolor(snap.StartColor, target); if (snap.LifetimeEnabled) { ColorOverLifetimeModule colorOverLifetime = system.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = Recolor(snap.Lifetime, target); } if (snap.SpeedEnabled) { ColorBySpeedModule colorBySpeed = system.colorBySpeed; ((ColorBySpeedModule)(ref colorBySpeed)).color = Recolor(snap.Speed, target); } if (snap.TrailsEnabled) { TrailModule trails = system.trails; ((TrailModule)(ref trails)).colorOverLifetime = Recolor(snap.TrailLifetime, target); ((TrailModule)(ref trails)).colorOverTrail = Recolor(snap.TrailOverTrail, target); } if ((Object)(object)snap.Renderer != (Object)null && snap.TintProperty != null) { EnsurePrivateMaterial(snap); if ((Object)(object)snap.PrivateMaterial != (Object)null && snap.PrivateMaterial.HasProperty(snap.TintProperty)) { Color val = (((Object)(object)snap.OriginalMaterial != (Object)null && snap.OriginalMaterial.HasProperty(snap.TintProperty)) ? snap.OriginalMaterial.GetColor(snap.TintProperty) : Color.white); snap.PrivateMaterial.SetColor(snap.TintProperty, new Color(1f, 1f, 1f, val.a)); } } } private static void Restore(Snapshot snap) { //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_001b: 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_0033: 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_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_0053: 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_0070: 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) ParticleSystem system = snap.System; if (!((Object)(object)system == (Object)null)) { MainModule main = system.main; ((MainModule)(ref main)).startColor = snap.StartColor; if (snap.LifetimeEnabled) { ColorOverLifetimeModule colorOverLifetime = system.colorOverLifetime; ((ColorOverLifetimeModule)(ref colorOverLifetime)).color = snap.Lifetime; } if (snap.SpeedEnabled) { ColorBySpeedModule colorBySpeed = system.colorBySpeed; ((ColorBySpeedModule)(ref colorBySpeed)).color = snap.Speed; } if (snap.TrailsEnabled) { TrailModule trails = system.trails; ((TrailModule)(ref trails)).colorOverLifetime = snap.TrailLifetime; ((TrailModule)(ref trails)).colorOverTrail = snap.TrailOverTrail; } if ((Object)(object)snap.Renderer != (Object)null && (Object)(object)snap.OriginalMaterial != (Object)null) { ((Renderer)snap.Renderer).sharedMaterial = snap.OriginalMaterial; } } } private static void EnsurePrivateMaterial(Snapshot snap) { //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_0057: Expected O, but got Unknown if (!((Object)(object)snap.PrivateMaterial != (Object)null) && !((Object)(object)snap.Renderer == (Object)null) && !((Object)(object)snap.OriginalMaterial == (Object)null)) { snap.PrivateMaterial = new Material(snap.OriginalMaterial) { name = ((Object)snap.OriginalMaterial).name + " (UltraBlood)" }; ((Renderer)snap.Renderer).sharedMaterial = snap.PrivateMaterial; } } private static Color TargetFor(Snapshot snap) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0040: 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_002c: 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 (UltraBloodConfig.SolidCyanParticles) { return Color.cyan; } if (UltraBloodConfig.EnemyBloodColorMatch) { return (Color)(((??)snap.EnemyColor) ?? OpaqueBloodColor()); } if (UltraBloodConfig.RainbowBlood) { return snap.RainbowColor; } return OpaqueBloodColor(); } private static Color OpaqueBloodColor() { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0005: 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_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_001d: Unknown result type (might be due to invalid IL or missing references) Color bloodColor = UltraBloodConfig.BloodColor; return new Color(bloodColor.r, bloodColor.g, bloodColor.b, 1f); } private static Color? EnemyColorFor(Bloodsplatter splatter) { //IL_0048: 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 (!UltraBloodConfig.EnemyBloodColorMatch) { return null; } if (BloodEnemies.TryGetValue(((Object)splatter).GetInstanceID(), out var value) && (Object)(object)value != (Object)null) { Color? val = SampleEnemyColor(value); LastEnemyColor = (Color)(((??)val) ?? OpaqueBloodColor()); return val; } return null; } private static Color? SampleEnemyColor(EnemyIdentifier eid) { //IL_0016: 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) int instanceID = ((Object)eid).GetInstanceID(); if (EnemyColors.TryGetValue(instanceID, out var value)) { return value; } Color? result = ComputeEnemyColor(eid); if (result.HasValue) { EnemyColors[instanceID] = result.Value; } return result; } private static Color? ComputeEnemyColor(EnemyIdentifier eid) { //IL_0006: 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_001a: 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_002b: Unknown result type (might be due to invalid IL or missing references) try { if (EnemyPalette.TryGetValue(eid.enemyType, out var value)) { return new Color(value.r, value.g, value.b, 1f); } } catch { } return null; } private static Color RandomVividColor() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) return Color.HSVToRGB(Random.value, Random.Range(0.7f, 1f), Random.Range(0.85f, 1f)); } private static MinMaxGradient Recolor(MinMaxGradient original, Color target) { //IL_0002: 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_0008: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected I4, but got Unknown //IL_0029: 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_0034: 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) //IL_0067: 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) //IL_0042: 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_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: 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_0081: 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_0096: 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_00ab: Unknown result type (might be due to invalid IL or missing references) ParticleSystemGradientMode mode = ((MinMaxGradient)(ref original)).mode; switch ((int)mode) { case 0: return new MinMaxGradient(RecolorSourceColor(((MinMaxGradient)(ref original)).color, target)); case 2: return new MinMaxGradient(RecolorSourceColor(((MinMaxGradient)(ref original)).colorMin, target), RecolorSourceColor(((MinMaxGradient)(ref original)).colorMax, target)); case 1: return new MinMaxGradient(RecolorGradientObject(((MinMaxGradient)(ref original)).gradient, target)); case 3: return new MinMaxGradient(RecolorGradientObject(((MinMaxGradient)(ref original)).gradientMin, target), RecolorGradientObject(((MinMaxGradient)(ref original)).gradientMax, target)); case 4: { MinMaxGradient result = default(MinMaxGradient); ((MinMaxGradient)(ref result))..ctor(RecolorGradientObject(((MinMaxGradient)(ref original)).gradient, target)); ((MinMaxGradient)(ref result)).mode = (ParticleSystemGradientMode)4; return result; } default: return original; } } private static Gradient RecolorGradientObject(Gradient source, Color target) { //IL_001e: 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_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_003d: 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_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown if (source == null) { return null; } GradientColorKey[] colorKeys = source.colorKeys; for (int i = 0; i < colorKeys.Length; i++) { colorKeys[i].color = RecolorSourceColor(colorKeys[i].color, target); } Gradient val = new Gradient(); val.SetKeys(colorKeys, source.alphaKeys); val.mode = source.mode; return val; } private static Color RecolorSourceColor(Color source, Color target) { //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_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_0025: 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_0035: 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) float num = Mathf.Max(source.r, Mathf.Max(source.g, source.b)); return new Color(target.r * num, target.g * num, target.b * num, source.a); } private static bool IsExcludedVariant(BSType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0002: Invalid comparison between Unknown and I4 //IL_0004: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Invalid comparison between Unknown and I4 //IL_0008: Unknown result type (might be due to invalid IL or missing references) //IL_000a: Invalid comparison between Unknown and I4 if ((int)type != 7 && (int)type != 8) { return (int)type == 6; } return true; } private static string FindRedDominantTintProperty(Material material) { //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: 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_0037: 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_004b: 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) if ((Object)(object)material == (Object)null) { return null; } string[] tintProperties = TintProperties; foreach (string text in tintProperties) { if (material.HasProperty(text)) { Color color = material.GetColor(text); if (color.r > 0.25f && color.r > color.g * 1.5f && color.r > color.b * 1.5f) { return text; } } } return null; } private static void Prune() { if (Snapshots.Count == 0) { return; } List list = new List(); foreach (KeyValuePair snapshot in Snapshots) { if ((Object)(object)snapshot.Value.System == (Object)null) { list.Add(snapshot.Key); } } foreach (int item in list) { Snapshots.Remove(item); } } private static void LogOnce(ParticleSystem ps, GameObject root) { //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_00b1: 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_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_00c1: 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_011d: 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_0126: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0184: Unknown result type (might be due to invalid IL or missing references) if (UltraBloodConfig.DebugLogging) { ParticleSystemRenderer component = ((Component)ps).GetComponent(); Material val = (((Object)(object)component != (Object)null) ? ((Renderer)component).sharedMaterial : null); Shader val2 = (((Object)(object)val != (Object)null) ? val.shader : null); MainModule main = ps.main; string text = HierarchyPath(((Component)ps).transform, root.transform); string item = string.Join("|", ((Object)root).name, text, ((Object)(object)val != (Object)null) ? ((Object)val).name : "no-mat", ((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "no-shader"); if (LoggedFingerprints.Add(item)) { ColorOverLifetimeModule colorOverLifetime = ps.colorOverLifetime; ColorBySpeedModule colorBySpeed = ps.colorBySpeed; TrailModule trails = ps.trails; ManualLogSource log = Plugin.Log; string[] obj = new string[11] { $"[particles] root='{((Object)root).name}' path='{text}' ps='{((Object)ps).name}' id={((Object)ps).GetInstanceID()} ", null, null, null, null, null, null, null, null, null, null }; object[] array = new object[4]; MinMaxGradient startColor = ((MainModule)(ref main)).startColor; array[0] = ((MinMaxGradient)(ref startColor)).mode; array[1] = ((ColorOverLifetimeModule)(ref colorOverLifetime)).enabled; array[2] = ((ColorBySpeedModule)(ref colorBySpeed)).enabled; array[3] = ((TrailModule)(ref trails)).enabled; obj[1] = string.Format("startMode={0} colorOverLifetime={1} colorBySpeed={2} trails={3} ", array); obj[2] = "renderMode="; obj[3] = (((Object)(object)component != (Object)null) ? ((object)component.renderMode/*cast due to .constrained prefix*/).ToString() : "n/a"); obj[4] = " material='"; obj[5] = (((Object)(object)val != (Object)null) ? ((Object)val).name : "null"); obj[6] = "' shader='"; obj[7] = (((Object)(object)val2 != (Object)null) ? ((Object)val2).name : "null"); obj[8] = "' redTintProperty='"; obj[9] = FindRedDominantTintProperty(val) ?? "none"; obj[10] = "'"; log.LogInfo((object)string.Concat(obj)); } } } private static string HierarchyPath(Transform node, Transform root) { if ((Object)(object)node == (Object)(object)root || (Object)(object)node == (Object)null) { if (!((Object)(object)node != (Object)null)) { return "?"; } return ((Object)node).name; } List list = new List(); Transform val = node; int num = 0; while ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)root && num++ < 32) { list.Insert(0, ((Object)val).name); val = val.parent; } list.Insert(0, ((Object)root).name); return string.Join("/", list); } private static int SafeSubEmitterCount(SubEmittersModule sub) { try { return ((SubEmittersModule)(ref sub)).enabled ? ((SubEmittersModule)(ref sub)).subEmittersCount : 0; } catch { return 0; } } private static ParticleSystem SafeGetSubEmitter(SubEmittersModule sub, int index) { try { return ((SubEmittersModule)(ref sub)).GetSubEmitterSystem(index); } catch { return null; } } } [HarmonyPatch] internal static class BloodPatches { [HarmonyPatch(typeof(BloodsplatterManager), "Start")] [HarmonyPostfix] private static void BloodsplatterManager_Start_Postfix(BloodsplatterManager __instance) { try { BloodColorController.ApplyToStainMaterials(__instance); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to recolor bloodstain materials: " + ex.GetType().Name + ": " + ex.Message)); } } [HarmonyPatch(typeof(Bloodsplatter), "OnEnable")] [HarmonyPrefix] private static void Bloodsplatter_OnEnable_Prefix(Bloodsplatter __instance) { try { BloodParticles.Register(__instance); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Failed to recolor blood splatter: " + ex.GetType().Name + ": " + ex.Message)); } } [HarmonyPatch(/*Could not decode attribute arguments.*/)] [HarmonyPostfix] private static void Bloodsplatter_set_eid_Postfix(Bloodsplatter __instance, EnemyIdentifier value) { try { BloodParticles.NoteEnemy(__instance, value); } catch (Exception) { } } [HarmonyPatch(typeof(PostProcessV2_Handler), "OnPreRenderCallback")] [HarmonyPostfix] private static void PostProcessV2_Handler_OnPreRenderCallback_Postfix() { try { BloodColorController.NoteCompositeRenderPass(); } catch (Exception) { } } } internal enum BundleCompatibilityResult { NotAttempted, FileMissing, Loaded, LoadReturnedNull, LoadThrew, AlreadyLoaded } internal static class CompatibilityTest { private struct BundleRow { public string Name; public string Path; public bool IsSbp; public bool IsGame; public bool FileExists; public long Length; public string Sha256; public BundleCompatibilityResult Result; public string[] AssetNames; public bool TextLoaded; public string ShaderName; public bool ShaderSupported; public int PassCount; public string UnityError; } private const string TestsFolderName = "CompatibilityTests"; private const string CompositeShaderName = "UltraBlood/CompositeBloodTint"; private static bool _ran; private static ManualLogSource _log; public static string Summary { get; private set; } = "not run"; public static bool AnySbpLoaded { get; private set; } public static bool SbpCompositeShaderValid { get; private set; } public static void RunOnce(ManualLogSource logger, string pluginDirectory) { if (!_ran) { _ran = true; _log = logger ?? Plugin.Log; _log.LogInfo((object)"[compat] CompatibilityTest entry reached."); try { Run(pluginDirectory); } catch (Exception ex) { Summary = "error: " + ex.GetType().Name; _log.LogError((object)("[compat] compatibility test crashed: " + ex)); } UltraBloodConfig.SetCompatStatus("Compatibility: " + Summary, AnySbpLoaded); } } private static void Run(string pluginDirectory) { string text = SafeAssemblyLocation(); string text2 = ((!string.IsNullOrEmpty(pluginDirectory)) ? pluginDirectory : SafeDirectoryName(text)); string text3 = (string.IsNullOrEmpty(text2) ? null : Path.Combine(text2, "CompatibilityTests")); _log.LogInfo((object)("[compat] current working directory: " + SafeCwd())); _log.LogInfo((object)("[compat] plugin assembly location: " + (text ?? ""))); _log.LogInfo((object)("[compat] plugin directory: " + (text2 ?? ""))); _log.LogInfo((object)("[compat] expected CompatibilityTests directory: " + (text3 ?? ""))); if (text3 == null) { Summary = "plugin directory could not be resolved"; _log.LogWarning((object)"[compat] plugin directory could not be resolved; matrix not run"); return; } bool flag = Directory.Exists(text3); _log.LogInfo((object)("[compat] directory exists: " + flag)); if (!flag) { Summary = "CompatibilityTests directory missing"; _log.LogWarning((object)("[compat] CompatibilityTests directory missing: " + text3)); return; } string[] array = Directory.GetFiles(text3, "*.bundle", SearchOption.TopDirectoryOnly).OrderBy(Path.GetFileName, StringComparer.OrdinalIgnoreCase).ToArray(); _log.LogInfo((object)("[compat] number of files found: " + array.Length)); string[] array2 = array; foreach (string path in array2) { _log.LogInfo((object)("[compat] discovered: " + Path.GetFileName(path))); } List list = new List(); try { array2 = array; foreach (string path2 in array2) { list.Add(TestBundle(Path.GetFileName(path2), path2, isGame: false, unloadAllLoadedObjects: true)); } BundleRow? bundleRow = TryGameControlRow(); if (bundleRow.HasValue) { list.Add(bundleRow.Value); } } finally { PrintTable(list); } int legacyTotal = list.Count((BundleRow r) => !r.IsSbp && !r.IsGame); int legacyLoaded = list.Count((BundleRow r) => !r.IsSbp && !r.IsGame && r.Result == BundleCompatibilityResult.Loaded); int sbpTotal = list.Count((BundleRow r) => r.IsSbp); int num = list.Count((BundleRow r) => r.IsSbp && r.Result == BundleCompatibilityResult.Loaded); AnySbpLoaded = num > 0; SbpCompositeShaderValid = list.Any((BundleRow r) => r.IsSbp && r.ShaderName == "UltraBlood/CompositeBloodTint" && r.ShaderSupported && r.PassCount >= 2); LogResidentBundles(); Summary = BuildSummary(legacyLoaded, legacyTotal, num, sbpTotal); _log.LogInfo((object)("[compat] summary: " + Summary)); } private static string BuildSummary(int legacyLoaded, int legacyTotal, int sbpLoaded, int sbpTotal) { string text = $"legacy {legacyLoaded}/{legacyTotal} loaded"; string text2 = $"SBP {sbpLoaded}/{sbpTotal} loaded"; string text3 = (SbpCompositeShaderValid ? "SBP composite shader valid (passes>=2)" : (AnySbpLoaded ? "SBP composite shader NOT validated" : "no SBP bundle loaded")); return text + ", " + text2 + ", " + text3; } private static BundleRow? TryGameControlRow() { try { string path = Path.Combine(Application.dataPath, "StreamingAssets", "aa", "StandaloneWindows64"); if (!Directory.Exists(path)) { _log.LogInfo((object)"[compat] game bundle control: Addressables folder not found, skipped"); return null; } string text = (from f in Directory.GetFiles(path, "*.bundle", SearchOption.AllDirectories) orderby new FileInfo(f).Length select f).FirstOrDefault(); if (text == null) { _log.LogInfo((object)"[compat] game bundle control: no game *.bundle found, skipped"); return null; } return TestBundle("GAME:" + Path.GetFileName(text), text, isGame: true, unloadAllLoadedObjects: false); } catch (Exception ex) { _log.LogWarning((object)("[compat] game bundle control failed: " + ex.Message)); return null; } } private static BundleRow TestBundle(string label, string path, bool isGame, bool unloadAllLoadedObjects) { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00bf: Expected O, but got Unknown BundleRow bundleRow = new BundleRow { Name = label, Path = path, IsGame = isGame, IsSbp = label.StartsWith("sbp-", StringComparison.OrdinalIgnoreCase), Result = BundleCompatibilityResult.NotAttempted, Sha256 = "n/a", ShaderName = "-", PassCount = -1 }; bundleRow.FileExists = File.Exists(path); if (!bundleRow.FileExists) { bundleRow.Result = BundleCompatibilityResult.FileMissing; LogRowDetail(bundleRow); return bundleRow; } bundleRow.Length = new FileInfo(path).Length; if (!isGame) { bundleRow.Sha256 = Sha256File(path); } string captured = null; LogCallback val = (LogCallback)delegate(string condition, string stackTrace, LogType type) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) //IL_0003: Unknown result type (might be due to invalid IL or missing references) //IL_0005: Invalid comparison between Unknown and I4 if (((int)type == 0 || (int)type == 4) && condition != null && condition.IndexOf("AssetBundle", StringComparison.OrdinalIgnoreCase) >= 0) { captured = condition.Trim(); } }; AssetBundle val2 = null; Application.logMessageReceived += val; try { val2 = AssetBundle.LoadFromFile(path); } catch (Exception ex) { bundleRow.UnityError = ex.Message.Trim(); bundleRow.Result = ((ex.Message.IndexOf("already loaded", StringComparison.OrdinalIgnoreCase) >= 0) ? BundleCompatibilityResult.AlreadyLoaded : BundleCompatibilityResult.LoadThrew); LogRowDetail(bundleRow); return bundleRow; } finally { Application.logMessageReceived -= val; } if ((Object)(object)val2 == (Object)null) { bundleRow.Result = BundleCompatibilityResult.LoadReturnedNull; bundleRow.UnityError = captured; LogRowDetail(bundleRow); return bundleRow; } bundleRow.Result = BundleCompatibilityResult.Loaded; try { bundleRow.AssetNames = val2.GetAllAssetNames(); TextAsset[] array = val2.LoadAllAssets(); bundleRow.TextLoaded = array != null && array.Length != 0; Shader val3 = val2.LoadAsset("UltraBlood/CompositeBloodTint"); if ((Object)(object)val3 == (Object)null) { Shader[] array2 = val2.LoadAllAssets(); val3 = ((array2 != null && array2.Length != 0) ? array2[0] : null); } if ((Object)(object)val3 != (Object)null) { bundleRow.ShaderName = ((Object)val3).name; bundleRow.ShaderSupported = val3.isSupported; bundleRow.PassCount = val3.passCount; } } catch (Exception ex2) { _log.LogWarning((object)("[compat] " + label + " inspection failed: " + ex2.GetType().Name + ": " + ex2.Message)); } val2.Unload(unloadAllLoadedObjects); LogRowDetail(bundleRow); return bundleRow; } private static void LogRowDetail(BundleRow row) { string arg = ((row.AssetNames != null) ? string.Join(", ", row.AssetNames) : "-"); _log.LogInfo((object)($"[compat] {row.Name}: exists={row.FileExists} length={row.Length} sha256={row.Sha256} " + $"result={row.Result} assets=[{arg}] text={YesNo(row.TextLoaded, row.Result)} " + "shader='" + row.ShaderName + "' supported=" + SupportedText(row) + " passes=" + PassText(row) + (string.IsNullOrEmpty(row.UnityError) ? string.Empty : (" error='" + row.UnityError + "'")))); } private static void PrintTable(List rows) { _log.LogInfo((object)"[compat] === matrix ==="); _log.LogInfo((object)string.Format("[compat] {0,-38} {1,-17} {2,-5} {3,-32} {4,-9} {5}", "Bundle", "Load", "Text", "Shader", "Supported", "Passes")); foreach (BundleRow row in rows) { _log.LogInfo((object)$"[compat] {Trim(row.Name, 38),-38} {row.Result,-17} {YesNo(row.TextLoaded, row.Result),-5} {Trim(row.ShaderName, 32),-32} {SupportedText(row),-9} {PassText(row)}"); } _log.LogInfo((object)"[compat] === end matrix ==="); } private static void LogResidentBundles() { try { AssetBundle[] array = AssetBundle.GetAllLoadedAssetBundles().ToArray(); _log.LogInfo((object)$"[compat] GetAllLoadedAssetBundles(): {array.Length} resident"); foreach (AssetBundle item in array.Take(12)) { _log.LogInfo((object)("[compat] resident: " + SafeName(item))); } if (array.Length > 12) { _log.LogInfo((object)$"[compat] ... and {array.Length - 12} more"); } } catch (Exception ex) { _log.LogWarning((object)("[compat] GetAllLoadedAssetBundles failed: " + ex.Message)); } } private static string YesNo(bool value, BundleCompatibilityResult result) { if (result != BundleCompatibilityResult.Loaded) { return "-"; } if (!value) { return "N"; } return "Y"; } private static string SupportedText(BundleRow row) { if (row.Result != BundleCompatibilityResult.Loaded || row.PassCount < 0) { return "-"; } if (!row.ShaderSupported) { return "N"; } return "Y"; } private static string PassText(BundleRow row) { if (row.Result != BundleCompatibilityResult.Loaded || row.PassCount < 0) { return "-"; } return row.PassCount.ToString(); } private static string Trim(string value, int max) { if (string.IsNullOrEmpty(value)) { return string.Empty; } if (value.Length > max) { return value.Substring(0, max - 1) + "~"; } return value; } private static string SafeName(AssetBundle bundle) { try { return ((Object)(object)bundle != (Object)null) ? ((Object)bundle).name : ""; } catch { return ""; } } private static string SafeCwd() { try { return Directory.GetCurrentDirectory(); } catch { return ""; } } private static string SafeAssemblyLocation() { try { return Assembly.GetExecutingAssembly().Location; } catch { return null; } } private static string SafeDirectoryName(string path) { try { return string.IsNullOrEmpty(path) ? null : Path.GetDirectoryName(path); } catch { return null; } } private static string Sha256File(string path) { try { using FileStream inputStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(inputStream); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("X2")); } return stringBuilder.ToString(); } catch { return "n/a"; } } } [BepInPlugin("ultrablood.kiyroprower.ultrakill", "UltraBlood", "0.2.1")] [BepInProcess("ULTRAKILL.exe")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "ultrablood.kiyroprower.ultrakill"; public const string Version = "0.2.1"; public const string PluginConfiguratorGuid = "com.eternalUnion.pluginConfigurator"; internal static ManualLogSource Log; internal static Plugin Instance; private Harmony _harmony; private void Awake() { //IL_0053: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; Instance = this; LogRuntimeEnvironment(); UltraBloodConfig.Initialize(((BaseUnityPlugin)this).Logger); string pluginDirectory = GetPluginDirectory(); try { CompatibilityTest.RunOnce(((BaseUnityPlugin)this).Logger, pluginDirectory); } catch (Exception arg) { Log.LogError((object)$"[compat] Compatibility test crashed: {arg}"); } _harmony = new Harmony("ultrablood.kiyroprower.ultrakill"); _harmony.PatchAll(typeof(BloodPatches)); Log.LogInfo((object)("UltraBlood loaded (ultrablood.kiyroprower.ultrakill). Recoloring is " + (UltraBloodConfig.Enabled ? "on" : "off") + ".")); } private static void LogRuntimeEnvironment() { //IL_0017: 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) Log.LogInfo((object)($"[runtime] Unity={Application.unityVersion}, Platform={Application.platform}, " + "Product=" + Application.productName + ", GameVersion=" + Application.version + ", " + $"ProcessBits={IntPtr.Size * 8}")); Log.LogInfo((object)($"[runtime] OS={SystemInfo.operatingSystem}, GraphicsAPI={SystemInfo.graphicsDeviceType}, " + "GPU=" + SystemInfo.graphicsDeviceName + ", GfxVersion=" + SystemInfo.graphicsDeviceVersion + ", " + $"ShaderLevel={SystemInfo.graphicsShaderLevel}, Instancing={SystemInfo.supportsInstancing}")); LogHostBinary(); } private static void LogHostBinary() { try { string text = Directory.GetParent(Application.dataPath)?.FullName; if (text != null) { string text2 = Path.Combine(text, "UnityPlayer.dll"); if (!File.Exists(text2)) { Log.LogInfo((object)"[runtime] UnityPlayer.dll not found next to the game"); return; } FileVersionInfo versionInfo = FileVersionInfo.GetVersionInfo(text2); string text3 = Sha256File(text2); Log.LogInfo((object)("[runtime] UnityPlayer.dll ProductVersion=" + versionInfo.ProductVersion + ", FileVersion=" + versionInfo.FileVersion + ", sha256=" + text3)); } } catch (Exception ex) { Log.LogWarning((object)("[runtime] UnityPlayer.dll inspection failed: " + ex.GetType().Name + ": " + ex.Message)); } } private static string Sha256File(string path) { using FileStream inputStream = new FileStream(path, FileMode.Open, FileAccess.Read, FileShare.ReadWrite | FileShare.Delete); using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(inputStream); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("X2")); } return stringBuilder.ToString(); } private static string GetPluginDirectory() { try { return Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } catch { return null; } } internal static void RunDelayed(GameObject target, Action action) { if (!((Object)(object)Instance == (Object)null) && !((Object)(object)target == (Object)null) && action != null) { ((MonoBehaviour)Instance).StartCoroutine(DelayedRoutine(target, action)); } } private static IEnumerator DelayedRoutine(GameObject target, Action action) { yield return null; yield return (object)new WaitForSeconds(0.1f); if ((Object)(object)target == (Object)null) { yield break; } try { action(); } catch (Exception ex) { Log.LogWarning((object)("[particles] delayed rescan failed: " + ex.GetType().Name + ": " + ex.Message)); } } private void Update() { if (UltraBloodConfig.Enabled && UltraBloodConfig.RecolorPuddles && !UltraBloodConfig.SolidCyanTest && (UltraBloodConfig.RainbowBlood || UltraBloodConfig.EnemyBloodColorMatch)) { BloodColorController.TickDynamicColor(); } } private void OnDestroy() { BloodColorController.RestoreStainMaterials(); BloodParticles.RestoreAll(); Harmony harmony = _harmony; if (harmony != null) { harmony.UnpatchSelf(); } } } internal enum BundleStatus { NotAttempted, Loaded, EmbeddedBundleResourceMissing, MultipleEmbeddedBundlesFound, BundleLoadFailed, ShaderNotFound, ShaderUnsupported, ShaderPassCountInvalid } internal static class ShaderBundle { private const string BundleResourceName = "UltraBlood.Resources.ultrablood-sbp.bundle"; private const string ManifestResourceName = "UltraBlood.Resources.ultrablood-sbp.manifest.json"; private const string ShaderName = "UltraBlood/CompositeBloodTint"; private const string ProbeAssetName = "UltraBloodBundleProbe"; private const string CompatibilityTestsFolder = "CompatibilityTests"; private const string ExternalCompositeBundleName = "sbp-probe-composite.bundle"; private const string RuntimeBundleFileName = "ultrablood-sbp.runtime.bundle"; private static bool _attempted; private static AssetBundle _bundle; private static Shader _compositeShader; public static BundleStatus Status { get; private set; } = BundleStatus.NotAttempted; public static string StatusMessage { get; private set; } = "not attempted"; public static string Source { get; private set; } = "none"; public static Shader CompositeShader { get { if (!_attempted) { _attempted = true; try { Load(); } catch (Exception ex) { Fail(BundleStatus.BundleLoadFailed, "exception: " + ex.GetType().Name + ": " + ex.Message); Plugin.Log.LogError((object)("[bundle] " + ex)); } } return _compositeShader; } } private static void Load() { //IL_0231: Unknown result type (might be due to invalid IL or missing references) Assembly executingAssembly = Assembly.GetExecutingAssembly(); Plugin.Log.LogInfo((object)("[bundle] assembly='" + executingAssembly.GetName().Name + "' location='" + executingAssembly.Location + "'")); string[] array = (from n in executingAssembly.GetManifestResourceNames() where n.IndexOf("ultrablood", StringComparison.OrdinalIgnoreCase) >= 0 && n.EndsWith(".bundle", StringComparison.OrdinalIgnoreCase) select n).ToArray(); string[] array2 = array; foreach (string text in array2) { Plugin.Log.LogInfo((object)("[bundle] embedded bundle resource: " + text)); } if (array.Length == 0) { Fail(BundleStatus.EmbeddedBundleResourceMissing, "no embedded *.bundle resource found"); return; } if (array.Length > 1) { Fail(BundleStatus.MultipleEmbeddedBundlesFound, "multiple embedded bundle resources: " + string.Join(", ", array)); return; } byte[] array3 = ReadResource(executingAssembly, "UltraBlood.Resources.ultrablood-sbp.bundle"); if (array3 == null) { Fail(BundleStatus.EmbeddedBundleResourceMissing, "bundle resource stream missing: UltraBlood.Resources.ultrablood-sbp.bundle"); return; } string text2 = Sha256Hex(array3); string arg = Encoding.ASCII.GetString(array3, 0, Math.Min(24, array3.Length)).Replace("\0", "."); Plugin.Log.LogInfo((object)$"[bundle] embedded bytes={array3.Length} sha256={text2} header='{arg}'"); LogManifest(executingAssembly, array3.Length, text2); _bundle = LoadBundle(array3); if ((Object)(object)_bundle == (Object)null) { Fail(BundleStatus.BundleLoadFailed, "all load methods returned null"); return; } string[] allAssetNames = _bundle.GetAllAssetNames(); Plugin.Log.LogInfo((object)("[bundle] contains assets: " + string.Join(", ", allAssetNames))); TextAsset val = LoadFirst(_bundle, "UltraBloodBundleProbe"); Plugin.Log.LogInfo((object)(((Object)(object)val != (Object)null) ? ("[bundle] probe TextAsset loaded: \"" + val.text.Trim() + "\"") : "[bundle] probe TextAsset not found")); _compositeShader = LoadFirst(_bundle, "UltraBlood/CompositeBloodTint"); if ((Object)(object)_compositeShader == (Object)null) { Fail(BundleStatus.ShaderNotFound, "composite shader not found in bundle"); return; } if (!_compositeShader.isSupported) { Fail(BundleStatus.ShaderUnsupported, $"shader '{((Object)_compositeShader).name}' is not supported on {SystemInfo.graphicsDeviceType}"); return; } if (_compositeShader.passCount <= 1) { Fail(BundleStatus.ShaderPassCountInvalid, $"shader '{((Object)_compositeShader).name}' has passCount={_compositeShader.passCount}; the composite draws pass index 1"); return; } Status = BundleStatus.Loaded; StatusMessage = "loaded from " + Source; Plugin.Log.LogInfo((object)$"[bundle] shader '{((Object)_compositeShader).name}' loaded from {Source}, supported=true, passCount={_compositeShader.passCount}"); } private static AssetBundle LoadBundle(byte[] bytes) { string text = null; try { text = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location); } catch { } if (text != null) { string text2 = Path.Combine(text, "CompatibilityTests", "sbp-probe-composite.bundle"); if (File.Exists(text2)) { try { byte[] array = File.ReadAllBytes(text2); Plugin.Log.LogInfo((object)$"[bundle] external SBP bundle '{text2}' bytes={array.Length} sha256={Sha256Hex(array)}"); AssetBundle val = AssetBundle.LoadFromFile(text2); Plugin.Log.LogInfo((object)("[bundle] external SBP LoadFromFile result: " + (((Object)(object)val != (Object)null) ? "loaded" : "null"))); if ((Object)(object)val != (Object)null) { Source = "external:sbp-probe-composite.bundle"; return val; } } catch (Exception ex) { Plugin.Log.LogWarning((object)("[bundle] external SBP load failed: " + ex.GetType().Name + ": " + ex.Message)); } } } if (text != null) { try { string text3 = Path.Combine(text, "ultrablood-sbp.runtime.bundle"); File.WriteAllBytes(text3, bytes); AssetBundle val2 = AssetBundle.LoadFromFile(text3); Plugin.Log.LogInfo((object)("[bundle] embedded SBP ->file LoadFromFile result: " + (((Object)(object)val2 != (Object)null) ? "loaded" : "null"))); if ((Object)(object)val2 != (Object)null) { Source = "embedded-file"; return val2; } } catch (Exception ex2) { Plugin.Log.LogWarning((object)("[bundle] embedded->file load failed: " + ex2.GetType().Name + ": " + ex2.Message)); } } AssetBundle val3 = AssetBundle.LoadFromMemory(bytes); Plugin.Log.LogInfo((object)("[bundle] embedded SBP LoadFromMemory result: " + (((Object)(object)val3 != (Object)null) ? "loaded" : "null"))); if ((Object)(object)val3 != (Object)null) { Source = "embedded-memory"; } return val3; } private static T LoadFirst(AssetBundle bundle, string preferredName) where T : Object { T val = bundle.LoadAsset(preferredName); if ((Object)(object)val != (Object)null) { return val; } T[] array = bundle.LoadAllAssets(); if (array == null || array.Length == 0) { return default(T); } return array[0]; } private static void LogManifest(Assembly assembly, int actualLength, string actualHash) { byte[] array = ReadResource(assembly, "UltraBlood.Resources.ultrablood-sbp.manifest.json"); if (array == null) { Plugin.Log.LogWarning((object)"[bundle] embedded manifest missing: UltraBlood.Resources.ultrablood-sbp.manifest.json"); return; } string text = Encoding.UTF8.GetString(array); Plugin.Log.LogInfo((object)("[bundle] build manifest: " + text.Replace("\r", string.Empty).Replace("\n", " "))); string text2 = ExtractJsonString(text, "sha256"); if (!string.IsNullOrEmpty(text2)) { bool flag = string.Equals(text2, actualHash, StringComparison.OrdinalIgnoreCase); Plugin.Log.LogInfo((object)("[bundle] manifest sha256 " + (flag ? "matches" : "DOES NOT MATCH") + " embedded bytes (manifest=" + text2 + ", actual=" + actualHash + ")")); } string text3 = ExtractJsonString(text, "unityEditorVersion"); if (!string.IsNullOrEmpty(text3)) { Plugin.Log.LogInfo((object)("[bundle] built with Unity " + text3 + "; runtime is Unity " + Application.unityVersion)); } } private static string ExtractJsonString(string json, string key) { Match match = Regex.Match(json, "\"" + Regex.Escape(key) + "\"\\s*:\\s*\"([^\"]*)\""); if (!match.Success) { return null; } return match.Groups[1].Value; } private static byte[] ReadResource(Assembly assembly, string name) { using Stream stream = assembly.GetManifestResourceStream(name); if (stream == null) { return null; } using MemoryStream memoryStream = new MemoryStream(); stream.CopyTo(memoryStream); return memoryStream.ToArray(); } private static string Sha256Hex(byte[] data) { using SHA256 sHA = SHA256.Create(); byte[] array = sHA.ComputeHash(data); StringBuilder stringBuilder = new StringBuilder(array.Length * 2); byte[] array2 = array; foreach (byte b in array2) { stringBuilder.Append(b.ToString("X2")); } return stringBuilder.ToString(); } private static void Fail(BundleStatus status, string message) { Status = status; StatusMessage = message; Plugin.Log.LogError((object)$"[bundle] {status}: {message}"); } } internal static class UltraBloodConfig { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static PostBoolValueChangeEvent <>9__39_0; public static PostColorValueChangeEvent <>9__39_1; public static PostBoolValueChangeEvent <>9__39_2; public static PostBoolValueChangeEvent <>9__39_3; public static PostBoolValueChangeEvent <>9__39_4; public static PostBoolValueChangeEvent <>9__39_5; public static PostFloatValueChangeEvent <>9__39_6; public static PostBoolValueChangeEvent <>9__39_7; public static PostBoolValueChangeEvent <>9__39_8; public static PostBoolValueChangeEvent <>9__39_9; internal void b__39_0(bool _) { ScheduleReapply(); } internal void b__39_1(Color _) { ScheduleReapply(); } internal void b__39_2(bool _) { ScheduleReapply(); } internal void b__39_3(bool _) { ScheduleReapply(); } internal void b__39_4(bool _) { ScheduleReapply(); } internal void b__39_5(bool _) { ScheduleReapply(); } internal void b__39_6(float _) { ScheduleReapply(); } internal void b__39_7(bool _) { ScheduleReapply(); } internal void b__39_8(bool _) { ScheduleReapply(); } internal void b__39_9(bool _) { UpdateInteractivity(); } } public static readonly Color DefaultBloodColor = new Color(0.5f, 0f, 0f); public const float DefaultPuddleOpacity = 0.65f; private static PluginConfigurator _configurator; private static ManualLogSource _log; private static BoolField _enabledField; private static ColorField _bloodColorField; private static BoolField _rainbowField; private static BoolField _enemyMatchField; private static BoolField _recolorSplattersField; private static BoolField _recolorPuddlesField; private static FloatField _puddleOpacityField; private static BoolField _debugLoggingField; private static BoolField _solidCyanTestField; private static BoolField _solidCyanParticlesField; private static ConfigHeader _puddleStatusHeader; private static ConfigHeader _compatStatusHeader; private static bool _reconciling; private static readonly Color TitleColor = new Color(1f, 0.3f, 0.3f); private static readonly Color EnabledColor = new Color(0.86f, 0.4f, 0.4f); public static bool Enabled { get { if (_enabledField != null) { return _enabledField.value; } return true; } } public static Color BloodColor { get { //IL_0012: 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) if (_bloodColorField != null) { return _bloodColorField.value; } return DefaultBloodColor; } } public static bool RainbowBlood { get { if (_rainbowField != null) { return _rainbowField.value; } return false; } } public static bool EnemyBloodColorMatch { get { if (_enemyMatchField != null) { return _enemyMatchField.value; } return false; } } public static bool RecolorSplatters { get { if (_recolorSplattersField != null) { return _recolorSplattersField.value; } return true; } } public static bool RecolorPuddles { get { if (_recolorPuddlesField != null) { return _recolorPuddlesField.value; } return true; } } public static float PuddleOpacity { get { if (_puddleOpacityField != null) { return Mathf.Clamp01(_puddleOpacityField.value); } return 0.65f; } } public static bool DebugLogging { get { if (_debugLoggingField != null) { return _debugLoggingField.value; } return false; } } public static bool SolidCyanTest { get { if (_solidCyanTestField != null) { return _solidCyanTestField.value; } return false; } } public static bool SolidCyanParticles { get { if (_solidCyanParticlesField != null) { return _solidCyanParticlesField.value; } return false; } } public static void SetPuddleStatus(string text, bool ok) { //IL_0040: 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) if (_puddleStatusHeader != null) { _puddleStatusHeader.text = text; _puddleStatusHeader.textColor = (ok ? new Color(0.56f, 0.86f, 0.56f) : new Color(1f, 0.55f, 0f)); } } public static void SetCompatStatus(string text, bool ok) { //IL_0031: 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 (_compatStatusHeader != null) { _compatStatusHeader.text = text; _compatStatusHeader.textColor = (Color)(ok ? new Color(0.56f, 0.86f, 0.56f) : Color.gray); } } public static void Initialize(ManualLogSource log) { _log = log; try { CreateMenu(); _log.LogInfo((object)"Config menu initialized."); } catch (Exception ex) { _log.LogWarning((object)("PluginConfigurator menu could not be initialized: " + ex.GetType().Name + ": " + ex.Message)); } } private static void CreateMenu() { //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Expected O, but got Unknown //IL_006c: 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_0091: Expected O, but got Unknown //IL_0056: 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_0061: Expected O, but got Unknown //IL_00df: Unknown result type (might be due to invalid IL or missing references) //IL_00e9: Expected O, but got Unknown //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_00b5: Expected O, but got Unknown //IL_012b: Unknown result type (might be due to invalid IL or missing references) //IL_0135: Expected O, but got Unknown //IL_0102: 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_010d: Expected O, but got Unknown //IL_0183: Unknown result type (might be due to invalid IL or missing references) //IL_018d: Expected O, but got Unknown //IL_014e: Unknown result type (might be due to invalid IL or missing references) //IL_0153: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Expected O, but got Unknown //IL_01cf: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Expected O, but got Unknown //IL_01a6: Unknown result type (might be due to invalid IL or missing references) //IL_01ab: Unknown result type (might be due to invalid IL or missing references) //IL_01b1: Expected O, but got Unknown //IL_0228: Unknown result type (might be due to invalid IL or missing references) //IL_0232: Expected O, but got Unknown //IL_01f2: 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_01fd: Expected O, but got Unknown //IL_026d: 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) //IL_02aa: Unknown result type (might be due to invalid IL or missing references) //IL_02b4: Expected O, but got Unknown //IL_024b: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0256: Expected O, but got Unknown //IL_02f6: Unknown result type (might be due to invalid IL or missing references) //IL_0300: Expected O, but got Unknown //IL_02cd: Unknown result type (might be due to invalid IL or missing references) //IL_02d2: Unknown result type (might be due to invalid IL or missing references) //IL_02d8: Expected O, but got Unknown //IL_0342: Unknown result type (might be due to invalid IL or missing references) //IL_034c: Expected O, but got Unknown //IL_0319: Unknown result type (might be due to invalid IL or missing references) //IL_031e: Unknown result type (might be due to invalid IL or missing references) //IL_0324: Expected O, but got Unknown //IL_0365: Unknown result type (might be due to invalid IL or missing references) //IL_036a: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Expected O, but got Unknown if (_configurator != null) { return; } _configurator = PluginConfigurator.Create("UltraBlood", "ultrablood.kiyroprower.ultrakill"); ConfigPanel rootPanel = _configurator.rootPanel; _enabledField = new BoolField(rootPanel, "Enabled", "ultrablood.enabled", true, true); BoolField enabledField = _enabledField; object obj = <>c.<>9__39_0; if (obj == null) { PostBoolValueChangeEvent val = delegate { ScheduleReapply(); }; <>c.<>9__39_0 = val; obj = (object)val; } enabledField.postValueChangeEvent += (PostBoolValueChangeEvent)obj; AddDescription(rootPanel, "Recolor blood using the color below. Turn off to restore vanilla blood.", EnabledColor); _bloodColorField = new ColorField(rootPanel, "Blood Color", "ultrablood.color", DefaultBloodColor); ColorField bloodColorField = _bloodColorField; object obj2 = <>c.<>9__39_1; if (obj2 == null) { PostColorValueChangeEvent val2 = delegate { ScheduleReapply(); }; <>c.<>9__39_1 = val2; obj2 = (object)val2; } bloodColorField.postValueChangeEvent += (PostColorValueChangeEvent)obj2; AddDescription(rootPanel, "The color applied to blood. Its alpha is not used; puddle transparency is set by Puddle Opacity below."); AddTitle(rootPanel, "Color Mode"); _rainbowField = new BoolField(rootPanel, "Rainbow Blood", "ultrablood.rainbow", false, true); BoolField rainbowField = _rainbowField; object obj3 = <>c.<>9__39_2; if (obj3 == null) { PostBoolValueChangeEvent val3 = delegate { ScheduleReapply(); }; <>c.<>9__39_2 = val3; obj3 = (object)val3; } rainbowField.postValueChangeEvent += (PostBoolValueChangeEvent)obj3; AddDescription(rootPanel, "Give each blood particle system a random color, and cycle puddle color through the rainbow. Replaces the Blood Color. Cannot be used with Enemy Blood Color Match."); _enemyMatchField = new BoolField(rootPanel, "Enemy Blood Color Match", "ultrablood.enemyMatch", false, true); BoolField enemyMatchField = _enemyMatchField; object obj4 = <>c.<>9__39_3; if (obj4 == null) { PostBoolValueChangeEvent val4 = delegate { ScheduleReapply(); }; <>c.<>9__39_3 = val4; obj4 = (object)val4; } enemyMatchField.postValueChangeEvent += (PostBoolValueChangeEvent)obj4; AddDescription(rootPanel, "Experimental. Recolor each enemy's blood to a curated color for that enemy. Puddles follow the last enemy that bled. Unmapped enemies use the Blood Color. Cannot be used with Rainbow Blood."); AddTitle(rootPanel, "What To Recolor"); _recolorSplattersField = new BoolField(rootPanel, "Recolor Splatters", "ultrablood.splatters", true, true); BoolField recolorSplattersField = _recolorSplattersField; object obj5 = <>c.<>9__39_4; if (obj5 == null) { PostBoolValueChangeEvent val5 = delegate { ScheduleReapply(); }; <>c.<>9__39_4 = val5; obj5 = (object)val5; } recolorSplattersField.postValueChangeEvent += (PostBoolValueChangeEvent)obj5; AddDescription(rootPanel, "Tint the blood spray particles that burst from enemies. Sand, gold, and underwater variants are left alone."); _recolorPuddlesField = new BoolField(rootPanel, "Recolor Puddles", "ultrablood.puddles", true, true); BoolField recolorPuddlesField = _recolorPuddlesField; object obj6 = <>c.<>9__39_5; if (obj6 == null) { PostBoolValueChangeEvent val6 = delegate { ScheduleReapply(); }; <>c.<>9__39_5 = val6; obj6 = (object)val6; } recolorPuddlesField.postValueChangeEvent += (PostBoolValueChangeEvent)obj6; AddDescription(rootPanel, "Tint the bloodstains that pool on floors and walls."); _puddleOpacityField = new FloatField(rootPanel, "Puddle Opacity", "ultrablood.puddleOpacity", 0.65f, 0f, 1f); FloatField puddleOpacityField = _puddleOpacityField; object obj7 = <>c.<>9__39_6; if (obj7 == null) { PostFloatValueChangeEvent val7 = delegate { ScheduleReapply(); }; <>c.<>9__39_6 = val7; obj7 = (object)val7; } puddleOpacityField.postValueChangeEvent += (PostFloatValueChangeEvent)obj7; AddDescription(rootPanel, "How opaque recolored puddles are. Lower is more see-through, closer to vanilla blood. 1 is fully opaque."); _puddleStatusHeader = AddDescription(rootPanel, "Puddle recoloring status is reported here once in a level.", Color.gray); AddTitle(rootPanel, "Diagnostics"); _compatStatusHeader = AddDescription(rootPanel, "Bundle compatibility test: not run.", Color.gray); _solidCyanTestField = new BoolField(rootPanel, "Solid Cyan Test (Puddles)", "ultrablood.solidCyan", false, true); BoolField solidCyanTestField = _solidCyanTestField; object obj8 = <>c.<>9__39_7; if (obj8 == null) { PostBoolValueChangeEvent val8 = delegate { ScheduleReapply(); }; <>c.<>9__39_7 = val8; obj8 = (object)val8; } solidCyanTestField.postValueChangeEvent += (PostBoolValueChangeEvent)obj8; AddDescription(rootPanel, "Force puddles to solid cyan, ignoring the color above. If puddles turn cyan the replacement shader is working. If they stay red it is not active."); _solidCyanParticlesField = new BoolField(rootPanel, "Solid Cyan Test (Impact Particles)", "ultrablood.solidCyanParticles", false, true); BoolField solidCyanParticlesField = _solidCyanParticlesField; object obj9 = <>c.<>9__39_8; if (obj9 == null) { PostBoolValueChangeEvent val9 = delegate { ScheduleReapply(); }; <>c.<>9__39_8 = val9; obj9 = (object)val9; } solidCyanParticlesField.postValueChangeEvent += (PostBoolValueChangeEvent)obj9; AddDescription(rootPanel, "Force blood impact particles to solid cyan. If the previously dark-red particles turn cyan they are being recolored. If they stay red another effect path remains."); _debugLoggingField = new BoolField(rootPanel, "Debug Logging", "ultrablood.debug", false, true); BoolField debugLoggingField = _debugLoggingField; object obj10 = <>c.<>9__39_9; if (obj10 == null) { PostBoolValueChangeEvent val10 = delegate { UpdateInteractivity(); }; <>c.<>9__39_9 = val10; obj10 = (object)val10; } debugLoggingField.postValueChangeEvent += (PostBoolValueChangeEvent)obj10; AddDescription(rootPanel, "Log the runtime environment, shader bundle loading, and material state to the BepInEx console."); ReconcileModes(); UpdateInteractivity(); } private static void UpdateInteractivity() { try { bool enabled = Enabled; bool flag = SolidCyanTest || SolidCyanParticles; bool enemyBloodColorMatch = EnemyBloodColorMatch; bool rainbowBlood = RainbowBlood; SetInteractable((ConfigField)(object)_bloodColorField, enabled && !flag && !enemyBloodColorMatch && !rainbowBlood); SetInteractable((ConfigField)(object)_rainbowField, enabled && !flag && !enemyBloodColorMatch); SetInteractable((ConfigField)(object)_enemyMatchField, enabled && !flag && !rainbowBlood); SetInteractable((ConfigField)(object)_solidCyanTestField, enabled); SetInteractable((ConfigField)(object)_solidCyanParticlesField, enabled); SetInteractable((ConfigField)(object)_recolorSplattersField, enabled); SetInteractable((ConfigField)(object)_recolorPuddlesField, enabled); SetInteractable((ConfigField)(object)_puddleOpacityField, enabled); SetInteractable((ConfigField)(object)_debugLoggingField, enabled); } catch (Exception ex) { ManualLogSource log = _log; if (log != null) { log.LogWarning((object)("Failed to update config interactivity: " + ex.GetType().Name + ": " + ex.Message)); } } } private static void SetInteractable(ConfigField field, bool value) { if (field != null && field.interactable != value) { field.interactable = value; } } private static void ScheduleReapply() { ReconcileModes(); UpdateInteractivity(); BloodColorController.Refresh(); BloodParticles.ReapplyAll(); } private static void ReconcileModes() { if (_reconciling || _rainbowField == null || _enemyMatchField == null || !_enemyMatchField.value || !_rainbowField.value) { return; } _reconciling = true; try { _rainbowField.value = false; } finally { _reconciling = false; } } private static ConfigHeader AddTitle(ConfigPanel panel, string text) { //IL_0004: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Expected O, but got Unknown return new ConfigHeader(panel, text, 18) { textColor = TitleColor }; } private static ConfigHeader AddDescription(ConfigPanel panel, string text) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) return AddDescription(panel, text, Color.gray); } private static ConfigHeader AddDescription(ConfigPanel panel, string text, Color color) { //IL_0004: 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_000a: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown return new ConfigHeader(panel, text, 14) { textColor = color }; } } }