mumain/ClientLibrary/ConnectionManager.ClientToServer.Custom.cs

73 lines
3 KiB
C#
Raw Permalink Normal View History

// <copyright file="ConnectionManager.ClientToServer.Custom.cs" company="MUnique">
// Licensed under the MIT License. See LICENSE file in the project root for full license information.
// </copyright>
namespace MUnique.Client.Library;
using System;
using System.Runtime.InteropServices;
using System.Text;
using MUnique.OpenMU.Network;
using MUnique.OpenMU.Network.Packets.ClientToServer;
using MUnique.OpenMU.Network.Xor;
/// <summary>
/// Extension methods to start writing messages of this namespace on a <see cref="IConnection"/>.
/// </summary>
public unsafe partial class ConnectionManager
{
private static readonly Xor3Encryptor Xor3Encryptor = new(0);
/// <summary>
/// Sends a <see cref="LoginLongPassword" /> to this connection.
/// </summary>
/// <param name="handle">The handle of the connection.</param>
/// <param name="username">The user name, "encrypted" with Xor3.</param>
/// <param name="password">The password, "encrypted" with Xor3.</param>
/// <param name="tickCount">The tick count.</param>
/// <param name="clientVersion">The client version.</param>
/// <param name="clientSerial">The client serial.</param>
/// <remarks>
/// Is sent by the client when: The player tries to log into the game.
/// Causes reaction on server side: The server is authenticating the sent login name and password. If it's correct, the state of the player is proceeding to be logged in.
/// </remarks>
[UnmanagedCallersOnly(EntryPoint = "ConnectionManager_SendLogin")]
public static void SendLogin(int handle, IntPtr username, IntPtr password, uint @tickCount, byte* @clientVersion, byte* @clientSerial)
{
if (!Connections.TryGetValue(handle, out var connection))
{
return;
}
try
{
Run and connect the client natively on Linux (issue #462 Phase 4) The engine now boots into the login scene, renders via SDL/OpenGL, and connects to a server on Linux. Brings up the remaining runtime pieces and fixes the bugs that surfaced once the game actually ran. Networking (.NET client library on Linux): - Build MUnique.Client.Library as a native linux-x64 Native AOT shared object and dlopen the .so instead of the Windows .dll. - Fix the native-to-managed string marshalling: the client passes wchar_t*, which is 4-byte UTF-32 on Linux but the library decoded it as UTF-16, garbling the server address into a bogus IP so connect() hung forever on the main thread (the apparent "black screen"). Decode by the platform's real wchar_t width. Updates the XSLT template so regeneration stays correct. Runtime fixes uncovered by running: - Config was never read on Linux: the exe-dir split looked for a backslash only, so config.ini was never found and every setting fell back to its default. Accept either path separator. - UI piled into the top-left: CInput::Create bailed on the null SDL window handle before setting the screen size, so centered windows computed negative positions. Set the size regardless of the handle off Windows. - LP64 width bugs reading binary assets (size fields are 32-bit on disk, but long/size_t are 8 bytes on Linux x64): pet.bmd speed array, BMD encrypted size, camera walk-script waypoint count. - Double fclose() of the same handle (filter file, object files): tolerated on the old CRT, a double-free on glibc. - mu_swprintf bounds the buffer by its real array size to stop a fortify abort, and the GL frame can be dumped via MU_CAPTURE_FRAME for headless verification. Portable subsystems: - GDI text backend backed by stb_truetype (CreateFont/CreateDIBSection/ TextOut), so UI text renders without Win32 GDI. - Case-correcting path resolver so Windows-style asset paths resolve on a case-sensitive filesystem, wired through every file-open shim. - GameShop compiles on Linux: the UI and list managers build, only the WinINet/urlmon downloader is excluded, with the download entry points failing gracefully. - Portable shims extended: StrSafe, Sleep/GetLastError, file attribute and directory helpers, system-info for the crash log, and the Linux entry point now calls the shared WinMain bootstrap.
2026-06-13 18:22:03 +02:00
var usernameStr = NativeInterop.PtrToWideString(@username);
var passwordStr = NativeInterop.PtrToWideString(@password);
// todo: check if username or password is too long
connection.CreateAndSend(pipeWriter =>
{
Span<byte> usernameBytes = stackalloc byte[10];
Span<byte> passwordBytes = stackalloc byte[20];
Encoding.UTF8.GetBytes(usernameStr, usernameBytes);
Encoding.UTF8.GetBytes(passwordStr, passwordBytes);
Xor3Encryptor.Encrypt(usernameBytes);
Xor3Encryptor.Encrypt(passwordBytes);
var length = LoginLongPasswordRef.Length;
var packet = new LoginLongPasswordRef(pipeWriter.GetSpan(length)[..length]);
usernameBytes.CopyTo(packet.Username);
passwordBytes.CopyTo(packet.Password);
packet.TickCount = @tickCount;
new Span<byte>(@clientVersion, packet.ClientVersion.Length).CopyTo(packet.ClientVersion);
new Span<byte>(@clientSerial, packet.ClientSerial.Length).CopyTo(packet.ClientSerial);
return length;
});
}
catch
{
// Log exception
}
}
}