using System;
using System.CodeDom.Compiler;
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using System.Resources;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using CybergrindDeathcam.Components;
using CybergrindDeathcam.Utils;
using HarmonyLib;
using PluginConfig.API;
using PluginConfig.API.Fields;
using TMPro;
using UKEnemyIdentifier.Components;
using UKEnemyIdentifier.Utils;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CybergrindDeathcam")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("CybergrindDeathcam")]
[assembly: AssemblyCopyright("Copyright © 2024 Flazhik")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("941412EE-5088-40AB-834A-40CA7F856E4B")]
[assembly: AssemblyFileVersion("1.0.4.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.4.0")]
namespace CybergrindDeathcam
{
public class AssetsManager : MonoSingleton<AssetsManager>
{
private const BindingFlags Flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
private static Dictionary<string, Object> _prefabs = new Dictionary<string, Object>();
private AssetBundle bundle;
public void LoadAssets()
{
bundle = AssetBundle.LoadFromMemory(Resources.CybergrindDeathcam);
}
public void RegisterPrefabs()
{
string[] allAssetNames = bundle.GetAllAssetNames();
foreach (string text in allAssetNames)
{
_prefabs.Add(text, bundle.LoadAsset<Object>(text));
}
Type[] types = Assembly.GetExecutingAssembly().GetTypes();
for (int i = 0; i < types.Length; i++)
{
CheckType(types[i]);
}
}
private static void CheckType(IReflect type)
{
type.GetFields(BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic).ToList().ForEach(ProcessField);
}
private static void ProcessField(FieldInfo field)
{
if (!field.FieldType.IsArray && field.IsStatic)
{
PrefabAsset customAttribute = field.GetCustomAttribute<PrefabAsset>();
if (customAttribute != null)
{
field.SetValue(null, _prefabs[customAttribute.Path]);
}
}
}
public static Object GetAsset(string assetName)
{
return _prefabs[assetName];
}
}
[BepInProcess("ULTRAKILL.exe")]
[BepInPlugin("dev.flazhik.cybergrinddeathcam", "CybergrindDeathcam", "1.0.4")]
public class CybergrindDeathcam : BaseUnityPlugin
{
[Serializable]
[CompilerGenerated]
private sealed class <>c
{
public static readonly <>c <>9 = new <>c();
public static PlayerHurtEventDelegate <>9__6_0;
internal void <Awake>b__6_0(PlayerHurtEvent e)
{
if (e.PlayerIsKilled && !(SceneHelper.CurrentScene != "Endless"))
{
DeathCam deathCam = ((Component)MonoSingleton<NewMovement>.Instance).gameObject.AddComponent<DeathCam>();
deathCam.killer = e.EnemyId;
((Behaviour)deathCam).enabled = true;
}
}
}
public static BoolField SkipLeaderboards;
public static IntField LeaderboardsSkipThreshold;
public static IntField AlwaysShowLeaderboardsStartingFrom;
private static PluginConfigurator _config;
private static void SetupConfig()
{
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
//IL_0048: Unknown result type (might be due to invalid IL or missing references)
//IL_0052: Expected O, but got Unknown
//IL_006b: Unknown result type (might be due to invalid IL or missing references)
//IL_0075: Expected O, but got Unknown
//IL_0081: Unknown result type (might be due to invalid IL or missing references)
//IL_008b: Expected O, but got Unknown
_config = PluginConfigurator.Create("CybergrindDeathcam", "dev.flazhik.cybergrinddeathcam");
SkipLeaderboards = new BoolField(_config.rootPanel, "Skip Cyber Grind leaderboards", "deathcam.skip-leaderboards", false);
LeaderboardsSkipThreshold = new IntField(_config.rootPanel, "Don't skip if PB is <= N waves away", "deathcam.threshold", 5);
AlwaysShowLeaderboardsStartingFrom = new IntField(_config.rootPanel, "Don't skip starting from wave", "deathcam.always-show-starting-from", 999);
SkipLeaderboards.onValueChange += new BoolValueChangeEventDelegate(ManageSkipFields);
SkipLeaderboards.TriggerValueChangeEvent();
_config.SetIconWithURL("file://" + Path.Combine(Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location), "icon.png"));
}
private static void ManageSkipFields(BoolValueChangeEvent e)
{
bool value = e.value;
((ConfigField)LeaderboardsSkipThreshold).hidden = !value;
((ConfigField)AlwaysShowLeaderboardsStartingFrom).hidden = !value;
}
private void Awake()
{
//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_003d: Expected O, but got Unknown
MonoSingleton<AssetsManager>.Instance.LoadAssets();
MonoSingleton<AssetsManager>.Instance.RegisterPrefabs();
SetupConfig();
EnemyIdentifierManager instance = MonoSingleton<EnemyIdentifierManager>.Instance;
object obj = <>c.<>9__6_0;
if (obj == null)
{
PlayerHurtEventDelegate val = delegate(PlayerHurtEvent e)
{
if (e.PlayerIsKilled && !(SceneHelper.CurrentScene != "Endless"))
{
DeathCam deathCam = ((Component)MonoSingleton<NewMovement>.Instance).gameObject.AddComponent<DeathCam>();
deathCam.killer = e.EnemyId;
((Behaviour)deathCam).enabled = true;
}
};
<>c.<>9__6_0 = val;
obj = (object)val;
}
instance.OnPlayerHurt += (PlayerHurtEventDelegate)obj;
}
}
internal static class PluginInfo
{
public const string GUID = "dev.flazhik.cybergrinddeathcam";
public const string NAME = "CybergrindDeathcam";
public const string VERSION = "1.0.4";
}
[AttributeUsage(AttributeTargets.Field)]
public class PrefabAsset : Attribute
{
public string Path { get; }
public PrefabAsset(string path = "")
{
Path = path;
}
}
[GeneratedCode("System.Resources.Tools.StronglyTypedResourceBuilder", "4.0.0.0")]
[DebuggerNonUserCode]
[CompilerGenerated]
internal class Resources
{
private static ResourceManager resourceMan;
private static CultureInfo resourceCulture;
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static ResourceManager ResourceManager
{
get
{
if (resourceMan == null)
{
resourceMan = new ResourceManager("CybergrindDeathcam.Resources", typeof(Resources).Assembly);
}
return resourceMan;
}
}
[EditorBrowsable(EditorBrowsableState.Advanced)]
internal static CultureInfo Culture
{
get
{
return resourceCulture;
}
set
{
resourceCulture = value;
}
}
internal static byte[] CybergrindDeathcam => (byte[])ResourceManager.GetObject("CybergrindDeathcam", resourceCulture);
internal Resources()
{
}
}
}
namespace CybergrindDeathcam.Utils
{
public static class EnemyIdentifierExtension
{
public static GameObject GetObject(this EnemyIdentifier value)
{
return FirstNonNull((IEnumerable<MonoBehaviour>)(object)new MonoBehaviour[5]
{
(MonoBehaviour)value.zombie,
(MonoBehaviour)value.drone,
(MonoBehaviour)value.machine,
(MonoBehaviour)value.spider,
(MonoBehaviour)value.statue
});
}
private static GameObject FirstNonNull(IEnumerable<MonoBehaviour> values)
{
return (from m in values
where (Object)(object)m != (Object)null
select ((Component)m).gameObject).FirstOrDefault();
}
}
public static class EnemyNames
{
private static readonly Dictionary<EnemyType, string> EnemyNamesDict = new Dictionary<EnemyType, string>
{
{
(EnemyType)19,
"SISYPHEAN INSURRECTIONIST"
},
{
(EnemyType)5,
"MINDFLAYER"
},
{
(EnemyType)26,
"FERRYMAN"
},
{
(EnemyType)2,
"HIDEOUS MASS"
},
{
(EnemyType)7,
"SWORDSMACHINE"
},
{
(EnemyType)33,
"GUTTERMAN"
},
{
(EnemyType)34,
"GUTTERTANK"
},
{
(EnemyType)31,
"MANNEQUIN"
},
{
(EnemyType)0,
"CERBERUS"
},
{
(EnemyType)1,
"DRONE"
},
{
(EnemyType)4,
"MALICIOUS FACE"
},
{
(EnemyType)6,
"STREETCLEANER"
},
{
(EnemyType)9,
"VIRTUE"
},
{
(EnemyType)12,
"STALKER"
},
{
(EnemyType)13,
"STRAY"
},
{
(EnemyType)14,
"SCHISM"
},
{
(EnemyType)15,
"SOLDIER"
},
{
(EnemyType)20,
"TURRET"
},
{
(EnemyType)3,
"FILTH"
},
{
(EnemyType)21,
"IDOL"
}
};
public static string GetEnemyName(EnemyType type)
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
if (!EnemyNamesDict.TryGetValue(type, out var value))
{
return "UNKNOWN ENTITY";
}
return value;
}
}
public static class ReflectionUtils
{
private const BindingFlags BindingFlagsFields = BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic;
public static object GetPrivate<T>(T instance, Type classType, string field)
{
return classType.GetField(field, BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic).GetValue(instance);
}
public static IEnumerable<CodeInstruction> IL(params (OpCode, object)[] instructions)
{
return ((IEnumerable<(OpCode, object)>)instructions).Select((Func<(OpCode, object), CodeInstruction>)(((OpCode, object) i) => new CodeInstruction(i.Item1, i.Item2))).ToList();
}
}
}
namespace CybergrindDeathcam.Components
{
public class DeathCam : MonoBehaviour
{
[PrefabAsset("assets/ui/elements/notification.prefab")]
private static GameObject _notificationPrefab;
[PrefabAsset("assets/audio/deathcam_sfx.mp3")]
private static AudioClip _deathcamSfx;
private static AudioSource _audioSource;
private const float RisingDistance = 10f;
private const float RisingTime = 0.1f;
private const float PointCameraAtKillerTime = 0.02f;
private const float ZoomInRate = 0.12f;
private const float TimeFreezeRate = 0.2f;
private const float DistanceToKillerThreshold = 0.5f;
private const float TimeScaleThreshold = 0.2f;
private const string CanvasPath = "/Player/FinishCanvas (1)";
public EnemyIdentifier killer;
private DeathcamState _state;
private GameObject _killerObj;
private float _killerHeight;
private bool _skipLeaderboards;
private bool _skipIgnored;
private NewMovement _nm;
private TimeController _timeController;
private FinalCyberRank _finalCyberRank;
private Vector3 _riseToPosition;
private Vector3 _risingVelocity;
private float _distanceToKiller;
private float _zoomInCutoff = 60f;
private void Awake()
{
((Behaviour)this).enabled = false;
}
private void Start()
{
//IL_0082: 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_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
_timeController = MonoSingleton<TimeController>.Instance;
_finalCyberRank = GameObject.Find("/Player/FinishCanvas (1)/Panel").GetComponent<FinalCyberRank>();
_state = DeathcamState.FocusingOnKiller;
_skipLeaderboards = CybergrindDeathcam.SkipLeaderboards.value;
if (!((Object)(object)killer == (Object)null))
{
_nm = ((Component)this).gameObject.GetComponent<NewMovement>();
_audioSource = ((Component)this).gameObject.AddComponent<AudioSource>();
_audioSource.clip = _deathcamSfx;
_riseToPosition = ((Component)_nm).transform.position + new Vector3(0f, 10f, 0f);
_killerObj = killer.GetObject();
_killerHeight = GetKillerHeight();
EnableNoclip();
((MonoBehaviour)this).StartCoroutine(DeathCamRoutine());
}
}
private void Update()
{
if (!(Time.timeScale > 0.2f) && _skipLeaderboards && !_skipIgnored)
{
CyberRankData bestCyber = GameProgressSaver.GetBestCyber();
int @int = MonoSingleton<PrefsManager>.Instance.GetInt("difficulty", 0);
bool flag = bestCyber.preciseWavesByDifficulty[@int] - _finalCyberRank.savedWaves <= (float)CybergrindDeathcam.LeaderboardsSkipThreshold.value;
if ((float)CybergrindDeathcam.AlwaysShowLeaderboardsStartingFrom.value <= _finalCyberRank.savedWaves || flag)
{
_skipIgnored = true;
return;
}
GameProgressSaver.AddMoney(_finalCyberRank.totalPoints);
SceneHelper.RestartScene();
}
}
private void FixedUpdate()
{
if (KillerIsDeadOrUnknown())
{
if (_skipLeaderboards)
{
_timeController.timeScaleModifier = 0.05f;
}
Time.timeScale = _timeController.timeScale * _timeController.timeScaleModifier;
return;
}
switch (_state)
{
case DeathcamState.FocusingOnKiller:
FocusingOnKiller();
break;
case DeathcamState.ZoomIn:
ZoomIn();
break;
case DeathcamState.TimeFreeze:
_timeController.controlTimeScale = false;
if ((double)_timeController.timeScale > 0.0)
{
Time.timeScale = Mathf.MoveTowards(Time.timeScale, 0f, 0.2f);
}
break;
default:
throw new ArgumentOutOfRangeException("Invalid Deathcam state");
}
}
private IEnumerator DeathCamRoutine()
{
yield return (object)new WaitForSecondsRealtime(2f);
ShowNotification();
_audioSource.Play();
_state = DeathcamState.ZoomIn;
}
private void EnableNoclip()
{
((Component)_nm).GetComponent<Rigidbody>().isKinematic = true;
((Behaviour)((Component)_nm).GetComponent<KeepInBounds>()).enabled = false;
}
private void FocusingOnKiller()
{
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Unknown result type (might be due to invalid IL or missing references)
//IL_0091: 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_009b: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Unknown result type (might be due to invalid IL or missing references)
//IL_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: 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_0052: 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)
if (!KillerIsDeadOrUnknown())
{
if (Math.Abs(((Component)_nm).transform.position.y - _riseToPosition.y) > float.Epsilon)
{
((Component)_nm).transform.position = Vector3.SmoothDamp(((Component)_nm).transform.position, _riseToPosition, ref _risingVelocity, 0.1f);
}
Quaternion val = Quaternion.LookRotation(_killerObj.transform.position - ((Component)_nm.cc.cam).transform.position);
((Component)_nm.cc.cam).transform.rotation = Quaternion.Lerp(((Component)_nm.cc.cam).transform.rotation, val, 0.02f);
}
}
private void ZoomIn()
{
//IL_000c: Unknown result type (might be due to invalid IL or missing references)
//IL_0026: 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_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_00a4: Unknown result type (might be due to invalid IL or missing references)
//IL_00a5: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_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_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Unknown result type (might be due to invalid IL or missing references)
//IL_00db: Unknown result type (might be due to invalid IL or missing references)
//IL_00dc: Unknown result type (might be due to invalid IL or missing references)
//IL_00dd: Unknown result type (might be due to invalid IL or missing references)
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_00e3: Unknown result type (might be due to invalid IL or missing references)
//IL_00e4: Unknown result type (might be due to invalid IL or missing references)
//IL_00e5: Unknown result type (might be due to invalid IL or missing references)
//IL_00ea: Unknown result type (might be due to invalid IL or missing references)
//IL_00ec: Unknown result type (might be due to invalid IL or missing references)
//IL_00f1: Unknown result type (might be due to invalid IL or missing references)
//IL_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_0129: Unknown result type (might be due to invalid IL or missing references)
//IL_0148: Unknown result type (might be due to invalid IL or missing references)
//IL_0149: Unknown result type (might be due to invalid IL or missing references)
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_015b: Unknown result type (might be due to invalid IL or missing references)
//IL_0171: Unknown result type (might be due to invalid IL or missing references)
_distanceToKiller = Vector3.Distance(_killerObj.transform.position, ((Component)_nm.cc.cam).transform.position);
if (_zoomInCutoff == 0f || KillerIsDeadOrUnknown())
{
_state = DeathcamState.TimeFreeze;
return;
}
float num = _killerHeight * DeathcamDistanceCoefficient();
if (_distanceToKiller - num < 0.5f)
{
_state = DeathcamState.TimeFreeze;
return;
}
Vector3 position = _killerObj.transform.position;
Vector3 position2 = ((Component)_nm.cc.cam).transform.position;
Vector3 val = num * ((position - position2) / _distanceToKiller) - new Vector3(0f, _killerHeight / 4f, 0f);
Vector3 val2 = position - position2;
Vector3 val3 = position - val;
Quaternion val4 = Quaternion.LookRotation(val2);
((Component)_nm.cc.cam).transform.rotation = Quaternion.Lerp(((Component)_nm.cc.cam).transform.rotation, val4, 0.12f);
((Component)_nm.cc.cam).transform.position = Vector3.Lerp(position2, val3, 0.12f);
_distanceToKiller = Vector3.Distance(position, ((Component)_nm.cc.cam).transform.position);
_zoomInCutoff -= 1f;
}
private float GetKillerHeight()
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Expected O, but got Unknown
//IL_0052: 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_005a: Unknown result type (might be due to invalid IL or missing references)
EnemySimplifier[] componentsInChildren = _killerObj.GetComponentsInChildren<EnemySimplifier>();
if (componentsInChildren.Length == 0)
{
return 0f;
}
Renderer val = (Renderer)ReflectionUtils.GetPrivate<EnemySimplifier>(componentsInChildren[0], typeof(EnemySimplifier), "meshrenderer");
Guttertank val2 = default(Guttertank);
if (_killerObj.TryGetComponent<Guttertank>(ref val2))
{
return 6f;
}
if (!((Object)(object)val == (Object)null))
{
Bounds bounds = val.bounds;
return ((Bounds)(ref bounds)).size.y;
}
return 0f;
}
private bool KillerIsDeadOrUnknown()
{
if (!((Object)(object)_killerObj == (Object)null) && !((Object)(object)killer == (Object)null))
{
return killer.dead;
}
return true;
}
private float DeathcamDistanceCoefficient()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000b: 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_000e: Invalid comparison between Unknown and I4
//IL_0030: Unknown result type (might be due to invalid IL or missing references)
//IL_0033: Invalid comparison between Unknown and I4
//IL_0010: Unknown result type (might be due to invalid IL or missing references)
//IL_002a: Expected I4, but got Unknown
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Invalid comparison between Unknown and I4
//IL_002a: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Invalid comparison between Unknown and I4
EnemyType enemyType = killer.enemyType;
if ((int)enemyType <= 7)
{
switch ((int)enemyType)
{
default:
if ((int)enemyType != 7)
{
break;
}
return 3.5f;
case 0:
return 0.6f;
case 4:
return 0.6f;
case 2:
return 0.6f;
case 1:
case 3:
break;
}
}
else
{
if ((int)enemyType == 31)
{
return 0.7f;
}
if ((int)enemyType == 33)
{
return 1.3f;
}
}
return 1f;
}
private void ShowNotification()
{
GameObject val = GameObject.Find("/Player/FinishCanvas (1)");
GameObject obj = Object.Instantiate<GameObject>(_notificationPrefab, val.transform);
obj.transform.SetSiblingIndex(0);
((TMP_Text)((Component)obj.transform.Find("KillerName")).GetComponent<TextMeshProUGUI>()).text = EnemyIdentifierExtension.GetEnemyName(killer).ToUpper();
}
}
public enum DeathcamState
{
FocusingOnKiller,
ZoomIn,
TimeFreeze
}
}