using System.Text;
using System.Text.Json;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
private sealed class CommerceCompletion(CommerceReadRequest work, byte[] body, uint capacity)
{
internal CommerceReadRequest work = work;
internal readonly ulong generation = work.generation;
internal readonly byte[] body = body;
internal readonly uint capacity = capacity;
internal string text = "";
internal bool ready;
}
private static CommerceCompletion? commerceCompletion;
// Only immutable response bytes reach this worker. No game objects or
// original callbacks may be dereferenced outside the owning game thread.
private static void PrepareCommerceCompletion(CommerceCompletion completion)
{
var work = completion.work;
try
{
completion.text = Encoding.UTF8.GetString(completion.body);
fixed (byte* body = completion.body)
{
var length = (nuint)completion.body.Length;
if (work.kind == 1)
{
work.serviceReplyVerified = ValidateCommerceMutationBody(work, body, length);
if (!work.serviceReplyVerified) { work.state = 4; work.error = 7; }
}
else if (work.kind == 0 && work.refreshClient)
{
using var document = JsonDocument.Parse(completion.body);
work.profileValidated = CommerceProfileValues(document.RootElement, completion.capacity, out work.serverCredits, out work.serverCargo);
if (!work.profileValidated) { work.state = 4; work.error = 11; }
}
else if (work.kind >= 4 && !ValidateOriginalServiceMutation(work, body, length))
{ work.state = 4; work.error = 9; }
}
}
catch { work.state = 4; work.error = work.kind == 0 ? 12u : work.kind == 1 ? 8u : 10u; }
finally { completion.work = work; Volatile.Write(ref completion.ready, true); }
}
private static bool CommerceWorkCurrent(in Snapshot frame, ref CommerceReadRequest work)
{
work.error = 1;
if (GetCurrentThreadId() != owningThread || !Enabled() || !inGame || !frame.valid || !frame.healthValid
|| frame.hullFraction<=0 || frame.healthEmergency || GetTickCount64() - frame.tick > 200)
{ work.state = 4; return false; }
work.error = 2;
if (work.entity != frame.entity || work.life != frame.life || work.epoch != controllerEpoch
|| work.expires <= GetTickCount64() || !CommerceDocked(frame, work.market))
{ work.state = 4; return false; }
work.error = 0; return true;
}
private static void PollCommerceCompletion(in Snapshot frame, CommerceCompletion completion)
{
if (!Volatile.Read(ref completion.ready)) return;
var work = completion.work;
if (work.generation != commerceRead.generation) return;
// A completed network response never authorizes a stale ship/menu.
if (work.state == 3 && CommerceWorkCurrent(frame, ref work))
{
fixed (byte* body = completion.body)
{
var length = (nuint)completion.body.Length;
try
{
if (work.kind == 1 && !ApplyCommerceMutation(frame, ref work, body, length))
{ work.state = 4; if (work.error == 0) work.error = 7; }
if (work.kind == 0 && work.refreshClient && !ApplyCommerceProfile(frame, ref work, body, length))
{ work.state = 4; if (work.error == 0) work.error = 11; }
if (work.kind >= 4 && !ApplyOriginalServiceMutation(frame, ref work, body, length))
{ work.state = 4; if (work.error == 0) work.error = 9; }
}
catch { work.state = 4; work.error = work.kind == 0 ? 12u : work.kind == 1 ? 8u : 10u; }
}
}
if (work.state == 3) work.observed = GetTickCount64();
commerceRead = work; commerceReadBody = completion.text;
if ((work.kind == 1 || work.kind >= 4) && work.mutationSent && !work.clientApplied) commerceReconciliationRequired = true;
CaptureServiceQuote(work, commerceReadBody);
commerceCompletion = null;
}
private static bool CommerceNonBlockingFixture()
{
// The fixture caller holds commerceReadLock. A competing tick must
// return while that lock is still held, without dispatching anything.
var tick = Task.Run(() => PollCommerceRead(default));
if (!tick.Wait(TimeSpan.FromSeconds(1))) return false;
var work = new CommerceReadRequest { kind = 1, commodity = 128049172, delta = 192, before = 0, after = 192, creditsBefore = 2000000, price = 7241, state = 3 };
var valid = new CommerceCompletion(work, "{\"credits\":609728,\"inventory\":[{\"commodity\":\"uranium\",\"qty\":192}]}"u8.ToArray(), 192);
PrepareCommerceCompletion(valid);
var invalid = new CommerceCompletion(work, "{\"credits\":609702,\"inventory\":[{\"commodity\":\"uranium\",\"qty\":192}]}"u8.ToArray(), 192);
PrepareCommerceCompletion(invalid);
return Volatile.Read(ref valid.ready) && valid.work.state == 3 && valid.work.serviceReplyVerified
&& Volatile.Read(ref invalid.ready) && invalid.work.state == 4 && !invalid.work.serviceReplyVerified;
}
}
using System.Text;
using System.Text.Json;
namespace XFEEDToolBox.Plugin;
internal static unsafe partial class Navigation
{
private sealed class CommerceCompletion(CommerceReadRequest work, byte[] body, uint capacity)
{
internal CommerceReadRequest work = work;
internal readonly ulong generation = work.generation;
internal readonly byte[] body = body;
internal readonly uint capacity = capacity;
internal string text = "";
internal bool ready;
}
private static CommerceCompletion? commerceCompletion;
// Only immutable response bytes reach this worker. No game objects or
// original callbacks may be dereferenced outside the owning game thread.
private static void PrepareCommerceCompletion(CommerceCompletion completion)
{
var work = completion.work;
try
{
completion.text = Encoding.UTF8.GetString(completion.body);
fixed (byte* body = completion.body)
{
var length = (nuint)completion.body.Length;
if (work.kind == 1)
{
work.serviceReplyVerified = ValidateCommerceMutationBody(work, body, length);
if (!work.serviceReplyVerified) { work.state = 4; work.error = 7; }
}
else if (work.kind == 0 && work.refreshClient)
{
using var document = JsonDocument.Parse(completion.body);
work.profileValidated = CommerceProfileValues(document.RootElement, completion.capacity, out work.serverCredits, out work.serverCargo);
if (!work.profileValidated) { work.state = 4; work.error = 11; }
}
else if (work.kind >= 4 && !ValidateOriginalServiceMutation(work, body, length))
{ work.state = 4; work.error = 9; }
}
}
catch { work.state = 4; work.error = work.kind == 0 ? 12u : work.kind == 1 ? 8u : 10u; }
finally { completion.work = work; Volatile.Write(ref completion.ready, true); }
}
private static bool CommerceWorkCurrent(in Snapshot frame, ref CommerceReadRequest work)
{
work.error = 1;
if (GetCurrentThreadId() != owningThread || !Enabled() || !inGame || !frame.valid || !frame.healthValid
|| frame.hullFraction<=0 || frame.healthEmergency || GetTickCount64() - frame.tick > 200)
{ work.state = 4; return false; }
work.error = 2;
if (work.entity != frame.entity || work.life != frame.life || work.epoch != controllerEpoch
|| work.expires <= GetTickCount64() || !CommerceDocked(frame, work.market))
{ work.state = 4; return false; }
work.error = 0; return true;
}
private static void PollCommerceCompletion(in Snapshot frame, CommerceCompletion completion)
{
if (!Volatile.Read(ref completion.ready)) return;
var work = completion.work;
if (work.generation != commerceRead.generation) return;
// A completed network response never authorizes a stale ship/menu.
if (work.state == 3 && CommerceWorkCurrent(frame, ref work))
{
fixed (byte* body = completion.body)
{
var length = (nuint)completion.body.Length;
try
{
if (work.kind == 1 && !ApplyCommerceMutation(frame, ref work, body, length))
{ work.state = 4; if (work.error == 0) work.error = 7; }
if (work.kind == 0 && work.refreshClient && !ApplyCommerceProfile(frame, ref work, body, length))
{ work.state = 4; if (work.error == 0) work.error = 11; }
if (work.kind >= 4 && !ApplyOriginalServiceMutation(frame, ref work, body, length))
{ work.state = 4; if (work.error == 0) work.error = 9; }
}
catch { work.state = 4; work.error = work.kind == 0 ? 12u : work.kind == 1 ? 8u : 10u; }
}
}
if (work.state == 3) work.observed = GetTickCount64();
commerceRead = work; commerceReadBody = completion.text;
if ((work.kind == 1 || work.kind >= 4) && work.mutationSent && !work.clientApplied) commerceReconciliationRequired = true;
CaptureServiceQuote(work, commerceReadBody);
commerceCompletion = null;
}
private static bool CommerceNonBlockingFixture()
{
// The fixture caller holds commerceReadLock. A competing tick must
// return while that lock is still held, without dispatching anything.
var tick = Task.Run(() => PollCommerceRead(default));
if (!tick.Wait(TimeSpan.FromSeconds(1))) return false;
var work = new CommerceReadRequest { kind = 1, commodity = 128049172, delta = 192, before = 0, after = 192, creditsBefore = 2000000, price = 7241, state = 3 };
var valid = new CommerceCompletion(work, "{\"credits\":609728,\"inventory\":[{\"commodity\":\"uranium\",\"qty\":192}]}"u8.ToArray(), 192);
PrepareCommerceCompletion(valid);
var invalid = new CommerceCompletion(work, "{\"credits\":609702,\"inventory\":[{\"commodity\":\"uranium\",\"qty\":192}]}"u8.ToArray(), 192);
PrepareCommerceCompletion(invalid);
return Volatile.Read(ref valid.ready) && valid.work.state == 3 && valid.work.serviceReplyVerified
&& Volatile.Read(ref invalid.ready) && invalid.work.state == 4 && !invalid.work.serviceReplyVerified;
}
}