Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of SkinwalkerByTihi v1.0.0
BepInEx\plugins\SkinwalkerByTihi\SkinwalkerByTihi.dll
Decompiled 8 hours agousing System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using Unity.Collections; using Unity.Netcode; using UnityEngine; [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("SkinwalkerByTihi")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+ca1470329f0a369121a9c909b55f935a31e9e07d")] [assembly: AssemblyProduct("SkinwalkerByTihi")] [assembly: AssemblyTitle("SkinwalkerByTihi")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace SkinwalkerByTihi { internal static class ClipManager { private readonly struct Entry { public readonly ulong PlayerId; public readonly int SeqNum; public readonly AudioClip Clip; public Entry(ulong pid, int seq, AudioClip clip) { PlayerId = pid; SeqNum = seq; Clip = clip; } } private static readonly object _lock = new object(); private static readonly List<Entry> _clips = new List<Entry>(); private static readonly Dictionary<ulong, int> _nextSeq = new Dictionary<ulong, int>(); public static void AddClip(ulong playerId, AudioClip clip) { lock (_lock) { if (!_nextSeq.TryGetValue(playerId, out var value)) { value = 0; } _nextSeq[playerId] = value + 1; _clips.Add(new Entry(playerId, value, clip)); while (_clips.Count > SkinwalkerConfig.MaxStoredClips.Value) { Object.Destroy((Object)(object)_clips[0].Clip); _clips.RemoveAt(0); } } } public static AudioClip? GetRandomClipFromPlayer(ulong playerId) { lock (_lock) { List<AudioClip> list = new List<AudioClip>(); foreach (Entry clip in _clips) { if (clip.PlayerId == playerId) { list.Add(clip.Clip); } } if (list.Count == 0) { return null; } return list[Random.Range(0, list.Count)]; } } public static ulong? GetRandomPlayerId() { lock (_lock) { if (_clips.Count == 0) { return null; } return _clips[Random.Range(0, _clips.Count)].PlayerId; } } public static bool HasAny() { lock (_lock) { return _clips.Count > 0; } } public static void Clear() { lock (_lock) { foreach (Entry clip in _clips) { Object.Destroy((Object)(object)clip.Clip); } _clips.Clear(); _nextSeq.Clear(); } } } internal class EnemyVoiceComponent : MonoBehaviour { private EnemyAI? _enemy; private NetworkObject? _netObj; private AudioSource? _voiceSource; private float _nextPlayTime; private void Start() { _enemy = ((Component)this).GetComponent<EnemyAI>(); _netObj = ((Component)this).GetComponent<NetworkObject>(); _voiceSource = ((Component)this).gameObject.AddComponent<AudioSource>(); _voiceSource.spatialBlend = 1f; _voiceSource.minDistance = 2f; _voiceSource.maxDistance = 30f; _voiceSource.rolloffMode = (AudioRolloffMode)1; _voiceSource.playOnAwake = false; ScheduleNextPlay(); } private void Update() { if (SkinwalkerConfig.Enabled.Value && !(Time.time < _nextPlayTime)) { ScheduleNextPlay(); TryTriggerPlayback(); } } private void TryTriggerPlayback() { if (!((Object)(object)NetworkManager.Singleton == (Object)null) && NetworkManager.Singleton.IsHost && !((Object)(object)_enemy == (Object)null) && !_enemy.isEnemyDead && !((Object)(object)_netObj == (Object)null) && ClipManager.HasAny()) { ulong? randomPlayerId = ClipManager.GetRandomPlayerId(); if (randomPlayerId.HasValue) { SkinwalkerNetworkHandler.SendPlayVoice(_netObj.NetworkObjectId, randomPlayerId.Value); } } } public void PlayClip(AudioClip clip) { if (!((Object)(object)_voiceSource == (Object)null)) { _voiceSource.PlayOneShot(clip, SkinwalkerConfig.ClampedVol); } } private void ScheduleNextPlay() { float num = Random.Range(SkinwalkerConfig.MinSecs, SkinwalkerConfig.MaxSecs); _nextPlayTime = Time.time + num; } } internal static class MyPluginInfo { public const string PLUGIN_GUID = "Tihi.SkinwalkerByTihi"; public const string PLUGIN_NAME = "SkinwalkerByTihi"; public const string PLUGIN_VERSION = "1.0.0"; } [BepInPlugin("Tihi.SkinwalkerByTihi", "SkinwalkerByTihi", "1.0.0")] public class Plugin : BaseUnityPlugin { internal static ManualLogSource Log = null; private static readonly Harmony Harmony = new Harmony("Tihi.SkinwalkerByTihi"); private void Awake() { Log = ((BaseUnityPlugin)this).Logger; SkinwalkerConfig.Init(((BaseUnityPlugin)this).Config); Harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"SkinwalkerByTihi v1.0.0 loaded!"); } } internal static class SkinwalkerConfig { public static ConfigEntry<bool> Enabled; public static ConfigEntry<float> MinInterval; public static ConfigEntry<float> MaxInterval; public static ConfigEntry<float> MaxClipLength; public static ConfigEntry<int> MaxStoredClips; public static ConfigEntry<float> Volume; public static float ClipLength => Mathf.Clamp(MaxClipLength.Value, 1f, 10f); public static float MinSecs => Mathf.Max(MinInterval.Value, 1f); public static float MaxSecs => Mathf.Max(MaxInterval.Value, MinSecs + 1f); public static float ClampedVol => Mathf.Clamp01(Volume.Value); public static void Init(ConfigFile cfg) { Enabled = cfg.Bind<bool>("General", "Enabled", true, "Enable or disable the mod entirely."); MinInterval = cfg.Bind<float>("Timing", "MinInterval", 5f, "Minimum seconds between voice clips playing on any enemy."); MaxInterval = cfg.Bind<float>("Timing", "MaxInterval", 60f, "Maximum seconds between voice clips playing on any enemy."); MaxClipLength = cfg.Bind<float>("Recording", "MaxClipLength", 5f, "Length of each recorded voice clip in seconds. Max allowed: 10."); MaxStoredClips = cfg.Bind<int>("Recording", "MaxStoredClips", 30, "How many voice clips to keep in memory across all players."); Volume = cfg.Bind<float>("Playback", "Volume", 1f, "Playback volume multiplier (0.0 – 1.0)."); } } internal static class SkinwalkerNetworkHandler { [CompilerGenerated] private static class <>O { public static HandleNamedMessageDelegate <0>__OnReceivePlayVoice; } private const string MsgPlayVoice = "SkinwalkerByTihi_PlayVoice"; private static bool _registered; public static void Register() { //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_0046: Expected O, but got Unknown if (_registered) { return; } NetworkManager singleton = NetworkManager.Singleton; if (((singleton != null) ? singleton.CustomMessagingManager : null) != null) { CustomMessagingManager customMessagingManager = NetworkManager.Singleton.CustomMessagingManager; object obj = <>O.<0>__OnReceivePlayVoice; if (obj == null) { HandleNamedMessageDelegate val = OnReceivePlayVoice; <>O.<0>__OnReceivePlayVoice = val; obj = (object)val; } customMessagingManager.RegisterNamedMessageHandler("SkinwalkerByTihi_PlayVoice", (HandleNamedMessageDelegate)obj); _registered = true; Plugin.Log.LogInfo((object)"[Skinwalker] Network handler registered."); } } public static void Unregister() { if (!_registered) { return; } NetworkManager singleton = NetworkManager.Singleton; if (singleton != null) { CustomMessagingManager customMessagingManager = singleton.CustomMessagingManager; if (customMessagingManager != null) { customMessagingManager.UnregisterNamedMessageHandler("SkinwalkerByTihi_PlayVoice"); } } _registered = false; } public static void SendPlayVoice(ulong enemyNetworkId, ulong sourcePlayerId) { //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_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_0052: Unknown result type (might be due to invalid IL or missing references) if (NetworkManager.Singleton.IsHost) { HandlePlayVoice(enemyNetworkId, sourcePlayerId); FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref enemyNetworkId, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref sourcePlayerId, default(ForPrimitives)); NetworkManager.Singleton.CustomMessagingManager.SendNamedMessageToAll("SkinwalkerByTihi_PlayVoice", val, (NetworkDelivery)2); ((FastBufferWriter)(ref val)).Dispose(); } } private static void OnReceivePlayVoice(ulong senderId, FastBufferReader reader) { //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_0018: 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) ulong enemyNetworkId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref enemyNetworkId, default(ForPrimitives)); ulong sourcePlayerId = default(ulong); ((FastBufferReader)(ref reader)).ReadValueSafe<ulong>(ref sourcePlayerId, default(ForPrimitives)); HandlePlayVoice(enemyNetworkId, sourcePlayerId); } private static void HandlePlayVoice(ulong enemyNetworkId, ulong sourcePlayerId) { if (!NetworkManager.Singleton.SpawnManager.SpawnedObjects.TryGetValue(enemyNetworkId, out var value)) { return; } EnemyVoiceComponent component = ((Component)value).GetComponent<EnemyVoiceComponent>(); if ((Object)(object)component == (Object)null) { return; } AudioClip randomClipFromPlayer = ClipManager.GetRandomClipFromPlayer(sourcePlayerId); if ((Object)(object)randomClipFromPlayer == (Object)null) { ulong? randomPlayerId = ClipManager.GetRandomPlayerId(); if (randomPlayerId.HasValue) { randomClipFromPlayer = ClipManager.GetRandomClipFromPlayer(randomPlayerId.Value); } } if ((Object)(object)randomClipFromPlayer != (Object)null) { component.PlayClip(randomClipFromPlayer); } } } internal class VoiceRecorder : MonoBehaviour { private readonly ConcurrentQueue<float[]> _audioQueue = new ConcurrentQueue<float[]>(); private readonly List<float> _accumulated = new List<float>(); private int _sampleRate; private int _channels; public ulong PlayerClientId { get; set; } private void Start() { _sampleRate = AudioSettings.outputSampleRate; } private void OnAudioFilterRead(float[] data, int channels) { if (SkinwalkerConfig.Enabled.Value) { _channels = channels; float[] array = new float[data.Length]; data.CopyTo(array, 0); _audioQueue.Enqueue(array); } } private void Update() { if (_sampleRate != 0 && _channels != 0) { float[] result; while (_audioQueue.TryDequeue(out result)) { _accumulated.AddRange(result); } int num = (int)(SkinwalkerConfig.ClipLength * (float)_sampleRate) * _channels; while (_accumulated.Count >= num) { float[] array = _accumulated.GetRange(0, num).ToArray(); _accumulated.RemoveRange(0, num); int num2 = num / _channels; AudioClip val = AudioClip.Create($"voice_{PlayerClientId}", num2, _channels, _sampleRate, false); val.SetData(array, 0); ClipManager.AddClip(PlayerClientId, val); Plugin.Log.LogDebug((object)$"[Skinwalker] Recorded clip from player {PlayerClientId} ({num2} samples)"); } int num3 = num * 4; if (_accumulated.Count > num3) { _accumulated.RemoveRange(0, _accumulated.Count - num3); } } } } } namespace SkinwalkerByTihi.Patches { [HarmonyPatch(typeof(EnemyAI), "Start")] internal static class EnemyPatch { private static void Postfix(EnemyAI __instance) { if (SkinwalkerConfig.Enabled.Value && !((Object)(object)((Component)__instance).GetComponent<EnemyVoiceComponent>() != (Object)null)) { ((Component)__instance).gameObject.AddComponent<EnemyVoiceComponent>(); } } } [HarmonyPatch(typeof(StartOfRound), "Start")] internal static class NetworkRegisterPatch { private static void Postfix() { SkinwalkerNetworkHandler.Register(); } } [HarmonyPatch(typeof(StartOfRound), "OnDestroy")] internal static class NetworkUnregisterPatch { private static void Postfix() { SkinwalkerNetworkHandler.Unregister(); ClipManager.Clear(); } } [HarmonyPatch(typeof(PlayerControllerB), "Start")] internal static class PlayerVoicePatch { [CompilerGenerated] private sealed class <AttachWhenReady>d__1 : IEnumerator<object>, IEnumerator, IDisposable { private int <>1__state; private object <>2__current; public PlayerControllerB player; object IEnumerator<object>.Current { [DebuggerHidden] get { return <>2__current; } } object IEnumerator.Current { [DebuggerHidden] get { return <>2__current; } } [DebuggerHidden] public <AttachWhenReady>d__1(int <>1__state) { this.<>1__state = <>1__state; } [DebuggerHidden] void IDisposable.Dispose() { <>1__state = -2; } private bool MoveNext() { switch (<>1__state) { default: return false; case 0: <>1__state = -1; break; case 1: <>1__state = -1; break; } if ((Object)(object)player.currentVoiceChatAudioSource == (Object)null) { <>2__current = null; <>1__state = 1; return true; } if ((Object)(object)player == (Object)(object)GameNetworkManager.Instance?.localPlayerController) { return false; } if ((Object)(object)((Component)player.currentVoiceChatAudioSource).GetComponent<VoiceRecorder>() != (Object)null) { return false; } ((Component)player.currentVoiceChatAudioSource).gameObject.AddComponent<VoiceRecorder>().PlayerClientId = player.playerClientId; Plugin.Log.LogInfo((object)$"[Skinwalker] VoiceRecorder attached to player {player.playerUsername} (id={player.playerClientId})"); return false; } bool IEnumerator.MoveNext() { //ILSpy generated this explicit interface implementation from .override directive in MoveNext return this.MoveNext(); } [DebuggerHidden] void IEnumerator.Reset() { throw new NotSupportedException(); } } private static void Postfix(PlayerControllerB __instance) { ((MonoBehaviour)__instance).StartCoroutine(AttachWhenReady(__instance)); } [IteratorStateMachine(typeof(<AttachWhenReady>d__1))] private static IEnumerator AttachWhenReady(PlayerControllerB player) { //yield-return decompiler failed: Unexpected instruction in Iterator.Dispose() return new <AttachWhenReady>d__1(0) { player = player }; } } }