VRCPlayerApi.playerId may returns -1 in OnPlayerLeft()
Yodokoro
When I called VRCPlayerApi.playerId of the parameter of OnPlayerLeft(), it returns -1 even IsValid() returns True.
Official document describes it should be return player id.
It never happenes if that player's id has read before they leaving from the world.
I guess it will happenes only when the id hasn't "cached".
Note here, the exact date is unknown, but it used to work. I think it was broken by a recent update.
Probably when it went to 2019.
Here is the reproducible code:
public class OnPlayerLeftTest : UdonSharpBehaviour
{
public override void OnPlayerLeft(VRCPlayerApi player)
{
Debug.Log($"OnPlayerLeft() player valid:{player.IsValid()} , id:{player.playerId}");
}
}
Join the world with 2 or more player, and see log after one of them has left.
You can find the log like:
OnPlayerLeft() player valid:True,id:-1
Log In
Tom Leylan
I believe the problem is even worse. I tried to log the playerId in OnPlayerLeft and it throws an exception. Accessing a public property should not throw an exception. In OnPlayerJoined I am able to log player.isMaster but again the playerId throws an exception. These should pass along full-formed player objects.
Puppet~
Tom Leylan:
I came here to double check if there is a new problem with VRCPlayerApi instances.
Seing as how you replied a day ago to a post from 2021, there is a decent chance this bug is resurfacing.
The bug that I am experiencing is a bit different but might be related. I'll try to test it out again later since I switched to Utilities.IsValid for the player instance and then moved on to other things.
Hopefully someone else can verify this as well.
Puppet~
From my tests:
- any cached VRCPlayerAPI will pass a null check after the player leaves
This is the issue I was experiencing and I'm honestly not sure if anything changed or if it has always been this way. My intution tells me it should become null when a player leaves because the player object gets cleaned up.
Puppet~
Okay, sorry for spamming the comments, but I just figured something out:
It turns out playerId DOES crash. But ONLY when you don't handle it it in join before that. So if you only have OnPlayerLeft and only get the playerId, it will crash!
Pretty sure there was a bug like that a long time ago. So definitely something resurfacing here.
Unsure if I should do a new canny post or not.
Tom Leylan
Puppet~: Thanks for confirming things. I think we can agree that if the player left then any attempt to fetch that player should return a null but... in OnPlayerJoined and Left a parameter is being passed representing the player. If that is going to be null it may as well not be passed and if it is an incomplete object it sounds like a bug as their is no way to know which properties work and which throw an exception. it isn't going to impact me... but :-)
Tom Leylan
Just a quick note but someone mentioned the need to read the playerId at least once to me (like you mentioned). I do it in OnPlayerJoined now and I can log it in OnPlayerLeft.
Oh bad news. It only reports correctly to the other players and throws an exception on the player that left. So we have no way to check if a property get will throw an exception. Bummer.
miru_kitsune
Tom Leylan: I can confirm this bug has resurfaced. I am using this method to deactivate objects that the player owned if they leave the instance or disconnect, and the PlayerId data is often inaccurate and leads to an exception error when a player disconnects or leaves.
An exception occurred during EXTERN to 'VRCSDKBaseVRCPlayerApi.__get_playerId__SystemInt32'.
Parameter Addresses: 0x0000002A, 0x00000083
Object reference not set to an instance of an object.
Hoping there can a fix for this bug. As a result, I have to come up with a workaround on how I can handle deactivating objects owned by the player when they leave/disconnect.
Tom Leylan
miru_kitsune: I'm no longer affected by the problem which may only be one of the docs being slightly incomplete. I access the playerId in OnPlayerJoined. Do not know if it is required but I log it anyway. But that might be worthwhile to check as someone mentioned it. Frankly I don't see how that can affect things but I suppose it might.
The important item in my case was handling my clean up in OnPlayerLeft. The playerId must not be accessed by the player that left but an object (or other player) monitoring things can clean up based upon the id if needed. Putting the burden on the master player is a good idea because the object's ownership will transfer there anyway.
miru_kitsune
Tom Leylan: Got it! I do store the PlayerIDs in a UdonSynced array if they choose to join the game. So I can gate that exit code to the master only since they always have control over the game options.
zeshin
I think there might be something wrong with the retuned player in general, i have a bug related to calling the displayname from the player on OnPlayerLeft crashed the udonBehavior.
I can say for a fact this is where it broke in my code from the debugger
2021.11.12 20:09:52 Log - ===OnPlayerLeft===
2021.11.12 20:09:52 Error - [UdonBehaviour] An exception occurred during Udon execution, this UdonBehaviour will be halted.
VRC.Udon.VM.UdonVMException: The VM encountered an error!
Exception Message:
An exception occurred during EXTERN to 'VRCSDKBaseVRCPlayerApi.__get_displayName__SystemString'.
Parameter Addresses: 0x00000050, 0x000001A9
this was the crash, and heres the code from that line, note the crash happenes right after ===OnPlayerLeft===
public override void OnPlayerLeft(VRCPlayerApi player) {
Debug.Log("===OnPlayerLeft===");
Debug.Log("playerName: " + player.displayName);
Debug.Log("playerID: " + player.playerId);
InitializePlayerList();
HnF_PlayerCaller playerWhoLeft =
GetPlayerByName(player.displayName);
......
I think the returned information for the player that left is likely referring to a now either emptied VRCPlayerAPI or the memory address it was pointing it got cleared out after returning the method or something of that nature