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

XFEEDToolBox

【WinUI】XFE精英危险工具箱

公开
关注 0 Fork 0 Star 0
UTF-8
// Build-pinned diagnostics and original eligible menu actions. No screen, input or readiness overrides.
const module = Process.getModuleByName('EliteDangerous64.exe');
if (module.path.toLowerCase() !== PROFILE.image.toLowerCase()) throw new Error('Unexpected game image');
const base = module.base;
const seen = new Set();
let flowThread = 0, flowState = '', lastPose = 0, lastFlow = 0, entered = false, menuStage = 0;
const poseBindings = new Map();
function emit(value) { send({...value, at: new Date().toISOString()}); }
function once(value) { const key=JSON.stringify(value);if(!seen.has(key)){seen.add(key);emit(value);} }
function rva(pointer) {return pointer.compare(base)>=0&&pointer.compare(base.add(module.size))<0?pointer.sub(base).toUInt32():null;}
function name(pointer) {try {const text=pointer.readUtf8String();return /^[A-Za-z][A-Za-z0-9_ .-]{0,127}$/.test(text)?text:null;}catch(_){return null;}}
function leaf(object, method) {
    const code=new Uint8Array(method.readByteArray(12));
    if(code[0]!==0x48)return null;
    if(code[1]===0x8D&&code[2]===0x81&&code[7]===0xC3)return object.add(method.add(3).readS32());
    if(code[1]===0x8D&&code[2]===0x41&&code[4]===0xC3)return object.add(method.add(3).readS8());
    if(code[1]===0x8B&&code[2]===0x81&&code[7]===0xC3)return object.add(method.add(3).readS32()).readPointer();
    if(code[1]===0x8B&&code[2]===0x41&&code[4]===0xC3)return object.add(method.add(3).readS8()).readPointer();
    return null;
}
function currentFlow(context) {
    const flow=context.add(0x30).readPointer(),table=flow.readPointer();
    if(!table.add(0x20).readPointer().equals(base.add(PROFILE.flowAction)))return null;
    const csm=flow.add(0x310).readPointer();
    const from=name(csm.add(0x100).readPointer().readPointer()),to=name(csm.add(0x108).readPointer().readPointer());
    if(from===null||to===null)return null;
    return {flow,csm,from,to};
}
Interceptor.attach(base.add(PROFILE.flowUpdate),{
    onEnter(args){this.flowContext=args[1];},
    onLeave(){
        if(Date.now()-lastFlow<100)return;lastFlow=Date.now();
        try {
            const state=currentFlow(this.flowContext);if(state===null)return;
            const thread=Process.getCurrentThreadId();
            if(flowThread!==0&&flowThread!==thread)throw new Error('Game owning thread changed');
            flowThread=thread;flowState=state.from===state.to?state.from:'';
            once({kind:'flow',from:state.from,to:state.to,thread,flowVtable:rva(state.flow.readPointer()),csmVtable:rva(state.csm.readPointer())});
            if(flowState==='InGame'&&!entered){entered=true;emit({kind:'native-world-entered'});}
        }catch(error){once({kind:'flow-unavailable',error:String(error)});}
    }
});
const selectMenu = new NativeFunction(base.add(PROFILE.menuAction),'void',['pointer','pointer','int'],{scheduling:'exclusive'});
if(ENTER_SOLO)Interceptor.attach(base.add(PROFILE.menuUpdate),{
    onEnter(args){this.activity=args[0];},
    onLeave(){
        if(entered||Process.getCurrentThreadId()!==flowThread)return;
        try {
            const activity=this.activity;
            if(!activity.add(0x80).readPointer().add(8).readPointer().equals(base.add(PROFILE.menuAction)))return;
            const flow=activity.add(0x118).readPointer();
            if(!flow.readPointer().add(0x20).readPointer().equals(base.add(PROFILE.flowAction)))return;
            const csm=flow.add(0x310).readPointer(),from=name(csm.add(0x100).readPointer().readPointer()),to=name(csm.add(0x108).readPointer().readPointer());
            if(from!==to)return;
            const wanted=menuStage===0&&from==='MainMenu'?'ContinueMenu':menuStage===1&&from==='ContinueMenu'?'SetupPlaySolo':null;
            if(wanted===null)return;
            const definition=activity.add(0x10).readPointer(),selected=activity.add(0x208).readU32(),categories=definition.add(0x10).readU32();
            if(categories>128||selected>=categories)return;
            const category=definition.add(8).readPointer().add(selected*0x58);
            if(category.readU8()<1||category.readU8()>3)return;
            const count=category.add(0x48).readU32(),buttons=category.add(0x40).readPointer(),cache=activity.add(0x248).readPointer();
            if(count>128||activity.add(0x240).readU64().toNumber()!==count)return;
            let candidate=-1;const rows=[];
            for(let index=0;index<count;index++) {
                const button=buttons.add(index*0x78),cached=cache.add(index*0xC8);
                const configured=new Uint8Array(button.readByteArray(0x78)),actual=new Uint8Array(cached.add(0x30).readByteArray(0x78));
                if(configured.some((byte,offset)=>byte!==actual[offset]))throw new Error('Menu cache/definition mismatch');
                const action=name(button.readPointer().readPointer()),eligible=cached.readU16();
                rows.push({action,eligible});
                if(action===wanted&&eligible===0x0101){if(candidate>=0)throw new Error('Ambiguous action');candidate=index;}
            }
            once({kind:'menu-eligibility',wanted,rows});
            if(candidate<0||cache.add(candidate*0xC8).readU16()!==0x0101)return;
            menuStage++;emit({kind:'original-native-menu-action',action:wanted,thread:flowThread});
            selectMenu(activity.add(0x80),ptr(0),candidate);
        }catch(error){once({kind:'menu-unavailable',error:String(error)});}
    }
});
function poseFor(physics) {
    const key=physics.toString();let binding=poseBindings.get(key);
    if(binding!==undefined)return binding;
    const owner=physics.add(0x20).readPointer(),ownerTable=owner.readPointer(),method=ownerTable.add(0x20).readPointer();
    const reference=leaf(owner,method);
    if(reference===null){once({kind:'owner-getter-unmapped',method:rva(method),code:method.readByteArray(24)});return null;}
    const life=reference.readPointer();if(life.add(0xC0).readU32()!==8)return null;
    const component=life.add(0xC8).readPointer(),root=component.sub(0x30),array=root.add(0x18).readPointer();
    let found=null;
    for(let index=0;index<512;index++){
        try{
            const object=array.add(index*8).readPointer(),table=object.readPointer();
            if(!table.add(0x28).readPointer().equals(base.add(PROFILE.poseGetter)))continue;
            if(found!==null&&!found.object.equals(object))throw new Error('Ambiguous ship transform');
            found={object,life,id:life.add(0xB0).readU64().toString(),index};
        }catch(_){}
    }
    if(found!==null){poseBindings.set(key,found);emit({kind:'player-transform-binding',id:found.id,index:found.index,transform:found.object.toString(),physics:key,ownerMethod:rva(method)});}
    return found;
}
function pooled(poolRva,owner,expectedSize) {
    const pool=base.add(poolRva),stride=pool.add(0x68).readU64().toNumber();
    if(stride!==expectedSize||pool.add(0x90).readU64().toNumber()>128)return null;
    let block=pool.add(0x30).readPointer();
    for(let chain=0;!block.isNull()&&chain<128;chain++){
        const count=block.add(0x38).readU64().toNumber();
        if(count<1||count>128)return null;
        for(let index=0;index<count;index++){
            const object=block.add(0x80+index*stride);
            try{if(rva(object.readPointer())!==null&&object.add(0x10).readPointer().equals(owner))return object;}catch(_){}
        }
        block=block.add(0x20).readPointer();
    }
    return null;
}
Interceptor.attach(base.add(PROFILE.physicsUpdate),{
    onEnter(args){
        if(flowState!=='InGame'||Date.now()-lastPose<100||Process.getCurrentThreadId()!==flowThread)return;
        lastPose=Date.now();
        try {
            const physics=args[0],binding=poseFor(physics);if(binding===null)return;
            if(binding.life.add(0xC0).readU32()!==8){poseBindings.clear();return;}
            const transform=binding.object;
            if(!transform.readPointer().add(0x28).readPointer().equals(base.add(PROFILE.poseGetter)))throw new Error('Transform type changed');
            const matrix=transform.add(transform.add(0x410).readU8()!==0||transform.sub(8).readPointer().add(0x10).readU32()===0?0xF8:0x1E8);
            const position=[0x60,0x68,0x70].map(offset=>matrix.add(offset).readDouble());
            const axes=[[0,8,0x10],[0x20,0x28,0x30],[0x40,0x48,0x50]].map(offsets=>offsets.map(offset=>matrix.add(offset).readDouble()));
            if(position.some(value=>!Number.isFinite(value))||axes.some(axis=>Math.abs(axis.reduce((sum,v)=>sum+v*v,0)-1)>.01))throw new Error('Invalid native transform');
            const owner=physics.add(0x10).readPointer();
            const heat=pooled(PROFILE.heatPool,owner,0x190),manager=pooled(PROFILE.heatManagerPool,owner,0x228),fsd=pooled(PROFILE.fsdPool,owner,0xEC0);
            const input=physics.add(0x3B0).readPointer();
            const sample={kind:'native-flight-sample',id:binding.id,position,axes,speed:physics.add(0x6A8).readFloat(),inputRoot:input.sub(0x60).toString(),inputVtable:rva(input.readPointer()),heatPercent:heat===null?null:heat.add(0x188).readFloat()*100,thermalObject:heat===null?null:heat.toString(),fsdObject:fsd===null?null:fsd.toString()};
            if(manager!==null){const ratio=manager.add(0x1F0).readPointer();sample.heatDisplayPercent=ratio.isNull()?null:ratio.readFloat()*100;}
            if(fsd!==null){sample.fsdState=fsd.add(0x758).readU8();sample.fsdStage=fsd.add(0x794).readU8();sample.fsdRemaining=fsd.add(0x7A0).readFloat();}
            emit(sample);
        }catch(error){once({kind:'telemetry-unavailable',error:String(error)});}
    }
});
emit({kind:'probe-ready',build:PROFILE.sha256,readOnlyFlight:true,originalSoloMenuAllowed:ENTER_SOLO});