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 : "<null>");
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 + ": <null material>"));
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=<null>");
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 = "<unknown>";
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 "<none>";
}
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<BloodsplatterManager>.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<int, Snapshot> Snapshots = new Dictionary<int, Snapshot>();
private static readonly HashSet<string> LoggedFingerprints = new HashSet<string>();
private static readonly Dictionary<int, EnemyIdentifier> BloodEnemies = new Dictionary<int, EnemyIdentifier>();
private static readonly Dictionary<int, Color> EnemyColors = new Dictionary<int, Color>();
private static readonly string[] TintProperties = new string[3] { "_Color", "_BaseColor", "_TintColor" };
private static readonly Dictionary<EnemyType, Color> EnemyPalette = new Dictionary<EnemyType, Color>
{
{
(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<int> visited = new HashSet<int>();
RegisterHierarchy(gameObject, visited, enemyColor);
Plugin.RunDelayed(gameObject, delegate
{
if (!((Object)(object)splatter == (Object)null) && !((Object)(object)((Component)splatter).gameObject == (Object)null))
{
HashSet<int> visited2 = new HashSet<int>();
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<int> visited, Color? enemyColor)
{
ParticleSystem[] componentsInChildren = root.GetComponentsInChildren<ParticleSystem>(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<int> 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<ParticleSystemRenderer>();
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<int> list = new List<int>();
foreach (KeyValuePair<int, Snapshot> 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<ParticleSystemRenderer>();
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<string> list = new List<string>();
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 ?? "<unknown>")));
_log.LogInfo((object)("[compat] plugin directory: " + (text2 ?? "<unknown>")));
_log.LogInfo((object)("[compat] expected CompatibilityTests directory: " + (text3 ?? "<unknown>")));
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<string, string>(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<BundleRow> list = new List<BundleRow>();
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<TextAsset>();
bundleRow.TextLoaded = array != null && array.Length != 0;
Shader val3 = val2.LoadAsset<Shader>("UltraBlood/CompositeBloodTint");
if ((Object)(object)val3 == (Object)null)
{
Shader[] array2 = val2.LoadAllAssets<Shader>();
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<BundleRow> 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 : "<null>";
}
catch
{
return "<unavailable>";
}
}
private static string SafeCwd()
{
try
{
return Directory.GetCurrentDirectory();
}
catch
{
return "<unavailable>";
}
}
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<TextAsset>(_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<Shader>(_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<T>(AssetBundle bundle, string preferredName) where T : Object
{
T val = bundle.LoadAsset<T>(preferredName);
if ((Object)(object)val != (Object)null)
{
return val;
}
T[] array = bundle.LoadAllAssets<T>();
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 <CreateMenu>b__39_0(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_1(Color _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_2(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_3(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_4(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_5(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_6(float _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_7(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>b__39_8(bool _)
{
ScheduleReapply();
}
internal void <CreateMenu>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
};
}
}
}