#udon-networking

1 messages · Page 25 of 1

fallow mountain
#
  • or simply send a network event to say "start moving up" for example, if you dont need late joiners to see the travelling elevator mid-journey
#
  • Even if you sync the transform of your elevator manual sync at 10 Hz, it shouldnt take up too much bandwidth... just check the Bps of the elevator in game
#
  • Or just use VRC Object Sync...
minor gale
#

adding rate limiting yourself is a good idea

strange token
#

the elevator itself isn’t synced, but the pos/rot of players is because I need to update the station they’re in 😛

I’ll add rate limiting to my notes 🙏

#

Might be a good break to take between the complex tasks I’ve left myself to struggle with 😵‍💫

minor gale
fallow mountain
#

is the stations just so they dont clip into the floor?
if you tie the Y of the station to the elevator you will achieve that
but you won't be able to jump while riding the elevator
an alternate solution would be move the entire world, rather than moving the players

solar crescent
#

Hm I have a moving object with a sphere collider that should hit a trigger collider setup with a script like that, but it does not react if the sphere bumps into the script, what should fire true if the name equals what I search for. I hate code. Why is it not working? :0

minor gale
solar crescent
#

I bite whoever invented Udon x33

fallow mountain
#

wait until you find out the collider shapes of local and remote players

solar crescent
#

I bite all

fallow mountain
#

its truly boggles minds

solar crescent
#

ok still not working when use OnTriggerEnter. I will just animate the whole crap now instead of making it modularly and reusable. I want to finish at some point and not find out one lil thing a whole day~ so doin all by hand now instead of automatized

frozen igloo
solar crescent
frozen igloo
solar crescent
#

Yeah and until then I whine myself into a puddle of despair ^^"

frozen igloo
#

In scripts, this is "private void FixedUpdate()" and in animators, this is "Simulate physics" - both achieve the same thing of moving stuff during the physics loop, which makes physics objects they are moving behave much better

solar crescent
#

arigatou sensei UxU

north thistle
twin portal
#

For the local player it is

lone zealot
#

Remote players have a sphere collider at their "root" (between the feet right under the hips bone in the default pose)

#

They also have a capsule collider, but thats only for raycasting for selecting the player

lusty pagoda
#

can i be loading 2 urls at once if i waited through 5 second delay

fallow mountain
#

2 urls with 5 seconds between them yes

fast pulsar
#

For the RequestSerialization command, does it sync up variables that are not tagged as UdonSynced or is it specifically for variables with that tag?

frozen igloo
fast pulsar
#

Thanks! That helps a lot figuring some of the examples out 😅

sterile goblet
#

i have a question:

i do have a gameobject that is animated (Transform) Position and Rotation.

how can i make it sync to all players? the object it on different positions for all players somehow even when using the Object Sync Script from udon.

Would be cool if someone can ping me with a solution/tips or documenation ive read the VRC Documentation already.

tulip sphinx
#

@sterile goblet if it has vrc sync component and noone can control its state then it should be plenty

sterile goblet
#

and its everything but not synced

#

I have an Flying object that moves it Position and everytime someone is joining the Object is on its start position on their screen.

#

The state cant be controlled.

It is just an Flying Object

#

This is literally everything

tulip sphinx
#

wait, its moving how

sterile goblet
tulip sphinx
#

well ye, then everyone plays their own animator

sterile goblet
#

How should i animated/move it then?

tulip sphinx
sterile goblet
#

In Normal Unity Games i work on i can make a normal sync script for animated Objects but udonSharp is so hardly limited

sterile goblet
tulip sphinx
#

if you dont mind it be just a random point of animation but being looped for everyone then this

sterile goblet
#

its desync so heavily

#

ye we have tried this Component already but the Desync is too big

#

It is kinda sad that we cant sync animations in 2025... you can do this since ages in Unity by default

#

It would help so much if VRC had an actual Github to contribute and open pull request

fast pulsar
#

in the JoinZone example, what does [SerializeField] protected UdonBehaviour[] targets; do? I know SerializeField makes it available in the Inspector, but I assume the rest just grabs all the players in the instance?

minor gale
# sterile goblet its desync so heavily

utc isn't going to align well enough across different devices for that, if you want something accurate you can send the progress of the animation periodically and work out the time since the packet was sent

in your case if you want something simple using object sync, disable the animator component for remote players, enable it if they become the owner at some point

void Start()
{
  animator.enabled = Networking.IsOwner(gameObject);
}

public override OnOwnershipTransferred()
{
  animator.enabled = Networking.IsOwner(gameObject);
}
sterile goblet
#

The delay is still to high

minor gale
#

you worked out the animation time based on the packet's age?

#

or do you mean object sync

sterile goblet
#

and transfered it to a different person once the previous owner leaves the instance

#

theres a delay of around 3-5 seconds

#

Also when you open the Ingame (Big) Menu you stop syncing with the movable object.

minor gale
#

in one of my own worlds i do something like this, but adjust the speed multiplier of the animation instead so it doesn't result in any snapping if there's discrepancy beyond the initial packet

sterile goblet
#

and i sadly found out this is a limitation of UdonSharp and nothing u can fix at your end

minor gale
#

i'm not sure what you mean by platform, like you're using something to keep the player on a moving platform?

minor gale
#

the best way to approach that is with stations if you want to see players in the correct location relative to the platform, but using stations has trade-offs and you'll have to handle the relative sync yourself

sterile goblet
#

im aware of it

#

but we want to fully avoid stations

#

Ive checked UdonSharp now and it is not possible to make iot perfectly sync without some adjustment on the core

minor gale
#

have you considered moving the world instead of the platform? might not be applicable to your case though

sterile goblet
#

i can only open a feature request and hope they will look into my example C# Code

sterile goblet
#

We do a Meme world with many places to visit its not a good idea to move the world :D

#

Ive thought about all the ideas you provide to me (i appreciate ur effort) i made sure to think of every single possible way before i did even ask here

#

Im very good in C# and ive checked UdonSharp it is too limited to make it possible to sync Players on movable platforms

#

the reason for this is because Positions of players are local and not synced. Theres no sync for Collisions, Physics, Platforms in VRC

#

In short: A Player on a Movable Platform saves the position Local and not Global for other players. Once you leave the platform you are synced again. the only way to be in "sync" (fake sync) with other players is you have to be on the same position of the platform at the same exact time

#

this is almost impossible to do in a efficient way

#

i will just contribute to VRC and open up a feature request with an example C# Code and hope they will implement it

fast pulsar
#

Does anyone know why UdonBehaviour[] targets is used (in the JoinZone example) to send custom events instead of using the networked event?

#

Or is this largely because of DataList not being able to be sent through the network event?

fast pulsar
#

I'll paste a snippet of the code if it helps:

public class PlayerJoinZone : UdonSharpBehaviour
{
    [SerializeField]
    protected UdonBehaviour[] targets;

    protected void SendEventToAllTargets(string eventName)
    {
        foreach (var target in targets)
        {
            target.SendCustomEvent(eventName);
        }
    }
    public virtual void OnPlayersChanged()
    {
        // Only the owner should run this logic
        if (!Networking.IsOwner(gameObject)) return;
        
        // Propagate Player changes to everyone
        foreach (var target in targets)
        {
            target.SetProgramVariable(nameof(Players), Players);
        }
        // Players is a Datalist, which does not trigger OnVariableChanged events, so we propagate its event manually
        SendEventToAllTargets(nameof(OnPlayersChanged));
    }
minor gale
#

it looks like the intent might be to allow creators to add their own graph programs to the targets array, which if they had a corresponding datalist Players and event OnPlayersChanged, the program could listen for changes to the player zone and react

fast pulsar
#

Thank you so much ❤️

fallow mountain
#

The canonical way to sync stuff is just using GetServerTimeInSeconds() (or GetNetworkDateTime())
Same logic as video players syncing their playback times
Or more precisely GetServerTimeInSeconds() + Stats.RoundTripTime() * 0.5
If you use local device UTC to sync it is going to vary unpredictably because someone's device clock can be off by any amount

minor gale
sterile goblet
#

?

#

@cold laurel what

cold laurel
sterile goblet
cold laurel
#

Yes you can :)

sterile goblet
#

do it and proof me wrong 👍 never seen it in vrchat

sterile goblet
cold laurel
sterile goblet
#

I want a non-desync demo im ready to get educated

sterile goblet
#

Ok what now?

#

Where is the platform

cold laurel
#

Want me to give you a little tour?

sterile goblet
#

I just want to know where the platform is that moves by an animator where two players can stand on without a desync

cold laurel
#

you're already on the platform

#

look out of the window

sterile goblet
#

thats a world that spins around the object

cold laurel
#

let me join and I'll show you

sterile goblet
#

But not a platform

cold laurel
#

lol

sterile goblet
#

i want to see an Unity example where you clearly change the transform rotation and position by using an animator controller

cold laurel
#

players can be outside and fly space ships, and if you look at the spawn area from the outside you see the players in the correct position in the spawn (on the ring)

sterile goblet
cold laurel
#

desynchronized stations, yes

#

locally you're set to Mobile

sterile goblet
#

I dont talk about stations

#

I do talk about Platforms 😭

cold laurel
#

I think you're misunderstanding

sterile goblet
#

I think you are misunderstanding me.

cold laurel
#

you can walk around normally when in the spawn area

#

right?

#

:)

sterile goblet
#

Kitkat,

Show me a Plane that moves Up and Down, Left and Right and It Rotates by using an Animation Controller. Let 4 People Join that Test World with that Test Plane and let them Jump on the plane and walk on it.

#

UdonSharp is limited here and it will Desync between all Players this is a common and known limitation of VRChat.

cold laurel
#

It's completely possible to prevent the desync.

#

Just join me and see

sterile goblet
#

Then you are a super hero and the only person world wide with a solution.

cold laurel
#

Sure, if you think so

#

But Far Citizen literally has this implemented.

sterile goblet
#

I think you missunderstand about what i talk

cold laurel
#

The only way a floating origin would be possible in VRChat is if you could locally override the position of remote players.

#

If you want to rotate the local player then that's a different question entirely.

#

If you only want to stick to a moving platform that translates and doesn't rotate on any other axis except the y axis then that's possible.

sterile goblet
#

I talk about platforms that change YXZ Axis and Position.

#

And about players that jump on that platform to different times.

cold laurel
#

Do you want to rotate the local player, yes or no

sterile goblet
#

Of corse.

cold laurel
#

Why do you want to rotate the local player

sterile goblet
#

Because it is a mechanic i want to add?

cold laurel
#

Can you be any more specific?

sterile goblet
cold laurel
#

You can rotate remote players upside down, but not the local player.

sterile goblet
#

What i want to do is simply not possible with Udon. i dont even need to discuss this

cold laurel
#

Have you considered that you might not know everything in the entire world?

sterile goblet
cold laurel
#

There is a lot of undocumented behavior in VRChat...

#

You don't need to be an idiot to not know the answer to everything.

#

It's okay to ask!

sterile goblet
cold laurel
#
  1. Players walking inside the moving platform
  2. Players seen on the platform from outside
#

The stutter is simply from the rotation source of the ring being a bit wonky.

#

You don't have to be sitting or stuck to "be" in a station.

#

You can use station mobility Mobile to still use the default VRChat player controller and locomotion while still technically being "seated"

#

This allows you to reposition remote players so they're in the correct position relative to the platform they are on.

#

Circumventing the "desync" you would normally observe from players being synchronized in world-space

fast pulsar
#

Is it possible to randomly assign roles to a list of players through a DataList that has player tokens or is there a different way to do this?

Currently I also have player objects assigned so im not sure if there's also a workaround through that but im not sure x_x (also didn't want to interrupt the other convo, my bad)

#

Basically trying to achieve something similar to that of prison escape, murder, among us, etc. With the random role assignment

cold laurel
#

Are you asking how it would be best to synchronize the "roles"?

fast pulsar
#

I guess, though initially I was trying to find a way to communicate to each player's player object to send info about their role but I feel like that might be a stretch.

#

Though I haven't figured a way to randomise or shuffle the DataList either 😦

cold laurel
#

You can do pretty much anything you want in Udon, it's Turing complete.

fast pulsar
#

Well im using udon sharp, yeah

finite sierra
fallow mountain
#

It is not peer-to-peer, the RTT is between you and the server

#

Other people get their ServerTimeInSeconds individually from the server

finite sierra
#

has anyone tested how many continous sync variables we can have per person before it starts suffering?

fast pulsar
#

Unless I can add the names of the players as a ref for the enum which the sync would be manual to avoid any high amounts of data too

cold laurel
#

And that it's not corrected for time in flight?

finite sierra
cold laurel
#

Yes, of course it has to request it once when you join the instance. Not every single time you call it.

finite sierra
cold laurel
#

...

#

Are you familiar with clocks?

finite sierra
finite sierra
minor gale
finite sierra
#

and if you then click a button for instance that says Sync. it would Request serialize for that local person and sync everyone else @fast pulsar and all they would have to do is when this happen is make sure to run whatever you need to run locally. and update your copy of their object with that data.

fallow mountain
#

if you know a correct source that says otherwise can you share?

minor gale
#

you mean this? "all clients should have the same value"

have you considered the rtt stat you're touting has only been exposed in the last update? that people have used a shared timespace for years?

#

like it's just misinformation to say it's not being offset up front to tie it to the server's picture

cold laurel
#

If you didn't know that then I'm glad I could help!

fallow mountain
#

it is offset up front?

#

you sure?

fast pulsar
# finite sierra and if you then click a button for instance that says Sync. it would Request ser...

Yeah. I have a Player Object set up where all players get a copy of a game object that stores all the different roles which are hidden unless they are given the role and are in the game. Making sure the randomisation is done on the Owner side is definitely a must though so that way everything else like teleporting, showing the role n stuff is all done locally. Mainly the randomisation part will be tough unless I can use the enum for that which I could see the enum storing the roles and a randomised order of numbers while respecting the number of players participating. Then I can run the players through that so in a way its randomised without directly trying to shuffle the List itself. The players would take that enum data in once then read off the role they were picked from that

minor gale
#

i don't know what you're suggesting as the alternative, if you believe it awaits an async call during your code execution i don't know what to say

fallow mountain
minor gale
#

that is not the call being made by udon

cold laurel
#

You get the number immediately!

finite sierra
fallow mountain
#

well udon video players use ServerTimeInSeconds to sync afaik so you can use that

fast pulsar
#

The roles are randomised like prison escape, murder n stuff as well. My bad x_x

finite sierra
#

yea you can still do that. everytime a game ends the owner shuffles the list. then ensures everyone else gets the update by requesting a serialize.

#

and the number indicates what seed it used.

#

you can just have a byte that is synced. that way you have up to 255 possible different seeds.

fast pulsar
#

😮 a seed!!! That actually would work perfectly

finite sierra
#

just make sure you actually sync the seed. not the list or any of that. also make sure its manual since it doesn't change often.

#

that way you atleast can make sure its always the same.

#

and then you could run some verification to ensure its the same for all people

fast pulsar
#

Ye

fallow mountain
fallow mountain
#

it should, i remember seeing the nodes in udon graph

#

but as the article suggest you may need to write using Random = System.Random;

fast pulsar
#

Alright 👍

foggy jackal
#

also I'm making a local RNG variable with new System.Random(); in Start()

north thistle
#

wouldn't Networking.GetServerTimeInSeconds() be calculated as server time at world entry + current real time since startup - real time since startup at world entry?

minor gale
north thistle
#

Well to clarify, I assume at world join, behind the scenes, with whatever method the desire to use, they link real time since startup to the server time, and GetServerTimeInSeconds() is based off that link using the difference in real time since startup

minor gale
#

i don't know that it'd be realtimesincestartup exactly, it's certainly possible, but yeah the polling is likely comparing a cached offset to some time source when you call it

fallow mountain
#

GetServerTimeInSeconds() and GetNetworkDateTime() jumps in whole milliseconds (there is no sub-millisecond resolution) whereas real time since startup gives sub-millisecond numbers, but it does seem to be cached only at instance entry, but prolly not calculated from real time since startup because of the millisecond jumps
I guess VRChat simply reads the PhotonNetwork.Time from their plugin and reports it
But only does FetchServerTimestamp() once at entry

#

However if you calculate it manually with real time since startup, naturally it should line up

#

at the lowest level both photon plugin and unity has to use the computer clock to keep track, so it's effectively the same

#

(although changing the computer clock with the game open won't actually change the numbers, cannot hack time)

foggy jackal
#

Hahaha hackerman!

north thistle
#

Idea: you might be able to make something equivalent to VRCObjectSync using a combo of a manual sync object with a continuous sync child

the manual sync contains the a bool saying if the continuous sync child is active or not; if active, enable to continuous sync and use the values it gives you; else disable the continuous sync object, save its last value in the manual sync object, and use that value instead

fallow mountain
#

imo we shouldnt have to manually do all these gymnastics to "fix" vrchat's continuous sync, if it just goes to sleep when not needed...

north thistle
#

I suspect VRCObjectSync is itself a manual and continuous behavior stitched. I'm pretty sure a continuous behavior by itself would not be able to support late join sync if not constantly outputting data

frozen igloo
north thistle
#

At the very least, more networking tools does seem nice if it is at all possible

cold laurel
fallow mountain
#

"secret third thing" makes it sounds like they map to these three options in PUN for Object Synchronization:

  • Reliable Delta Compressed - manual?
  • Unreliable - continuous?
  • Unreliable OnChange - vrcobjectsync?
minor gale
#

that's pun 2, i don't think it's directly applicable

fallow mountain
#

Of course this is pure guessing but this might give insight into how they do what they claim (or rumored) to do...

  • manual sync:
    • reliable
    • "guaranteed to be received with an internal optimization mechanism which sends null if data doesn't change"
  • continuous:
    • unreliable
    • "received in order but some updates may be lost"
    • "this means no delay in cases of loss"
  • vrcobjectsync:
    • unreliable but sleeps when no updates
    • "received in order but some updates may be lost"
    • "If updates repeat the last information, the PhotonView will pause sending updates until the next change."
cold laurel
#

"guaranteed to be received with an internal optimization mechanism which sends null if data doesn't change"
?

minor gale
# fallow mountain Of course this is **pure guessing** but this might give insight into how they do...

i don't totally understand the point of pure speculation, this comes across as some sort of authority/fact sheet to a casual viewer and if you don't actually know, this type of thing can be pretty misleading. i feel the need to correct misinformation that's relevant to what i've worked on and it probably detracts from this channel's purpose or deters people from posting about actual issues

like certainly discussion about networking is good, but i'm not sure i really understand the point of this

fallow mountain
#

it's okay, you don't need to understand, you always accuse something you don't understand as misleading misinformation

minor gale
fallow mountain
#

hey i am just trying to talk about how udon networking works, if you know something we don't, feel free to contribute

frozen igloo
#

speculation has value - it can be used as the basis for building a hypothesis and tests needed to validate positive or negative. It does not need to be interpreted as a claim of 100% truth

cold laurel
#

Wow.

#

It only has value if the speculation changes based on the observations that have been made. The scientific method and all that.

frozen igloo
#

"guaranteed to be received with an internal optimization mechanism which sends null if data doesn't change"

I'm pretty sure is incorrect but it doesn't mean that it's invalid as speculation

#

and it was clearly presented as such

minor gale
#

i don't think prefacing with "this is just a theory, but i think this is how it works" leading into posts that read like a comprehensive overview; like that doesn't give a blanket pass and this is definitely something casual observers will pick up on and use if they have no concept of it otherwise

fallow mountain
#

nice official confirmations, at least now we know

frozen igloo
#

Theories need to be comprehensive in order for tests to be comprehensive. Being comprehensive doesn't make a theory any more "claiming to be true"

fallow mountain
#

i dont remember where i read about manual has internal optimizations, so i thought that was what it meant

#

maybe it was just about hitching

frozen igloo
frozen igloo
#

allowing one speculation to override another speculation is just arguing without any connection to the truth. Same for standing behind a speculation that has been disproven with test results

fallow mountain
#

yeah ok just tested manual serializing the same data does not really shave off any Bps
so that is that

#

actually, why not? isn't this opportunity for optimizations?

frozen igloo
#

what you're describing is delta sync, which is not implemented yet. It's on the backlog, will get to at some point if we can find time for

fallow mountain
#

oh great
in the meantime we can actually Udon this

frozen igloo
#

newer versions of PUN have delta sync, but vrchat is based on an older version and has a ton of custom stuff built on top of it

#

generally, if you assume that photon documentation applies to vrchat you're going to run into a lot of misleading info

frozen igloo
# fallow mountain oh great in the meantime we can actually Udon this

doing it with udon naively will break late join sync because the relay server stores the most recent serialization and will repeat that to late joiners when they arrive. If your recent serialization is only a collection of the data that changed, they will not have the full picture

#

if you do it on separate objects so that one object stores a complete state and then another object stores a smaller set of changes since that complete state, that can work. But you need to be careful to link them together with definitive hashing, not blindly throw data around

fallow mountain
#

ok but what if I do a basic if (newvalue != oldvalue) RequestSerialization(); so it only syncs if there is an actual change in value? i mean not even going into the delta stuff

#

if my goal is just to decrease throughput

frozen igloo
#

regardless of how you detect it - yeah, doing requestserialization only when your data changes is a good practice and if you are intentionally relying on triggering it even when it hasn't changed, I would certainly question why

fallow mountain
#

good point... because some suggests manual sync at a certain Hz can update more frequently than continuous, so it is like one way people are manual syncing

#

e.g. manual sync at 10 Hz vs continuous seems to be capped at 4 Hz or so?

#

and it is more "reliable"

cold laurel
#

Continuous sync rate depends on if it's on a held pickup or not. For VR players it will be higher than for desktop players.

frozen igloo
#

yeah, continuous sync is a very mild, slow system. It has a lot of compensation to allow for there to be many continuous objects. It's not surprising that manual can go faster, but the important thing to keep in mind is that if you set manual objects to go faster, you won't be able to have as many of them

cold laurel
meager quiver
#

Worth a note here for how that works, which might use useful for context. Request specifically means to add to the serialization scheduler (I don't know if there's a specific scheduler here, but can be thought of like this) and the serialization will occur when it comes up. The frequency that an object's schedule will come up is a combo of overall data rate and per-object data rate - the data sent being a result of serialization of all behaviours on a given gameobject combined, as RequestSerialization() operates on a per-gameobject level, not a per-script level (which is why you can't mix manual and continuous sync).

You can go well above 10hz if you are syncing near to no data.
The unknown here that I haven't tested, and thus should be taken with a grain of salt, is exactly how the serialization size of one object affects the rate of others - if it's global, or if individual objects update rates can be slowed down. I do know that objects have an actual serialization rate - this can be seen using the standard VRC debug overlays. Players have em too, to sync IK and expressions.

#

I mean it is global

#

but if serializing a lot of data on one slows down only that one object, or all objects - i.e. if scheduling an object knows to call a given object less frequently with respect to other objects vs just slowing it down in general and crossing your fingers.

frozen igloo
cold laurel
meager quiver
frozen igloo
#

or, well... manual still uses 8 bit if it's below a threshold. That could be part of it

meager quiver
#

I wonder what the deal is here

cold laurel
meager quiver
minor gale
#

i expect the overhead is more likely on the net object being continuous, it probably sends some superfluous data that's only used in continuous, the size stat differs from the actual output; it was just an 8 byte variable when i tested that

cold laurel
meager quiver
minor gale
#

it's possible the new network stats are wrong, but they align with the debug menu

cold laurel
#

The "best case" / "worst case" is due to the variables not being sorted by type, which means that more header has to be wasted when the variables happen to be in an unfortunate order.
I don't know if this is fixed yet, but I sure hope so.

meager quiver
#

Oh that's janky

#

lmao

cold laurel
#

y e a h

fast pulsar
#

(Also that video you posted I feel has saved so much headache when I was looking for similar videos on YouTube, so thank you ❤️ )

finite sierra
fast pulsar
#

Gotcha. I haven't normally seen OnPostSerialization around in some code but im guessing that counts when code runs after the RequestSerialization is called?

finite sierra
#

Indeed. Only for the one requesting it

#

It's used for doing things you want to happen after a serialize

#

So you run owner and remote in seperate methods

#

I use post heavily for sync

finite sierra
fast pulsar
#

is it good practice to have a condition to check for isOwner before doing anything in a block of code that's going to run the request?

finite sierra
#

Well. For the purpose of debug yes. Since you can use it to check if someone is trying to run it if they shouldn't etc

fast pulsar
#

Yea

#

I remember back in Arma 3 I've had to use that condition a couple of times just to make sure it's running on the Owner's side but at the same time it probably might be fine if the code is being executed by the owner in the first place

north thistle
#

Meanwhile continious does not have that limitation. As far as I know you have no limit to the amount of scene-wide continuous syncs you can have per second, the only limitation being the kb/s out limitation.

cold laurel
north thistle
#

Well technically it's using whatever the "secret third thing" VRCObjectSync is using, lol.

I do need to test my manual/continuous hybrid idea.

fast pulsar
#

Well I ran into a snag where it doesn't seem to be possible to send a DataList of player data into JSON because of the Reference Data Tokens included in it (mainly to sync it with others). 😦 is there a workaround for this?

fast pulsar
#

nvm I decided to pull the playerId instead as a string then had it convert to an array later on.

north thistle
#

yah if you want to sync VRCPlayerAPIs, you need to do it via playerId

cold laurel
meager quiver
#

If I can't fit my family of 3 dads, 6 children and a dog, all of different races and nationalities, as a single character of my name, what's even the point of having a name

#

My name must look like the back window of my car - with those family stickers missing their heads and a sticker with a really long and overly verbose thing about who I am that somehow involves my husband who is in the army who is the third cousin removed of some other rich guy

fast pulsar
#

I wonder though, unrelated, but is it possible to hide a person's avatar from everyone else (with exceptions for some players) and then have a character model in the world be puppeteered by that player and seen by those that can't see the original avatar.

#

Or is this potentially too much information to send over the network? 😅

#

Basically one team sees the player as a monster while the monster team can see eachother normally

twin portal
#

I think that's doable

finite sierra
fast pulsar
#

Ye I did it by playerid and it's working now

finite sierra
#

Good good

#

Also we can't really hide other people's avatar through scripting.

fast pulsar
#

I'll have to tinker around with what might be possible then since I really want to try and make it possible to keep things spooky for the other team without breaking character. Even thought about maybe immobilizing it unless there's a different way

cold laurel
cold laurel
fast pulsar
#

Negatory but now I'm curious on what it does 👀

#

ohhhhhhhhhhhhhhhhhhhhhhhhhhhh

#

I just had a quick glace at the docs and now im excited XD

cold laurel
#

So, if you ensure that every player gets their own VRCStation, and that they're always "in" that station you can change the Station Mobility locally

#

You should use Player Objects for this

fast pulsar
#

Right, and I assume the desync station would make it so you can move around outside of the avatar?

cold laurel
#

set the station mobility to Mobile locally, and then to Immobilize on a remote player's station if you want to desynchronize their position.

finite sierra
cold laurel
#

You literally just did.

minor gale
#

here's an example of desynced stations, this is the same physical space in this example (not teleportation); there was a good post in udon-showoff that has a similar concept

finite sierra
#

Nope

fast pulsar
#

(that would explain how some of the mmd worlds work now that I think about it)

cold laurel
#

The entire player will be moved

#

their voice source too

#

which might be problematic for your use case

#

you can use a station animator though

fast pulsar
#

Yeah

finite sierra
#

That's not really hiding then lol. So you are incorrect once again kitkat

fast pulsar
#

Well if it's just putting the avatar somewhere on the map safe that's fine enough in terms of hiding tbh

#

I basically just want to have the player appear as a monster towards other players pretty much

cold laurel
#

What you can do is you can put their player far away but still keep their relative direction correct

#

and locally increase their voice distances

finite sierra
#

So once again misinformation kit Kat lol

fast pulsar
cold laurel
#

yes

minor gale
#

here's another example that makes it a bit more apparent, i like this one personally

fast pulsar
#

Now im hyped

#

thanks @cold laurel ❤️

#

Once I get it working I'll be sure to post the result into #udon-showoff 😄

cold laurel
finite sierra
minor gale
#

beyond a certain distance the player is effectively culled, from a remote perspective

#

unrelated to avatar culling though (like the vrc setting)

finite sierra
#

Well yeah. That's just culling doing it's work

minor gale
#

it's not, it's custom culling

finite sierra
minor gale
#

you mean the one that turns into a diamond?

finite sierra
#

Yea

minor gale
#

i made that orange thing myself, that's the representation i made

fast pulsar
cold laurel
finite sierra
#

I don't know kit Kat you have a trend to spread incorrect info

minor gale
#

i'm literally moving the player behind the remote player from the remote perspective, i implemented it myself, i don't know that telling me it doesn't work that way is relevant

finite sierra
cold laurel
#

Literally clueless

finite sierra
twin portal
#

the conversation they're having is mostly related to desynced stations, Hostile
the examples occala is showing is using those
it's not the VRChat culling settings, they're using desynced stations to mimic it

finite sierra
#

Oh yeah I was starting to notice the odd station stuff.

finite sierra
twin portal
#

no it's not a bug..... it's literally a function available to stations

#

though by some contexts I'd consider stations as a whole an unintended bug.

cold laurel
#

real

twin portal
#

I jest a bit. mostly a stab at stations just being really jank in general

#

one of these days they'll get a rework, I hope

finite sierra
#

Oh because of how messy they can be in general?

twin portal
#

yeah
working with stations you kinda have to go into it prepared that they have some very odd, illogical behaviours that you just have ta roll with

finite sierra
#

Ngl never really looked much into stations. The last time I really saw them used was easy back with the horror maps series. Huggies horror series it was called I believe

#

@twin portal would you per chance know what kind of problems can happen if you disable a object that has a continuous sync on it. And then reenable it say 2 seconds later?

twin portal
#

not specifically, when you disable a gameobject with an udon script on it, some things still run, some things don't
If my script involves disabling objects, I usually put the script on a different object than the one that gets disabled in order to avoid any headaches that come with disabling it

#

I think from my latest projects, you can still set variables and I think call custom events, but Unity events like Start and Update won't run

#

those were manual sync objects, but I wouldn't be surprised if a disabled continuous object would no longer send updates

#

no wait, I think someone was troubleshooting some NPC enemies with continuous sync the other day, and they still try and send data when disabled?

finite sierra
#

Hmm. Is it known how reliable continuous is? Like say with more people it gets worse or something ? For instance if I want to have a controlled say 40 bytes synced. But I do not want the cost of manual and its reliable guarantee. I wonder if it actually is possible to have it just do the continuous sync for say 30 frames or so and then disable it

#

To have a wierd psudo continuous controlled sync.

twin portal
#

that feels like something that probably won't work that way, but is worth testing

finite sierra
#

Yea. All through that does mean every user need to validate changes and ensure the object gets disabled locally for every other person.

#

But then again how would they know to activate it again.

#

Have some sort of a dirty flag system for each person?

twin portal
#

that's the thing I was talking about where some things still run, some don't

#

I'm pretty sure you can call a custom event on a disabled object that enables itself

#

but as you can probably tell even at this point that it can get troublesome to manage. What works and what doesn't? I dunno; so it's generally not worth pursuing, there's easier ways

finite sierra
#

Yeeaa

twin portal
#

what you'd need to test if the object still sends data even if it's disabled

finite sierra
#

That is true it's something I never really considered since I was always using manual

twin portal
#

but you can't have a script that say, increments a number on Update and set that number to continous sync. Update will stop running when the object is disabled

finite sierra
#

Yea

#

It's just that I really want to avoid the cost that manual had for everyone in the world

twin portal
#

I would hedge to bet that continuous sync sends acknowledgements as well, so you'll likely still see that bandwidth increase as player number increases

finite sierra
#

I just need to test it. Put simply.

#

Gonna get 48 people and get them to do 3 different worlds with no udon. With cont and one with manual just to see the baseline cost for no udon and then for cont and manual

north thistle
#

makes VRCObjectSync pretty good for high update rate positional syncing is an environment where networking is a concern

heavy spindle
#

Inside PlayerObjects on Start, is the Networking owner guaranteed to be set on Start?

#

or what event should I check in when the player the object was instantiated for is the owner?

#

Oh yes it is. I didn't read the docs :(

fast pulsar
#

Regarding Ownership. Is it always best to change ownership on things like doors to people that interact with them or is it not necessary?

fallow mountain
#

it is better to take ownership because you can immediately change the bool and sync it, instead of sending an event to owner and waiting for the owner to sync a new bool... less perceived lag

#

unless your door is susceptible to multiple people trying to spam it open and close then maybe you want to make a cooldown timer or just send event to owner to prevent weird desync visuals

fast pulsar
#

Right, yeah

#

I guess that's good to know to ensure not everything is on the Owner. Thanks!

fallow mountain
#

only the owner can sync the bool state, but you can send an event to tell the owner to change the bool state and sync it, rather than taking ownership

#

so yeah you dont have to be the owner if you just tell the owner to do the thing

north thistle
#

An ideal system involves as little ownership transfers as possible. There are situations where ownership transfer is necessary and there are situations where implementation speed is more important than optimal implementations, but in general you should try to avoid ownership transfers.

north thistle
fast pulsar
north thistle
#

So messing around with Events With Parameters, it appears that they're just manual sync in disguise minus the values being saved on the VRC server (and thus not synced with late joiners). They have identical networking performance to manual sync and appear to behave in an eventually reliable way where only the latest event is guaranteed to arrive, no intermediate events. Thus they should be treated as eventually reliable variables rather than just events.

For example if you send an event multiple times with different variables of A, B, C, and D (in that order), if the receiver gets the events in the order of A, B, D, and then C, then C will be dropped and never occur.

This would match the docs saying that events will play in order. If C arrives late then then still having the C event occur would result in the events playing out of order.

north thistle
fallow mountain
#

events can send at much higher Hz tho isnt it

#

than manual sync

north thistle
#

Yep

#

I'm guessing since the VRC servers don't have to worrying about storing Event data, VRC allows you to use them in a way less restricted than normal manual sync

#

Actually, I haven't actually tested it. What is the highest hz that events can be sent out? If you send out events at 100hz, do they start to get batch sent out?

fallow mountain
#

i tested at 60 Hz and it appears to be working and that was capped by my frame rate, because i was doing send delayed custom event with 1 frame

#

so i assume it can go up to 100 Hz

#

manual sync highest was about 15 Hz in my test, but it wasnt the absolute smallest data

north thistle
#

I know that the time it takes an event to go from sender to receiver is notably longer than the ping time, although I suspect a big part of that is events getting artificially delayed on the receiving side to help reduce the occurrences of out-of-order events getting dropped.

fast pulsar
#

Well mine changes the ownership anyway and just tested it with a few friends who live on the opposite side of the world and so far everything works almost instantly for everyone so all is good now. Thanks though ❤️

minor gale
finite sierra
fallow mountain
#

it was continuous non stop
if it dips that means it is throttled for some reason, but 2 times a minute is not even any Hz, that is like 0.033 Hz so idk...

finite sierra
fallow mountain
#

yes, the receiver also generates output traffic, but as long as you (one client) is below your bandwidth limit then it shouldnt throttle, maybe it has to do with grouping and delay

north thistle
minor gale
finite sierra
north thistle
# minor gale this is applicable to manual sync as well

Well doing some tests using clumsy to simulate awful internet and testing while the world was under heavy network load, I was not able to observe any dropped events.

What I have observed must have been caused by something else in my code (most likely), or is a bug with VRC's networking that only occures under very specific conditions (hopefully not)

north thistle
#

I think I found my issue. Turns out you should perform state changes on the owner's side immediately instead of OnPreSerialization. If you wait to do it in OnPreSerialization it can create race conditions that can allow bad code to make illegal state changes that bypass your normal safeguards.

tropic sigil
#

Hey yall, so im having a problem where things work in unity but not in vrc and i think it might be networking stuff.
I have a candle script thats supposed to make it turn on when a collider enters it. however, the thing that holds the collider is instanced per player, i think thats what might be making it mess up in vrc, but im not sure how to go about fixing it.
https://streamable.com/abgrkl
https://streamable.com/b1vuwj

Watch "2025-06-20 02-18-32" on Streamable.

▶ Play video

Watch "2025-06-20 02-16-51" on Streamable.

▶ Play video
#

i have the scripts if anyone has time to take a look

heavy spindle
north thistle
#

You mean if I end up losing intermediate states doing this? My system is designed so the receiver of the sync doesn't need those intermediate states, only the latest state

heavy spindle
#

Well im not so worried about intermediary states either, just you saying this makes it sound like what was recommended isn't actually good to do.

Like lets say a user interacts with something and sets a state of something and that state is a bit critical to not have any difference between clients like some animation or something else that would be really hard to undo should VRC actually not send off that data to other clients

north thistle
#

to be clear, the owner checks if a state change is valid and only changes/syncs that new state if it is

heavy spindle
#

I mean like here's what I got from you saying that and what I'm trying to get across:

[UdonSynced] private bool State = false;
private bool localState = false;

private override void OnDeserialization()
{
    if (State != localState) // protect against initial state syncs
    {
          localState = State;
          _DoFlip(); // do it for clients' end
     }
}

private override void OnPostSerialization(SerializationResult result)
{
    if (result.success)
    {
         localState = State;
         _DoFlip(); // Would be safe but you're suggesting against?
    }
}

private void _DoFlip()
{
     // trigger something
}

private void _Flip()
{
    State = !State;
    RequestSerialization();
    _DoFlip(); // is what you're suggesting we should do?
}
#

Just a crude example

north thistle
#

My issue is I have the owner check if an attempted state change is actually legal before performing it; and that fails to correctly check stuff if there is a gap between the state change check and the state actually being applied when there are a couple or more rapid state changes in a row

minor gale
#
[UdonSynced] private int interactCounter;

public override Interact()
{
    RequestSerialization();
}

private override void OnPreSerialization()
{
    interactCounter++;
}

my example is pretty poor and not how you'd want to do this probably, but this would be something where pre or post could fail to capture an increment

#

post wouldn't be as applicable here anyway, but someone might consider using pre for this

#

pre is still a good case for something you want as close to the send of the packet as possible, like a shared timestamp; or if you want to have your own packet identifiers per send

north thistle
#

What caused issues in my case

private void SetState(MonsterState state)
{
    if (!Networking.IsOwner(gameObject))
    {
        LogWarning("Attempted to set state as non owner!");
        return;
    }
    if (!IsLegalStateChange(State, state))
    {
        LogWarning("Ignoring invalid state change attempt");
        return;
    }
    _stateInt = (int)state;
    RequestSerialization();
}
public override void OnPreSerialization()
{
    State = (MonsterState)_stateInt;
}

Note that State, when a value is set to it, it automatically runs through the state machine transition code

frozen igloo
#

Waiting for onpostserialization to apply a variable is reasonable - you're adding unnecessary latency but it's not gonna break anything. And if there's a possibility of it failing to serialize (such as with user input values that aren't always serializable) then you can check for that before applying what could be invalid data

But waiting for onpostserialization to change the data? No, that's backwards.

Waiting for onpreserialization to change data is slightly better and technically valid, but I'd only recommend it for "packing up data before sending" not something like "increment a number in response to user input"

minor gale
#

i think for applying data, people probably do it to keep parity between owner and remote logic, like pre or post owner side, deserialize remote side

they do actually behave differently if you override ownership request; the requested serialization will only fire when you're granted ownership over net. it does not fire if you're denied ownership; the two events can be treated as a confirmation of ownership to some extent in that specific case, but it comes with other issues (the request flag isn't cleared if you're denied ownership, if you were to gain ownership through other means, like the original owner leaving, it'd end up firing the serialize at that point)

fast pulsar
#

I noticed that with OnPlayerRestored the reference to the player is not valid when using it in the method, even though on the docs it says it's safe to access the data. 🤔

#

is this because that the player is still joining or is this some kind of voodoo thing going on x_x

minor gale
#

restored fires for every player when you join and for subsequent joiners

if the script is not synced (like a scene script), you'd usually just check if the player being restored is the local player and branch into your logic there

if it's like a player object, you'd additionally check if it's owned by yourself

https://creators.vrchat.com/worlds/udon/graph/event-nodes#onplayerrestored

fast pulsar
#

Mainly checks like isValid and isOwner

#

I did do a build and test with 2 clients so idk if I wasn't supposed to run it that way

minor gale
#

you probably want utilities.isvalid, not isValid on the player

public override OnPlayerRestored(VRCPlayerApi player)
{
    if (!Utilities.IsValid(player) || !player.isLocal) return;

    // Do stuff here
}
fast pulsar
#

Ye thats what I did

proper coral
#

Does RequestSerialization only work for manually synced stuff?

hoary frost
#

its a pain to figure out

north thistle
proper coral
#

Heyyyy my friends how do I sync a material across a network? I want a synced material to be updated

fallow mountain
#

you sync an int number that represents the material

proper coral
#

it turns out that syncing like that wasn't my solution unfortunately, however I have now encountered an issue of documented code not existing. Specifically https://creators.vrchat.com/worlds/udon/networking/events#sending-events-with-parameters

Is there a new version im not aware of or is the documentation wrong somehow?

Network events allow simple one-way network communication between your scripts. When a script executes a network event, it executes the event once for the target players currently in the instance.

hoary frost
#

youll still need to go by an int

proper coral
tulip sphinx
#

step zero, get ownership, step one, you set param value on the owner, step two you propagate it via request serialization, step three you apply it locally, nothing changed. send network event, be it with parsms or not is good only for smth that lasts a few seconds top, learn proper manual/serialization based sync

timber ferry
#

quick question, if you set a player as the owner of object A, will all its children also be owned by that player automatically?
Object A
- Object B
- Object C
- Object D

tulip sphinx
#

no

#

each not None sync udon has its own network id and thus owner

timber ferry
#

makes sense

frozen igloo
#

Note that if you ask for the owner of an object which doesn't have networking, it will go up and find the first parent which does have networking. Not because the children have "transferred", but just because of that upward search

fast pulsar
#

Uhhhhh curious, but when it comes to testing persistence data between 2 clients. Is it better to build and publish the world to test this?

Every time I do a build and test it keeps logging me into the same accounts so I just get a bunch of errors in unity that I just don't understand x_x

fast pulsar
north thistle
fast pulsar
#

on one client yeah

north thistle
#

and two or more

fast pulsar
#

it doesnt work if you are using identical accounts

#

well it does work I guess but if you are checking data to make a new player in a list then it would freak out

north thistle
#

You mean the way Test & Build works by default? I've never had it fail to work while using multiple identical accounts.

fast pulsar
#

oh by default build and test works perfectly fine. Its just with Persistence data it'll freak out with errors when trying to handle data on identical accounts since you cant really launch 2 separate accounts without building and publishing it

north thistle
fast pulsar
#

Every day you learn something new x_x . I had no idea that existed, so I'll give that a try then 👀. Thanks ❤️

jaunty thicket
#

Quick Launcher my beloved

fast pulsar
crude trail
#

I have 2 stations in my world and I want the local player to use the station as normal but go into the other station for remote players. Its a vehicle that is only supposed to exist once but the station is being hogged by other players and not updating remote users. This setup will result in players floating without a model to go with it but it would keep the main object for everyone locally where it should be. Im not sure if this is possible but maybe someone could help?

fallow mountain
#

this is a desync situation, you know, because both players will be local player in their point of view, they will both sit in the station 1.....
wait, why would you want local always at the front?

#

and do you want just 1 remote player to sit, or any number of remote can sit in and hidden away in the back? what is the intention here?

crude trail
#

there should only be 1 vehicle and there are script that reference the 'main' local one. I dont want othr players to mess with the main one as there should only be that one. The extra one is just to sync the other player's position so they dont just stay in one spot

fallow mountain
#

you will need a vrc player object so that a new station is assigned for every player
and have your button/interact to sit your player to the station that they own
and move/not move the station based on if the player is remote/local

#

so any amount of remote players can enter and stay at the back, each have their own station

#

and... you dont need any sync station positions, because you specifically dont want it to sync, because everyone will sync they are in front

crude trail
#

I want remote players to show where they actually are.

#

basically

#

player1 gets in a car and thy drive off, player2's car doesn't move and player1 floats off to player2

fallow mountain
#

so you need multiple cars, one car per player, you can do this with a the car being vrc player object

crude trail
#

oki, I attached the player object prefab to the station and it didnt seem to do anything. Pretty much everything in the world has syncing disabled, do I need to enable it for the station, im guessing yes but im not sure

fallow mountain
#

put it on the car, since it is the whole car you want duplicated for each player

#

the car contains the station so it will be duplicated as well

#

and you then just sync the car

crude trail
#

oki so spawning one with vrc player object on it should give everyone their own when they load a level and spawn one

fallow mountain
#

yes but you dont spawn it manually, it is done automatically

crude trail
#

All objects in the world besides the level geometry and level collision are instantiated at runtime, and can be unloaded and loaded at any point and its only set up to spawn one. Its ok if it gives one to someone else but if its relying on being in the scene when building its cooked

fallow mountain
#

you can just disable the object at start or something

crude trail
#

It wouldnt be that many objects to deal with but Im maybe thinking of trying to have a station prefab that locks on to the car so only 1 station ends up being required per person and not dealing with several copies of the car with its references and turning off all but the one the current player owns at turning one in use on

#

not sure how viable a station linking setup would be

#

ill just have to try it and see how it behaves tho tbh

#

ill try when I wake up

fast pulsar
#

So for some reason my player doesn't exist for OnPlayerRestored, any idea why this is happening? 🤔

#

My code for OnPlayerJoin and OnPlayerRestored looks like this

    public override void OnPlayerRestored(VRCPlayerApi player)
    {
        if (!Networking.IsOwner(gameObject)) return;
        playerListLocal = playerData.SetupPlayer(player, playerListLocal);
        gameManager.SyncData(playerListLocal);
        player.Immobilize(false);
        OnPlayersChanged();
    }
    public override void OnPlayerJoined(VRCPlayerApi player)
    {
        if (!Networking.IsOwner(gameObject)) return;
        player.Immobilize(true);
    }
fallow mountain
#

you can only immobilize the local player

fast pulsar
#

oh...

#

So it only works for Networking.LocalPlayer.isLocal?

#

I had no idea immobilize wasn't able to be executed remotely, dang...

#

well the only reason im doing it is to immobilize the player until their data is loaded, so idk where to put that code 😦

fallow mountain
#

um but you did check if owner is local, so it should kinda work

#

is this a player object?

fast pulsar
#

OnPlayerRestored is listening out for synced data from a player object, yeah

#

wait I see what you mean

#

🤦‍♂️

fallow mountain
#

a vrc player objcet?

fast pulsar
#

uhhh I should have worded it a bit better after realising what you meant my bad XD, but the code you're seeing is in an object not owned by the player object, but the code is listening out for a vrc player object yeah.

I might have to wrap a condition to check if the user is local, then run the owner code separately

fast pulsar
frozen igloo
# crude trail All objects in the world besides the level geometry and level collision are inst...

Udon is not able to instantiate objects and give them network IDs, so if you expect your things to have network IDs then it's not going to work.

VRCPlayerObjects are unique in that their automated setup process does assign network IDs during instantiation.

If you attempt to manually instantiate VRCPlayerObjects, you would be interrupting their process and they would not get network IDs.

However, if you don't need networking then there's not much of a reason to use VRCPlayerObjects for this purpose.

Or, if you do need some object to pass networking through before routing it back out to your instantiated objects, then you can use VRCPlayerObjects for that. But you'd have to be careful to ensure that the VRCPlayerObject is not disabled or instantiated manually, because that will break it.

vast agate
#

So uh, how does one determine why network is clogged?

fallow mountain
#

network becomes clogged when suffering reaches >100
suffering reaches >100 when there is too many queued messages
there is too many queued messages when you are sending above around 9 KB/s for your serializations and it throttles and tries to stay below this amount

#

(suffering starts building up from 0 when serialization throughout goes near or above 0.5)

#

(which is nominally around 9 KB/s)

vast agate
fallow mountain
#

the debug menu 6 in-game shows you which object is sending how many Bps and you can monitor from there

vast agate
#

It seems to only be clogged at the very start, but I am also getting debug messages saying OnDrop is delayed so I dunno

fallow mountain
#

what are u syncing?

#

maybe u are syncing a very big burst of data

frozen igloo
#

being clogged on start isn't usually a problem you need to worry about. Is there a specific bug that you're seeing that makes you think it would be?

north thistle
#

if you have a bunch of VRCObjectSync objects in the world, they will all be on at the start and can clog it for a bit before their sleep mode activates

north thistle
simple wyvern
#

Which method would be better to minimize the network stress (assuming their count is fixed, and uses Manual Sync)?
All the Vector3 variables are targeted to be updated very slowly, and the purpose of them being synced is just to at least make late joiner see the variable changes.

  1. Combine them into Vector3[] respectively in OnPreSerialization and unpack them in OnDeserialization
  2. Mark every Vector3 variables [UdonSynced] (with respective FieldChangeCallback setup)
minor gale
# simple wyvern Which method would be better to minimize the network stress (assuming their coun...

you'd probably have to measure the difference between an array and individual vars, my instinct would say that individual vars may be cheaper on bandwidth, but if it's easier to do an array logically i think you should use an array. objects send all of their synced vars when you serialize, regardless of which you've changed, so it's not like making them individual vars will really save you that much unless they do some bundling up to specific fixed sizes on arrays

for your idea on point 2, i think FieldChangeCallback may still fire on any deserialize, regardless of whether it actually changes, but that's something you'd have to test (i don't know if they check for equality, but in terms of deserialization it would likely be assigned again)

using the deserialization event is typically better practice than using the field change for synced vars

simple wyvern
# minor gale you'd probably have to measure the difference between an array and individual va...

My goodness, I thought using Manual sync would only send the changed variables when RequestSerialization is called. Couldn't find mentions on the docs so I pretty much assumed it would, because the network debug (Rshift + tilde + 6) reported lower Bps than the size. That's one knowledge added to my head, thanks a lot. You may have saved one's life and one's project as well. lol

Well, based on your explanation (and also my own measurement of how those Vector3 variables would be in use), I may have to go with PlayerData instead of any of two methods I listed. They will always be in a fixed count, and does not update frequently (happens when player avatar has changed or something like that), I think it fits the criteria.

minor gale
# simple wyvern My goodness, I thought using Manual sync would only send the changed variables w...

Bps will only show a somewhat accurate picture of the package size if you were to serialize every second (bytes per second)

Size, or TotalBytes (divided by number of sends) would get you a more accurate picture of the data use
https://creators.vrchat.com/worlds/udon/networking/network-stats

if you're tying some position or offset to a specific player and need it for every player, PlayerObjects would be pretty applicable, PlayerData could probably be used too

simple wyvern
#

Oh that was why the Bps number was always lower than the size, that makes sense now.

And yes, I've already using PlayerObject but only used PlayerData to save the settings data. Now I've digged further and realized that PlayerData is also synced between players via separate Player Data Object [n], so I would use this instead to let my PlayerObject's synced variable size as small as possible and make PlayerData do the job. Thanks again.

north thistle
frozen igloo
#

Requeststerilization 💀

sick epoch
#

i have multiple objects each running the same script (toggles for a door) and need to sync a single boolean between all of them, is there a way i could go about doing this for the several distinct objects so that they all are updated with the current state of the boolean when one button is hit?

#

(i keep having issues with it desyncing but havent been able to figure out exactly why)

#

heres what i currently have running on each button

obtuse echo
sick epoch
#

i think in this case, its multiple buttons affecting one door, so multiple buttons each have their own boolean to affect the door

#

everything works fine when only one toggle exists per door, but for the big gate, i have multiple toggle points

#

and so occasionally the syncing for new joiners gets messed up

obtuse echo
sick epoch
#

i see, thats a good idea, how would i send the info to the manager to open / close the door?

obtuse echo
sick epoch
#

i see, like this?

obtuse echo
#

First udon behaviour: Create a variable of type UdonBehaviour. Then do Interact > SendCustomEvent, but like in your screenshot you put the new variable into the instance socket.
Second udon behaviour: Drag the game object this is on into the first udon behaviour game object (newVariable in your screenshot). Then do the sync code you did initally, but without the interact. Use a custom event instead of interact.

sick epoch
#

i see! thank you so much for the help

obtuse echo
sick epoch
#

no no i think thats a great explanation, i was unaware that was even a possibility

#

basically making the buttons dumb and just sending the event to a central manager

obtuse echo
fallow mountain
#

yea in your central door script you want to set local as owner before touching and syncing the bool,
and to avoid multiple people spamming different buttons trying to steal ownership you can put in a cooldown to refuse ownership request for like a 1 or 2 seconds or something

sick epoch
#

it seems to work wonderfully, thanks for the help

crude trail
#

This is probably a dumb question but do playerObjects have problems with reparenting? Trying to get it to rigidly stick to another object and its mostly fine until a collision happens and then its off a bit. Attempted to reparent but I dont think it likes this

#

XD Position is syncing but its deffinitely not moving with it and almost moves as if its scaling the movement

crude trail
minor gale
#

make sure you're parenting to something with a scale of 1 on each axis, i can't really tell otherwise without seeing the code. i don't know of any specific issues with reparenting playerobjects (though it's not something i typically see and am unsure if its networking would be happy with that)

crude trail
#

unsure if its networking would be happy with that
I am also trying to parent to a local only object. This is a really niche usecase but this is the most viable setup for my project I can think of

minor gale
#

it looks like it's an issue on local (right hand client)? presumably their own player object station? i think it's more likely an issue with how you're parenting or the hierarchy, the networking is kind of beside the point if the local portion isn't working properly

crude trail
minor gale
#

if you want to keep it stuck on the vehicle like that, do it in a late loop that happens every frame (LateUpdate for example)

#

i feel like parenting should work in this case too, but i don't know enough about the setup

crude trail
#
scene:
  StationPlayerObject
  Floor
  racer
    armature (rigidbody component)
      renderer and stuff
        bone
          Seat (Link StationPlayerObject here rigidly)
minor gale
#

racer, armature, renderer and bone are all scaled to one?

crude trail
#

ah, racer is scaled to 0.5

minor gale
#

i don't know if that'd affect it, but mixing scales down a hierarchy can make parenting messy

#

0.5 on a base object doesn't seem like it'd break the parenting to me, so idk

crude trail
#

pretty sure ive already tried the late update setup, with it working perfectly in editor and all over the place in game

#

ill do it again tho

minor gale
#

do you have the relevant portion for where you're parenting and setting the position? or could you describe if it's event-driven or every frame?

crude trail
#

heres about what it looks like

script on Seat object:
  userStation (StationPlayerObject)
  
  OnStationEntered(VRCPLayerApi player){
    if(player.isLocal){
      userStation.transform.parent = transform.parent;
      userStation.transform.position = transform.position;
      userStation.transform.rotation = transform.rotation;
  
      userStation.UseStation(player);
    }
  }
#

just a basic reparent and set to the exact same spot

#

position sync is handled by the objectSync component on the userStation

minor gale
#

that's being done because you want a station per player, but one vehicle, right?

crude trail
#

yep

crude trail
minor gale
#

are you certain they're entering their specific station? i'm also not sure what the intent is with the stations moving behind the vehicle before anyone has entered them, but i'd assume intentional

crude trail
crude trail
# crude trail

when becoming smaller so I can more easily see the station sphere I can see that the station is linked rigidly now but the station only appears to move me using fixedUpdate

minor gale
#

does the station happen to have a rigidbody on it?

#

the thing you were initially showing with the station lagging behind can actually happen with rigidbodies parented under other rigidbodies if the child has any interp settings enabled

crude trail
#

interpolation off actually make it worse

minor gale
#

and it's kinematic?

crude trail
#

kinematic on station or vehicle?
vehicle no

minor gale
#

the station specifically

crude trail
#

no rigidbody at all on the station

#

just setting on fixedupdate causes it to lag behind a frame, and accounting for that frame to lock it in place ends up desyncing it on colision

minor gale
#

you could try setting the execution order later than the vehicle, above the class itself

[DefaultExecutionOrder(100)] // After vehicle
public class StationScript : UdonSharpBehaviour
{
crude trail
#

tried 100 and -50, didnt seem to change anything

#

ima try it on the seat script itself rather than the racer script so its lower than the armature where the rigidbody is

crude trail
#

postLateUpdate is locking the station perfectly but now the player is lagging behind XD this shouldnt be this hard

minor gale
#

lagging behind locally? 🤔

minor gale
crude trail
# minor gale lagging behind locally? 🤔

stations seem to move the player during fixedUpdate, which lags behind since it seems to be before the rigidbody physics calculations, so ig im required to move the station ahead by the current velocity and just deal with the 1 frame desync during large velocity changes

crude trail
fallow mountain
#

how is the car moved? in script in update?

#

if the station is reparented then you shouldnt have to move it yourself

#

why your car has bone? does it do animation?

crude trail
timber ferry
#

so, i'm making an ownership system for my tycoon thing, and networking is hard.

i have an Owner Gate, which will by default have a isTrigger collider, and a preset message. when a player enters the trigger, it will tell my tycoonManager to set the owner as the player that entered (the local player), and update the message to include that user's name. then, it also changes an IF statement to make it so, if the player that enters the trigger isn't the tycoonManager's Owner, isTrigger gets disabed, so that they can't walk through.

after a player walks through the trigger and becomes the owner for the first time, i also set a bool to false, so that any subsequent players will not trigger the code to set themselves as the owner, until that bool is set back to true from the tycoonManager (which will happen when that tycoon's owner leaves, because if the tycoon owner leaves their progress will unload, meaning any new-joiners will then have a tycoon to claim)

#

then, in my tycoonManager, i have a few things set-up, which i'm just not sure about. first of all, i set the tycoonOwner to be the master by default, so that it isn't null, and i can check in other scripts to see if the player is the master, since it means the tycoon technically won't have an owner.

then, i made a getter/setter for changing the owner, so that instead of running SetOwner from my owner gate, i can have the getter/setter change the tycoonOwner variable and the actualy Networking owner at the same time.

i have a few other things in my tycoon system that i want to make sure the tycoonOwner is the owner of, so i made SetOwnership, and i run that before doing any logic i figured would need an owner for. i originally thought about sending an event to all scripts that need to have an owner set , when the tycoon owner changes, but i don't think i can do that without having the manager have references to all those scripts, which is just not viable.

CheckOwnership is just there for a specific other script, so that it can only run code past an IF statement if the owner of the object is the tycoonOwner.

OnOwnershipTransferred is something i don't really know much about. but what i'm wanting to do with it, is if the ownership changes (like from the master to a player that touched the owner gate), update the tycoonOwner variable, and run UpdateCurrencyOwnership so that the new tycoon owner is also the owner of the object pool for this tycoon (it's not a VRCObjectPool, it's my custom one). and if the tycoonOwner leaves, i added OnPlayerLeft to try and check for that, but i feel like i could get that information from OnOwnershipTransferred too?

also, i don't even know if ownership over my custom object pool is necessary, because none of the objects are actually synced. that's why i made my own, because i didn't need or want the objects synced. but something i noticed, is that when one of those objects enters my Collector's trigger (which runs tycoonManager.Money += (value)) the Money display would not update for both clients i was testing with. so i figured i would need to set the tycoon owner as owner of the currency objects and the collector, since i already have the FieldChangeCallback and UdonSynced on the Money variable

#

i just realized that canInteract on my OwnerGate should be synced, so i at least know i can fix that

#

also, if someone reads this and doesn't know what i'm asking for, i just want to have someone know what i'm trying to do right now and make sure i'm not doing anything wrong or strangely. my OnOwnershipTransferred method i don't even know will work, so i'm also asking if that will do what i said i wanted it to do

#

and, do i need to set oenership over my objectpool objects if they don't have any networking on them

fallow mountain
#

local objects dont need to mess with ownership, ownership is for syncing, no sync, no ownership needed

timber ferry
#

okay, so i changed OwnerGate to have this:

[UdonSynced] private bool canInteract = true;

private void UpdateOwner() {
    Networking.SetOwner(localPlayer, this.gameObject);
    tycoonManager.Owner = localPlayer;

    canInteract = false;
    RequestSerialization();

    UpdateDisplay();
}

public void ResetCanInteract() { canInteract = true; RequestSerialization(); }

and i removed the logic for setting ownership of the currencyManagers child objects from TycconManager

timber ferry
#

if the ownership of the object is manually set, and then that person it was manually set to leaves the instance, does the ownership transferred return the instance master again?

fallow mountain
#

the docs just says automatically assign new owner, and avoid relying on master

#

so probably no

timber ferry
#

yeah.. so then who does it automatically set the owner to if the previously selected owner leaves?

fallow mountain
#

you will have to check for the owner again with GetOwner()

#

the owner will be Networking.GetOwner(gameObject)

minor gale
#

it does automatically transfer if the owner leaves, yes, you can't rely on it alone in the way you're wanting to use it

timber ferry
#

so maybe i don't need to use OnOwnershipTransferred for this.. cause what i want is that, at first the master owns everything, of course, and tycoonOwner is set to the master. then, when a player steps in the owner gate to claim a tycoon, i want to set that player as the owner of the tycoonManager, and as the tycoonOwner variable. and if that person leaves, i want the tycoonOwner to be master again, and to run some other code when they left

#

yep, as i was saying just that

fallow mountain
#

but you dont want to rely on master, what if the master is afk or is sleeping, i mean the instance master is not a special player or anything, what if the master is playing the game as another player

timber ferry
#

if the tycoon owner is the master, it means the tycoon will have nothing in it. the tycoon owner being the master will just be like a default state, where nothing is loaded on that plot and the only thing there is the gate to allow someone to claim it and become the owner again. that's why i want to know when the selected owner leaves, so i can unload the enabled objects and basically reset that plot. the player's progress will be saved in playerdata so they can load it in again next time, so i won'thave to worry about progress being lost

#

i'm not trying to rely on master for anything, just using it as the default state for tycoonOwner basically

fallow mountain
#

...what if the master wants to play the game

#

what if the master leaves and some random person became the new master

timber ferry
#

ah, i see.. but then what do i use as a default state for the tycoonOwner?

#

since an object can't have no one as an owner

minor gale
#

it'd be more typical to sync the owner player id on it (the player who has claimed it would sync their id on it), if someone walks into the trigger they can infer if that player actually exists by using vrcplayerapi.getplayerbyid, if they're not in the session you can safely take it over, you'd usually use -1 to denote no active player despite it having an owner inherently

fallow mountain
#

just keep it as is if you are not syncing anything

timber ferry
#

i'm syncing objects that get unlocked by unlock buttons, and the Money variable i the tycoonManager

#

so mainly, those are what need to have an owner

#

but i also have a couple things that use network events, so i use my SetOwner method to control that

#

anything i need to use the tycoonOwner for, i have those reference the tycoonManager and check the owner through that, so that i can handle the changing of the owner in the one place

timber ferry
fallow mountain
#

network ownership should not be part of your game mechanic, just use playerapi or player[1] or something so it is a certain player that has joined the game

#

network ownership is just for syncing variable

timber ferry
#

i can see that now, since i realize master shouldn't be the default state

#

what i should be doing is what occala said, and storing an ID for who owns the tycoon, and when that changes, set whoever the new owner is as the owner of the things that need syncing

#

also i just tested in playmode and i'm getting a bunch of random errors that i wasnt getting before, so now i'll have tofix that too.. i didn't even change some of these scripts

proper coral
#

Hey folks, so the variable isnt getting synced. Anyone know why?

using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class DiscardPile : UdonSharpBehaviour
{

    public HarpyUnoGame game;

    [UdonSynced] private string _currentCard; 
    void Start()
    {
        
    }
    
    private void OnTriggerStay(Collider other)
    {
        if (!other.gameObject.name.Contains("Card")) return;
        if (other.gameObject.GetComponent<VRC_Pickup>().IsHeld) return;
        Networking.SetOwner(Networking.LocalPlayer, gameObject); // Networking.GetOwner(other.gameObject)
        _currentCard = other.gameObject.GetComponent<Card>().ToString();
        game.AddToDiscard(other.gameObject);
        RequestSerialization();
        SendCustomNetworkEvent(NetworkEventTarget.All, nameof(UpdateDisplayedCard));
        
    }


    public void UpdateDisplayedCard()
    {
        Debug.Log("Updated card to " + _currentCard);
        GetComponent<Renderer>().material = game.GetCard(_currentCard).GetComponent<Renderer>().material;
    }
}
#

Ok so now it's like updating very inconsistently

cedar crescent
# proper coral Hey folks, so the variable isnt getting synced. Anyone know why? ```cs using Ud...

You might want something more like this? Usually don't need network events if you use synced variables.

private void OnTriggerStay()
{
    // ...
    Networking.SetOwner(Networking.LocalPlayer, gameObject);
    _currentCard = other.gameObject.GetComponent<Card>().ToString();
    game.AddToDiscard(other.gameObject);
    RequestSerialization();
    // Update card for the local player
    SendCustomEvent(nameof(UpdateDisplayedCard));
}

private void OnDeserialization()
{
    // Update card for remote players
    SendCustomEvent(nameof(UpdateDisplayedCard));
}

public void UpdateDisplayedCard()
{
    Debug.Log("Updated card to " + _currentCard);
    GetComponent<Renderer>().material = game.GetCard(_currentCard).GetComponent<Renderer>().material;
}
#

Also you may want to move game.AddToDiscard(other.gameObject); to inside UpdateDisplayCard(). But it depends how it works, so I'm not sure

proper coral
cedar crescent
proper coral
#

so SCE is saying "Make Everyone run this function" and SCNE is "Run this function on everyone"?

cedar crescent
#

No, SendCustomEvent is "make only me run this function"

proper coral
#

so does everyone in that instance get the contents of OnTriggerStay called?

cedar crescent
#

oh, yes OnTriggerStay is run separately for everyone.

#

It's kind of funky because OnTrigger and OnPlayerTrigger aren't themselves doing any kind of syncing/networking. But because player movements are synced, then each player's game is detecting the trigger being entered/exited separately.

proper coral
#

I see, this is very odd to me haha

cedar crescent
#

It's understandable. I actually often forget triggers behave a bit differently.

cerulean zealot
#

What us the upper limit of an object pool and how many vrcobject pools can we have?

frozen igloo
# cerulean zealot What us the upper limit of an object pool and how many vrcobject pools can we ha...

vrcobjectpool doesn't have an inherent limit either way, but it does use bandwidth and will flow into the standard global bandwidth limitations. Fortunately, it does pack the data pretty tight - afaik, it uses bit packing to put 8 toggles in a single state. So you'd be able to get away with pretty large ones in that regard.

I consider the cost of the objectpool to be more like a small overhead - the thing that really matters is the cost of the objects inside.

cerulean zealot
north thistle
north thistle
#

Actually I think there is an exception. If you put a VRCObjectSync and a Continuous udon script on the same object, when the VRCObjectSync goes to sleep it seems to also sleep the Continuous udon script.

#

I would, however, generally disadvise putting a script that uses any networking (including events) on the same object as a VRCObjectSync as it results in undocumented behavior. In my case I found having a script that used networking events on a VRCObjectSync object caused network suffering in situations it otherwise wouldn't if the networking event script was a child instead.

cerulean zealot
frozen igloo
# cerulean zealot 👀 wait... wut? VRCObjectSync, a component that comes with the VRC SDK.... is...

not incompatible - there's a specific exception made for objectsync and continuous to work together. That exception does fully work, but it also was made before manual sync.

When manual sync was made, it ended up being just so significantly better that there are very few cases where you'd want to do it the old way.

The problem is that networking is managed by a component, added at runtime, which manages all the networking per gameobject. Manual sync is a completely different mode of operation, and so by necessity the entire gameobject must change. Objectsync simply doesn't have a way to run in manual mode, and even if it did it would need to do so by changing the definition of manual mode.

So no, manual isn't compatible with objectsync, because they're very different things

north thistle
#

The only two networking methods I can imagine are designed to work well together are manual sync and events (and maybe also continuous sync and events)

frozen igloo
#

events are independent from the sync type, so they can run on top of anything

north thistle
#

Do you believe the increased suffering I saw occurring if I combined events (via a NoVariableSync script) and VRCObjectSync on the same object was caused by something else?

frozen igloo
#

I have no idea how that happened, but I know that network events go through a different pipeline that isn't dependent on the regular sync mode

north thistle
#

When I have the time I'll see if I can reproduce it in a clean project

timber ferry
#

i assume string?

north thistle
#

It's an int. Do people often store integers as a string?

twin portal
#

you mean I shouldn't be storing all of my numbers as "one", "two", etc.?

timber ferry
#

well, IDs sometimes have letters and numbers, depending what it is

#

i’ve never worked with player IDs before, so i didn’t know what they contained

#

like Minecraft player UUIDs for example, are a mix of letters and numbers separated by hyphens

twin portal
#

naur they're just an int that counts up, and they aren't unique to the player's account, just in that specific instance

#

first player that joins gets playerid 1, next gets 2, etc.

#

if playerid 2 leaves, they get a new id when they rejoin the same instance

timber ferry
#

ah right, i think i’ve heard that before

#

sounds like it makes a lot more sense to use for a tycoon ownership system…

#

what does GetPlayerById return if the player doesn’t exist? it just says it will return an id if the player exists, but doesn’t mention if it’s null or something else if they don’t exist

#

ints aren’t nullable are they? if not i guess it would return -1?

cedar crescent
#

ints aren't nullable, no. Although -1 is the most common stand-in for "null". Like string.IndexOf can return -1, for example

timber ferry
#

that’s why i was thinking it would return -1 for a non-existent player

twin portal
#

GetPlayerById gets you the VRCPlayerApi for the player, which I believe will return null if the player doesn't exist
though I think the script crashes if you try to GetPlayerById with 0

timber ferry
#

oh, right, i meant GetPlayerId

#

or wait, no i didn’t, man players and IDs are confusing

minor gale
#

you'd probably be interacting with the playerId property if anything, i think you're going for something like this

[UdonSynced] private int activePlayerId = -1;
void EnterPlayZone()
{
    VRCPlayerApi activePlayer = VRCPlayerApi.GetPlayerById(activePlayerId);
    if (!Utilities.IsValid(activePlayer))
    {
        // Player not found
        activePlayerId = Networking.LocalPlayer.playerId;

        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        RequestSerialization();
    }
    else
    {
        // Player is in the session
    }
}
timber ferry
#

seems about right

#

for some reason i was thinking i would get an int from GetPlayerById, but that’s what i would be putting into the overload

crude trail
north thistle
#

Yah I would assume that VRCPlayerApi.GetPlayerById returns null if the playerId doesn't match any player currently in the instance.

hoary frost
north thistle
#

I would hope it'd be better programmed than that. There's no reason why it'd need to throw an exception.

minor gale
#

it returns null (correctly) in what i'm seeing, the number on the left is the ID being polled, there's a space between the non-null clients because i tested it after one rejoined (making slot 2 null)

north thistle
#

Bitwise stuff is really cool. Have the chance to actually use it in my project to pack my network synced data.

simple wyvern
#

I had roughly 18 UdonSynced variables (16 ints, 1 bytes, 1 bool). The behaviour no longer syncs when I add an additional 16 byte variables. If I remove those, everything works fine. Here are some diagnostics ran by me:

  • All variables (including the newly added ones) are initialized with some values (like byte.MaxValue or such)
  • All variables are private
    • I think it's Irrelevant because all the other behaviours uses private synced variables and they work great
  • All variables have FieldChangeCallback configured respectively, with get and set (no private get or set)
  • Same 16 variables without UdonSynced works perfectly fine though
  • In Network debugging, the delay is noticiablely long (other behaviours stays roughly 0.1s to 0.25s, but this one goes over 0.5s)

What could be the issue? Is 16 synced variables too much? (I mean... the other behaviour's variable size is larger than 34 synced variables...)

simple wyvern
#

Update: temporary bug. I've removed the new 16 byte variable's UdonSynced, add UdonSynced to one variable, Build & Test, and repeated until which variable triggers the issue. I've tested all 16 newly added variables and now it works fine. (?)

finite sierra
fallow mountain
#

the issue could be too much Bps, are you syncing every frame?

fast pulsar
#

Question. Since SendCustomNetworkEvent is rate limited to 5 per second. If say it gets triggered 10 or so times instead, will it still eventually execute the 10 or only 5?

#

(e.g. player runs through trigger, code modifies list on owners end. Very lightweight)

twin portal
#

5 events will trigger, the other 5 will be added to the queue

#

but you can also increase the limit to up to 100 per second

fast pulsar
#

Oh, that's awesome to hear vrcDanceRat. I assume increasing the limit applies to the overall world or the script doing those calls?

#

Also when they queue up, do they wait for the owner to finish running the method being called by the network or does it interrupt it?

twin portal
#

they wait until the next second to continue

twin portal
fast pulsar
#

I see. That would be very helpful regardless though especially if I need to send more than 5 through the network especially during time critical events. Thank you very much for the info ❤️

fast pulsar
#

Hmmmm. I wonder. When it comes to player distance culling, do triggers still accurately execute when the player enters the trigger or would it be better to have the trigger executed by the one entering it then send the data over via CustomNetworkEvent?

north thistle
#

Udon's built in Player Collision events use a collider that we're not allowed to touch or directly interact with as far as I know, so I'm not sure what you mean by "player distance culling" in this context.

proper coral
#

Say I have code where i need to assign ownership of about 52 items to a player temporarily, is it worth storing the old owners to then assign them back after the operation completes?

twin portal
#

if you really need to return the owners, then yeah that's what you'd have to do

#

but do you really need to do all of that ownership transfer?

#

you could just have the target player request the owner to do something, rather than transfer

proper coral
#

would that be less intensive than transferring the ownership?

minor gale
#

it's not really intensive, it'd be more about avoiding race conditions. to your original question, there's usually not much impetus to transfer ownership back unless you have a specific reason

fast pulsar
#

usually when that happens their position can sometimes jitter

north thistle
fast pulsar
#

Maybe? Idk when I've joined a few people some in the distance can look like they're not moving smoothly but jittering unless its just a connection thing for me x_x

north thistle
#

Well VRChat does deprioritize the sync data of players far from you, so that might be part of it

fast pulsar
#

Yeah

fringe agate
#

Has anyone done a "Settings persistance for dummies" yet? I want to make my home world's settings (Perf Toggles, video players volume, ect) persist

north thistle
fallow mountain
#

put the script on a PlayerObject and put on a VRCEnablePersistence, it will save any synced variable on it
and wait for OnPlayerRestored to load before applying or syncing any variable for next time you join the instance

twin portal
#

you don't want to use PlayerObjects for something like persistent world settings

minor gale
#

it's potentially relevant if you expect to have a large amount of data on playerdata, but it could be a bit roundabout for a basic setup

timber ferry
#

if i have an int on a script that's on a player object, and i want to read from that int to display it on a scoreboard, does the int need to be networked?

#

i've used playerobjects one time ever, and am working on a project that i need them for

frozen igloo
#

but playerobjects can also have local non-synced non-persistent variables which can be accessed and passed around like any other

north thistle
fast pulsar
#

When it comes to player ownership, does an object's movement (e.g. an object attached to the owner's hand) appear more smoother than those who aren't the owner of the object?

#

or is it the same?

north thistle
#

movement is timing dependent; anything timing dependent is going to be smoother if it generated locally than something that has to compensate for the unpredictable timings that networking introduces.

fast pulsar
#

I see. Thank you

fringe agate
#

I think persistence is over my head for now vrcTupCry I'll wait for someone to make a tool or something that I can just reference stuff into that I want to be persistent, if that's even a thing that can be done.

woven trail
timber ferry
#

(i see why the score wasn't changing for the localplayer now, i have to call SetScoreText() in the ModifyScore method, so don't worry about that)

minor gale
#

polling every entry like that might be something you can avoid. it'd be possible to track them with a local data structure and only push changes to data representing the slot that actually updated. the text/position updates don't have to be done in the same instant if data is updated often. it probably doesn't matter if it's round based, this is more like what i'd consider if it's a constantly incrementing score with multiple players

timber ferry
#

it wont be updating very often, im helping someone with making disc golf in vrc, so the score will only update when a player successfully throws their frisbee into the goal. the difficult part for me, is figuring out how to have the "score" synced on the leaderboard, but not persistent, and the "highscore" display on the leaderboard if "isHighScores" is true, and be persistent. and i dont know how to network the positions of the players on the leaderboard. it's done by parenting them to a ui object, and having a vertical layout group sort them, meaning its based off their place in the hierarchy

foggy jackal
#

oh huh, disc golf would be great actually

minor gale
# timber ferry it wont be updating very often, im helping someone with making disc golf in vrc,...

you could look up selection sorting or bubble sorting for swapping their positions. the leaderboard itself doesn't need to be networked unless you need to sync the fact that it's displaying the score or high score

like if you want to save on performance for non-master players you could work out some way to sync them by player ID in an array where indices indicate position, but it's probably better to just infer the positions on each player (where they all do sorting logic), which is kinda what you're doing already i think, aside from sorting

finite sierra
# timber ferry it wont be updating very often, im helping someone with making disc golf in vrc,...

All you have to do is each person has a synced score value. and everytime someone scores it positions them self depended on the current scores of others. It can all be done manually and requires only to be sorted and ran when a score happen. But it does need to run for each person. And depended on the max score someone can get you can use a byte or short. If it's scores like 10.5 etc you have to use a double or float.

#

Cost wise you are only looking at 12 to 24 bytes I believe per person. That's included overhead

frozen igloo
fringe agate
timber ferry
#
public class PersistentToggleExample : UdonSharpBehaviour
{
  private const string PersistenceKey = "toggle";
  public GameObject exampleObj;
  private bool state;
  
  public override void OnPlayerRestored(VRCPlayerApi player) {
    if (PlayerData.TryGetBool(player, PersistenceKey, out bool savedValue)) {
      state = savedValue;
      Apply();
    }
  }
  
  public void OnClick() {
    state = !state;
    Apply();
    PlayerData.SetBool(PersistenceKey, state);
  }
  
  public void Apply() {
    exampleObj.SetActive(state);
  }
}
#

it's quite literally just save the value when it's changed, and load it in OnPlayerRestored

timber ferry
#

now i just need to know, what would be a good way of having it refresh for everyone when a score changes? would a network event suffice?

minor gale
# timber ferry alright, got it working much better now, with bubblesort and correctly synced/pe...

just inferring that a score has changed (via deserialize or serialize) would be enough i think. if you expect people to score rapidly, i like to do something like this to lock out rapid calls

on any score change

leaderboard._CallUpdateLeaderboard();


in leaderboard

private bool updateScoreRunning = false;
public void _CallUpdateLeaderboard()
{
  if (updateScoreRunning) return;
  updateScoreRunning = true;
  SendCustomEventDelayedSeconds(nameof(_UpdateLeaderboard), 0.25f);
}

public void _UpdateLeaderboard()
{
  updateScoreRunning = false;

  // Order them at this point
}
timber ferry
#

hopefully people won't be scoring rapidly, otherwise the game's broken or someone's cheating

but thanks, that should be pretty simple since i call SetScoreText(); in OnDeserialization and locally

finite sierra
proper coral
#

How can I instantiate an object for every player? Atm when I do it, only the player that spawns it in can see it, it's invisible to everyone else

strange token
proper coral
twin portal
#

a PlayerObject will automatically be instantiated for every player when they join
each player gets their own copy of the object

proper coral
twin portal
#

if you make it synced, yes

proper coral
#

Sorry, badly worded question. Say I instantiate an object for 1 player, will that object be created for everyone else too?

twin portal
#

yes

#

if it's a PlayerObject it will be done automatically

proper coral
#

👍 thanks

proper coral
# twin portal if it's a PlayerObject it will be done automatically

So I tried this with the following code but it only shows for the player that interacts:

public override void Interact()
    {
        Debug.Log("Spawned Tab");
        GameObject tab = Instantiate(Networking.LocalPlayer.GetPlayerObjects()[0], tabContainer.transform);
        Vector3 location = Networking.LocalPlayer.GetPosition() + Networking.LocalPlayer.GetRotation() * (Vector3.forward * 1.2f);
        location.y = Networking.LocalPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head).position.y / 1.2f;
            
        tab.transform.position = location;
        tab.transform.LookAt(Networking.LocalPlayer.GetPosition());
        tab.transform.rotation = Quaternion.Euler(tab.transform.rotation.eulerAngles.x + 270f, tab.transform.rotation.eulerAngles.y + 180f, tab.transform.rotation.eulerAngles.z);
    }
twin portal
#

don't Instantiate it yourself.... the PlayerObject will automatically be instantiated when the player joins

proper coral
twin portal
#

the PlayerObject will already create a copy for every player. Why not just use that instead?

proper coral
#

Ohhh I see what you mean! Sorry! My brain wasnt on the right frequency

twin portal
#

if you want to test PlayerObjects, just make a cube that's a pickup with ObjectSync, then make it a PlayerObject too
then do a test with multiple players and you'll see how they work

#

no new udon scripts required, you could even chuck EnablePersistence on it for fun

proper coral
#

When you say UI tab, do you mean a tab on the UI layer? Or a tab that uses a canvas?

twin portal
#

no don't put UI on the UI layer

proper coral
#

Yeah I have it on default but I wasnt sure which you were referring to

twin portal
#

your UI canvas, it's just a GameObject that you can reposition like any other object

#

when a PlayerObject gets created as a player joins, the copy will be created at the exact place that the original is

#

you can use the OnPlayerRestored event or Start on it to then move it to where you need it
Though maybe for UI you could just use one of those components that auto-layouts them

proper coral
#

I can probably just put them inside of the same thing, so that when it's needed it can just be grabbed

proper coral
#

Is there a way I can let everyone pick up a player object?

twin portal
#

nope, PlayerObjects are stuck being owned by one player

#

so other players can't pick up pickups

proper coral
#

So player objects is out of the question now

#

Might try and object pool and see if that will work

twin portal
#

yeah as far as I'm aware that's a drawback of PlayerObjects; they're intended to be a copy for every player, but specifically only for that player to use. Imagine a system where you want to give every player a sword to fight with, but that's their sword, nobody elses

#

I was going to suggest an object pool instead yeah, but could potentially get tricky if you want the objects to populate with player's info

proper coral
#

The info on them will be self contained

gentle dove
#

Is it just me or is OnOwnershipRequest not a thing?
It's in the documentation, but when I try to use it, it doesn't exist.

#

Oh nevermind, the return type had to be bool instead of void.

hoary frost
proper coral
hoary frost
light vine
#

I am trying to figure out if it's possible to update a vrchat world over networking rather than updating a world manually

Not fully update a world, but be able to modify certain parts, I want to see if there's a way I can update avatar pedestals in real-time without having to reupload my world, it would save a lot of time since my internet is slow

Is this something that is possible? If it is I want to look into it

twin portal
#

so the only way to update a world without a reupload would be any streamed data, like string loading or image loading

#

you could, theoretically, have a system where you have a text file hosted somewhere, then use string loading to download it once you join the world. This file can have a list of avatar blueprint IDs or something.
Then when the string loads, you can have an Udon script that programmatically changes the blueprint ID that's on the avatar pedestal

#

@light vine

light vine
#

Thank you for the info!

#

That helped a lot vrcPartyRat

foggy jackal
#

Rule #10

cloud plank
#

Can any1 tell me how to compile Udon...or help me with compilation errors?

timber ferry
#

ask in one place please

solar patio
#

Is ther someone that knows VJ/LJ stuff? im currently creating a world and i need to know stuff about their workflow and how they get data in the world

foggy jackal
#

DMX most likely

tropic granite
#

Is there a good document for array syncing? I'm trying to get long arrays of positions and rotations synced for late joiners, practically a history of object transforms. For normal use, it'd only need to add the added items, but a late joiner should receive the whole array.

So I'm wondering what would be the optimal way to sync them. Would it be to sync some other temporary arrays with just the added items and then initiating a full sync if someone joins? Or would a synced array be able to recognize that something has been added/updated and sync only those items? Or am I thinking in a wrong direction?

minor gale
# tropic granite Is there a good document for array syncing? I'm trying to get long arrays of pos...

it's probably more common to handle it at object level in vrc, but if you want to manage a history in an array you can (it'd be 2 arrays in this case, position and rotation)

if you can guarantee a consistent player hosting whatever you're doing, it'd be relevant to cache the history on them and send it over events to late joins, but it's more complex

otherwise you'll likely want to store the full history in synced arrays, if it grows beyond what you consider reasonable to sync in one step or you're updating it often, you could consider using multiple buffers

about whether arrays only sync changed items, they do not, they send the absolute/full state

you could also manage it in a string, but it'd have some overhead on bandwidth in terms of how much you can store

are you trying to manage instantiated items or what's the use-case?

tropic granite
#

Spray system, so storing the paths where the spray has been applied. I can render the painted texture analytically so it should be possible to 'replay' the data for late joiners to get the current state without having to start syncing big textures... If I can get the data synced.

Practically each frame that a spray is hitting a surface will create a record of the pos&rot. So... about 2kB/s/spray can 😬 it'll get big quick... maybe I can optimize it somehow later...

Anyways, I'm guessing the best bet would be to send the data over events then? Is the bandwidth limit outgoing or incoming? If it's possible to only receive ~10kbps, I might need to rethink some things... but otoh if every connected user can send data at that rate, it might be possible to send the history from multiple users at once like in p2p networks? 🤔 (if I can guarantee that each of them have the same history data) the rendering would probably become the bottleneck at that point though...

finite sierra
north thistle
#

It's actually around 11KB/s iirc but what is contributing to it is influenced by a lot of things.

Also the only thing that is only limited by the upload speed limit is continuous sync. Manual sync has its secondary, seemingly secret limit influenced by how often you are attempting to perform manual syncs.

#

I imagine that each player is regularly sending out network data that remote players are forced to send data back to the server about to confirm reception and that will count against your network limit.

frank fjord
#

Okay once again I'm diving into networking but it's been like 7 months since I last touched any of this.

Are there good modern docs for Udon# networking? The https://udonsharp.docs.vrchat.com/ docs have always been pretty lackluster and don't touch on a lot of frequently-problematic edge cases in ownership conflicts and the like

A compiler for compiling C to Udon assembly

#

For example, a question I've never really gotten a straight answer on is: what is the default fashion in which two clients rectify both players simultaneously attempting to claim ownership of a behavior? And if that default resolution mechanism is problematic, is there a better way networked world makers manage these conflicts?

finite sierra
finite sierra
north thistle
frank fjord
frank fjord
# north thistle why do you say that?

'cuz as far as I'm aware, it's true? Proton just repeats client messages to other clients that are connected to the same address, but the clients are sort of left to figure out the state of their respective game worlds on their own

#

It is effectively a peer to peer system, if not literally then in spirit

north thistle
#

The instance server handles at least a few things. For example an owner of synced data only needs to get that data to the server and from there the server will handle getting that data to everyone else, including late joiners

#

Specifically with manual sync data when it comes to late joiners

frank fjord
#

Mhm, I know. I'm... not precisely sure if that is contrary to my point though

#

In either case. I'm going to experiment a little with parameterized network events and see if my design can fit into the "never change ownership" approach

#

but... there's lots of reasons why that would be untennable for a lot of use-cases

#

I'd really love a deep dive on how to finely manage network ownership in a robust way that's highly edge-case resistant.

#

Wish I could find that sort of information or documentation online x"D

north thistle
#

My world uses ownership transfers, but it's exclusively managed by the instance master

frank fjord
#

Is that using the Request Ownership Transfer pipeline?

north thistle
#

It's using SetOwner

frank fjord
#

Also... how would that be possible? If the instance master isn't the owner of something, they don't really have the authority to confirm or deny an ownership request. Are you bypassing that entirely and --

#

ahh

#

yeah, that was my second guess

#

Curious.

north thistle
#

Also network ownership uses eventually reliability, in that there might be a period where it is incorrect, but it will eventually get to the correct state

frank fjord
#

A small personal nitpick. "Eventual reliability" isn't a thing that's being "used." It just is. There's no special system working diligently under the hood to assure this eventual reliability, it's just the nature of the system that it's NOT immediately bringing things into alignment. So the "eventuality" of this reliability is... really quite variable, based on your specific implementation.

frank fjord
#

... Is there some subtle difference in the way synchronized variables propagate for late joiners, when the instance master/behavior owner has changed...?

#

I'm currently investigating a bug where, if a player joins late and the original instance master (and owner of all synced objects) hasn't changed, they get all the synced variables correctly.

But if the instance master leaves and rejoins - resulting, presumably, in ownership of everything they had being transferred to the other player - they do NOT get all the synced variables.

Even more strangely, they do get a few synced variables, but ONLY the ones that the newly assigned instance master was around to see assigned at some point.

minor gale
#

if you request serialization and handle synced variables remotely in the deserialization event, they should work as intended for late joins, regardless of the master changing

#

though there are some nuances in doing that with objects that start disabled or in vrc's object pool (which also start disabled)

frank fjord
#

Is there any reliable way for a late joiner to know that they've received the up to date state of synced variables?

It looks to me from testing like Start() can run before synced variables arrive after joining

It also looks to me from testing like IsNetworkSettled can return true before synced variables arrive after joining

Finally, OnDeserialization appears to not always run for objects, on late-join, if the current owner of those objects hasn't seen any of the object's variables change since THEY joined (even if those variables were changed from their default values before they late-joined)

frozen igloo
frank fjord
#

OnDeserialization won't run on late join for objects whose synced variables haven't changed

#

But "haven't changed" appears to be fuzzy

#

It seems like if a player joins a world, gets a late-join update for a variable, but then never sees the variable change again... they can then later become the owner of that variable's object, and not send the previously updated variable to other late-joiners.

#

resulting in a desync where future late-joiners see the variable as its loaded default value, because the variable's new owner doesn't think the variable has 'ever changed' and thus doesn't replicate the value to new late joiners

#

This is pretty easily testable. If you output a log in OnDeserialization(), and just put a bunch of those objects in a scene, you'll see that, if you never make any changes to those objects, the log inside OnDeserialization never shows up for new late joiners

#

Then you can see this 'well it never changed for ME' behavior by having two players shuffle rejoins.

Have 2 players load into a world. Make a change to an object and serialize it. Have the non-owner rejoin; they'll see OnDeserialization for the one changed object run.

If you then don't change that object again, and have the OWNER rejoin, THEY WON'T see OnDeserialization run

frank fjord
#

At the recommendation of a friend, I tried to change my system to basically entirely use field change callbacks.

The same thing happens.

If I set a variable and rejoin with the non-owner, the non-owner gets field change callbacks and successfully updates the changed variable.

If I then do nothing, and rejoin with the owner, the owner rejoins and gets no field change callbacks and never gets the updated variable, even though the other player (who now owns the object) has a different, changed value for that variable

#

I'm steadily becoming more and more convinced that this is a network API bug :S I was ready to accept it was an error in my code yesterday, but now I've tried rearchitecting the system 3 different ways and the same behavior keeps happening:

If a late-joiner takes ownership of something, but its variables haven't changed since that late-joiner joined (even if those values were updated AS they joined by OnDeserialization), they will not send out those variables to other late-joiners...

#

Either that, or it's just an undocumented necessity that a player taking new ownership of something must always request serialization after they do so - even if ownership is THRUST upon them automatically by the original owner leaving - or future players won't get updates on late join

frozen igloo
#

If the variable has never changed and the object has never serialized - yeah, you're not going to get ondeserialization. If that's your problem, it's a quirk in the network API that I don't love but it's technically not a bug. I'd recommend ensuring that the master serializes those objects where this matters when they set up the instance.

If the object has been serialized before but then transferred ownership and the new owner never serialized so late joiners get nothing? That would be cause for concern, strictly a bug

frank fjord
#

Yeah. If a late joiner gets the state of an object when they join - that state doesn't change again AFTER that - and then they take ownership, it appears that future late-joiners do not get updates about that object.

#

I guess for now I can try just detecting ownership transfer and then forcing a serialization, see if that makes a difference.

frozen igloo
#

Yeah that's a safe bet

#

Should be serializing on ownership transfer anyway. What situation are you transferring without serializing? Or is that just due to owner leaving?

frank fjord
#

Owner leaving.

#

I'd never do an ownership transfer without serializing otherwise, but frankly I was and am making the assumption that VRC's networking api would handle making objects available to late joiners in the event of an owner disconnect, automatically

frozen igloo
#

Yeah that's odd

frank fjord
#

Well, good news is that I can at least fix the problem in my world by detecting the ownership transfer, and using that as a trigger to force a new serialization by the new owner...

#

Verified that works

minor gale
frank fjord
#

Nope, object sync is not something I'd ever like to touch lol

#

That's really strange that I'm getting this behavior very repeatably and you're not. The mystery deepens...

#

You using manual serialization I presume?

minor gale
#

yeah, manual sync

north thistle
#

Also object sync is amazing for what it is and as far as I'm aware it's behavior can't be replicated by any tools we currently have access to. My current project wouldn't be possible without it.

minor gale
#

if you mean the upper limit of manual sync yes, if you mean the fact that it can sleep, you can make that behaviour yourself in manual a number of ways

north thistle
#

I mean I don't think it's possible with our current tools to make something as network performant for non-predictable positional sync as object sync

finite sierra
# north thistle I mean I don't think it's possible with our current tools to make something as n...

if we did not pay the cost as we do for overhead we would be able to make it ourself pretty easily. all through its still possible to make it yourself with full control. but cost would be 48 bytes versus just 27 bytes which is the cost of 1 vector3, 1 Quaternion, and 2 bools.. making one yourself would allow you to do predictions which essentially could make it less costly far less so even. all through the manual limits is obviously making it very hard lol

vast agate
#

I would appreciate any help with this. I have a button that sets a count, and syncs it manually. However, it seems that the sync is one step behind the owner. The weird part is I have another script that syncs the same exact way and that one is up to date. Anyone know why this is? The section that syncs it to all players is run on the owner and is this script.

#
            startlives++;
            RequestSerialization();
            SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, nameof(UpdateLives));```
#

My only guess is that the serialization isn't completing before the Network event does

north thistle
vast agate
#

But why would that only happen on some scripts and not others? And would adding another custom event with just the send network and running it with Delayed event fix it?

north thistle
#

You're mixing two different networking methods and the timings of those two networking methods are not going to match each other

vast agate
#

You know, that's probably why the other script works, as I have an OnDeserialization function for late joiners

#

So I guess sending that custom network event would be redundant

north thistle
#

yah, and in this circumstance not a good idea as you can already tell

vast agate
#

OnDeserialization is run on all clients after a requested Serialization is completed no?

twin portal
#

everyone except the sender

north thistle
#

To put it simply, yes. In a bit more accurate description, OnDeserialization will fire whenever networked synced values are received on the object on a continuous or manual sync. This will occur shortly after an owner of an object sends out those new synced values for anyone currently in the instance and, for anyone late joining, shortly after the join the instance

vast agate
#

Thank you for the help, As an added bonus, one less network event required

cyan hollow
#

Hey, I need some help with teleporting an item spawned from a VRCObjectPool.

internal void SpawnDrink(Transform spawnTransform)
{
    Networking.SetOwner(Networking.LocalPlayer, gameObject);

    var drinkObject = drinkPool.TryToSpawn();
    if (!drinkObject) return;

    Networking.SetOwner(Networking.LocalPlayer, drinkObject);

    var objectSync = drinkObject.transform.GetChild(0).GetComponent<VRCObjectSync>();
    objectSync.FlagDiscontinuity();
    objectSync.TeleportTo(spawnTransform);
}

This code works sometimes, but sometimes the item won't actually be teleported, just enabled from the pool. Does anyone know what could be the issue?

foggy jackal
#

Does TeleportTo() work on non-players? I mean, you could simply just set the position and rotation of the object via its Transform

#

it should work for any object

cyan hollow
minor gale
foggy jackal
cyan hollow
tulip sphinx
#

no, why

cyan hollow
minor gale
#

they can be independent; if that were the case a pool with the intent you're using it for would fail to function if the pooled objects were children of the pool (if the intent was to allow different drink owners)

tulip sphinx
#

cause each script (or rather network ID-ed object) has its own owner, why changing owner on one would change it for some other object, child or not.

north thistle
cyan hollow
north thistle
#

A frame later will not work most of the time

#

It has to happen after the objectsync has fully reenabled its networking and will have predictable behavior again, and I don't think the amount of time that will take is strictly knowable.

#

You'll either have to wait a second or two and tolerate any potential edge cases where it doesn't work, or use a different object pooler that doesn't disable the objectsync object

#

I suppose putting your object sync in a parent object by itself while putting the child object in the VRCObjectPool instead (so the parent object sync stays active but the rest of the object does get deactivated) might work

minor gale
#

that sounds a bit messy in terms of inferring if a pickup collider should be active; or the pickup pickupable, but i guess if the collider isn't a concern

north thistle
# cyan hollow Why tf wouldn't it?

Also I can tell you from experience, being able to handle ownership on a per object basis instead of having to worry about ownership cascading down to children is way more convenient

north thistle
#

But that will require coding your own custom pooler. Worth it if you're doing something complex, but if you're just doing something simple the faster, more messy approach might be better.

vast agate
#

what does FieldChangeCallback do?

foggy jackal
#

runs code when a field is changed

hoary frost
vast agate
#

so basically OnDeserialization but for a specific variable?

strange token
#

All my networking is done with field change callback o/

north thistle
#

I'm more of a OnDeserialization user myself as it better captures the idea that it's a unified object getting synced rather than a bunch of individual variables

finite sierra
#

Field callback also fails if the value changes from the same value. To the same one again.

frank fjord
#

So while refreshing myself on the creator api, I noticed that there's this very stern warning on the VRCPlayerAPI page that says that code should always account for any player's device becoming suspended at any time, as suspended devices do not run Udon. Also, because suspended devices don't run Udon, IsSuspended will always be false for the local player.

... This seems like a huge design challenge. Is there any good documentation on design patterns that are recommended for this issue? Especially as it regards to networking. Like, it would seem to me like you can't even safely call networked events or ask for ownership - even if you check to make sure the owner you're sending networked messages or ownership requests to, isn't suspended - because that player could BECOME suspended during the half-ping between your clients. And then you'd just... get no response

twin portal
#

you could use this to detect if that player is the owner of something important, and transfer it if needed

#

I think I read somewhere that the Instance Master also gets switched if a player becomes suspended, but I can't find where it said that so don't know if that's actually true

frank fjord
#

Sure, but there's still a vulnerable window where players could think that the owner of an important object isn't suspended, because they haven't received that event yet...

Additionally, which player would assume responsibility for changing the ownership away from the suspended player? How would you determine that, rather than every client independently trying to do it—

Actually, now that I think about it. When you try to change the ownership of an object, isn't that ownership change event sent to THE OWNER OF THE OBJECT to be carried out by them? How would you change ownership away from a suspended player, if the suspended player cannot respond to or operate on Udon?...

twin portal
#

the ownership transfer negotiation is optional

#

so the suspended player doesn't have to respond, the player requesting ownership immediately can assume that they are the owner

frank fjord
#

I thought all ownership changes were managed by the original owner, even if RequestOwnershipTransfer isn't used

twin portal
#

no they don't have to be

#

that's how you can set owner, then immediately start using synced variables

frank fjord
#

I presumed that was a temporary local thing, and that other players don't immediately begin respecting your ownership conquest until the original owner fires off an event to everyone saying 'oh yeah they're the owner after all.'

And I presumed this was necessitated because if two players try to take ownership of something at the same time, there has to be some way for that to shake out. If there isn't any verification - automatic or manual through request ownership transfer - on the original owner, then two players could be led to believe they own the object at the same time, and never get corrected... or both correct each other into both NOT being the owner

#

I was just talking to someone about this the other day, actually. I was scratching my head over ownership race conditions.

If two players seize ownership of something at the same time, they both momentarily think they're the owner and can begin doing things with synced variables.

... Then what? If they both took ownership at approximately the same time, then they both send out events to other players, including one another, at approximately the same time. When each player receives that follow-up event that says "okay but this OTHER player took ownership," how do they know which one really has it? If there's no tie-breaker somewhere, either players A and B BOTH ignore the message, and now both locally think they have ownership (which clearly is broken), or they both HEED the message and LOSE ownership, potentially resulting in no one having ownership at all (which is also clearly broken)

#

Someone said this doesn't happen because players A and B both send their ownership transfer event to the original owner. And one of those two players' ownership claims arrives after the other, after the original owner has already given away ownership, meaning that that second player gets a callback, under the hood, from the previous original owner that says "uh no I can't give you that, I don't own that anymore"

north thistle
#

Does the suspended state even apply to Questies?

frank fjord
#

And this would necessitate that this ownership negotiation is occurring automatically even if you're not using the manual ownership transfer request system...

north thistle
#

It doesn't apply to PC players and considering the age of that documentation I don't see thet ever changing that.

frank fjord
#

I'd sure hope not! But

#

I dunno. Is this a 'feature' that veteran world devs all currently ignore, and just hope they'll never have to fix everything if it becomes necessary later?

north thistle
#

At least for my world, and my own personal design philosophy, the amount of design constraints it would impose isn't worth it for a "maybe" and I'd rather design without it in mind and redesign if needed in the future.

Don't want to worry about solving maybe future problems when I still have a bunch of problems today that need solving.

frank fjord
#

I s'pose

#

I just hope I don't discover that my game world shatters into a million pieces whenever a quest player joins the game

north thistle
#

That's why I'm curious to hear if anyone knows if Questies can get suspended

minor gale
#

mobile can, i don't know about quest, but it probably can if they can swap away from the app somehow. accounting for suspended state like the docs suggest is pretty unreasonable imo; it has some implications with ownership/master as the suspended player can be the master

minor gale
north thistle
#

Do we know that the server indeed manages ownership like I suspected?

frank fjord
#

There really should be something in the doc that clearly outlines the role of the proton servers

#

I'm tired of guessing x'D

minor gale
#

if that were the case playerids would be unreliable, photon does handle some aspects

#

ownership is likely one of those things

north thistle
#

The networking has changed significantly from the early days of Udon to my understanding

frank fjord
#

I mean yeah making sure that there is a database of players that messages should be repeated to, would necessitate that something like a 'playerID' exists on Photon... Proton? Whichever it's called

#

I know it does SOME things, it's just not clear at all WHICH things

#

especially when so much of the game does act strictly like it's p2p

twin portal
#

network serializations include data on who is owner of what; so the "winning" owner is whatever serialization ends up being sent out last
So whichever packet the server decides to send after, that's the winner

#

you generally want to design around not having simultaneous ownership requests, really

frank fjord
#

even if the server sends out timestamped messages

minor gale
#

it's not a response from the server actually, they just believe they have ownership

twin portal
#

it's absolutely possible

frank fjord
#

How do you 'design' around making sure two players don't click a button at around the same time?

north thistle
#

For my world, there is a lot of ownership transferring happening but the instance master is the sole authority on it

minor gale
#

you could send the request for their button press to a central authority (the master/owner)

frank fjord
#

Sure, yes, though there are significant challenges with doing that as well. Other edge cases that are just as hard to resolve...

#

... Regardless, it's not really my point here

#

we've kinda gone on several tangents ;P

minor gale
#

the ownership situation isn't great, you can respond reactively (dropping a pickup if you lose ownership while held is a good example)

north thistle
#

Also ownership transfer isn't always necessary

You can have clicking on a button instead send an event requesting the owner of the object to do something

frank fjord
#

Point is, 1) clarity on how important or not-important "IsSuspended" conscious design is right now, would be nice, and 2) what on earth is Proton responsible and not-responsible for

frank fjord
#

and this suspension issue might be one of them