namespace XFEEDToolBox.Plugin; internal static unsafe partial class Navigation { internal sealed class GalaxyPowerActivityContext { internal nuint expectedImage,service,owner; internal ulong tick,entity,currentSystem; internal uint thread; internal int optionCount; internal Dictionary indices=[]; } // Evidence RVAs refer to pinned 6891: 3B1CFA0, 1412900, 14121E0, // 1412A90 and 1414100. Current vtables below are verified ED5A addresses // from the shared compatibility ledger and existing PowerOptions reader. // This port calls no getter: 1414100 writes the original last-key cache. static bool GalaxyPowerActivitySource(nuint service,nuint expectedImage,nuint owner) { try { return service>=0x10058&&owner>=0x10000&&Pointer(service)==expectedImage+0x51BB600&& Pointer(service-0x58)==expectedImage+0x51BB4D0&&Pointer(service-0x50)==expectedImage+0x51BB500&& Pointer(service-0x48)==owner&&Read(service+0x308)==1&&Read(service+0x309)==1&& Read(service+0x30A)==1&&Read(service+0x30C)==0; } catch{return false;} } static bool TryCreateGalaxyPowerActivityContext(Snapshot frame,GalaxyServices services,out GalaxyPowerActivityContext result) { result=new(); if(!Enabled()||!inGame||!frame.valid||frame.entity==0||owningThread==0||GetCurrentThreadId()!=owningThread||services.registry<0x10000)return false; try { var service=RegisteredComponent(services.registry,Read(image+0x5F3C524)); if(service<0x10058)return false; var owner=Pointer(service-0x48); if(!GalaxyPowerActivitySource(service,image,owner)||!CopyGalaxyPowerOptions(service-0x58,owner,image,out var options)||options.Length==0)return false; var indices=new Dictionary(options.Length); foreach(var option in options)if(!indices.TryAdd(option.internalPowerId,option.index))return false; if(!GalaxyPowerActivitySource(service,image,owner))return false; result=new(){expectedImage=image,service=service,owner=owner,tick=GetTickCount64(),entity=frame.entity, currentSystem=frame.referenceWorld&0x007FFFFFFFFFFFFFUL,thread=owningThread,optionCount=options.Length,indices=indices}; return result.currentSystem!=0; } catch{return false;} } static uint GalaxyPowerActivityPairHash(ulong address,uint mode) { unchecked { var hash=mode*0x1001;hash=((hash>>22)^hash)*0x11;hash=((hash>>9)^hash)*0x401; hash=((hash>>2)^hash)*0x81;hash^=hash>>12; return (uint)GalaxyFactHash(address)^(hash<<16|hash>>16); } } // Original open-address layouts: metadata stride180/alignment16; // unoccupied counters stride10/alignment8; controlled pairs stride18/alignment8. // A valid empty counter table means original getter zero. A missing metadata // record remains unknown, even though the game getter has a fallback record. static bool GalaxyPowerActivityFind(nuint map,ulong address,int mode,int stride,int alignment,out nuint node) { node=0; try { var count=Read(map+8);var capacity=Read(map+0x10);var storage=Pointer(map+0x18); if(count>1_048_576||capacity>2_097_152||count>capacity||capacity!=0&&(capacity&(capacity-1))!=0)return false; if(count==0)return Read(map+8)==0&&Read(map+0x10)==capacity&&Pointer(map+0x18)==storage; if(capacity==0||storage<0x10000)return false; var rows=storage+(nuint)(((capacity>>3)+(ulong)alignment-1)&~((ulong)alignment-1)); var hash=mode<0?GalaxyFactHash(address):GalaxyPowerActivityPairHash(address,(uint)mode); var slot=hash&(capacity-1);var ended=false; for(ulong step=0;step(storage+(nuint)(slot>>6)*8); if((bits&(1UL<<(int)(slot&63)))==0){ended=true;break;} var at=rows+(nuint)slot*(nuint)stride; if(Read(at)==address&&(mode<0||Read(at+8)==mode)){node=at;ended=true;break;} slot=(slot+1)&(capacity-1); } if(!ended||Read(map+8)!=count||Read(map+0x10)!=capacity||Pointer(map+0x18)!=storage){node=0;return false;} return true; } catch{node=0;return false;} } static int GalaxyPowerActivityCounterMode(int action,bool allPowers,ulong ownerIndex,int selectedIndex) =>allPowers?action==2?0:1:(ownerIndex==(ulong)selectedIndex)==(action!=4)?0:1; static bool CopyGalaxyPowerActivityCounter(nuint service,nuint expectedImage,nuint owner,ulong address, bool allPowers,int selectedIndex,int optionCount,int actionId,out float? recentActivity) { recentActivity=null; if(address==0||address>=0x80000000000000UL||actionId is <1 or >5||optionCount is <1 or >128|| !allPowers&&(selectedIndex<0||selectedIndex>=optionCount)||!GalaxyPowerActivitySource(service,expectedImage,owner))return false; try { if(!GalaxyPowerActivityFind(service+0x3C0,address,-1,0x180,16,out var node))return false; if(node==0)return true; var metadata=node+0x10;var ownerIndex=Read(metadata);var state=Read(metadata+0xC); if(state<0||state>65535||state!=0&&ownerIndex>=(ulong)optionCount)return false; float value; if(actionId==5)value=Read(metadata+0x124); else if(state==0) { if(!GalaxyPowerActivityFind(service+0x3218,address,-1,0x10,8,out var counter))return false; value=counter==0?0:Read(counter+8); } else { var mode=GalaxyPowerActivityCounterMode(actionId,allPowers,ownerIndex,selectedIndex); if(!GalaxyPowerActivityFind(service+0x3240,address,mode,0x18,8,out var counter))return false; value=counter==0?0:Read(counter+0x14); } if(!float.IsFinite(value)||value<0||!GalaxyPowerActivitySource(service,expectedImage,owner)|| Read(node)!=address||Read(metadata)!=ownerIndex||Read(metadata+0xC)!=state)return false; recentActivity=value;return true; } catch{return false;} } static bool TryReadGalaxyPowerActivityCounter(GalaxyPowerActivityContext context,ulong address, bool allPowers,int actualInternalId,int actionId,out float? recentActivity) { recentActivity=null; if(!Enabled()||!inGame||context.thread==0||context.thread!=owningThread||GetCurrentThreadId()!=context.thread|| GetTickCount64()-context.tick>500||context.expectedImage!=image)return false; var frame=Current(); if(!frame.valid||frame.entity!=context.entity||(frame.referenceWorld&0x007FFFFFFFFFFFFFUL)!=context.currentSystem)return false; var index=-1; if(allPowers?actualInternalId!=-1:!context.indices.TryGetValue(actualInternalId,out index))return false; return CopyGalaxyPowerActivityCounter(context.service,context.expectedImage,context.owner,address, allPowers,index,context.optionCount,actionId,out recentActivity); } }