Closed FDAapproved closed 2 years ago
Not opposed to the idea in principle, but this is very much not how I'd like it to be done. The proper solution is using GZDoom's Service class to handle cross-mod communication.
I have not dug into this yet, though I've been meaning to. The wiki page is also a bit confusing and needs revised. In any case, I believe it would look something like the following on UaS:
class UaS_RespiratorStatus : Service {
// Returns -1 on any invalid condition
override int GetInt(String request, string stringArg, int intArg, double doubleArg, Object objectArg) {
// Do casting and nullchecks for player and respirator
let p = HDPlayerPawn(objectArg); if (!p) return -1;
let r = UaS_Respirator(p.FindInventory("UaS_Respirator")); if (!r) return -1;
// Process the request
if (request ~= "IsWorn") { return int(r.activated); } // Yes this uses an int return for a bool value...
if (request ~= "AirRemaining") { return int(r.mags[0]); }
return -1;
}
}
And then your mod would use a ServiceIterator
to find the UaS_RespiratorStatus
service and call the GetInt()
function. Very rough example (doesn't include pointer caching or proper iteration or nullchecking) but something like:
let i = ServiceIterator.Find("UaS_RespiratorStatus");
service RespStatus = i.Next();
bool RespActive = RespStatus.GetInt("IsWorn", objectArg:owner);
I have not tested, this is mostly theoretical and from memory. If you can make it work I'll gladly accept this, or I'll try to do it myself later.
Sidebar, please use the same brace style UaS does for your submissions 😉 Saves me feeling compelled to fix it later.
Alright; I'll cancel the PB addon push and then see if I can get this to work first. It seems like much more overhead to achieve the same solution, though I'll trust your judgement here.
Performance-wise I think it's probably a wash. It's more about robust implementation and proper use of engine features. Inventory tokens have always been a hack borne out of necessity in the DECORATE era, and there's not really any reason to use them anymore..
In this case, using a token would certainly solve the problem with ease, is the respirator active or not? However it requires the respirator code to do double-duty (manage the presence of the token), and it can't be expanded in the future for other things. For example, reporting the available air supply would require a different token which also needs duplicated management code to set its amount. But using the service I can simply add another request type to the service class (with as little as one line, as shown), and it pulls data directly from the original object instead of requiring a separate handling process.
I've pushed an update which adds the service on UaS as described above. You can use the following example code in your mod to check whether a particular player number is wearing a respirator (or pass the player object pointer directly). This should work without creating a hard dependency of any kind.
bool IsPlayerUsingRespirator(int pnum) {
ServiceIterator i = ServiceIterator.Find("UaS_RespiratorStatus");
service RespStatus;
while (RespStatus = i.Next()) {
int RespActive = int(RespStatus.GetInt("IsWorn", objectArg:players[pnum].mo));
console.printf("player "..pnum.." Resp "..RespActive);
return RespActive;
}
return false;
}
Return values:
-1
invalid request or no respirator found0
respirator found but not worn1
respirator found and worn
Adds an easily-check-able inventory token for whenever a respirator is active (worn) on a player's person, which parodies the status of respirator.activated. I am proposing this change for cross-mod compatibility, since without adding UAS as a dependency there's no easy way to check for this otherwise. If you are worried about the performance impact of this check on active players, staggering the check with (level.time % sometickamount) should alleviate that somewhat.