using System.Security.Cryptography;
using System.Text;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
private struct CommunityGoalRequest
{
internal ulong generation,entity,epoch,expires,queued,observed;
internal nuint life,request;
internal uint market,state,error,kind;
internal ulong goal;
internal bool mutationSent;
}
private static readonly object communityGoalLock=new();
private static CommunityGoalRequest communityGoalRequest;
private static ulong communityGoalGeneration;
private static string communityGoalBody="";
private static readonly byte[] communityGoalBuffer=new byte[1024*1024];
private static readonly Dictionary<string,ulong> communityGoalKeys=new(StringComparer.Ordinal);
private static string CommunityGoalProof(string body)=>Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(body)));
private static bool CommunityGoalReadProofMatches(in Snapshot frame,in CommunityGoalRequest prior,string? proof,ulong generation,ulong now,string body)
=>prior.kind==0&&prior.state==3&&prior.generation==generation&&prior.entity==frame.entity&&prior.life==frame.life&&prior.epoch==controllerEpoch
&&now>=prior.observed&&now-prior.observed<=60000&&string.Equals(proof,CommunityGoalProof(body),StringComparison.Ordinal);
private static bool FreshCommunityGoalDock(in Snapshot frame,uint market)
=>Enabled()&&inGame&&frame.valid&&frame.healthValid&&!frame.healthEmergency&&frame.hullFraction>0
&&GetTickCount64()>=frame.tick&&GetTickCount64()-frame.tick<=200&&market!=0&&CommerceDocked(frame,market);
private static bool StartCommunityGoalRequest(in Snapshot frame,ref CommunityGoalRequest work)
{
var route=GameRoute(frame,out _);var context=route!=0?route-0x50:0;
if(context==0||Pointer(Pointer(context))!=image+0x541C70||Pointer(context+8)==0)return false;
var endpoint=work.kind==1?(nuint)0x5247D00:work.kind==2?(nuint)0x529B270:0x52405E0;
ReadOnlySpan<byte> expected=work.kind==1?"2.0/elite/initiative/optin\0"u8:work.kind==2?"2.0/elite/initiative/commander/list\0"u8:"2.0/elite/initiative/list\0"u8;
if(!Bytes(image+endpoint,expected)||!Prefix(0x3433030,[0x48,0x8B,0xC4,0x48,0x89,0x58,0x10]))return false;
var storage=(nuint)Call(image+0x53A690,0xF8);if(storage==0)return false;
ClearServiceMemory(storage,0xF8);work.request=storage;
Call(image+0x33FCC50,storage+0xA8,context);
Call(image+0x99F4F0,storage,work.kind==1?3u:1u,image+endpoint);
Write(storage,image+0x511F9D0);
if(work.kind==1){work.mutationSent=true;Call(image+0x3433030,storage,work.goal);}
else Call(image+0x340E980,storage);
return true;
}
private static void DeleteCommunityGoalRequest(ref CommunityGoalRequest work)
{
var request=work.request;
try{if(request!=0&&Pointer(request)==image+0x511F9D0){var destroy=Pointer(Pointer(request));if(InImage(destroy))Call(destroy,request,1);}}
catch{}
work.request=0;
}
private static void PollCommunityGoals(in Snapshot frame)
{
CommunityGoalRequest work;lock(communityGoalLock)work=communityGoalRequest;
if(work.generation==0||work.state>=3||GetCurrentThreadId()!=owningThread)return;
string? body=null;
try
{
work.error=1;
if(!FreshCommunityGoalDock(frame,work.market)||work.entity!=frame.entity||work.life!=frame.life||work.epoch!=controllerEpoch||work.expires<=GetTickCount64())work.state=4;
else
{
if(work.request==0)
{
work.error=2;
if(work.kind==1&&GetTickCount64()-work.queued>250||!StartCommunityGoalRequest(frame,ref work))work.state=4;
else work.state=2;
}
if(work.state==2)
{
var request=work.request;work.error=0;
var pending=Read<uint>(request+0x3C) is 1 or 2;
if(!pending||(byte)Call(image+0x9A3250,request)!=0)
{
if((byte)Call(image+0x9B5480,request)==0){work.error=(uint)Call(image+0x9A8F10,request);work.state=4;}
else
{
nuint text=0;Call(image+0x9A8DC0,request,(ulong)&text);
try
{
var length=text!=0?Read<ulong>(text):0;
if(length==0||length>=(ulong)communityGoalBuffer.Length){work.error=3;work.state=4;}
else
{
fixed(byte* destination=communityGoalBuffer)CopyCommerceMemory(text+0x14,destination,checked((int)length));
body=Encoding.UTF8.GetString(communityGoalBuffer,0,checked((int)length));
work.state=3;work.observed=GetTickCount64();
}
}
finally{if(text!=0)Call(image+0x204010,(ulong)&text);}
}
}
}
}
}
catch(Exception error){work.error=CommerceExceptionCode(error);work.state=4;}
if(work.state>=3)DeleteCommunityGoalRequest(ref work);
lock(communityGoalLock)
{
if(communityGoalRequest.generation!=work.generation)return;
communityGoalRequest=work;if(body is not null)communityGoalBody=body;
}
}
private static JsonObject CommunityGoalCall(string op,JsonElement request,in Snapshot frame)
{
lock(communityGoalLock)
{
if(op=="cg.operation.status")
{
var lookupKey=request.Required("operationKey").GetString()!;
if(!CommerceOperationKey(lookupKey))throw new InvalidOperationException("Identified CG operation required");
if(!communityGoalKeys.TryGetValue(lookupKey,out var generation))return Obj(("known",false));
return Obj(("known",true),("generation",generation),("receiptAvailable",generation==communityGoalRequest.generation));
}
if(op=="cg.status")
{
var work=communityGoalRequest;
if(request.Required("generation").GetUInt64()!=work.generation)throw new InvalidOperationException("CG request generation changed");
return Obj(("generation",work.generation),("state",work.state),("error",work.error),("kind",work.kind),("goalId",work.goal),
("mutationsSent",work.mutationSent?1:0),("responseBody",work.state==3?communityGoalBody:""),
("proof",work.state==3?CommunityGoalProof(communityGoalBody):""),("fresh",work.state==3&&GetTickCount64()-work.observed<=60000));
}
var market=request.Required("marketId").GetUInt32();
if(!FreshCommunityGoalDock(frame,market))throw new InvalidOperationException("Fresh healthy docking at the requested CG market required");
var join=op=="cg.join";ulong goal=0;string? key=null;
if(join)
{
key=request.Required("operationKey").GetString()!;
if(!CommerceOperationKey(key))throw new InvalidOperationException("Identified CG signup required");
if(communityGoalKeys.TryGetValue(key,out var old))return Obj(("generation",old),("duplicate",true));
goal=request.Required("goalId").GetUInt64();
var proof=request.Required("proof").GetString();var prior=communityGoalRequest;
if(goal==0||goal>uint.MaxValue||communityGoalKeys.Count>=32
||!CommunityGoalReadProofMatches(frame,prior,proof,request.Required("generation").GetUInt64(),GetTickCount64(),communityGoalBody))
throw new InvalidOperationException("Current original CG list proof required before signup");
}
if(communityGoalRequest.generation!=0&&communityGoalRequest.state<3)throw new InvalidOperationException("Original CG request already pending");
var next=++communityGoalGeneration;
communityGoalRequest=new(){generation=next,entity=frame.entity,life=frame.life,epoch=controllerEpoch,expires=GetTickCount64()+30000,queued=GetTickCount64(),
market=market,state=1,kind=join?1u:op=="cg.read.mine"?2u:0u,goal=goal};communityGoalBody="";
if(key is not null)communityGoalKeys.Add(key,next);
return Obj(("generation",next),("queued",true),("mutationsSent",0));
}
}
}
using System.Security.Cryptography;
using System.Text;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
private struct CommunityGoalRequest
{
internal ulong generation,entity,epoch,expires,queued,observed;
internal nuint life,request;
internal uint market,state,error,kind;
internal ulong goal;
internal bool mutationSent;
}
private static readonly object communityGoalLock=new();
private static CommunityGoalRequest communityGoalRequest;
private static ulong communityGoalGeneration;
private static string communityGoalBody="";
private static readonly byte[] communityGoalBuffer=new byte[1024*1024];
private static readonly Dictionary<string,ulong> communityGoalKeys=new(StringComparer.Ordinal);
private static string CommunityGoalProof(string body)=>Convert.ToHexStringLower(SHA256.HashData(Encoding.UTF8.GetBytes(body)));
private static bool CommunityGoalReadProofMatches(in Snapshot frame,in CommunityGoalRequest prior,string? proof,ulong generation,ulong now,string body)
=>prior.kind==0&&prior.state==3&&prior.generation==generation&&prior.entity==frame.entity&&prior.life==frame.life&&prior.epoch==controllerEpoch
&&now>=prior.observed&&now-prior.observed<=60000&&string.Equals(proof,CommunityGoalProof(body),StringComparison.Ordinal);
private static bool FreshCommunityGoalDock(in Snapshot frame,uint market)
=>Enabled()&&inGame&&frame.valid&&frame.healthValid&&!frame.healthEmergency&&frame.hullFraction>0
&&GetTickCount64()>=frame.tick&&GetTickCount64()-frame.tick<=200&&market!=0&&CommerceDocked(frame,market);
private static bool StartCommunityGoalRequest(in Snapshot frame,ref CommunityGoalRequest work)
{
var route=GameRoute(frame,out _);var context=route!=0?route-0x50:0;
if(context==0||Pointer(Pointer(context))!=image+0x541C70||Pointer(context+8)==0)return false;
var endpoint=work.kind==1?(nuint)0x5247D00:work.kind==2?(nuint)0x529B270:0x52405E0;
ReadOnlySpan<byte> expected=work.kind==1?"2.0/elite/initiative/optin\0"u8:work.kind==2?"2.0/elite/initiative/commander/list\0"u8:"2.0/elite/initiative/list\0"u8;
if(!Bytes(image+endpoint,expected)||!Prefix(0x3433030,[0x48,0x8B,0xC4,0x48,0x89,0x58,0x10]))return false;
var storage=(nuint)Call(image+0x53A690,0xF8);if(storage==0)return false;
ClearServiceMemory(storage,0xF8);work.request=storage;
Call(image+0x33FCC50,storage+0xA8,context);
Call(image+0x99F4F0,storage,work.kind==1?3u:1u,image+endpoint);
Write(storage,image+0x511F9D0);
if(work.kind==1){work.mutationSent=true;Call(image+0x3433030,storage,work.goal);}
else Call(image+0x340E980,storage);
return true;
}
private static void DeleteCommunityGoalRequest(ref CommunityGoalRequest work)
{
var request=work.request;
try{if(request!=0&&Pointer(request)==image+0x511F9D0){var destroy=Pointer(Pointer(request));if(InImage(destroy))Call(destroy,request,1);}}
catch{}
work.request=0;
}
private static void PollCommunityGoals(in Snapshot frame)
{
CommunityGoalRequest work;lock(communityGoalLock)work=communityGoalRequest;
if(work.generation==0||work.state>=3||GetCurrentThreadId()!=owningThread)return;
string? body=null;
try
{
work.error=1;
if(!FreshCommunityGoalDock(frame,work.market)||work.entity!=frame.entity||work.life!=frame.life||work.epoch!=controllerEpoch||work.expires<=GetTickCount64())work.state=4;
else
{
if(work.request==0)
{
work.error=2;
if(work.kind==1&&GetTickCount64()-work.queued>250||!StartCommunityGoalRequest(frame,ref work))work.state=4;
else work.state=2;
}
if(work.state==2)
{
var request=work.request;work.error=0;
var pending=Read<uint>(request+0x3C) is 1 or 2;
if(!pending||(byte)Call(image+0x9A3250,request)!=0)
{
if((byte)Call(image+0x9B5480,request)==0){work.error=(uint)Call(image+0x9A8F10,request);work.state=4;}
else
{
nuint text=0;Call(image+0x9A8DC0,request,(ulong)&text);
try
{
var length=text!=0?Read<ulong>(text):0;
if(length==0||length>=(ulong)communityGoalBuffer.Length){work.error=3;work.state=4;}
else
{
fixed(byte* destination=communityGoalBuffer)CopyCommerceMemory(text+0x14,destination,checked((int)length));
body=Encoding.UTF8.GetString(communityGoalBuffer,0,checked((int)length));
work.state=3;work.observed=GetTickCount64();
}
}
finally{if(text!=0)Call(image+0x204010,(ulong)&text);}
}
}
}
}
}
catch(Exception error){work.error=CommerceExceptionCode(error);work.state=4;}
if(work.state>=3)DeleteCommunityGoalRequest(ref work);
lock(communityGoalLock)
{
if(communityGoalRequest.generation!=work.generation)return;
communityGoalRequest=work;if(body is not null)communityGoalBody=body;
}
}
private static JsonObject CommunityGoalCall(string op,JsonElement request,in Snapshot frame)
{
lock(communityGoalLock)
{
if(op=="cg.operation.status")
{
var lookupKey=request.Required("operationKey").GetString()!;
if(!CommerceOperationKey(lookupKey))throw new InvalidOperationException("Identified CG operation required");
if(!communityGoalKeys.TryGetValue(lookupKey,out var generation))return Obj(("known",false));
return Obj(("known",true),("generation",generation),("receiptAvailable",generation==communityGoalRequest.generation));
}
if(op=="cg.status")
{
var work=communityGoalRequest;
if(request.Required("generation").GetUInt64()!=work.generation)throw new InvalidOperationException("CG request generation changed");
return Obj(("generation",work.generation),("state",work.state),("error",work.error),("kind",work.kind),("goalId",work.goal),
("mutationsSent",work.mutationSent?1:0),("responseBody",work.state==3?communityGoalBody:""),
("proof",work.state==3?CommunityGoalProof(communityGoalBody):""),("fresh",work.state==3&&GetTickCount64()-work.observed<=60000));
}
var market=request.Required("marketId").GetUInt32();
if(!FreshCommunityGoalDock(frame,market))throw new InvalidOperationException("Fresh healthy docking at the requested CG market required");
var join=op=="cg.join";ulong goal=0;string? key=null;
if(join)
{
key=request.Required("operationKey").GetString()!;
if(!CommerceOperationKey(key))throw new InvalidOperationException("Identified CG signup required");
if(communityGoalKeys.TryGetValue(key,out var old))return Obj(("generation",old),("duplicate",true));
goal=request.Required("goalId").GetUInt64();
var proof=request.Required("proof").GetString();var prior=communityGoalRequest;
if(goal==0||goal>uint.MaxValue||communityGoalKeys.Count>=32
||!CommunityGoalReadProofMatches(frame,prior,proof,request.Required("generation").GetUInt64(),GetTickCount64(),communityGoalBody))
throw new InvalidOperationException("Current original CG list proof required before signup");
}
if(communityGoalRequest.generation!=0&&communityGoalRequest.state<3)throw new InvalidOperationException("Original CG request already pending");
var next=++communityGoalGeneration;
communityGoalRequest=new(){generation=next,entity=frame.entity,life=frame.life,epoch=controllerEpoch,expires=GetTickCount64()+30000,queued=GetTickCount64(),
market=market,state=1,kind=join?1u:op=="cg.read.mine"?2u:0u,goal=goal};communityGoalBody="";
if(key is not null)communityGoalKeys.Add(key,next);
return Obj(("generation",next),("queued",true),("mutationsSent",0));
}
}
}