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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
namespace XFEEDToolBox.Plugin;

internal static unsafe partial class Navigation
{
    // Exact string comparisons in original1D5F600. The prefix loops include
    // each literal's NUL; they are exact matches, not StartsWith matches.
    static readonly HashSet<string> GalaxySocialGameplayStates=new(StringComparer.Ordinal)
    {
        "InGame","Pause","Respawn","BuyArx_Buffer","BuyArx_Pause","BuyArx_PC","BuyArx_PS4","BuyArx_XB1",
        "Cancel CQC join","CancelMultiCrewJoin","CancelScenarioLoad","CheckMultiplayerPrivilegeForFriends",
        "Confirm Quit To CQC","Confirm Quit To MultiCrew","Confirm Quit To Scenario","Confirmed Quit Game",
        "Confirmed Quit To Game","Confirmed Quit To Main Menu","Confirmed Restart Checkpoint","Confirmed Restart Scenario",
        "CustomerSupport_Pause","Debug_InEditor","DiedInHumanoidConflictZone","ExitOptions","Friends Management Screen",
        "FriendsUnavailable","HelpAndInfo_PauseMenu","Increment checkpoint","IssueTracker_Pause","Leaving Pause Menu",
        "OpenCustomerSupport_PC","OpenCustomerSupport_PS4","OpenCustomerSupport_XB1","OpenIssueTracker_PC",
        "OpenIssueTracker_PS4","OpenIssueTracker_XB1","Pause Audio Options","Pause Control Binding Options",
        "Pause Controller Layout","Pause Graphic Options","Pause Options","PrePauseMenu","ScenarioSuccess",
        "ScenarioRestartOptions","Skip Scenario","Skip Scenario: Flow stage","Skip to next Checkpoint","StartRespawn"
    };

    static bool? GalaxyFriendMarkerCurrent(int status,int? mode,bool? gameplay)
    {
        // Exact 3AFF080 conjunction, independent from the display option.
        if(status is not(5 or 6)||gameplay==false||mode==0)return false;
        if(mode==1)return status==5?gameplay:false;
        if(mode==2)return status==6?gameplay:false;
        return null;
    }

    static bool CopyGalaxySocialModes(nuint flow,nuint expectedImage,uint avatarTypeId,out int? mode,out bool? gameplay)
    {
        mode=null;gameplay=null;
        try
        {
            // 1D00EC0, 1D507A0: same flow interface used by SessionMenu.
            if(flow<0x10058||Pointer(flow)!=expectedImage+0x5239F60||Pointer(flow-0x48)==0)return false;
            var csm=Pointer(flow+0x310);
            if(csm<0x10000||Pointer(csm)!=expectedImage+0x513BE00)return false;
            var current=Pointer(csm+0x100);if(current<0x10000)return false;
            var name=Pointer(current);if(!SessionName(name,out var state))return false;
            gameplay=GalaxySocialGameplayStates.Contains(state);

            // 1D53050 lazy-initialises this reference. Only copy it when
            // already present; never call that getter or initialise config.
            var config=Pointer(flow+0x568);
            if(config==0)return Stable();
            // Original integer value vtable4DDED20, whose type getter150DD0
            // returns5F059C0. 1D53050 reads the signed value at+10.
            if(Pointer(config)!=expectedImage+0x4DDED20)return Stable();
            var cached=Read<int>(config+0x10);if(cached is <0 or >2)return Stable();
            if(cached!=2){mode=cached;return Stable()&&StableConfig();}

            // Original2175F70 (5F3492C iface+40) is exactly state12..15.
            // If false, 1D53050 may suppress mode2 for an avatar value<100.
            var multiplayer=Pointer(flow+0x90);
            if(multiplayer<0x10000||Pointer(multiplayer)!=expectedImage+0x5269B28)return Stable();
            var multiplayerState=Read<sbyte>(multiplayer+0x140);
            if(multiplayerState is >=12 and <=15)
            {
                mode=2;return Stable()&&StableConfig()&&StableMultiplayer();
            }
            var user=Pointer(flow+0xD8);
            if(user<0x10000||Pointer(user)!=expectedImage+0x52A0258)return Stable();
            // Original978AF0 yields user+138's weak life, 636A80 tests>4.
            var life=Pointer(user+0x138);nuint components=0,avatar=0;int lifeState=0;uint value=0;
            if(life!=0)
            {
                lifeState=Read<int>(life+0xC0);
                if(lifeState>4)
                {
                    components=Pointer(life+0xC8);if(components<0x10030)return Stable();
                    avatar=RegisteredComponent(components-0x30,avatarTypeId);
                    if(avatar!=0)
                    {
                        if(Pointer(avatar)!=expectedImage+0x52A3188)return Stable();
                        // Original26055E0. Preserve its unsigned comparison.
                        value=Read<uint>(avatar+0x138);
                    }
                }
            }
            mode=avatar!=0&&value<100?0:2;
            if(!Stable()||!StableConfig()||!StableMultiplayer()||Pointer(flow+0xD8)!=user||
               Pointer(user)!=expectedImage+0x52A0258||Pointer(user+0x138)!=life||
               life!=0&&(Read<int>(life+0xC0)!=lifeState||lifeState>4&&Pointer(life+0xC8)!=components)||
               avatar!=0&&(Pointer(avatar)!=expectedImage+0x52A3188||Read<uint>(avatar+0x138)!=value))
            {mode=null;gameplay=null;return false;}
            return true;

            bool Stable()=>Pointer(flow)==expectedImage+0x5239F60&&Pointer(flow+0x310)==csm&&
                Pointer(csm)==expectedImage+0x513BE00&&Pointer(csm+0x100)==current&&Pointer(current)==name&&
                SessionName(name,out var after)&&after==state;
            bool StableConfig()=>Pointer(flow+0x568)==config&&Pointer(config)==expectedImage+0x4DDED20&&Read<int>(config+0x10)==cached;
            bool StableMultiplayer()=>Pointer(flow+0x90)==multiplayer&&Pointer(multiplayer)==expectedImage+0x5269B28&&
                Read<sbyte>(multiplayer+0x140)==multiplayerState;
        }
        catch{mode=null;gameplay=null;return false;}
    }
}