#world-persistence
1 messages · Page 6 of 1
I have a very very thicc playerobject with lots of stuff in it lol
Peak
I haven’t coded my mobs yet but planned to pool their prefabs since they’d need to sync so much data they probably shouldn’t be instantiated
That will need grief prevention
Oo what are they gonna do
Destroying all mirrors would be enough backfire to cause mental damage to some users...an adequate punishment! <w<
As for the PlayerObject solution to prevent forced ownership...
Does that mean if I wanted a menu whose variables have to be read by the network for other mechanics to know the current "player stats", but interactions themselves are local...
I should make the menu a PlayerObject, then locally turn off the copies that arn't owned by the local player? (so they don't overlap)
I'm stil new to this "coding defensively" thing, no idea what are the actual good practices aside of the underscore thing (that I always forget to use...)
If you want to use player objects for data storage then I would suggest doing that. But if you want a menu to accompany that data, in a situation where you only need the local player's menu visible, then I would suggest having the menu be outside of the player object, only exist once unsynced, and communicate with the local players player object to get/set the data it needs
The only time I'd put a menu inside a player object is if I wanted the ability to view the menu connected to someone else.
My world has no mirrors so that's a no go
Although
I could make it turn on a bunch of mirrors 
Ya know to uhhhhh, symbolically let them "reflect" on how their actions affect others and how it casts shame onto themselves

Hey uh
Where would I go to ask / look for worlds? (Idk where to ask this at 😭)
There aren’t any world search channels here, since you can just search world names in game
Well that's the thing
I'm trying to find this certain world that I forgot the name of that im not sure if its still up
does it matter whether i use Manual or None syncing on a persistent script that won't have any synced variables?
I mean I think it still gets a networking ID so you’re essentially cluttering the networking data still slightly
None = no network id
i'm just wondering if the playerdata still saves and loads fine if the sync behaviour is set to none
i would think it does but i never actually checked
anyone had a problem where sometimes when quest user's network lags or they come back from sleep mode, it calls OnPlayerRestored with null data, potentially resetting their save?
If you mean data that is persisted via VRC's Persistence, then yes, afaik it needs to be synched data; the only way for Persistence data to reach the server and be saved is via sync and afaik Persistence doesn't have its own form of sync: you need to sync the data to everyone else even if you don't need or want to.
PlayerData does its own syncing outside of any of your scripts, so you can have a none sync script that makes use of PlaywrData, yes. If you were using player objects with synced variables, it would have to be manual or continuous though
that’s what i figured
So am thinking of migrating all of my separate persistence bools into one string for scalability of my project but I'm worried about the size cost. Is it not worth it and it wouldn't even be scalable because it would quickly hit that cap
How much is 1 char on persistence
Pretty much
Also I know there's that compression how does it compress and what are the benefits from it
a char is 2 bytes
we don't really have any documentation on how exactly the compression works. In my testing though, it would compress by about 30%-80%
I've seen most people pack bools into bytes, not chars
which does tend to save space if you have a lot of bools, since 1 bool and 1 byte are both 1 byte each when synced
if you're planning to pack data from different sources into a single bundle, use byte array instead of strings. Then you can use bit shifting and bit converters
Thats actually a really good idea thanks fr
Should be much more preformant then my current system too
I’m not very familiar with bit shifting or converters so I don’t really understand the value of packing into byte arrays vs strings?
And I currently have two different scripts wrapping some network data into strings so >.>
I think conceptually, you could achieve the same thing with strings, it's just easier with bytes
if you just straight up convert most things into a string though, it usually ends up taking more memory than before
you can save a significant amount of space by packing bools into bytes though
If I understand it correctly I can store 8 "bools" in one byte
right, due to 1 bool taking up a full byte when networked
Or 4 double digit integers for arrays and whatnot
Wait no nvm thinking of something else
I’d love to learn about the bit packing instead of string packing, any recommended tutorials? 👀
it's a classic computer science thing, you're likely to find lots of posts on it, but I'd be surprised if there's anything vrchat or U# specific.
might try "bit fields" too maybe
There's probably a C# tutorial out there on it
probably is
for PlayerData does the Key count towards the data limit or just the value?
It does
is there any specifics on how the data gets compressed? and does the key get saved as a string always or if it just numbers then it optimizes to int or uint or something like that?
or does the key string get hashed?
sorry to be more specific, i wanna know how many Bytes the key takes up
@meager spoke #udon-networking message
nice data although it does mention persistence, it doesent take into account the key size, and if like @/phasedragon says it does get counted towards the size limit, the estimation for the persitence they give there would be waaay off
I tried to do some testing to figure this out.
It seems like VRChat no longer logs the detailed persistence info, like the compressed amount, but we do have new functions to get the current amount of saved persistence data
with 1 int, I got:
key "a" : 364 bytes
key "aaaaaaaaaa" : 366 bytes
since it's just one key, most of this is probably header, but it seems like the name of the key directly contributes to the size, but is compressed along with the rest of the data
It's difficult to give precise estimates for persistence because the number that matters is after compression. It depends not only on the type of data, but the content of the data. For example, "aaaaa" will take up less data than "abcde". The more repeating patterns in your data, the easier it is to compress. The more randomness in your data, the less it will compress and the more data it will take up. Ultimately, that's why those functions to check the size of persistence data exist - you have to run them in your own environment to see the real numbers
You can have a 100k length byte array but if it's all zeros, it will compress down to less than 1% of that. If it's pure random data, it won't compress at all. If it has large chunks of similar data but still with some variety, it will be somewhere between
okay so with this little test of ~2k values stored it... seems to work but uhh i dont really get the math, uncompressed it's i think over 300k and compressed 70k while on raw data i'm only storing 2048 uint all the remaining is key or other database stuff
Im wanting to make a game world with persistence but have zero idea how to set up one. Can anyone help teach me?
Nobody has the time to directly teach you the ins and outs of world dev because it’s a very thorough process, but during your research if you’re ever confused or stuck you can ask specific questions in these channels and folks may chime in to help o/
This guide explains how to create and upload a very simple VRChat world. You'll learn the basics of setting up a Unity scene, using VRChat's Control Panel, and publishing your world.
this depends on what part you're stuck at; do you already have a game designed and are trying to figure out how to add persistence to it? Or is it the game itself you need help creating, but you plan for it to have persistence at some point later?
I have two different game worlds (almost 3) and no persistence in any of them because I’m lazy 😂
depending on the game it can easily not be necessary at all
just doesn't make sense as part of the game design
It just feels like ass to give people settings to customize and not save them >.<
anything that takes a moment of UI navigation feels worth saving for them after the first time
it's probably easier than you might expect to set that up to work with persistence
It is but the only time I’ve tried I didn’t like having to wait for player to restore before applying variables because there were other things that were also time sensitive (like string loading patron state) and I didn’t know which should trigger first
ideally you'd design it so it's not that sensitive to timing
for UI it'd just auto-move or change the UI element when the data is loaded in
Im wanting to make an idle world where people can pick herbs and plant a garden and a few other things. I just need help in general with it. I want to make a ui menu where tools can be bought and skins and areas for the items to be collected. I would like a backpack they can upgrade to hold more items
you'll want to plan out each feature that you'll need to make, ideally break it up into little things that all add up to be the entire game.
Breaking it up into little pieces is crucial in turning a big, difficult task, into a handful of easy tasks.
you've already got, in no particular order:
- UI Menu
- Plant growing system
- player inventory
From these broad pieces, you then pick a piece. Could be any piece, or the part that makes the most sense to do first, like if one part depends on another part already existing.
So I'd start with maybe... the plant growing? Up to you what makes the most sense
how do i set up a ui menu? how do i make it where plants grow? how do i set up a player inventory?
this is why im asking for help. i have never done this before and have no idea
right. So, you'd just pick one of those questions and then go from there
UI Menu: pretty easy, in theory. Right click the hierarchy > UI > Button - TextMeshPro (VRC)
The Unity documentation will help a lot here, most of the UI stuff is just Unity, not VRChat-specific.
anyone had a problem with player data randomly fully/partially resetting on quest?
I've seen reports of it from players after they crash in a world, but only on one specific world that tends to be pretty heavy for quest
it usually happens after they crash or their network lags in some way or smth, its really weird and im not sure what to do
it's rare too, like no way to reproduce
me neither, but you confirming this is great to hear it's not a specific world problem
but i'm just tired of players approaching me with that problem and having to restore their stuff
really hoping to find a fix
I can relate a lot to that 😅
Honestly, after digging and asking them, it often turns out they are pressing the delete all world data button, thinking it will help with their fps or other issues or something.
It's kinda unfortunate
But of course, there is always a chance your persistence setup has issues too. I personally simply use one PlayerData slot and put in a json into that. So usually it's impossible for the data to get lost in any way.
Another thing I've done recently that might help: I paste the encrypted save to their log when they join. Some people just give that to me and I just can paste that into the recover system.
(but obviously a lot of people have issue getting to the logs as well)
its usually only partial loss so thats not the cause, it just rarely happens when quest crashes or lags
thanks for the idea, i might try that, was just really hesitant to do it that way because storing in string uses so much more data
yeah already doing that but no one's getting logs from quest, too complicated for an average user😔
Depends how complex your idea thing is. I left screenshots of my graphs, back when I was learning persistance on my own, in my world back then. It's not much, but can be pointers to which nodes to look for at least.
Search "THE CUBE GAME", same username as in here.
There's a few persistant puzzles, map that uncovers as you walk, an idle game to test upgrade menu, simple stuff
Most of the persistance is "on player join (then node to check the data), if bool is true, send custom event" tho...And turning the key on condition met. The rest is just normal world making really (at least for PlayerData)
It depends on your use case, but just simple player data is really not that bad. I personally just use VRCJson to get it without line breaks or spaces. It's pretty simple and fast to do.
Thank you
does vrc update/upload all of the persistence data when updating a single value? because i had heaps of performance difference at ~100 keys and ~1000 keys, when i try to update a single value with 1000 key/values in the database it would give a lag spyke / frame drop, also network suffering increases a waaay lot
for PlayerData, yes
networked data is serialized per-object; so if you have 100 separate objects, and tell one to sync, it'll sync all data on that object together, even if you only changed one value.
PlayerData, however, is essentially one object. So changing one value, all data must be serialized together and re-sent
kay.. i understand what you mean but i feel like playerdata, the way it works, it should be it's own database then that allows for single value changes, i dont see how uploading all the data for playerdata on a single value makes much sense, i mean other than reusing the same system from player objects?
it's because it has to all be serialized together, due to how VRChat does its networking
and "reusing the same system from player objects" is almost exactly what it's doing. Even further, just how objects themselves are networked. both PlayerObjects and PlayerData network the same way as normal networked scripts do
it's not really an entirely separate thing
Should it work how you describe? Maybe, yeah. Is it how persistence currently works? no
well there already is a canny for that https://feedback.vrchat.com/persistence/p/dont-serialize-the-entire-playerdata-every-time
this :c
it would certainly be a useful upgrade, but I don't see it happening anytime soon
they'd essentially have to rework both persistence and the network stack from scratch
i guess i'll have to figure out some other way for frequent updates of small values on larger data pool
your answer to that would be using PlayerObjects
PlayerData is not at all designed for data that you'd be updating often, that should be in a PlayerObject instead
additionally, you can make multiple PlayerObjects and separate the data if needed, so that not all of the data is being sent all at once
yeah... just that i need about ~1000 values that i'd have to efficiently store and update single values frequently, mostly because i wouldnt want crashes to allow for dataloss
that's safer to do with PlayerObjects than with PlayerData
yeah but i feel like i'd reach the data limit quicker, rn i'm at about ~2000 objects stored using 8% of the storage limit
PlayerObjects is a whole, separate limit, and has the same capacity as PlayerData
yeah but a key already takes a lot of bytes from the limit, how many bytes does an object take with a stored int?
you wouldn't store the object, just the data
it might take even less even, since you don't need to store the key name
hmm, i'll look into it
can i instantiate player objects in runtime and/or can i destroy them aswell?
i mean make new ones
well, you can technically instantiate anything, yes. but you can't have networked scripts on instantiated objects
you can have as many PlayerObject templates in your scene as you want though
yeah probably best idea i was just thinking on making it scripted to make modifications to the world or system easier
with an editor script yeah you can make as many as you want, just can't really make new ones at runtime
guess an editor script it will be then to preload the objects, good idea, didnt think about that
okay it still is very proportional to how many values per key/objects i got but i got now 2048 values stored in player objects down to just a little less than 10% with 32 objects and an array of 64 uints per object
thx 💜
there are workarounds for instanced objects to do networking
Yep, I use one all the time
it's very possible to design lightweight, generic, networking-only objects and use those to give networking to instantiated objects; very useful if you have different objects that work similarly (for example different pickupable items in a game that you want networked)
im trying to make a item unlock system for a Project im working on and i tried searching up Videos and Guides and i can't find anything about it i tried using the example but it not the way i want it to be
Item unlock system? You gotta be more specific
Like when you find a serect or item and when you click on the item you unlock a reward for it that what is trying to figure out
There is sorta a prefab in VRChats home central thing
oh yeah there is
check out this example, might be similar to what you're trying to do:
https://creators.vrchat.com/worlds/examples/persistence/unlock-items
Unlock items forever, using PlayerData.
Yeah I tried the example already but it didn’t seem to work for me what I needed for
Often you can't find a thing that fits your needs exactly
the idea would be to take that example and then modify it for what you want, or at least pick it apart to get a better understanding
just checked again and there still isn't really any video tutorials on persistence, best you've got will be reading the docs
I was actually interested in asking, the documentation kinda lists a limit of like 100kb if i remember correctly, for player data, is the limit for playerobject the same? And if so, for stuff like world settings or even save files is it better to use playerdata or playerobject data for persistence?
For like preformance or general use i mean
both systems have a separate limit of 100kb each, so it's 200kb (compressed) total persistence data overall.
Which you use heavily depends on what you're saving, how much, and most importantly how often.
saving in PlayerData is often more convenient, but a drawback of PlayerData is that all of the data must be sent over the network. So if you have a large amount of data in PlayerData, and you update just one value, all of that data gets sent again. If it's updated often, you could potentially clog the network
PlayerObject data is easier to break up, since you can have multiple PlayerObjects. You can split up any values that are being changed frequently from the ones that aren't, giving you room to optimize it
So for your case, if it's just a couple of world settings, PlayerData should work fine
Can you control how often or when playerdata gets updated? Like having a button that uploads the data when pressed
definitely
You actually can't delay syncing PlayerData; if you change any value it internally makes a network sync request
Where do we go for World SDK bugs?
I have a bug when using ulong as a persistence field data type. Persistence data get serialized as JSON then reloaded to give you persistence. JSON doesn't officially support ulong so you get a truncated value like 1.84219742784434E+19 and converted to double for the ulong value of 18421974278443368513.
Not sure if this reproduces on live, but does happen in Unity and super annoying to deal with and test locally. 🙁
You submit bugs on canny, but here's a good place to discuss them
I don't think that's technically a bug, that's just a drawback of converting to JSON
but.... persistent data doesn't get converted to JSON though.
yeah don't expect math to be very accurate if you convert it a bunch of times
The file that holds persistent data is a json I’m pretty sure
it's only JSON for ClientSim
Oh weird
Hey! Is there any good persistence examples out there? Im really just looking to get examples on how data gets stored/accessed for different data types such as lists/arrays/maps
In the example central on the VRChat SDK
So I am trying to wrap my head around the documentation for playerdata, but for something like this PlayerData.SetInt(POINTS_KEY, points); it seems as if this doesn't target a specific player? does this only target the local player? And what if I were iterating through all players in a world and I wanted to update a "win" or "lose" value?
correct; it does not target a specific player because you can only save the local player's data
Use these methods to save PlayerData for the local player. It is not possible to set a remote player's data.
if you want all players to update a PlayerData value, you'll have to send an event to the other players so they can run it locally
I think that makes sense! so for example if I wanted to reward the team, or a specific player, I would want to store them, or the team, in some sort of variable, then run an event that checks if (player.isLocal) then from there modifiy the respective PlayerData?
mmm kind of. It's more important that the function to set the PlayerData runs for all players
you might not need to check for the local player, because the methods are only going to apply to the local player anyway
it's likely your game management script is being executed by just one player, I assume. So whenever the game "ends" or whatever, they could call SendCustomNetworkEvent and target All players; then you'd have that function update the PlayerData
I think that makes sense. Ill have to play around with some ideas I have and see how everything works. I appreciate the help!
Wouldnt OnPlayerDataUpdated be more suitable? since it is the OnDeserialization equivalent for manual sync
…equivalent for PlayerData, you know what i mean
that runs after a player's data has been changed
so you could use that to possibly update a UI with the counts for all of the players
that doesn't get around the initial issue of, you can only set the local player's PlayerData
Oh right
if it does help to have some context, essentially what I am trying to make is a tcg. The player obviously will have a card inventory along with their deck, so updating the players owned cards and wins/losses, along with other misc values I don't want to super dive into. So a lot of the data will be important to keep per player rather than EVERYONE in the world
so something like:
Networking.LocalPlayer;
if (!PlayerData.HasKey(player, INITIALIZED_KEY)) {```
everything in the if statement woud ONLY run for the local player correct?
it will only apply to the local player, yes
It would run for every player that does not have the INITIALIZED_KEY key in their own PlayerData
A psudocode way of writing that if statement would be "If I don't have the INITIALIZED_KEY in my PlayerData then I should"
is there a good way to save a sort of "community" leaderboard/stats across ALL instances?
Depends on what you mean tbh
Are things user submitted or automated
I wouldn't say good... But you can store a leaderboard outside of the game and grab it via string loading
Users would need to self submit, one of the main tycoon guys has a system for that
it would be user submitted.
his may work. ill have to researh this
Ah, then as @twilit meteor mentioned then
In this example such things are stringloaded:
String Loading allows you to download text files from the internet and use them in your VRChat world. You can either use the DownloadString script included in the SDK, or you can make your own script using the new VRCStringDownloader.LoadUrl function.
IDK if the systems are public but you could follow a similiar setup
Alternatively Japan Street has a nice demo of a "contagious" leaderboard that is updated with everyones data and is persistent across instances and rejoins
Stored in persistence
Is that what I am going to be known as lol
its the tycoon guy!
(Ik you do other stuff, just what I am most familiar from your works)
Sorry, doing some self-learning on how to make worlds... is player persistence (like.. level, score, vip, etc) stored in the cloud or locally?
It’s in VRC’s servers, so cloud
Thanks! I wasn't sure if I wanted to use it if it would get wiped when someone clears all the caches and folders.
it is possible for players to wipe their own Persistence data; there will be a button that appears on your world page to clear it for just that world, and there's also the ability to delete all persistence data from the website
That's likely fine. That seems more accident-proof than those that wipe caches constantly (that 2GB folder) for performance/bug clearing reasons.
👍🏼
My thinking is that the ToS for Udon-powered world moderation as currently written was well-suited before worlds could have persistence, but now that worlds can be powered by persistence, it is time to re-evaluate the ToS and create rules that account for cheaters able to misbehave in one instance and carry that result with them into new instances where the ToS does not currently allow creators to do anything about it.
Thoughts?
I don't think persistence warrants any change to the TOS
What is the best ToS-complaint way of keeping cheaters from ruining a competitive game's community/economy/high scores/rankings via hacked save data or modded clients (cheated item equipment, currency etc)
I do think VRChat is a good place for these kind of experiences, but there's really not a good way of maintaining good game integrety, as written.
Traditionally, it would just be "ban cheaters" , but, this seems to not be allowed
right, due to the common misconception that you as the world creator also have the authority to globally moderate your world
the most you can do is just make it harder to cheat, and to punish cheaters in a specific instance, but it will never be foolproof
I've seen strategies to obsfucate the data in the variable that holds the value of things like currency
Well that's why I think there needs to be a fundamental change in the TOS, essentially what's being said is you cannot use VRChat as a platform for the types of games that require the ability to designate specific users as no longer welcome in the game's global community
There needs to be a VRChat-sanctioned way to remove bad actors from ruining the global experience, not just from specific instances
there already is; you report them to moderation and they get banned
I don't think VRChat's T&S team can handle or understand all the individual little made up rules and codes of conduct that a game may have, understanding if they are legitimately broken or not, and banning VRChat accounts wholesale for violating any one of them.
Perhaps then, a world creator could create world-specific report categories to be sent to the T&S team?
And those categories populated into VRChat's own reporting system
But you can't expect a general VRC T&S member to understand the nuances of every contrived game mechanic in every game world to determine if the report is legitimate or not. It does not scale.
I mean, you can also already just report someone under the category "Client Modding / Hacking"
breaking arbitrary game rules doesn't seem like a T&S issue to me
Not if the cheating was done in a previous instance and carried over to yours via persistent data. There's no ToS rule against "cheated" save data.
Big agree, but the question is, who's issue is it then?
We can't have world creators making user "blacklists" because that will inevitably lead to the very worst kinds of discrimination. However, we also can't be flooding T&S team with "User cheated at Game" requests because its not scalable and a waste of their time. The best moderation we have right now is Group instances where the group moderator can directly kick players who are cheating. But if the player has already made whatever gains, and those gains persist across instances...now we have a corner case where cheating has little consequence and there's no clear way to solve it.
So like, listed name auto kick from the world is a tos no no but invalid cheat data make the experience awful a yes yes?
you are definitely allowed to have some sort of detection saying "woah you have an absurdly high amount of currency/you just gained way more currency than is normally possible. Set currency to 0"
My answer is - if there was a way for game developers to solve this than no game would ever need moderators because they'd have solved it all in code. Game devs still have moderators and still ban cheaters because it's impossible to solve in code
Cheat detection is an arms race, and manual review will always be needed to fix what you can't catch
Essentially, the status quo is world creators are going to have to get creative with how they detect cheaters and what they choose to do about them - but whatever they do must stop short of fully locking them out of the world/game altogether. Which opens up a can of worms of "following the letter of the law, but not the spirit of it". Also, its kind of a burden on world creators who want to you know create a fun game, to spend much of their resources combatting cheaters instead.
yeah that's the entire point of the rule; it is not, and should not, be your burden as a world creator to moderate your world. Your world isn't really "yours" in the sense that you are supposed to boot out cheaters from every instance; rather, other people are just borrowing your world in their own instance and can do what they want within it as they see fit.
VRChat deliberately wants the burden of moderation to be on themselves
As a world creator at most you should be developing tools to punish cheaters on a per-instance basis, but are not permitted to develop systems to moderate in a global scope
If it's truly the case that VRChat wants the burden of moderation solely on themselves, then perhaps we should have some Udon calls to report suspicious behaviour to VRChat in an automated way? That...seems like a big ask to me, and a large burden on T&S team. But who knows, perhaps VRC would be game for it. Some automated reporting tools I think would be welcomed by the creator community, I simply have no concept how expensive a system like this would be to implement
If this really is The Way VRChat Wants It To Be™ then world creators should be able to specify their own custom report categories to be populated on the report menu. But like I said, I don't believe this can scale. No T&S Team member is going to know the rules of 7D Multi-Dimentional Calvinball and be able to tell if a player actually cheated.
In the ideal world, world authors are just designers, and VRChat Inc. ban all cheaters with cheat detection.
But evidently, VRChat Inc. is not effective nor efficient at policing cheaters. Perhaps because VRChat itself takes a fairly lenient approach to cheat detection (e.g. multiboxing is allowed lol) due to it being fundamentally a chat room with a fancy 3D interface rather than a serious game engine.
Imo it should be entirely VRChat's responsibility to up their cheat detection standard and treat their game more like a game.
User level moderation should be moderating user level problems, like someone pisses someone off, or breaking some social rules in the lobby.
User level moderation (or Udon moderation tools) should never have to tackle program level or hacking related problems, because that is a program level violation that is VRChat Inc.'s domain.
I mean they did add EAC
not on quest🤷♂️
I've been doing some thinking on this, and my feelings I think can be summarized thusly:
The fact of the matter is that persistence has introduced a very important change: instances are no longer entirely self-contained. The consequences of actions from one instance can carry directly into another. The Terms, and our ability to respond to this as a community, have to be updated to reflect that change. Regardless of what those updates might look like, they are in fact necessary.
I don't feel like that's probably something most people would disagree with?
Also hi I don't hang out here normally but I've been trying to branch out
persistent data can travel from instance to instance, but not from player to player (unless the world is programmed to do so). So I don't get how cheated persistent data can ruin a game, even if the game is direct PVP, unless a player with enough time (who doesn't cheat) can also ruin it, by doing the same thing, except obtaining any resources/currency legitimately by investing time.
So you don’t think in an rpg forcing yourself to max level and having all the quest items without any work wouldn’t ruin the game for anyone he kills?
Cuz I’d be upset if I found out a cheater didn’t work for any of the shit they had after they fucked me up 😂
If you have a very powerful one use item that is intended to be seen used rarely, and then someone can instantly buy up thousands of them and spam them endlessly. One way to determine sure-fire that it is almost certainly a cheater is to have a currency cap, so that at best the average player can only buy (and probably hold) one or two at a time.
You'd have to worry about avoiding false positives and it would probably be really easy to get around (only spawn up to the cap; and then spawn more as needed while keeping within the cap)
But it would be clear that they are obtaining money far faster than ever intended.
Well that would depend on how they're cheating or exploiting; exploiting is itself the game working as it was coded, even if the consequences weren't intended
Was wondering if anyone could help fix this code. Im using a text mesh pro ui button to toggle an object on and off but I want it persistent and can't seem to make it work. I have no idea what im doing. ive gotten non persistant toggles to work fine
nvm i think I got it to work, I just need to figure out how to have it start as on the first time you ever join. if anyone knows how to do that, i would be very greateful
Messed with it all yesterday and still couldnt figure it out
I figured it out finally!!! I was putting a unary negation in the wrong spot. It goes between the playerdata get bool and the game object set active incase anyone runs into the same issue
what. but it is supposed to go between get and set
I’m trying to create a fully-functioning Chao Garden system in VR Chat. I want to allow other worlds to participate, such as allowing players to summon their chao into the world, race their friends’ chao in the world, and even find up to 3 animals in each world
The best system I’ve found so far is just to save chao data as a text file and have players copy/paste the data into each world. With some encryption and a check to make sure that ChaoID matches PlayerID, to prevent cheaters from copying each other’s chao
Is there a better way to do this? The VRC website says there’s no way to program Persistence between worlds 🙁 But is it possible to set up my own server to store chao data? Or is multi-world persistence coming sometime soon?
Multi world persistence is not coming anytime soon, the single world persistence is janky as is and there is no sign they will fix it
Your current plan isn't a bad idea since yeah, cross-world persistence is not planned. An external server is also possible, as long as you know what you're doing; you would have to require your players to allow untrusted URLs as well
It’s janky? How so? o.o
Ah… Yeah I don’t think that’ll work then 🥲 Since the games I’m making are kinda geared towards kids…
My main goal is to create a game series called SPEED: Self-Paced Education for Expedited Diplomas. I could go on for hours about what makes it unique, but… Yeah… It’s meant to help teach Math, Physics, and Chemistry to people of all ages, and I don’t want to encourage children to turn off the safety settings 🥲
Sounds like a very noble thing to make. I'd imagine you could still make the idea work, you'd just have to reduce the scope so that progress only needs to be saved in one world
Personally, I wouldn't call the current persistence implementation "janky". I have not had any issues with it. I have a world from a year ago that still has my data saved and it loads it just fine.
Persistence is known to be exploitable by malicious clients at the moment, though. It is currently possible for cheaters to reset other players' data
Allowing untrusted URLs is a really common request in many different types of worlds. It’s not a “safety setting” to the degree that there’s no reason not to that I’ve ever encountered.
Oof… Cheaters being able to reset others’ data sounds terrible x.x’ Do they do that by flooding the PlayerObject with data >100kb? Either way, I don’t want my players spending hundreds of hours in my games just to get their progress deleted >.< So I probably won’t use VRC’s built-in Persistence then. Thank you for letting me know about this!
Icic~ That makes sense. I’ve had mine turned off for quite some time and I’ve never had any issues with it yet
I asked the VRC Help Desk if it’d be possible to set up an external server and get the URL added to the whitelist of trusted URLs
Their AI suggested that I just use github JSON strings since Github is already a trusted URL
Is this true? Would this work? Could github be used to send and receive chao data without a user changing their settings?
As with any AI suggestion.... it's half true
What it's referring to is String Loading, you can download data from the internet as a string and do whatever with it. It is technically only download/receiving data, you can't use it to properly upload/send data.
However, if you have your own webserver, there are ways to configure it so that when it receives a "download" request, the server just pretends it's actually an upload. Udon still treats it as a download, but the webserver just does its magic on the backend to save the data instead.
I hope that makes sense. I've never done it myself so I don't know the specifics, but there are a handful of worlds in VRChat that have set up something like this
Ahhh icic~ o,o May I know the names of these worlds? I’d love to talk to the creators and replicate that method~
Its only possible for people to reset others data because world devs keep making persistence methods networked for some reason
(Looking at you fish devs)

So it’s possible for world devs to prevent hackers/cheaters? Also, what do you mean their persistence methods are “networked”?
Prevent, no.
Minimize impact, yes.
"Networked" normally means networked events, but I dont know if that is what is in FISH that got exploited, I dont even know if non-networked methods can be called via network calling
I think the problem is anything public can be networked, so you’d have to make all the persistence methods private and put all the saving stuff directly in the persistence script 👀
I am about to start writing a new persistence script and will try this
how do you even call any arbitrary public method? is it some third party hack tool? (mod this is a valid question of actual Udon security, we have to know the common points of attack in order to defend them)
if it is third party stuff, then shouldn't anti-cheat be catching them? (and shouldnt the Udon VM have some basic checks to prevent random methods being called?)
The world dev marks them as being networked by accident
So there's nothing to catch
Its correct behaviour for the input state
Udon has very primitive networking
Anything not marked as private is assumed to be public networkable
Hack clients
Hmm it seems there were some changes a few sdks back too
Network events allow simple one-way network communication between your scripts. When a script executes a network event, it executes the event once for the target players currently in the instance.
Cant expect anybody to fully understand the vaguely synced multiverses that is multiplayer games
Ahhh I think I understand what mistake they made. It sounds like they made their variables Public so they could adjust their variables directly from Unity’s interface. Instead of using the optimal [SerializeField] private variable type
I’m still fairly new to C# though so I could be totally wrong about that
Hackers/clients can still change private variables soo
YL gl with any proper security
The key to security is recognizing that hacked clients can do anything they want to your world on their computer. If you have private methods, private variables, disabled gameobjects, honeypot udonbehaviours, whatever - they can all be manipulated and you can't stop them.
However, what you do have control over is how other clients in the instance respond to what a hacked client is doing. If you really want to do everything you can about security, you have to assume that all incoming synced data can be compromised.
An example of this might be if you have an admin panel that can teleport other people around. VRChat clients do not have the built-in capability of teleporting other clients, so the only way to do this is with networking. You have to have some mechanism where the admin client communicates with the target client and tells them to teleport themself. However, if you implement it without the target running any verification, you are leaving it wide open for anybody to send the network event that makes it happen. It doesn't matter if the admin panel is locked behind a gameobject that is only enabled for admins. You have to assume that hacked clients can always break into your systems and enable it on their end. They can even pretend to be a username they're not. But they can't extend that same control out to other clients, so whenever they send a network event, your other clients will always be able to verify the name of the sender and see that they're not an admin, so they ignore it.
Similarly, any local setting like mirror toggles shouldn't have any networking connected to them.
You shouldn't leave holes for people to control other's persistence data - PlayerObjects and PlayerData have strictly controlled ownership and cannot be stolen by hacked clients, but if you have some other synced behaviour or network event that can lead to affecting someone's persistence data, that's still a backdoor. You need to ensure that you close all your backdoors.
Great write up, thank you 💜
Someone smart should make a tool that obfuscates your scripts and game objects when you upload to vrchat. Either when you click the upload button or just a script you run that creates a duplicate scene and temp folder that changes and scrambles all game objects names, method names, custom event names etc to random text that way it would make it harder for client users to mess with stuff.
or Udon VM should do it natively
although, debugging will never be possible
if everything is scrambled
Yea I was saying this to someone yesterday 😂 I also would love exactly this
An on build script so it’s random each upload and you don’t have to ever read the jank
If you didn’t want debugging to be as hard you could probably also give it the ability to spit out the seed so you can use that to interpret logs 
name obfuscation of gameobjects that doesn't really help against hacked clients. Even without names, a gameobject's function can rather easily be identified by how it looks in game, and it's fairly simply to highlight any gameobject of your choosing (with a hacked client or the debug view, if the latter is enabled) to find out where it is in the world.
On the flip side, if a singular hacked client user wrote a hack for a specific world and handed it out, any update or change to any gameobjects in said hack would become unusable until the OP wrote a new one- this paired with daily or weekly uploads could completely throttle 90% of a world’s hack problems if there’s only a handful of folks who know what they’re doing
right but any layer that makes it a little harder is better than none!
hence such a world specific hack would not rely on the randomized names staying the same, but the non-randomized metadata surrounding it. (gameobject positions, components attached to game objects, the udon instructions of behaviours [in case your obfuscation tool also randomizes variable offsets])
Sure, if you know exactly what the hack relies on to find what it needs you can break it, but most often the world author does not. And the names of the native unity functions udon calls cannot be randomized, and those will stand out like a sore thumb in most cases.
Imma be honest… I’m mostly familiar with Javascript and I’m still very new to C#, so all this private/public synced networking stuff is going way over my head @.@;
I think my strategy going forward will be to start off super simple and then work my way up once I get more familiar with C# and its vulnerabilities. And I’ll also leave a lot of room for power creep in my game to make any vulnerabilities obsolete… Like, if a hacker finds a way to give themselves 9999 pokemon, but all the pokemon are Magicarp, it won’t help the hacker in the long term + it’ll teach me a vulnerability for me to patch out
I’ll save this post and come back to it later once I understand the terminology better ^^’ Thank you~ 💛
@sturdy veldt @viral linden Bit of a late response, but any public method that starts with an underscore (for example _MyMethod) cannot be called over the network. ([NetworkCallable] might override this but I have not tested this). https://creators.vrchat.com/worlds/udon/networking/events/#legacy-events-and-security
To simplify what I know of how it works, a hacker can effectively send a SendCustomNetworkEvent to any or all players in an instance. That means any public method that doesn't take parameters is a valid target (they might also need to return void, but I am unsure of that). The underscore is how you protect from this vulnerability. Note that while VRC can't fix this issue in Udon without breaking backwards computability in countless works, Soba will likely (hopefully) fix this issue, where methods will need to be explicitly marked as networkable to be called over the network.
Network events allow simple one-way network communication between your scripts. When a script executes a network event, it executes the event once for the target players currently in the instance.
Is that what happened? Damn, did they not read the docs about public method security or did they never consider it?
Honestly its a really easy mistake to make
Its a really obscure workaround to something that people shouldn't have to worry to begin with, why is udon so burdened with unfixable legacy stuff and why cant they just fix it and keep the old stuff running with old vm
You are quite literally describing the plan with Soba. lol
Soba methods will be non-networked by default, and will require [NetworkCallable] in order to be networked, just like how events with parameters work currently
Well i dont have very high hopes, we dont even know when it is coming out
Can someone help me out
I've been trying to learn persistence and I kind of got it working but I have no idea why the object is turning on for everyone else whenever somebody is joining. I've tried several workarounds but haven't figured it out yet.
the object is disabled in unity and the boolean isnt on by default either so i have no idea why it turns on
onplayerrestored runs anytime a player is restored
so a new player joins, they're restored, and you run your code again
you need to check if the player that was restored is equal to the local player reference
How could i do that?
I'm still looking for a solution
I've tried a few variations of this but it either doesn't change the outcome or makes it worse.
Like it does work, it'll fix itself when they finish joining but during that time I have 0 clue why it bugs out and appears. it fires twice but shouldn't it still be using the localplayer anyways?
That's what I'm confused about, even if the player joining's data hasn't loaded yet when it fires the first time why would it affect other people when it's using the localplayer's bool. And why would the object turn on, Isn't the default bool value false? And if It did nothing the object is turned off by default in unity.
I really wanna figure this out
it's kinda hard to tell what your exact situation or aim is, but you're using the local player's bool on someone else's object from what i can tell (when you see player restore fire for anyone, you're reading your local player bool for every playerobject of this type)
i suppose the equality check means it will only fire when you restore, but you probably want to read the owner's bool; by checking if it's the owner of the object being restored
I simply only want this gameobject to be active for people who have the boolean
is the intent that everyone gets one of these objects? because playerobjects are created for every player that joins
Not necessarily, The object wouldn't be something you pick up and move around, more like an achievement that would only be visible to you.
But it wouldn't work without it having persistence enabled.
And I can't have it enabled without it having the playerobject comp
playerdata is actually independent of that component to add persistence to the object; it's not necessary if you read/write with playerdata
if it's a single object you want visible/hidden, you may want to just remove these two components
the persistence component there only adds persistence to the player object itself for synced vars on it, playerdata can be read separately and persists regardless
you might want to log out the results of the bool and see if it's actually retrieving it with the TryGet as well
How could I do that?
it's the Debug.Log node i believe; you can probably apply the bool as the message directly; i'd consider logging the bool to retrieve it (to see if it succeeds or fails), then the resulting value
it'll appear in the console, you can probably even test it in clientsim (in editor)
I might not be seeing it,
Is this right?
i believe so, i'd probably have to check myself because i don't work with graph often
i'm seeing it log false for me (which is expected) here
Can you show me what the log looks like
by default it's a lower tab near project
and you'll want the exclamation point toggled on, on the right hand side
Yeah I have everything toggled on, I'm looking there I just dont see anything
(toggled just the warnings on for this)
I looked through the log and there wasn't anything.
Searched through all the false flags and nothing there either.
it should be returning true
I don't know why but It's just straight up not logging it
is the object inactive in scene?
ah it'll need to be active to fire restore
you may want to decouple the script as a parent above the visual if you want the visual to start off
the playerobject instantiates it as a new active object for every player
ahh okay
So that's why they were on by default, I still don't know why other people could see it maybe it spawned before assigning it to the other person but that's just my guess
Ohh so then when they finished loading, it would hide it but there would be 2 hidden ones not a singular object thats being hidden and unhidden
New issue, now it's not turning off
when you toggle it with interact? or when you restore?
oh wait
okay nevermind I just had it not routed to the setactive
Let me test this rq
YAAAAY
It work's now.
Hopefully with no issues
just bear in mind if it's like an achievement people can acquire during play you'll need to enact the setactive at that point too
Yeah I was just waiting til this worked to iron it out
Otherwise they won't see it til' they rejoin
But!
It works, completely local (it seems)
Somebody joining with or without the boolean doesn't affect what somebody else sees
Tysm!
Now I understand a bit more about how persistence and playerobjects work and that's all I wanted.
Here's my graph code for a simple persistence object
Make sure to add GameObject and String as public variables to edit on the object itself
Use either the trigger or Interact version to set the bool
Then use that same bool name on Active on join to enable that object when you load in to the world.
I hope this can help somebody 💜
So has anyone looked into the cross-world persistence for into the [un]known
Or know how it was done etcetc
It has to be another VRChat secret beta testing round
Yea, I'd be down with that
I think it's something that's been requested for a whileeeee(?)
So I just hope it's not gatekept
from what I've been told, it's not a secret feature, it's some trick that has to do with shader globals
I see
So two world lines
- Feature testing
- Officially endorsed hack of requested feature
Let's hopee it's not the latter
What does the world do special? In general the answer to these sorts of questions is "they use their own server"
Although with the mention of "shader globals" it might not be persistence at all, but rather one or multiple flags being set that persist through world change (although I imagine they'll be lost on game reload)
Persistence is persistence is persistence
Whether thru shader or other means
The data has persisted sorta deal
The method is in question
No URLs loaded
To answer your first question
When you exit the world, complete a world made by another
And come back (immediately)
Progress for completion is tracked in this "hub"
On some crash bandicoot hub world schnizzle
How can shaders persist data across a scene load?
At the very least they need to persist an int or a float to carry across at least 13 different flags because there are 13 linked worlds to complete
It's a good question because that's what's still in question
If we have "Shader Hack A" and that's used to tell the hub to trigger w/e flags they have to change save data
That'd be the method
I was thinking of testing with these or something, maybe these don't get reset when you switch worlds
https://creators.vrchat.com/worlds/udon/vrc-graphics/#vrcshadersetglobal
Udon has access to a variety of Unity's graphics functions.
Questioning the open air is kinda silly
These people are here and currently just exist to be silent
I don't even know if it unlocks a tape but @velvet barn your world was a part of this
Do you have any input or were you told anything
I can confirm it's not some hidden beta persistence feature provided by VRChat as people had speculated (like Fish! has for the anti-flying mechanic) since that much has already been stated elsewhere. But I'm not really at liberty to speak more about it at least at present. It's not something I came up with, was only shared with me in confidentiality as part of this project, and it's the sort of unintended mechanic that could theoretically be patched out by VRC.
hence why I was theorizing testing it.... because this^ is pretty much the only answer I've gotten so far every time I ask about it
Cool beans
Thasall I needed to know
I promise we're not trying to be gatekeepy about it arbitrarily. I'd love for VRC to have cross world persistence broadly. This just exists in a weird gray area, and until told otherwise it's not something at least myself and many others involved can speak on right now 🙁
World line two (bad ending)
Sigh
Just means I need more notoriety to be in the in-club one day with my awesome sauce world building skills
I'll get there one day
Official event! Theme: VRChat cannot patch things because UGC is built on hacks and exploits. In both the fictional universe, and the actual execution of the event!
I don't mean to bash on anyone but at a more basic level, while the Jank gives birth to some amazing hacks (like this one) it is ultimately detrimental and an obstacle to UGC.
Imagine a world where flying is a well made mechanic, where stations just works, and where persistence works across worlds, that is the condition where UGC can flourish. These collider flying hacks, and shader based multi-world persistence hacks, while creative and impressive in their own right, are not true indication of a platform that fosters creativity, but the opposite of it.
I fear that VRChat Inc might be mistaking Jank workarounds as expressions of creative freedom hence not willing to patch things or implement things/tools properly. That would not be a correct path in my opinion.
VRChat is usually very vocal about patching such things, and tends to offer an alternative to the same feature when it's patched out
Yea, that's fine
World line two still marks this as a bad ending
Despite anything else
Did UGC have something taken away from it, or have the existing conditions made it incapable of flourishing for the past 10 years?
I like new things too, and I do agree VRC is quite often conservative on their restrictions and slow to implement new things. But we also finally got built-in persistence at all just a year ago. To suggest the platform is incapable of flourishing unless it has everything everyone asks for immediately feels a bit dramatic.
Yeah tbh the fish thing is way crazier
This at-the-top gatekeeping thing is just only nasty/mini-corrupt
I'm fine with that one if once testing concludes they proceed to roll it out broadly, or otherwise roll it back.
Actually, that's my bad
Did they actually announce it anywhere in any official channels
I'll roll back my fish statement
"We're testing X/Y/Z for Fish" sorta deal
iirc it was on last week's dev stream they commented on it
I don't have a timestamp bc I missed it but I think it was pretty early on
Yeah. They have mentioned it on official channels, just not in a mass VRC discord announcement or the dev posts. Which is okay by me, I don't think it applies to most people.
I guess I can give it to them if it was unprompted
And not a "what's going with fish sorta deal" in which they then had to answer on it during a q&a or w/e
I could barely give them that though if "World A" is being tested with "Feature A" and it's not on dev forum, channels, or other
That's baarreeelly a give
Esp for such tunnel visioning for something at the top
I can't grant popularity as if the sample size for the popular worlds that came before it collectively didn't already surpass its numbers today
Especially over X duration for however long they've been wanting to test it
X duration over Y popular worlds already gives more data
At this rate
If numbers were the goal
Get as many large worlds as you can including Fish
What r we saying tbh
I think it's healthier to just say they sortakinda forgot about it and when fish blew up they threw it in as a test
Not because they were thinking about any optimal methods or a chance for popularity
Likely because Fish just had a higher demand to disable flight across an open area
it was also Godfall who submitted the Canny suggestion to disable flight colliders in the first place
I missed this message btw
It's kind of a crazy one
Don't all anti-cheat measures apply to all world creators whether or not they want to use them
All new world features apply or relate to the set of all world creators which is why they make roadmaps or announcements
Not that it had to be an announcement when they decided to do it
But maybe as a mention in any announcements thereafter or sooooomeeething
I will never endorse such arbitrarily low communications about the platform I want to make things for
that's the entire point of enabling it only for Fish, they're still testing the system and figuring out what will work best
currently how it works would not be ideal for everyone
Just to be clear
This is only about communication
Not about what it means for everyone else
I guess i was looping in stations and collider flying to illustrate the point of janky chairs and janky wings makes it harder and arguably impossible to design or creative maps with them, and the loss would be measured in years of lost UGC due to poor implementations (or non-fixing of a bug). If station worked at some point it would have became a more common feature thus more variety of maps. If the collider flying was fixed years ago creators would have the drive to innovate world based flying where flying is less jank. Arguably persistence (the multi-world version) would follow the path of the latter. My argument is bad tools only benefits a contorted and less accessible expression of creativity.
One can say, yes nothing is perfect and can always be better, but cmon, jank is jank, i'd say, and call it what it is, and that we can all use a bit of less jank
VRChat is fixing things, sure, but it seems they can never get rid of jank, almost at a religious level they must include jank in their execution, but can the devs simply make things just work?
Can VRChat transition away from its humble and janky origins and become something a bit more... polished at its core?
I am rambling at this point but jank is jank
Nothing to do with globals
Valid
Though everything that it's not isn't helpful
After already being told it was under NDA
I don't really need more info
How is persistance data linked to player GOs? More specifically, does it have anything to do with the network ids?
Im curious if regarating the newtwork IDs for a scene would break all of the current persistance data.
@junior goblet yes it absolutely would for player objects. wont for player data
ofc depends on it actually getting a different network id
Hmm yea i assumed it was networkID based. Alright. 👍
Where do you go to delete persistence data from clientsim again?
VRChat SDK > ClientSim PlayerData/PlayerObjects
Huh, I checked there and didn’t see anything, guess guess I just wrote bad code and it’s not the data 😂
keep that window open while in Play mode, should be able to refresh and see it update live
worse case you can hit the folder button and see if a JSON file is getting created
Excuse! Is oversized player data associated with endless 'Vrchat transmit important data'? Or a playerdata will continuously get larger as the game goes on?
What is Persistence?
so i have a world with about 120 objects, and each one has a bool for whether it's been discovered, and a string for it's name saved in persistence. right now they're all separate keys and are saved separately, but i figured it's probably ridiculous to have so many separate keys and values, so is there a better way to save all that data?
can i persist a JSON or a data dictionary maybe?
You could save a data dictionary as a string, but it's going to take up more space than if it was just the bools
that's what i was wondering mainly, is 120 bools and strings more or less data than if i use some other data type to save it all
i don't think there's any noticable performance impact for loading all of the bools and strings anyway
(i'm just activating or deactivating gameobjects or setting the text of a Text component)
With them being all bools, if needed you could save space by bit packing them together
is there a way to see how much space my playerdata takes up? would the clientsim JSON file be accurate? (not if it gets compressed by VRC)
Yes you can, but I know the ClientSim and Build & Test values are inaccurate
There's a function in Player data for it
PlayerData is a key-value database for storing persistent data about players, such as their score in a game or their preferences in a world.
Bit packing could be worth it for you to do, theoretically could turn 120 bools + strings to just 15 bytes + strings
Bit packing would be a lifesaver for this ^^
why have 120 bools if you could just do 120 bits in a few ints instead yepyepyep
32 (or 31?) bits per int means what, 4?
so uh, how would i do bit packing? i’ve only heard of it, never done it
Would this be best accomplished by making a flags enum?
hm maybe
well...
I mean if it's all bools then what are you gonna do with the enum
I forgot to get around to answering this
so I get the concept of bit packing, but never actually had a reason to do it in Udon, it'd be one of those "figure out as a go" type deals. There's probably C# tutorials out there for it too
but you get that 1 bool should theoretically only take up 1 bit of space right? It's just a 0 or 1. But in C#, and when a bool is networked in Udon, it takes up a full byte instead, either 00000000 or 11111111
That's a lot of wasted space for something that's essentially just a 0 or a 1 in the end.
So, if you've got 8 bools or less, you can "pack" them into one single byte instead. Potentially turning 8 bytes of data, down into just 1 byte
You'd decide a certain spot in the byte for each bool, then just set the individual bits as a 1 or a 0 depending on the value of the bool
you pack them up in OnPreSerialization, then unpack them and assign out the bools in OnPostSerialization and OnDeserialization
how you pack them I guess would be the fun part. You'd probably make use of the bitwise operators, like bit shifting or bitwise logical operators
Interacting with ints and flag-enums is the same since it’s just bit shifting, which is why I suggested that since an enum is basically a preset “one string per bit” stuffed into an int, which is exactly what is needed rn
But internally idk if an enum has a bigger overhead or jack all about that, and if this needs to be udonsynced idk if you can sync an enum
you can't sync an enum, no
not directly at least
oh you mean use an enum like this
https://codingbolt.net/2025/07/26/bit‑packing-in-c/
I don't even know if Udon lets you use one like this
It does cuz I’ve been using it for the past few weeks now
I made a tag based furniture browser UI with it
you can't sync an enum, but you can convert it into a syncable value in OnPreSerialization
just a heads up that directly casting an enum into anything that isn't an int will either cause a runtime exception in Udon or silently break networking in the background; you'll need to cast and assign it it to an int variable and then cast that int variable into your desired data type
public override void OnPreSerialization()
{
// directly converting an enum to a byte here silently breaks the object's Udon networking
int golfBallStateInt = (int)golfBallState;
golfBallStateByte = (byte)golfBallStateInt;
}
I tried to add a second PlayerObject to my game but it always errors out with the message:
Network ID 117 for [POTemplate name] [1] does not match desired ID 115
This is when trying to access it with Networking.FindComponentInPlayerObjects in OnPlayerRestored
Right before that, I access the first PO I had added and it's never given me a problem.
Regenerating network IDs only changed the number in the error.
I upgraded the SDK from 3.10.1 -> 3.10.2 and that didn't fix it either.
Edit: Fixed by removing the VRC Player Object & VRC Enable Persistence components and then re-adding them.
can you show that error fully in the console? Seems like an odd one
Well I just inadvertently fixed it by removing the VRC Player Object and VRC Enable Persistence components and re-adding them. Guess some bug during creation of the PO left it in a weird state.
Added a third PlayerObject and the second one is throwing an error again in the editor, but this time it's functioning anyways (previously I would get this error twice and the object would never show in the ClientSim PlayerObjects).
UnityEngine.Debug:LogError (object)
VRC.SDK3.ClientSim.ClientSimMain:FindComponentInPlayerObjects (VRC.SDKBase.VRCPlayerApi,UnityEngine.Component) (at ./Packages/com.vrchat.worlds/Integrations/ClientSim/Runtime/System/ClientSimMain.cs:508)
VRC.SDKBase.Networking:FindComponentInPlayerObjects (VRC.SDKBase.VRCPlayerApi,UnityEngine.Component)
VRC.Udon.Wrapper.Modules.ExternVRCSDKBaseNetworking:__FindComponentInPlayerObjects__VRCSDKBaseVRCPlayerApi_UnityEngineComponent__UnityEngineComponent (VRC.Udon.Common.Interfaces.IUdonHeap,System.Span`1<uint>)
VRC.Udon.VM.UdonVM:Interpret ()
VRC.Udon.UdonBehaviour:RunProgram (uint) (at ./Packages/com.vrchat.worlds/Runtime/Udon/UdonBehaviour.cs:1156)
VRC.Udon.UdonBehaviour:RunEventAdvanced (string,bool,bool,System.ValueTuple`2<string, object>[]) (at ./Packages/com.vrchat.worlds/Runtime/Udon/UdonBehaviour.cs:1801)
VRC.Udon.UdonBehaviour:RunEvent (string,System.ValueTuple`2<string, object>[]) (at ./Packages/com.vrchat.worlds/Runtime/Udon/UdonBehaviour.cs:1759)
VRC.Udon.UdonManager:RunEvent (string,System.ValueTuple`2<string, object>[]) (at ./Packages/com.vrchat.worlds/Runtime/Udon/UdonManager.cs:1222)
VRC.SDK3.ClientSim.ClientSimUdonManagerEventSender:RunEvent (string,System.ValueTuple`2<string, object>[]) (at ./Packages/com.vrchat.worlds/Integrations/ClientSim/Runtime/System/ClientSimUdonManagerEventSender.cs:16)
VRC.SDK3.ClientSim.ClientSimPlayer:CheckPlayerRestored () (at ./Packages/com.vrchat.worlds/Integrations/ClientSim/Runtime/Player/ClientSimPlayer.cs:368)
VRC.SDK3.ClientSim.ClientSimPlayer:OnPlayerDataDecoded (VRC.SDK3.ClientSim.ClientSimOnPlayerDataDecodedEvent) (at ./Packages/com.vrchat.worlds/Integrations/ClientSim/Runtime/Player/ClientSimPlayer.cs:381)
VRC.SDK3.ClientSim.ClientSimEventDispatcher:SendEvent<VRC.SDK3.ClientSim.ClientSimOnPlayerDataDecodedEvent> (VRC.SDK3.ClientSim.ClientSimOnPlayerDataDecodedEvent) (at ./Packages/com.vrchat.worlds/Integrations/ClientSim/Runtime/Events/ClientSimEventDispatcher.cs:62)
VRC.SDK3.ClientSim.Persistence.ClientSimPlayerDataStorage:LateUpdate () (at ./Packages/com.vrchat.worlds/Integrations/ClientSim/Runtime/Player/PlayerPersistence/ClientSimPlayerDataStorage.cs:864)```
do the gameobjects have the same name?
Nope, different names, created from scratch separately, nothing connecting them. Now it's just randomly selecting one to complain about each time 🤷♀️ another random bit of log spam to add to the pile
I have a player persistence object as a child of my playermanager playerobject, with a reference to the persistent object built into my playermanager script so I can pull my save data with the manager
Is this allowed?
Or is my pre-set reference making it so all players get a reference to the disabled, original persistence obj?
Because rn I can't load any persistent data and Idk if this is the culprit or if I need to look somewhere else
I was under the impression this would be ok 😅
yeah they're all synced, I actually got it to load partway by delaying my playermanager with execution order 🙏
I was already bumping persistence up but I apparently had to specifically knock playermanager back
Use the
OnPlayerRestoredto detect that a PlayerObject has finished loading User Data. This event is executed once for every player in the instance, including the owner of the PlayerObject.
?
yeah I'm doing that already, really confused why it's seeing null values
ok it only worked once lmao
And now it's again not working on rejoin
hard to say without seeing the full codes, are you writing stuff before OnPlayerRestored?
I don't have any time to investigate any more today, just gonna have to blow another day on this at some point ig
So weird that it worked once tho, and specifically someone else was in the instance at the time. Like re-opening the instance loads differently than joining an existing or something.
what is the null for? just one variable?
no it's all of them, all my true/false are read as false, all my arrays are read empty
like the entire persistence doesn't exist
but I added a function that loops every 5 frames until a flag that's set at the END of persistence is true, so the fact that it's even putting me in a room (which it does) means it's getting the OK that persistence is done
then it checks the data and sees nothing for some reason
Even persistence direclty setting the settings board is setting it to false in its own restore
Like it's just seeing a stock version of persistence for no reason smh
and they're all synced public variables
When you're in-game and you place any furniture, it adds to your persistence and runs a networked event to ask all players in that room to check your persistence
everyone can place, remove, and watch others do the same perfectly fine
there's literally no reason that I shouldn't be seeing the data on persistence when I load in after doing allat
this the type shit that makes people give up on VRC I swear xD
um, if it is synced variables, you don't need to ask other player to check your persistence, because the synced variables should already be synced, they are ready at OnDeserialization like normal synced variables... wait, are you using the VRCEnablePersistence component?
i was under the impression you have a VRCEnablePersistence component on a child object
nope I definitely didn't enable persistence on my persistent save object 
then... it has nothing to do with PlayerObject really
ooh, there's a classic
i cant tell if this is /s
It's a classic cuz everyone's been there for sure 😭
🐥🚬
I don't know if this is an issue in practice but shouldn't you not set a variable to an initial value like this because it's synced? I'd worry about the playerSeed getting picked up early by something before the value is restored and causing some problem with my code later on, or maybe the variable gets overwritten despite having a persisted value.
I create my persisted variables then set them on restore if they don't exist already, but maybe it's really not an issue and I'm just overthinking it.
sounds like overthinking 😂
That sounds more like a problem of your "something", "something" should not have picked up the value (or use) before OnPlayerRestored, if it is causing problems because it picked up the value early, then it is its own fault...
The thing is not ready yet
Imma use it anyway
problems
Why did it not work?
And as far as whether to initialize the value before OnPlayerRestored, I think all persistence data are value types so they cannot be null, they will have some sort of default value
Awesome, I know you should kick things off from OnPlayerRestored, I just wasn’t sure if setting a default would prevent your values from restoring properly. (I would assume no, but things tend to misbehave in my presence)
I think I’ve finally found a workaround to create cross-world data persistence
Please let me know if there’s an easier method because this current method is soul-sucking
this is so cursed and cool
Doesnt avatars get reloaded upon entering a new world? Would bone positions persist?
you could also use contacts to transfer data to an avatar, which uses a parameter driver to set synced and saved parameters (which will persist upon entering a new world), and then use contacts again to read the data out.
I coulda sworn there is a setting on avatars that either loads fresh into a world or keeps all values but idk. Wacky but interesting method
I didn't play the latest event that sparked this cross-world persistence, but was everyone required to wear a specific avatar?
no, that wasn't necessary for VITU
From what I heard it required you to directly travel from one world to the other, right?
not directly, just has to be done at some point in your current VRChat session
so the data is stored "persistently", but only while you have the game open; if you close the game, you have to revisit the world to get the values it's looking for saved again, then you could go to the hub to permanently save it
for example, I took a friend through, he did the first world without going to the hub after, just went straight to the second world. but after returning from the second, it saved the progress that he did the first two
I also went and 100%'d it by speedrunning all of the "Discovery' worlds in a row, and only had to return to the hub once at the end when I finished them
there's no way for Udon to access to logging menu or file, right?
did anyone try joining a non-participating world in-between?
Contacts? I’ve never heard of those before… I’ll look into those 👀 Thank you!
contacts would be a new thing but still do require for a certain avi to be worn. still no idea how physbones/bones would work beyond figuring out furry bases via bone position proportions (or a custom avi to be worn so back to a pre persistent days). am i missing smth?
ie i dont think physbones or any of that kind are persistent between instances
Has the clipboard copy/paste method been brought up yet. Idk anything about it personally but ive seen worlds that let you save to your windows copy button
I'd be a bit converned if they had the ability to read your clipboard without you knowing
My understanding of it (I didn’t write the software) is that it adds & deletes particles which interact with the physbones. But the software was written like 5 years ago, before single-world data persistence was a thing, so the project has largely been abandoned and is probably outdated. Hence I’m looking for other ideas
I’m really curious what avatar contacts are 👀
And forcing players to wear a certain avatar is totally fine for me. My game, Pokemon SPEED (self-paced education for expedited diplomas), is meant to be PG-13, so I was planning on forcing players to wear SFW avatars anyway
Contacts are a system that allows avatars and worlds to detect collisions with other contacts. You can use collisions to drive avatar and world behavior to perform all sorts of custom interactions.
Thank you! ^.^ 💛
Quick question. It says an avatar can only have 256 contacts. And that contacts can only have 16 tags. Does this mean I can have 16 tags total? Or 256*16=4096 tags total?
Did some studying using kapa ai. It seems that Contacts can send some data, but not a lot
Yeah, that’s the fallback option if all else fails (and tbh I might have to start with that, because everything else is complicated af)
Could you elaborate? I’m trying to study Avatar Contacts but it’s very complicated and kapa ai isn’t helping much x.x
have you tried the VRChat docs?
I’ve looked at their Avatar Contacts page on the website but I had a hard time understanding some things x.x
feel free to ask for clarification in here, you'll probably get better results than an AI
If I make a fully-functional Pokemon game in VR Chat, how likely is it to actually get taken down? ||I.e., how likely is it to persist through moderation?||
In that same vein of questioning, how often do worlds actually get taken down for copyright infringement?
The more popular it got, the more attention Nintendo will give to you.
How likely is VR Chat to take down a game like that? @.@;
if they get a DMCA, yes
It's certainly once they got complaint from the people who own the assets or IP.
Icic @.@; So very likely…
more like "certainly".
Unless I could somehow get permission from Nintendo… But I’d be more likely to win the lottery 😞
While I will not comment on the specifics of VRC's rules and ToS, I will point out that VRC's design largely obscures worlds from outside view and that getting attention from IP owners enough for them to care is going to be very hard to accomplish. I'll also point out the existence of games recreated in VRC and that while a significant amount of content in VRC may or may not be copyright infringement, I've never heard of any DMCA takedowns for generic stuff.
The biggest consequence will likely be the VRC devs giving your world zero official acknowledgment no matter how popular it gets, and also the world never getting approved for the creator economy.
I have seen VRC cancel their own planned events after asking creators about them, because the world in question felt “too copyrighted”
even when it actually had no copywritten content, it was just heavily inspired by something
the same group I mentioned earlier has had a mostly functional mario kart 8 recreation that was never released because nintendon’t 😂
Worlds have been taken down because of DMCA's in the past. The moment you use someone else's IP without their permission, you run the risk of action against you.
I’m getting two conflicting messages x.x The Pokemon Fusion people are telling me that Nintendo doesn’t care as long as it’s free and doesn’t use their code. But you’re saying it’s more strict on VR Chat? Are the Mario people more strict than the Pokemon people?
oh no the expectation that they’ll get in trouble is just scary enough for them not to at all 😛
idk if anyone would actually issue a takedown / dmca. the only dmca I’m aware of ever happening was for someone pirating movies for their site and posting it all over / heavily associating it with their world.
which is to be expected 😅
Ace Combat DMCA's a couple flight worlds because they were using their jet 3d models
think of it this way.... technically, every time you upload a world or avatar to VRChat, you check a little box and agree that you own the rights to everything you're uploading.
So, do you own the rights to Pokemon? No.... so you're technically lying when checking that box. According to VRChat's TOS, you are not allowed to upload that content
however
There is no automated system in place that checks your world for IP infringement. That isn't really possible, really. For your world to be sanctioned for IP infringement, the owner of the rights would have to submit a DMCA request to VRChat asking to take it down. As in, they actually have to care enough to feel like that's worth doing.
If you search VRChat worlds for "Pokemon", you find hundreds of worlds based on Pokemon. Even worlds with straight-up illegally obtained assets!
The thing is though, Nintendo has to care to go in and request these to be taken down. None of these worlds are doing any significant harm to their image or profits.... so it quite literally costs them less money not to care. And so, all of these worlds stay up
So in summary, if you wanted to make your own world, based on Pokemon, or Mario, or Sonic, or whatever? Use your best judgement. The most likely scenario is Nintendo will not care, and not bother you. But that risk will technically always remain.
Law language is very specific for a reason. Over general answers from people will never really give you the true answer. You'd need to look into the exact wordings of all the statements from all sources to build the proper picture. Aka what lawyers are paid to do.
Nintendo is quite... litigious
So when people make "Pokemon stuff" on VRChat these are known as derivative works, which the "new parts" are copyrightable. However the original copyright owner The Pokemon Company (which Nintendo owns partially) has exclusive rights to prepare derivative works based upon the copyrighted work, subject to fair use. So unless your world or avatar is firmly in the realm of fair use (which is a test of several factors like commercial/non-profit and transformative and fiction/non-fiction and substantiality and effect upon work's value) then you are infringing the copyright of The Pokemon Company, who can DMCA you and sue you.
But since you are unlikely to make any substantial commercial profit and have much effect on the IP of Pokemon, you are not going to be a big enough fish for Pokemon Company to spend money/attention on. Unless, of course if you somehow make it a super profitable world and is attracting massive viral attention, that changes the risk/reward equation for Pokemon Company.
So it can be a grey area, the original copyright owner may or may not DMCA and/or sue you for infringement (regardless of whether it may or may not be actual infringement or fair use, which is decided by the court), depending on what you create, and how other people react, and how these change over time as well.
Most likely outcome is Pokemon Company is not going to care. But that does not automatically mean it is not an infringement. It is entirely your risk and it is really a case-by-case situation.
So I need to make it transformative to lean more towards Fair Use? That’s good to know~ So:
- Adding Pokemon, with no changes, onto my SPEED game = copyright infringement
- Adding Pokemon but with new features and abilities = grey area between copyright infringement and fair use?
That alone would not be enough to make it fair use, it would not even be enough to make it to the grey area... you are hinting at some level of transformativeness, but arguably that is not transformative at all, actual copyrighted Pokemon can learn new moves all the time in all sorts of combination, you are not changing anything really
And it can be a matter of opinion, and it also depends on what your new features and abilities are really
But if you have to ask, it most probably is not fair use. If it is not quite obviously fair use, it is entirely your risk
The new features would be a fusion mechanic, where each fused pokemon would have 2 models (the models of the two input pokemon) and then allow the player to lerp the values such as vertices’ positions and color palettes. So like, if I wanted a fire/ghost Ninetails with Ghastly’s color scheme, it would 100% Ninetails on all of the Legs/Arms/Torso/Head vertices and 0% Ninetails on all of the color palettes. Similar to Pokemon Infinite Fusion but in 3D
The same system that Chao Gardens used in the Sonic Adventure games
Arguably, Pokemon Infinite Fusion creates new and unique pokemons by mixing two together ~50/50. Mathematically, you lerping between two existing pokemon make a sort of bell curve of "newness", with only the middle part is more unique, and either ends are close to straight copies of an existing pokemon.
So while you are in a similar boat of Pokemon Infinite Fusion (which is not risk-free), allowing it to slide between the two actually decreases the overall proportion of arguably original content, if that makes sense. Mathmetically speaking if you average a bell curve you end up having only 50% of your originality. So you are really only on a same boat with one leg, and the other leg in hot water so to speak.
It gets even worse if you slide on two axis.
That is, even if mixing two pokemon is even considered new. Arguably it is still derivative work. Pokemon Company choosing to ignore it, is their choice.
But again, it is a matter of opinion, fan games and fan content are made all the time. And again, they probably won't go after you if you are just making a fan game and not really making any profit.
Like LEGOS has pointed out there are hundreds of pokemon worlds already. You are not making any super revolutionary content, you are probably fine.
Nice~ But I’ll still make my own models just to be sure
I met this guy who made avatars. He has pokemon trainers and each one can summon a pokemon and you can kinda fight.
That is a bit harder to detect, compared to a world, but I don't think they are taken down.
Also, maybe Nintendo has bigger issues now, since they lost their patent or whatever VS Palworld
Honestly it's always gunna be a coinflip in regards to this stuff.
Just don't paint a target on your back by profiting off of the content.
I found a solution but it’s TL;DR:
- 3 versions of the game; two versions are legally distinct
- Games can share data with each other thanks to the cross-world data persistence thing
hey how do i fix my world popping this up and just not going away
I’ve never seen that before in my life
I wonder what you did to your persistence setup for that to happen
unless it’s just waiting to pull it from the servers and won’t for some reason
maybe?
@ebon timber using the Pokemon name alone could run afoul of trademark laws
maybe the network is clogged and the world is trying to save
i mean it happens every time and for every one
wait how does cross-world data persistence work?
It’s very janky. You literally have to:
- Force your users to wear a NUSS avatar
- Save the player’s data onto the NUSS avatar by changing avatar parameters that add particles that alter the rotation of the avatar’s physbones
- Now your next worlds are able to read their save data by interacting with the avatar to read the rotation of the physbones
||Or you can just force your users to copy/paste their save data between worlds like in Bullet Time Agent||
i think that would be easier tbh
Frfr. That’s what I’m going to start with on my game, then move on to NUSS later
yea fair
im still stuck on this
could it be because the world is private?
no
no idea why it happenes, but no, persistence works in private worlds
have you had anyone else besides yourself join to test it?
yea a lot of people see it also
could it be the save code file is too big?
what are you saving?
the limit is 100kb so it’s not like you can save a ton of data
seriously think you could block “bro” with 4 images and wouldn’t effect a single human post
So tired of the creative channels being targeted.
At some point I'd hope the creative channels split into a VRC creator's space away from the chaos of the main VRC discord.
Would be nice.
yeam it pmo that the bots keep hitting these channels cause them im wasting all these click for no new messages 😡
why are these hackers so selfish and eating up my precious seconds
good problem solving, don’t think it’ll ever happen tho 😔
well well well speaking of
lmao
No the easiest addition would be dont let people post photos in here if they have never sent beyond like 10+ messages in these channels
So then if people are explaining issues, we will try a bit and then eventually get photos, 10 may not be right
proibablyt can just do 1 tbh
since there are only so many brave souls that step into this domain. IDK if this is even doable to setup but maybe a helper can pass the idea along?
I’ve found a way to store nearly 33kb of useable data per avatar. Each avatar can have up to 8192 avatar parameters. If updated locally, each avatar parameter can store a 32-bit float. But those 32-bit floats get turned into 8-bit floats if synced with the server and other players. So now I just need to:
- Find a way to read & write all data locally to maintain the 32-bit floats
- Find a way to read & write data in a way that’s actually fast and doesn’t require 10,000 physbones (probably easy, but I have skill issues)
- Then I’ll finally have cross-world data persistence by storing 33kb of data onto an avatar
- MMORPG in VR Chat
I gave him that a week ago and he ended up not using it
I have no idea why he’s reinventing the wheel tho
Why do you even need to store that much data
NUSS has an upper limit of 8kb / avatar. And after talking to the creator, he recommended I re-write a lot of the code to implement VR Chat’s new features, which can make the read/write processes a lot faster and can store 4x as much data per avatar as before. Or, alternatively, could store the same amount of data with only 25% of the physbones
Technically, if a player keeps their data at <2304 floats, they wouldn’t need any physbones whatsoever and could just use avatar contacts instead
Like, NUSS is awesome, but it was created 5 years ago so there’s a lot of potential to optimize its design
I’m making a game called VRmon SPEED, an MMORPG similar to Pokemon. More data storage = more VRmon slots
So how does this work at a big picture? Its not persistence?
Or would it be a combination of using this technique for data storage and saving to persistence?
oh wait u gave it at a big picture got it
It would have to be both tbh
Avatars could store a maximum of 33kb if fully optimized, but avatar data is stored on the user’s device. So there’s 2 issues there:
- If the user plays on 2 or more devices, they’ll have 2 or more sets of avatar data, which will need some way to sync up
- If the game is competitive, there needs to be encryption on the data to prevent cheating. But VRC doesn’t provide Udon# with UserIDs, so we have to use DisplayName as the primary encryption key. But DisplayName can be changed once every 90 days (or 30 days with VRC+), so if that’s our only key, players would lose access to their data when changing names
So single-world persistence must be used to provide:
- A secondary storage so that multiple devices can be synced up
- A secondary encryption key to authenticate users when they change their DisplayName
I don’t want to get too technical, but TL;DR, an MMO in VRC would need to use single-world data persistence and avatar storage to shore up each other’s weaknesses
I do agree we need user ids in the API or whatever. It is super frustrating dealing with the names changing. People love these pointless shape that they probably don't even know the key combination to send em.
Frfr encryption would be 100x easier if VRC would let us access UserIDs. But I also understand that they don’t want automated systems being able to catalog visitors and access their data on the website
you could always just save your own generated ID into persistence
that we can tell who its for
but they have the private key to use it idk
Ah yeah that works too
Sounds like more work VRC should let us access but that's my opinion. Or maybe just an example of it for advanced persistence saves in example central. Either or
But if the game spans across multiple worlds, you’d end up with multiple generated IDs. So you’d have several different keys but only one lock
I def tried the IDs for persistence that wipes on diff IDs generated based on the users stored ID
That is a really good point
damn
It would allow for cross world saves, like u could go catch in kanto and then goi somewhere else (dont sue me nintendo)
sounds cool
That could ALSO be resolved if
worlds could share the same table too
but idk, give us some ids. even if its anonymous to the world creator. Like public private keys kinda, idk tho
Frfr this would be 999999x easier if worlds could just share their persistence
But opening databases up to multiple worlds would either:
- Create a massive security threat if the databases allow any worlds to read & write to them
- Create an extra layer of complexity and confusion if the creators have to configure security on their databases
Frfr but I think I can create a solution that keeps things simple for everyone (except me). My end goal is to create a system that:
- Can store up to 20kb per avatar
- Can rip all the data & functionality
- Can combine that cloned avatar with the 20kb storage system, so now the players can use their preferred avatars for storage
- A system that automatically translates any data you feed it into the optimized floats to be stored within the avatar parameters, and vice-versa for getting the data back out again
- Create an SDK where this is all already set up, and creators can place SaveBlocks and LoadBlocks wherever they want in their worlds
- A customizable encryption algorithm so that different creators’ worlds won’t read & write with other creators’ storage avatars
If I could accomplish this, every creator would effectively have access to cross-world data persistence. But I’m probably being a bit too ambitious tbh
So would we like equip a specific avatar to do this?
and then join the next instance
so say u enter a portal (not a VRC instance portal), swaps avi and then u go to the next instance?
Also excited to see it. Would def open the potential of worlds to a far far bigger way
Sort of. The creators’ game would need to have a hub world, and that hub world would:
- Take the data from the player’s storage avatar and save it to world persistence as a sort of backup save file
- Have the option to create new avatars for the player based on their favorite avatars. I.e., I could create a clone of my chao avatar
- Cram the player’s save data into the cloned avatar’s parameters
- Now the player can use their favorite (cloned) avatar, with their save data, without actually bloating their (original) favorite avatar
-# Knowing my luck, VRC will release proper cross-world data persistence just as soon as I finish this system
Try interpreting it as they are scared of you
Could the new Raycast feature be used to read data out of an avatar’s parameters? I.e., could an avatar’s parameters influence the raycasts to transmit different data to Udon#?
the only new thing is that the avatar can use a raycast now, right?
you could already utilize raycasts in world
I haven't done it in Udon yet, but I assume you can just use Physics.Raycast (https://docs.unity3d.com/6000.4/Documentation/ScriptReference/Physics.Raycast.html) in an Udon script.
In which case yes, you could always use it for worlds.
og question was about reading avi data. and the answer is no, i dont see how it changes anything
Sadge. I was hoping Udon# might have some way to detect raycasts, but it seems to be done completely through avatars with no Udon interaction
udon does have its own raycast support via physics.raycast tho 👌
True, but it’d be really difficult to use the Udon#-spawned raycasts to read data out of avatars. I’m trying to see if we could transmit data from Avatar Parameters to Udon# through raycasts. And if so, would it be faster and more-reliable?
I’ll still use NUSS ofc but I want to have a fallback option in case VRC changes something and breaks NUSS
So far I know of 2 methods:
- NUSS (max of 8kb per avatar)
- Contacts (max of 2304 floats, not sure how many bytes per float)
Both of which fall short of the 33kb theoretical maximum that avatar parameters should be able to provide
It’s also generally good practice to have 3 methods of data transfer so that, if one method breaks and starts sending jumbled data, the other 2 methods can overrule it and the system can distinguish the good data from the junk data
cycling data on to contacts is probably the way you'd have to do it, but you're going to be waiting a lot of time to read across frames and the setup isn't trivial on avatars
Are you familiar with those kinds of setups? 👀 Because tbh, I know what to do but not really how to do it tbh
Like I know that the animator uses avatar parameter values to change a change object to change the scale, rotation, etc. of the contact but it sounds like there’s a lot of room to make mistakes in such a convoluted process
i've done it with osc to push data to a world via contacts, automating it from an avatar to udon doesn't sound especially fun. i'd much sooner use strings
https://github.com/Occala/netcode.notes/blob/main/OSC/AvatarWorldOSC/README.md
it involves a setup at origin to read and acknowledge data, but i don't really like working with avis and i don't have example code
Is OSC easy for the player to set up, though? I haven’t actually used OSC
For context, the game I’m making is called VRmon SPEED, self-paced education for expedited diplomas, a pokemon-like MMORPG that teaches Math & Physics k-12. So any solution I implement needs to be simple enough for even literal children can do it
Ideally, of course, I’d just have an avatar. The players clicks on the avatar once and everything happens automatically
Luckily, all players will be using the same avatar (the games must be PG-13, so my scripts will automatically kick anyone who changes out of the game’s avatar) so the parameter names etc. will be universal across all players
osc is just driving the data, it's avatar contacts -> world udon for what's actually happening. if you used osc for it, it'd require people to install some osc solution you make
in your case it sounds more like you want it to be solely avatar and world interaction, the state machine to write and read from an avi would be extremely convoluted
it'd be magnitudes easier to just provide players with their save/load string data for input fields
with contacts it would also likely take minutes to transfer the data in either direction and be very brittle
Brittle? Nani?
i consider origin contact reading brittle and it'd need to recover if they change avis, though you intend to "kick" them if they change avis i guess? i imagine you mean removing them from the play area or disabling scripts
brittle being something that is easily broken or prone to error is what i mean
That’s correct. If they change avatars mid-game, they’ll automatically be teleported 999999m into the sky and set to a nearby respawn point so they can’t come back down
Ahhh icic~ Yeah, that’s why I’m trying to look for 3 different solutions. So far I have 2:
- NUSS uses physbones to transmit data while the player is in a designated VRC Station
- Contacts transmit data somewhat continuously
But if either method breaks and starts sending junk data, then the worlds will be receiving one set of good data and one set of junk data; and won’t be able to tell which data to load. So I need a 3rd data transmission method so that the good data will always have a 2/3rds majority
-# I was hoping to use raycasts but that turned out to be a dead end
raycasts don't transfer data; i really think you should consider string copy/pasting as it's very easy in comparison to avatar data and it's easy for anyone to understand how to copy/paste a string. it does require they keep track of the string themselves though
That’s the issue. If the game goes viral, I’ll end up with a thousand kids crying in my DMs about the pokemon they lost because their phone got stolen or something 🙃
avatar data isn't stored server-side
if they lost their device, avatars have the same issue
Luckily that can be mitigated a bit with single-world data persistence. I.e., each world would save a player’s most-recent progress and could re-generate their string for them. But having to explain that 1000x sounds like a pain
True, that’s a bad example. But the players are much more likely to lose their string than to lose their device. And the single world data persistence -> avatar parameters transfer could allow their save data to spread to multiple devices automatically
you could have both the string method and persistence
have it update and save itself while you're in one world, then require players to "export" their savefile when they want to play in a different world with the same data
True. But then there’s one glaring issue with that (and it’s the main reason I’m trying my best to avoid it):
- In case the player starts a new save file on a different device, I need to know which save data is their main save data. Otherwise their fresh save file could overwrite their main save file in the single-world data persistence, which is the opposite of what we want
- Therefore, each save file will have several bytes dedicated to the “Playtime” variable. I.e., if there are 2 conflicting save files, the one with the higher Playtime will overwrite the one with less playtime
- But if students have access to their encrypted data, obviously they’re going to try tampering with it to see if they can cheat. And this is going to result in save files with tampered data having massively higher Playtimes than their actual data and then overwriting their actual data
- Alternatively, if someone tries to plug in someone else’s encrypted data, the decryption process will yield the same result
It’s honestly just better to not give the players easy access to their data
Keeping a player’s save data stored only on their device, encrypted, unable to be shared, but able to spread to their new devices, is the only reliable way to preserve data and prevent cheating
avatar data is quite easily accessible, perhaps one layer removed, but it's not safe from tampering by any means if someone intends to cheat
Even so, it’d be very difficult for a player to read my code (I deliberately write it so that only I can read it), and even more difficult for them to actually decrypt it themselves. At that point, cheating becomes harder than beating the game normally
Just to double check, Disbridge only allows for one-way communication, right? From Discord -> VRC?
do you worry at all about sabotaging future you in like 2 months
Hello I had a question...
Why does this stay on for over 10 minutes? Going close to 15 minutes now......
The craziest thing is I went to go cook mac and cheese and it's still doing it..... 😞
Update: The instance I tried to join prior to leaving the fishing world has recently closed and they said I didn't have permission to join that instance.
Essentially the instance was closed.
It's been that long, I'm now eating my macncheese
Yes it finally finished
15:24 on timer
Yeah, VRC’s built-in persistence is pretty buggy tbh x.x
Is there a way I can test my persistance stuff with out uploading to the public version?
All the persistence features should work both in Play mode in Unity and when you Build & Test.
two questions:
- Should I use persistence to save if someone clicked Accept on a disclaimer like this? (should as in, I think I do want to so people dont have to click on it every time, but should I only show this popup once? or is it better to show it more often?)
- How should I go at this, if I should.
just my take/opinion, but i think vrc views sessions as the boundary for accepting rules or enforcing anything. i think it's probably safer to have them accept every time. possible someone could come back x amount of time later and now have issues they didn't have before. or creator side, someone could change their disclaimer without proper versioning and it'd skip past without them accepting the updated text
optionally you could add a "remember my choice" checkbox
good idea.
this should do the trick, I assume?
I just winged this graph
(was too lazy to just write C# code for now, I am way too deep into the .NET 8+ for me to write valid code for Udon)
Sorry, I really don't do Graph, I'm not the one you want to ask for help with it
Also is there a good way to like clear persistance if data of user older than a month?
fair enough. I could rewrite it to U# if you need me to
but honestly they work kind of the same
don't do it for me, I don't need such a thing 🙂
no worries
... is something like this possible?
Oh wait, i think I can make that
if you record the utc of their save time it'd be pretty easy to reconstruct the time since when loading (i also don't do graph much). would recommend the networking version of datetime over local system utc though
Was already working on that. This graph is getting a bit out of hand. Might need to rewrite it to U# anyways
hmmmm fair
this one?
or this one?
GetNetworkDateTime()
and then .Ticks?
yeah i'd probably use ticks
also you shouldn't do it on start, you should do it on player restore for the local player being passed in
like this?
(and yeah I optimized the code by just using one variable and checking if it even exists)
yeah that restore looks correct for a non playerobject
I'm confused about the storage limit. It is 100 KB for PlayerData and peristence enabled PlayerObject in total right?
Not 100 KB for PlayerData and a separate 100 KB for PlayerObject?
pretty sure they’re separate?
most folks talk about it like they’re separate
their storage limits*
;\ that doesn't answer it does it
It does not seem separate from my experiments. Saving persistence enabled PlayerObject and PlayerData occupy the same storage when calling GetPlayerDataStorageUsage() and GetPlayerDataStorageLimit()
All PlayerData gets 100KB (it's a single object), all PlayerObjects get 100KB (spread across them shared)
And therefore we have 200 KB in total!
and that would mean users don't have an API to tell apart which is which for GetPlayerDataStorageUsage()
^ that is false because I didn't try Networking.GetPlayerObjectStorageLimit
Actually that was super strange because I had been testing persistence enabled PlayerObject and this would fill up the PlayerDataStorageUsage. Or should this be the expected behaviour?
Here's 1000 manual synced objects that are a child of a persistence enabled PlayerObject. Each with saved position, rotation, various IDs and states.
I'm not sure where the PlayerData usage is coming from in this case, could it be that it's overflowing PlayerObject storage? I don't understand
it might be that they store the playerobject keys on playerdata or something, i'm seeing a small amount of playerdata usage without any calls to it in my playerobject setup
we broke Kitkat
🐈
There's evidence of this. I speculate that hashes for the [UdonSynced] variables are stored there
I'm experimenting with cases such as adding more UdonSynced variable to a persisted object
it knows that there are 8 synced variables and I tried to add a 9th
what other PlayerObject secrets do you know? Tell us
using one blob over many objects is the best playerobject of all 📗
that sounds very plausible
this is how my player object is structured
SaveLoad holds my player data
i was more referring to the idea of holding one persisted object with a block of data on it; as opposed to many objects with udonsync across them
if SaveLoad is the only point where udonsync lives it may fit that idea
like this?
xD
yeah; i'd advocate for versioning at least and packing it rather than parallel arrays, but if your layout is very rigid then parallel arrays are okay too
mind telling me about packing? I know a decent few languages, but not enough about them to say I KNOW them
but yes, they're rigid, the item id is linked to the position and rotation
packing to a single unit, like a byte array or string. if you ever need to introduce a new field or fields it becomes easier to maintain if you're not operating across multiple data structures. usually you'd pack your working/intermediate data from local to the udonsync side on save and unpack when loading (going from a byte array to your working arrays or data structures)
i'm not sure it'd be worth it for what you're doing at this point though
hmm... so if I'm understanding you correctly, you'd save multiple fields into 1 byte array, save it, then on load put it into a local script?
I feel like that'd be harder to maintain though
maybe it is easier to reason about in your case, idk. it involves serializing your data into the byte array yeah. i feel it's easier to reason about when managing migration or upgrading your scheme in a central place and i prefer to separate the concern of saved/packed data from the working data. in your case if the working data and save data are at parity there's probably not much benefit
I like having the data put into the udonsynced the way it is so that it can be saved when something is placed
and since it's not constantly syncing - I use manual serialization - it should save data (I hope)
you can achieve the same with packing, there's not really a difference between packing upon change and requesting to serialize it like you're doing, but it probably requires thinking about it a bit differently
packing seems interesting though, so I could use it for a future project if I ever have an idea to make a different game world, would you mind providing a sample of it as I could probably get a better idea
https://creators.vrchat.com/worlds/udon/data-containers/byte-and-bit-operations/
this gives an overview of how you might pack or unpack different types to a byte[] given a known layout
it probably looks a bit unclear or verbose because they're just hand packing it right there inline and using different types
I see, so you unpack it in the same order you pack it