XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEWarframe

【WinUI】基于Warframe游戏本体的公开服务器以及安装器

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFEWarframe.Bridge;

internal static unsafe partial class GameTestLua
{
    internal readonly record struct Ref(int Index);

    // Used by fixed production HUD calls as well as the opt-in test adapter.
    // Each scope owns its stack values; Lua tables own all retained resources.
    internal sealed class Scope : IDisposable
    {
        private readonly nint state;
        private readonly int saved;
        private bool returnsValue;
        internal Scope(nint scriptState = 0)
        {
            state = scriptState != 0 ? scriptState : *(nint*)(image + 0x2734D40);
            if (state == 0) throw new InvalidOperationException("Game scripts are not initialized.");
            saved = Top(state);
            ((delegate* unmanaged<nint, int, void>)(image + 0x11E1C40))(state, 1024);
        }
        internal int Count => Top(state);
        internal Ref At(int index) => new(index);
        internal Ref NativeFunction(nint function, Ref? captured = null)
        {
            if (captured is { } value) Copy(state, value.Index);
            ((delegate* unmanaged<nint, nint, nint, int, nint, void>)(image + 0x80DFE0))(state, function, 0, captured is null ? 0 : 1, 0);
            return new(Top(state));
        }
        internal Ref Captured(int index) { Copy(state, -10002 - index); return new(Top(state)); }
        internal void AssignRaw(nint target, Ref source) => new ReadOnlySpan<byte>((void*)Value(state, source.Index), 16).CopyTo(new Span<byte>((void*)target, 16));
        internal Ref RawValue(nint source)
        {
            var destination = *(nint*)(state + 8);
            new ReadOnlySpan<byte>((void*)source, 16).CopyTo(new Span<byte>((void*)destination, 16));
            *(nint*)(state + 8) = destination + 16;
            return new(Top(state));
        }
        internal void Return(Ref result)
        {
            new ReadOnlySpan<byte>((void*)Value(state, result.Index), 16).CopyTo(new Span<byte>((void*)Value(state, saved + 1), 16));
            returnsValue = true;
        }
        internal Ref Global(string name) { Get(state, -10002, name); return new(Top(state)); }
        internal Ref Field(Ref owner, string name, bool literal = true)
        { Get(state, owner.Index, name, literal); return new(Top(state)); }
        internal int Kind(Ref value) => Type(state, value.Index);
        internal nint Object(Ref value)
        {
            if (Kind(value) != 9) return 0;
            var reference = *(nint*)(*(nint*)Value(state, value.Index) + 0x18);
            return reference == 0 ? 0 : *(nint*)reference;
        }
        internal nint ResourceType(Ref value) { var instance = Object(value); return instance == 0 ? 0 : *(nint*)(instance + 8); }
        internal nint Identity(Ref value) => *(nint*)Value(state, value.Index);
        internal float Number(Ref value) => Kind(value) == 3 ? *(float*)Value(state, value.Index) : 0;
        internal string? Text(Ref value) => Kind(value) == 6 ? Describe(Value(state, value.Index))["text"]!.GetValue<string>() : null;
        internal bool Boolean(Ref value) => Kind(value) == 1 && *(uint*)Value(state, value.Index) != 0;
        internal Ref Table(int array = 0, int fields = 0)
        {
            ((delegate* unmanaged<nint, int, int, void>)(image + 0xFADDA0))(state, array, fields);
            return new(Top(state));
        }
        internal Ref Call(Ref function, params object?[] arguments)
        {
            if (Kind(function) != 8) throw new InvalidOperationException("HUD function is unavailable.");
            Copy(state, function.Index);
            foreach (var argument in arguments) Push(argument);
            GameTestLua.Call(state, arguments.Length);
            return new(Top(state));
        }
        internal Ref Method(Ref owner, string name, params object?[] arguments)
        {
            var before = Top(state);
            Get(state, owner.Index, name, false);
            if (Type(state, Top(state)) != 8) throw new InvalidOperationException("HUD method is unavailable: " + name);
            Copy(state, owner.Index);
            foreach (var argument in arguments) Push(argument);
            try { GameTestLua.Call(state, arguments.Length + 1); }
            catch (Exception ex) { throw new InvalidOperationException("HUD method " + name + ": " + ex.Message, ex); }
            if (Top(state) != before + 1) throw new InvalidOperationException("Unexpected HUD stack result.");
            return new(Top(state));
        }
        internal Ref Raw(Ref table, object key) => Call(Global("rawget"), table, key);
        internal void Set(Ref table, object key, object? value)
        {
            var before = Top(state);
            Call(Global("rawset"), table, key, value);
            SetTop(state, before);
        }
        internal Ref Load(string path) => Call(Global("Type"), path);
        internal Ref Require(string module) => Call(Global("require"), module);
        private void Push(object? argument)
        {
            if (argument is Ref reference) { Copy(state, reference.Index); return; }
            if (argument is string text) { PushString(state, text); return; }
            var value = *(nint*)(state + 8); new Span<byte>((void*)value, 16).Clear();
            if (argument is bool flag) { *(uint*)value = flag ? 1u : 0u; *(int*)(value + 12) = 1; }
            else if (argument is not null) { *(float*)value = Convert.ToSingle(argument, System.Globalization.CultureInfo.InvariantCulture); *(int*)(value + 12) = 3; }
            *(nint*)(state + 8) = value + 16;
        }
        public void Dispose() => SetTop(state, saved + (returnsValue ? 1 : 0));
    }
}