// // Licensed under the MIT License. See LICENSE file in the project root for full license information. // namespace MUnique.Client.Library; using System; using System.Runtime.InteropServices; using System.Text; using MUnique.OpenMU.Network; using MUnique.OpenMU.Network.Packets.ChatServer; using MUnique.OpenMU.Network.Xor; /// /// Extension methods to start writing messages of this namespace on a . /// public partial class ConnectionManager { private const int TokenOffset = 6; private const int MessageOffset = 5; private static readonly Xor3Encryptor TokenEncryptor = new(TokenOffset); private static readonly Xor3Encryptor MessageEncryptor = new(MessageOffset); /// /// Sends a to this connection. /// /// The handle of the connection. /// The room id. /// The token to authenticate the client. /// /// Is sent by the client when: This packet is sent by the client after it connected to the server, to authenticate itself. /// Causes reaction on server side: The server will check the token. If it's correct, the client gets added to the requested chat room. /// [UnmanagedCallersOnly(EntryPoint = "ConnectionManager_SendAuthenticateExt")] public static void SendAuthenticateExt(int handle, ushort @roomId, uint token) { if (!Connections.TryGetValue(handle, out var connection)) { return; } try { connection.CreateAndSend(pipeWriter => { var length = AuthenticateRef.Length; var packet = new AuthenticateRef(pipeWriter.GetSpan(length)[..length]); packet.RoomId = @roomId; var tokenString = token.ToString(); Encoding.UTF8.GetBytes(tokenString, packet.Token); TokenEncryptor.Encrypt(packet); return length; }); } catch { // Log exception } } /// /// Sends a to this connection. /// /// The handle of the connection. /// The sender index. /// The message. It's "encrypted" with the 3-byte XOR key (FC CF AB). /// /// Is sent by the server when: This packet is sent by the server after another chat client sent a message to the current chat room. /// Causes reaction on client side: The client will show the message. /// [UnmanagedCallersOnly(EntryPoint = "ConnectionManager_SendChatMessageExt")] public static void SendChatMessageExt(int handle, byte @senderIndex, IntPtr @message) { if (!Connections.TryGetValue(handle, out var connection)) { return; } try { connection.CreateAndSend(pipeWriter => { var messageString = Marshal.PtrToStringAuto(@message); var messageLength = Encoding.UTF8.GetByteCount(messageString!); var length = ChatMessageRef.GetRequiredSize(messageLength); var packet = new ChatMessageRef(pipeWriter.GetSpan(length)[..length]); packet.SenderIndex = @senderIndex; packet.MessageLength = (byte)messageLength; Encoding.UTF8.GetBytes(messageString, packet.Message); MessageEncryptor.Encrypt(packet); return length; }); } catch { // Log exception } } }