OnPlayerDataUpdated is invoked every frame
ゆーた@フレンズ
After I update my player data by PlayerData.SetXxx, OnPlayerDataUpdated is called every frame.
The minimum U# code I can reproduce it:
using UdonSharp;
using UnityEngine;
using VRC.SDK3.Persistence;
using VRC.SDKBase;
public class SimpleStorageRegistererTest : UdonSharpBehaviour
{
private const string Key = "RespawnCount";
public override void OnPlayerDataUpdated(VRCPlayerApi player, PlayerData.Info[] infos)
{
Debug.Log($"PlayerData updated for player[{player.playerId}]");
for (var i = 0; i < infos.Length; i++)
{
var info = infos[i];
Debug.Log($"Player[{player.playerId}] Key=[{info.Key}] State={info.State}");
}
}
public override void OnPlayerRespawn(VRCPlayerApi player)
{
if (player.isLocal)
{
if (!PlayerData.TryGetInt(player, Key, out int currentCount))
{
currentCount = 0;
}
PlayerData.SetInt(Key, currentCount + 1);
}
}
}
Place a GameObject with SimpleStorageRegistererTest and PlayerObject components, as well as the minimum objects & components (VRCSceneDescriptor, PipelineManager, and BoxCollider for the floor). (See embed image)
After I respawn, the log spam starts. Logs read
* "PlayerData updated for player[1]"
* "Player[1] Key=[RespawnCount] State=Added"
Note: This doesn't occur in ClientSim.
Log In
ゆーた@フレンズ
UPDATE 2024-11-23: I found the
Collection was modified
error cause!When I Instantiate a GameObject with U# Behaviour in it at the
OnPlayerRestored
method, this error occurs.I created 2 U# scripts (each in a file with the same name as its class name):
using UdonSharp;
using UnityEngine;
using VRC.SDK3.Persistence;
using VRC.SDKBase;
public class SimpleStorageRegistererTest : UdonSharpBehaviour
{
private const string Key = "RespawnCount";
[SerializeField] private GameObject m_gameObjectWithUdonSharp;
public override void OnPlayerRestored(VRCPlayerApi player)
{
if (player.isLocal)
{
Instantiate(m_gameObjectWithUdonSharp, transform);
}
}
public override void OnPlayerDataUpdated(VRCPlayerApi player, PlayerData.Info[] infos)
{
Debug.Log($"PlayerData updated for player[{player.playerId}]");
for (var i = 0; i < infos.Length; i++)
{
var info = infos[i];
Debug.Log($"Player[{player.playerId}] Key=[{info.Key}] State={info.State}");
}
}
public override void OnPlayerRespawn(VRCPlayerApi player)
{
if (player.isLocal)
{
if (!PlayerData.TryGetInt(player, Key, out int currentCount))
{
currentCount = 0;
}
PlayerData.SetInt(Key, currentCount + 1);
}
}
}
using UdonSharp;
using UnityEngine;
public class ChildComponent : UdonSharpBehaviour
{
void Start()
{
Debug.Log($"Start called (name={gameObject.name})");
}
}
Then I placed 2 GameObjects in the VRCDefaultWorldScene with the U# components above. (see images for detail)
After I uploaded and joined the world, I found the
Collection was modified
error in the Unity console.ゆーた@フレンズ
When I changed the script for
Instantiate
to be called 1 frame later using SendCustomEventDelayedFrames
, the error disappeared.ゆーた@フレンズ
I found that the script in my original post itself seems innocent. When I go to the minimum world with the script after I launch VRChat client, it seems go well.
This issue occurred just after I got an error in another test world:
[Unknown] [All] An exception occured while trying to invoke a NetworkEvent. System.NullReferenceException: Object reference not set to an instance of an object.
at VRC.Udon.UdonManager.RegisterUdonBehaviour (VRC.Udon.UdonBehaviour udonBehaviour) [0x00000] in <00000000000000000000000000000000>:0
at VRC.Udon.Serialization.OdinSerializer.Utilities.LinqExtensions.ForEach[T] (System.Collections.Generic.IEnumerable`1[T] source, System.Action`1[T] action) [0x00000] in <00000000000000000000000000000000>:0
at VRC.Udon.UdonManager.CheckUdonBehavioursToRegister () [0x00000] in <00000000000000000000000000000000>:0
at VRC.Udon.UdonManager.RunEvent (System.String eventName, System.ValueTuple`2[System.String,System.Object][] eventParameters) [0x00000] in <00000000000000000000000000000000>:0
at ÏÍÏÏÎÍÎÌÍÍÍÎÌÏÎÌÏÌÌÏÍÍÍ.ÍÏÍÎÍÏÌÎÏÍÏÏÎÏÍÌÍÎÌÎÎÍÏ (ExitGames.Client.Photon.EventData ÏÏÌÎÏÌÏÌÍÏÍÍÍÏÍÎÌÍÎÍÎÍÍ) [0x00000] in <00000000000000000000000000000000>:0
at ÎÍÍÌÎÏÏÌÏÌÎÎÍÌÍÎÎÍÎÎÎÎÍ.OnEvent (ExitGames.Client.Photon.EventData ÏÏÌÎÏÌÏÌÍÏÍÍÍÏÍÎÌÍÎÍÎÍÍ) [0x00000] in <00000000000000000000000000000000>:0
at ÎÍÎÌÌÍÌÌÍÌÍÎÌÍÍÍÎÏÍÍÍÏÌ[T].ÏÌÏÌÌÍÏÎÍÎÎÍÍÌÍÍÏÌÎÌÎÌÎ () [0x00000] in <00000000000000000000000000000000>:0
at ÍÍÏÎÍÍÌÎÍÎÌÎÎÍÍÌÌÌÍÎÎÌÍ.ÏÌÏÌÌÍÏÎÍÎÎÍÍÌÍÍÏÌÎÌÎÌÎ () [0x00000] in <00000000000000000000000000000000>:0
at ÏÏÎÏÏÏÎÏÌÎÌÎÏÍÎÌÏÏÌÎÎÏÎ.FixedUpdate () [0x00000] in <00000000000000000000000000000000>:0
After that, I went back to the minimum world, and the problem restarted. It continued until I close VRChat application and restart it.
ゆーた@フレンズ
Additional info: I receive the exception log just after joining to the world:
[Unknown] [All] An exception occured while trying to invoke a NetworkEvent. System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
at System.Collections.Generic.Dictionary`2+ValueCollection+Enumerator[TKey,TValue].MoveNext () [0x00000] in <00000000000000000000000000000000>:0
at VRC.Udon.UdonManager.RunEvent (System.String eventName, System.ValueTuple`2[System.String,System.Object][] eventParameters) [0x00000] in <00000000000000000000000000000000>:0
at ÏÍÏÏÎÍÎÌÍÍÍÎÌÏÎÌÏÌÌÏÍÍÍ.ÍÏÍÎÍÏÌÎÏÍÏÏÎÏÍÌÍÎÌÎÎÍÏ (ExitGames.Client.Photon.EventData ÏÏÌÎÏÌÏÌÍÏÍÍÍÏÍÎÌÍÎÍÎÍÍ) [0x00000] in <00000000000000000000000000000000>:0
at ÎÍÍÌÎÏÏÌÏÌÎÎÍÌÍÎÎÍÎÎÎÎÍ.OnEvent (ExitGames.Client.Photon.EventData ÏÏÌÎÏÌÏÌÍÏÍÍÍÏÍÎÌÍÎÍÎÍÍ) [0x00000] in <00000000000000000000000000000000>:0
at ÎÍÎÌÌÍÌÌÍÌÍÎÌÍÍÍÎÏÍÍÍÏÌ[T].ÏÌÏÌÌÍÏÎÍÎÎÍÍÌÍÍÏÌÎÌÎÌÎ () [0x00000] in <00000000000000000000000000000000>:0
at ÍÍÏÎÍÍÌÎÍÎÌÎÎÍÍÌÌÌÍÎÎÌÍ.ÏÌÏÌÌÍÏÎÍÎÎÍÍÌÍÍÏÌÎÌÎÌÎ () [0x00000] in <00000000000000000000000000000000>:0
at ÏÏÎÏÏÏÎÏÌÎÌÎÏÍÎÌÏÏÌÎÎÏÎ.FixedUpdate () [0x00000] in <00000000000000000000000000000000>:0
only when I enter the "broken" world, including the "another test world" in the former post.
EDIT: I don't use
foreach
in any U# scripts.Phasedragon
ゆーた@フレンズ Excellent, that's something we can work with! What world was causing that issue?
ゆーた@フレンズ
Phasedragon This is the
"broken" world link:
You will see the error just after you enter it. Don't touch the calender and sphere, or the world become too heavy.
Phasedragon
That's very strange, nothing in this code would appear to cause this to happen. I'm not aware of anybody else having this problem. Are you absolutely certain you don't have another script somewhere that is setting playerdata every frame?
ゆーた@フレンズ
Phasedragon Yes. I created a new project with VCC from Unity 2022 World Project template, do the same steps written in the original post, and then uploaded it.
After some tests, I found this issue occurs only when I join the world instance from VRChat menus (i.e. the production environment). It doesn't occur when I do Local Test from VRChat SDK.
This is the world link I've uploaded for test:
ゆーた@フレンズ
Additional Note: The value I tried to save doesn't seem to be actually saved. When I rejoin world after I "respawn" (= count up) once, the value is not incremented.