[Libs] Implement sceAgcGetIsTrinityMode, NpReachability and Trophy2 info

Three exports DOOM + DOOM II (PPSA21444) imports and currently receives
unresolved-stub errors for.

sceAgcGetIsTrinityMode reports the base console this backend emulates. It
returns the flag in rax and writes no guest memory: the observed rdi at
the call site sits inside the AGC state block, immediately below the
shader handles the guest stores, so writing through it would corrupt live
state if that register is stale rather than an out-pointer.

sceNpRegisterNpReachabilityStateCallback accepts the callback and never
fires it, matching the existing sceNpRegisterStateCallback handling.
Reachability transitions only occur on a live PSN connection.

sceNpTrophy2GetTrophyInfo reports NOT_FOUND rather than success.
Succeeding requires filling SceNpTrophy2Details and SceNpTrophy2Data,
whose layouts are not confirmed here, and a title trusting zeroed details
would read an empty name and grade 0 as real data. NOT_FOUND is a
documented outcome callers already handle.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
shadowbeat070
2026-07-19 14:01:25 +02:00
parent 848f035827
commit 181286f621
3 changed files with 51 additions and 0 deletions
+15
View File
@@ -640,6 +640,21 @@ public static partial class AgcExports
public static int GetRegisterDefaults2Internal(CpuContext ctx) =>
ReturnRegisterDefaults(ctx, internalDefaults: true);
/// <summary>
/// Reports that the GPU is not running in Trinity mode, matching the base
/// console this backend emulates.
/// </summary>
[SysAbiExport(
Nid = "BfBDZGbti7A",
ExportName = "sceAgcGetIsTrinityMode",
Target = Generation.Gen5,
LibraryName = "libSceAgc")]
public static int GetIsTrinityMode(CpuContext ctx)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "f3dg2CSgRKY",
ExportName = "sceAgcCreateShader",
+17
View File
@@ -69,6 +69,23 @@ public static class NpManagerExports
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
/// <summary>
/// Accepts the reachability callback and never invokes it. Reachability
/// transitions only ever fire on a real PSN connection, which an offline
/// session does not have, so registering successfully and staying silent is
/// the accurate emulation of a signed-out console rather than a stub.
/// </summary>
[SysAbiExport(
Nid = "hw5KNqAAels",
ExportName = "sceNpRegisterNpReachabilityStateCallback",
Target = Generation.Gen4 | Generation.Gen5,
LibraryName = "libSceNpManager")]
public static int NpRegisterNpReachabilityStateCallback(CpuContext ctx)
{
ctx[CpuRegister.Rax] = 0;
return (int)OrbisGen2Result.ORBIS_GEN2_OK;
}
[SysAbiExport(
Nid = "qQJfO8HAiaY",
ExportName = "sceNpRegisterStateCallbackA",
+19
View File
@@ -80,6 +80,25 @@ public static class NpTrophy2Exports
LibraryName = "libSceNpTrophy2")]
public static int NpTrophy2ShowTrophyList(CpuContext ctx) => ReturnOk(ctx);
/// <summary>
/// Gen5 ABI: context, handle, trophy id, then SceNpTrophy2Details and
/// SceNpTrophy2Data output pointers.
/// </summary>
/// <remarks>
/// Reports "no such trophy" rather than succeeding. Succeeding would require
/// filling both output structures, and their exact layouts are not confirmed
/// here — a title that trusted zeroed details would read an empty name and a
/// grade of zero as real data. NOT_FOUND is a documented outcome that callers
/// must already handle, so it degrades along a path the game tests.
/// </remarks>
[SysAbiExport(
Nid = "EwNylPdWUTM",
ExportName = "sceNpTrophy2GetTrophyInfo",
Target = Generation.Gen5,
LibraryName = "libSceNpTrophy2")]
public static int NpTrophy2GetTrophyInfo(CpuContext ctx) =>
SetReturn(ctx, OrbisGen2Result.ORBIS_GEN2_ERROR_NOT_FOUND);
private static int WriteIdAndReturn(CpuContext ctx, ulong outAddress, ref int nextId)
{
if (outAddress == 0)