using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.MemoryMappedFiles;
using System.Linq;
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;
using System.Threading;
using Agents;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Core.Logging.Interpolation;
using BepInEx.Logging;
using BepInEx.Unity.IL2CPP;
using GTFO.API;
using Microsoft.CodeAnalysis;
using Player;
using SNetwork;
using UnityEngine;
using mumblelib;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = ".NET 6.0")]
[assembly: AssemblyCompany("OpenPA")]
[assembly: AssemblyConfiguration("Debug")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("OpenPA")]
[assembly: AssemblyTitle("OpenPA")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("1.0.0.0")]
[module: UnverifiableCode]
namespace Microsoft.CodeAnalysis
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
internal sealed class EmbeddedAttribute : Attribute
{
}
}
namespace System.Runtime.CompilerServices
{
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)]
internal sealed class NullableAttribute : Attribute
{
public readonly byte[] NullableFlags;
public NullableAttribute(byte P_0)
{
NullableFlags = new byte[1] { P_0 };
}
public NullableAttribute(byte[] P_0)
{
NullableFlags = P_0;
}
}
[CompilerGenerated]
[Microsoft.CodeAnalysis.Embedded]
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)]
internal sealed class NullableContextAttribute : Attribute
{
public readonly byte Flag;
public NullableContextAttribute(byte P_0)
{
Flag = P_0;
}
}
}
namespace PositionalAudio
{
public class OpenPAConfig
{
public static ConfigEntry<bool> configTalkState;
public static ConfigEntry<bool> configVerbose;
public static ConfigEntry<int> configIntensity { get; set; }
}
[BepInPlugin("net.devante.gtfo.positionalaudio", "PositionalAudio", "2.0.0")]
public class Plugin : BasePlugin
{
public struct ClientCharID
{
public int PlayerID;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct ClientSendData
{
public int clientSlot;
public bool clientStatus;
}
public interface LinkFileFactory
{
LinkFile Open();
}
public interface LinkFile : IDisposable
{
uint UIVersion { set; }
Vector3 CharacterPosition { set; }
Vector3 CharacterForward { set; }
Vector3 CharacterTop { set; }
string Name { set; }
Vector3 CameraPosition { set; }
Vector3 CameraForward { set; }
Vector3 CameraTop { set; }
string ID { set; }
string Context { set; }
string Description { set; }
void Tick();
}
private MumbleLinkFile mumbleLink;
private Timer gameStateCheckTimer;
private Timer reportingTaskTimer;
private string endData;
public bool isPlayerInLevel = false;
private Thread clientThread;
public bool gameStarted = false;
private volatile bool clientNoise = false;
private static Random random = new Random();
public override void Load()
{
OpenPAConfig.configTalkState = ((BasePlugin)this).Config.Bind<bool>("TalkState", "Enabled", false, "Whether or not the game should tap into the TalkState plugin for Mumble.");
OpenPAConfig.configIntensity = ((BasePlugin)this).Config.Bind<int>("TalkState", "Refresh Rate", 120, "The amount of time in milliseconds that the plugin will check for TalkState changes. 120 is a good sweetspot, but you can lower this if it's not precise enough. You could also up it if your host has a bad CPU, since hosts will be a bit more stressed out in this process. I would stay between 30ms and 240ms.");
OpenPAConfig.configVerbose = ((BasePlugin)this).Config.Bind<bool>("Verbose", "Enabled", false, "Enables debug logs in the BepInEx console. Can get very spammy, but useful for debugging.");
LevelAPI.OnEnterLevel += CheckIfPlayerIsInLevel;
SendDebugLog("Plugin is loaded!", verbose: false);
gameStateCheckTimer = new Timer(CheckGameState, null, TimeSpan.Zero, TimeSpan.FromSeconds(3.0));
}
public override bool Unload()
{
clientThread.Abort();
SendDebugLog("Plugin is unloading...", verbose: false);
return ((BasePlugin)this).Unload();
}
public unsafe void CheckGameState(object state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
eGameStateName currentStateName = GameStateManager.CurrentStateName;
string text = ((object)(eGameStateName)(ref currentStateName)).ToString();
if (gameStarted && text != "InLevel" && text == "Inactive")
{
((BasePlugin)this).Unload();
}
if (text == "Generating" || text == "InLevel")
{
SendDebugLog("Game is now in the 'Generating' OR 'InLevel' state. (" + text + ")", verbose: false);
mumbleLink = MumbleLinkFile.CreateOrOpen();
Frame* ptr = mumbleLink.FramePtr();
ptr->SetName("GTFO");
ptr->uiVersion = 2u;
string text2 = RandomString(16);
SendDebugLog("Setting Mumble ID to " + text2, verbose: false);
ptr->SetID(text2);
SendDebugLog("Setting context to InLevel", verbose: false);
ptr->SetContext("InLevel");
SendDebugLog("Mumble Link Shared Memory Initialized", verbose: false);
if (OpenPAConfig.configTalkState.Value)
{
PlayerStatus.PlayerStartedTalking(0, isTalking: false);
PlayerStatus.PlayerStatusChanged += PlayerStatusChangedHandler;
HostSync();
FindTalkState();
SendDebugLog("TalkState Shared Memory Initialized", verbose: false);
gameStarted = true;
}
gameStateCheckTimer.Change(-1, -1);
reportingTaskTimer = new Timer(FixedUpdated, null, TimeSpan.Zero, TimeSpan.FromMilliseconds(24.0));
}
else
{
SendDebugLog("Currently not in level. Reattempting.. (" + text + ")", verbose: true);
}
}
public void SendDebugLog(string msg, bool verbose)
{
if (verbose)
{
if (OpenPAConfig.configVerbose.Value)
{
((BasePlugin)this).Log.LogInfo((object)msg);
}
}
else
{
((BasePlugin)this).Log.LogInfo((object)msg);
}
}
public void SendErrorLog(string msg, bool verbose)
{
if (verbose)
{
if (OpenPAConfig.configVerbose.Value)
{
((BasePlugin)this).Log.LogError((object)msg);
}
}
else
{
((BasePlugin)this).Log.LogError((object)msg);
}
}
private string RandomString(int len)
{
return new string((from s in Enumerable.Repeat("ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789", len)
select s[random.Next(s.Length)]).ToArray());
}
public void CheckIfPlayerIsInLevel()
{
SendDebugLog("Player connected to level.", verbose: true);
isPlayerInLevel = true;
}
private unsafe void FixedUpdated(object state)
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_00a0: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0164: Unknown result type (might be due to invalid IL or missing references)
//IL_0169: Unknown result type (might be due to invalid IL or missing references)
//IL_016e: Unknown result type (might be due to invalid IL or missing references)
//IL_04bd: Unknown result type (might be due to invalid IL or missing references)
//IL_04c4: Expected O, but got Unknown
//IL_01cc: Unknown result type (might be due to invalid IL or missing references)
//IL_022b: Unknown result type (might be due to invalid IL or missing references)
//IL_01e7: Unknown result type (might be due to invalid IL or missing references)
//IL_0201: Unknown result type (might be due to invalid IL or missing references)
//IL_021e: Unknown result type (might be due to invalid IL or missing references)
//IL_0289: Unknown result type (might be due to invalid IL or missing references)
//IL_028e: Unknown result type (might be due to invalid IL or missing references)
//IL_0246: Unknown result type (might be due to invalid IL or missing references)
//IL_0260: Unknown result type (might be due to invalid IL or missing references)
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_02f2: Unknown result type (might be due to invalid IL or missing references)
//IL_02f8: Unknown result type (might be due to invalid IL or missing references)
//IL_02fd: Unknown result type (might be due to invalid IL or missing references)
//IL_02ba: Unknown result type (might be due to invalid IL or missing references)
//IL_02cf: Unknown result type (might be due to invalid IL or missing references)
//IL_02e7: Unknown result type (might be due to invalid IL or missing references)
//IL_036e: Unknown result type (might be due to invalid IL or missing references)
//IL_0374: Unknown result type (might be due to invalid IL or missing references)
//IL_0379: Unknown result type (might be due to invalid IL or missing references)
//IL_032a: Unknown result type (might be due to invalid IL or missing references)
//IL_0344: Unknown result type (might be due to invalid IL or missing references)
//IL_0361: Unknown result type (might be due to invalid IL or missing references)
//IL_03ec: Unknown result type (might be due to invalid IL or missing references)
//IL_03f2: Unknown result type (might be due to invalid IL or missing references)
//IL_03f7: Unknown result type (might be due to invalid IL or missing references)
//IL_03a6: Unknown result type (might be due to invalid IL or missing references)
//IL_03c0: Unknown result type (might be due to invalid IL or missing references)
//IL_03dd: Unknown result type (might be due to invalid IL or missing references)
//IL_0424: Unknown result type (might be due to invalid IL or missing references)
//IL_043e: Unknown result type (might be due to invalid IL or missing references)
//IL_045b: Unknown result type (might be due to invalid IL or missing references)
eGameStateName currentStateName = GameStateManager.CurrentStateName;
string text = ((object)(eGameStateName)(ref currentStateName)).ToString();
if (text != "InLevel" && text == "Inactive")
{
((BasePlugin)this).Unload();
}
bool flag = default(bool);
if (text != "Generating" && text != "ReadyToStopElevatorRide" && text != "StopElevatorRide" && text != "ReadyToStartLevel" && text != "InLevel")
{
ManualLogSource log = ((BasePlugin)this).Log;
BepInExWarningLogInterpolatedStringHandler val = new BepInExWarningLogInterpolatedStringHandler(44, 0, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val).AppendLiteral("Expedition Aborted, Closing Link Connection.");
}
log.LogWarning(val);
reportingTaskTimer.Change(-1, -1);
gameStateCheckTimer = new Timer(CheckGameState, null, TimeSpan.Zero, TimeSpan.FromSeconds(3.0));
mumbleLink.Dispose();
mumbleLink = null;
isPlayerInLevel = false;
}
else
{
if (!isPlayerInLevel)
{
return;
}
if (!PlayerManager.HasLocalPlayerAgent())
{
SendErrorLog("No PlayerAgent.", verbose: true);
return;
}
PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
Vector3 val2 = ((Agent)localPlayerAgent).EyePosition - new Vector3(0f, 1f, 0f);
FPSCamera fPSCamera = localPlayerAgent.FPSCamera;
if ((Object)(object)localPlayerAgent != (Object)null && (Object)(object)fPSCamera != (Object)null && text != null)
{
if (mumbleLink == null)
{
SendDebugLog("Initializing Load(). (mumbleLink == null).", verbose: false);
((BasePlugin)this).Load();
}
Frame* ptr = mumbleLink.FramePtr();
_ = fPSCamera.Position;
if (true)
{
float* fixedElementField = ptr->fCameraPosition;
*fixedElementField = fPSCamera.Position.x;
ptr->fCameraPosition[1] = fPSCamera.Position.y;
ptr->fCameraPosition[2] = fPSCamera.Position.z;
}
_ = fPSCamera.Forward;
if (true)
{
float* fixedElementField2 = ptr->fCameraFront;
*fixedElementField2 = fPSCamera.Forward.x;
ptr->fCameraFront[1] = fPSCamera.Forward.y;
ptr->fCameraFront[2] = fPSCamera.Forward.z;
}
currentStateName = GameStateManager.CurrentStateName;
if (((object)(eGameStateName)(ref currentStateName)).ToString() == "InLevel")
{
float* fixedElementField3 = ptr->fAvatarPosition;
*fixedElementField3 = val2.x;
ptr->fAvatarPosition[1] = val2.y;
ptr->fAvatarPosition[2] = val2.z;
}
else
{
_ = ((Agent)localPlayerAgent).Forward;
currentStateName = GameStateManager.CurrentStateName;
if (((object)(eGameStateName)(ref currentStateName)).ToString() != "InLevel")
{
float* fixedElementField4 = ptr->fAvatarPosition;
*fixedElementField4 = fPSCamera.Position.x;
ptr->fAvatarPosition[1] = fPSCamera.Position.y;
ptr->fAvatarPosition[2] = fPSCamera.Position.z;
}
}
_ = ((Agent)localPlayerAgent).Forward;
currentStateName = GameStateManager.CurrentStateName;
if (((object)(eGameStateName)(ref currentStateName)).ToString() == "InLevel")
{
float* fixedElementField5 = ptr->fAvatarFront;
*fixedElementField5 = ((Agent)localPlayerAgent).Forward.x;
ptr->fAvatarFront[1] = ((Agent)localPlayerAgent).Forward.y;
ptr->fAvatarFront[2] = ((Agent)localPlayerAgent).Forward.z;
}
else
{
_ = ((Agent)localPlayerAgent).Forward;
currentStateName = GameStateManager.CurrentStateName;
if (((object)(eGameStateName)(ref currentStateName)).ToString() != "InLevel")
{
float* fixedElementField6 = ptr->fAvatarFront;
*fixedElementField6 = fPSCamera.Forward.x;
ptr->fAvatarFront[1] = fPSCamera.Forward.y;
ptr->fAvatarFront[2] = fPSCamera.Forward.z;
}
}
ptr->uiTick++;
}
else if (mumbleLink != null)
{
SendDebugLog("Closing Link Connection.", verbose: false);
mumbleLink.Dispose();
mumbleLink = null;
isPlayerInLevel = false;
}
else
{
ManualLogSource log2 = ((BasePlugin)this).Log;
BepInExErrorLogInterpolatedStringHandler val3 = new BepInExErrorLogInterpolatedStringHandler(22, 0, ref flag);
if (flag)
{
((BepInExLogInterpolatedStringHandler)val3).AppendLiteral("An error has occurred.");
}
log2.LogError(val3);
}
}
}
public void FindTalkState()
{
//IL_0001: Unknown result type (might be due to invalid IL or missing references)
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
eGameStateName currentStateName = GameStateManager.CurrentStateName;
string text = ((object)(eGameStateName)(ref currentStateName)).ToString();
clientThread = new Thread(ReadMemoryMappedFile);
clientThread.Start();
SendDebugLog("Initiated TalkState!", verbose: false);
if (text != "Generating" && text != "ReadyToStopElevatorRide" && text != "StopElevatorRide" && text != "ReadyToStartLevel" && text != "InLevel")
{
SendDebugLog("Expedition Aborted, Closing TalkState Connection.", verbose: false);
isPlayerInLevel = false;
clientThread.Join();
}
void ReadMemoryMappedFile()
{
//IL_010e: Unknown result type (might be due to invalid IL or missing references)
//IL_0113: Unknown result type (might be due to invalid IL or missing references)
while (!isPlayerInLevel)
{
SendErrorLog("Player is not in level yet! Holding...", verbose: true);
Thread.Sleep(5000);
}
while (!PlayerManager.HasLocalPlayerAgent())
{
SendErrorLog("No PlayerAgent.", verbose: true);
}
PlayerAgent localPlayerAgent = PlayerManager.GetLocalPlayerAgent();
bool flag = false;
bool flag2 = false;
HashSet<string> hashSet = new HashSet<string> { "Generating", "ReadyToStopElevatorRide", "StopElevatorRide", "ReadyToStartLevel", "InLevel" };
int value = OpenPAConfig.configIntensity.Value;
try
{
using (MemoryMappedFile.OpenExisting("posaudio_mumlink"))
{
SendDebugLog("TalkState Enabled, and MemoryMappedFile found, continuing with operation.", verbose: true);
}
}
catch (FileNotFoundException)
{
SendErrorLog("TalkState enabled, but MemoryMappedFile could not be found. Disabling TalkState for this session.", verbose: false);
return;
}
catch (Exception)
{
SendErrorLog("An error occurred while initializing TalkState MMF. Aborting...", verbose: false);
return;
}
SendDebugLog("Initiated RMMF!", verbose: false);
while (true)
{
eGameStateName currentStateName2 = GameStateManager.CurrentStateName;
if (!hashSet.Contains(((object)(eGameStateName)(ref currentStateName2)).ToString()))
{
break;
}
using (MemoryMappedFile memoryMappedFile2 = MemoryMappedFile.OpenExisting("posaudio_mumlink"))
{
using MemoryMappedViewAccessor memoryMappedViewAccessor = memoryMappedFile2.CreateViewAccessor(0L, 1024L);
byte[] array = new byte[1024];
memoryMappedViewAccessor.ReadArray(0L, array, 0, 1024);
string text2 = Encoding.UTF8.GetString(array).TrimEnd('\0');
if (SNet.LocalPlayer.IsMaster)
{
if (text2 == "Talking")
{
((Agent)localPlayerAgent).Noise = (NoiseType)3;
SendDebugLog("Sending WALK type to localplayeragent.", verbose: true);
}
}
else
{
if (text2 != "Talking")
{
if (!flag2)
{
SendDebugLog("Sending stop signal for '" + SteamManager.LocalPlayerName.ToString() + "'.", verbose: true);
NetworkAPI.InvokeEvent<ClientSendData>("Client_Status", new ClientSendData
{
clientSlot = PlayerManager.GetLocalPlayerSlotIndex(),
clientStatus = false
}, (SNet_ChannelType)2);
flag2 = true;
flag = false;
}
}
else if (text2 == "Talking" && !flag)
{
SendDebugLog("Sending talk signal for '" + localPlayerAgent.PlayerName + "'!", verbose: true);
NetworkAPI.InvokeEvent<ClientSendData>("Client_Status", new ClientSendData
{
clientSlot = PlayerManager.GetLocalPlayerSlotIndex(),
clientStatus = true
}, (SNet_ChannelType)2);
flag = true;
flag2 = false;
}
flag = false;
}
}
Thread.Sleep(value);
}
}
}
public void HostSync()
{
SendDebugLog("Checking HostSync...", verbose: true);
if (NetworkAPI.IsEventRegistered("Client_Status"))
{
return;
}
NetworkAPI.RegisterEvent<ClientSendData>("Client_Status", (Action<ulong, ClientSendData>)delegate(ulong senderId, ClientSendData packet)
{
if (SNet.LocalPlayer.IsMaster)
{
SendDebugLog($"Message received from {senderId}: {packet.clientSlot}, {packet.clientStatus}.", verbose: true);
if (packet.clientStatus)
{
PlayerStatus.PlayerStartedTalking(packet.clientSlot, isTalking: true);
}
else
{
PlayerStatus.PlayerStoppedTalking(packet.clientSlot);
}
}
SendDebugLog("Triggered NetworkEvent.", verbose: true);
});
SendDebugLog("Registered NetworkEvent.", verbose: true);
}
public void PlayerStatusChangedHandler(object sender, PlayerStatusChangedEvent e)
{
int playerID = e.PlayerID;
PlayerAgent val = null;
if (e.IsTalking)
{
SendDebugLog($"Player {e.PlayerID} started talking.", verbose: true);
if (PlayerManager.TryGetPlayerAgent(ref playerID, ref val))
{
((Agent)val).Noise = (NoiseType)3;
}
}
else
{
SendDebugLog($"Player {e.PlayerID} stopped talking.", verbose: true);
}
}
}
public static class PlayerStatus
{
private static ConcurrentDictionary<int, bool> playerStatus = new ConcurrentDictionary<int, bool>();
public static event EventHandler<PlayerStatusChangedEvent> PlayerStatusChanged;
public static void PlayerStartedTalking(int playerID, bool isTalking)
{
playerStatus.AddOrUpdate(playerID, isTalking, (int key, bool oldValue) => isTalking);
OnPlayerStatusChanged(new PlayerStatusChangedEvent(playerID, isTalking));
}
public static void PlayerStoppedTalking(int playerID)
{
bool value;
bool flag = playerStatus.TryRemove(playerID, out value);
}
public static List<int> GetPlayersTalking()
{
return (from kv in playerStatus
where kv.Value
select kv.Key).ToList();
}
private static void OnPlayerStatusChanged(PlayerStatusChangedEvent e)
{
PlayerStatus.PlayerStatusChanged?.Invoke(null, e);
}
}
public class PlayerStatusChangedEvent : EventArgs
{
public int PlayerID { get; }
public bool IsTalking { get; }
public PlayerStatusChangedEvent(int playerID, bool isTalking)
{
PlayerID = playerID;
IsTalking = isTalking;
}
}
}
namespace mumblelib
{
internal class Text
{
public static Encoding Encoding = System.Text.Encoding.Unicode;
}
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)]
public struct Frame
{
public uint uiVersion;
public uint uiTick;
public unsafe fixed float fAvatarPosition[3];
public unsafe fixed float fAvatarFront[3];
public unsafe fixed float fAvatarTop[3];
public unsafe fixed ushort name[256];
public unsafe fixed float fCameraPosition[3];
public unsafe fixed float fCameraFront[3];
public unsafe fixed float fCameraTop[3];
public unsafe fixed ushort id[256];
public uint context_len;
public unsafe fixed byte context[256];
public unsafe fixed ushort description[2048];
public unsafe void SetName(string name)
{
fixed (Frame* ptr = &this)
{
byte[] bytes = Text.Encoding.GetBytes(name + "\0");
Marshal.Copy(bytes, 0, new IntPtr(ptr->name), bytes.Length);
}
}
public unsafe void SetDescription(string desc)
{
fixed (Frame* ptr = &this)
{
byte[] bytes = Text.Encoding.GetBytes(desc + "\0");
Marshal.Copy(bytes, 0, new IntPtr(ptr->description), bytes.Length);
}
}
public unsafe void SetID(string id)
{
fixed (Frame* ptr = &this)
{
byte[] bytes = Text.Encoding.GetBytes(id + "\0");
Marshal.Copy(bytes, 0, new IntPtr(ptr->id), bytes.Length);
}
}
public unsafe void SetContext(string context)
{
fixed (Frame* ptr = &this)
{
byte[] bytes = Encoding.UTF8.GetBytes(context);
context_len = (uint)Math.Min(256, bytes.Length);
Marshal.Copy(bytes, 0, new IntPtr(ptr->context), (int)context_len);
}
}
}
public class MumbleLinkFile : IDisposable
{
private readonly MemoryMappedFile memoryMappedFile;
private unsafe readonly Frame* ptr;
private bool disposed;
private static string LinkFileName()
{
return "MumbleLink";
}
public unsafe MumbleLinkFile(MemoryMappedFile memoryMappedFile)
{
this.memoryMappedFile = memoryMappedFile ?? throw new ArgumentNullException("memoryMappedFile");
byte* pointer = null;
memoryMappedFile.CreateViewAccessor().SafeMemoryMappedViewHandle.AcquirePointer(ref pointer);
ptr = (Frame*)pointer;
}
public unsafe Frame* FramePtr()
{
return ptr;
}
public static MumbleLinkFile CreateOrOpen()
{
return new MumbleLinkFile(MemoryMappedFile.CreateOrOpen(LinkFileName(), Marshal.SizeOf<Frame>()));
}
public void Dispose()
{
Dispose(disposing: true);
GC.SuppressFinalize(this);
}
private void assertNotDisposed()
{
if (disposed)
{
throw new ObjectDisposedException(GetType().FullName);
}
}
protected virtual void Dispose(bool disposing)
{
if (!disposed)
{
if (disposing)
{
memoryMappedFile.Dispose();
}
disposed = true;
}
}
}
}