mirror of
https://github.com/sven-n/MuMain
synced 2026-08-15 20:32:27 -04:00
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.
53 lines
1.8 KiB
C#
53 lines
1.8 KiB
C#
// <copyright file="NativeInterop.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;
|
|
|
|
/// <summary>
|
|
/// Helpers for marshalling strings passed from the native (C++) client.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// The native client passes strings as <c>wchar_t*</c>. <c>wchar_t</c> is 2 bytes
|
|
/// (UTF-16) on Windows but 4 bytes (UTF-32) on Linux/macOS, while
|
|
/// <c>Marshal.PtrToStringAuto</c> always decodes UTF-16. Reading a Linux UTF-32
|
|
/// buffer as UTF-16 garbles every character (e.g. a host address turns into
|
|
/// nonsense and the connection hangs). This decodes by the platform's real
|
|
/// <c>wchar_t</c> width so both sides agree.
|
|
/// </remarks>
|
|
internal static class NativeInterop
|
|
{
|
|
/// <summary>
|
|
/// Decodes a native <c>wchar_t*</c> string using the platform's wchar_t width.
|
|
/// </summary>
|
|
/// <param name="ptr">Pointer to the native string (may be zero).</param>
|
|
/// <returns>The managed string, or <see langword="null"/> for a null pointer.</returns>
|
|
public static unsafe string? PtrToWideString(nint ptr)
|
|
{
|
|
if (ptr == 0)
|
|
{
|
|
return null;
|
|
}
|
|
|
|
// Windows wchar_t is 2 bytes (UTF-16); the built-in decoder is correct.
|
|
if (OperatingSystem.IsWindows())
|
|
{
|
|
return Marshal.PtrToStringUni(ptr);
|
|
}
|
|
|
|
// Unix wchar_t is 4 bytes (UTF-32). Find the null terminator (a 32-bit
|
|
// zero) and decode the preceding code units.
|
|
var p = (uint*)ptr;
|
|
var count = 0;
|
|
while (p[count] != 0)
|
|
{
|
|
count++;
|
|
}
|
|
|
|
return Encoding.UTF32.GetString((byte*)ptr, count * sizeof(uint));
|
|
}
|
|
}
|