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 ChaosCompany v0.8.0
ChaosCompany.dll
Decompiled 3 days ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Concurrent; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Net; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ChaosCompany.Brain; using ChaosCompany.Effects; using ChaosCompany.Items; using ChaosCompany.Mobs; using ChaosCompany.Net; using ChaosCompany.Speech; using ChaosCompany.Voice; using Dissonance; using Dissonance.Audio.Capture; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using NAudio.Wave; using TMPro; using Unity.Collections; using Unity.Netcode; using UnityEngine; using UnityEngine.AI; using UnityEngine.Audio; using UnityEngine.UI; [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("ChaosCompany")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("0.8.0.0")] [assembly: AssemblyInformationalVersion("0.8.0")] [assembly: AssemblyProduct("ChaosCompany")] [assembly: AssemblyTitle("ChaosCompany")] [assembly: AssemblyVersion("0.8.0.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 ChaosCompany { public static class ChaosApi { public static string MyVoiceConsent => VoiceConsent.Mine; public static string BrainStatus => BrainClient.Status; public static string NetRole => ChaosNet.Role; public static bool EchoEnabled { get { return EchoMonitor.Enabled; } set { EchoMonitor.Enabled = value; } } public static float EchoVolume { get { return EchoMonitor.Volume; } set { EchoMonitor.Volume = value; } } public static float DuckVolume { get { return Plugin.DuckVolume.Value; } set { Plugin.DuckVolume.Value = Mathf.Clamp(value, 0f, 4f); } } public static float EchoLevel => EchoMonitor.Level; public static void ApplyEffect(PlayerControllerB player, EffectId id, float seconds) { if (!((Object)(object)player == (Object)null) && !(seconds <= 0f)) { ChaosNet.RequestSet((int)player.playerClientId, id, seconds); } } public static void RemoveEffect(PlayerControllerB player, EffectId id) { if (!((Object)(object)player == (Object)null)) { ChaosNet.RequestSet((int)player.playerClientId, id, 0f); } } public static void ClearEffects(PlayerControllerB player) { if (!((Object)(object)player == (Object)null)) { ChaosNet.RequestClear((int)player.playerClientId); } } public static bool HasEffect(PlayerControllerB player, EffectId id) { if ((Object)(object)player != (Object)null) { return EffectManager.Has((int)player.playerClientId, id); } return false; } public static float EffectSecondsLeft(PlayerControllerB player, EffectId id) { if (!((Object)(object)player == (Object)null)) { return EffectManager.Remaining((int)player.playerClientId, id); } return 0f; } public static void SpawnItem(PlayerControllerB near, ChaosItem item) { if (!((Object)(object)near == (Object)null)) { ChaosEvents.RequestSpawn(item, (int)near.playerClientId); } } public static void SpawnMob(PlayerControllerB near, ChaosMob mob) { if (!((Object)(object)near == (Object)null)) { ChaosEvents.RequestMobSpawn(mob, (int)near.playerClientId); } } public static string GetPlayerNames(PlayerControllerB player) { return PlayerNames.GetVariants(player); } public static void SetPlayerNames(PlayerControllerB player, string csv) { PlayerNames.SetVariants(player, csv); } public static string VoiceConsentOf(PlayerControllerB player) { if (!VoiceConsent.IsAllowed(player)) { return "нет согласия"; } return "разрешил"; } public static float RecordedVoiceSeconds(PlayerControllerB player) { if (!((Object)(object)player == (Object)null)) { return VoiceRecorder.RecordedSeconds(VoiceRecorder.Key(player)); } return 0f; } public static void DeleteVoiceRecordings(PlayerControllerB player) { if ((Object)(object)player != (Object)null) { VoiceRecorder.Delete(VoiceRecorder.Key(player)); } } public static void SetMyVoiceConsent(bool allow) { VoiceConsent.SetMine(allow); } public static void TestMyClone(Action<string> done) { StartOfRound instance = StartOfRound.Instance; PlayerControllerB me = (((Object)(object)instance != (Object)null) ? instance.localPlayerController : null); if ((Object)(object)me == (Object)null) { done("нет игрока"); return; } string playerKey = VoiceRecorder.Key(me); if (!BrainClient.Available) { done("компаньон не подключён"); return; } if (!BrainClient.HasClone(playerKey)) { done("клона нет: нужно согласие и хотя бы ~8 с записей (список обновляется раз в 30 с)"); return; } string line = DuckInserts.PickLine(instance, me) ?? "картошка в тапках"; BrainClient.RequestSpeakAs(playerKey, line, delegate(byte[] audio) { if (audio == null) { done("не получилось (на вылазке - только заранее озвученное; попробуй на орбите)"); } else { VoiceEffects.PlayInsert((int)me.playerClientId, audio); done("«" + line + "»"); } }); } public static void TestBrain(PlayerControllerB player, Action<string> done) { Dictionary<string, string> context = new Dictionary<string, string> { { "игрок", ((Object)(object)player != (Object)null) ? player.playerUsername : "кто-то" } }; BrainClient.RequestLine("anatoly", "compare", context, done); } } internal class ChaosRunner : MonoBehaviour { private static ChaosRunner instance; internal static ChaosRunner Instance => instance; internal static void Ensure() { //IL_0013: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)instance != (Object)null)) { instance = new GameObject("ChaosCompany_Runner").AddComponent<ChaosRunner>(); ((Component)instance).gameObject.AddComponent<ConsentPrompt>(); } } private void Update() { EffectManager.Tick(); EchoMonitor.EnsureState(); VoiceEffects.Update(); BrainClient.Update(); VoiceRecorder.Update(); DuckInserts.Update(); } private void LateUpdate() { BodyEffects.LateUpdate(); } private void OnGUI() { BodyEffects.OnGUI(); } } [BepInPlugin("claude.chaoscompany", "ChaosCompany", "0.8.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "claude.chaoscompany"; public const string Name = "ChaosCompany"; public const string Version = "0.8.0"; internal static ManualLogSource Log; private Harmony harmony; internal static ConfigEntry<bool> HitEffectsEnabled; internal static ConfigEntry<float> HitEffectDuration; internal static ConfigEntry<float> DuckVolume; internal static ConfigEntry<bool> BrainEnabled; internal static ConfigEntry<string> BrainUrl; internal static ConfigEntry<string> VoiceConsent; internal static ConfigEntry<bool> RecordVoices; internal static ConfigEntry<float> MaxVoiceSecondsPerPlayer; private void Awake() { //IL_00d5: Unknown result type (might be due to invalid IL or missing references) //IL_00df: Expected O, but got Unknown //IL_017b: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Expected O, but got Unknown Log = ((BaseUnityPlugin)this).Logger; HitEffectsEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("Test", "VoiceEffectOnEnemyHit", true, "Temporary test hook: when an enemy hurts you, you get a random voice effect."); HitEffectDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Test", "VoiceEffectOnEnemyHitSeconds", 20f, "Duration of that effect in seconds."); BrainEnabled = ((BaseUnityPlugin)this).Config.Bind<bool>("AI", "UseChaosBrain", true, "Host only: take monster lines from the ChaosBrain companion app (local neural network). If it's not running, phrase files are used."); BrainUrl = ((BaseUnityPlugin)this).Config.Bind<string>("AI", "ChaosBrainUrl", "http://127.0.0.1:5077", "Address of the ChaosBrain companion app."); VoiceConsent = ((BaseUnityPlugin)this).Config.Bind<string>("Voice", "VoiceConsent", "Ask", new ConfigDescription("Do you allow the HOST of a ChaosCompany game to record your voice so monsters can speak with it? Recordings stay only on the host's computer. Ask = show the question in game, Allow, Deny. Changing to Deny makes the host delete your recordings.", (AcceptableValueBase)(object)new AcceptableValueList<string>(new string[3] { "Ask", "Allow", "Deny" }), Array.Empty<object>())); RecordVoices = ((BaseUnityPlugin)this).Config.Bind<bool>("Voice", "RecordVoicesAsHost", true, "Host only: record voices of players who allowed it (for voice clones)."); MaxVoiceSecondsPerPlayer = ((BaseUnityPlugin)this).Config.Bind<float>("Voice", "MaxVoiceSecondsPerPlayer", 300f, "Host only: how many seconds of voice to keep per player (older recordings are deleted)."); DuckVolume = ((BaseUnityPlugin)this).Config.Bind<float>("Sound", "DuckVolume", 2f, "Volume of the duck quack (1 = normal, up to 4)."); VoiceConsent.SettingChanged += delegate { ChaosCompany.Voice.VoiceConsent.SendMine(); }; harmony = new Harmony("claude.chaoscompany"); harmony.PatchAll(typeof(Plugin).Assembly); Log.LogInfo((object)"ChaosCompany 0.8.0 loaded"); } } } namespace ChaosCompany.Voice { internal static class DuckInserts { private static readonly string[] Categories = new string[8] { "insult", "insult_friend", "dare", "annoying", "nonsense", "confession", "offtopic", "quack" }; private static readonly Dictionary<int, float> next = new Dictionary<int, float>(); private static readonly HashSet<int> pending = new HashSet<int>(); private static bool IsHost { get { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsListening) { return singleton.IsServer; } return true; } } internal static void Update() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || !IsHost || !BrainClient.Available) { return; } float time = Time.time; for (int i = 0; i < instance.allPlayerScripts.Length; i++) { PlayerControllerB val = instance.allPlayerScripts[i]; if ((Object)(object)val == (Object)null || !val.isPlayerControlled || val.isPlayerDead || !EffectManager.Has(i, EffectId.Duck) || pending.Contains(i)) { continue; } string playerKey = VoiceRecorder.Key(val); if (!BrainClient.HasClone(playerKey)) { continue; } if (!next.TryGetValue(i, out var value)) { value = (next[i] = time + Random.Range(1.5f, 3f)); } if (!IsSpeaking(instance, val)) { if (value < time + 1f) { next[i] = time + 1f; } } else { if (time < value) { continue; } next[i] = time + Random.Range(4f, 9f); string text = PickLine(instance, val); if (text == null) { continue; } int player = i; pending.Add(player); BrainClient.RequestSpeakAs(playerKey, text, delegate(byte[] audio) { pending.Remove(player); PlayerControllerB val2 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.allPlayerScripts[player] : null); if (audio != null && (Object)(object)val2 != (Object)null && IsSpeaking(StartOfRound.Instance, val2)) { ChaosEvents.ServerPlayerInsert(player, MatchLoudness(audio, VoiceRecorder.VoiceRms(val2))); } }); } } } private static bool IsSpeaking(StartOfRound sor, PlayerControllerB p) { if ((Object)(object)p == (Object)(object)sor.localPlayerController) { DissonanceComms voiceChatModule = sor.voiceChatModule; VoicePlayerState val = (((Object)(object)voiceChatModule != (Object)null) ? voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName) : null); if (val != null) { return val.IsSpeaking; } return false; } if (p.voicePlayerState != null) { return p.voicePlayerState.IsSpeaking; } return false; } internal static string PickLine(StartOfRound sor, PlayerControllerB speaker) { PhraseBank phraseBank = PhraseBank.Get("duck", Mobs_.DuckDefaults); for (int i = 0; i < 8; i++) { string text = Categories[Random.Range(0, Categories.Length)]; string playerName = null; if (text == "insult_friend") { List<PlayerControllerB> list = new List<PlayerControllerB>(); PlayerControllerB[] allPlayerScripts = sor.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val != (Object)null && (Object)(object)val != (Object)(object)speaker && val.isPlayerControlled) { list.Add(val); } } if (list.Count == 0) { continue; } playerName = PlayerNames.Spoken(list[Random.Range(0, list.Count)]); } string text2 = phraseBank.Pick(text, playerName, allowRepeat: true); if (!string.IsNullOrEmpty(text2)) { return text2; } } return null; } internal static byte[] MatchLoudness(byte[] ulaw, float targetRms) { if (targetRms <= 0f) { return ulaw; } float[] array = MobSpeaker.DecodeUlaw(ulaw); float num = 0f; float[] array2 = array; foreach (float num2 in array2) { num = Mathf.Max(num, Mathf.Abs(num2)); } double num3 = 0.0; int num4 = 0; array2 = array; foreach (float num5 in array2) { if (Mathf.Abs(num5) > num * 0.1f) { num3 += (double)(num5 * num5); num4++; } } if (num4 == 0) { return ulaw; } float num6 = (float)Math.Sqrt(num3 / (double)num4); float num7 = Mathf.Clamp(targetRms / num6, 0.15f, 4f); for (int j = 0; j < array.Length; j++) { array[j] = Mathf.Clamp(array[j] * num7, -0.99f, 0.99f); } return MobSpeaker.EncodeUlaw(array); } internal static void Reset() { next.Clear(); pending.Clear(); } } internal static class DuckSound { private static AudioClip[] clips; private static bool searched; internal static AudioClip Get() { if (!searched) { Find(); } if (clips == null || clips.Length == 0) { return null; } return clips[Random.Range(0, clips.Length)]; } private static void Find() { searched = true; AudioClip val = LoadEmbeddedWav("ChaosCompany.quack.wav"); if ((Object)(object)val != (Object)null) { clips = (AudioClip[])(object)new AudioClip[1] { val }; Plugin.Log.LogInfo((object)"Duck sound: embedded quack"); return; } List<Item> list = (((Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.allItemsList != (Object)null) ? StartOfRound.Instance.allItemsList.itemsList : null); if (list != null) { foreach (Item item in list) { if (!((Object)(object)item == (Object)null) && !((Object)(object)item.spawnPrefab == (Object)null) && item.itemName != null && item.itemName.ToLowerInvariant().IndexOf("duck") >= 0) { NoisemakerProp component = item.spawnPrefab.GetComponent<NoisemakerProp>(); if ((Object)(object)component != (Object)null && component.noiseSFX != null && component.noiseSFX.Length != 0) { clips = component.noiseSFX; Plugin.Log.LogInfo((object)$"Duck sound: using '{item.itemName}' ({clips.Length} clips)"); return; } } } } clips = (AudioClip[])(object)new AudioClip[1] { Synth() }; Plugin.Log.LogWarning((object)"Duck sound: Rubber Ducky not found, using synthesized quack"); } private static AudioClip LoadEmbeddedWav(string name) { try { using Stream stream = typeof(DuckSound).Assembly.GetManifestResourceStream(name); if (stream == null) { return null; } byte[] array = new byte[stream.Length]; stream.Read(array, 0, array.Length); int num = BitConverter.ToInt16(array, 22); int num2 = BitConverter.ToInt32(array, 24); int i = 12; int num3 = -1; int num4 = 0; int num5; for (; i + 8 <= array.Length; i += 8 + num5) { string text = Encoding.ASCII.GetString(array, i, 4); num5 = BitConverter.ToInt32(array, i + 4); if (text == "data") { num3 = i + 8; num4 = num5; break; } } if (num3 < 0) { return null; } int num6 = num4 / 2 / num; float[] array2 = new float[num6]; for (int j = 0; j < num6; j++) { array2[j] = (float)BitConverter.ToInt16(array, num3 + j * 2 * num) / 32768f; } AudioClip obj = AudioClip.Create("chaos_quack", num6, 1, num2, false); obj.SetData(array2, 0); return obj; } catch (Exception ex) { Plugin.Log.LogWarning((object)("Embedded sound " + name + ": " + ex.Message)); return null; } } private static AudioClip Synth() { int num = 44100; int num2 = (int)((float)num * 0.22f); float[] array = new float[num2]; float num3 = 0f; float num4 = 0f; for (int i = 0; i < num2; i++) { float num5 = (float)i / (float)num2; float num6 = Mathf.Lerp(620f, 380f, num5); num3 += num6 / (float)num; num3 -= Mathf.Floor(num3); float num7 = num3 * 2f - 1f; num4 += 0.35f * (num7 - num4); float num8 = Mathf.Min(1f, num5 * 25f) * (1f - num5) * (1f - num5); array[i] = (num7 - num4) * num8 * 0.8f; } AudioClip obj = AudioClip.Create("chaos_quack", num2, 1, num, false); obj.SetData(array, 0); return obj; } } internal class EchoMonitor : MonoBehaviour, IMicrophoneSubscriber { private static EchoMonitor instance; private static bool wanted; public static float Volume = 1f; private AudioSource source; private VoiceFilter filter; private DissonanceComms comms; private const int RingSize = 65536; private readonly float[] ring = new float[65536]; private readonly object sync = new object(); private long writePos; private double readPos; private volatile int micRate = 48000; private int outRate = 48000; private volatile bool transmitting; private volatile float volume = 1f; private float gate; private float peak; public static float Level { get; private set; } public static bool Enabled { get { return wanted; } set { wanted = value; if (value) { TryCreate(); } else { Shutdown(); } } } internal static VoiceFilter Filter { get { if (!((Object)(object)instance != (Object)null)) { return null; } return instance.filter; } } internal static void EnsureState() { if (wanted && (Object)(object)instance == (Object)null) { TryCreate(); } } internal static void Shutdown() { if ((Object)(object)instance != (Object)null) { Object.Destroy((Object)(object)((Component)instance).gameObject); } instance = null; Level = 0f; } private static void TryCreate() { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown if (!((Object)(object)instance != (Object)null)) { DissonanceComms val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.voiceChatModule : null); if (!((Object)(object)val == (Object)null) && !((Object)(object)SoundManager.Instance == (Object)null)) { GameObject val2 = new GameObject("ChaosCompany_EchoMonitor"); AudioSource val3 = val2.AddComponent<AudioSource>(); instance = val2.AddComponent<EchoMonitor>(); instance.filter = val2.AddComponent<VoiceFilter>(); instance.source = val3; instance.comms = val; int outputSampleRate = AudioSettings.outputSampleRate; val3.clip = AudioClip.Create("chaos_silence", outputSampleRate, 1, outputSampleRate, false); val3.loop = true; val3.spatialBlend = 0f; val3.playOnAwake = false; val3.Play(); val.SubscribeToRecordedAudio((IMicrophoneSubscriber)(object)instance); Plugin.Log.LogInfo((object)"Echo monitor ON"); } } } private void Awake() { outRate = AudioSettings.outputSampleRate; } private void Update() { PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if ((Object)(object)val != (Object)null && (Object)(object)SoundManager.Instance != (Object)null) { AudioMixerGroup[] playerVoiceMixers = SoundManager.Instance.playerVoiceMixers; int num = (int)val.playerClientId; if (playerVoiceMixers != null && num < playerVoiceMixers.Length && (Object)(object)source.outputAudioMixerGroup != (Object)(object)playerVoiceMixers[num]) { source.outputAudioMixerGroup = playerVoiceMixers[num]; } } VoicePlayerState val2 = (((Object)(object)comms != (Object)null) ? comms.FindPlayer(comms.LocalPlayerName) : null); transmitting = val2 != null && val2.IsSpeaking; volume = Volume; Level = Mathf.Lerp(Level, peak, 0.3f); peak *= 0.8f; } private void OnDestroy() { if ((Object)(object)comms != (Object)null) { comms.UnsubscribeFromRecordedAudio((IMicrophoneSubscriber)(object)this); } Plugin.Log.LogInfo((object)"Echo monitor OFF"); } public void ReceiveMicrophoneData(ArraySegment<float> buffer, WaveFormat format) { int num = Math.Max(1, format.Channels); micRate = format.SampleRate; float num2 = 0f; lock (sync) { for (int i = buffer.Offset; i < buffer.Offset + buffer.Count; i += num) { float num3 = buffer.Array[i]; ring[writePos & 0xFFFF] = num3; writePos++; if (num3 > num2) { num2 = num3; } else if (0f - num3 > num2) { num2 = 0f - num3; } } } if (num2 > peak) { peak = num2; } } public void Reset() { lock (sync) { writePos = 0L; readPos = 0.0; } } private void OnAudioFilterRead(float[] data, int channels) { double num = (double)micRate / (double)outRate; float num2 = (transmitting ? 1f : 0f); float num3 = volume; lock (sync) { if ((double)writePos - readPos > (double)micRate * 0.3) { readPos = (double)writePos - (double)micRate * 0.06; } if (readPos < (double)(writePos - 65536 + 2)) { readPos = writePos - 65536 + 2; } for (int i = 0; i < data.Length; i += channels) { float num4 = 0f; long num5 = (long)readPos; if (num5 + 1 < writePos) { float num6 = (float)(readPos - (double)num5); float num7 = ring[num5 & 0xFFFF]; float num8 = ring[(num5 + 1) & 0xFFFF]; num4 = num7 + (num8 - num7) * num6; readPos += num; } gate += (num2 - gate) * 0.002f; num4 *= gate * num3; for (int j = 0; j < channels; j++) { data[i + j] = num4; } } } } } internal static class VoiceConsent { private static readonly Dictionary<int, bool> allowed = new Dictionary<int, bool>(); internal static string Mine => Plugin.VoiceConsent.Value; internal static bool NeedsAnswer => Mine == "Ask"; internal static void Reset() { allowed.Clear(); } internal static bool IsAllowed(PlayerControllerB p) { bool value = default(bool); return (Object)(object)p != (Object)null && allowed.TryGetValue((int)p.playerClientId, out value) && value; } internal static void SetMine(bool allow) { Plugin.VoiceConsent.Value = (allow ? "Allow" : "Deny"); SendMine(); } internal static void SendMine() { PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if (!((Object)(object)val == (Object)null) && !NeedsAnswer) { ChaosEvents.SendConsent((int)val.playerClientId, Mine == "Allow"); } } internal static void OnConsent(int player, bool allow) { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null) && player >= 0 && player < instance.allPlayerScripts.Length) { allowed[player] = allow; PlayerControllerB val = instance.allPlayerScripts[player]; Plugin.Log.LogInfo((object)("Voice consent: " + val.playerUsername + " -> " + (allow ? "allowed" : "denied"))); if (!allow) { VoiceRecorder.Delete(VoiceRecorder.Key(val)); } } } } internal class ConsentPrompt : MonoBehaviour { private float showAt; private bool visible; private Rect window; private bool sent; private void Start() { showAt = Time.time + 6f; } private void Update() { if (!sent && !VoiceConsent.NeedsAnswer && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.localPlayerController != (Object)null) { VoiceConsent.SendMine(); sent = true; } bool flag = VoiceConsent.NeedsAnswer && Time.time >= showAt && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.localPlayerController != (Object)null; if (flag != visible) { visible = flag; SetInputBlocked(visible); } if (visible) { Cursor.lockState = (CursorLockMode)0; Cursor.visible = true; } } private static void SetInputBlocked(bool blocked) { PlayerControllerB val = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.localPlayerController : null); if (!((Object)(object)val == (Object)null)) { val.disableLookInput = blocked; val.disableMoveInput = blocked; val.disableInteract = blocked; if (!blocked) { Cursor.lockState = (CursorLockMode)1; Cursor.visible = false; } } } private void OnGUI() { //IL_002a: 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_0068: 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_0078: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Expected O, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (visible) { GUI.depth = -10; float num = (float)Screen.height / 1080f * 1.6f; GUI.matrix = Matrix4x4.Scale(new Vector3(num, num, 1f)); float num2 = 560f; float num3 = 300f; window = new Rect(((float)Screen.width / num - num2) / 2f, ((float)Screen.height / num - num3) / 2f, num2, num3); GUILayout.Window(805382, window, new WindowFunction(Draw), "ChaosCompany", Array.Empty<GUILayoutOption>()); } } private void Draw(int id) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Expected O, but got Unknown GUIStyle val = new GUIStyle(GUI.skin.label) { wordWrap = true, fontSize = 15 }; GUILayout.Label("На этом сервере стоит мод ChaosCompany: монстры могут говорить голосами игроков.\n\nРазрешаешь хосту записывать твой голос для этого? Записи хранятся только у хоста. Согласие можно отозвать в любой момент в настройках мода (VoiceConsent) - тогда хост удалит твои записи.\n\nThis server runs ChaosCompany: monsters can speak with players' voices. Allow the host to record your voice for that? Stored only on the host's PC, can be revoked any time.", val, Array.Empty<GUILayoutOption>()); GUILayout.FlexibleSpace(); GUILayout.BeginHorizontal(Array.Empty<GUILayoutOption>()); if (GUILayout.Button("Разрешаю / Allow", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) })) { Answer(allow: true); } if (GUILayout.Button("Не разрешаю / Deny", (GUILayoutOption[])(object)new GUILayoutOption[1] { GUILayout.Height(40f) })) { Answer(allow: false); } GUILayout.EndHorizontal(); } private void Answer(bool allow) { VoiceConsent.SetMine(allow); sent = true; visible = false; SetInputBlocked(blocked: false); } } internal static class VoiceEffects { internal static float[] PitchMul = new float[0]; private static bool[] pitchOverridden = new bool[0]; private static float[] nextQuack = new float[0]; private static float[] muteUntil = new float[0]; private static readonly Dictionary<int, AudioSource> quackSources = new Dictionary<int, AudioSource>(); private static readonly Dictionary<AudioSource, VoiceFilter> filters = new Dictionary<AudioSource, VoiceFilter>(); private static readonly Dictionary<int, AudioSource> insertSources = new Dictionary<int, AudioSource>(); internal static void Reset() { PitchMul = new float[0]; pitchOverridden = new bool[0]; nextQuack = new float[0]; muteUntil = new float[0]; quackSources.Clear(); insertSources.Clear(); filters.Clear(); } internal static void Update() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || instance.allPlayerScripts == null) { return; } PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; EnsureArrays(allPlayerScripts.Length); float time = Time.time; PlayerControllerB localPlayerController = instance.localPlayerController; bool flag = (Object)(object)localPlayerController != (Object)null && !localPlayerController.isPlayerDead && EffectManager.Has((int)localPlayerController.playerClientId, EffectId.Drunk); for (int i = 0; i < allPlayerScripts.Length; i++) { PlayerControllerB val = allPlayerScripts[i]; if ((Object)(object)val == (Object)null) { continue; } bool num = val.isPlayerControlled && !val.isPlayerDead; float num2 = 1f; float num3 = 0f; if (num) { if (EffectManager.Has(i, EffectId.PitchUp)) { num2 *= 1.45f; } if (EffectManager.Has(i, EffectId.PitchDown)) { num2 *= 0.72f; } if (EffectManager.Has(i, EffectId.Wave)) { num2 *= 1f + 0.28f * Mathf.Sin(time * 2f * MathF.PI * 0.6f + (float)i); } if (EffectManager.Has(i, EffectId.Drunk)) { num2 *= 1f + 0.18f * (Mathf.PerlinNoise(time * 0.7f, (float)i * 3.1f) * 2f - 1f); num3 = 2200f; } if (EffectManager.Has(i, EffectId.Muffled)) { num3 = 500f; } } PitchMul[i] = num2; bool flag2 = (Object)(object)val == (Object)(object)instance.localPlayerController; if (!flag2 && flag) { num3 = ((num3 > 0f) ? Mathf.Min(num3, 1200f) : 1200f); } VoiceFilter voiceFilter = (flag2 ? EchoMonitor.Filter : GetFilter(val.currentVoiceChatAudioSource)); if (num && EffectManager.Has(i, EffectId.Duck)) { UpdateDuck(val, i, flag2, time); } if ((Object)(object)voiceFilter != (Object)null) { voiceFilter.LowpassHz = num3; voiceFilter.Gain = ((time < muteUntil[i]) ? 0f : 1f); } } } internal static void ApplyPitch(SoundManager sm) { float[] playerVoicePitches = sm.playerVoicePitches; if (playerVoicePitches == null) { return; } int num = Mathf.Min(PitchMul.Length, playerVoicePitches.Length); for (int i = 0; i < num; i++) { if (!Mathf.Approximately(PitchMul[i], 1f)) { sm.SetPlayerPitch(playerVoicePitches[i] * PitchMul[i], i); pitchOverridden[i] = true; } else if (pitchOverridden[i]) { sm.SetPlayerPitch(playerVoicePitches[i], i); pitchOverridden[i] = false; } } } private static VoiceFilter GetFilter(AudioSource src) { if ((Object)(object)src == (Object)null) { return null; } if (filters.TryGetValue(src, out var value) && (Object)(object)value != (Object)null) { return value; } value = ((Component)src).GetComponent<VoiceFilter>(); if ((Object)(object)((Component)src).GetComponent<VoiceTap>() == (Object)null) { if ((Object)(object)value != (Object)null) { Object.DestroyImmediate((Object)(object)value); } ((Component)src).gameObject.AddComponent<VoiceTap>(); value = null; } if ((Object)(object)value == (Object)null) { value = ((Component)src).gameObject.AddComponent<VoiceFilter>(); } filters[src] = value; return value; } private static void UpdateDuck(PlayerControllerB p, int i, bool isLocal, float t) { bool flag; if (isLocal) { DissonanceComms voiceChatModule = StartOfRound.Instance.voiceChatModule; VoicePlayerState val = (((Object)(object)voiceChatModule != (Object)null) ? voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName) : null); flag = val != null && val.IsSpeaking; } else { flag = p.voicePlayerState != null && p.voicePlayerState.IsSpeaking; } if (!flag) { if (nextQuack[i] < t + 0.7f) { nextQuack[i] = t + 0.7f; } } else if (!(t < nextQuack[i])) { AudioClip val2 = DuckSound.Get(); if (!((Object)(object)val2 == (Object)null)) { AudioSource quackSource = GetQuackSource(p, i, isLocal); quackSource.pitch = Random.Range(0.9f, 1.2f); quackSource.PlayOneShot(val2, Mathf.Clamp(Plugin.DuckVolume.Value, 0f, 4f)); float num = Mathf.Clamp(val2.length / quackSource.pitch, 0.35f, 1f); muteUntil[i] = t + num; nextQuack[i] = t + num + Random.Range(1.2f, 3f); } } } internal static void PlayInsert(int player, byte[] ulaw) { StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance == (Object)null) && ulaw != null && player >= 0 && player < instance.allPlayerScripts.Length) { PlayerControllerB val = instance.allPlayerScripts[player]; EnsureArrays(instance.allPlayerScripts.Length); AudioClip val2 = MobSpeaker.DecodeVoice(ulaw); GetInsertSource(val, player, (Object)(object)val == (Object)(object)instance.localPlayerController).PlayOneShot(val2, 1f); muteUntil[player] = Time.time + val2.length + 0.15f; Object.Destroy((Object)(object)val2, val2.length + 1f); } } private static AudioSource GetInsertSource(PlayerControllerB p, int i, bool isLocal) { //IL_001d: 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_0034: 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_00b2: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00f3: Invalid comparison between Unknown and I4 if (!insertSources.TryGetValue(i, out var value) || (Object)(object)value == (Object)null) { GameObject val = new GameObject("ChaosCompany_VoiceInsert"); val.transform.SetParent(((Component)p).transform, false); val.transform.localPosition = new Vector3(0f, 1.6f, 0f); value = val.AddComponent<AudioSource>(); value.playOnAwake = false; insertSources[i] = value; } AudioSource currentVoiceChatAudioSource = p.currentVoiceChatAudioSource; if (isLocal || (Object)(object)currentVoiceChatAudioSource == (Object)null) { value.spatialBlend = 0f; return value; } value.outputAudioMixerGroup = currentVoiceChatAudioSource.outputAudioMixerGroup; value.volume = currentVoiceChatAudioSource.volume; value.spatialBlend = currentVoiceChatAudioSource.spatialBlend; value.rolloffMode = currentVoiceChatAudioSource.rolloffMode; value.minDistance = currentVoiceChatAudioSource.minDistance; value.maxDistance = currentVoiceChatAudioSource.maxDistance; value.spread = currentVoiceChatAudioSource.spread; value.dopplerLevel = currentVoiceChatAudioSource.dopplerLevel; if ((int)currentVoiceChatAudioSource.rolloffMode == 2) { value.SetCustomCurve((AudioSourceCurveType)0, currentVoiceChatAudioSource.GetCustomCurve((AudioSourceCurveType)0)); } return value; } private static AudioSource GetQuackSource(PlayerControllerB p, int i, bool isLocal) { //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0036: 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) if (quackSources.TryGetValue(i, out var value) && (Object)(object)value != (Object)null) { return value; } GameObject val = new GameObject("ChaosCompany_Quack"); val.transform.SetParent(((Component)p).transform, false); val.transform.localPosition = new Vector3(0f, 1.6f, 0f); value = val.AddComponent<AudioSource>(); value.playOnAwake = false; value.spatialBlend = (isLocal ? 0f : 1f); value.rolloffMode = (AudioRolloffMode)1; value.minDistance = 2f; value.maxDistance = 35f; quackSources[i] = value; return value; } private static void EnsureArrays(int n) { if (PitchMul.Length != n) { PitchMul = new float[n]; for (int i = 0; i < n; i++) { PitchMul[i] = 1f; } pitchOverridden = new bool[n]; nextQuack = new float[n]; muteUntil = new float[n]; } } } internal class VoiceFilter : MonoBehaviour { public volatile float LowpassHz; public volatile float Gain = 1f; private int sampleRate = 48000; private float gain = 1f; private readonly float[] z1 = new float[8]; private readonly float[] z2 = new float[8]; private void Awake() { sampleRate = AudioSettings.outputSampleRate; } private void OnAudioFilterRead(float[] data, int channels) { float lowpassHz = LowpassHz; float num = Gain; if (channels > 8) { return; } if (lowpassHz <= 0f && num >= 1f && gain >= 0.999f) { gain = 1f; return; } float num2 = ((lowpassHz > 0f) ? (1f - Mathf.Exp(MathF.PI * -2f * lowpassHz / (float)sampleRate)) : 0f); float num3 = 1f / (0.005f * (float)sampleRate); for (int i = 0; i < data.Length; i += channels) { gain = Mathf.MoveTowards(gain, num, num3); for (int j = 0; j < channels; j++) { float num4 = data[i + j]; if (lowpassHz > 0f) { z1[j] += num2 * (num4 - z1[j]); z2[j] += num2 * (z1[j] - z2[j]); num4 = z2[j] * 1.4f; } data[i + j] = num4 * gain; } } } } internal static class VoiceRecorder { private class Segment { public readonly List<float> Samples = new List<float>(); public int Rate; public float LastSpeech; } private const int OutRate = 24000; private const float MinSegment = 2f; private const float MaxSegment = 12f; private const float SilenceGap = 0.8f; private static readonly Dictionary<string, Segment> segments = new Dictionary<string, Segment>(); private static readonly Dictionary<string, float> seconds = new Dictionary<string, float>(); private static MicTap mic; internal static string Root => Path.Combine(Application.persistentDataPath, "ChaosCompany_voices"); private static bool IsHost { get { NetworkManager singleton = NetworkManager.Singleton; if (!((Object)(object)singleton == (Object)null) && singleton.IsListening) { return singleton.IsServer; } return true; } } internal static string Key(PlayerControllerB p) { if (p.playerSteamId != 0L) { return p.playerSteamId.ToString(); } StringBuilder stringBuilder = new StringBuilder(); string playerUsername = p.playerUsername; foreach (char c in playerUsername) { stringBuilder.Append(char.IsLetterOrDigit(c) ? c : '_'); } return "nick_" + stringBuilder; } internal static void Update() { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || !Plugin.RecordVoices.Value || !IsHost) { return; } float time = Time.time; EnsureMic(instance); PlayerControllerB[] allPlayerScripts = instance.allPlayerScripts; foreach (PlayerControllerB val in allPlayerScripts) { if ((Object)(object)val == (Object)null || !val.isPlayerControlled) { continue; } bool flag = (Object)(object)val == (Object)(object)instance.localPlayerController; bool flag2 = VoiceConsent.IsAllowed(val); VoiceTap voiceTap = (flag ? null : (((Object)(object)val.currentVoiceChatAudioSource != (Object)null) ? ((Component)val.currentVoiceChatAudioSource).GetComponent<VoiceTap>() : null)); if (!flag2) { if (flag && mic != null) { mic.Capture = false; } if ((Object)(object)voiceTap != (Object)null) { voiceTap.Capture = false; } continue; } string key = Key(val); bool flag3 = RecordedSeconds(key) >= Plugin.MaxVoiceSecondsPerPlayer.Value; bool flag4; ConcurrentQueue<float[]> chunks; int rate; if (flag) { if (mic == null) { continue; } DissonanceComms voiceChatModule = instance.voiceChatModule; VoicePlayerState val2 = (((Object)(object)voiceChatModule != (Object)null) ? voiceChatModule.FindPlayer(voiceChatModule.LocalPlayerName) : null); flag4 = val2 != null && val2.IsSpeaking && !val.isPlayerDead; mic.Capture = flag4 && !flag3; chunks = mic.Chunks; rate = mic.Rate; } else { if ((Object)(object)voiceTap == (Object)null) { continue; } flag4 = val.voicePlayerState != null && val.voicePlayerState.IsSpeaking && IsClean(val.currentVoiceChatAudioSource); voiceTap.Capture = flag4 && !flag3; chunks = voiceTap.Chunks; rate = voiceTap.Rate; } if (!segments.TryGetValue(key, out var value)) { value = (segments[key] = new Segment()); } float[] result; while (chunks.TryDequeue(out result)) { value.Rate = rate; value.Samples.AddRange(result); } if (flag4) { value.LastSpeech = time; } float num = ((value.Rate > 0) ? ((float)value.Samples.Count / (float)value.Rate) : 0f); if (num > 0f && (time - value.LastSpeech > 0.8f || num >= 12f)) { if (num >= 2f) { Save(key, value.Samples.ToArray(), value.Rate, val.playerUsername); } value.Samples.Clear(); } } } internal static float UpdateRms(float current, float[] chunk) { double num = 0.0; foreach (float num2 in chunk) { num += (double)(num2 * num2); } float num3 = (float)Math.Sqrt(num / (double)Math.Max(1, chunk.Length)); if (num3 < 0.005f) { return current; } if (!(current <= 0f)) { return current * 0.97f + num3 * 0.03f; } return num3; } internal static float VoiceRms(PlayerControllerB p) { StartOfRound instance = StartOfRound.Instance; if ((Object)(object)instance == (Object)null || (Object)(object)p == (Object)null) { return 0f; } if ((Object)(object)p == (Object)(object)instance.localPlayerController) { if (mic == null) { return 0f; } return mic.Rms; } VoiceTap voiceTap = (((Object)(object)p.currentVoiceChatAudioSource != (Object)null) ? ((Component)p.currentVoiceChatAudioSource).GetComponent<VoiceTap>() : null); if (!((Object)(object)voiceTap != (Object)null)) { return 0f; } return voiceTap.Rms; } private static bool IsClean(AudioSource src) { AudioLowPassFilter component = ((Component)src).GetComponent<AudioLowPassFilter>(); AudioHighPassFilter component2 = ((Component)src).GetComponent<AudioHighPassFilter>(); bool num = (Object)(object)component == (Object)null || !((Behaviour)component).enabled || component.cutoffFrequency >= 15000f; bool flag = (Object)(object)component2 == (Object)null || !((Behaviour)component2).enabled; return num && flag; } private static void EnsureMic(StartOfRound sor) { if (mic == null && !((Object)(object)sor.voiceChatModule == (Object)null)) { mic = new MicTap(); sor.voiceChatModule.SubscribeToRecordedAudio((IMicrophoneSubscriber)(object)mic); } } internal static void OnSessionEnd() { if (mic != null && (Object)(object)StartOfRound.Instance != (Object)null && (Object)(object)StartOfRound.Instance.voiceChatModule != (Object)null) { StartOfRound.Instance.voiceChatModule.UnsubscribeFromRecordedAudio((IMicrophoneSubscriber)(object)mic); } mic = null; segments.Clear(); } private static void Save(string key, float[] samples, int rate, string nick) { float num = (float)samples.Length / (float)rate; seconds[key] = RecordedSeconds(key) + num; Task.Run(delegate { try { float[] array = Resample(samples, rate, 24000); Normalize(array); string text = Path.Combine(Root, key); Directory.CreateDirectory(text); File.WriteAllText(Path.Combine(text, "player.txt"), nick); WriteWav(Path.Combine(text, DateTime.Now.ToString("yyyyMMdd_HHmmss_fff") + ".wav"), array, 24000); TrimOldest(key, text); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Voice record: " + ex.Message)); } }); Plugin.Log.LogInfo((object)$"Voice recorded (consent given): {nick} +{num:0.0}s"); } private static void TrimOldest(string key, string dir) { List<string> list = new List<string>(Directory.GetFiles(dir, "*.wav")); list.Sort(StringComparer.Ordinal); float num = 0f; foreach (string item in list) { num += WavSeconds(item); } while (num > Plugin.MaxVoiceSecondsPerPlayer.Value && list.Count > 1) { num -= WavSeconds(list[0]); File.Delete(list[0]); list.RemoveAt(0); } seconds[key] = num; } private static float WavSeconds(string file) { return (float)Math.Max(0L, new FileInfo(file).Length - 44) / 2f / 24000f; } internal static float RecordedSeconds(string key) { if (seconds.TryGetValue(key, out var value)) { return value; } float num = 0f; string path = Path.Combine(Root, key); if (Directory.Exists(path)) { string[] files = Directory.GetFiles(path, "*.wav"); foreach (string file in files) { num += WavSeconds(file); } } seconds[key] = num; return num; } internal static void Delete(string key) { try { string path = Path.Combine(Root, key); if (Directory.Exists(path)) { Directory.Delete(path, recursive: true); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Voice delete: " + ex.Message)); } seconds[key] = 0f; if (segments.TryGetValue(key, out var value)) { value.Samples.Clear(); } Plugin.Log.LogInfo((object)("Voice recordings deleted: " + key)); } private static float[] Resample(float[] src, int from, int to) { if (from == to) { return src; } int num = (int)((long)src.Length * (long)to / from); float[] array = new float[num]; double num2 = (double)from / (double)to; for (int i = 0; i < num; i++) { double num3 = (double)i * num2; int num4 = (int)num3; int num5 = Math.Min(num4 + 1, src.Length - 1); float num6 = (float)(num3 - (double)num4); array[i] = src[num4] + (src[num5] - src[num4]) * num6; } return array; } private static void Normalize(float[] a) { float num = 0f; foreach (float value in a) { num = Math.Max(num, Math.Abs(value)); } if (!(num < 0.0001f)) { float num2 = 0.9f / num; for (int j = 0; j < a.Length; j++) { a[j] *= num2; } } } private static void WriteWav(string path, float[] data, int rate) { using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path)); int num = data.Length * 2; binaryWriter.Write(new char[4] { 'R', 'I', 'F', 'F' }); binaryWriter.Write(36 + num); binaryWriter.Write(new char[4] { 'W', 'A', 'V', 'E' }); binaryWriter.Write(new char[4] { 'f', 'm', 't', ' ' }); binaryWriter.Write(16); binaryWriter.Write((short)1); binaryWriter.Write((short)1); binaryWriter.Write(rate); binaryWriter.Write(rate * 2); binaryWriter.Write((short)2); binaryWriter.Write((short)16); binaryWriter.Write(new char[4] { 'd', 'a', 't', 'a' }); binaryWriter.Write(num); foreach (float num2 in data) { binaryWriter.Write((short)(Mathf.Clamp(num2, -1f, 1f) * 32767f)); } } } internal class VoiceTap : MonoBehaviour { public volatile bool Capture; public volatile float Rms; public readonly ConcurrentQueue<float[]> Chunks = new ConcurrentQueue<float[]>(); public int Rate = 48000; private void Awake() { Rate = AudioSettings.outputSampleRate; } private void OnAudioFilterRead(float[] data, int channels) { if (Capture && Chunks.Count <= 2000) { float[] array = new float[data.Length / channels]; for (int i = 0; i < array.Length; i++) { array[i] = data[i * channels]; } Rms = VoiceRecorder.UpdateRms(Rms, array); Chunks.Enqueue(array); } } } internal class MicTap : IMicrophoneSubscriber { public volatile bool Capture; public volatile float Rms; public readonly ConcurrentQueue<float[]> Chunks = new ConcurrentQueue<float[]>(); public volatile int Rate = 48000; public void ReceiveMicrophoneData(ArraySegment<float> buffer, WaveFormat format) { if (Capture && Chunks.Count <= 2000) { int num = Math.Max(1, format.Channels); Rate = format.SampleRate; float[] array = new float[buffer.Count / num]; for (int i = 0; i < array.Length; i++) { array[i] = buffer.Array[buffer.Offset + i * num]; } Rms = VoiceRecorder.UpdateRms(Rms, array); Chunks.Enqueue(array); } } public void Reset() { } } } namespace ChaosCompany.Speech { internal class MobSpeaker : MonoBehaviour { public float VoicePitch = 150f; public bool Sad; public float HeadHeight = 1.2f; public Transform Head; private AudioSource source; private TextMeshPro text; private float hideAt; private float speakingUntil; private float pendingUntil; private AudioClip lastClip; private static TMP_FontAsset cyrillicFont; internal bool IsBusy { get { if (!(Time.time < speakingUntil)) { return Time.time < pendingUntil; } return true; } } internal float BusyUntil => Mathf.Max(speakingUntil, pendingUntil); internal void MarkPending(float timeout) { pendingUntil = Time.time + timeout; } private void Awake() { //IL_005e: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Expected O, but got Unknown //IL_00d3: Unknown result type (might be due to invalid IL or missing references) //IL_00f2: Unknown result type (might be due to invalid IL or missing references) //IL_0112: Unknown result type (might be due to invalid IL or missing references) //IL_0117: Unknown result type (might be due to invalid IL or missing references) source = ((Component)this).gameObject.AddComponent<AudioSource>(); source.spatialBlend = 1f; source.rolloffMode = (AudioRolloffMode)1; source.minDistance = 4f; source.maxDistance = 35f; source.playOnAwake = false; GameObject val = new GameObject("ChaosCompany_Subtitle"); val.transform.SetParent(((Component)this).transform, false); text = val.AddComponent<TextMeshPro>(); ((TMP_Text)text).font = GetFont(); ((TMP_Text)text).fontSize = 2.2f; ((TMP_Text)text).alignment = (TextAlignmentOptions)514; ((TMP_Text)text).enableWordWrapping = true; ((TMP_Text)text).rectTransform.sizeDelta = new Vector2(4f, 2f); ((Graphic)text).color = new Color(1f, 0.95f, 0.75f); ((TMP_Text)text).outlineWidth = 0.2f; ((TMP_Text)text).outlineColor = Color32.op_Implicit(Color.black); ((TMP_Text)text).text = ""; } private static TMP_FontAsset GetFont() { if ((Object)(object)cyrillicFont == (Object)null) { try { cyrillicFont = TMP_FontAsset.CreateFontAsset(Font.CreateDynamicFontFromOSFont(new string[3] { "Arial", "Segoe UI", "Tahoma" }, 64)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Subtitle font: " + ex.Message)); } } return cyrillicFont; } internal void Show(string line, byte[] voice = null) { if (!string.IsNullOrEmpty(line)) { ((TMP_Text)text).text = line; AudioClip val = ((voice != null && voice.Length > 100) ? DecodeVoice(voice) : Mumble.Make(line, VoicePitch, Sad)); hideAt = Time.time + Mathf.Max(val.length + 1f, Mathf.Clamp((float)line.Length * 0.07f, 2.5f, 7f)); speakingUntil = Time.time + val.length + 0.4f; pendingUntil = 0f; source.Stop(); source.clip = val; source.Play(); if ((Object)(object)lastClip != (Object)null) { Object.Destroy((Object)(object)lastClip); } lastClip = val; } } internal static float[] DecodeUlaw(byte[] ulaw) { float[] array = new float[ulaw.Length]; for (int i = 0; i < ulaw.Length; i++) { float num = (float)(int)ulaw[i] / 127.5f - 1f; array[i] = Mathf.Sign(num) * (Mathf.Pow(256f, Mathf.Abs(num)) - 1f) / 255f; } return array; } internal static byte[] EncodeUlaw(float[] data) { byte[] array = new byte[data.Length]; float num = Mathf.Log(256f); for (int i = 0; i < data.Length; i++) { float num2 = Mathf.Clamp(data[i], -1f, 1f); float num3 = Mathf.Sign(num2) * Mathf.Log(1f + 255f * Mathf.Abs(num2)) / num; array[i] = (byte)Mathf.Clamp(Mathf.RoundToInt((num3 + 1f) * 127.5f), 0, 255); } return array; } internal static AudioClip DecodeVoice(byte[] ulaw) { float[] array = new float[ulaw.Length]; for (int i = 0; i < ulaw.Length; i++) { float num = (float)(int)ulaw[i] / 127.5f - 1f; array[i] = Mathf.Sign(num) * (Mathf.Pow(256f, Mathf.Abs(num)) - 1f) / 255f; } AudioClip obj = AudioClip.Create("chaos_voice", array.Length, 1, 16000, false); obj.SetData(array, 0); return obj; } private void LateUpdate() { //IL_007b: 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_008b: 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_00d8: 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_00e8: Unknown result type (might be due to invalid IL or missing references) //IL_00ed: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)text == (Object)null) { return; } if (((TMP_Text)text).text.Length > 0 && Time.time > hideAt) { ((TMP_Text)text).text = ""; } if (((TMP_Text)text).text.Length != 0) { Transform val = (((Object)(object)Head != (Object)null) ? Head : ((Component)this).transform); text.transform.position = val.position + Vector3.up * HeadHeight; Camera val2 = (((Object)(object)StartOfRound.Instance != (Object)null) ? StartOfRound.Instance.activeCamera : Camera.main); if ((Object)(object)val2 != (Object)null) { text.transform.rotation = Quaternion.LookRotation(text.transform.position - ((Component)val2).transform.position); } } } private void OnDestroy() { if ((Object)(object)lastClip != (Object)null) { Object.Destroy((Object)(object)lastClip); } } } internal static class Mumble { private const int Rate = 44100; internal static AudioClip Make(string text, float basePitch, bool sad) { int num = 0; string text2 = text.ToLowerInvariant(); foreach (char value in text2) { if ("аеёиоуыэюяaeiouy".IndexOf(value) >= 0) { num++; } } num = Mathf.Clamp(num, 2, 40); float num2 = 0.12f; float num3 = 0.03f; int num4 = (int)(44100f * ((float)num * (num2 + num3) + 0.1f)); float[] array = new float[num4]; int num5 = 0; float num6 = 0f; for (int j = 0; j < num; j++) { float num7 = (float)j / (float)num; float num8 = (sad ? Mathf.Lerp(1.05f, 0.8f, num7) : 1f); float num9 = basePitch * num8 * Random.Range(0.88f, 1.12f); float num10 = num2 * Random.Range(0.8f, 1.25f); int num11 = (int)(44100f * num10); float num12 = Random.Range(0.3f, 1f); for (int k = 0; k < num11 && num5 + k < num4; k++) { float num13 = (float)k / (float)num11; float num14 = num9 * (1f - 0.08f * num13); num6 += num14 / 44100f; num6 -= Mathf.Floor(num6); float num15 = Mathf.Sin(MathF.PI * 2f * num6) + 0.5f * num12 * Mathf.Sin(MathF.PI * 4f * num6) + 0.25f * num12 * Mathf.Sin(MathF.PI * 6f * num6) + 0.12f * (1f - num12) * Mathf.Sin(MathF.PI * 10f * num6); float num16 = Mathf.Min(1f, num13 * 12f) * Mathf.Min(1f, (1f - num13) * 6f); array[num5 + k] = num15 * num16 * 0.28f; } num5 += num11 + (int)(44100f * num3); if (num5 >= num4) { break; } } AudioClip obj = AudioClip.Create("chaos_mumble", num4, 1, 44100, false); obj.SetData(array, 0); return obj; } } internal class PhraseBank { private readonly Dictionary<string, List<string>> lines = new Dictionary<string, List<string>>(); private readonly Dictionary<string, List<string>> aiLines = new Dictionary<string, List<string>>(); private readonly Dictionary<string, List<string>> fileBag = new Dictionary<string, List<string>>(); private readonly HashSet<string> usedAi = new HashSet<string>(); private string mob; private static readonly Dictionary<string, PhraseBank> banks = new Dictionary<string, PhraseBank>(); internal static string Folder => Path.Combine(Paths.ConfigPath, "ChaosCompany"); internal static PhraseBank Get(string mob, string defaults) { if (!banks.TryGetValue(mob, out var value)) { value = (banks[mob] = Load(mob, defaults)); value.mob = mob; } return value; } internal static void ResetSession() { foreach (PhraseBank value in banks.Values) { value.fileBag.Clear(); } } internal void SetAi(string category, List<string> list) { aiLines[category] = list.FindAll((string l) => !usedAi.Contains(l)); } internal static PhraseBank Load(string mob, string defaults) { PhraseBank phraseBank = new PhraseBank(); Dictionary<string, string> sections; foreach (KeyValuePair<string, List<string>> item in Parse(defaults, out sections)) { phraseBank.lines[item.Key] = item.Value; } try { Directory.CreateDirectory(Folder); string path = Path.Combine(Folder, "phrases_" + mob + ".txt"); if (!File.Exists(path)) { File.WriteAllText(path, defaults, new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); return phraseBank; } Dictionary<string, string> sections2; Dictionary<string, List<string>> dictionary = Parse(File.ReadAllText(path, Encoding.UTF8), out sections2); foreach (KeyValuePair<string, List<string>> item2 in dictionary) { phraseBank.lines[item2.Key] = item2.Value; } StringBuilder stringBuilder = new StringBuilder(); foreach (KeyValuePair<string, string> item3 in sections) { if (!dictionary.ContainsKey(item3.Key)) { stringBuilder.Append("\n").Append(item3.Value); } } if (stringBuilder.Length > 0) { File.AppendAllText(path, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Phrases for " + mob + ": can't use file, using built-in (" + ex.Message + ")")); } return phraseBank; } private static Dictionary<string, List<string>> Parse(string text, out Dictionary<string, string> sections) { Dictionary<string, List<string>> dictionary = new Dictionary<string, List<string>>(); sections = new Dictionary<string, string>(); string key = "default"; StringBuilder stringBuilder = new StringBuilder(); string[] array = text.Replace("\r", "").Split('\n'); foreach (string text2 in array) { string text3 = text2.Trim(); if (text3.StartsWith("[") && text3.EndsWith("]")) { if (stringBuilder.Length > 0) { sections[key] = stringBuilder.ToString(); } key = text3.Substring(1, text3.Length - 2).Trim().ToLowerInvariant(); stringBuilder.Clear(); stringBuilder.Append(text3).Append("\n"); continue; } stringBuilder.Append(text2).Append("\n"); if (text3.Length != 0 && !text3.StartsWith("#")) { if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List<string>()); } value.Add(text3); } } if (stringBuilder.Length > 0) { sections[key] = stringBuilder.ToString(); } return dictionary; } internal string Pick(string category, string playerName = null, bool allowRepeat = false) { string text = null; List<string> value2; if (aiLines.TryGetValue(category, out var value) && value.Count > 0) { int index = Random.Range(0, value.Count); text = value[index]; value.RemoveAt(index); usedAi.Add(text); BrainClient.ReportUsed(mob, category, text); if (value.Count < 3) { BrainClient.RequestRefresh(mob); } } else if (lines.TryGetValue(category, out value2) && value2.Count > 0) { if (aiLines.ContainsKey(category)) { BrainClient.RequestRefresh(mob); } if (!fileBag.TryGetValue(category, out var value3)) { value3 = (fileBag[category] = new List<string>(value2)); } else if (value3.Count == 0) { if (!allowRepeat) { return null; } value3.AddRange(value2); } int index2 = Random.Range(0, value3.Count); text = value3[index2]; value3.RemoveAt(index2); } return text?.Replace("{name}", string.IsNullOrEmpty(playerName) ? "эй ты" : playerName); } } internal static class PlayerNames { private static readonly string[] Anonymous = new string[4] { "дружище", "приятель", "эй, ты", "товарищ" }; private static Dictionary<string, string> variants; private static Dictionary<string, string> nicks; private static string FilePath => Path.Combine(Application.persistentDataPath, "ChaosCompany_names.txt"); private static string Key(PlayerControllerB p) { if (p.playerSteamId == 0L) { return "nick:" + p.playerUsername; } return p.playerSteamId.ToString(); } private static void EnsureLoaded() { if (variants != null) { return; } variants = new Dictionary<string, string>(); nicks = new Dictionary<string, string>(); try { if (!File.Exists(FilePath)) { return; } string[] array = File.ReadAllLines(FilePath, Encoding.UTF8); for (int i = 0; i < array.Length; i++) { string text = array[i]; string text2 = null; int num = text.IndexOf('#'); if (num >= 0) { text2 = text.Substring(num + 1).Trim(); text = text.Substring(0, num); } int num2 = text.IndexOf('='); if (num2 > 0) { string key = text.Substring(0, num2).Trim(); variants[key] = text.Substring(num2 + 1).Trim(); if (text2 != null) { nicks[key] = text2; } } } } catch (Exception ex) { Plugin.Log.LogWarning((object)("Names file: " + ex.Message)); } } internal static string GetVariants(PlayerControllerB p) { if ((Object)(object)p == (Object)null) { return ""; } EnsureLoaded(); if (!variants.TryGetValue(Key(p), out var value)) { return ""; } return value; } internal static void SetVariants(PlayerControllerB p, string csv) { if (!((Object)(object)p == (Object)null)) { EnsureLoaded(); string key = Key(p); variants[key] = (csv ?? "").Trim(); nicks[key] = p.playerUsername; Save(); } } private static void Save() { try { StringBuilder stringBuilder = new StringBuilder(); stringBuilder.AppendLine("# Как мобы ChaosCompany называют игроков. Варианты через запятую."); stringBuilder.AppendLine("# Формат: steamId = Вася, Васёк # ник"); foreach (KeyValuePair<string, string> variant in variants) { if (!string.IsNullOrEmpty(variant.Value)) { stringBuilder.Append(variant.Key).Append(" = ").Append(variant.Value); if (nicks.TryGetValue(variant.Key, out var value)) { stringBuilder.Append(" # ").Append(value); } stringBuilder.AppendLine(); } } File.WriteAllText(FilePath, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: false)); Plugin.Log.LogInfo((object)("Player names saved: " + FilePath)); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Names file: " + ex.Message)); } } internal static string Spoken(PlayerControllerB p) { List<string> list = new List<string>(); string[] array = GetVariants(p).Split(','); for (int i = 0; i < array.Length; i++) { string text = array[i].Trim(); if (text.Length > 0) { list.Add(text); } } if (list.Count == 0) { return Anonymous[Random.Range(0, Anonymous.Length)]; } return list[Random.Range(0, list.Count)]; } internal static bool HasNames(PlayerControllerB p) { return GetVariants(p).Length > 0; } } } namespace ChaosCompany.Patches { [HarmonyPatch(typeof(PlayerControllerB), "DamagePlayer")] internal static class HitEffectPatch { private static void Postfix(PlayerControllerB __instance, int damageNumber, CauseOfDeath causeOfDeath, bool fallDamage) { //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0040: Invalid comparison between Unknown and I4 //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0045: Invalid comparison between Unknown and I4 //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Invalid comparison between Unknown and I4 //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_006e: Unknown result type (might be due to invalid IL or missing references) if (Plugin.HitEffectsEnabled.Value && !((Object)(object)__instance != (Object)(object)GameNetworkManager.Instance?.localPlayerController) && !(__instance.isPlayerDead || damageNumber <= 0 || fallDamage) && (int)causeOfDeath != 2 && (int)causeOfDeath != 9 && (int)causeOfDeath != 5 && (int)causeOfDeath != 3) { EffectId effectId = EffectInfo.Bad[Random.Range(0, EffectInfo.Bad.Length)]; Plugin.Log.LogInfo((object)$"Hit by {causeOfDeath} ({damageNumber} dmg) -> {effectId}"); ChaosApi.ApplyEffect(__instance, effectId, Plugin.HitEffectDuration.Value); } } } [HarmonyPatch(typeof(GameNetworkManager), "Start")] internal static class ItemCreatePatch { private static void Postfix(GameNetworkManager __instance) { NetworkManager component = ((Component)__instance).GetComponent<NetworkManager>(); ItemFactory.CreateAll(component); MobFactory.CreateAll(component); } } [HarmonyPatch(typeof(StartOfRound), "Awake")] internal static class ItemRegisterPatch { private static void Postfix(StartOfRound __instance) { ItemFactory.RegisterInRound(__instance); MobFactory.RegisterInRound(__instance); } } [HarmonyPatch(typeof(ItemCharger), "ChargeItem")] internal static class PortalGunNoChargePatch { private static bool Prefix() { if (GameNetworkManager.Instance?.localPlayerController?.currentlyHeldObjectServer is PortalGun) { if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("Portal gun", "It can't be recharged.", true, false, "LC_Tip1"); } return false; } return true; } } [HarmonyPatch(typeof(StartOfRound), "Start")] internal static class LoadedTipPatch { private static void Postfix(StartOfRound __instance) { Plugin.Log.LogInfo((object)"StartOfRound.Start - ship loaded"); ((MonoBehaviour)__instance).StartCoroutine(ShowTip()); } private static IEnumerator ShowTip() { yield return (object)new WaitForSeconds(3f); if ((Object)(object)HUDManager.Instance != (Object)null) { HUDManager.Instance.DisplayTip("ChaosCompany", "v0.8.0 loaded - chaos is coming", false, false, "LC_Tip1"); } } } [HarmonyPatch(typeof(StartOfRound))] internal static class SessionPatch { [HarmonyPostfix] [HarmonyPatch("Start")] private static void OnStart() { EffectManager.ClearAll(); VoiceEffects.Reset(); BodyEffects.Reset(); PhraseBank.ResetSession(); VoiceConsent.Reset(); DuckInserts.Reset(); ChaosNet.Register(); ChaosRunner.Ensure(); BrainClient.OnSessionStart(); VoiceConsent.SendMine(); } [HarmonyPostfix] [HarmonyPatch("OnDestroy")] private static void OnDestroy() { ChaosNet.Unregister(); EchoMonitor.Shutdown(); VoiceRecorder.OnSessionEnd(); BodyEffects.Reset(); EffectManager.ClearAll(); VoiceEffects.Reset(); Plugin.Log.LogInfo((object)"Session ended - effects cleared"); } } [HarmonyPatch(typeof(SoundManager), "SetPlayerVoiceFilters")] internal static class VoicePitchPatch { private static void Postfix(SoundManager __instance) { VoiceEffects.ApplyPitch(__instance); } } } namespace ChaosCompany.Net { internal interface IMobStateSync { void ReadState(FastBufferReader reader); } internal static class ChaosEvents { [Serializable] [CompilerGenerated] private sealed class <>c { public static readonly <>c <>9 = new <>c(); public static HandleNamedMessageDelegate <>9__19_0; public static HandleNamedMessageDelegate <>9__19_1; public static HandleNamedMessageDelegate <>9__19_2; public static HandleNamedMessageDelegate <>9__19_3; public static HandleNamedMessageDelegate <>9__19_4; public static HandleNamedMessageDelegate <>9__19_5; public static HandleNamedMessageDelegate <>9__19_6; public static HandleNamedMessageDelegate <>9__19_7; public static HandleNamedMessageDelegate <>9__19_8; public static HandleNamedMessageDelegate <>9__19_9; public static HandleNamedMessageDelegate <>9__19_10; internal void <Register>b__19_0(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { byte kind = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives)); ulong id = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives)); ServerTeleport(kind, id); } } internal void <Register>b__19_1(ulong s, FastBufferReader r) { //IL_0013: 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_0026: 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_0047: 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) if (!Net.IsServer) { byte kind = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives)); ulong id = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives)); Vector3 val = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref val); Vector3 to = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref to); ApplyTeleport(kind, id, val, to); } } internal void <Register>b__19_2(ulong s, FastBufferReader r) { //IL_001c: 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_002e: 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_003a: Unknown result type (might be due to invalid IL or missing references) if (Net.IsServer) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref pos); float range = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives)); float loud = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives)); ServerNoise(pos, range, loud); } } internal void <Register>b__19_3(ulong s, FastBufferReader r) { //IL_001c: 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_002e: 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_003a: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsServer) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref pos); float range = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives)); float loud = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives)); ApplyNoise(pos, range, loud); } } internal void <Register>b__19_4(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { byte item = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref item, default(ForPrimitives)); int player = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives)); ServerSpawn((ChaosItem)item, player); } } internal void <Register>b__19_5(ulong s, FastBufferReader r) { //IL_0013: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsServer) { ulong id = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives)); string line = default(string); ((FastBufferReader)(ref r)).ReadValueSafe(ref line, false); int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); byte[] audio = null; if (num != 0 && voiceParts.TryGetValue(num, out var value)) { voiceParts.Remove(num); audio = Join(value); } ShowSay(id, line, audio); } } internal void <Register>b__19_6(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { return; } int player = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives)); int key = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives)); if (voiceParts.TryGetValue(key, out var value)) { voiceParts.Remove(key); byte[] array = Join(value); if (array != null) { VoiceEffects.PlayInsert(player, array); } } } internal void <Register>b__19_7(ulong s, FastBufferReader r) { //IL_0013: 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_0026: 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) if (Net.IsServer) { int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); bool allow = default(bool); ((FastBufferReader)(ref r)).ReadValueSafe<bool>(ref allow, default(ForPrimitives)); StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance != (Object)null) || !instance.ClientPlayerList.TryGetValue(s, out var value) || value == num) { VoiceConsent.OnConsent(num, allow); } } } internal void <Register>b__19_8(ulong s, FastBufferReader r) { //IL_0013: 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_0026: 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_0039: 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) //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) if (!Net.IsServer) { int key = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives)); int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); int num2 = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num2, default(ForPrimitives)); byte[] array = default(byte[]); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref array, default(ForPrimitives)); if (!voiceParts.TryGetValue(key, out var value) || value.Length != num2) { value = (voiceParts[key] = new byte[num2][]); } if (num >= 0 && num < num2) { value[num] = array; } if (voiceParts.Count > 20) { voiceParts.Clear(); } } } internal void <Register>b__19_9(ulong s, FastBufferReader r) { //IL_0013: 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_0055: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsServer) { ulong key = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref key, default(ForPrimitives)); if (Net.SpawnManager != null && Net.SpawnManager.SpawnedObjects.TryGetValue(key, out var value) && ((Component)value).GetComponent<EnemyAI>() is IMobStateSync mobStateSync) { mobStateSync.ReadState(r); } } } internal void <Register>b__19_10(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { byte kind = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives)); int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); PlayerControllerB val = FindPlayer((ulong)num); if ((Object)(object)val != (Object)null) { MobFactory.ServerSpawnNear((ChaosMob)kind, val); } } } } private const string MsgTeleportReq = "ChaosCompany.TeleportReq"; private const string MsgTeleportDo = "ChaosCompany.TeleportDo"; private const string MsgNoiseReq = "ChaosCompany.NoiseReq"; private const string MsgNoiseDo = "ChaosCompany.NoiseDo"; private const string MsgSpawnReq = "ChaosCompany.SpawnReq"; private const string MsgSay = "ChaosCompany.Say"; private const string MsgVoiceChunk = "ChaosCompany.VoiceChunk"; private const string MsgConsent = "ChaosCompany.Consent"; private const string MsgPlayerInsert = "ChaosCompany.PlayerInsert"; private const string MsgMobSpawnReq = "ChaosCompany.MobSpawnReq"; private const string MsgMobState = "ChaosCompany.MobState"; internal const byte TargetEnemy = 1; internal const byte TargetPlayer = 2; private static int nextUtterance = 1; private static readonly Dictionary<int, byte[][]> voiceParts = new Dictionary<int, byte[][]>(); private const int ChunkSize = 12000; private static NetworkManager Net => NetworkManager.Singleton; private static bool Online { get { if ((Object)(object)Net != (Object)null && Net.IsListening) { return Net.CustomMessagingManager != null; } return false; } } private static bool IsServerOrOffline { get { if (Online) { return Net.IsServer; } return true; } } internal static void Register(CustomMessagingManager cmm) { //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0025: Expected O, but got Unknown //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_004f: Expected O, but got Unknown //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0079: Expected O, but got Unknown //IL_0098: 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_00a3: Expected O, but got Unknown //IL_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Expected O, but got Unknown //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_00f7: Expected O, but got Unknown //IL_0116: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0121: Expected O, but got Unknown //IL_0140: Unknown result type (might be due to invalid IL or missing references) //IL_0145: Unknown result type (might be due to invalid IL or missing references) //IL_014b: Expected O, but got Unknown //IL_016a: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Expected O, but got Unknown //IL_0194: Unknown result type (might be due to invalid IL or missing references) //IL_0199: Unknown result type (might be due to invalid IL or missing references) //IL_019f: Expected O, but got Unknown //IL_01be: Unknown result type (might be due to invalid IL or missing references) //IL_01c3: Unknown result type (might be due to invalid IL or missing references) //IL_01c9: Expected O, but got Unknown object obj = <>c.<>9__19_0; if (obj == null) { HandleNamedMessageDelegate val = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { byte kind = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives)); ulong id = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives)); ServerTeleport(kind, id); } }; <>c.<>9__19_0 = val; obj = (object)val; } cmm.RegisterNamedMessageHandler("ChaosCompany.TeleportReq", (HandleNamedMessageDelegate)obj); object obj2 = <>c.<>9__19_1; if (obj2 == null) { HandleNamedMessageDelegate val2 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_0026: 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_0047: 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) if (!Net.IsServer) { byte kind = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives)); ulong id = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives)); Vector3 val12 = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref val12); Vector3 to = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref to); ApplyTeleport(kind, id, val12, to); } }; <>c.<>9__19_1 = val2; obj2 = (object)val2; } cmm.RegisterNamedMessageHandler("ChaosCompany.TeleportDo", (HandleNamedMessageDelegate)obj2); object obj3 = <>c.<>9__19_2; if (obj3 == null) { HandleNamedMessageDelegate val3 = delegate(ulong s, FastBufferReader r) { //IL_001c: 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_002e: 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_003a: Unknown result type (might be due to invalid IL or missing references) if (Net.IsServer) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref pos); float range = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives)); float loud = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives)); ServerNoise(pos, range, loud); } }; <>c.<>9__19_2 = val3; obj3 = (object)val3; } cmm.RegisterNamedMessageHandler("ChaosCompany.NoiseReq", (HandleNamedMessageDelegate)obj3); object obj4 = <>c.<>9__19_3; if (obj4 == null) { HandleNamedMessageDelegate val4 = delegate(ulong s, FastBufferReader r) { //IL_001c: 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_002e: 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_003a: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsServer) { Vector3 pos = default(Vector3); ((FastBufferReader)(ref r)).ReadValueSafe(ref pos); float range = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref range, default(ForPrimitives)); float loud = default(float); ((FastBufferReader)(ref r)).ReadValueSafe<float>(ref loud, default(ForPrimitives)); ApplyNoise(pos, range, loud); } }; <>c.<>9__19_3 = val4; obj4 = (object)val4; } cmm.RegisterNamedMessageHandler("ChaosCompany.NoiseDo", (HandleNamedMessageDelegate)obj4); object obj5 = <>c.<>9__19_4; if (obj5 == null) { HandleNamedMessageDelegate val5 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { byte item = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref item, default(ForPrimitives)); int player = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives)); ServerSpawn((ChaosItem)item, player); } }; <>c.<>9__19_4 = val5; obj5 = (object)val5; } cmm.RegisterNamedMessageHandler("ChaosCompany.SpawnReq", (HandleNamedMessageDelegate)obj5); object obj6 = <>c.<>9__19_5; if (obj6 == null) { HandleNamedMessageDelegate val6 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsServer) { ulong id = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref id, default(ForPrimitives)); string line = default(string); ((FastBufferReader)(ref r)).ReadValueSafe(ref line, false); int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); byte[] audio = null; if (num != 0 && voiceParts.TryGetValue(num, out var value)) { voiceParts.Remove(num); audio = Join(value); } ShowSay(id, line, audio); } }; <>c.<>9__19_5 = val6; obj6 = (object)val6; } cmm.RegisterNamedMessageHandler("ChaosCompany.Say", (HandleNamedMessageDelegate)obj6); object obj7 = <>c.<>9__19_6; if (obj7 == null) { HandleNamedMessageDelegate val7 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (!Net.IsServer) { int player = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref player, default(ForPrimitives)); int key = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives)); if (voiceParts.TryGetValue(key, out var value)) { voiceParts.Remove(key); byte[] array = Join(value); if (array != null) { VoiceEffects.PlayInsert(player, array); } } } }; <>c.<>9__19_6 = val7; obj7 = (object)val7; } cmm.RegisterNamedMessageHandler("ChaosCompany.PlayerInsert", (HandleNamedMessageDelegate)obj7); object obj8 = <>c.<>9__19_7; if (obj8 == null) { HandleNamedMessageDelegate val8 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_0026: 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) if (Net.IsServer) { int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); bool allow = default(bool); ((FastBufferReader)(ref r)).ReadValueSafe<bool>(ref allow, default(ForPrimitives)); StartOfRound instance = StartOfRound.Instance; if (!((Object)(object)instance != (Object)null) || !instance.ClientPlayerList.TryGetValue(s, out var value) || value == num) { VoiceConsent.OnConsent(num, allow); } } }; <>c.<>9__19_7 = val8; obj8 = (object)val8; } cmm.RegisterNamedMessageHandler("ChaosCompany.Consent", (HandleNamedMessageDelegate)obj8); object obj9 = <>c.<>9__19_8; if (obj9 == null) { HandleNamedMessageDelegate val9 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_0026: 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_0039: 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) //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) if (!Net.IsServer) { int key = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref key, default(ForPrimitives)); int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); int num2 = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num2, default(ForPrimitives)); byte[] array = default(byte[]); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref array, default(ForPrimitives)); if (!voiceParts.TryGetValue(key, out var value) || value.Length != num2) { value = (voiceParts[key] = new byte[num2][]); } if (num >= 0 && num < num2) { value[num] = array; } if (voiceParts.Count > 20) { voiceParts.Clear(); } } }; <>c.<>9__19_8 = val9; obj9 = (object)val9; } cmm.RegisterNamedMessageHandler("ChaosCompany.VoiceChunk", (HandleNamedMessageDelegate)obj9); object obj10 = <>c.<>9__19_9; if (obj10 == null) { HandleNamedMessageDelegate val10 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_0055: Unknown result type (might be due to invalid IL or missing references) if (!Net.IsServer) { ulong key = default(ulong); ((FastBufferReader)(ref r)).ReadValueSafe<ulong>(ref key, default(ForPrimitives)); if (Net.SpawnManager != null && Net.SpawnManager.SpawnedObjects.TryGetValue(key, out var value) && ((Component)value).GetComponent<EnemyAI>() is IMobStateSync mobStateSync) { mobStateSync.ReadState(r); } } }; <>c.<>9__19_9 = val10; obj10 = (object)val10; } cmm.RegisterNamedMessageHandler("ChaosCompany.MobState", (HandleNamedMessageDelegate)obj10); object obj11 = <>c.<>9__19_10; if (obj11 == null) { HandleNamedMessageDelegate val11 = delegate(ulong s, FastBufferReader r) { //IL_0013: 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_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) if (Net.IsServer) { byte kind = default(byte); ((FastBufferReader)(ref r)).ReadValueSafe<byte>(ref kind, default(ForPrimitives)); int num = default(int); ((FastBufferReader)(ref r)).ReadValueSafe<int>(ref num, default(ForPrimitives)); PlayerControllerB val12 = FindPlayer((ulong)num); if ((Object)(object)val12 != (Object)null) { MobFactory.ServerSpawnNear((ChaosMob)kind, val12); } } }; <>c.<>9__19_10 = val11; obj11 = (object)val11; } cmm.RegisterNamedMessageHandler("ChaosCompany.MobSpawnReq", (HandleNamedMessageDelegate)obj11); } internal static void Unregister(CustomMessagingManager cmm) { cmm.UnregisterNamedMessageHandler("ChaosCompany.TeleportReq"); cmm.UnregisterNamedMessageHandler("ChaosCompany.TeleportDo"); cmm.UnregisterNamedMessageHandler("ChaosCompany.NoiseReq"); cmm.UnregisterNamedMessageHandler("ChaosCompany.NoiseDo"); cmm.UnregisterNamedMessageHandler("ChaosCompany.SpawnReq"); cmm.UnregisterNamedMessageHandler("ChaosCompany.Say"); cmm.UnregisterNamedMessageHandler("ChaosCompany.VoiceChunk"); cmm.UnregisterNamedMessageHandler("ChaosCompany.Consent"); cmm.UnregisterNamedMessageHandler("ChaosCompany.PlayerInsert"); cmm.UnregisterNamedMessageHandler("ChaosCompany.MobSpawnReq"); cmm.UnregisterNamedMessageHandler("ChaosCompany.MobState"); } internal static void PlaySoundLocal(ChaosSounds id, Vector3 pos) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) ChaosSoundBank.PlayAt(id, pos); } internal unsafe static void RequestTeleport(byte kind, ulong id) { //IL_0020: 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_0032: 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_004f: Unknown result type (might be due to invalid IL or missing references) if (IsServerOrOffline) { ServerTeleport(kind, id); return; } FastBufferWriter val = default(FastBufferWriter); ((FastBufferWriter)(ref val))..ctor(16, (Allocator)2, -1); try { ((FastBufferWriter)(ref val)).WriteValueSafe<byte>(ref kind, default(ForPrimitives)); ((FastBufferWriter)(ref val)).WriteValueSafe<ulong>(ref id, default(ForPrimitives)); Net.CustomMessagingManager.SendNamedMessage("ChaosCompany.TeleportReq", 0uL, val, (NetworkDelivery)3); } finally { ((IDisposable)(*(FastBufferWriter*)(&val))/*cast due to .constrained prefix*/).Dispose(); } } private unsafe static void ServerTeleport(byte kind, ulong id) { //IL_007a: Unknown result type (might be due to invalid IL or missing references) //IL_007f: 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_003c: Unknown result type (might be due to invalid IL or missing references) //IL_009f: 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_00a5: 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_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: 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_00bd: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Unknown result type (might be due to invalid IL or missing