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 AEIOUCompany v1.3.7
aeioucompany/SharpTalk.dll
Decompiled 2 years agousing System; using System.Diagnostics; using System.IO; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: AssemblyTitle("SharpTalk")] [assembly: AssemblyDescription("A .NET wrapper for the DECtalk TTS engine.")] [assembly: AssemblyConfiguration("")] [assembly: AssemblyCompany("")] [assembly: AssemblyProduct("SharpTalk")] [assembly: AssemblyCopyright("")] [assembly: AssemblyTrademark("")] [assembly: ComVisible(false)] [assembly: Guid("a8dbd00f-6cfd-4d00-a4d6-b0059b2eb887")] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.8726.31713")] [module: UnverifiableCode] namespace SharpTalk; public class FonixTalkEngine : IDisposable { [UnmanagedFunctionPointer(CallingConvention.Cdecl)] private delegate void DtCallbackRoutine(int lParam1, int lParam2, uint drCallbackParameter, uint uiMsg); private struct PhonemeMark { public byte ThisPhoneme; public byte NextPhoneme; public ushort Duration; } [StructLayout(LayoutKind.Explicit)] private struct PhonemeTag { [FieldOffset(0)] public PhonemeMark PMData; [FieldOffset(0)] public int DWData; } private struct InMemoryRaiiHelper : IDisposable { private readonly FonixTalkEngine _engine; public InMemoryRaiiHelper(FonixTalkEngine engine) { _engine = engine; } public void Dispose() { _engine.CloseInMemory(); } } private struct BufferRaiiHelper : IDisposable { private readonly FonixTalkEngine _engine; public BufferRaiiHelper(FonixTalkEngine engine) { _engine = engine; } public void Dispose() { _engine.FreeBuffer(); } } public const uint DefaultRate = 200u; public const TtsVoice DefaultSpeaker = TtsVoice.Paul; private const uint WaveFormat_1M16 = 4u; private const uint TtsNotSupported = 32767u; private const uint TtsNotAvailable = 32766u; private const uint TtsLangError = 16384u; private static readonly uint UiIndexMsg = RegisterWindowMessage("DECtalkIndexMessage"); private static readonly uint UiErrorMsg = RegisterWindowMessage("DECtalkErrorMessage"); private static readonly uint UiBufferMsg = RegisterWindowMessage("DECtalkBufferMessage"); private static readonly uint UiPhonemeMsg = RegisterWindowMessage("DECtalkVisualMessage"); private IntPtr _handle; private IntPtr _speakerParamsPtr; private IntPtr _dummy1; private IntPtr _dummy2; private IntPtr _dummy3; private DtCallbackRoutine _callback; private TtsBufferManaged _buffer; private Stream _bufferStream; public TtsVoice Voice { get { Check(TextToSpeechGetSpeaker(_handle, out var speaker)); return speaker; } set { Check(TextToSpeechSetSpeaker(_handle, value)); } } public uint Rate { get { Check(TextToSpeechGetRate(_handle, out var rate)); return rate; } set { Check(TextToSpeechSetRate(_handle, value)); } } public SpeakerParams SpeakerParams { get { Check(TextToSpeechGetSpeakerParams(_handle, 0u, out _speakerParamsPtr, out _dummy1, out _dummy2, out _dummy3)); return (SpeakerParams)Marshal.PtrToStructure(_speakerParamsPtr, typeof(SpeakerParams)); } set { Check(TextToSpeechGetSpeakerParams(_handle, 0u, out _speakerParamsPtr, out _dummy1, out _dummy2, out _dummy3)); Marshal.StructureToPtr(value, _speakerParamsPtr, fDeleteOld: false); Check(TextToSpeechSetSpeakerParams(_handle, _speakerParamsPtr)); } } public event EventHandler<PhonemeEventArgs> Phoneme; [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechStartupEx(out IntPtr handle, uint uiDeviceNumber, uint dwDeviceOptions, DtCallbackRoutine callback, ref IntPtr dwCallbackParameter); [DllImport("FonixTalk.dll")] [return: MarshalAs(UnmanagedType.Bool)] private static extern bool TextToSpeechSelectLang(IntPtr handle, uint lang); [DllImport("FonixTalk.dll")] private static extern uint TextToSpeechStartLang([MarshalAs(UnmanagedType.LPStr)] string lang); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechSetSpeaker(IntPtr handle, TtsVoice speaker); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechGetSpeaker(IntPtr handle, out TtsVoice speaker); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechGetRate(IntPtr handle, out uint rate); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechSetRate(IntPtr handle, uint rate); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechSpeakA(IntPtr handle, [MarshalAs(UnmanagedType.LPStr)] string msg, uint flags); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechShutdown(IntPtr handle); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechPause(IntPtr handle); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechResume(IntPtr handle); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechReset(IntPtr handle, [MarshalAs(UnmanagedType.Bool)] bool bReset); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechSync(IntPtr handle); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechSetSpeakerParams(IntPtr handle, IntPtr spDefs); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechGetSpeakerParams(IntPtr handle, uint uiIndex, out IntPtr ppspCur, out IntPtr ppspLoLimit, out IntPtr ppspHiLimit, out IntPtr ppspDefault); [DllImport("FonixTalk.dll")] private unsafe static extern MMRESULT TextToSpeechAddBuffer(IntPtr handle, TtsBufferManaged.TTS_BUFFER_T* buffer); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechOpenInMemory(IntPtr handle, uint format); [DllImport("FonixTalk.dll")] private static extern MMRESULT TextToSpeechCloseInMemory(IntPtr handle); [DllImport("user32.dll")] private static extern uint RegisterWindowMessage([MarshalAs(UnmanagedType.LPStr)] string lpString); [DllImport("kernel32.dll")] private static extern void CopyMemory(IntPtr dest, IntPtr src, uint count); public FonixTalkEngine(string language) { Init(language); } public FonixTalkEngine() { Init("US"); } public FonixTalkEngine(string language, uint rate, TtsVoice speaker) { Init(language); Voice = speaker; Rate = rate; } public FonixTalkEngine(uint rate, TtsVoice speaker) { Init("US"); Voice = speaker; Rate = rate; } private void Init(string lang) { _callback = TtsCallback; _buffer = null; _bufferStream = null; if (lang != "XX") { uint num = TextToSpeechStartLang(lang); if ((num & 0x4000u) != 0) { switch (num) { case 32767u: throw new FonixTalkException("This version of DECtalk does not support multiple languages."); case 32766u: throw new FonixTalkException("The specified language was not found."); } } if (!TextToSpeechSelectLang(IntPtr.Zero, num)) { throw new FonixTalkException("The specified language failed to load."); } } Check(TextToSpeechStartupEx(out _handle, uint.MaxValue, 0u, _callback, ref _handle)); Speak("[:phone on]"); } private unsafe void TtsCallback(int lParam1, int lParam2, uint drCallbackParameter, uint uiMsg) { if (uiMsg == UiPhonemeMsg && this.Phoneme != null) { PhonemeTag phonemeTag = default(PhonemeTag); phonemeTag.DWData = lParam2; PhonemeTag phonemeTag2 = phonemeTag; this.Phoneme(this, new PhonemeEventArgs((char)phonemeTag2.PMData.ThisPhoneme, phonemeTag2.PMData.Duration)); } else if (uiMsg == UiBufferMsg) { _bufferStream.Write(_buffer.GetBufferBytes(), 0, (int)_buffer.Length); _ = _buffer.Full; _buffer.Reset(); Check(TextToSpeechAddBuffer(_handle, _buffer.ValuePointer)); } else if (uiMsg != UiErrorMsg) { _ = UiIndexMsg; } } public byte[] SpeakToMemory(string input) { using (_bufferStream = new MemoryStream()) { using (OpenInMemory(4u)) { using (ReadyBuffer()) { Speak(input); Sync(); TextToSpeechReset(_handle, bReset: false); } } return ((MemoryStream)_bufferStream).ToArray(); } } public void SpeakToStream(Stream stream, string input) { _bufferStream = stream; using (OpenInMemory(4u)) { using (ReadyBuffer()) { Speak(input); Sync(); TextToSpeechReset(_handle, bReset: false); } } _bufferStream = null; } public void SpeakToWavFile(string path, string input) { using MemoryStream memoryStream = new MemoryStream(); SpeakToStream(memoryStream, input); int num = (int)memoryStream.Length; using BinaryWriter binaryWriter = new BinaryWriter(File.Create(path), Encoding.ASCII); binaryWriter.Write("RIFF".ToCharArray()); binaryWriter.Write(num + 44 - 8); binaryWriter.Write("WAVE".ToCharArray()); binaryWriter.Write("fmt ".ToCharArray()); binaryWriter.Write(16); binaryWriter.Write((short)1); binaryWriter.Write((short)1); binaryWriter.Write(11025); binaryWriter.Write(22050); binaryWriter.Write((short)2); binaryWriter.Write((short)16); binaryWriter.Write("data".ToCharArray()); binaryWriter.Write(num); memoryStream.Position = 0L; memoryStream.CopyTo(binaryWriter.BaseStream); } public void Pause() { Check(TextToSpeechPause(_handle)); } public void Resume() { Check(TextToSpeechResume(_handle)); } public void Reset() { Check(TextToSpeechReset(_handle, bReset: false)); } public void Sync() { Check(TextToSpeechSync(_handle)); } public void Speak(string msg) { Check(TextToSpeechSpeakA(_handle, msg, 1u)); } private static void Check(MMRESULT code) { if (code != 0) { throw new FonixTalkException(code); } } private InMemoryRaiiHelper OpenInMemory(uint format) { Check(TextToSpeechOpenInMemory(_handle, format)); return new InMemoryRaiiHelper(this); } private void CloseInMemory() { Check(TextToSpeechCloseInMemory(_handle)); } private unsafe BufferRaiiHelper ReadyBuffer() { if (_buffer != null) { throw new InvalidOperationException("Buffer already exists."); } _buffer = new TtsBufferManaged(); Check(TextToSpeechAddBuffer(_handle, _buffer.ValuePointer)); return new BufferRaiiHelper(this); } private void FreeBuffer() { _buffer.Dispose(); _buffer = null; } ~FonixTalkEngine() { Dispose(disposing: false); } public void Dispose() { Dispose(disposing: true); } private void Dispose(bool disposing) { TextToSpeechShutdown(_handle); if (_buffer != null) { _buffer.Dispose(); } if (disposing) { GC.SuppressFinalize(this); } } } public sealed class FonixTalkException : Exception { internal FonixTalkException(MMRESULT code) : base(GetMessage(code)) { } internal FonixTalkException(string message) : base(message) { } private static string GetMessage(MMRESULT code) { return code switch { MMRESULT.MMSYSERR_INVALPARAM => "An invalid parameter was passed to the function.", MMRESULT.MMSYSERR_INVALHANDLE => "The associated handle is invalid. Did you dispose it?", MMRESULT.MMSYSERR_ERROR => "The function returned a generic error. Please check that you are using the functions correctly.", MMRESULT.MMSYSERR_NOERROR => "The function did not throw an error. If you are seeing this, Berkin was obviously high while coding.", MMRESULT.MMSYSERR_NOMEM => "There was insufficnent memory available to allocate the requested resources.", MMRESULT.MMSYSERR_ALLOCATED => "The requested resources are already in use somewhere else.", MMRESULT.WAVERR_BADFORMAT => "Wave output device does not support request format.", MMRESULT.MMSYSERR_BADDEVICEID => "Device ID out of range.", MMRESULT.MMSYSERR_NODRIVER => "No wave output device present.", _ => code.ToString(), }; } } [Flags] internal enum DeviceOptions : uint { OwnAudioDevice = 1u, ReportOpenError = 2u, UseSapi5AudioDevice = 0x40000000u, DoNotUseAudioDevice = 0x80000000u } public static class LanguageCode { public const string EnglishUS = "US"; public const string EnglishUK = "UK"; public const string SpanishCastilian = "SP"; public const string SpanishLatinAmerican = "LA"; public const string German = "GR"; public const string French = "FR"; public const string None = "XX"; } internal enum MMRESULT : uint { MMSYSERR_NOERROR = 0u, MMSYSERR_ERROR = 1u, MMSYSERR_BADDEVICEID = 2u, MMSYSERR_NOTENABLED = 3u, MMSYSERR_ALLOCATED = 4u, MMSYSERR_INVALHANDLE = 5u, MMSYSERR_NODRIVER = 6u, MMSYSERR_NOMEM = 7u, MMSYSERR_NOTSUPPORTED = 8u, MMSYSERR_BADERRNUM = 9u, MMSYSERR_INVALFLAG = 10u, MMSYSERR_INVALPARAM = 11u, MMSYSERR_HANDLEBUSY = 12u, MMSYSERR_INVALIDALIAS = 13u, MMSYSERR_BADDB = 14u, MMSYSERR_KEYNOTFOUND = 15u, MMSYSERR_READERROR = 16u, MMSYSERR_WRITEERROR = 17u, MMSYSERR_DELETEERROR = 18u, MMSYSERR_VALNOTFOUND = 19u, MMSYSERR_NODRIVERCB = 20u, WAVERR_BADFORMAT = 32u, WAVERR_STILLPLAYING = 33u, WAVERR_UNPREPARED = 34u } public class PhonemeEventArgs : EventArgs { public readonly char Phoneme; public readonly uint Duration; internal PhonemeEventArgs(char phoneme, uint duration) { Phoneme = phoneme; Duration = duration; } } public enum TtsVoice : uint { Paul, Betty, Harry, Frank, Dennis, Kit, Ursula, Rita, Wendy } public struct SpeakerParams { [MarshalAs(UnmanagedType.I2)] public Sex Sex; public short Smoothness; public short Assertiveness; public short AveragePitch; public short Breathiness; public short Richness; public short NumFixedSampOG; public short Laryngealization; public short HeadSize; public short Formant4ResFreq; public short Formant4Bandwidth; public short Formant5ResFreq; public short Formant5Bandwidth; public short Parallel4Freq; public short Parallel5Freq; public short GainFrication; public short GainAspiration; public short GainVoicing; public short GainNasalization; public short GainCFR1; public short GainCFR2; public short GainCFR3; public short GainCFR4; public short Loudness; public short SpectralTilt; public short BaselineFall; public short LaxBreathiness; public short Quickness; public short HatRise; public short StressRise; public short GlottalSpeed; public short OutputGainMultiplier; } public enum Sex : short { Female, Male } [Flags] internal enum SpeakFlags : uint { Normal = 0u, Force = 1u } internal enum TTSMessageType : uint { Buffer, IndexMarker, Status, Visual } [StructLayout(LayoutKind.Sequential)] internal class TtsBufferManaged : IDisposable { public struct TTS_BUFFER_T { public const int BufferSize = 16384; public IntPtr DataPtr; public unsafe TTS_PHONEME_T* PhonemeArrayPtr; public unsafe TTS_INDEX_T* IndexArrayPtr; public uint MaxBufferLength; public uint MaxPhonemeChanges; public uint MaxIndexMarks; public uint BufferLength; public uint PhonemeChangeCount; public uint IndexMarkCount; public uint _reserved; } private TTS_BUFFER_T _value; private GCHandle _pinHandle; public bool Full => _value.BufferLength == _value.MaxBufferLength; public uint Length => _value.BufferLength; public unsafe TTS_BUFFER_T* ValuePointer { get { fixed (TTS_BUFFER_T* result = &_value) { return result; } } } public TtsBufferManaged() { _value = default(TTS_BUFFER_T); _pinHandle = GCHandle.Alloc(this, GCHandleType.Pinned); _value.MaxBufferLength = 16384u; _value.DataPtr = Marshal.AllocHGlobal(16384); } public byte[] GetBufferBytes() { byte[] array = new byte[_value.BufferLength]; Marshal.Copy(_value.DataPtr, array, 0, (int)_value.BufferLength); return array; } public void Reset() { _value.BufferLength = 0u; _value.PhonemeChangeCount = 0u; _value.IndexMarkCount = 0u; } public void Dispose() { Marshal.FreeHGlobal(_value.DataPtr); _pinHandle.Free(); GC.SuppressFinalize(this); } } internal struct TTS_INDEX_T { public uint IndexValue; public uint SampleNumber; private readonly uint _reserved; } internal struct TTS_PHONEME_T { public uint Phoneme; public uint PhonemeSampleNumber; public uint PhonemeDuration; private readonly uint _reserved; }
aeioucompany/AEIOUCompany.dll
Decompiled 2 years agousing System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.IO.Pipes; using System.Linq; using System.Linq.Expressions; using System.Reflection; using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Security; using System.Security.Permissions; using System.Text; using System.Threading.Tasks; using BepInEx; using BepInEx.Logging; using GameNetcodeStuff; using HarmonyLib; using Microsoft.CodeAnalysis; using TMPro; using UnityEngine; using UnityEngine.SceneManagement; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)] [assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")] [assembly: AssemblyCompany("AEIOUCompany")] [assembly: AssemblyConfiguration("Debug")] [assembly: AssemblyDescription("Jogn Maden")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+a793af3289ccebff065d9e9d557e48fdd5464acb")] [assembly: AssemblyProduct("AEIOUCompany")] [assembly: AssemblyTitle("AEIOUCompany")] [assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)] [assembly: AssemblyVersion("1.0.0.0")] [module: UnverifiableCode] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } public readonly struct Speak { public readonly string ChatMessage; public readonly int PlayerId; public Speak(string chatMessage, int playerId) { ChatMessage = chatMessage; PlayerId = playerId; } } namespace AEIOU_Company { [HarmonyPatch] public class Patches { private static int NEW_CHAT_SIZE = Plugin.ChatSize; private static TMP_InputField chatTextField = null; private static string lastChatMessage = ""; private static readonly float[] emptySamples = new float[8388608]; private static readonly List<Speak> pendingSpeech = new List<Speak>(); private static Task<TTS.SpeechData> currentSpeechTask = null; [HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageClientRpc")] [HarmonyPostfix] public static void AddPlayerChatMessageClientRpcPostfix(HUDManager __instance, string chatMessage, int playerId) { //IL_007f: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) if (lastChatMessage == chatMessage || chatMessage.StartsWith(Plugin.BlacklistPrefix)) { return; } lastChatMessage = chatMessage; if (playerId <= HUDManager.Instance.playersManager.allPlayerScripts.Length) { bool flag = GameNetworkManager.Instance.localPlayerController.holdingWalkieTalkie && StartOfRound.Instance.allPlayerScripts[playerId].holdingWalkieTalkie; float num = Vector3.Distance(((Component)GameNetworkManager.Instance.localPlayerController).transform.position, ((Component)HUDManager.Instance.playersManager.allPlayerScripts[playerId]).transform.position); if (num > 25f && !flag && GameNetworkManager.Instance.localPlayerController.isPlayerDead) { MethodInfo methodInfo = AccessTools.Method(typeof(HUDManager), "AddChatMessage", (Type[])null, (Type[])null); methodInfo.Invoke(HUDManager.Instance, new object[2] { chatMessage, HUDManager.Instance.playersManager.allPlayerScripts[playerId].playerUsername }); } Plugin.Log($"AddTextToChatOnServer: {chatMessage} {playerId}"); QueueSpeak(__instance, chatMessage, playerId); } } [HarmonyPatch(typeof(HUDManager), "Update")] [HarmonyPostfix] public static void UpdatePostfix(HUDManager __instance) { if (currentSpeechTask != null) { if (!currentSpeechTask.IsCompleted) { return; } if (!currentSpeechTask.IsCanceled && !currentSpeechTask.IsFaulted) { Speak(__instance.playersManager, currentSpeechTask.Result); } currentSpeechTask = null; } if (pendingSpeech.Count > 0) { Speak nextSpeech = pendingSpeech[0]; pendingSpeech.RemoveAt(0); currentSpeechTask = Task.Run(() => TTS.SpeakToMemory(nextSpeech.PlayerId, nextSpeech.ChatMessage, 7.5f)); } } private static void QueueSpeak(HUDManager __instance, string chatMessage, int playerId) { Plugin.Log("Speak"); pendingSpeech.Add(new Speak(chatMessage, playerId)); } private static void Speak(StartOfRound playersManager, TTS.SpeechData speechData) { //IL_006f: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Expected O, but got Unknown //IL_008d: Unknown result type (might be due to invalid IL or missing references) //IL_03d8: Unknown result type (might be due to invalid IL or missing references) int playerId = speechData.PlayerId; PlayerControllerB val = playersManager.allPlayerScripts[playerId]; if ((Object)(object)val == (Object)null) { Plugin.Log("couldnt find player"); return; } Plugin.Log("Found player"); Transform obj = ((Component)val).gameObject.transform.Find("AEIOUSpeakObject"); GameObject val2 = ((obj != null) ? ((Component)obj).gameObject : null); if ((Object)(object)val2 == (Object)null) { val2 = new GameObject("AEIOUSpeakObject"); val2.transform.parent = ((Component)val).transform; val2.transform.localPosition = Vector3.zero; val2.AddComponent<AudioSource>(); val2.AddComponent<AudioHighPassFilter>(); val2.AddComponent<AudioLowPassFilter>(); } Plugin.Log("Found AEIOUSpeakObject"); AudioSource component = val2.GetComponent<AudioSource>(); if ((Object)(object)component == (Object)null) { Plugin.LogError("Couldn't speak, AudioSource was null"); return; } if ((Object)(object)component.clip == (Object)null) { component.clip = AudioClip.Create("AEIOUCLIP", 8388608, 1, 11025, false); } Plugin.Log("Setting up clip"); component.clip.SetData(emptySamples, 0); component.clip.SetData(speechData.AudioData, 0); component.outputAudioMixerGroup = SoundManager.Instance.playerVoiceMixers[val.playerClientId]; component.playOnAwake = false; component.rolloffMode = (AudioRolloffMode)2; component.minDistance = 1f; component.maxDistance = 40f; component.dopplerLevel = Plugin.TTSDopperLevel; component.pitch = 1f; component.spatialize = true; component.spatialBlend = (val.isPlayerDead ? 0f : 1f); bool flag = !val.isPlayerDead || StartOfRound.Instance.localPlayerController.isPlayerDead; component.volume = (flag ? Plugin.TTSVolume : 0f); AudioHighPassFilter component2 = val2.GetComponent<AudioHighPassFilter>(); if ((Object)(object)component2 != (Object)null) { ((Behaviour)component2).enabled = false; } AudioLowPassFilter component3 = val2.GetComponent<AudioLowPassFilter>(); if ((Object)(object)component3 != (Object)null) { component3.lowpassResonanceQ = 1f; component3.cutoffFrequency = 5000f; } if (component.isPlaying) { component.Stop(true); } Plugin.Log($"Playing audio: {component}{component.volume}"); if (val.holdingWalkieTalkie) { GrabbableObject currentlyHeldObjectServer = val.currentlyHeldObjectServer; WalkieTalkie val3 = (WalkieTalkie)(object)((currentlyHeldObjectServer is WalkieTalkie) ? currentlyHeldObjectServer : null); if (val3 != null) { Plugin.Log("WalkieTalkie"); bool flag2 = false; for (int i = 0; i < WalkieTalkie.allWalkieTalkies.Count; i++) { if ((Object)(object)((GrabbableObject)WalkieTalkie.allWalkieTalkies[i]).playerHeldBy == (Object)(object)StartOfRound.Instance.localPlayerController && ((GrabbableObject)WalkieTalkie.allWalkieTalkies[i]).isBeingUsed) { flag2 = true; } } if ((Object)(object)val3 != (Object)null && ((GrabbableObject)val3).isBeingUsed && flag2) { component.volume = Plugin.TTSVolume; if ((Object)(object)val == (Object)(object)StartOfRound.Instance.localPlayerController) { Plugin.Log("Pushing walkie button"); val.playerBodyAnimator.SetBool("walkieTalkie", true); ((MonoBehaviour)val3).StartCoroutine(WaitAndStopUsingWalkieTalkie(component.clip, val, speechData.AudioLengthInSeconds)); } else { ((Behaviour)component2).enabled = true; component3.lowpassResonanceQ = 3f; component3.cutoffFrequency = 4000f; component.spatialBlend = 0f; } } } } component.PlayOneShot(component.clip, 1f); RoundManager.Instance.PlayAudibleNoise(val2.transform.position, 25f, 0.7f, 0, false, 0); } private static IEnumerator WaitAndStopUsingWalkieTalkie(AudioClip clip, PlayerControllerB player, float audioLengthInSeconds) { Plugin.Log($"WalkieButton Length {audioLengthInSeconds}"); yield return (object)new WaitForSeconds(audioLengthInSeconds); Plugin.Log("WalkieButton end"); player.playerBodyAnimator.SetBool("walkieTalkie", false); } [HarmonyPatch(typeof(HUDManager), "EnableChat_performed")] [HarmonyPostfix] public static void EnableChat_performedPostfix(ref TMP_InputField ___chatTextField, HUDManager __instance) { ___chatTextField.characterLimit = NEW_CHAT_SIZE; chatTextField = ___chatTextField; Plugin.Log("Enable Chat"); } [HarmonyPatch(typeof(PlayerControllerB), "KillPlayer")] [HarmonyPostfix] public static void KillPlayerPostfix(PlayerControllerB __instance) { if (!Plugin.EnableDeadChat) { Plugin.Log("EnableDeadChat false, skipping KillPlayerPostfix patch"); return; } HUDManager.Instance.HideHUD(false); HUDManager.Instance.UpdateHealthUI(100, false); Plugin.Log("Player died, re-enabling UI"); } [HarmonyPatch(typeof(HUDManager), "EnableChat_performed")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> EnableChat_performedTranspiler(IEnumerable<CodeInstruction> oldInstructions) { if (!Plugin.EnableDeadChat) { Plugin.Log("EnableDeadChat false, skipping EnableChat_performedTranspiler patch"); return oldInstructions; } List<CodeInstruction> list = new List<CodeInstruction>(oldInstructions); for (int i = 0; i < list.Count - 3; i++) { if (list[i].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.Is(list[i + 1], OpCodes.Ldfld, (MemberInfo)AccessTools.Field(typeof(HUDManager), "localPlayer")) && CodeInstructionExtensions.Is(list[i + 2], OpCodes.Ldfld, (MemberInfo)AccessTools.Field(typeof(PlayerControllerB), "isPlayerDead")) && list[i + 3].opcode == OpCodes.Brfalse) { Plugin.Log("Patching dead chat in EnableChat_performed"); list[i].opcode = OpCodes.Br; list[i].operand = list[i + 3].operand; break; } } return list.AsEnumerable(); } [HarmonyPatch(typeof(HUDManager), "SubmitChat_performed")] [HarmonyTranspiler] public static IEnumerable<CodeInstruction> SubmitChat_performedTranspiler(IEnumerable<CodeInstruction> oldInstructions) { List<CodeInstruction> list = new List<CodeInstruction>(oldInstructions); patchMaxChatSize(list); if (Plugin.EnableDeadChat) { patchDeadChat(list); } else { Plugin.Log("EnableDeadChat false, skipping SubmitChat_performedTranspiler patch"); } return list.AsEnumerable(); static void patchDeadChat(List<CodeInstruction> newInstructions) { for (int i = 0; i < newInstructions.Count - 3; i++) { if (newInstructions[i].opcode == OpCodes.Ldarg_0 && CodeInstructionExtensions.Is(newInstructions[i + 1], OpCodes.Ldfld, (MemberInfo)AccessTools.Field(typeof(HUDManager), "localPlayer")) && CodeInstructionExtensions.Is(newInstructions[i + 2], OpCodes.Ldfld, (MemberInfo)AccessTools.Field(typeof(PlayerControllerB), "isPlayerDead")) && newInstructions[i + 3].opcode == OpCodes.Brfalse) { Plugin.Log("Patching dead chat in SubmitChat_performed"); newInstructions[i].opcode = OpCodes.Br; newInstructions[i].operand = newInstructions[i + 3].operand; break; } } } static void patchMaxChatSize(List<CodeInstruction> newInstructions) { CodeInstruction val = null; bool flag = false; foreach (CodeInstruction newInstruction in newInstructions) { if (CodeInstructionExtensions.Is(newInstruction, OpCodes.Ldc_I4_S, (object)50)) { flag = true; val = newInstruction; } else { if (newInstruction.opcode == OpCodes.Bge && flag) { val.opcode = OpCodes.Ldc_I4; val.operand = NEW_CHAT_SIZE + 1; Plugin.Log("Patched max chat length"); break; } if (flag) { flag = false; val = null; } } } } } [HarmonyPatch(typeof(HUDManager), "AddPlayerChatMessageServerRpc")] [HarmonyTranspiler] private static IEnumerable<CodeInstruction> AddPlayerChatMessageServerRpcTranspiler(IEnumerable<CodeInstruction> oldInstructions) { List<CodeInstruction> list = new List<CodeInstruction>(oldInstructions); foreach (CodeInstruction item in list) { if (CodeInstructionExtensions.Is(item, OpCodes.Ldc_I4_S, (object)50)) { item.opcode = OpCodes.Ldc_I4; item.operand = NEW_CHAT_SIZE; Plugin.Log("Patched server max chat length"); break; } } return list.AsEnumerable(); } } public class LCModUtils { private static Harmony _harmony; private static bool _shouldHost; private static bool _shouldJoin; public LCModUtils(Harmony harmony) { _harmony = harmony; } public void DisableFullscreen() { //IL_0061: Unknown result type (might be due to invalid IL or missing references) //IL_006f: Expected O, but got Unknown MethodInfo methodInfo = AccessTools.Method(typeof(IngamePlayerSettings), "SetFullscreenMode", (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.LogError("Couldn't find method SetFullscreenMode"); } MethodInfo methodInfo2 = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => SetFullScreenModePrefix())); _harmony.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); Plugin.Log("Disabled Fullscreen"); } public void BootToLANMenu() { Plugin.Log("Attempting to load lan scene"); SceneManager.sceneLoaded += OnSceneLoaded; SceneManager.LoadScene("InitSceneLANMode"); } public void StartLANHost() { BootToLANMenu(); _shouldHost = true; } public void StartLANClient() { BootToLANMenu(); _shouldJoin = true; } private static bool SetFullScreenModePrefix() { return false; } private static void OnSceneLoaded(Scene scene, LoadSceneMode mode) { //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00ea: Expected O, but got Unknown MenuManager val = Object.FindObjectOfType<MenuManager>(); if (!(((Scene)(ref scene)).name == "MainMenu")) { return; } Plugin.Log("MainMenuLoaded"); GameObject lanWarningContainer = val.lanWarningContainer; if (Object.op_Implicit((Object)(object)lanWarningContainer)) { Plugin.Log("Destroy LAN Warning"); Object.Destroy((Object)(object)lanWarningContainer); } else { Plugin.Log("LANWarning Null"); } if (_shouldHost || _shouldJoin) { MethodInfo methodInfo = AccessTools.Method(typeof(MenuManager), "Start", (Type[])null, (Type[])null); if (methodInfo == null) { Plugin.LogError("Couldn't find method \"Start\" in MenuManager"); } MethodInfo methodInfo2 = SymbolExtensions.GetMethodInfo((Expression<Action>)(() => HostOrJoin())); _harmony.Patch((MethodBase)methodInfo, (HarmonyMethod)null, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } SceneManager.sceneLoaded -= OnSceneLoaded; } private static void HostOrJoin() { MenuManager val = Object.FindObjectOfType<MenuManager>(); if (_shouldHost) { if (val != null) { val.ClickHostButton(); } if (val != null) { val.ConfirmHostButton(); } } else if (_shouldJoin) { AccessTools.Method(typeof(MenuManager), "ClickJoinButton", (Type[])null, (Type[])null)?.Invoke(val, null); } } } [BepInPlugin("AEIOUCompany", "AEIOUCompany", "1.0.0")] public class Plugin : BaseUnityPlugin { public static Harmony Harmony = null; protected static ManualLogSource Logger = null; public static bool PlayStartingUpMessage = false; public static float TTSVolume = 0f; public static float TTSDopperLevel; public static int ChatSize; public static bool EnableDeadChat = true; public static string BlacklistPrefix = "/"; public static void Log(object data) { ManualLogSource logger = Logger; if (logger != null) { logger.LogInfo(data); } } public static void LogError(object data) { ManualLogSource logger = Logger; if (logger != null) { logger.LogError(data); } } public void Awake() { //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_000c: Expected O, but got Unknown Harmony harmony = new Harmony("AEIOUCompany"); Harmony = harmony; Logger = ((BaseUnityPlugin)this).Logger; PlayStartingUpMessage = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "StartingUpMessage", true, "Enables \"starting up\" sound effect.").Value; TTSVolume = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Volume", 1f, "Volume scale of text-to-speech-voice. Values range from 0 to 1").Value; TTSDopperLevel = ((BaseUnityPlugin)this).Config.Bind<float>("General", "Doppler Effect Level", 1f, "Values range from 0 to 1").Value; ChatSize = ((BaseUnityPlugin)this).Config.Bind<int>("Advanced", "Chat Character Limit", 1024, "WARNING: Everybody must have the same value set for this!").Value; EnableDeadChat = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "Enable Dead Chat", true, "Enables chatting after dead").Value; BlacklistPrefix = ((BaseUnityPlugin)this).Config.Bind<string>("General", "Blacklist Prefix", "/", "TTS Ignores messages starting with this").Value; TTS.Init(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"Plugin AEIOUCompany is loaded!"); Harmony.PatchAll(); ((BaseUnityPlugin)this).Logger.LogInfo((object)$"Plugin total patches appled: {Harmony.GetPatchedMethods().Count()}"); } public void OnDestroy() { if (PlayStartingUpMessage) { TTS.Speak("Starting Up"); } } private void EnableTestMode() { LCModUtils lCModUtils = new LCModUtils(Harmony); lCModUtils.DisableFullscreen(); lCModUtils.BootToLANMenu(); } } internal static class TTS { public readonly struct SpeechData { public readonly int PlayerId; public readonly float[] AudioData; public readonly float AudioLengthInSeconds; public SpeechData(int playerPlayerId, float[] audioData, float audioLengthInSeconds) { PlayerId = playerPlayerId; AudioData = audioData; AudioLengthInSeconds = audioLengthInSeconds; } } private const int OUT_BUFFER_SIZE = 8192; public const int IN_BUFFER_SIZE = 8388608; private static readonly float[] audioFloatBuffer = new float[8388608]; private static byte[] audioByteBuffer = new byte[16777216]; private static NamedPipeClientStream _namedPipeClientStream; private static StreamWriter _streamWriter; private static BinaryReader _binaryReader; private static bool _initialized = false; public static void Init() { StartSpeakServer(); try { _namedPipeClientStream = new NamedPipeClientStream("AEIOUCOMPANYMOD"); _streamWriter = new StreamWriter(_namedPipeClientStream, Encoding.UTF8, 8192, leaveOpen: true); _binaryReader = new BinaryReader(_namedPipeClientStream, Encoding.UTF8, leaveOpen: true); } catch (IOException data) { Plugin.LogError(data); } ConnectToSpeakServer(); _initialized = true; } public static void Speak(string message) { if (!_initialized) { Plugin.LogError("Tried to speak before initializing TTS!"); return; } try { SendMsg(message, "msgA"); } catch (IOException ex) { Plugin.LogError("Speak" + ex); } } public static SpeechData SpeakToMemory(int playerId, string message, float volumeScale = 1f) { if (!_initialized) { Plugin.LogError("Tried to speak before initializing TTS!"); return default(SpeechData); } message = message.Replace("\r", "").Replace("\n", ""); SendMsg(message, "msg"); int num = _binaryReader.ReadInt32(); if (num > audioByteBuffer.Length) { audioByteBuffer = new byte[num]; } Array.Clear(audioFloatBuffer, 0, audioFloatBuffer.Length); int num2 = 0; _binaryReader.Read(audioByteBuffer, 0, num); for (int i = 0; i < Math.Min(num / 2, audioFloatBuffer.Length); i++) { float num3 = volumeScale * ((float)BitConverter.ToInt16(audioByteBuffer, i * 2) / 32767f); audioFloatBuffer[i] = num3; if (num3 != 0f) { num2 = i; } } float audioLengthInSeconds = (float)num2 / 11025f; Plugin.Log("END"); return new SpeechData(playerId, audioFloatBuffer, audioLengthInSeconds); } private static void SendMsg(string message, string prefix) { if (!_namedPipeClientStream.IsConnected) { StartSpeakServer(); ConnectToSpeakServer(); } message = prefix + "=[:np]" + message + "]"; Plugin.Log("Sending: " + message); try { _streamWriter.WriteLine(message); _streamWriter.Flush(); } catch (Exception data) { Plugin.LogError(data); } } private static void ConnectToSpeakServer() { Plugin.Log("ConnectingToPipe"); try { _namedPipeClientStream.Connect(7500); } catch (TimeoutException) { Plugin.LogError("Unable to connect to SpeakServer after timeout"); } catch (IOException) { Plugin.LogError("IOException while trying to ConnectToSpeakServer"); } } private static void StartSpeakServer() { if (CheckForAEIOUSPEAKProcess()) { Process[] processesByName = Process.GetProcessesByName("AEIOUSpeak"); Process[] array = processesByName; foreach (Process process in array) { process.Close(); } } string text = new Uri(Assembly.GetExecutingAssembly().CodeBase).LocalPath.Replace("AEIOUCompany.dll", ""); Plugin.Log(text + "AEIOUSpeak.exe"); Process process2 = Process.Start(text + "AEIOUSpeak.exe"); Plugin.Log("Started Speak Server"); if (process2 == null) { Plugin.LogError("Failed to start Speak Server"); } } private static bool CheckForAEIOUSPEAKProcess() { Process[] processesByName = Process.GetProcessesByName("AEIOUSpeak"); if (processesByName.Length != 0) { return true; } return false; } } public static class PluginInfo { public const string PLUGIN_GUID = "AEIOUCompany"; public const string PLUGIN_NAME = "AEIOUCompany"; public const string PLUGIN_VERSION = "1.0.0"; } }