#udon-networking
1 messages · Page 2 of 1
so the position/rotation is synced by VRCObjectSync?
Yes, locally the object is rotated and then I rely on VRCObjectSync to carry that to the remote? at least thats how I understand it. I'm still new to this sorta stuff
I'm using moving these empties which both have VRCObjectSync on them
VRCObjectSync can be a bit choppy sometimes afaik, someone once demonstrated a script they made which was a smoother version of VRCObjectSync in certain scenarios
later on they sent a code snippet #udon-showoff message
however, with a lot of objects it can actually be choppier #udon-showoff message
When moving around it feels for lack of a better word like if the change in rotation is not large enough it doesn't update
yeah it might be, idk exactly how VRCObjectSync works
I have some new things I need to try
I want to make an object follow the player when the player clicks on it. Position yourself in the head and follow him. But I don't know how to change the owner of the object based on when I click it
Networking.SetOwner
and then plug Networking.LocalPlayer in there
thx @weak mirage i change some of the code. now all player can click and take the owner of the object. But the master of the rooms it set as owner when they enter. also i need to check if the object have owner stop the fuction of can be grabeable. can i use the stuff you send here?
well my question was deleted as spam
I'm having an odd issue where teleporting the player to zero once they move a certain distance away works as expected in the Client Simulator but in test builds it somehow is teleporting between the two extremes rapidly and I'm stumped on the how or why this is happening. I'm using desynced stations and the player exits the station before teleporting then re-enters after teleporting and the station is also moved to zero. Weirder still after a seemingly random amount of time pinging between the two extremes it will eventually teleport to zero. Not sure how to debug this or what could be causing the different behavior.
I swapped from FixedUpdate to just Update and its now behaving as expected
Does anyone know what happens to manually synced variables when the owner crashes? Like if I set an int, serialize it, everyone gets it, and then the owner crashes. Everything should be fine and the new owner should have the update?
I need someone to just show me the basics of udon. I have everything installed... right now I'm just looking to make a simple setup where you can pick up anmd object, carry it around then drop it and it won't respawn, or reset. how do I do this in laymen terms?
For what you've described it's not necessary to use Udon for this, you can use existing components made by VRChat for this very purpose. Specifically you'll add a VRC_Pickup component to make it pickupable locally, and presumably a VRC_ObjectSync component so the object's position becomes networked and others can see it being moved.
video tutorial on this subject: https://www.youtube.com/watch?v=dfjlVe0XXTU
more details on these components:
https://docs.vrchat.com/docs/udon-networking#example-the-simplest-networked-object
https://docs.vrchat.com/docs/network-components#vrc-object-sync
https://docs.vrchat.com/docs/vrc_pickup
Thank you for the info
I have a question in regarding a Network Event to an owner using SendCustomNetworkEvent
If I send a Network Event to the object's owner, will the rest of the code wait until it gets a response from the owner, or does it continue to execute the rest of the code regardless if the Network Event was received at that time
Your code will continue to run. Network events are asynchronous.
If I want to set a synced string to the display name of someone that clicks a ui button do I need to make the person clicking the button the owner? Or can I somehow get the name of the person that clicked it sent out another way
Somehow I feel like there's overhead to transferring ownership and I should avoid it
when they crash the owner changes, the synced variables are stored by everyone at the same time, it's just only the owner can change them. When the owner crashes a new owner will be picked which will still just have the same variable values
Thanks. That's what I figured but I wanted to confirm.
I'm working on a board game with randomized tiles and it'd be a nightmare if those go out of sync an hour in
you'll need to make it the owner yeah
transferring ownership isn't to bad, you mostly should just make sure that 2 people don't request owner at the same time. When that happens, only 1 of the clicks will actually get through, depending on what arrives first (that's called a "race condition").
If you have a button that gets clicked on by a lot of people at once, like a join button, you can either consider a different design, like an area where people need to stand to join the game, or use player object pooling, which has a synced object for every player in the instance (which can be a bit tricky to code with if you don't have a lot of programming experience). If you're gonna use player object pooling, I highly recommend this prefab: https://github.com/CyanLaser/CyanPlayerObjectPool which handles allocating and removing owners when people join/leave for you
I've got a decent amount of experience in everything except udon. Race condition shouldn't matter here as it only puts their name on a turn order board. If the string is set to anything other than empty it doesn't allow a new entry. Whichever gets in first is fine.
Thanks for the info though.
hmm, how reliable is testing network things with multiple local clients? I'm checking some synced variables and it appears to be working fine - but is it client-based or is it just working because both have the same IP? 🤔
I'm assuming it's ok, since one would be the owner and one isn't
local testing is a very reliable way to test networking. It should behave exactly the same because it's using a real remote server as the host
great! good to know, thank you
usually the only thing you can't test well locally is if you have a lot of people doing things at once, for example lots of people pressing buttons at the same time in a synced menu for example
Is the local testing intentionally extra desynced? Or is this a side effect of me handling the networking poorly (I've only ever really done local/rollback stuff before)
no, it's the same conditions as a normal instance
If it's all done locally shouldn't most things be updating instantly though? there's nearly a second delay between what I do in one instance and what I see in the other
I might be too uneducated on this ^^' just trying to understand
Mostly only worked with rollback before
it still uses a normal server, so it has the same round trip as anything else
a full second delay is a lot, but could be explained by either being far from the server you're connected to, lots of other network traffic causing you to be clogged, or simply using continuous sync when you probably want manual sync
"local" refers to where the world files come from, it does not refer to where the networking takes place
Oh this makes more sense then
I thought it did everything locally ^^' it not being uploaded to the servers and all that
it doesn't need to be uploaded to the servers, since the servers don't need to know anything about the world. They just relay synced data between clients, that's all
I'm trying to play a sound that can be heard by other players via a game object, which is spawned from the VRCObjectPool, but I'm not hearing the audio from the other player's window and they're getting constant Non-owner attempted to return sndGameObject to sndObjPool errors in their logs. Wat do?
only the owner of an object can spawn or return objects from a vrcobjectpool. All you need to do is networking.setowner before doing stuff
Is there a way I can have late joiners be able to hear music that has already been played, so that when they join, they are in the middle of the song? (basically trying to figure out late joiner event syncing)
VRCDN works wonders for PC & Quest with a compatible player
That won't work for audio files that exist within the world itself. They're referring to embedded audio elements (as per the other channel).
I think I'd sync the start server time of when the audio source starts playing. And then, everyone who receives that server time calculates the delta and adds it to the audio source (AudioSource.time I believe).
If it's looping, you can rotate the delta using modulo and AudioClip.length.
I've tried making it so that every time a player joins, it gets the time of the song, but it doesn't want to play for the person when they join
Idk, ill keep looking into it. Thanks for the advice guys
Can you post what you tried?
Is there any reason where manually synced variables that are being updated by an object owner running RequestSerialization wouldn't get updated for clients? I've been working on a lot of stuff for the past few weeks and its been working fine; until a few days ago when my synced variables decided to no longer sync for other clients when RequestSerialization is ran.
I cant find any sort of cause in my logs, and bizzarely, network events still function fine on the scripts which rules out crashing; it only seems to be syncing variables that isnt working. Deserialization is being ran by clients, so they are getting something I guess(?); but its not updating their variables. I'm mostly just wondering if anyone else has had something like this happen and if theres anything that would stop variables from being updated (apart from setting them locally, which isn't happening either)
I'm having issues with sync atm. Basically my program sets a float timer every frame on the host of the lobby. The variable is UdonSynced. I then have it send a custom network event every frame aswell to update a float on an animator for all players based on the variable. However, it appears that the float is not being synced as the progress bar is empty for everyone but the host. Anyone know what could be happening
you shouldn't send stuff every frame, make it a few times a second or once a second by making a simple timer ```cs
private float timer;
private void Update()
{
timer += Time.deltaTime;
if (timer >= 0.5f) // runs every 0.5s
{
timer = 0f;
// do your syncing stuff here
}
}
Its a timer that runs up to 20, similar to what you have, so I guess technically its not every frame. The problem is the variable I have, which would be timer in your code, isn't syncing between clients despite being designated as UdonSynced
Or at least I don't think it is, but there isn't a console in build&test to check
and play mode only has one player, who is the owner
Why is it bad if it's synced every frame?
there's limits on how much you can sync
idk where and what to post but the world is called "Band Together!"
I'm talking about the code you were trying out that didn't work. Specifically the networking part is only needed.
Super basic question; How DO you populate a player array with the players in the instance?
Like, GetPlayers wants an input and outputs and array... but I want to get the players in the instance, not from another array, and it can't be blank.
Or.. .do I GIVE GetPlayers an empty player array, and it populates it?
Logic tells me that GetPlayers from the empty array would retrieve nothing from it... not from whoever is in the instance.
I can use GetPlayerCount... That tells me how many people are in the instance... but not who they are.
OK, so it looks like you have to first get the player count of the instance... use that to construct an empty array of that size... and then fill it with players afterwards.
THEN you can copy that populated array to one you've made to keep that information.
Boy that is convoluted~
I'm surprised there's no node that like... SetPlayers, and drops all that directly into an array for you.
GetPlayerCount will just get the number of players... why isn't there something that just gets the players too? 🤷
It seems backwards to me.
Get the players, and THEN count them.
Not... get the player count, and then build a list of players from that. 🤔
The reason why it's a bit convoluted is because it encourages you to reuse the same array any time you want to get all the players. Constantly recreating a large array like that is not great and can cause hitches from the garbage collector.
Hmm. See, I'm still thinking it's just easier to construct the array each time and not even bother putting it into my own... because then I would have to add and remove from my own each time players change. XP
no, you don't have to add and remove manually. Any time a player joins, you just need to call getplayers on an existing array, that's it
Does GetPlayers resize the array too?
no, but you can just start with an array that can fit all the players that your world supports
which is (softcap * 2) + 2
How would you count players then? If the array starts with a fixed size, you can't just get length to use for a FOR loop or something then. It will always report 32 for example.
the simplest way is to just iterate over the entire array. But if this is a performance-critical context such as happening every frame, then what you can do is only iterate the loop counter when you find a valid player. Then use playercount as the max instead of the array length. I don't think you can do this with a for loop in graph, though, you'd have to do it with a while loop
Phew... OK. 🤔
Far easier to recreate the array from GetPlayerCount though at OnPlayerJoined and OnPlayerLeft and use GetLength. 😂
I'm pretty new to all of this, so I'm trying to apply logic and keeping things simple without knowing the consequences. :B
ultimately, if it's just one script doing that then sure, no big deal. But if you've got hundreds it could add up
Noted. Currently making a UI player list, just to figure out exactly how this whole player array things works, and stumbled on how to actually get an array of players.
Thanks for the explanation though~ ¦3
nothing wrong with that
Hey, Does anyone know if it would be faster to sync an array of 16 bytes, or an array of 2 ulongs?
same bits total, just wondering
you can check the total bytecount of syncing if you add onpostserialization and check serializationresult bytecount. if they're the same, they're the same
i’m assuming it would be negligibly faster to serialize/deserialize less objects overall despite same overall size
well if it was anything other than bytes I would agree with that. But a byte array doesn't need to be serialized, since the thing that it serializes into is a byte array
though if you're serializing from something else into a byte array in udon, that's going to be a lot slower than the system doing that for you
oh you’re right, i didn’t read close enough to see they’re both arrays
regardless the performance difference should be extremely negligible with 1 vs 2 obiects
How do I forcefully wake up an non-moving object with continuous sync so that the variables update for other clients?
Providing that the script with continuous sync also has a rigidbody and object sync component on the same game object.
Sorry for replying so late, but here's an example of a script I attempted. The plan was that when a player joins late, it syncs the time of that late player's audio source to that of the players who were already in the middle of a song. Then, the song plays for the late player without the previous players needing to replay the song from the beginning in order for the late player to hear it.
One thing I notice is that you have the same event name twice. Is that even allowed in udon graph?
Also, you are getting the audio source time and then setting it to the same value again, basically not changing anything.
You need to define a synced variable for the time and use that to set the audio source time when it's being updated. I think you can hold Alt (or something) to get access to the on change event when drag and dropping the variable.
Also, the master needs to set that synced time so it gets send to people who join.
Can I get some assistance I’m trying to make a working weapon for pvp combat and I’m struggling can someone please help me out I’ll pay if wanted
Try Toly's combat system or P - Shooters.
^
I set up the networking for the decoration that will turn on/off globally. It works and everyone can see it when someone presses the button, but whenever someone joins the world, it would be turned off by itself. Any reason why this happens?
I'm a fucking idiot. Thank you very much. You are the best.
Does anyone know how I can use an audio player and have it pull MP3s from Github? I've tried several audio players with zero results. I don't see why if a player can pull from YouTube that it should be able to pull from another source. I'm very new to this Udon thing, and I'm not a coder. Reading the instructions and script options makes me cross-eyed. 
you can't load mp3 files, however you can convert it into an mp4 and just not output video to a render texture, that's how audio players that get audio from links work
The usual mp3 format also plays great in the players.
oh really? I kinda assumed it doesn't because it's not a video
The following services are on the video player whitelist. If a service is not on this list, it will not play unless "Allow Untrusted URLs" is checked in Settings. VRChat on Android will not play video if the host is not using HTTPS protocol. Whitelisted Services The services listed below are inheren...
Does RequestSerialization() sync transform of the object by default?
no, it just syncs synced udon variables
if you want to sync the transform you can use the VRCObjectSync component
be aware that if you're talking about requestserialization you're probably talking about a manual synced udonbehaviour, and manual sync cannot be on the same object as a vrcobjectsync
Maybe a warning about that in the SDK would be neat
Would it be more optimized to stuff all my game pieces in one ObjectPool and spawn the correct amount based off the index?
Or would it be fine for each piece to have its own objectpool?
If you are dealing with objects of different data types (resources vs tools) split them, if objects have the same data pieces (chess pieces) keep them in the same pool. If your pools get large, consider using a stored indexer (location of last valid) to use during iteration. Ideally you won't instantiate objects during run-time and will already have them generated before uploading your world (have all your chess pieces initialized and in-scene, editor-enabled scripts are your friend here). In my experience this helps cutting down on initial lag and possible object desync, you also get to fiddle with the object net assignments (TopBar ->VRChat -> Utilities -> Network ID Utility).
Yeah each piece has different attributes and they are summoned dynamically with non predetermined amounts.
At the moment in testing I only have four pieces.
I know there cannot be more than 77 of one piece at once though.
Also how do object pools work exactly like if I place 1 game object in it can it infinitely generate that game object or can it only summon one of each in the array at a time?
Each type of piece will work the same. The only difference in similar types of pieces is their health.
I am seasoned in c# however so all my game pieces use inheritance and have a base class of piece. Then they all have a class which overrides their attack methods for custom attributes.
I would also like to mention the pieces are not all spawned in at once. A piece spawning in is "rare" it's slow to happen maybe like once per 30 seconds
I'm not sure how the default/included pooling solution works, I just wrote my own to give me more control over processing (like optimizing access attempts and pool object regeneration in editor). If each piece is derived from the same interface, then you could use a single pool system. The downside would be that access becomes more expensive as the number of pooled objects grows. Processing is extremely slow in udon, so if you are using large object sets it still might be best to decompose pools based on true classes rather than their interface.
Yeah I only used that joined interface for calling a few main methods code wise so I don't have to store active pieces separately.
Maybe it would just be optimized to have 77 instances pre-made?
That would get horrible over time though when say I have 10 different pieces not just 4
You'll still want to pre-generate assets regardless of how often objects are spawned, it makes state control/sync of those object way easier if you are planning on networking your scene. Is this for enemy unit generation/what's the project your building?
I don't want to share too much info on it but basically it's like tower defense.
I understand. The number of assets existing in your scene at a time usually isn't a big worry as long as they are prefab'd. It's going to be the amount of processing/networking those objects do in your scene that you'll want to look out for.
I think the best solution for units would be pools per AI type/complexity, but you could also do mesh type/complexity as an alternative for built-in load balancing. Have your data/control object (health, move-speed, movescript) as the pooled/parent object to the lower display object (animated unit moving down the lane). You'll also likely want to lock the control object to only process on the local player and break the synced data for enemies apart into smaller packet objects with certain manual deserialization calls (set state, take damage) that call back up to your data object.
Yeah that's what I was thinking about networking.
I would just have an event to start enemies and game pieces.
And in theory since everything movement wise is predetermined all clients should be synced but just in case o was planning on doing manual sync for death of an enemy
I just was unsure about the spawning of game pieces.
Like can I just have 1 hidden on scene and use the pool to spawn more. Or will I need 77 of each piece on scene since I know that's the max that can be placed.
Rather than free placement I'm going based off of calculated voxel (cubes) in an area
So each piece holds its voxel place x1 y~ z4
I'm not 100% on what the spawning method for the default pools are, but you'll want your object to exist in your scene before the starts. From there you can easily de/activate them as needed (instead of instantiating them as needed). Udon is extremely slow, so a space for speed trade is usually always a win.
So if you already know the max # of allowed enemies and towers, you should generate your pools to those limits
Hmm alright, thx! Gonna go play around with that.
I have an array of Text and want to display one entry of that array. The Player should be able to interact to display the next entry. The currently displayed Text should be synced to all players. I did get some synced behaviour working but synced players ended up having different Texts and it was continous.
My latest try does not work at all and I don't know why
UdonBehaviour Synchro is set to Manual
iterator Variable is marked as synced
Synchronization of all variables works only through SetOwner.
i added a RequestSerialization at the end of both Branch Pathes. Both can interact to display the next Text, but it only syncs with one user, (the owner i guess?)
I don't know how to use SetOwner here
oh... it automatically assigns the player and the object. That's nice. Works so far.
So I have to change the owner everytime someone else wants to make a change?
This scene is ready to Build & Test or Publish, and it demonstrates many common interactive items. Prefabs These objects show off some of the Prefabs included with the SDK which demonstrate default interactions with the VRChat components for Avatar Pedestals, Stations and Mirrors. AvatarPedestal...
Set SliderValue looks like a custom function. Is it possible to create own functions with udon?
No, not yet. Potentially will be able to when they make Udon2
Aren't they just called custom events?
If I use manual sync do I have to handle the ownership change of the gameobject?
Using OnOwnershipTransferred event
Onownershiptransferred is not something you "handle" it's just an event that notifies you when something happened, so you can use it however you want. If you want a nameplate somewhere to update to the name of the current owner, then yes that is something you would have to handle and you would do so by using onownershiptransferred
Hello, I'm trying to figure out why a drinking game I made is not syncing between the PC and Quest version of my world.
I am using U# to code the functionality and how I have it setup is there is a RoundTable gameobject in the world (first picture) that has an arrow the players have to click on in order to swap out the RoundTable with the actual DrinkingTable gameobject which is active by default but is stored in a parent gameobject that is inactive by default called "SpinWheelGame".
Once SpinWheelGame becomes active so should the DrinkingTable gameobject which has the game functionality on it. The DrinkingTable has an arrow on it that once clicked, spins the wheel through a script attached to it. It rotates the anchor point (second picture) rotating the arrow as well. The arrow has the script set to Continuous Synchronization and also has a VRC Object Sync script attached to it. The Continuous synchronization only handles a UdonSynced bool named isSpinning so that once someone spins the arrow, no one else will be able to spin the arrow until it stops
Hello, need a clarification of this sentence from the documentation. Can someone help me? I am understanding that whoever owns the script is the local player from that script.
"The local player is the Player that this Udon script is currently running on-- alternately, the local player is you. It's very important to know yourself!"
If we are talking about Networking.LocalPlayer, that's not the owner. It's the player whose machine the script is currently running on. You get the owner of the script by calling Networking.GetOwner.
Which part exactly does not sync? Does the swapping work for everyone?
aight i got my nice panel to work, now i need to network it properly! can i test OnDeserialization on the local test with 2 clients? or do i need to upload and test with someone else?
nevermind the question above it works with local
how would i transfer ownership of a slider tho? because i want everyone that sees a slider or button to be able to use it
yeah networking is my nemesis. i can't transfer ownership for my sliders because it wants a Gameobject.
your slider component would be on a gameobject
ye i know but i'm kinda confused which gameobject i should use. my ui structure is full of emptys to keep organization hehe
should i use the rLabel or the sliders or the ringcontrol or the panel or canvas etc
my brain is not working properly rn xd
this is my code for the owner check as an example
The game object is the one the script is on. So you can just do Networking.SetOwner(Networking.LocalPlayer, gameObject)
wait i can legit just put gameObject down?
i swear to god i feel so stupid right now
Don't feel that way. Maybe you just need to look into some examples more. It also sounds like you want to do manual syncing, so probably a good idea to look into that.
Sync method is set to manual
HA it works!
besides slider 1 but i'm pretty sure i just fed up on the ui itself there
yes the swapping works for everyone. so basically what I should of said at first was that spinning the arrow is not cross-platform syncing for some reason. So PC players see other PC players spin the arrow. And quest users see other quest users spin the arrow, but a PC player will not see a quest player spin the arrow and vice versa
Yeah, then it has to be an issue with the VRCObjectSync component, which means I can't be of much help. Maybe it has problems initializing properly on the quest? You could try leaving that game object enabled and disable it at start, just guessing here though.
hiii one of the lines on my script is saying it doesnt recognize the identifier 'NetworkInstantiate' does anyone know what to use in udon to replace that? the line is
grid[i][j] = NetworkInstantiate(objects[randomIndex], transform.position, transform.rotation);
do you need these objects to be synced with other players?
yes
Instantiated objects cannot sync, so you need to make an object pool. You can either create your own or use VRCObjectPool
For a new client joining, does OnPlayerJoined get called once for each person already in the room?
Yes, and the user joining also does a self call
Okay I'm starting to piece together what I'm doing wrong. Got a couple more questions though. Are playerId's the same in every instance? and Can a player's ID be larger than a room's max player capacity?
Augh. I have this world were each player gets a script from a array. Player one joins They get the first script. Player 2 gets the second script, Etc. But for some reason It breaks for Player 1 (the host) as soon as anyone else joins, it doesn't seem to break for anyone else though
Just to clarify: OnPlayerJoined is an event that fires on everyone's client for each person that joins. If they are already in the world it won't fire.
Player ids are simply incremented by one every time someone joins. So if the person with the highest player id - let's say 5 - rejoins, then they get the player id 6 now. So yes, the id can and will be higher than the player count.
How can I create a new object synced with everyone? Right now I'm only using Instantiate(object) so it's only local
Edit: I just notice someone with the very same question above, but I'm still confused on how it works
Player IDs start 1 and then increment for every user joining the instance (even if when a user has already been in the instance, left and came back). So yes it can be above the max player capacity.
The "Player ID" is really more of a session id...but naming things is hard :P
who tf begs for roles xd?
does anyone know what "suffering" refers to? (because it probably shouldn't be this high!)
Suffering refers to how saturated your outbound connection is. If you try to send too much data too quickly, you will get "suffering" which will slow down how fast you're able to send data. Suffering will slowly go down over time as traffic is successfully sent out. 13k suffering is very very high indeed, and may result in some network events being dropped completely. Udon sync variables should still be able to get through eventually, though it may take them a while.
You can't get the suffering number directly in your code in order to prevent people from relying on specific arbitrary thresholds, but you can get networking.isclogged which is a bool that returns true if suffering is anything above 0
I see, there's been a lot of reports in my worlds of lagging and i've concluded its related to 'suffering' constantly going up overtime. I don't exactly know why, and it wasn't an issue when I uploaded them; only seemed to start happening this week. Thanks for the answer though, I guess i'll wait and see if there's either more reports of random sufferings or try and deduce whatever got changed within the past week to cause it.
is it possible that you're sending tons of data, either on purpose or on accident? Maybe requestserialization or sendcustomnetwork every frame?
I don't think so, but i'd have to check to make sure whenever I have some spare time. Thanks!
I just found it odd that they suddenly started having this after being fine for the past few months; but yeah, i'll take a look and try and get some more info later.
I cannot get these freaking spawned objects to network! Any ideas what I'm doing wrong?? I can post the spawner udon screenshots here
Fixed
I've done some more experimenting, and have concluded that having literally anything marked as using the "Continuous" synchronization method seems to be the source of the issue. I don't think a gameObject storing a couple synced integers should be outputting 340 bps if it's sleeping and not even doing anything with said integers. (unless that is correct, and that's just how badly continuous runs. also this example was through experimenting, i am aware its not actually practical.)
I'm not really sure what to do about it except just well, not using continuous, and just rewriting my code to work with Manual syncing instead, but I think it's something that should be looked into I guess because it wasn't an issue for the past year. I also had issues with Continuous in my other world project where it would cause all my scripts to be unable to get the server time; so I am kind of in the belief that something is wrong with Continuous syncing at the moment.
I guess it's also worth noting I use U#, so maybe it's an error on U#'s part? I dunno. If I find time i'll try to isolate the issue and put it up on canny or something.
I looked at it a little and noticed that you have "Thingy" sending consistently every 3 seconds, and it contains 1700 bytes, which is very significant
continuous sync objects will automatically adjust depending on network conditions, so if you have a ton of them they'll keep you right under the limit. But if you have one large manual sync in addition to that, it will blast right past the limit. If it continues to do that over and over without allowing any chance for the network to recover, it will just get worse and worse over time
also, continuous sync objects do not sleep. They will continue to send even if there is no activity. So If you have a lot of little things and each one only sends occasionally, you should set them to manual so that they can sit in the background and do nothing
I'm working off Kuro's Apartment at the moment; since it also got effected by it (it does significantly less than the bus). I have found swapping to manual sync on all of the pickup able items has stopped the world (Kuro's Apartment) from gaining suffering; so I think I'm just going to do that to the bus at some point and see what happens.
That does make sense though; thanks. I'll keep that in mind
Hi. I have a question about syncing arrays. If I try to sync 1 Int array with a size of 500 different values, will the network have a difficult time sending the data? It is in Manual sync and it should sync about one time at least every 3 minutes or more. I am new to array syncing and would like to know the limitation/what not to do when syncing arrays before I try it with a high array size. In the docs it says that Manual sync is limited to 49 kB per serialization, is an Int array with a size of 500 values close to that number? Or it depends on the value and size of the array?
It may take a few seconds to send and leave you clogged for a bit longer, but waiting 3 minutes before the next one should be totally fine. That's a fairly large but still reasonable amount of data.
1 int is 32 bits or 4 bytes, so 500 ints is 2KB
though I should mention, if you don't need to represent very large values, you won't need to sync an int. You could use a smaller data type that is cheaper to sync.
a classic "int" is 32 bits and can go up to 2,147,483,647
a "short" is a 16-bit integer and can go up to 32,767
a "byte" is an 8-bit integer and can go up to 255
I see thank you for the info. I will not be needing an int larger than 32´000 so If i try using a short int array with 500 (in reality I would use about 350) 2 bytes * 350 , will that be a more reasonable amount of data sent to avoid getting the network clogged? I believe that is about 700 bytes.
eh, it might still clog a little but it would clear up very quick
it really depends on how much other things you have in the world trying to sync
but once every 3 minutes is plenty of time regardless
it's really not the end of the world to get clogged a little if you leave room for it to clear
I am planning on having just that one int variable be synced over the network. When the network gets clogged, does it affects players in some way (for example, their IK starts to slow down, along with voice breaking) Or does it only affects networked events with Udon scripts? Can I use this node to see when the data has finished completed on the local player or is that node used differently?
serializationresult comes from OnPostSerialization event, which happens after sending synced data. It allows you to know whether or not it was sent successfully and how many bytes were sent. It does not give you any information about when other players receive it
and yes, if you are heavily clogged it can affect all your outbound traffic a little, making your movement slow down. But voice is pretty resilient and unlikely to notice a difference
udon can know if you're clogged by checking Networking.IsClogged and ingame you can see the exact amount by looking in debug menu 4's Suffering readout. 0 is ideal, hundreds are pretty light, thousands are heavy https://docs.vrchat.com/docs/world-debug-views
These are the tools you can use to debug your worlds in-game. In order to access debug views you need two things: Launch VRChat with the launch parameter --enable-debug-guiPress Rshift + Tilde + 1-9. If you have a keyboard layout where tilde is not directly to the left of the 1 key, try using whiche...
I see, very useful info! I will keep all in mind when working on it, thanks. One more question: Does "OnPostSerialization" event fires for the owner of the script, or for everyone receiving the serialized data? (I understand that OnSerialization only runs on remote players, not the owner so I wonder if it is the same with OnPostSerialization)
only for the sender
sender gets OnPreserialization and OnPostserialization
receivers get OnDeserialization
I see. Thanks for the information!
I'm having trouble getting sync between pc and quest. I have a UdonSynced bool that keeps track of the state of whether or not a gameObject should be shown.
for some reason it works between PC users in the world, and it works for Quest users in the world but it's not cross-platform syncing between the two.
if anyone can help me figure this out I'd really appreciate it
I'm available to share my screen as well
Synchronize ID in both versions.
hang on, before you try that, do you have the pc and quest versions in two different projects? That's what that tool is for
yes they are both in two different projects
i'm not really sure how that tool works though, never heard of it
so i'll have to look into it
ok, then yes that's exactly what you need. You can use it to export network IDs from one project and then import network IDs into the other project
When you set the VRC video player on repeat, does it take a toll on bandwidth usage on it just stores the entire video in cache and replays it?
I am trying to figure out if it makes any difference on the server side were the video is being taken from in terms of bandwidth.
That is generally up to the driver i.e. maybe. But in general videos are not downloaded in their entirety and then played, but streamed and downloaded in chunks which are kept in a self-overwriting buffer.
So yeah generally it will redownload. maybe.
Is it possible to network gameobject child detachment
sure, you just need to do it on all clients. You can do that with a synced bool. Reparenting does not break network IDs so you can do that safely as much as you want
I did something like this
SendCustomNetworkEvent(NetworkEventTarget.All, "UpdatePosition");
it works so I believe its alright 😄
be aware that that won't sync with late joiners
hmmm, it means it will stay in the same position as the world loaded?
it means it will not unparent
or will not perform whatever action you have in UpdatePosition
I see, so synced variables is better option?
yes, synced variables are much more reliable and built for syncing with late joiners automatically
I see, thank you 😄
Do players have a persistent Id that I can get? For example if a player leaves and then enters an instance, I would like to be able to have their hp and upgrades stored. For this I would need to be able to uniquely identify the player...
Only thing we have is the displayName in the player api.
You can just store their username?
Usernames are unique arent they?
So long as they dont change it
@obtuse echo @normal sundial how can I get that? I was reading a section about player in the manual https://docs.vrchat.com/docs/getting-players Okay, i see it says "Look for a particular name" in the details about getting all players now that I read it again but it is not listed as any method there in the list which confused me. Is there a decent up to date detailed documentation about the different APIs somwehere?
These nodes are useful for getting an individual Player, a group of them, or all of them. Networking.get LocalPlayer VRCPlayerApi The local player is the Player that this Udon script is currently running on-- alternately, the local player is you. It's very important to know yourself! GetPlayerCount ...
What method are you looking for
That part of the documentation tells you that you can for loop them and then compare the displayName to find a specific player. There is no such method afaik
This has some API stuff too, in case you missed it: https://docs.vrchat.com/docs/players
You can interact with Players in your world through the VRCPlayerApi. Each Player has a VRCPlayerApi Object, and your world fires the OnPlayerJoined / OnPlayerLeft events on any UdonBehaviours that listen for them when a player joins or leaves. This page includes info on using some general nodes. Si...
So what would the equallient to that graph be in UdonSharp?
I'm guessing this?
allPlayers looks like an uninitialized array?
ah
It both takes allPlayers as a parameter and returns it?
Keep in mind I haven't tested it. You are probably right and it's missing this:
allPlayers = new VRCPlayerApi[VRCPlayerApi.GetPlayerCount()];
How did you find out that there was an GetPlayerCount?
It's on the doc page you linked. But you can also just use intellisense to see what's in the namespace. Ahh, but not all of them are exposed, so need to reference the docs anyway, or try them out. Looking at the graph search can show you what's exposed as well.
Ah thank you, i had the top level of Player API selected and did not realize searching that page did not search the sub levels.
There is also this: https://udonsharp.docs.vrchat.com/vrchat-api
Just remembered it exists, maybe it might be helpful to you.
Why the heck is the bot telling me no spamming when I try to ask questions?
Are the some forbidden letters or something that makes a message count as spam?
Okay if i post code it tells me to not spam...
Ahh, yeah. It seems like you can't do that.
What works is uploading a file. So you could create a quick text document for it.
Right, well it wasn't important I managed to get it to work with some minor adjustments. Is there a way to persist data once all players leave an instance? Like for example a persistent leaderboard?
And is there something equallilent to UnityEvent where I can add an arbitrary amount of objects and methods in the inspector to call?
Both these things are not supported right now. There are some hacky solutions for persistency, or loading data externally, but a leader board is going to be rough because it requires you to send custom data from VRChat to some server, which is a big no no.
Do you know how things like storing player health and such is generally handled? I was thinking of having a name int dictionary but it seems like that's butt in the list if things that can be synced...
Persisting within an instance is one thing. Persisting across instances is a whole other can of worms.
Well I want data persistence within an insyance for this case.
Generally, each player is given an object that holds the health for them. For example, some kind of "station" thing where people click join so they get assigned to that object on it.
Ah i see. Butter If the player gets disconnected for 15 minutes and then rejoins vrchat, i think they will be kicked out of the worlds they were in and would lose their association? I guess if it's a5 minuter game it's irrelevant but if it's something longer it could be nice to be able to handle scenarios where a player leaves the instance against their will. Perhaps that's not generally expected even if it would feel good too know a good solution to it.
Yeah, you'd want to handle people leaving and clearing the object. Using syncing, you could create some kind of pool of save data that you write to when someone leaves. And when they rejoin that instance, you just check if their name is in one of the save slots. But all of that would require time and work.
Yeah i was hoping someone would say "we have this UdonSyncedPlayerMagic that does everything you want" but i guess it's not that fun. Is there some built in functionally for object pooling that works over network? If i for example want to fire bullets but may not want the overhead of instantiation of and destruction of bullet prefabs...
There is VRCObjectPool in the SDK that you could use. I personally don't think using it with bullets is a good idea though. Bullets should only be visual, so a local pool is enough for that.
If you want to have a pool assign objects to each player that joins, then you could look into Cyan's Object Pool on github.
Bullets should only be visual?
Generally, I'd say yes. Usually it's better to spawn them on each client individually.
You only want to send the actual hits.
Let's say i would have A fireball that moves slowly enough to be avoided then? If you're thinking of bullets as something that generally hit what's in it's path at fire time.
The VRCObjectPool won't sync the positions for you. It just enables an object for everyone when the owner spawns it. So unless you use VRCObjectSync, you will have to handle the position logic yourself anyway.
VRCObjectSync might honestly work for your use case, even if it's a bit overkill.
you need to take ownership of an object pool before trying to spawn
is that just set to local player?
yes
also it's totally unnecessary to have the interact call a sendcustomevent when it's just.. right there. You could just put everything in the interact directly
the main reason to do it separately would be if you want sendcustomnetworkevent, but that's not what you want in this case unless you wanted the master to handle spawning or you wanted everyone to spawn one thing each
i want everyone to see the same object.
There's a VRCPlayerApi.CombatSystem which can do health and such and even ragdolls your character when you reach 0 health although I'm not sure if the health value is synced, but I'm certain that setting the health to 0 tells the owner to die.
What you have to do in order to get it to work is
OnPlayerJoin => player.CombatSetup(); => set the CombatSetup death graphic to null (otherwise it's always on) => you're good to go. You can call GetHealth and SetHealth freely. There's also some other options like if players should respawn at all after dying, how long it takes to respawn and where they respawn at which can be updated at any time
but this approach is uncommom because for Udon, it's undocumented on how to get it to work and that it's also not supposed to work. I use it personally because I want to avoid object ownership and such and all of my players die in one shot anyways
Interesting, I saw some notes in the documentation about these stuff not working, but it actually does? That's confusing... https://docs.vrchat.com/docs/players
You can interact with Players in your world through the VRCPlayerApi. Each Player has a VRCPlayerApi Object, and your world fires the OnPlayerJoined / OnPlayerLeft events on any UdonBehaviours that listen for them when a player joins or leaves. This page includes info on using some general nodes. Si...
it does! A bit of self ads, but if other players are playing, you can see how it works in Murder Classic
pretty sure the combat system was depricated with sdk2 was it not?
technically, but it still works for Udon
oh cool
Anyone know of any tutorials for making a multiplayer game with combat that is synced? I get the feel like there is a lot of stuff that isn't really documented here and it would be nice to see how someone else had done stuff. Even a git repo for a basic game like this would be very nice to have something to study.
depends on what kind of combat
Players shooting fireballs at enemies and enemies slashing players. So i made this game a long time ago in unity and wanted to see if i could rebuild something like that in vr and with multiplayer https://play.unity.com/mg/other/dungeon-0-1
---Make sure you click the speaker icon and turn on sound when playing --
Release 13 Updated 2020-07-12. Please see https://connect.unity.com/p/dungeon-crawler-change-log-and-wish-list for complete release notes.
- Made some enemies walk around randomly in the dungeon instead of just standing still to make things feel more alive and less predi...
Hey quick question.
I got an object (A) with object sync.
Now I have other objects (B) with object sync that I, on runtime, assign as children to the first object.
The objects are moving out of sync now.
I am under the assumption that they all try to sync their position separately, mismatching their positions in the process.
Is there a way to stop the child objects (B) from syncing their own positions individually and just let the parent object (A) sync the position of the whole construct?
If your goal is to have objects (B) be parented to object (A), don't give them object sync and set them as children of object (A).
well, it's more of an easter basket kinda problem.
There's is an indefinite amount of (A)s that each can hold an indefinite amount of (B)s.
You can't tell ahead of time which instances of (B) (A) is going to get assigned.
Like a game of easter egg hunt.
(A) is the basket, (B) are the eggs.
Everyone participating can grab any egg they come across, and put it in their basket.
That's why I can't simply assign them as children of (A) from the beginning.
At this point I'm thinking of just faking the (B)s in (A) by just telling (A) what (B) it got and deactivating (B).
Then just tell (A) to instantiate a simplified copy of (B) over a networked Call.
It's just effort I was hoping to avoid...
Now would be the question, if it's possible to, on pickup of the decoy, to activate the original (B) and make the player Hold the original instead.
Current Code:
Uploading a file with the code will work.
I just wasn't sure if I might be doing Owner changes wrong...
This is where I set the RecentPlayer Variable
What are you expecting that code to do that it doesn't?
Aside from that, some things are not necessary like base.OnPickup or SetOwner on pickup. Last one, I think it does it for you. I also wouldn't set all children to the owner and be specific instead. These things are not a problem, but can be cut out imo.
well, I might have a solution.
While testing with two clients the pickups move wonkily for the none owner player.
It doesn't break anything, but it looks janky.
Just figured that my alternative route might not be as complicated as I thought.
It works fine for the owner, so I just have to deactivate the children for everyone except the owner and put in placeholders that only have a meshfilter and renderer that are identical to the originals
So once A is put into B, it should stop running its own sync code and just behave as a child of A, which would keep it where it was placed in the basket
yeah, but I noticed that the VRCObjectSync-Component can't be deactivated in the editor.
I haven't tried deactivating it at runtime with code though...
Also, I'd like to take the items back out again so I can't just remove the component, because I've heard you can't put it back on...
You can definitly disable components through code.
idk if the object sync component specifically doesnt let you though
and once you take the object out again you could just re-enable it
you'd have to make sure to sync that on / off sync state between clients though
yep, maybe I should just check if turning it off works in the game
I'm searching for a tutorial (or help of any kind) to make a script that attaches an object to all players on join, before and after any one person joins, visible by all and attached to all. Synced attached object for all players. Always on, no trigger or on/off. I've tried a couple scripts I've found, yet they only work for the local player or the first joiner depending on the script. I have a couple ideas on how to make it, though I'm too lost already and inexperienced with Udon. Anyone able to point me in the right direction? tyyy
you want an object pool when it comes to object ownership. I personally have CyanPlayerObjectPool come to mind I would use. Beyond initial setup, if you want the object to follow a player, you'd have the position not be Object synced if it's fixed and can't be removed. In such a scenario, you'd get tracking data of the Owner of the Object (which CyanPlayerObjectPool does automatically) and then do position and rotation of the object stuff in code.
Thanks for the starting point! I'll give it my best shot...
is it possible to RequestSerialization only for late joiners ?
When Im local testing, is my ID is the same with all clients? or its different?
What ID are you talking about? PlayerId is unique to every player joining that instance, even if you have the same name.
Yes Im talking about playerId, thank you 😄
Beware that if someone rejoins, their PlayerId will be different. It's just incremented for everyone new joining.
Yes it make sense, Im working on system that will hold player ID when they left the list will be updated
When Im doing Instantiate for game object I need to also sync it, correct?
You can't sync instantiated objects. You can only sync them from another object that was already there when you uploaded the scene.
I have this structure
Players_vitals (handling every player in the world, each player that join this gameObject have script that duplicate MDVS and rename it to player ID)
|
- MDVS (GameObject with class for storing and manipulating all the parameters)
So there is no option to get data from the new gameObjects?
If you have an udon script on that MDVS object, then you can call it and store data on it as usual. The only thing that won't work is sending networked events or having synced variables.
OnOwnershipTransferred doesn't seem to fire when the owner leaves the instance, is there a good means to catch this some other way?
I would try catching it with OnPlayerLeave and check if the player is the owner
It definitely did at some point in time. Wonder if the change was intentional or is a bug.
OnOwnershipTransferred seems to work as expected for me when the player who is the Owner of any given object is not the instance master
So the behavior seems to be that when the current master leaves and ownership transfers to the new master it will not trigger an OnOwnershipTransferred event
I noticed that too very recently. It's really confusing because you'd expect ANY ownership transfer to trigger that method. Initially, I was using it to clean up an object, which obviously didn't go well resulting in some rare errors.
I had to switch to OnPlayerLeft, that worked for me.
Related question: If I call GetOwner in OnPlayerLeft, will I get the previous or the new owner?
Yeah, that's what I noticed. It feels like a bug IMO, as it should still be an ownership transfer.
I THINK it fires after the player's removed and ownership shuffles around, so new owner.
Hmm, but then you can't check if the owner of that object just left which sucks. Would be nice if OnOwnershipTransferred would cover that use case. I think that's why I had to check against a saved playerId in my project.
Didn't test GetOwner in OnPlayerLeft explicitly but the results I was getting would suggest it was giving the new owner
Using a delayed custom event is the way to avoid requesting serialization too often, right?
if you want to build a reliable clock that happens less often than update, yes
Hi guys, how do I make an avatar always pick up a weapon from the hilt?
idk search it up on youtube\
You can define an 'exact grip' transform to customize the held position of a pickup.
https://docs.vrchat.com/docs/vrc_pickup
What's the easiest way to synchronise the enabled state of gameobjects for late joiners?
Object Pool
This isn't the spawning/deletion of objects so I'm not sure that would be suitable?
Object pool manages only active state of objects in its pool. It doesn't actually instantiate/destroy an object
Oh, hmm ok so I was thinking of something else.
So it sounds like it's designed for spawning. Will it work just to keep objects enabled/disabled state synced if I'm not using any spawning functionality? (e.g. if I'm just toggling the objects on/off via another script).
If you already have another script then you could have a synced variable to store active state of the object. Then set object active state on OnDeserialization event
That wouldn't quite fit into what I'm trying to do without making it a lot more messy. But yeah, does the object pool keep the object's enabled/disabled state synced regardess of how they are toggled?
I'm not sure about this. Better use it in intended way
Keep in mind that an object pool is made to have a bunch of objects of the same type that you can have a lot of. Is that what you want?
If you want to have a on/off toggle for a lot of specific objects, like a poster, or chunks of your map, then you can look into synced toggles instead. There are a few videos like this out there: https://www.youtube.com/watch?v=K3kAGQvrH9A
Synced toggles are back! Now we've got them set up using a Synced Bool, which is a way more efficient way then the Send Custom Network Event we had previously, as well as making full use of Ownership transfer and Manual sync!
All assets are available on my Patreon if you'd like to have access to anything I made during or before the video.
Full ...
Oh, and I just remembered. There are examples in the SDK if you search for "toggle", which can be used.
This is essentially what I need, but the reason it's more complicated is because it's 5 buttons which all toggle something different BUT only one of them can be enabled at any one time. The latter is what makes this fiddly.
A simple way to do that is to use an integer instead of a bool for State. So you'd sync the index of an array and disable all the objects in it, then only enable the one you synced.
That's easy enough for that stage, but what would be the easiest way to link the interaction back? As Interact won't really work anymore as it's 5 buttons, which would all need to be linked back to this script via another bunch of scripts I'd guess?
Instead of Interact, you'd have a custom event. Then make a separate script that you can attach to each button with a public integer and a reference to the main script. You can use that public integer to set the State and then call the custom event to update it for everyone.
So one main script with the sync from the video but with integer instead of bool. And then one other script that can be attached to each button. No need to make 5 scripts each.
Yeah that all makes sense. That was what I originally thought I'd have to do but hoped there'd be some cleaner, somewhat unified way to do it without multiple scripts. Ah well, thanks for confirming.
Yeah, making two scripts the way I described is as clean as you can get. I guess you could have one script that you attach to every button, but then you'd need to reference all 5 on each of the 5 instances to disable them which is just more work and not very clean.
Question, if i want any pick up to be seen for other player i probably need networking sync or something, does this video helps? https://www.youtube.com/watch?v=MOw8a5RmMjU
Networking can be trick to understand, I hope this video can help people understand some of the basics.
public GameObject superHotMirror;
[UdonSynced] private bool mirrorIsOn;
public override void Interact()
{
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "MirrorStuff");
}
public void...
that's talking more about how to make your own scripts with networking. If you just need a synced pickup, all you need is to add vrcobjectsync
If you want a pickup to be synced between multiple players, VRChat has a handy component for that: VRCObjectSync https://docs.vrchat.com/docs/udon-networking#example-the-simplest-networked-object
The three main concepts used for networking in Udon are Variables, Events and Ownership. Variables are containers for values - like a number, a set of colors or a 3D position.Events are things that happen at a moment in time.Ownership is the system that decides which user can update a variable, whic...
now my main question is, i want person B to see person A holding an object.. how do i do that?
add vrcobjectsync
thats all?
yes
and for object thats is spawned?
depends how it's spawned. You cannot sync objects that are instantiated, but you can sync objects that are simply enabled from a pool
hmm
is there any way i can check my object can be seen without the need of a second player to test?
you can launch multiple test clients yourself
Oh
yeah just realise thanks.
Does anyone know why continuous physics collision would result in what looks like only one networked positioned update per second?
Not sure why it would affect networking, maybe it's sending too much data and causing vrchat to throttle it?
can anyone help with somthing im trying to code ??
im trying to make it when you press a button it changes the skybox and the lighting of the world how can i do that
Is there a way to sync animations with the networking?
as i'm working on a show that involves animations.
and i need them to be synced with everyone (even late-joiners)
Hi
Do you still need help?
i do have a script from github. but i still want to make sure.
@amber ice the script from github should be fine. If it causes you any performance trouble I can give you my "elastic sync" that I'm building out now. I'd have to write in some clamp method so it doesn't spam and use up to many resources from the computer.
lemme link it in dms btw
Oh. I cant send dms.
Just link it here. Why be all secrete with dms? @amber ice
Was this the system clock / GMT one?
Yeah, I use that one. It works well for the most part, until people come along with PCs that have out of sync clocks 😉
exactly
The spamming bot hates me so resend as an image. I'm still very new to Networking & I'm trying to build a card game but wondering how I should network it. I was thinking of using just SendCustomNetworkEvent and treating the Owner as a server and all other players as clients that track an event log. Opinions / "gotchas" you can see with something like this?
^ note I don't want to resend all events to late joiners but instead just events to sync the current game state 🤔
Sorry, I'm not sure if I understood you correctly, since your approach seems unusual for udon. It sounds like you are trying to send data using networked events? Udon doesn't really support that. You have to rely on synced variables to transport data like that.
Oh I think I understand, SendCusomtNetworkEvent second param is the eventName, misread it. I'll look into synced variables thank you 🙂
Make sure to check out the docs: https://docs.vrchat.com/docs/udon-networking#variables
They have some videos and examples to download as well.
And yeah, the approach I usually use is to save state in the manually synced variable, and then react to it changing to adjust visuals, etc.
Depends on the specific rules of your card game though.
So in total it's going to be about 1100 shared variables, would this be too much to handle? From the tips on the docs, I can send about 11kb per second so should be fine as not everything will be updated at once. Because of the "ownership de-sync issue"
Tested with the VRC Quick Launcher with two users and a button that randomly refreshes 144 cards, unless someone tells me there is going to be an issue this seems viable? Each card has a Sync() method that performs the RequestSerialization() call once ready and is set to Manual Sync Mode. The game itself is never going to perform 144 requests at once so should be fine?
Maybe it's better to have a single script that calls a unique requestserialization of an synced int array for all your cards.
I don't think that would be a problem. As you said, if each card syncs individually, it's really not that much data at each point at time. And since it's a card game, I'd assume the syncing is pretty infrequent.
Of course, there are more efficient way to do things. For example, I don't think you need to sync stuff like attack and defense, or even the state of the cards. You can just sync the act of placing the card on the field using the id, and the on placing the card, calculate the states locally.
Does the VRC Quick Launcher use the normal VRC Networking servers? Or do I need to stress test in game?
Local tests use normal servers, the only local part about it is where the world files come from. That being said, VRC Quick launcher can launch either normal or local test so even if it was an issue, quick launcher has nothing to do with it.
Can anyone recommend a Video tutorial or similar explaining how I can spawn a pickup prefab and have the spawning and positions synced for everyone?
Basically I just need a button that spawns a prefab, which is just a pickup with objectsync on it.
Synced Objects "spawning" at runtime must be done with VRC Object Pool. You can't use Unity's Instantiate(). There are a few tutorials on YouTube about the VRC Object Pool
So there's no way to actually create a new object and have it properly networked synced with vrcobjectsync? They all have to exist already?
Yep
Are there any known issues of OnDeserialization() not running for late joiners? My world relies on manual synced objects and now breaks for late joiners. OnDeserialization() not running seems to be the cause of it. It runs properly while in the world, just not after joining. It used to work a few months ago and the docs say it should run. Am I misunderstanding something?
Are you saying that it isn't running only because you don't see the effect? I suggest any time you really want to know stuff is to add Debug.Log statements. During development I place them in every method so I can trace them in the logs.
What I don't know is when the OnDeserialization() callback occurs. I assume Awake and Start must be called first. If Start sets the value an UdonSynced property I am assuming it is overwritten by the deserialization as it syncs with the world owner. I wish more of this "peeking under the hood" stuff was documented with examples.
Yes, I checked with Debug.Log. Start() gets called but no sign of OnDeserialization(). I made a new project with a simple script to test, toggling an object, same result with late joiners, they don't toggle the object and don't run the OnDeserialization() method. It used to work correctly a year ago, only recently I noticed it doesn't anymore. Either I am doing something wrong or the behavior changed without the docs getting updated.
To add to this: before Start() wasn't called when spawned from a VRC Object pool. This seems to work fine now. And variables seem to be already synced before Start().
Because Start() didn't work back then I put my initialization logic into a one time method firing once at OnDeserialization(), I can fix it by moving it to Start(), although still, the documentation says it should fire once for late joiners, but doesn't.
And another add: objects not from a VRC Object pool call Start() without synced data, so can't even workaround it by updating/initializing in Start() because data is not correct yet. No OnDeserialization() called.
Ok I checked and I too do not see the OnDeserialization call. It seems reasonable to believe that this is because my client would not have called it. I was the world owner in this case so only other player's would have it called. You may need to have to set something in the world that indicates it was called and/or get a friend to send them their copy of the log.
Yes, my log is from a second instance of the client. The object owner doesn't call it (and I don't need it, as the owner sets the variables), just late joiners are the problem.
There are some videos that demonstrate that it works. I'd be surprised if you more or less clone that as an example that it wouldn't work for you as well.
Meanwhile... is there a way to detect that a playing sound file has ended?
Ok I have an idea. I just watched another video which may have provided a clue. Are you certain you have set the owner of the game object? I know that I didn't figuring that the first person in was set automatically.
Yes, I checked the owner. The owner changes the variable value. OnDeserialization() gets called correctly for non owners. Just late joiners never call it, even though documentation says it should. https://docs.vrchat.com/docs/udon-networking#bonus-concept-late-joiners
📘OverviewMultiplayer experiences are the heart of VRChat, so creating a world that reacts to players and synchronizes the data between them is key.This page introduces the concepts that power our networking system. Once you've understood the basics, you can dig into specifics:Network ComponentsNetw...
Hah, wanted to create a test case for the canny, but this one worked now. I will have to look into this why that one syncs now
Does this example also have the manual synced Udon behaviors within an Object Pool?
No, this is without the object pool, I have two test cases, one with object pool, one without. Before both wouldn't do it. This one (simplified a bit more for the canny) is working correct now. Still trying to figure out why/what changed.
I don't think its reported or documented anywhere specifically but as far as I know OnDeserialization will fail for late joiners if the object is disabled by default
The variables still sync properly though so you should be able to use Start() to read back the variables
The test object was enabled by default, so that can't be it. But good to know.
Which test object?
The object that has the udonbehavior on it
Was that object part of an object pool though?
Not this time, just an object in the scene, no spawning. Though my previous one also was just like this and didn't work. Still debugging it.
Are you using Udon Graph or Udon Sharp?
UdonSharp
Odd, similar scripts, one calls OnDeserialization() on join, the other one doesn't.
This one works, it calls Ondeserialization() when joining:
And this one doesn't
both work fine for players in the world and toggle their object (in different ways), but I don't understand why one calls OnDeserialization() and the other one doesn't
You aren't calling RequestSerialization() anywhere in the second script
it doesn't need to, it just sends a network request to toggle it, so each client toggles it on their own. the deserialization is only for late joiners (which has worked in the past)
it's also just a small example script, my actual problem was objects that were placed by players in the world (spawned from a object pool) would not sync their location for late joiners. also because no OnDeserialization()
but easier to test with simpler scripts
So for the second script, a late joiner should call OnDeserialization() when joining (as it does for the first script) and sync up the current state of it
OnDeserialization() wont happen unless you have called RequestSerialization() at least once
Not based on the documentation, which says it is called once you join the world
(and has done so, the world that broke is over a year old and has worked flawlessly until recently)
When someone joins your world, the OnDeserialization event will fire for every Networked Object in the world with the latest data, and they'll run whatever logic you have in place to update things based on that data.
So based on this, I would assume it should callOnDeserialization()when entering the world
(which it used to)
I thought maybe it detects if the RequestSerialization() method is used in behavior and then does it, otherwise it doesn't count as a networked object
but seemed to make no difference adding a bogus RequestSerialization() call in there
My spawned objects from the pool do call RequestSerialization() though and don't sync on late joiners, so that can't be it
Without calling RequestSerialization() there will be no variable data that can be sent over the network
If you set a synced int to 10 and RequestSerialization then update the int to 20 and don't RequestSerialization again the serialized value that gets networked is still going to be 10
yes, but late joiners should get the value
Yes and they would receive the value 10
in the past, they would have received 20
I have used this script before and it synced properly without calling RequestSerialization
I'll quickly do a sanity test, if that's the case for the button now
It would work if you didn't have it set to manual sync mode
In that case RequestSerialization isn't used
I'm not sure how the internals work, I assume RequestSerialization is only needed if I want to spread a new value. if a new client joins it gets the current value. the 10 should be no longer anywhere stored, unless vrchat has a serialization cache on the master/owner
hah, ok so. seems to be the case now. A year ago I didn't need to call RequestSerialization, it would just get the latest data on join. Now I HAVE to do it
a little bit closer to the solution now
It probably does based on a super annoying bug I had to fix recently. I used IsOwner for RequestSerialization when a player pool object got removed and reset some synced values. Late joiners would receive the old ones still, probably because RequestSerialization was never executed.
Well, in that case it was also disabling objects, so I'm guessing that plays a role in that too.
There are definitely some undocumented quirks in there
Especially with an object pool it seems, calling RequestSerialization placing an object (from a pool), it still does not call OnDeserialization for late joiners.
BUT it has synced values on Start(), so there's at least that.
Maybe a special case for object pool spawned objects
RequestSerialization() seems to fail if you try to call it OnEnable() / Start() when enabling a GameObject and OnDeserialization() will also fail to run when a GameObject first gets enabled
this also fixed another (test) script for me now, just calling RequestSerialization on Start() once (variable sets at start randomly, never changes again). Might be part of their "making udon faster" updates, not syncing variables that never got serialized. Definitely not backwards compatible though
though the missing OnDeserialization might actually be a bug. I remember I wanted to sync up using Start() but Start() was never called
and OnDeserialization worked fine
Made two cannies for my problems yesterday, just in case these are actual bugs:
https://feedback.vrchat.com/vrchat-udon-closed-alpha-bugs/p/1287-ondeserialization-no-longer-being-called-on-manual-synced-objects-unless-re
https://feedback.vrchat.com/vrchat-udon-closed-alpha-bugs/p/1287-ondeserialization-no-longer-called-for-late-joiners-for-manual-synced-objec
for note
Ah, yeah I did not consider the "disabled" part. My world only uses object pools, so I thought it might be related to that. Haven't tested a disabled case without pool
does Networking.SetOwner change the owner instantly, so if you set the owner of something to the local player and then later on in the same method have a check to see the local player is the owner, should it pass?
Because it doesnt seem to be. Or maybe I have something else weird going on.
https://docs.vrchat.com/docs/udon-networking#requesting-ownership-advanced
I think* it's set once you receive OnOwnershipTransferred
Hey, quick question if I call RequestSerialization() on two different networked gameObjects, are the requests handled in order for other players? e.g:
Local
ObjectA.RequestSerialization()@ 0.01msObjectB.RequestSerialization()@ 0.02ms
Remote
ObjectA.OnDeserialization()ObjectB.OnDeserialization()
Or could Remote receive them in any order?
From my local testing with VRC Quick Launcher it appears to be sequential.
Does vrchat send the entire networked object variables or just the ones with a changed value? e.g:
some networked object:
- byteA = 1
- byteB = 1
- byteC = 2 // just changed, RequestSerialization()
Is that one byte of data sent over the network or three?
When a serialization happens, all networked variables of the UdonBehaviour (or even the whole object? not sure right now) are serialized.
Meaning that this would be 3 bytes.
You should see it in build and test when using two clients, won't work in editor though
what could be preventing this from working?
public override void OnPickup(){ Networking.SetOwner(Networking.LocalPlayer, gameObject); playerApi = Networking.LocalPlayer; debounce = true; }
public override bool OnOwnershipRequest(VRCPlayerApi requester, VRCPlayerApi newOwner){ return true; }
Thx
well it's not really doing anything... if you have vrcpickup and vrcobjectsync, it'll already take ownership automatically on pickup. What do you expect this to do?
also, implementing OnOwnershipRequest and then always returning true is not recommended because OnOwnershipRequest changes ownership transfers to require confirmation from the previous owner, which increases latency. If you just don't include it, all transfers will go through without any need for confirmation
The revolver itself has manual variable sync which prevents me from using object sync, so I made my own object sync script that looks like this:
and this is set to continuous
basically the owner should update everyone else
but if it has manual then it would also conflict with this being continuous
yeah that's why I have a seprate sync script on a empty
so then why can't you use objectsync?
so the object with the pickup has the manual sync and the separate sync script is continuous?
YES :D
you have it backwards, typically you have the pickup use objectsync and then the separate sync script is manual
would the order really matter? Considering most actions are done ON the revolver root I wanted to sync all those variables manually, and just the transformation is continuous. Just wondering
well the order matters because then you can have objectsync instead of trying to make your own sync script, which is a pretty big task that I would only recommend if you actually needit. This scenario does not need it
ahh alright thanks . . . time for a mild rewrite 🥲 thx for the help
good to know
is there anything that would cause the rotation of a synced object to not be exactly the same between clients?
I have a stationary object on a table with an object sync on it. On interact the person takes ownership of it, and sets its rotation to a specific direction, and then after a delay everyone else reads the rotation of that object to preform some math (to calculate wat its pointing at)
Now sometimes the owner sees a few degrees different result to everyone else and i have no idea why.
does it have something to do with the movement interpolation or something?
If i can't find why I'll just stop using the object sync script and just manually sync the rotation angle.
I wouldn't be surprised if they quantize rotations
You could try call FlagDiscontinuity on the Object Sync which could make it update properly, though you are probably better off using manual sync for anything you need to be precise.
Yea i already have a FlagDiscontinuity call after it sets the rotation initially. It helps make it look better but still has the accuracy error sometimes.
As impiaaa said, might just be easier to manually sync the rotation to be more exact
Yeah object sync is not designed to be precise
question about Deserialization. Does OnDeserialization happen for every script everywhere, all at once? or do I have the ability to control what type of information comes down and where?
For example: I have an Array that contains a lot of information. I want to send it to another client but only that specific client. Can I isolate the sending of information to only client A to client B? Or do I have to send everything to everyone and only client B accepts the information and every other client ignores it.
[2:21 PM]
and does happen accross different scripts at different times?
Synced variables get broadcasted to everyone. You can't target a specific client.
cool thx
you could have a set of duplicate variables that are only applied to a target player:
`private Vector3 loc;
[UdonSynced]private Vector3 syncedLoc;
[UdonSynced]private int targetPlrID;
public override void OnDeserialization(){
if(VRCPlayerApi.GetPlayerId(Networking.LocalPlayer)) == targetPlrID){
loc = syncedLoc;
}
}`
WARNING with the method above cheaters will still be able to intercept everything :/
Question about networking data: (context Udon Graph editor)
So the data that is sent out across the network, do I have to set that data (synced variables) on the OnPreSerialization loop? Can I just have synced variables and call request serialization for that script?
this is what I mean: do i need to do wonky shit like this?
what are you trying to do?
ok, so from a highlevel perspective:
I'm trying to have my NPC's be able to handle Dynamic Ownership transfers to other users so I can run their code locally on clients machines on a case by case basis. This will allow me higher fidelity interactions between User and NPC while having it synced for remote players (give 1-2 seconds delay for remote players). This is very important if I want the NPC to look the selected player in the eyes, hand them a drink, birds land on their finger, and so forth.
The issue im running into: I'm trying to set up a Ownership module that all other scripts will reference when it comes to any branch statements where I need to separate code that runs only for the owner of the object and non-owners of the object. This Ownership module will also contain synced information about the previous owner of the object incase I have the ownership of my NPCs have to jump back to the previous owner. This is important for late joiners.
I've ran into an issue with the variable heap limit (512 is limit) if I constantly do a gameobject.getowner -> vrcplayerAPI.
My idea is to extract the Owner Players ID and store it as an int. This would allow me to sync the data.
I'm doing it this way because my previous method of ownership syncing is still causing issues and i'm trying to centralize where in my code it handels it all.
Having get.gameobject -> get.vrcplayerapi -> store vrcplayerAPI as a variable on start does not allow late joiners to sync previous owners.
This script will be one of many scripts in a state machine style behavior tree.
I'm very new when it comes to programming. (only started back in December) and I only know how to work with the udon Graph because in my artist brain that makes the most sense.
@weak mirage if you want to see what im trying to do. here is my concept test world. Everything in my system works wonderfully until the NPC's try to dynamically switch ownership. Then they start to get desynced amongst players: https://vrchat.com/home/world/wrld_74d85604-b4b0-4c53-a5f3-c97aadbc41fd
so like, you're trying to separate code depending if someone's the owner or not? in that case you can just use if (Networking.GetOwner(gameObject) == Networking.LocalPlayer) but the graph equivalent?
yes, but it will display the result as a public variable so all other scripts will get that variable and use it in their code. Therefore if there is a problem with the syncing and ownership. I have ONE script to look at instead of possible hundreds.
and making sure that information is consistent across all machines at all times on manual sync is where i'm getting all wonky and flustered lol.
just make a public GameObject variable and drag that object in there, and then use Networking.GetOwner
OnPreSerialization is an event that is invoked immediately, before the "networked data" of the UdonBehaviour is serialized, such that it can be sent to other players over the network.
You can set the data in there, you can set the data before it. It doesnt matter when you set the data. The data that is set after "OnPreSerialization" exits is the data that will be serialized.
For manual sync:
RequestSerialization => OnPreSerialization => OnPostSerialization => OnDeserialization
(not immediate i.e. some (real)time might pass between these)
However be aware that OnPre/PostSerialization are only called for the current network owner of the GameObject the UdonBehaviour is on, and OnDeserialization is not called for the current owner.
And RequestSerialization may only be called by the current owner.
I'm trying to wrap my head around network basics to sync a gun and bottles I made a few years ago. The bottles can be broken via collision, or the gun can call the break function after a raycast. If I understand the answer to another recent question, one script (e.g., VRCPickup) suffices to assign ownership for other scripts on an object. If this is correct, does ownership from one script apply to other objects in the hierarchy (at least children)? Also, ownership of a held bottle is clear, but shooting a bottle won't trigger an OnPickup function. Is it necessary to use the gun script to set the bottle owner after a raycast hit?
Ownership only applies to the current Game Object and won't affect children objects. For ownership you could set the owner after a raycast hit but it isn't necessarily needed as you can use SendCustomNetworkEvent to send events from any client to the owner of the object, but in that case you would probably need local and remote handling for bottles being hit and breaking otherwise the local player would notice a delay as they would have to wait for the owner to relay back that it had been hit.
Thanks! I'm experiencing intermittent delays after the shot, so I'll try to set it up both local and remote. I don't think the owner can be excluded from the network event, though, so I'll probably need to come up with a workaround to prevent them from running the function twice (maybe a special network version that filters out the owner?).
Taking ownership rather than using a networked event for your use-case would probably be better since you may only need some logic for the local player that is shooting the bottle and maybe a manual synced variable, though you could do both ownership transfer and networked events, all should work fine.
I assigned ownership of the bottle from the gun script. Doing that alone didn't help with the delays, so I decided to try your local/remote event suggestion. Now, the gun script directly calls the break function for the owner and sends a network event for a second function. The second function just calls the break function for anyone who isn't the bottle's owner. Despite the extra steps, everything now appears to be smooth and fast for both the owner and the networked instance.
So I'm wanting to create a throttle lever like control in my world for a control panel.
In terms of operation, I'm thinking I'll have an invisible grabbable block at the handle of the lever that will act like a short piece of string to drag the lever its self that will be pinned in place and can only rotate a small amount on one axis.
I'm then thinking VRCObjectSync on the lever would let me sync the basic rotation of the lever automatically, and I can then perform some additional smoothing if needs be on the value of the control possibly.
Let's see if I'm understanding the logic right.
I've got a turned based game situation. With Vehicles and command Markers.
The markers don't ever need to be interacted by more than one player so I don't need to network them at all.
When placed the Marker sends a event to the Vehicle which gives it target position data etc. The Vehicle replicates this data to all clients and then each client simulates it moving to the target position.
Should I set the vehicle to manual sync as I only have to send target location data once a turn?
This event is successfully being called by one client, but the bool movementActive is not updating to the other clients. Did I miss something.
Only one client is calling it at a time so they shouldn't be ownership fighting.
Hey I've created a simple logic for a private room lock that will unlock the door when a player inside the trigger respawns or exits the room. However, when I test with 2 clients and I exit the game on one client, the room remains locked.
Can someone help me create an udon graph or script to check if there are no valid players in a trigger area so that I can then trigger the doors to unlock if someone crashes or logs off or leaves the world in that room? Thanks!!
Is this a ban speedrun or smthn?
I'd like to remind you that using a custom SDK is against VRC ToS and is a one way to get banned :)
i did not know that
I'd suggest doing a lil reading
https://hello.vrchat.com/legal
You accepted it, would be good to know what you accepted :p
and the SDK one, just in case 
https://hello.vrchat.com/legal/sdk
question is there a way to initialize a object to all world members?
currently I am using Object.Initialize but this is only local any scripts that one there aren't sync at all?
even if I initialize it for all players at the exact time, the scripts aren't getting synced
(using udonsharp)
Instantiated object doesn't have ability to sync. Use object pool to control and sync object active state instead.
I am working with a game that idk how many players will be playing
so it need to be scaleable (preferably) unlimited
^ also makes world download size smaller if I dont initialize all object in unity before uploading
Again, instantiated object doesn't have ability to sync. So that's totally out of question. And object data in a scene take only a few kb per object, and even less if you use prefab. That's very neglectable size.
I doubt that will get accepted, but feel free to do so.
Hi there. I forgot if running request serialization on a parent will affect child objects that have their own manual sync scripts
it will not, objects are independent
🙏
... when you have been troubleshooting for hours and it turn out you had the wrong variable with Sync ticked
Back on my subject of 2d ago~
So there is no way to initialize a object network wise? Only local (causing even with the same name / same place in hierarchy not to be sync with any type of udon syncing)
Since gonna throw out a case scenario:
Like I am building a card game~ a card deck exists of 52 cards~
meaning that I have to make my card deck 2-4x the size to get all the cards the game requires (even still limited to the amount of card decks I put in)
having to copy over groups of card decks instead of able to spawn in a entire deck as prefab and directly being synced to all players (pickup able or interactable -> triggers of udon scripts)
What is the best way of doing this since making X *f 52 cards per decks 'pre-spawned' in kinda unnecessary?
be able to spawn in network wise a object or object group (all cards as example) when I really required it
first of all, the term you're looking for is Instantiate, not initialize
Second, use an object pool. You can either use the built in vrcobjectpool or make your own.
but will these object be 'synced' on instantiate?
since udon script aren't synced if you instantiate a object with a script on it
an object pool does not instantiate, it simply enables objects that have always been there
^ yeah I am trying to not use that
since I might require 52 cards at max
or maybe 500 cards
I understand what you want
you need to use an object pool
synced instantiation is not available
okay! Guess I got to use the 'dirty way' of using it then for now
since instantiate 500 cards from the start~ can become performance heavy + download size increase
But thank you for letting me know
download size shouldn't be affected because additional gameobjects are basically nothing. Assets themselves such as textures should always be there
frame rate performance should be unaffected. Startup performance may be worse if you have an udonbehaviour with lots of code on every card.
fair yeah download shouldnt be effected as much~ I just like scalability when I make stuff so don't have to worry about any 'edge case scenario's of running out of cards' in my case
I agree that you should just use object pool.
But if you insist...
Make each deck a deck controller. This controller has a list of objects and a list of translations and a list of rotations. The deck controllers are manual synced.
When activated each deck spawns it's list of cards. Each card is unsynced and has it's own little script that says "when dropped, tell the controller my transform"
Then the controller syncs the data, and all of its networked versions "on deserialize, update all the card locations"
I don't think this is actually a good idea though.
Or a better way. Just have a large object pool of blank cards. Then update their texture to be the next card's one as they are drawn. Then send them back to the pool when discarded.
Avoid using any cards with discard pile mechanics and you're golden.
That's by far the most efficient option.
yeah since cards are pick up having to make my own sync on pickup might not be the smartest.
Currently I will just make a object pool with 52 cards (all defined)
and in unity I just copy them over with names as 'Deck_1' and just use a loop to active the next card deck when the first runs out and continue that until there isn't any more card decks
Sorry n00b question, for: "200 bytes per serialization". Does this mean 200 bytes udon synced per script or all scripts?
For context my world idea requires continuous syncing of: ( 1 Vector3 + 1 Quaternion + 2 floats ) * 5 * number of players
All script. Including VRCObjectSync
Ahh okey that's annoying then 😛 but thank you for clarifying
I misread your question. Per serialization means per request. So it's limited the size to one script. But you still have total bandwidth sharing with all script to be aware of.
Oh okey, so I can have 200B per script for continuous syncing, i just need to be careful of the 11kb per second?
Yes. I'm still not sure how often continuous syncing sent off data though.
Nice, I'll write a quick continuous script later and see how it scales for this 🙂
V = 12B // vector 3
Q = 16B // quaternion
F = 3B // float
(V + Q + F + F) * 5 * 16 = 2.7kB
That seems doable then (unless my data sizes are wrong lol)
floats are four bytes, not three
keep in mind that the maximum number of people that can be in an instance is x2 the limit you set in the SDK upload screen + 2
because world creator and instance creator can always join regardless
Anyone know what this means??
This message appears every time I want to test build my world
Yes but where is that located??
the console tab, bottom left
Ok thank you!! I'm not home rn I'll check it out later when I'm on my pc
What would be the best way to change a transform parent and have it synced to all user & late joiners?
Currently thinking of making a script for each obj and store its current parent~
But I got todo this from 50 to 300 objects~
that might not work~ since the parent that I am setting it to only exist locally since there no way to init a gameobject to all users and have it synced~
or I need to init all the gameobject in unity before uploading~
trying to make it scaleable so idk how much the max can be
the path stays the same~ as in /player/p_1/cards/stack_1
but locally init
if you need to put synced things on an object, then it can't be instantiated. But if you don't explicitly need the syncing on those objects, then you could put the syncing somewhere else and have the instantiation managed by a synced object
syncing a setparent operation is a bit complex because you can't sync transforms. If you could, it would be as easy as syncing the current parent and then when you receive ondeserialization you just set the object to that parent.
But since you can't sync transforms, you'll instead have to build an array of possible transforms that it could be a child of, and then sync an int that specifies where it is in the array.
The size of that array will depend on how many possibilities you need, like if this can just be arbitrarily parented anywhere in the scene, then you need every object in the scene in that array. But if it's only a few different possibilities, you only need that array to be a few long. If it's just switching between two different parents, you don't even need an array at all, it could just be a bool and 2 parents that it switches back and forth on.
okay thanks for clearing this up for me that only thing init in the game engine (before uploading) can be synced.
Will me might see in the support in the future something that would be able todo it?
I was thinking of writing my own syncing script for gameobject but this ofc can cause being limited by amount of bytes we can send per update (total)
I still say you should have a bunch of bank cards that update their texture/text only when pulled from the deck. That way you only need a object per card that would be in hand/play at once, rather than everycard.
the card amount is depending on how many people are playing and how long the game last
so can be 20 cards for a round
or 140 cards
and all 140 can be in the game at the same time
question is there a way to test thing regarding network easy~
since trying it using unity test build, I will have 2x the same account name?
Or is there a way what makes it 'different' for the session~?
currently storing the displayname of the player in a string list (since a vrcplayerapi list isn't possible)
If you simply need something to identify a "player" use their session id "VRCPlayerApi.playerId".
This is an idea starting at 0 incrementing for every player that joins the instance. If you rejoin, you get a new id.
You can then store that in an int[] and get a player by id via the method (which name I forgot)
I know the function but yeah
And no. If you need to be absolutely certain that some networking thing is working then upload the world and test it with two (or more) accounts.
Thats the safest way. It sucks, but it is what it is.
but yeah need to make sure for they can rejoin if they would crash
only local testing with displayname is just not possible (without 2 accounts)
but someone told me I could use the quick launcher in the vcc to use profiles
There were requests about exposing a player GUID in Udon, however the concern was that people would maliciously target specific players with certain functionality.
guid is not needed since wouldn't fix the test button in unity since still launch the same aaccount twice. Also don't need udon to expose that, I could already get that without needing udon but yeah that ouside
Two things:
You can definitely have a VRCPlayerApi array. The only restriction is that this can't be synced - in that case, you should use an int[] of playerid's as @lone zealot suggested. These two options should cover most use cases.
But, if there is a situation where you absolutely do need to launch multiple different accounts into the same local test, you can use the VRC Quick Launcher. It's available in the creator companion tools section. You can set up multiple "profiles" which simply correspond to remembered login details. So profile 0 is your default, already logged in as you. You can set another to profile 1, and then you can log in as a different account. And those two login profiles will be remembered independently. You can then use VRC Quick launcher's local option to launch into a local test build.
yeah I got told about the quick launcher
after posting my message
and yes I meant having it synced playerapi list, if I say correctly this still wouldn't work since the playerapi in the list becomes null if I am not mistaking if the player leaves.
that's correct, but you should be using extensive validity checks when dealing with players in general because they could become invalid at any time
So only storing the player guid in a list would be optional
no, the GUID is not necessary. PlayerID is sufficient
if the player leaves, their playerapi becomes invalid, and you simply check for that and stop doing things with them, done
playerid is network relate so if they leave it won't work , so if they crash they can't join back in since new playerid right?
if your goal is to recover from leaving and coming back, then yes you'll need to use player displayname, that's an important detail
that's why I am using displayname since there is less chance anyone would change there name then crashing
ok, then keep doing that
quick launcher is helpfully
Well if a player crashes or rejoins and you want to restore their data, then playerID doesnt work.
The only currently "stable" (i.e. same after rejoin) metric is their displayname. Which isnt great.
A GUID would solve that, but as I said it has the issue of targeting.
A potential solution would be a session/temporary GUID which changes weekly, daily or every session.
You could still run into issues then, but those would be rare I suppose.
it depends entirely on the use case. And if the use case was clearly stated from the beginning I would not have said that
could use a third party webserver and use custom api code to collect the guid
but yeah latency and isn't worth it
maybe don't do that
I won't don't worry
As far as I know there also isnt a way to do that.
There is no point in the ToS that would disallow you from doing that in general. (that I know of)
You just cant use it maliciously or to collect user data, or in any other way harm, damage or violate any user or VRChat.
But as I said, you wouldnt even be able to get a players displayname out of VRChat. There is measures in place to avoid that.
I am not gonna agree or deny, I will say it is against tos 
Me will just write a feature request for the SDK to able to also use profiles within unity (easier to reload and test)
So I usually just call OnDeserialization to apply the new synced state locally. But with the new parameter it doesn't really work anymore, so I have to do this:
My problem is that the timing doesn't seem to be the same local vs remote.
Is there a better way I can do this?
what do you mean by the timing isn't the same?
if you're referring to the sendtime and receivetime being different between two different clients, it's because they're both relative to each player's individual Time.RealTimeSinceStartup
so if you're going to sync anything, you need to sync relative numbers, not absolute
this documentation has more details: https://docs.vrchat.com/docs/network-components#deserializationresult
This doc covers Networking Components, Properties and Events you can use in your Udon Programs.Networking PropertiesSpecial properties you can get from Networking:IsClogged - returns true if there is too much data trying to get out. You can use this to hold off some operations or adjust your logic.I...
I'm talking about the difference between using Time.sinceLevelLoad manually and when network traffic is sent.
This is what the above code causes:
what does syncstate do?
I'm having a hard time following this logic, especially without seeing the entire thing and no coloring. But I can tell you that sendTime is not based on Time.TimeSinceLevelLoad, it is based on Time.RealTimeSinceStartup of the current local client
Ok, I'll try that.
Here is the code for context. You're supposed to hold down a button and depending on the duration after letting go, a different particle plays. When I'm close to that timing - which is 0.5s - both clients see a different particle.
Ahh, this is wit the realTimeSinceStartup change, going to try that right now.
oh, if that's your goal then using ondeserialization timing probably isn't the best use case. I would not rely on letting other players decide the timing. Just do the timing locally and send which one it's supposed to be
You are probably right. I was mostly just trying out the new parameter, which I thought would be me relying on the timing of the original user.
Yeah, realtimeSinceStartup doesn't seem to produce the same timing either.
I'll just scrap that idea and make it more simple.
Is there any known issues going on with VRC Object Sync and Udon, currently? Or with Udon ownership in general?
I and a friend with two different worlds of ours (one each) are having issues where objects:
-
Sync incorrectly (
Respawn()respawns the object, then returns it to where it was right before respawn). -
Fail to sync (
Respawn()fires locally, not globally) -
Fail to change ownership (Variables do not change globally; possibly related to previous entry.)
-
Fight for ownership (
Respawn()causes the object to interpolate between its previous position and the spawn point, as if both ends are vying for ownership.)
There's no consistency in the behavior, either, as sometimes it will work just fine. It's wholly inconsistent and happening across worlds.
—
And is there any way to protect from these issues?
Network ID spec got changed so maybe rearrange it from SDK.
Update: It's also causing psuedo-kinematic physics
When a player picks up an object, there is a chance that it stays where the player last let go of it, despite not being kinematic and having rigidbody physics.
At random.
Would using 3.1.11 be causing these issues?
Package resolver just started showing a new SDK.
currently 3.1.13 so maybe worse a try.
kinematic matter be I saw long back but not see it recently like before.
(but can be happen.)
My friend in my instance is reliably reproducing this
Like straight up anything they touch is suddenly kinematic.
With no reason, lmao
yeah, it is intended I think. they are.....lost what to do by lost of owner...
I saw it in murder previously.
Yeah definitely ownership issues then. Maybe the SDK update will fix it (hopefully) but if so they need to start blocking non compatible SDKs.
only affected people update SDK recently and update world multiple times....so....bit tricky.
soooo~
what can possibly cause that my udon behavior get reset when someone joins~
all the functions in my OnDeserialization are all local
they only get the value of the object and translate it towards UI and or the state of the game
figured out the issue~
the issue that caused it: changing the value of a ui element (toggle isOn/ slider value) with code in the start or OnDeserialization
cause it to trigger it as a event -> that connected to changing the value making the person loading the owner before he has all the data causing a complete reset of the behavior~
soo using the 'SetIsOnWithoutNotify(X)' instead of 'IsOn = X' fixed the issue
I am trying to send a networked event to teleport players, but found that custom network events do not activate the custom event? This is a stripped down version of the nodes and this does not even have the log that the custom event even fired so its not calling?
That should work if this object was fully synced. Is this object instantiated or set to not sync?
It sounds like you're describing the behavior where ObjectSync goes to sleep. When it does this, it takes any udonbehaviours with it. If you want to sync variables while the objectsync is asleep, the best way to do that is to put it on a separate object, yes
Wait that's a thing? What determines if object sync sleeps?
whether or not it's moving
why does smoothing not work on quaternions?
I read that wrong. Are you using Quaternion.Slerp?
sorry, i meant an UdonSynced quaternion
Ohh...not sure if smoothing quaternions was ever supported out of the box. I would just do that myself. But I also generally like to know whats happening instead of having to rely on blackbox implementations.
ah, i see
Question do VRC Object Pool also go in sleep or can cause strange behavior with udonscript on the same object like not syncing correctly?
It shouldn't, unless it's on the same object as an objectsync
nope
found out the issue was caused by switching between owners to quick before the serialization was finished
Would an objectsync with a station be woken up if the station is inuse?
Or would it be more appropriate to sync the position directly in Udon in that case?
it would be woken up when the objectsync moves. If the station has an udonbehaviour that takes ownership and moves the objectsync then that would work
sometimes the drop isn't working and the gun stays in the players hand is this a bug?
Drop can only work when the holder is localplayer
hey there, can i force animation on player with udon? with C#
Use station with custom animator
thanks
im using a station and turned "seated" off so my head wont be tracked while animating a dance, but now im unable to leave the station's location
That is a bug. Can be fixed by doing something like this though
Just need to call Immobilize(false) on the player when they exit
thank you, it worked
hmmmm, head still tracking now that i tested the world, any way to stop the head tracking during animation?
It's a bit finnicky and not really properly supported to my knowledge but if you add the avatar SDK package it will give you access to the Animator Tracking Control behavior that you can add to animator states, you can then add those animator states to the VRCStation animator controllers
what? you can do that? lol
interesting, you sure it cannot be done otherwise?
Yeah, anything involving stations you kind of have to expect to learn work-arounds and accept dealing with some level of jank
oh well, i hope they will fix that in the future
As a basic example of station animator controller it would be setup something like this
And this has been reported as a wanted change by other users already: https://feedback.vrchat.com/vrchat-udon-closed-alpha-feedback/p/add-avatar-related-components-also-to-sdk3world
got another upvote :), we need more freedom
@quaint rain is it normal that i cannot use "build&test" after i added the avatar sdk?
no error, it just doesn't start
I was able to get it to work without error with the avatar package version 3.1.13 from (https://vrchat.com/home/download) and these creator companion package versions:
hmm,alright thanks, maybe the way i added the avatar sdk was wrong, im unable to build the project, i will try to mess around with the sdk bit more
oh well, for some reason it doesnt compile when avatar sdk is added, no idea why
That's the thing it IS running on local player
what is the max characters limit of a string that is udonsynced?
like can we for example sync a string with 2000 letters/characters ?
C# use 2 bytes for each character. You can do the math
is this all udon behavior combined~
or is this per udon behavior~
since manual serialization ~ idk when other script sync triggers so what will get priority in that case
Per serialization which per udon script. But there's limit of how much total byte can be synced across all the script per second
yeah I knew about the bandwidth limit (idk how much that is but yeah)
also what happens if we would go over the max serialization on the obj? will it be send in parts or not send at all
Be aware that every string has an overhead. However its quite minimal. (I think 20 Bytes)
Actually not so sure about that. Best to check the debug panel on that one.
I wanted to possibly use a string as a list just with seperators~
since vrc doesn't allowed List<> and only type[] <- that has to be set else it won't sync.
Generally serialized objects have bigger memory footprints than their non-serialized form, so you want to avoid strings if you can.
For example the string "100000" takes up 12B while the int 100000 takes up 4B
If you go over the limit, it will fail to serialize. If anything ever fails to serialize for some reason, then it will never send anything to other players. If you want to know whether or not it succeeded, you can add the onpostserialization event and log result.success
if i want a real list need to use string and splitting thm
The best workaround for that right now is to use array extensions like this https://github.com/Varneon/VUdon-ArrayExtensions
ohh thank u~ are those syncable?
Array of syncable can be synced
Hi still new to udonscripting. And i dont know if someone can help me or not. But what i want to do is that when players enter this room. That is outside of the main world. A colliders check for all the players inside that room and then returns a synced list. I just dont know how what VRC feature to call to get the name that is not local player. Unless using Networking.Localplayer is the only way to get a list
I'm having an insane issue.... I have a game world that's been working for a while through PC and Quest players and I was going to full launch today, but all of a sudden PC and Quest players are unable to see room syncing up. I have 12 rooms to be claimable. Only the very first room is able to be seen by both PC and Quest. If a PC player is host and grants Room 2, only PC players can see it. If a Quest Host Grants rooms, only Quest players can see rooms 2-12 and not PC
Literally everything else works and are synchronized except those rooms
A recent update restored the functionality of custom network IDs, which was broken for a while. This means that network IDs are assigned in the SDK, rather than when joining the world. If you are using a different scene or project between your quest and PC world, you should use the network ID utility to copy from one to the other
Sure not. It's the same one
And I've refreshed the NetworkIDs several times and still not working
It was all working until last night
when it suddenly stopped
Me and my coder's been tearing out our hair tying to figure it out
(mostly me)
and after clearing network IDs you reuploaded both quest and PC?
You want me to clear all id's instead refresh? (honest question)
wait are you talking about this button?
Sorry regenerate
that doesn't do anything to network IDs, it just refreshes to find the VRCWorld
Brain's been mush for the past 20 hours
regenerate does pretty much the same as clear, because if you clear and then upload it generates during upload
hm
I'm just asking if you uploaded both PC and quest after doing that
Yeah.
okay so it's probably not a network ID difference then
could these issues be explained by udonbehaviour crashes? Is it that nothing happens, or that the wrong thing happens?
After running some more tests a moment ago, the data is being held, as when I hit randomize rooms, a room a Quest player couldn't see a PC player owning gets updated if it hits room 1
There's no errors in my Console, both on build and while observing unity with Vrc
(we have debug scripts pop, but that's nothing intersting)
So say You are on quest and claim room 1, and I claim room 2, I hit randomize. Room 1 is now me but room 2 wouldn't show up for you (but would for me)
I hit it again and you get room 1 back and can see it
is it a race condition?
I.. doubt it?
I'll ask him
Yeah he said "nope"
I've been over here scratching my head trying to figure out what happened, since it all was working last week
im having a weird issue. Maybe its obvious and i am not seeing it but i have two scripts talking to each other. When i get the cachedname from the room script,it returns nothing. Even if room already knows the data.
Ok so I did "clear" instead of "regenerate" and this worked
What the actual hell. Thank you.... I've been so stressed out about this
Okay i got it working at a certain point. I have this and the networkevent is being called. I tried it on a test build and it is working. But i recently tried it on 2 differentes computers and accounts. But the second account is not seeing the name being instantiated
I think i already know where i got it wrong. I only can do manual sync for arrays. So how can i exactly pass on the array data to others?
A few things, some minor and not important but just suggestions:
-
You can use an autoformatter in VSCode. I think it's Shift+Alt+F (haven't used it in a while). I see some odd spaces left in the code.
-
I haven't tried syncing arrays continuously yet, which I feel like you shouldn't. But the the issue is probably because of this: https://docs.vrchat.com/docs/udon-networking#requestserialization
When syncing behaviours with synced array variables on them - make sure to always initialize those arrays to some value, e.g. an empty array. If any of the synced arrays are left uninitialized - the behaviour will not sync! -
The ChangePlayerListNetworked is not really required if all the people see and trigger the collider. If someone walks in the collider, the OnPlayerTriggerEnter will be executed and therefore ChangePlayerList is executed for everyone without networking. In fact, that networked event will be executed multiple times for every player in the lobby, which is a bit redundant.
Now that I look at it, you also try to sync playersInRoom. Again, OnPlayerTriggerEnter will be executed for everyone without networking. So you can just remove the UdonSynced.
I left it like this. But the problem is that it does indeed work. But it only works for the players that have at least used the get in button at least once. If the second player doesnt use the button the second player wont sync or receive the data changed by the first player that did used the button
And the strange thing is if i use the [udonsynced] in playersinroom and cachedNamed. It does work regarless of whoever presses the button first. But it does it twice.
Initialize the array. Basically: ... = new string[0]; Might work (or might not, I have no idea honestly).
But yeah, as I said, things should work on their own if you remove all the networking calls and don't check if the player is local on the OnTrigger events. Should make it a lot easier to debug.
Thank you. Now it is indeed working. This is how i left the code
(in ClientSim)
I have an UdonBehaviour with Sync set to Manual and I'm calling RequestSerialization but am never receiving an OnPreSerialization or OnPostSerialization on local and the remotes are never receiving an OnDeserialization
Using UdonSharp btw
and yes, I do check if the local player is the Owner as well
Networking related tests will need to be done in client
unfortunate, I assumed that ClientSim would at least support basic networking
thanks for the info
Went to update today and learned I have to do this every time I need to upload either version....
rather annoying but at least I can still get it uploaded with syncing
hey guys I'm having an issue trying to make sure a Player as joined but is also ready - Should be OnPlayerJoinComplete() but it is not exposed.
The player will receive OnDeserialization when they have received synced data for a particular object, sounds like that's what you need?
Oh could well be thanks I'm gonna look into it
@frozen igloo but ONDeserialisation will run before OnPlayerJoinComplete so do you have a specific workaround in mind like checking smthing specific there?
OnPlayerJoinComplete isn't a thing and it's a bit unclear exactly what you're asking for
OnDeserialization happens when you receive data. Is that not complete enough of a join for you?
If you need to wait for all your objects to receive OnDeserialization not just one, then you should keep track of which ones have received and which ones haven't, and wait until all of them have
as for your suggestion of VRChat implementing something like this - VRChat cannot do that for you because it does not know the difference between an object that has sent something you haven't received yet, and an object that never sent anything at all
there is a random delay between payer joined and the scene is completely initialized (OnPlayerJoined complete then spawns in the log). I'm trying to sync audio track timing for late joiners (using network manual syncing).
If you have a recent SDK, OnDeserialization will give you a DeserializationResult with SendTime and ReceiveTime. You can subtract SendTime from ReceiveTime to give you the total delay in seconds between when it was sent and when it was received. You can use that to figure out a more accurate time to play the audio at
audio is desync from 5 / 10 seconds because of that delay network values are ready before the scene
yes thanks. But in my case as the scene is not completely initalized I don't think it can help.
that doesn't sound right, udon and networking starts pretty late, long after unity stuff like audio
ho idk that's not what I see (local testing with quickLauncher) but that may be a lead
The scene litteraly fade out from black but it has already completed initialisation and network process. I'm using UdonSharp btw could that make a difference?
ok, thanks for your help 🙂 I'm gonna continue working on it
What kind of scale should i be looking to limit myself to as far as syncing variables? For example if i wanted to sync, 10, 100, 1000, etc. Ulongs, where would i start to experience limitations of the platform?
You're limited to sending about 10KB per second right now, and vrc players take up about 3-5 of that. 1 ulong is 64 bits or 8 bytes, so 10, 100, you can spam as much as you want. 1000 would be 8KB, so you'll be limited in sending that about once every two seconds at most, but ideally it would be good to leave breathing room for everything else and only send that once every 5 or 10 seconds or more
Thanks! Thats great to know! My plans shouldnt really involve much other than the ulongs im using so it sounds like im good to go!
On a similar note, do you or someone else know how much of that limit some of the common pen set assets use of that?
not much
Cool, thanks!
How is this a networking problem.
No problem, I understand that.
You could put it in #udon-general
hello! so I'm trying to build a procedurally-generated backrooms world and i'm having issues with the part where everyone should see the same thing.
i have an empty gameobject that serves as the main manager, and in its Start function i call the subfunction to set up the initial state of the rooms. i want to send non-owners the random seed used by the owner so that when they spawn the rooms they spawn the same rooms, so I make that function only run if the player is the owner of that gameobject, but then no matter what i do that object does not seem to call the OnDeserialization event.
@cerulean zealot pinging you 'cause you asked me to
OnDeserializtion doesn't get called for the owner.
ik the owner is doing fine
Are you calling RequestSerialization?
Start checks that the player is owner, if so it sets assigns the rng seed to a UdonSynced variable and then calls the SetUp function; then the OnDeserialization function for the non-owners uses that rng seed to do the thing
i thought OnDeserialization ran on player spawn but i did try both with and without calling it, though i'm not sure when i'd call it so what i did was add a condition to the Start function so that if the player is not the owner it sends a network message to the owner to run a function that then fires RequestSerialization. also tried to run that function in the non-owner's version of the script themself and that also didn't work
You should be caching the local player on start and then checking if the local player is the owner every time you do networking. Ownership can change.
That is not how any of that works.
so how does it work?
The owner needs to RequestSerialization
Then eventually when VRC is ready to sync OnPreserialization is called for the owner.
This is where the owner can make sure the synced variables contain the most up to date information.
For every other player in the instance, OnDeserialization is called after the synced variables have been synced.
like I said:
what i did was add a condition to the
Startfunction so that if the player is not the owner it sends a network message to the owner to run a function that then firesRequestSerialization
so how do i make sure the owner runs RequestSerialization for every new player that spawns as soon as they spawn?
it just does
i thought as much yeah but it does not seem to
It does.
i added a simple Debug.Log to OnDeserialization and it does not get fired
i did
Really?
Can I have a look at the code here.
this bit here i added just for debugging purposes and the "fired ondeserialization" message doesn't show
How are you testing? In editor or build and test?
this code does not have the networking part, i got frustrated after trying a million things and deleted it all to try to start over from scratch after asking stuff here
Fair enough, syncing a single number shouldn't be that complicated
this shows up fine
but the second client is not sending the "fired deserialization" message at all
nor the "owner start" ofc
What variable is the seed here?
i don't have it, that was part of what i deleted, lemme rewrite what i had at first real quick
That's a little bit of indentation there
i had three variables with
[UdonSynced] int rngSeed;
[UdonSynced] bool syncRng = false;
bool syncedRng = false;
then down at the start i had
public override void OnDeserialization()
{
if(syncRng && !syncedRng) {
syncedRng = true;
SetUp();
}
}
void Start()
{
if(Networking.IsOwner(transform.gameObject)) {
rngSeed = UnityEngine.Random.Range(Int32.MinValue, Int32.MaxValue);
syncRng = true;
SetUp();
}
}
public void SetUp()
{
Unity.Random.InitState(rngSeed);
...
}
er
there
ik there must be a way to get the seed that isn't making a new one
but UnityEngine.Random.seed is deprecated
What purpose was "syncRng" supposed to serve
make sure OnDeserialization() only gets run exactly once in case that was getting funky
but i did try without
That..
having only the rngSeed variable and have no if condition inside OnDeserialization
Shouldn't be synced.
why not?
it needs to be local?
syncedRng is local, syncRng is not
Each client needs to keep track of if it's been synced
You aren't calling RequestSerialization here?
you said it runs on player join
yes
but i also tried calling requestserialization
like such:
public override void OnDeserialization()
{
SetUp();
}
void Start()
{
if(Networking.IsOwner(transform.gameObject)) {
rngSeed = UnityEngine.Random.Range(Int32.MinValue, Int32.MaxValue);
syncRng = true;
SetUp();
} else {
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "serializeMe");
}
}
public void serializeMe()
{
RequestSerialization();
}
public void SetUp()
{
Unity.Random.InitState(rngSeed);
...
}
i am aware, that is why i am asking here :P
but you said OnDeserialization runs on player join; empirically it does not, otherwise Debug.Log would have fired
public override void OnDeserialization()
{
if(syncedRng) return;
syncedRng = true;
SetUp();
}
void Start()
{
if(Networking.IsOwner(transform.gameObject)) {
rngSeed = UnityEngine.Random.Range(Int32.MinValue, Int32.MaxValue);
RequestSerialization();
SetUp();
}
}
public void SetUp()
{
Unity.Random.InitState(rngSeed);
...
}
😐
what's shocking about this
How confidently wrong you are while I am trying my very best to help you.
sorry, i don't mean to sound confident
that was not the intended tone
i meant to sound confused
i am not confident in any of this
sorry, I am very bad at reading cues like that 😅
this was in the original code i sent up above:
public override void OnDeserialization()
{
Debug.Log("<color=lime>fired ondeserialization</color>");
}
void Start()
{
if(Networking.IsOwner(transform.gameObject)) {
Debug.Log("<color=lime>owner start</color>");
}
...
}
if OnDeserialization runs on player join, shouldn't the Debug.Log up above run? if not, why not? and in that case, how do I get it to?
Holdon, are you able to get in a call?
give me five minutes i'm getting a coffee but then i am
okay i'm available
@/KitKat thank you it worked! i am ready to rumble 😁
@misty sail hello Red i'm avalible now
ok so i have an extremely simple script for a flashlight that i got from a tutorial. it works fine locally, and the other client sees me carrying it just fine, but the light's state doesn't seem to change for the other client. any idea what's up?
I have no idea how to do syncing in graph but it's the same idea as with the number we synced earlier.
you have the udonbehaviour set to syncmode none
I am blind kek
thank you for pointing that out
I usually prefer forcing the sync mode in my scripts but again (this is graph xd)
if i use GameObject.Instantiate to spawn some prefabs that have objectsync in them, do i still need every player to spawn them or do i just have the owner do it?
no syncing of any kind will work on objects that have been instantiated. You need to use an objectpool to enable objects that have always been in the world from the start
Why is that a limitation btw?
because synced instantiation requires communicating network IDs with other clients which is fragile and not something we want to directly expose to udon. Instantiation and destruction in general is also good to discourage because it generates a lot of garbage which needs to be collected later, causing hitches
That makes sense. Also another thing, why is objects named with seemingly random "i" and "l"? Is it to give them unique id's too look for or something else?
I'm not sure what you're referring to
When using the debug menu in game, if you pickup/drop an object, it's logging that, and the object it's referring to (I think is an object) has a random name made up of "i" and "l" 's
If you're referring to variable name i, i is usually signified that variable has integer type value. For l, it isn't that common, I have only seen it used in switch case .
Oh, that's due to obfuscation, to hide the name of the class as it's internal to VRC
Have never noticed that before
That makes sense
Well, there you go xd
You'll not be able to not see that now lol
I don't even read the log about pickup object since it seems too redundant.
Fair
So I have a RequestSerialization that isn't firing and I'm unsure why. I've done a similar pattern up to now, but all of a sudden it's not working.
First a player hits a button that is hooked up to this function.
It declares that person as the current owner and hops to the next function with an integer.
It goes through this and at lines 120 and 121 it does the serializtion process which looks like this:
Is it alright to be using this sort of switch system in Deserialization?
This system worked for the previous three cases, but this fourth one... when I put a debug log in the case or the UpdateCurrentPlayers, the RequestSerialization is not even firing....
This is for a memory matching game in English and Japanese.
I'm trying to make it so the board locks for the other 3 people when it's one persons turn to flip cards.
I had some trouble with referencing a separate script for strings when I first started off, so this time I tried to keep the entire code on script... is that generally better with Udon?
(Sync mode is set to Manual)
I do have a fair bit of [UdonSynced] variables... not sure if this is a lot or just a few...
I kind of have some questions about Udon Syncing,so while I'm here typing away. I thought I should ask:
- What is a rough estimate for to much Udon Synced variables?
- If Setowner is called once, that user can make changes to variables outside the function it's called in right? ex. a function called by a function.
- Should I manually be doing something with Preserialization, or is that better left untouched?
This is what it looks like so far.
This is the next step:
- I noticed that when I run two clients in the builder, the displayName of all the avatars I have in separate windows are all the same, but the recieve separate player Ids.
Do these separate avatars count as separate VRCPlayerAPI units in the Build and Test mode? I was hoping to avoid having to create two separate accounts and debug things online that way.
Sorry for all the questions, I just kind of hit a wall with this. It's so much nicer when the computer does weird things such as nothing at all.
Any other good networking documentation like this: https://docs.vrchat.com/docs/udon-networking ?
📘OverviewMultiplayer experiences are the heart of VRChat, so creating a world that reacts to players and synchronizes the data between them is key.This page introduces the concepts that power our networking system. Once you've understood the basics, you can dig into specifics:Network ComponentsNetw...
Yes they count as separate VRCPlayerAPIs despite having the same displayName.
Hooray!
Also when you say RequestSerialization() isn't firing can you verify by putting a Debug Log before the switch statement?
Oh, that's a clever spot to put it.
gimme a sec
this text should change to:
hmmm.
- https://docs.vrchat.com/docs/network-details
- Yes, as long as the changes happen before the object is serialized.
- You can for example use pre serialization to move data that changed into a single synced byte[] to save bandwidth by only syncing the data that changed.
TipsTry not to sync everything; consider what you can determine from the minimal amount of information shared. For example: if an object will move on a fixed or predictable path, then its position may not need to be synchronized and instead its initial location and velocity may be sufficient.If ther...
Manual sync is limited to roughly 49 Kilobytes per serialization.
You should be fine :p
The only thing I can think of right now is that the owner isn't setting for some reason...
You should notice that the IDE is telling you some hint: the OnDeserialization function must also include override modifier
the yellow warning?
Yes
So do you understand that?
Actually, I'm not sure. I've heard the override term before, but I didn't really get it.
Do I want to override that implimentation?
It seems like I should put in override or new.
Yes. That's to mark that the function is actually a member of UdonSharpBehaviour, not something you newly define yourself
The implementation is called metamorphism in object-oriented programming, where you try to change function implementation of base class it's derived from.
I feel like I don't want to change it, so I put in override.
You usually don't want to use "feeling" in programming: computer doesn't feel.
hmm, isolated the bit of code in a separate script, and gave it a go, but it doesn't change though.
I'll have to take another look at OOP sometime soon.
Have you verified that what trying to change variable is called?
And if your udon sync type set to Manual, you have to call RequestSerialization after object owner changing the variable.
These three guys:
hang on the isolated script wasn't manual...
That manual button... haha.
I'm gonna check the big script now with override. Thanks for the help!
hmm, override doesn't do it in the mainscript, but I can build off the smaller script for now.
Thanks to everyone for the info/help! I learned a lot! 🙏
Smaller script works!
Thank you!
Isn't it polymorphism? "Many forms"
Oh, it's actually that.
Polymorphism
Haven't used this term for years
