Persistence

Share us your Persistence bugs and feedback here (one item per post).
Non-constructive and off-topic posts will be moved or deleted.
Persistence does not restore synced variables in Udon components other than the first one on the same GameObject
When multiple Udon components with synced variables attach on the same child GameObject (whose parent has VRCPlayerObject and VRCEnablePersistence), Persistence only restores variables from the first Udon component. Steps to Reproduce: 1.Create two Udon components (A and B). Each Udon component contains one synced variable. 2.Create a parent GameObject with VRCPlayerObject and VRCEnablePersistence. 3.Create a child GameObject under it and attach components A and B. 4.Run a local test with a single client. 5.Set the values of the variables in A and B using any method. For example, set A to 3 and B to 5. 6.Rejoin the instance. 7.Check the values of the restored variables using any method. Expected Behavior: All variables are restored to their previously set values (A is 3, B is 5). Observed Behavior: Only the variable in component A, which was attached first, is restored. Component B's variable is reset to its initial value. (A is 3, B is 0). Additional Notes: Swapping the order of components A and B on the child GameObject reverses the result (A is 0, B is 5). This confirms that the issue is related to the component order. SDK version is 3.8.1. Similar issues found below, but it's unclear if they are related: https://vrchat.canny.io/bug-reports/p/pickup-events-may-not-be-called-when-multiple-udon-components-are-attached https://ask.vrchat.com/t/potential-issue-with-multiple-udon-components-execution-in-sdk-3-7-5/33845
1
·

tracked

Persistence Data Rollback Support
At the moment there is a high risk that a world builder may release an update to their world that ends up breaking everyone's Persistence data in an unrepairable way. This could be caused by bugs within Persistence itself. When either of these conditions occur, there is zero recourse for the world builder to correct peoples' data beyond telling everyone to wipe their data completely, losing all progress. This can be catastrophic in cases where player progress was enhanced by purchases through the Creator Economy. This problem isn't unique to VRChat, as it occurs within Roblox as well, and is especially important due to how many transactions are tied to progress in their games. However, Roblox provides a comprehensive interface where the world builder can force a roll back of player saved data to any prior date at any time. This effectively eliminates all risk with releasing world/game updates, giving the builder recourse in the case of irrecoverable corruption. I brought this to Fax who thought it was a good idea and recommended making a Canny post, so this post is to request that we get a similar feature, so world builders have the option of force rolling back a prior date of saved Persistence data. An example world is my world: Elite's RNG Land. Players can purchase an upgrade that speeds up progression, however there have been instances where a bug, either through code or API bugs, caused players to completely lose months-worth of progress. The only recourse was to tell people to wipe their player data and start over.
2
Add GetPlayerRestoreStatus Check
A Networking.GetPlayerRestoreStatus(GameObject) and PlayerData.GetPlayerRestoreStatus(VRCPlayerApi) that returns a custom enum with the values: Incompatible , Awaiting , Success , Failed , & NoDataToRestore . This would only work on networked objects that can store persistence data like PlayerData or PlayerObjects with an Enable Persistence component. Other objects will always return the Incompatible value. This would allow worlds to ask for a particular object's persistence status for many things: * Incompatible - This object does not support persistence. Use a PlayerObject with the Enable Persistence component. * Awaiting - Data has not been received from the server so the world knows to wait until a further update before trying to read/write persistence data for that object. * Success - Data was successfully restored from the server without any exceptions from VRChat's side. The world knows it is safe to read and write data to it. * Failed - Data restoration encountered an error on VRChat's side and data should not be manipulated for data loss. The world can present an error message and/or allow the player to clear their data. * NoDataToRestore - There was no data to restore from the server. The world knows this is a new player, a new update bringing a new persistent compatible object, or a player who has recently cleared their data. This also indicates to the world that this object is ready for writing new persistence data. Related: https://feedback.vrchat.com/persistence/p/add-persistence-data-status-event-or-status-parameter-for-onplayerrestored
0
Add Persistence Data Status Event or Status Parameter for OnPlayerRestored
Currently worlds do not have the ability to check when persistence data fails to load or if there is any persistence data to load at all. OnPlayerRestored seems to only run when there is persistence data to load and only after all network objects have performed their checks for that player. 2 Suggestions: Create a new OnPlayerRestoreStatusUpdate event with a status parameter. This would tell the world the current state of the scene's (or better the object's) status for the Player Data Restoration process: Awaiting , Success , Failed , & NoDataToRestore . Or Add a similar parameter to OnPlayerRestored to indicate a general status for the whole scene. * Awaiting - Not all data has not been received from the server for the scene or object. The world knows to wait until a further update before doing anything related to persistence. * Success - All data was successfully restored from the server for the scene or object without any exceptions from VRChat's side. * Failed - Data restoration encountered an error on VRChat's side and data in the scene or on the object should not be manipulated for data loss. The world can present an error message and/or allow the player to clear their data. * NoDataToRestore - There was no data to restore from the server for the whole scene or object, this is a new player or a player who recently deleted their data. This would be extremely helpful at preventing future data loss with networking issues from errors from either the Creator or VRChat. Such as when Network IDs are lost due to a regeneration with the Network ID Utility. Or when VRChat makes a breaking network patch that fails to load certain types of data correctly. Related: https://feedback.vrchat.com/persistence/p/add-getplayerrestorestatus-check
2
Preventing Persistence Exploits from Multiple VRChat Instances
The ability to open two instances of VRChat in separate windows under the same account, each being a different instance of the same world, creates significant issues for any game world that relies on persistence. I'll refer to the two windows as "Window 1" and "Window 2." Both are running the same world but in different instances. If a player performs an action in Window 1, such as getting a reward or losing progress, and the world saves that, they can simply close Window 1, switch to Window 2, and wait for the world to save their data. This will entirely overwrite the changes from Window 1, restoring their progress as if nothing had happened. This exact issue happens very commonly on mismanaged Minecraft servers, where you can have two instances open on the same server but in different subservers. This is most commonly used to duplicate items, which no RPG-style game world wants. An example in VRChat would be the world "Project Aincrad". If, in Window 1, Player 1 trades 10,000 in-game coins they have to Player 2 while Window 2 is up, then at the end of the trade, when the game forces them to save their persistence data, Player 1 in Window 1 will have 0 coins, Player 2 will have 10,000 coins, but Player 1 in Window 2 will still have the 10,000 coins, meaning that 10,000 coins have now turned into 20,000 Coins. I'm not very technical, so this is more of a guess for a potential solution, something like only allowing Window 1, or whichever window was first in that specific world, to be capable of changing the persistence data for that user and world.
10
Adding new UdonSynced fields to a Player Object appears to make saved data read-only / unsyncable / Guideline to add new UdonSynced fields in a VRCEnablePersistence object unclear
Steps to reproduce (TLDR: bold ): Create a world that has this UdonBehaviour(OurTestObject.cs): https://gist.github.com/hai-vr/3439f25571fcc4ad4f65107ad46657d8 Hierarchy example: - Pool - PlayerObject -- VRCPlayerObject + VRCEnablePersistence - OurTestObj -- UdonBehaviour(OurTestObject.cs) - Canvas 5x5 - Text -- TMP_Text 5x5 Alignment=Center&Bottom Wrapping=Disabled Overflow=Overflow In UdonBehaviour(OurTestObj), reference the TMP_Text component Upload the world Start two real clients Make Client A join the world Make Client B join Client A's world Make Client A rejoin the world After Client A finished rejoining the world, Make Client B rejoin the world At this stage, timesJoined should equal to 2 for both clients, confirming that Persistence is working for this world. In OurTestObject.cs, uncomment line 2. This will add a new UdonSynced bool field initialized to false, and a new line in the debug text. Recompile and reupload the world. Make Client A create and join a new instance of that world In Client A's perspective, notice the following in the debug text over the their own head: - The dateTime timer is ticking - timesJoined is equal to 3 - testBool has no text displayed (neither true nor false), but testBool is defined as a bool in U# (testBool appears to be null) Make Client B join Client A's instance In Client B's perspective, notice the following in the debug text over the Client A's head: - The dateTime timer is NOT ticking - timesJoined is equal to 2 (instead of 3) - testBool has no text displayed (neither true nor false), but testBool is defined as a bool in U# - The message "No new data received since ...s" appears, indicating no serialization has occurred. In Client A's perspective, notice the following in the debug text over the Client B's head: - The observations are identical to Client B's of Client A (serialization is failing, so no new data is received) (despite the above, data has been restored to persistent values because timesJoined is greater than 1) (testBool appears to be restored to null from the perspective of other clients, prior to the failed serializations) In Client B, go to the world description and click "Reset User Data", this will make Client B rejoin the world In Client B's perspective, notice the following in the debug text over the their own head: - testBool is equal to false In Client A's perspective, notice the following in the debug text over the Client B's head: - testBool is equal to false - The dateTime timer is ticking (resetting the User Data has correctly set testBool to its expected value of false, so testBool is correctly supposed to be initialized to a non-null value of false) In Client A, rejoin the world. In Client B's perspective, notice the following in the debug text over the Client A's head: - The message "No new data received since ...s" appears, indicating no serialization has occurred. In Client A's perspective, notice the following in the debug text over the their own head: - timesJoined is equal to 3 (despite the Client A having rejoined the world 4 times, the data can no longer be updated. VRChat servers still appear to retain the value of 2 being stored for timesJoined) Observed: Persistent data becomes frozen, unable to be updated any further, and is no longer syncable. UdonSynced fields is contaminated with illegal values (null is never supposed to be in a field of type bool), possibly affecting other Udon program that depend on the integrity of that data. Expected: Persistent data should remain updatable after new fields are introduced to Player Objects. Fields of a certain type should not be contaminated/overriden with illegal values for that type. A clear guideline about adding new fields to Player Objects should be documented officially. According to a VRChat representative on Discord: "in theory it should be just adding udonsynced fields and it's done. There's even metadata that is used to match up an old serialization to a new script to ensure compatibility (and this code has been in use for over a year when two people in the same instance are on different versions of the world). There seems to be some bugs with that system occasionally and it's definitely got room for improvement. Providing a default value rather than straight null would definitely be a good start, and I assume that's 90% of the issues, but it's hard to quantify so I'm not sure exactly what other issues might exist" https://discord.com/channels/189511567539306508/1294086083524432022/1330996987797045320
2
·

tracked

Load More