Created
May 20, 2026 21:47
-
-
Save z16/2d022186f54b553a5444785742a4ef2d to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| public unsafe class Ipc { | |
| public Ipc(String addon) { | |
| AddonBytes = Encoding.UTF8.GetBytes(addon); | |
| if (AddonBytes.Length >= AddonSize) { | |
| throw new InvalidDataException("Maximum length for addon name is 31 bytes in UTF-8."); | |
| } | |
| } | |
| public void Send(String message, String character) => | |
| Send(message, GetPid(character)); | |
| public void Send(String message, Int32? pid = null) { | |
| var messageBytes = Encoding.UTF8.GetBytes(message); | |
| if (messageBytes.Length >= TextSize) { | |
| throw new InvalidDataException("Maximum length for the message is 2015 bytes in UTF-8."); | |
| } | |
| Send(messageBytes, pid); | |
| } | |
| public void Send(Byte[] messageBytes, String character) => | |
| Send(messageBytes, GetPid(character)); | |
| public void Send(Byte[] messageBytes, Int32? pid = null) { | |
| if (messageBytes.Length >= TextSize) { | |
| throw new InvalidDataException("Maximum length for the message is 2015 bytes."); | |
| } | |
| Mutex.WaitOne(); | |
| try { | |
| using var instancesFile = MemoryMappedFile.CreateOrOpen(@"Local\Windower MMF IPC Instances", sizeof(Instance) * InstanceCount, MemoryMappedFileAccess.ReadWrite); | |
| using var instancesView = instancesFile.CreateViewAccessor(); | |
| for (var i = 0; i < InstanceCount; ++i) { | |
| instancesView.Read<Instance>(i * sizeof(Instance), out var instance); | |
| if (instance.Id == 0 || pid.HasValue && instance.Id != pid.Value) { | |
| continue; | |
| } | |
| var name = new String(instance.Name, 0, NameSize); | |
| using var instanceFile = MemoryMappedFile.OpenExisting(@"Local\Windower MMF " + name, MemoryMappedFileRights.Write); | |
| using var instanceView = instanceFile.CreateViewAccessor(); | |
| var offset = instance.Index * sizeof(Message); | |
| instanceView.WriteArray(offset, AddonBytes, 0, AddonBytes.Length); | |
| instanceView.WriteArray(offset + AddonBytes.Length, Zeroes, 0, AddonSize - AddonBytes.Length); | |
| instanceView.WriteArray(offset + AddonSize, messageBytes, 0, messageBytes.Length); | |
| instanceView.WriteArray(offset + AddonSize + messageBytes.Length, Zeroes, 0, TextSize - messageBytes.Length); | |
| instancesView.Write(IndexOffset, (instance.Index + 1) % MessageCount); | |
| using var instanceEvent = EventWaitHandle.OpenExisting(@"Local\Windower Event " + name); | |
| instanceEvent.Set(); | |
| break; | |
| } | |
| } finally { | |
| Mutex.ReleaseMutex(); | |
| } | |
| } | |
| private readonly Byte[] AddonBytes; | |
| private static readonly Mutex Mutex = new(@"Local\Windower Mutex IPC", new() { | |
| CurrentUserOnly = false, | |
| }); | |
| private struct Instance { | |
| public UInt32 Id; | |
| public UInt32 Index; | |
| public fixed Char Name[NameSize]; | |
| } | |
| private struct Message { | |
| public fixed Byte Addon[AddonSize]; | |
| public fixed Byte Text[TextSize]; | |
| } | |
| private static readonly IntPtr IndexOffset = Marshal.OffsetOf<Instance>(nameof(Instance.Index)); | |
| private const Int32 InstanceCount = 100; | |
| private const Int32 MessageCount = 0x10; | |
| private const Int32 NameSize = 0x10; | |
| private const Int32 AddonSize = 0x20; | |
| private const Int32 TextSize = 0x7E0; | |
| private static readonly Byte[] Zeroes = [.. Enumerable.Range(0, TextSize).Select(_ => (Byte)0)]; | |
| private static Int32 GetPid(String character) => | |
| Process.GetProcesses().Single(process => process.MainWindowTitle == character).Id; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment