#udon-networking

1 messages · Page 30 of 1

potent lance
#

could someone look at my code. I'm trying to make a script that displays a synced array of players within an area, It works in the editor but not in game.

sick gull
#

Have you looked at the example script in example central for a join zone?

humble girder
north thistle
#

Haven't tested it, though

vapid pagoda
fallow mountain
#

and is this dead code?

restive cliff
north thistle
#

don't include the base stuff for VRC override methods; you'll be calling an empty function and acomplishing nothing but a slight performance cost

potent lance
#

i've moved UpdateDisplay to the GameManager script and and am now using OnPlayerTriggerStay. It now works for everyone but the Owner

restive cliff
normal sundial
#

does anyone have that overhead spreadsheet calculator

twin portal
normal sundial
#

oh neat ty

warped latch
#

Is there a good way to test player leaving in clientsim? There's an add remote player button, but nothing for removing

humble girder
chilly osprey
#

Uhm my syncedobject is synced until I trigger this respawn button trigger I made when someone is still holding it.

reproduction:

  1. Hold the object on one user
  2. Click the respawn trigger on the other
  3. hold the object again
  4. see it is no longer synced for either of the players

Do I just add a drop method?
Edit: I tried, but nope that didnt work

minor gale
chilly osprey
#

respawn script is on a box mesh that I made a button

the pickup and object sync is on the camera object itself

minor gale
#

if you set the sync type of your script to manual you'd be able to do the custom network event version i described

chilly osprey
#

on the respawn?

minor gale
#

in the inspector where it says Synchronization: None

chilly osprey
#

okey

#

and then a custom network event you say?

minor gale
#

i don't have unity or graph open right now, but you'd want to send a custom network event upon interact

the custom network event, when triggered, should use a branch node, the condition being that the person seeing the event is the owner of the gameobject you want to respawn

if they are the owner (true branch), they should drop the pickup and call respawn

chilly osprey
#

as long as the owner is holding, then it wont respawn correctly. otherwise when its not held its not a problem

when they're holding the object they dont need and cannot press the button, which simplifies the logic

minor gale
#

you only want it to respawn if it's not held then? you can check that after the ownership check if needed, on the pickup itself, it can tell you if it's currently held

chilly osprey
#

nope thats also not what I meant

minor gale
#

i am not sure what you're asking then, sorry

chilly osprey
#

Im just saying: when its NOT held, then the respawn works fine.

when it is held the respawn desyncs the object. requiring a full rejoin to work again

minor gale
#

i was suggesting an alternative that forces the current owner to respawn it, which bypasses the idea of the player pressing the button respawning it, which means it wouldn't desync to begin with

chilly osprey
#

hmm right

#

anyways, so I trigger a custom event like this? I guess

minor gale
#

personally i think you should call the event directly from the interact, unless you want the logic to differ when it's held vs not held

#

you'll need to define a custom event with a name and make the custom network event reference it by name, in the eventName field

chilly osprey
#

well if the object is not held, then it doesnt matter whose the owner.

chilly osprey
minor gale
#

i believe it's called custom event, the node

#

it has an impulse coming from it

#

you'll be able to name it and select it from the eventName dropdown

chilly osprey
#

hmmm

#

or does it need to drop first

#

I guess it probbabbly would

minor gale
#

atm that will make everyone call respawn, i don't know what that does; you may want to force everyone to drop the pickup when they see the network event and then branch after the custom network event based upon ownership

#

oh i'm wrong, the network event targets owner

#

so that should work

chilly osprey
#

you sure?

#

haha

#

alrighties,, time to test

minor gale
#

actually it targets the owner of your external script

#

not the owner of the pickup

#

so you will need the ownership check prior to the respawn, you actually want it to target all

chilly osprey
#

hmmm

#

not the greatest of codes but sure

chilly osprey
# minor gale so that should work

Thank you for the idea.

I do see some input delay between the button click and the camera/object being respawned, but it does not desync.

strange token
#

Input delay is expected in VRC

#

Networking isn’t instant like other games

minor gale
#

you could attempt the first approach i described if you want it to be locally instant afaik, but i don't really trust the order of that interaction and it'd require you to place a script on the pickup itself too, to check for the ownership transfer event

chilly osprey
#

honestly I dont really mind.
I just wanted to be able to respawn the camera if it was missing (either left behind or still in someones hand) without it desyncing.

so yeah this input delay is fine.

thanks guys

north thistle
# strange token Networking isn’t instant like other games

TBF I think think there is any game where Networking is instant. Networking is a pretty complex topic with many different ways to approach them, all with their pros and cons.

For general usage the way VRC approaches networking seems pretty good. The biggest issues is that VRC's networking being a jack of all trades, it isn't particularly good at specific things.

iron burrow
#

why i keep having this issues

#

nvm

#

ive find the issues

fallow mountain
#

network id utilities

zenith shard
#

Hewwo ^^

I'm about to debug my Udon networking shenanigans and I wanted to know if there is a way to do it with the unity debugger ?

My assumption is that it's not possible and that I'll have to upload a private version of the world and ask friends / create a second VRC account

strange token
zenith shard
#

haaaaa

#

now that'll be usefull ^^ thanks

north thistle
#

I'm pretty sure you can also have alt accounts load into a local-only world via the VRC Quick Launcher (go to the VRChat Creator Companion and then Tools)

at the very least it also allows to test late joining even without an alt account

tulip sphinx
#

if four players under the same name is fine then build and test is enough, for 2 under one and 2 onder the others (actual vrc accounts) you want vcc launcher

strange token
#

I’ve always hated not being able to have separated names 😅 I see now that you can

north thistle
#

build and test supports up to 8 iirc

#

and that might be the player limit overall for a local world

#

Also does anyone know whether or not it is possible for Networking.IsOwner(gameObject) to be true within OnDeserialization?

For example can player 1 sync values and then leave; and then player receives ownership after which they receive those synced values?

fallow mountain
#

it should be possible during the window if you set ownership locally and before the actual owner can say no and your ownership goes back to the original owner, which in theory takes at least your RTT + the owner's RTT which can total quite a bit of time; during this time the "actual" ownership is still with the original owner so it should be entirely possible to have received syncs and getting OnDeserialization to fire

north thistle
#

There is the possibility they designed it so if someone sees themself as the Owner of an object they reject remote sync values; that way an Owner that tries immedietly setting values after taking ownership doesn't have those values randomly changed on them

fallow mountain
#

I dont know if that is the case but I have certainly experienced something like that, like picking up something and having it glitched back and forth like it is confused about its position

north thistle
#

well that's VRCObjectSync I presume, which uses its own special networking

warm steeple
#

yea I did notice the glitching when transferring ownership

#

also using object sync

#

but somehow making my own udon behavior with cont sync was way worse than just using object sync

strange token
#

continuous sync having a smaller limit than manual makes it sound like the worse possible thing lol

normal sundial
#

Hi, so I asked this awhile back but I want to get confirmation since I am now going forward with implementing networking. For network events, if I have copies of a u# script (think a copy of a network manager class for a board game, several identical boards per world) and i call a newtork event with a named target, will network events know implicitly which script to send the network event to, even though the scripts will have identical names of files/methods/objects, or will I need to figure out some way to discriminate between each table copy i have in the world, i.e. with a table id

#

The example in mind is
table 1
table 2

literally copy pasted in unity, so same everything
player 1 interacts with table 1, calling SendCustomNetworkEvent(NetworkEventTarget.All, nameof(Foo)). Will this trigger Foo on table 1 and table 2, or just table 1? If not, should I add a variable to discriminate between tables?

fallow mountain
#

just table 1

normal sundial
#

very convenient

#

suspiciously convenient vrcCatSquint

fallow mountain
#

They are different instances of a same script, you can imagine they being different scripts just with exact same code

normal sundial
#

Sweet, I was hoping that was how it works

#

that makes my approach easy

#

many thanks

fallow mountain
#

You can send network events to a targeted instance of a Udon Behavior, but by default if you dont taget anything it just targets itself, so it is just table 1 in your example

#

Alternatively if you target table 2, it will just be table 2, but not table 1

normal sundial
#

When the docs say this, this means across all networking events in a world?

fallow mountain
#

for one client, yes

strange token
#

I’ve never even heard of that

#

I guess cuz I rarely use networked events

fallow mountain
azure swallow
fallow mountain
#

its one video afaik

rigid temple
#

How is that video not pinned yet

wooden sentinel
rigid temple
#

yipee

finite sierra
fallow mountain
#

Global as in for all people in an instance? I vaguely remember testing this to be local only but maybe I rememberd wrong

#

That makes things complicated if someone wants to do events like rapid gunshots with several people firing at the same time

twin portal
#

The docs refer to it as "global" as in, the 100 event limit shared across all UdonBehaviours, but not shared between players

#

Local clients have literally no way of knowing how many events another player is sending at the moment of them sending it anyway

north thistle
#

I swore it was pinned. Did it accidentally get unpinned at some point?

tawny basin
#

For anyone who's created games that use a single player as the "source of truth" for game logic to prevent cheating or other
How did it go for you?
Is the latency bad?

marble berry
#

helo quick question
Where can i get the prefab path/name to use for Networking.Instantiate ?

tulip sphinx
#

@marble berry thats not a thing, instantiated stuff cannot be networked on its own

marble berry
#

huh

tulip sphinx
#

every networked object has predetermined network id on upload

#

instantiating and syncing stuff consists of some external script doing network part or reusing a pool etc

marble berry
#

Should i use object.instantiate to instantiate gameobjects ? it works in editor but not in vrchat for some reason
i thought networking.instantiate was the thing to use to fix that
the script is the thing doing the networking, its just instantiating a mesh for a visual

tulip sphinx
#

yes. In Udon its VRChat.Instantiate node but in u# iirc you just call Instantiate

marble berry
#

hmm, i have to figure out why insantiate doesnt do anything in vrc

#

i know the code runs because it logs right before and right after, but the object isnt instantiated

#

its a method that is called through network and instantiates one mesh, it should work i think, unless instantiating is affected by networking one way or another

#

also yes its U#

tulip sphinx
#

instantiating runs locally for everyone who received an event, thats the idea

marble berry
#

yeah thats what im going for

tulip sphinx
#

@marble berry are you sure your object to instantiate is valid for everyone?

marble berry
#

what do you mean ? that its instantiating the right object/isnt instantiating nothing ?

tulip sphinx
#

well maybe they dont have an object reference set

marble berry
#

it should work but im not sure how to test that, it doesnt throw any errors so i didnt think about it much

#

ima change some stuff around and test that

#

got it working ^^
it was in fact the references missing due to how they were set i assume, im surprised that made no errors and worked fine in the editor
Thank you !

#

Another little question, are local (self) network events instant or is there delay compared to directly calling a method ?

twin portal
#

they are instant, and also ignore the network event queue

marble berry
#

nice nice thank you :3

twin portal
#

and not just if you target Self, it's for any event type that would end up targeting self
(like when All sends to self, or if Owner is also the local player)

minor gale
# tawny basin For anyone who's created games that use a single player as the "source of truth"...

with network events the latency is pretty much just the latency between the players, so it being bad depends on what you're doing or the players involved

if you're awaiting a player to shoot a gun, that would feel bad

if you're awaiting a player to place a block on a grid, it might feel fine

i wouldn't really frame it as preventing cheating though, in the worst case the host could be the one cheating. it's more like central actions are something you can use if it makes more sense logically

tawny basin
#

Yea, I had that in mind
The whole hacker just being the host to send out host truths
Something I'd be fine with

#

Prevent nott erm
Eliminate sorta deal

#

Though, I have to wonder if it's even worth the implementation at that rate even still

sick gull
#

Feel like atp its gg.

tawny basin
#

Yeah I guess it's the difference between all lobbies being compromised or when they manage to get game host
But ugh
Maybe they can just give it to themselves or something
p2p makes my blood boil

warm steeple
#

vrc isnt p2p tho

wise pawn
#

It is. It only uses a server as a go between for the info for security and such, but doesn't do anything with that info. Just passes it along to the other user.

minor gale
true magnet
#

I have my data fields set up like this:

[UdonSynced, FieldChangeCallback(nameof(ScoreData))]
private string[] _scoreData = new string[GameController.MAX_PLAYERS];

public string[] ScoreData
{
    get => _scoreData;
    set
    {
        _scoreData = value;
        OnScoreUpdated();
    }
}

I feel like this should work when later in the code I do something like this:

ScoreData = newScoreData;

However it seems like the FieldChangeCallback never fires. Is that because it's an array and it goes by reference or something?

#

Or is it something like Udon comparing and updating the ScoreData array by index and only assigning into the individual entries of the array, never actually reassigning the entire object?

twin portal
#

yeah it being an array will affect it.

#

FieldChangeCallback only works if the value of the variable changes to a new one; but in the case of an array, this does not include the array contents. Since, if you know about arrays, the actual "value" of the array is the pointer to the array's contents, not the contents themselves

#

so for FieldChangeCallback to fire for an array, the entire array would need to be reassigned

true magnet
#

Right, but I am in fact reassigning the array on the object owner

#

ScoreData = newScoreData;

#

I was wondering if Udon on the network recipients is not actually reassinging the array if it figures out that they are the same length

#

and it only diffs the elements or something

twin portal
#

it should still be seeing it as a different array, since the pointer will have changed

true magnet
#

On the data owner it does

twin portal
#

(this is usually why, for arrays, I wouldn't use FieldChangeCallback)

true magnet
#

It just doesn't work right I assume?

#

I'd assume it's like what I presumed, which is that Udon does not automatically create a new instance for the array assign if it can avoid it

twin portal
#

does the serialization actually succeed when you sync it? Or is it OnScoreUpdated that you're not seeing fire?

true magnet
#

No, the property setter is not being called

twin portal
#

hm... how you have it should work

true magnet
#

Yeah you'd think haha

#

it's very strange that it doesn't

minor gale
#

i'm pretty sure it doesn't create a new array if the length is the same

#

on remote

twin portal
#

that would explain it

#

but be really weird

true magnet
#

yeah, it makes FieldChangeCallback just not behave properly with arrays at all

#

What would be the best alternative then?

twin portal
#

You could just call OnScoreUpdated in OnDeserialization instead

true magnet
#

I've looked at that function before, but within it I can't really tell which field got updated, right?

#

so if I've got multiple fields that get synced, they would all need to have the same handler code

minor gale
#

unless you're like incrementing something locally when the score changes there's not much difference calling your OnSomethingUpdated methods in series

true magnet
#

I have omitted my client prediction code from what I've shown above

#

wouldn't be too bad to update all of it, but it'd be cleaner not to

#

So looks like OnDeserialization is best practice then for arrays?

minor gale
#

i'd consider OnDeserialization best practice in any case personally, because you can read stale values if you ever try to access values other than the one being changed in fieldchangecallbacks

true magnet
#

Yeah that's true

twin portal
#

yeah FieldChangeCallback is best for a value that's handling some kind of state, and doesn't depend on any other networked variables

true magnet
#

I was more thinking about reducing computing cost as much as possible, but I guess it's not too bad

true magnet
#

either way, I'll be doing it with OnDeserialization, thanks for the help you two :)

true magnet
#

I guess one way around it is to serialize the array data into a string and send that over the network and then deserialize it in the callback

north thistle
#

I know I've long stopped using FieldChangeCallback because it personally never really made sense to me to use

minor gale
#

if you really want to mimic the fieldchange, you could cache the latest. check the cached array length, then elements, against the new array and only fire the change method if it differs at any point

though i wouldn't personally structure it around that, i think it's more clear/clean to simply reinterpret the absolute state of the networked variables at any point they come in

strange token
#

my latest solution is to send an arrayUpdated event that makes other players run a delayed event using Time.realTimeSinceStartup - SimulationTime(NetworkCalling.CallingPlayer) as the time offset, so you wait for their data to finish serializing

#

the reason I chose this way this time is because not all players need to run the arrayUpdated, so they can check in the networked event first 👌

marble berry
#

Is there a way to send a custom event to a specific player ? should i just send an event to all with the target playerapi as parameter and each recipient checks if its them on their own ? or is there a proper way to do this ?

fallow mountain
#

unless you are targeting NetworkEventTarget.Owner yes that is pretty much the only way

marble berry
#

oki thanks ^^

marble berry
#

Can a joining player receive custom events as soon as OnPlayerJoined triggered for others ? or can there be a delay before they can receive custom events ?

marble berry
#

looks like it works
nice

normal sundial
#

when sending an empty string over the network, or an array of empty strings, will udon convert it to a null string? I'm getting a weird issue where i send precisely empty text, but when I am checking the text on the receiver end I am getting (mystring != "") returning true instead of false like i would expect

heavy spindle
#

Might make sense to Debug.Log the typeof(mystring) and the value

#

If you are directly comparing the Arrays as well instead of the elements, quite a few languages will always return false unless they are the same reference

normal sundial
frozen igloo
normal sundial
strange token
#

never heard of that until now, that’s some good knowledge right there

true magnet
#

Is it best practice to mark all my UdonSharpBehaviors that don't have any UdonSynced variables with [UdonBehaviourSyncMode(BehaviourSyncMode.None)]?
I'm not sure if it would create network ids for GameObjects with those behaviors even if they don't store any network synced state, or if that would affect network performance.

minor gale
true magnet
minor gale
zenith shard
#

Hewwo ^^'
is it possible to SendCustomNetworkEvent with arrays as parameters ? (int[] and byte{]) ?

#

in the manual, it says that UdonSync types are supported and at the bottom of the type page there is a mention for arrays

#

am doing some testing

twin portal
#

The total size of all parameters in a single network event cannot exceed 16 KB.

zenith shard
#

I just tested it and yeah it works, I'm just putting BS in the arrays ^^'

Thanks for the tip though

brave panther
#

having weird issues with an NPC that I have walk back to its start point at the end of game. The NPC is VRC Object Sync'ed. Position is sync'ed fine. When there's only one player in the instance
transform.Rotate(0, 180, 0);
works just fine. If a second player joins, my NPC moonwalks. Not sure if the Rotate is firing n times, or not at all.

#

I don't bother with setting ownership on the NPC since no player directly interacts with it in any way. The rotation is sync'ed (we both see the same thing), it just doesn't seem to trigger with multiple people (or it's happening multiple times - not sure yet)

#

Is using gameObject.transform.Rotate just bad practice for Udon networking?

#

Do I have to do something like
SendCustomNetworkEvent(NetworkEventTarget.All, nameof(TurnAround));

public void TurnAround()
    {
        transform.Rotate(0, 180, 0);
    }```
fallow mountain
#

Moonwalks for who? Who is the owner?

brave panther
#

Everyone in the instance. Instance owner would own the object

fallow mountain
#

That would be the problem, instance owner had nothing to do with networking object ownerships

#

Since both clients thinks they are owner and rotate it and then the real owner syncs it and it rotates again and it is just constantly having schizo moments about what it should do... you should do a check before the rotation to check if local player is owner

#

If not owner, dont touch it, it aint yours

#

There should be only one owner per object, you can transfer it but that is beyond your situation

brave panther
#

okay, so I'll add a Networking.IsOwner check and play around with that. Thanks for the insight!

jolly star
#

as a suggestion, Id say stay away from object sync on npcs and instead give networked destination goals or tracking targets and let all the calculations of movement happen clientside, specifically with nav agents. Only have the owner calculate out a target/destination and send that to everyone. Its much lighter on the network and gives you way more control and scalability.

warm steeple
#

that would be great except almost all of my npc logic runs on the owner, without object sync the position desyncs

#

it works fine if it's only one in the world but with many of them it would be a problem yeah

zenith shard
#

Hewwo,

I'm doodling with players atm and I have a question :

When a player joins, OnPlayerJoined is called
There is also OnPlayerRestored whne the player's data are loaded and ready.

If I want both the player to be joined and it's data to be ready, what should I use ?

I assume OnPlayerRestored is my man ?

twin portal
#

if it's persistence data you're waiting for, then yes you want OnPlayerRestored

zenith shard
#

it is yes

#

thanks ^^

true magnet
warm steeple
tropic cedar
#

ok i have an elevator animation for a map and it auto moves up and down but its dsynced anyone know how to make it use the first joins animation time or something?

chrome kayak
# tropic cedar ok i have an elevator animation for a map and it auto moves up and down but its ...

there's a number of ways to go about it, but what I would do is have the game master sync some variables whenever a player joins. These should be the server time and whatever you use to sync the position of the elevator. Then on deserialization, you can use CalculateServerDeltaTime() to get the difference between the current server time and the server time that was synced in order to accurately set the position of the elevator.

https://udonsharp.docs.vrchat.com/vrchat-api/
https://creators.vrchat.com/worlds/udon/networking/

Multiplayer experiences are at the heart of VRChat. To create a world that reacts to players and synchronizes data between them, you need to understand networking in VRChat.

#

I haven't really done much networking myself, so I'll probably not be great help with this, but from what I've seen in the research I have done, this would be the correct way to go about it

tropic cedar
#

how would i do that tho for animations using animatiors? i know how to for phyiscal objects like pickup but idk

chrome kayak
tulip sphinx
#

@tropic cedar main question is how long is that animation

tropic cedar
#

25sec

tulip sphinx
#

huh not great not terrible. easiest way to go round this would be just syncing animator param tho youd need more than just one state animation

#

ie, elevator is down, elevator is moving up, elevator is up, elevator is movin down each of them being its own state with its own parameter

tropic cedar
#

its one long animation that loops

#

but i think i might be able to

tulip sphinx
#

ie its running unconditionally

#

?

tropic cedar
#

yes

#

just looping from start

tulip sphinx
tropic cedar
#

ok

tulip sphinx
#

most pcs do have a properly synced time anyway

#

otherwise itd be an owner storing animation start time timestamp and then setting animation to some percentage of that locally. doable ofc but not entry level

fallow mountain
#

The SDK video player example prefab uses essentially the same basic principle, maybe it can adapt to a animator

olive quail
#

I was confused here, on https://creators.vrchat.com/worlds/udon/networking/
In bubble gum example it got no attributes for "Trigger" event that being called to the network for all users and yet in "Network Events" page it says the method must use [NetworkCallable]

currently I'm getting "network event ... does not exist on target udon behaviour ..." which I fixed by adding [NetworkCallable] to that event

tldr issue is fixed but docs got me confused for a moment

Multiplayer experiences are at the heart of VRChat. To create a world that reacts to players and synchronizes data between them, you need to understand networking in VRChat.

minor gale
twin portal
olive quail
twin portal
#

Yeah that would do it

jolly star
#

How do we deal with race conditions with vrc object pool spawn at specific locations over the network? Network events are randomly firing before the vrc spawn is firing unless I put a huge delay on the event and that never guarantees network latency conditions so it might just fail anyways if you are far from the host IRL. Setting synced variables directly doesn't seem to want to work. I set the variable, and then do an on change it wont fire, I'm guessing it's because the object is disabled by the pool and this is happening before the object is spawned.
Am I expected to build some big queue system for spawns and queue up vector3 positions and push/pull them when the object is confirmed available because that just seems insane.

#

IIRC think in backrooms corrupted I had like a holding area for the objects/enemies and with huge mutli second delays to let everything settle but there has got to be a better way.

tulip sphinx
#

@jolly star at that point stop using vrc pool, just disable stuff on object. idle vrc sync doesnt produce any network load

jolly star
#

You mean use object sync but then disable it after the object is settled for a late joiner?

tulip sphinx
#

i mean for pickup make it invisible+no collider+kinematic, then its as good as nonexistent for a player without disabling an object with networkin on it.

#

vrc pool is an edge case where its okay to disable networked objects, until it breaks cause you need to apply smth to it, not just spawn, then it is easier to avoid it

jolly star
#

I suppose you could do everything manually but that seems like a lot of extra work to manage lists of objects and their sync states for late joiners and in-game networked players versus just having a holding zone with a ~1-2 second delay on spawn before being allowed to manipulate things.

I suppose my frustration is they have this feature to save a lot of effort but it is and has been very obviously broken and could be hot fixed by just adding a parameter for tryspawn to take vector3/quat for a spawn location.

north thistle
#

Yah generally speaking you want VRC networked objects to always be enabled and instead disable the renderer/collider/etc components to "disable" it

#

the VRC Object Pool is only really designed for very simple use cases

warm steeple
chrome kayak
#

Is there any better way to sync fast moving rigidbodies? I have a basketball in my world using vrc object sync, but for remote players, when it bounces on the ground, it typically ends up appearing to float, like it bounces about a foot or two off of the ground

tawny basin
#

Networked ball physics
The bane of game devs everywhere
Is there any room for determinism or states in your project? Or do you want the players to physically control the ball all the time?

It's the difference between a "dribbling state" which can be easier to sync vs a full on physics sim over the network

normal sundial
#

Can I use VRCPlayerApi.SimulationTime to check who the player who has been in the world the longest is? If no, is there anyway I can check how long a player has been in an instance without leaving?

#

I could do something myself but I would really rather not

minor gale
#

typically they'd also be the master

normal sundial
minor gale
# normal sundial is this true regardless of how old the instance is or who joins and leaves? i.e....

player ids aren't recycled and are given out in order of joins, so the eldest being the lowest should always be true

whether that person is always the master is questionable because vrc may prioritize more stable players to be given master at the point of the master leaving; the master can also go unresponsive for long enough that master is transferred, but i'm not 100% sure what the rules are right now; vrc has changed them a few times

normal sundial
north thistle
zenith shard
#

Hewwo
I have void OnPlayerRestored(VRCPlayerApi player) being called twice for the same player, is it normal ?

I know it is called once for every player joining but I didn't know it'd could do that multiple time for one player ?

#

Am double checking atm

fallow mountain
#

my understanding is it shouldnt

zenith shard
#

so I thought but looks like it is

#

I'll just ignore the second time

fallow mountain
#

is it in quick succession or after a while? what happens with the data after the first and second?

zenith shard
#

in quick succession

#

I get
player 1 restored
player 1 restored
player 2 restored

#

it is the the multi client vrc test though ? so could be why

fallow mountain
#

maybe

twin portal
#

not sure why that's happening, but depending on what you're doing you could use OnPlayerDataUpdated instead; this event gives you info if the data was actually changed or not, so you can use that to check if you actually need to update anything with the data

zenith shard
#

hou that could be usefull indeed

#

thanks ^^

normal sundial
#

Do we have a way in udon sharp to detect specifically the start and end of a click interaction with a trigger? I.e. OnInteractClick and OnInteractRelease

strange token
#

why do you need these events? I don’t think they exist like that 🤔

fallow mountain
#

From memory there is, on use down and on use up, something like that i cannot check right now

young thunder
#

That would be for the player's controller inputs

#

I don't believe you can get a "release" event for an interaction -- it's an instant thing

#

However, you can note when an interaction happens, then watch for the corresponding input event

normal sundial
#

I suppose I could coopt interact to start a timer and then use that in addition to onusedown and onuseup

tender vapor
#

Does anyone know when the "VRChat Udon - What is networking" video says "join world -> get latest data -> onDeserialization event fires for them for every networked object"

Does the "get latest data" part mean latest variable values?

chilly osprey
#

yes-ish

true magnet
#

When a player joins a world, they receive the current state for all networked objects automatically.

north thistle
tender vapor
true magnet
tender vapor
#

Thank you very much for the information, I really appreciate it!

normal sundial
#

I ended up figuring out a pretty consistent solution using a combination of Interact() and InputUse events

#

Just needed a "hold for x seconds to trigger interact" thing

clear ocean
#

(this does have Udon networking was the start of the problem also I don't know where to put this) I'm having a big problem and its not even my fault. I did 4 instances by mistake. I was testing the networking. Now every time I enter my world it says unusual account behavior. I changed the networking Ids and now I get the offline problem. And still the unusual account behavior every time I try to test build my world or enter into it playing vrc. The unusual account behavior started when I was doing networking with Udon sliders then it just happened.

fallow mountain
#

Yeah that sounds like the problem

clear ocean
#

I have even made a new world file. Still does the "Unusual client behavior"

fallow mountain
#

try delete the slider with the udon

normal sundial
#

Is there any concern about the number of network IDs you have in a world? I've ended up with about 400 or so, and if there is a concern with the number, what's the best practice for keeping the count low?

minor gale
# normal sundial Is there any concern about the number of network IDs you have in a world? I've e...

i consider there is likely some overhead for network object count, but if you're using pooling it might be necessary (i'd consider 400 okay personally, but it depends what you're doing)

if you can bundle multiple objects together logically that can help. imagine i have 9 bricks representing a wall that players can damage, each segment of the wall can be destroyed

instead of holding 9 synced objects (1 per brick), i could hold 1 synced object per n bricks, syncing their states on an array, which remote players can apply any time states come in

in my example you'd want to balance how many objects you bundle, to make it both advantageous for sync count while keeping it low enough that it can be synced as often as needed

normal sundial
#

One thing that struck me as odd is that even though I have my other scripts marked as [UdonBehaviourSyncMode(BehaviourSyncMode.None)] it doesn't seem to stop it from creating a network id for the script

minor gale
#

are they just pickups contributing to network ids?

normal sundial
#

i guess

minor gale
#

i wouldn't worry about it then

normal sundial
#

nice

minor gale
#

some components are always given a network id

#

afaik

normal sundial
#

Ok I was hoping that was the case. So the actual count isn't that important, more what happens with those network ids?

minor gale
#

they're just numbers used to refer to the object, i don't know if they iterate them periodically if they lack udonsync behaviour

#

i would hope that yeah, if it doesn't have an udonsync behaviour that it wouldn't contribute to overhead

normal sundial
#

cool cool, thanks for the help as always occala.

clear ocean
clear ocean
normal sundial
#

I noticed my network id count was scaling as I add more copies of the prefab im working on developing, and just wanted to head off any possible issues before i ran into them

clear ocean
normal sundial
#

this is why i don't trust anything given to me

#

make it from scratch u know it works 👍

clear ocean
#

With world building in vrc you never know what will work. It always wants to break. I have had the same udon code break in 1 world because of stations.

normal sundial
#

Yeah it's one of the reasons I decided to do everything from scratch

#

if something breaks I know it's something i wrote, and therefore something i can fix

#

i just dont like having blackboxes in my code

tulip sphinx
normal sundial
#

👍 i have 0 continuous or manual syncs in my world as of now

#

just network events

fallow mountain
#

try regen network id

north thistle
# normal sundial Is there any concern about the number of network IDs you have in a world? I've e...

If you're looking at the id count in editor, I'm pretty sure every single GameObject with a UdonBehaviour on it gets assigned a network id, even if it has networking disabled. This is likely the best way to handling things due to UdonBehaviour's having the ability to have their networking behavior changed at any moment.

I'm not sure, but I assume that when you're building/uploading your world, all these excess network ids are automatically purged. Or maybe they don't and it doesn't even have a meaningful difference.

tender vapor
#

So, when a late joiner joins the world and gets the latest variable changes, they also fire fieldchangecallback and the methods they trigger if the values of said variables were different from default?

strange token
#

I use fieldchangecallback for all my late join behavior

tender vapor
#

It has been a journey the past few months. Slowly but surely getting the hang of this!

true magnet
#

Make sure if you sync arrays this way that you don't init them with the same length that you expect to get synced or the callback won't fire

warm steeple
#

wha, the callback only fires if the array length changes and not its contents?

true magnet
strange token
frozen igloo
#

really just don't use fieldchangecallback for arrays. Use OnDeserialization

north thistle
#

use OnDeserialization for all networked value, imo

twin portal
#

and deny myself the convenience of it? no way

north thistle
#

As far as I can tell, fieldchangecallback doesn't really make sense when it comes to how networked values work and trying to use it with networked values can produce race conditions

twin portal
#

it only produces race conditions if you make a FieldChangeCallback dependent on another networked value

#

but it's very useful if you just have one variable that's meant to track a state, and you always want to keep the changes in sync with the value of the variable. In this case, not only does it avoid bloating OnDeserialization with stuff, it's an easy place to keep things in sync from the Owner vs. other players

#

it's a place where you can update the state for both the Owner and other players in the same place, rather than needing to juggling something like an "ApplyState" function that you call in both OnDeserialization and in OnPostSerialization, for example

north thistle
#

Could you explain what you mean by "bloating" OnDeserialization with stuff?

twin portal
#

sometimes I use it for non-networked things too. Say I want the color of one thing to be blue or red depending on a condition.... instead of just setting the color on the material manually in every instance that state changes, or making a whole new function like "UpdateVariable".... just do it in FieldChangeCallback. Then I just set that variable whenever the state needs changing, and FieldChangeCallback automatically handles everything it needs to do then, without bloating up that portion of the code with unnecessary things

north thistle
twin portal
# north thistle Could you explain what you mean by "bloating" OnDeserialization with stuff?

Without FieldChangeCallback, then anything I'd want to do in there, I'd have to do in OnDeserialization instead. (which again, doesn't run for the sending player).
So instead of having things organized under a variable's FieldChangeCallback depending on what that variable is meant for, it would need to be done under OnDeserialization, and then I'd also have to write extra stuff that tends to disorganize things to make sure the same things happen for the Owner and receiving players....
I dunno. I think FieldChangeCallback just allows you to remove a lot of the networking headaches that can potentially happen.

Obviously not useful for everything networked related, as you've noted, there are limitations to it

twin portal
#

it's really the difference of "can I do a thing when only this variable changes" or "do I need to wait for ALL network variables are confirmed ready to use before doing a thing"

north thistle
# twin portal Without FieldChangeCallback, then anything I'd *want* to do in there, I'd have t...

But you're already writing that same code elsewhere (except with all the syntax to support FieldChangeCallback) so you're really just moving the "bloat" elsewhere. The main thing you are accomplishing is obfuscating the connection between OnDeserialization and the code that handles the changes in those networked values. And that obfuscation is what allows various issues, like race conditions between different networked values and arrays not working as expected, to appear in your code.

You're, of course, allowed to obfuscate that connection if you want, but I'd personally HIGHLY disadvise it for anything but the most simple of networking.

twin portal
#

I don't see it as obfuscating.... I see it as more as organizing

#

like FieldChangeCallback is a little folder for just that variable. It's the things I want to happen only when that variable changes

north thistle
#

It's objectively obfuscation, is it not?

twin portal
#

I don't know if I'm getting this right but it sounds like from your perspective, "OnDeserialization" is "the place where networked stuff happens"

#

but it's not the only place

#

so, I wouldn't consider it obfuscation

#

arrays absolutely don't work as expected in FieldChangeCallback. That's definitely clear, and not something I'd use when syncing arrays

north thistle
#

You're obfuscating the connection between the externally fired event that changes your networked values and the internal code that handles changes in your networked values

twin portal
#

...no? I really don't see it. FieldChangeCallback can also be a place that handles changes to networked values.

north thistle
#

Yes but FieldChangeCallback is not explicitly a network connected event which is where the obfuscation comes in

twin portal
#

I guess?. I think. It's used for both

As I was saying, it's code I want to run whether or not the variable changed locally, or it was changed via the network. Rather than build some dedicated functions for that, FieldChangeCallback handles both simultaneously

north thistle
#

"it's code I want to run whether or not the variable changed locally, or it was changed via the network. Rather than build some dedicated functions for that"

That is what I meant by obfuscation btw

twin portal
#

alright, but.... I'm failing to see how that is a negative thing

north thistle
#

Because it hides, obfuscates, the precise way that networked values are handled. It lets you avoid writing specific networking code, the benefit of obfuscation, but it hides the precise way that network code works and thus allows errors with race conditions and arrays to appear.

It seems more practical to fully acknowledge and respect that networking requires its own coding style and approach and to fully commit to that, rather then trying to piecemeal it.

strange token
#

I can’t understand a word of this 😂

twin portal
#

I don't really fully get it other. Or moreso still agree with it. I don't see it as hiding it at all..... the FieldChangeCallback IS my networking code. it's not pretending not to be.

#

but it's not the only tool in the toolbox.... all depends on what I need to have my code do

true magnet
#

Semi-related, it's possible for OnDeserialize to also not receive fully consistent data, right?
If I change two fields and call RequestSerialization(), it's still possible to split it into two frames

twin portal
#

if you're getting race conditions, thats not the fault of FieldChangeCallback, that's the fault of not understanding the execution order of when FieldChangeCallback runs vs. OnDeserialization

twin portal
north thistle
#

Perhaps a better choice of work here would have been excessive abstraction; it abstracts out the connection between networking and value changes to a degree that allows issues to appear

true magnet
twin portal
#

no, in this case they would be sent together

true magnet
#

is that ALWAYS the case?

twin portal
#

yes

true magnet
#

no matter how much data?

twin portal
#

all of the networked variables on a single script are sent all at once during a serialization

#

on a single object* rather

true magnet
#

per network id I presume

twin portal
#

right ✅

true magnet
#

I gotchu

twin portal
#

by "how much data" if you for example sent too much data in one serialization, the serialization would just fail and not send at all

#

it won't break it up and send it in parts or anything

true magnet
twin portal
#

of the top of my head I think its 4 times every second?

#

oh not network tick your asking data size

true magnet
#

ya

twin portal
#

yea it's in a doc

north thistle
#

depending on how pedantic we want to be we could say the data is sent and recoieved in parts; but in any case I'm pretty sure OnDeserilisation is only called once a complete individual state (which includes all networked values on that object) is received

true magnet
#

that one

#

turns out, a quite substantial amount

twin portal
#

that's it ^

#

yeah manual lets you do A LOT. but sending a package near the max size takes about ~30 seconds

true magnet
true magnet
twin portal
#

right, like I mentioned before:
FieldChangeCallback: only this variable is ready with its new value. nothing else is guaranteed
OnDeserializzation: ALL variables are confirmed to have their latest values and are ready to be used

north thistle
#

I have no idea how it handles FieldChangeCallback/the timing of it; that part of VRC's code might be a blackbox and at the very least could be changed at any time and shouldn't be depended upon

twin portal
#

I think the order of individual variables' FieldChangeCallback order is not guaranteed, but they all run before OnDeserialization

true magnet
#

If you actually have stuff that's important for data consistency, use OnDeserialization
An example of when I'm using FieldChangeCallback is when it's non-critical UI display data that gets synced from an object owner.
Instead of having to update large parts of UI with every small change, FieldChangeCallback lets me only update small parts as they are changed.

twin portal
#

because if you think about it. OnDeserialization is the confirmation that the new values are ready. Well, the only way they could be ready is if the variables have their new values right? And what runs when a variable gets a new value? FieldChangeCallback. thus, they all run first

strange token
#

most of the time if a field change variable depends on another in the same frame you have to toss the resulting code in a one frame delay, in my experience

twin portal
#

which is a hacky way to jump around the race condition, but for something like that, then it might be better to have that logic in OnDeserialization instead

true magnet
north thistle
#

The way I tend to handled my networking stuff is that anything directly connected to the networking is explicitly and rigidly handled state based logic; and then everything that derives from the network data can be more flexible and dynamic

twin portal
#

you are describing exactly what I would use FieldChangeCallback for 😁

north thistle
#

FieldChangeCallback does not support explicitly and rigidly handled state based logic; it handles data individually rather than in the monolithic way that state based would imply

twin portal
#

Which is perfectly fine if your state is only determined by that one variable

north thistle
#

Sure, but then you're handling the same goal in different ways depending on how many networked variables you have when you could just normalize the process

minor gale
#

i consider fieldchangecallback to be a bit of a trap, like it's fine for a few unrelated vars, but it breaks down if you use arrays or have any related variables or enough variables. i wouldn't really say it's wrong to use in pretty constrained cases, but i think it scales poorly and can be more error-prone if you add things in the future

from a maintenance standpoint it's less clear defining the behaviour across variables, defining it at variable-level to begin with is less readable imo. i guess you could call into methods for each var, but at that point i'd consider it ideal to just call it in deserialize

using deserialize to centralize is much more clear and contained, it's more legible in terms of execution flow, instead of peeking every variable if you need to see what's being networked in your code

// The owner calls this instead of RequestSerialization()
private void CallSerialization()
{
  RequestSerialization();
  ApplySerialization();
}

public override void OnDeserialization()
{
  ApplySerialization();
}

private void ApplySerialization()
{
  ApplySomeColor();
  DoSomeOtherThing();
  MaybeAnotherThing();
  SomethingNotAssociatedWithAnySpecificVariable();
}
tawny basin
#

I just don't think I'll ever use it tbh
Always felt funky to me in the same way as one who uses public members felt funky
Might provide what's needed
But could also more easily cause a slew of problems

I like the UI usage though

twin portal
#

You guys still aren't making any sense :/

I see no difference in having an ApplySerialization method, versus a FieldChangeCallback, besides execution order.

Again I want to emphasize it's extremely useful when you want something to happen when THAT variable's value changes, regardless if it's a local change or has happened over the network.. Any time I see someone run into issues using it, it's due to assuming that it is purely a networking-related feature, and all variables are safe to use. And as I've explained, this is not true.

minor gale
#

it's fine for a few unrelated vars, but it breaks down if you use arrays or have any related variables or enough variables. i wouldn't really say it's wrong to use in pretty constrained cases, but i think it scales poorly and can be more error-prone if you add things in the future

i'm advising against it for scaling, i'd admit that it's fine for cases where the variables are legitimately self-contained, but can, by design, lead to errors if you're not slightly careful with the scope

i personally find it less clear to optionally apply state only on change, preferring to apply absolute state every time, unless it legitimately impacts performance, that's just my preference though

i'm probably too critical of it, but i think it's a legitimate take on the boundary

you're right, if it's scoped to just that var it's fine

#

like if someone was showing me some learning code for udon and they had a single synced var with a fieldchange i don't think i'd even bring it up, but if they introduced 3 more vars and started showing a pattern of applying state across all the vars separately, i'd probably try to inform them of the caveats and preference to use deserialization

because it could develop into a pretty poor pattern or outright bugs if they never understood the distinction, though i'm not saying that's the case here

twin portal
#

Now you're making sense, that's basically everything I've been trying to say

#

Just feel like this discussion has boiled down to
"Don't use thing. It causes problems in X scenario."
"Actually, thing is quite useful in Y scenario."
"No, don't ever use thing."

minor gale
#

i think my point would be that by nature, applying in deserialization means there's no room for error. for someone completely aware of the potential issues i'm sure they could manage it themselves, though i don't like managing that distinction

for example, i click a button and display my high score on some synced board

VERSION 1

public class SomeClass : UdonSharpBehaviour
{
    public TMP.Ugui scoreboard;

    [UdonSynced, FieldChangeCallback(nameof(PlayerHighestScore))]
    private string _playerHighestScore;

    public string PlayerHighestScore
    {
        set
        {
            _playerHighestScore = value;
            scoreboard.text = $"{value}";
        }
        get => _playerHighestScore;
    }

    public override void Interact()
    {
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        PlayerHighestScore = GameManager.GetMyPlayerHighestScore();
        RequestSerialization();
    }
}

then i realize i actually want to display the player's name too, prior to the score, so i make this

VERSION 2

public class SomeClass : UdonSharpBehaviour
{
    public TMP.Ugui scoreboard;

    [UdonSynced, FieldChangeCallback(nameof(PlayerHighestScore))]
    private string _playerHighestScore;

    public string PlayerHighestScore
    {
        set
        {
            _playerHighestScore = value;
            scoreboard.text = $"[{PlayerName}] {value}";
        }
        get => _playerHighestScore;
    }
    
    [UdonSynced]
    private string PlayerName;

    public override void Interact()
    {
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        PlayerHighestScore = GameManager.GetMyPlayerHighestScore();
        PlayerName = Networking.LocalPlayer.displayName;
        RequestSerialization();
    }
}

you could definitely make the argument for just making it one string. or inferring the player name from ownership. or applying it in both. there are issues with doing it this way obviously, though it may not be apparent at a glance to someone unfamiliar. but i don't think i'd want to differentiate between "this is the point where i move my logic from a change callback to deserialize instead", i'd just use deserialize to begin with

mostly, i'd want to put across that this is simply never an issue if deserialize is the point of call

strange token
#

I’ve never used deserialization for networking because there are places that callbacks support more, such as being able to interact with the original value on change before applying the new one over the variable

#

also nobody has ever explained how to detect changes to specific variables in deserialization, and I don’t see any reason to trigger an update to every single synced variable on a script just because I received an update for one or two variables

#

seems more self contained to me to put them in a callback so their behavior is handled as needed, specifically only when they’re changed

minor gale
#

you receive every value whether they've changed or not, i think deserialize reflects that more logically

i do a lot of networking and i've never had a case where applying the entire state was the breaking point between deciding to apply it all or only some, in the worst case you're applying everything if it all changes. it might sound like a gain, but in practice unless you've measured that it's causing you issues it's really not worth selectively applying

as for how you'd detect that, if you were updating a text field, you could check if the synced string is equivalent to the text on some field you plan to update prior to pushing it, but again i really think that's not worthwhile unless you're doing it for a reason

strange token
#

it honestly sounds worse performance to build the system to apply extra code changes without detecting any reason to do so :| especially if you want something to only happen when specific variables are changed, since you can’t detect a changed state without separately cloning every variable into a local state and comparing those for each variable in deserialization

#

also think storing all the networking code for many different variables in one place would get way more cluttered

minor gale
#

the things you're doing in the logic matter far more than deciding to apply it on fieldchange or on deserialize, instantiating 1500 objects will be an issue in either case. the performance gain is trivial compared to the logic in most cases

#

like a bundle of variables, a snapshot, is something that at worst needs to be interpreted wholesale, not piecemeal (a late-joiner is the prime example of this)

being able to infer the absolute state at any point across all variables aligns more with how it actually works

but fieldchange is fine if your variables have zero correlation to each other ever

north thistle
#

Just tested that RequestSerialization will trigger a network sync on the owner and a OnDeserialization on remote clients, even if there are zero changes in the networked values.

This is actually desirable and helps me with a Two Generals' Problem I had with some networking I'm working on.

Consider a block that has it's type denotated by an int; this value is currently set to 1 to denote a block type of one.

I want anyone to be able to change the block type of the block but I want to avoid ownership-related race conditions. As a result I'll have non-owners use a network event to request the owner of the block to change the value for them.

But what if the Owner crashes/dcs after sending them the request event but before they had time to change the block type? To address this I'd have the remote client remember that it sent out this event and resend it to any new owners if the old owner dced without changing the block type.

But what about the edge case of the block, due to some other actor, getting switched back to the default value of 1? The remote client would never see the expected value change happen even though their request event was successfully received. But since OnDeserialization we can simply rely on that to presume our event was received successfully. There is still an edge case that allows for an event to never be properly recieved, but I consider it small enough to be tolerable.

tawny basin
# minor gale > it's fine for a few unrelated vars, but it breaks down if you use arrays or ha...

i'm advising against it for scaling, i'd admit that it's fine for cases where the variables are legitimately self-contained, but can, by design, lead to errors if you're not slightly careful with the scope

Marvelous
In a perfect nutshell what I was trying to convey here -> #udon-networking message
Systems that increase in variability to scale
I'd rather just use more reliable the catch all even for small things at that rate

azure swallow
#

Everytime i start a new project i feel like i need to relearn networking x)

finite sierra
# strange token also nobody has ever explained how to detect changes to specific variables in de...

you can detect it by having two variables.
One Private/Protected which act as a last known value.
One [UdonSynced] Public Variable that act as the newest value.

then in the OnDeserialize you can check the old last known value you have. And if it's different from the value you have that means it changed.
This will always ensure that you know its changed or not..
And then you can run whatever methods etc.

Or you can use FieldChangeCallback that allows you to see the old value and the new one before setting it. Do know that it does not run if its the same value.

minor gale
north thistle
minor gale
north thistle
#

That sounds like a different networking goal than what I am thinking of. I'm setting a finite state, not accumulating an amount. Unless I misunderstand what you mean by delta and "depositing gold into a central box"

minor gale
#

it is different yes, it was more of an open-ended question that i found interesting to think through after considering yours; i'm not really expecting an answer, just wanted to say that it's an interesting networking problem in a similar vein

north thistle
#

Ahh I see

#

I think the way persistence data is designed makes it impossible to guarantee transfers like that

I'm not sure you could guarantee stuff like that without a central, authoritative source

minor gale
#

the persistence part would never be guaranteed yeah, though if on the sender you deduct it first, serialize, then wait some timeframe, after both post serialize fires and clog is false, it's reasonable to assume that the persistence update will hit network

deducting first means they could lose the gold if it wasn't processed, but i think that's preferable to duplicating it; which leads into ensuring it's processed while they remain in the session

north thistle
#

My idea would be to send the owner of the box a network event including the the amount and uid for the event; the owner would then send back a confirmation that the event was received including the uid for the event

then the deduction to the persistance amount happens for that uid

minor gale
#

a uid (something like a unique id for that transaction) would be quite apt yes

north thistle
#

the most important thing is, of course, that you don't have any network events that directly allow remote clients to control your persistence data

finite sierra
#

unless i missunderstood the inherit problem

minor gale
finite sierra
#

well maybe? but again im pretty sure a Queue should absolve it to some degree with some extra careful steps?

minor gale
#

a queue on the receiver doesn't resolve if their client doesn't logically process it

finite sierra
#

well in case of vrchat its eventuelly going to happen no?

minor gale
#

from the perspective of the relay, it sent the event to the correct person, even if they're currently unavailable, the event would not be resent to the new owner if the original disconnects, leaving it in limbo from the perspective of the sender

finite sierra
#

Hmm. i must say i have yet to observe that kind of a problem through.,.

minor gale
#

it's a pretty narrow problem, it's not common either, but it's definitely possible if someone suspends their device or internet cuts out for some duration before they're forcibly disconnected

the stakes are more for transactions, which you can't secure in any way, but you can attempt to protect regular users from the issue i'm describing

#

in most cases the event dropping is fine if the user can just retry the action, in the case of currency it's not really a great experience for the player if they submit x currency and nothing happens

finite sierra
#

hmm true. but to avoid issues its eaiser to have one person be the handler? otherwise you would have to have CRDT

minor gale
#

using a central handler is the norm in applying a delta like this yeah

finite sierra
#

but also the most risky one in case of vrchat.

#

atleast in terms of this problem

minor gale
#

the alternative is a race condition that could just as easily result in issues if you use ownership transfers and variable setting (i'd say more easily in the case of applying delta to a synced value)

finite sierra
#

yea i mean if you have an issue like you said here. you have 2 people updating and then lets say the person who is in charge of it have issues and it does not operate on the problem.

#

considering that eventuelly? it switches who the new owner is i hope.

#

but then again if we had a proper server/owner that never changes. it would make things so much eaiser but that like is more costly on vrchats side

north thistle
#

Having it handled server-side would either require the data handling to be so limiting as to be frustrating to work with, or would require us to be able to write code that would run on the server which is its own whole thing.

finite sierra
#

it's not really more frustrating to work with at all. its the same way as you have been doing it now. all it would require on Vrc's side is to have similar thing like [UdonSynced]. and then have it handle it like so. Or if it only is for simple things like updating values then all you would need is to send it to the owner with the data obviously.

#

Cost may or may not be larger. But complexity on Vrc's side would be much larger. More to keep under control but also to ensure nothing bad can be ran on the server.

#

Also i would actually more or less call it instanced side owner. as in when an instance is being created it automaticly assigns the instance it self as a master and not the users.

north thistle
finite sierra
#

yea but we have no control over it. nor can it be the owner. since the relay just copies the data and sends it on

#

and relays cant really be managed either

north thistle
finite sierra
#

you can't you have to write it as a server only running method. the limits would be the same as we have for the client it self and the only real difference is just what we would be allowed to run on the server.

north thistle
#

So what, anyone in the instance would be allowed to drain anyone's persistence data inventory?

chrome kayak
humble girder
north thistle
humble girder
north thistle
#

They seemed to have some amorphous idea that having "server owned" networked objects would solve common networking issues people run into

finite sierra
finite sierra
# north thistle They seemed to have some amorphous idea that having "server owned" networked obj...

eh cause it would. Having a single owner of an object for things like shared inventories, Banks etc whatever requires something shared between everyone. Would make it far eaiser as you only need to request to that specific owner. and you wouldn't need this to be replicated for every single user either. Or added or removed by every user either. And most problems that comes from multiple people trying to add/remove from a shared bank for instance would be gone.

#

Yes. all through it likely wont happen

#

Server Authoritative are far better then Client Authoritative for things like this.

humble girder
#

Tenant users are complicated pattern by itself. Can't really see how vrc will support this. If the main point still is having server-side script, that's also better to have one.

finite sierra
#

Tenant Users?

humble girder
#

A group of user that can access the same resource.

finite sierra
#

well you never really access it.

#

you request the data

humble girder
#

That's also accessing it.

finite sierra
#

well in a sense yes.

#

but you still have various checks to ensure that you cant just get the data that doesnt belong to you etc

#

like server sided scripts or functionality would solve a crap ton of issues that we have because its not a centralized Authoritative Server

#

and instead its all Client Authoritative

humble girder
#

The main point is just to have server-side script.

finite sierra
#

yes the main point is server sided scripts would solve issues

minor gale
#

the relay doesn't run a unity instance afaik, it wouldn't be able to do things like run physics or nav agents. at best it might be able to arbitrate some things centrally in primitive data is my impression (which isn't bad, but it's probably not a priority)

marble berry
#

Helloo
Probably an easy question but how do i set the position of a synced pickup ? just setting the transform position doesnt work if you havent held the pickup last or if its being held, and i dont see a function to respawn it built in or a set owner either
How do i do this ?

#

U# btw

fallow mountain
#

You are in the right direction, you need to set owner, only the owner has the "final say" of the synced variables (eg the position) so that is what you need to do before moving it

#

Go watch the pinned video, it explains the basics well

tawny basin
finite sierra
finite sierra
tawny basin
#

Might be the original poster tbh

finite sierra
#

oh eh. i honestly dont know LOL 😄 i forgot

tawny basin
#

Yeah, all that really matters is that we agree it would solve a lot

minor gale
#

i'd love to have a proper client-server setup, but it'd be asking them to change their entire model. like it'd be a very extreme change on their end

finite sierra
#

it's kinda a proven fact. with how every single game that is networked uses it 😄

finite sierra
tawny basin
#

(Sky might be blue)

finite sierra
#

but it would also greatly benefit us creators and them self in the end by reducing overall cost.

#

considering Vrchat uses the Legacy Proton Networking from what i undertand. and its the Relay Legacy

#

anyway it's a big ask and a big wish of mine we do. it would just make things so much eaiser for us.

tawny basin
#

For now let's hope for the absolute basics (how did we survive for this long without interfaces)

#

(VRC+ API before such features)

north thistle
north thistle
#

It's a bit oh a hassle, but that's how people have been surviving in the meantime

tawny basin
#

(we'll keep waiting for the absolute basics)

north thistle
#

Hey, I'm pretty sure the people who created the foundation of the modern world did so without those fancy tools

tawny basin
#

I'm so glad we're in the current_era
I agree it's amazing that we just
Don't have to go back to that period

#

Punch cards for programming HAD to go

finite sierra
finite sierra
tawny basin
#

(There are no contracts even if this wild polymorphism route remains)

finite sierra
#

alot of these things is what the promised Soba is gonna solve. If it ever comes out

north thistle
# finite sierra Vincill do you actually know what an interface is? and what it does. Cause you c...

Since you're confused, let me explain: the goal of interfaces is to allow different classes to be handled in a polymorphic way, allowing you to tell an object to do a specific thing even if you don't know what specific class it is. While you currently don't have the type safety and strict compiler-side enforcement of interfaces, you can still implement this core goal via SendCustomEvent and SetProgramVariable while treating the objects as UdonBehaviours

minor gale
#

i think it's a stretch to say that we can achieve nothing close to an interface

a close approximation would be using a base type and deriving from it to guarantee the methods for a generic base

what vincil's describing isn't a bad approximation either if you enforce the methods are available yourself, but it's much more manual

tawny basin
#

Huh
All in all
We'll keep waiting for the absolute basics to be properly implemented

north thistle
#

I wonder if what is considered "the absolute basics" will change once Soba comes out

tawny basin
#

Hopefully so
Iteration is awesomesauce

north thistle
#

I'm just hoping we eventually get coroutines

finite sierra
finite sierra
north thistle
tawny basin
#

I read two crazy statements today
Someone proposing the concept that a base class is suitable for replacing interfaces (we desperately tried to escape inheritance hell and scope creep by creating interfaces in the first place)
And someone else talking about customevents as an approximation for coroutines

#

What a day

finite sierra
#

well the only reason for that is because of how we can do what exactly a corutine already does. just we can't get any data back from a CustomEvent etc. And a few other things that corutines can do which we can't but thats primarily making it wait until something returns

minor gale
#

i said it was a close approximation, not a replacement. i think interfaces would benefit udon greatly, but saying we can't do anything remotely in that vein is an exaggeration

there isn't a ton of functional difference between providing IDamageable on a class and providing a base that can be damaged as if it were any type that could be damaged

if you want to say it's less composable i'd agree

north thistle
finite sierra
north thistle
tawny basin
tawny basin
minor gale
#

base classes can still be useful though if you actually want to make something. the alternatives are something like doing sequential getcomponent calls to find the specific type and call a method. or using generic string events/program variable sets. there are places where i describe a base type with base methods (where i'd probably prefer interfaces) and it works reasonably

i don't like inheritance, i don't nest more than one layer in my projects, but it's not like a base class is only a theoretically useful thing, you can use it in practice and it's preferable to just not doing the thing you want to do

north thistle
tawny basin
#

I wouldn't call what they've created lazy either tbh

tawny basin
heavy spindle
#

Even from the perspective of multi-inheritance, you cannot have a super of more than one class, but you can implement multiple interfaces in C#, so that's pretty good. But… I absolutely despise how you have to proxy properties with methods with interfaces and I've found getters/setters to be buggy. I was stuck in inheritance hell, but I was making a game with multiple gun types and they had to inherit from like a base class and different sub types like if the gun was to have recoil, was full/semi auto or single shot. This was done in combination with static classes that accepted their respected interface of type of weapon so I could de-dupe code and provide standard interfaces for future weapons

finite sierra
normal sundial
# tawny basin Absolutely To be fair we both want what's best for the dev platform for this gam...

How much of their design philosophy is limited by security concerns, do we know? Im not a cs major so i dont have great background in these kinds of things, but if they dont implement something i want i tend to assume its more due to some possible risk of exploitation by programmers. Like allowing the io libaries is obviously a pretty catastrophic idea, are there things they just cant do because it would allow access beyond the sandbox they provide for us?

tawny basin
#

We (you AND I) can't really know

#

But we do know they use a VM so what the VM says goes

#

It shouldn't really be a concern from there
The implementation of the absolute basics would conform to what the VM can do when translated into yadda yadda bytecode

#

There are no surprises because it's top-down sorta deal
They made Da Rules

heavy spindle
#

What about in cases where I want to extract a set of specific properties to a type which I will pass? I’d still have to make proxy methods and an interface it implements to access properties?

#

because interfaces cannot declare props directly

wet halo
#

@sullen junco While Instantiate() is prohibited, is there way to spawn object dynamically?

twin portal
#

Instantiate isn't prohibited, you can use it

wet halo
twin portal
#

PlayerObjects would be easier, but only if it makes sense to use them for your use-case

#

There's also the option of using an ObjectPool

wet halo
#

I would like to spawn a object almost infinitely and it should not belong to someone, so started to using Object Pool
Thanks :)

sonic dew
#

So I never realized that to do networking stuff you have to send the network event to a different udon behavior

#

So I been struggling to make something for over a week because of it

twin portal
sonic dew
twin portal
#

yeah just SendCustomNetworkEvent. In Graph, just leave the "instance" input empty. You should even be able to select the event you want in the dropdown, if it's already set up

#

the only things I could see that would prevent this from working is:
-The script's sync type is set to None
-This script is on an instantiated object

north thistle
#

If you know how to write a serializer, one way to give networking to instantiated objects is to create a pool of networked objects that sync a byte array and have instantiated objects that know how to serialize their networked data and deserialize it; then you have a way to link the networked objects to the instantiated objects in a way that doesn't produce desynchs

sonic dew
#

Is there anyway for me to test my networking without uploading the world

twin portal
#

yes, Build & Test with multiple clients

sonic dew
#

I forgot that existed

flat osprey
#

Hey how would I make this server side?

#

Its a script for a button that changes the skybox but I can't get it to sync for players when one person touches it. ):

foggy jackal
#

doesn't look like you have any networking there. I don't really work with Graph though

flat osprey
#

wait I fixed it

foggy jackal
#

nice

flat osprey
#

forgot this little guy 😅

foggy jackal
#

there it is

humble girder
normal sundial
#

This isnt even an "um actually' thing so i dont get the reacts on rens message, networking in udon is designed as peer-to-peer, not server-client, its a really important point of understanding for designing your code and systems

fallow mountain
#

Yea, there is no server, instead you have "owners" of each networked object, and ownership can be transferred and every object can have different owners, it is essential that you understand what an owner is
The pinned video is great, it is a must watch for anyone trying to get into udon networking, it explains this concept well

strange token
#

can confirm, there’s nothing server side in udon, bro’s just being rude for no reason after asking for help :v

north thistle
# strange token can confirm, there’s nothing server side in udon, bro’s just being rude for no r...

I mean it depends on how pedantic we want to be. If we're speaking very technically, when we "RequestSerialization" on a manual sync object we are pushing the data to the server. The server is what then distributes that data to everyone else. And if I understand correctly that is how late sync is handled, anyone joining gets the last network data sent to the server and thus the owners of objects don't need to resync their data every time someone joins.

With that said "make this server side" still isn't good terminology here and can leave confusion on what is actually meant.

sick gull
#

Oh how I wish we had a server

tawny basin
#

Somethingsomething relay

sick gull
#

And voice channel "zones" to help reduce the bandwidth (I was told recently that lobbies get really bad fps the more players due to the connections you need to make to hear everyone)

normal sundial
#

Does OnPlayerJoined trigger for the joining player, using their VRCPlayerApi?

#

yes

minor gale
#

it's also presented every player in the session when you join i think

#

including yourself yeah

normal sundial
#

NetworkEventTarget.Owner will target the owner of the gameobject the script is attached to?

minor gale
#

yeah the owner of the object the network event is called on

normal sundial
#

nice, many thanks 😄

#

If I use Networking.SetOwner(playerapi, gameobject), i only need to fire it from a single client to apply to the whole lobby, right?

#

best practice would be to check playerapi.islocal before doing Networking.SetOwner so I don't fire the same request from every client, i imagine

minor gale
#

in the context of a network event sent to everyone i suppose so

but yeah the setowner is automatically propagated, it only needs to be called from one client

normal sundial
#

perfect, thank you

north thistle
#

current networking project: handle relatively high degrees of environmental simulation (think something like SS13) but on VRC's P2P networking

I think I can get it to work, just need to give a good amount of thought to the structuring

sick gull
#

Always thought SS13 was so cool. I liked watching hour long videos of everything hitting the fan
Best of luck

warm steeple
normal sundial
#

For the OnPlayerLeft event, will this trigger for the local player such that I can run code before they actually leave the instance? Or will this only trigger after they have actually left?

#

My syncing requires intelligent transfer of ownership and id like to avoid having to send out an extra ping to do so if i can

#

i might need to dedicate a variable to having a backup owner to handle this 🤔

tulip sphinx
#

@normal sundial you cant run code locally for leaving player. cause it can very well be player losing network connection, crashing or turning their quest off via button. so having this makes no sense. however nowadays player api is at least guaranteed to still be valid during that call for the others

normal sundial
#

alright, backup owner variable approach it is, thanks

jolly star
#

If I send a string as a network parameter, is there a general character limit still to that? I read 50 but wondering if that's old info or just for a sync'd variable? It seems fine with going quite a bit above that but this is just in build and test so wondering if live with multiple players that would just fail.

strange token
#

so I think the limit is just the sync byte limit

jolly star
#

sweet, thank you. Haven't had an issue yet either so that's great.

twin portal
jolly star
#

I should be hitting about 1-2k so I should be pretty safe thankfully. I'm just time slicing to get more now :)
So far so good!

solid wraith
#

hello

finite sierra
young thunder
#

I need to sync a small amount of data per-player. Would Player Objects be the way to go here?

twin portal
#

They can certainly make doing that a lot easier compared to the alternative

young thunder
#

in the past, i tried to create a dictionary that mapped player IDs to the data I was syncing

#

but i messed something up and never wound up finishing it

#

(this is also data that each player should own)

#

it's going to be used for toggles that other players need to know about

#

in this case, it's a toggle that prevents you from triggering a sound effect when you enter a collider

minor gale
#

playerobjects are a little indirect but probably the right choice. you could use playerdata if you really felt like having less indirect access quickly, but it would persist the value (i suppose you could swap it false on restore)

finite sierra
tulip sphinx
#

you didn't watch the vid did you

#

source: become the owner - set the variables - request serialization - run custom event

other folks: on deserialization - same custom event

custom event: look at the variables and apply changes like open the door or set the material.

thats a flow for 99% of manual sync stuff

wary quarry
#

that is my bad

wary quarry
tulip sphinx
#

step one, figure out where setting variables and applying them to actual stuff is. step two, divide em with custom event call

tulip sphinx
#

nope. both top and bootom stuff do things to actual things so i dont see any disivion, nor i see custom event

wary quarry
#

The only thing going in to it is this

tulip sphinx
#

so no customevent still

wary quarry
#

oh i see what youre saying

tulip sphinx
#

setting var is one thing, it can branch and stuff. then comes custom event for everyone that is deteministic

tulip sphinx
#

also sendChange is useless networking wise btw

#

uh, but you dont set it before

#

wait what

#

where did events ever came to this

#

oooh

#

no, just no

wary quarry
#

yeahhhhh

tulip sphinx
#

naming things True and False is just illegal

wary quarry
#

Really?

tulip sphinx
#

i wish

wary quarry
#

Ill change it to set glass and set fogged

#

Can you tell ive been teaching myself?

tulip sphinx
#

anyway

#

i cant even can see how you determine if is glass or not

#

on, its just IsGlass

#

then thats it

wary quarry
#

I mean if IsGlass is true, we set to fogged, and if IsGlass is false, we set to glass right

tulip sphinx
#

interact - become owner - get "isglass" - unarynegation - set "isglass" (variable only!) - req serialization- custom event "apply mf glass"

#

ondeserialization - custom event "apply mf glass"

#

event custom "apply mf glass" - branch "isglass" - true set whatever, false set whatever

#

given your interact button is just on/off

#

if you have button per mode then its slightly more

wary quarry
tulip sphinx
#

thats get (current value)

#

thats set (to a new value)

wary quarry
#

@tulip sphinx So something like this?

tulip sphinx
#

love me android so its very lowres but looks decent👍

wary quarry
#

I love the effect of not knowing how anything works but the second i see it made im like oh yeah that makes sense lol

tulip sphinx
#

ye was about to tell to set IsGlass to synced

#

ah also sets in the end are useless

#

if not harmfull

#

you generally normally dont manipulate variables in "everyone's" custom event, its just to apply variables to more meaningful things

wary quarry
#

Forgot to set a value to public

#

It does work

lusty pagoda
#

can you perfectly recreate vrcobjectsync in udonbehaviour so that you dont have to rely on network ids and be able to sync multiple objects with 1 script?

humble girder
lusty pagoda
#

not that huge, 10 bytes per object

#

and loading 1000 objects into it seems more sane than holding 1000 placeholder vrcobjectsyncs in the scene?

humble girder
lusty pagoda
#

well do we have examples of vrcobjectsync in udonbehaviour then? i assume it holds some velocity and other stuff

humble girder
random parrot
tulip sphinx
#

vrcsync is an unique type of sync, that doesnt send anything when idle (but sending up to 5hz when moving) so recreating it perfectly doesnt look very doable?

lusty pagoda
#

i mean world full of them tends to lag more even when not moving so i dont know about that

minor gale
#

i'm pretty sure they do something like if (isowner && notSleeping) SendLoop()

not impossible to recreate on manual

#

mine isn't public, but yeah you can route things through one script and handle instantiation yourself and late join propagation. some people end up using synced arrays to place static objects, with the downside of it being type specific and difficult for dynamic objects

finite sierra
#

even if you managed to recreate it you would have to deal with the Limits of Manual Sync and it's inherit higher data consumption due to the handshake needed to by anyone who receives it.

#

and it is more efficent to have 1000 of them precreated and in the scene before hand. Since you do not need to spend resources and time on intializing those 1000 objects. Since u can just disable the render when not in use. or combine it with the vrcobject pool to disable them etc potentially.

strange token
#

this means the only time you’re network syncing is the quick notification that something was just grabbed or dropped

#

but I always end up integrating this with lots of other code so I can’t just post the code for this solution, it’ll take some work for you to recreate

north thistle
# lusty pagoda and loading 1000 objects into it seems more sane than holding 1000 placeholder v...

the position (Vector3) and rotation (Quaternion) would be 28 bytes in itself

also in my testing the max amount of simultaneously active vrcobjectsyncs is ~40, no way are you getting 1000 working

also by combining them all together you're losing out on the main advantage of VRCObjectSync, it can sleep its individual object while it is not moving thus causing it to not consume networking bandwidth

north thistle
tulip sphinx
#

@north thistle how did you got 40, i was piling up physics enabled and got suffering somewhere around 300

#

and thats active ie not sleeping, so 1000 overall still makes sense most cases

north thistle
tulip sphinx
#

they were just piling up after i mass spawn them. i mean not kinematic ie they collided and affected each other

north thistle
#

I'm pretty sure them simply being in contact with another object doesn't awaken them; they have to actually move to be awoken otherwise they sleep

tulip sphinx
#

nope, they use rigindbody sleeping property. ie unity uses sleeping state to save physx calculations, vrc re-uses it to pause sync on top of that

#

oh i mean just being in contact doesnt keep them awake sure

#

but its a mass spawn of 300 things in one place so they need a lot of time to wiggle down

#

also did math and it made sense. like probably uuuh 32x7x5x300/8 is 8KBs+whatever overhead

finite sierra
north thistle
#

it won't use a fixed usage rate as it has a dynamic update rate

finite sierra
#

and it always used 100+

north thistle
finite sierra
#

light? you hit max out all the time thats heavy suffering

minor gale
# north thistle VRCObjectSync uses a Continuous sync-like sync when it is active. Continuous is...

"lightweight" in that it doesn't clog on more than some count per second like manual?

vrc's object sync runs an update loop, always, presumably to check for sleeping status/movement to wake their sync loop. this is logically heavier

you can avoid it entirely if you only wake the sync on relevant events (pickup events and collision events for example) and subscribe to an opt-in loop

in my own handling i run the sync through a central manager which makes it not beholden to the ~40 manual per second rate anyway, using network events, though this isn't really necessary for manual handling

continuous is necessary if you want it at object level with active counts > ~40/s, which i'd imagine might not be the case for someone wanting 1k objects around (many would typically be inactive)

you can also control the rate and data sent if you run your own sync, which can be lighter on bandwidth, or heavier if you need, you can control the interpolation type or handle it differently as needed

using their object sync is valid, it's probably not an option for every creator to invest in making and running bespoke handling; but i'd state my preference for controlling every layer

finite sierra
minor gale
#

i did specifically state that in the case for continuous

north thistle
minor gale
#

i would disagree data-wise, i'd only agree on the merit of manual having a per second object serialization limit

finite sierra
minor gale
#

i run through a central handler myself, meaning i only pay the ack once per bundle, but there's a trade-off to be made in manual handling, at some point manual loses out in an environment. i don't think either is absolute or "the best" in all cases

finite sierra
tulip sphinx
#

what in the. it is like 220bps per sync indeed. and its 27B (16B pos, 20B quarternion - with overheads, 1B who knows, so for apparently new standard 4hz its already 108Bps). And also my math doesnt add up at all (or rather it does and shows 42KBps without overhead)

#

still, its per player and active so 1000 doesnt sound unreasonable

minor gale
#

a central router, it isn't owned by a specific person

#

i should clarify, it is technically owned by the master i suppose

#

you're allowed to own an object at object-level and route the data differently

north thistle
#

(note that the suffering would increase seemingly without ever stopping if not for my manual sync skipping a sync attempt if it detects that the network is suffering)

minor gale
#

i've been saying that i use a central object for passing the data myself; 13 objects is quite low though, it might be that manual at object level is less viable than i'd expect. i don't know that i feel like testing it myself this instant. are you saying you had 50 moving on manual or just 13 moving on manual?

north thistle
#

also manual sync incures a remote upload cost on everyone else in the instance while VRCObjectSync does not, for instances where that matters

north thistle
#

VRC really doesn't like performing many manual syncs per second world wide

minor gale
#

oh you're hitting the manual limit there yeah

#

the kb/out is only ~5

#

manual is less viable at object level then, for nav agents it's probably preferable to cluster them or use object sync. for rigidbodies i'd* be okay with manual sends at object level unless i expected a lot to be moving at once, but again i use a central event so i don't really encounter either issue in my environment

north thistle
#

On a side note, if you want a small handful of relatively low latency position syncs the best sync method to use would be network events

frank fjord
#

Does anyone remember offhand what the calculation is for the byte size of an UdonSync array?

#

Obviously it is at least the combined size of its constituent members

#

but I know there's some amount of overhead and I do not remember what that overhead calculation is

frank fjord
#

Digging through an old testbed project I found that I recorded it as "52 byte header plus the combined size of constituent members, but in 4-member chunks (so an array with 1, 2, 3, or 4 members are all 52 + 4*membertypesize bytes)"

#

I hope I don't have that wrong

#

there's also a ton of undocumented mysteries around how actual traffic from manual serialization works because the tools showing you bandwidth usage show VASTLY higher outgoing data sizes than the calculated 'serialization result bytesize' value, even after accounting for the baseline usage from the player themselves...

#

I don't even think documentation tells you that of the 11 kb/s you have for outgoing traffic before network suffering kicks in, your player and VOIP are already using about half or more of that number...

north thistle
# frank fjord I don't even think documentation tells you that of the 11 kb/s you have for outg...

The most up-to-date place in the documentation for networking limits is contained, unintuitively, in the page for Network Events: https://creators.vrchat.com/worlds/udon/networking/events/#parameter-size-limits-and-event-splitting

"Total outgoing data is hard-capped at approximately 18 KB/s. This includes all network overhead however, so in practice it is unlikely you will see more than 8-10 KB/s."

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.

frank fjord
north thistle
#

Also an additional thing cutting into your bandwidth is you having to confirm that you have successfully received network data from other people in the instance; so the more people in the instance the more your "background" upload usage will go up

frank fjord
#

What? There's actually a handshake??

#

I had no idea

#

All these networking systems have felt very... UDP to me

north thistle
#

I'm not 100% sure; but I have observed that background upload usage goes up the more people are in an instance; and apparently at 80 people you can't get any world-side networking done with any good reliability

frank fjord
#

oof...

north thistle
#

At the very least the only networking available to Udon that doesn't seem to use a handshake is VRCObjectSync and Continuous sync

frank fjord
#

Hmm. Did we ever get access to classes that make bitstring editing easier? I forget the predominant class--

#

I am strongly debating implementing a custom byte array compression to some of my bulkier classes

#

but man editing bytes manually is a slog

minor gale
#

they mean ack rather than handshake, it's rudp

frank fjord
#

Ah, I'm a little too naive to know the nuance/difference here, I think

minor gale
#

handshake would be more tcp land

north thistle
frank fjord
#

yeah BitConverter was the one I was thinking of. I know for at least some period of time, it was inaccessible to UdonSharp

#

I hope it works now

normal sundial
#

Im pretty sure i recall using it for a bit in the early stages of my project without any issue

tulip sphinx
north thistle
tulip sphinx
#

@north thistle well ye thats why the answer was "its easier to create 1000vrc syncs so you have plenty ids than trying to avoid them"

tranquil hull
#

Introducing an Open Beta release for the Spring 2021 Networking Open Beta! This beta is expected to run for several weeks as we gather feedback and continue making improvements. If you're reading this in the pins, click the pin to jump up to this message! There's a few more after it.

Who is this for?
This beta release will benefit all users of VRChat but the main audience is World Creators.

  • We encourage you to update your SDK3 worlds to use the new networking abilities in this update. If you're going to do this, make sure to publish with a new blueprint ID so it doesn't overwrite your existing world.
  • If you're not ready to update your world, or you have an SDK2 world that you haven't rebuilt in SDK3 yet, this is a good time to test them and make sure they continue to work in this new system.
#

What's in it?
You can find the details of the new Udon Networking system here: https://docs.vrchat.com/docs/udon-networking. Basically, these updates provide new precise controls for syncing, support for syncing arrays (collections of variables) and fixes for join-in-progress issues. More details for creators below:

  • Array variables can be synced (see docs for list of supported Array types)
  • New 'Manual' Sync Mode for UdonBehaviours for precise control of when variables are serialized.
  • New 'VRCObjectSync' component instead of 'Sync' property on UdonBehaviours if you just need to sync Transform & Rigidbody. Also allows you to temporarily disable interpolation on an object, and properly set the Gravity and Kinematic properties on a synced physics object.
  • Networking.SetOwner now works immediately - you can update variables immediately after changing ownership and the changes will apply properly.
  • Join-In-Progress issues fixed, you should no longer have issues with variables not being Deserialized for Players who join the world after they are changed.
  • New VRCObjectPool for managing collections of objects, including automatically managing their active states. Use this instead of Instantiation when you want a lot of networked objects.
  • New Debugging tools for seeing info about networked objects in your world, including the current owner, the data being used, and state information.
#

How do I use it?
As a creator, read through the new documentation to understand what has changed, download this SDK: https://files.vrchat.cloud/sdk/VRCSDK3-Udon-Networking-Beta-v5.unitypackage, implement new Manual UdonBehaviours, Array Types, etc as needed, test in new Beta branch. The UdonExampleScene has been updated to use the new features, and includes a few new examples as well - for Array Sync, Object Pools, and Pens.
As a general user, you're welcome to switch to this beta branch to test your favorite worlds - but give the creators some time to update things.

To use the beta branch of the application, use the code SyncYourTeethIntoUdon and you'll unlock the Udon Networking Update branch. This won't work with Live!

Any updates we provide will be announced in the #open-beta-announcements channel. To get pinged for updates on this project, please check #open-beta-info and click the vrcUdon emoji. You'll be assigned the <@&821522584871895051> role and will be pinged any time we make a relevant announcement, such as updated SDKs or etc.

How to report issues?
We've created a new section on our Canny here for bugs and feature requests: https://feedback.vrchat.com/udon-networking-update

When will the full version be released?
When it's ready! 😉 We want to make sure everyone's amazing worlds work better than ever, and no existing content breaks.

errant siren
#

Excited to share this work with everyone!

turbid horizon
#

🎉

coral pier
#

oh?

fresh stump
#

this looks ncie

cedar hill
#

pog

turbid horizon
#

@sand goblet wake the fuck up samurai, we've got a city to burn.

drowsy quiver
#

pog

coral pier
#

yeah panda wake up

lusty radish
#

no persistence? 😦

grave laurel
#

Finally yo! New Udon things for me to learn slowly and by that I mean A whole year to learn...but that's just how I learn.

sand goblet
#

...

#

... ... ...

dusty burrow
#

what about udon messaging ping which is around 2000 ms?

sand goblet
#

I have risien

#

Object sync is outdated

tranquil hull
#

give me some polease

sand goblet
#

Network events overrated

shrewd veldt
#

no

grave laurel
#

tupper give me that.

sand goblet
#

Long have we waited

errant siren
#

before people ask about it - This update does not include Custom Network Events with Parameters. However, it is a necessary update for that feature and many many others 😄

grave laurel
#

I want some.

oblique reef
#

Defend me from them that rise up against me

undone wren
#

New VRCObjectPool for managing collections of objects, including automatically managing their active states. Use this instead of Instantiation when you want a lot of networked objects. so does this mean we can use this to enable and disable game objects and have that synced without needing to setup a system to sync if something is enabled or disabled on our own?

sand goblet
#

Now we manually syncing and somehow end this sentence with aited

undone wren
#

like object sync for enable/disable?

#

oh nice! that will make things so much better!

sand goblet
#

Anyway I have to go make a video explaining features now

#

Good good good

frozen igloo
#

sort of. It's meant to be almost as simple as spawning/despawning. You tell the pool "hey give me an object" then "ok put this object away"

tranquil hull
#

don't forget to go to #open-beta-info and click the vrcUdon emoji to get pings for updates on this beta

iron vortex
grave laurel
#

oh btw tupper is only having one or the other role for open beta intentional?

sand goblet
#

The pool is solid from what I have tested.

grave laurel
#

Would like to have both :p

tranquil hull
#

ohhhh

#

hmmm

#

ill figure it out

#

sec

grave laurel
#

I'll give you thirty minutes.

turbid horizon
tranquil hull
#

ya thats prob enough

lofty shoal
crisp echo
#

Steam is bad at fetching new betas at times.

sand goblet
#

Right so it is half 11 and I have been valiantly attempting to fix my sleep for the last few days. And this server doesn't allow for posting meme GIFs. So imagine I am posting the Undertaker doing his sit up no sell thing

errant siren
grave laurel
#

Steam is just that - Steam powered. It's slow.

scenic heath
#

yeah usually just restarting steam makes things popup

undone wren
sand goblet
#

Yes

#

But that is a misuse of the system.

#

You are better off using a manually synced bool for that

blissful lark
#

If you want to give an item to each player that joins for example, you'd use the pool

frozen igloo
#

it's meant for large groups of objects

sand goblet
#

Yeah

#

For folks that care, there is a LOT of nuance to this update.

#

I am going to get out some example work in a bit

frozen igloo
#

if it's just for a single object, that's overcomplicating it because you'd still need an udonbehaviour to work with the pool, then the pool itself. If you just use a manually synced bool, all you need is the one udonbehaviour with the one synced bool

sand goblet
#

Has byte[] been made syncable yet btw?

#

Or do we still have to base64 encode

frozen igloo
#

I don't think so

sand goblet
#

Ugh

#

Whelp time for a canny

blissful lark
#

has byte been made syncable 😔

errant siren
#

wait - dan said it was

tranquil hull
errant siren
#

and I listed byte[] here:

blissful lark
#

it's certainly in the supported type list

errant siren
#

lmk if it doesn't work and I'll update the docs

grave laurel
undone wren
#

wouldn't you need some manager to take care of syncing enable/disable anyways since the udon script can't run on the individual object while disabled anyways? so I would need some "manager" udonbehaviour that then tells new joiners which objects in the scene are enabled and disabled

sand goblet
#

Right if you lot have byte array syncable then that is v.good news for the FSP.VRCBilliards port.

blissful lark
#

does it work though? Byte, sbyte, short, ushort have been broken for a long while

#

they all get deserialized as int on the receiving end, which will basically always crash the receiving behaviour due to heap type mismatches

errant siren
#

oh - I don't have a test for it. If those were broken before, they may be broken still

sand goblet
#

Oh no

#

Actually before hand the behaviour was specifically that sync would fail

#

Would throw due to a bad cast

#

One nerd stat atm

#

A serialisation is 72b + what looks like 2x the bits actually serialized

#

You have 18kb and catch up serialization load sits on Owner

#

Will have that re tested and then written up

errant siren
#

We weren't aware of this issue - @frozen igloo is testing now and we'll put it on the list of things to fix.

obsidian cedar
#

Oh my god I think I am dreaming .. gonna be testing so much of this today..

oblique reef
#

We need a VRNow in celebration

obsidian cedar
#

Yes

#

We need VR now emote.. vrcLabs

fresh stump
#

true

undone wren
#

I look forward to updating ring of fire with this

turbid horizon
#

okay regression benchmarks are gonna take a bit since I have to use VNC from my laptop on mountain satellite internet

#

expecting it to be the same as closed beta anyway

jovial gyro
#

sooo.... we have reliable sync now? like sync it once and late joiners also get that value? That would really be awesome!

woven pewter
#

doc clarification - object ownership seems to indicate that OnOwnershipRequest will always be called to confirm ownership transfer but the notes above suggest immediate ownership transfer is possible. Is this just a doc miss for the "event isn't implemented" case?

ruby tulip
#

was too excited and missed this new channel existing.

jovial gyro
#

ah found the docs, never mind 🙂

turbid horizon
#

I got confused too

pure cypress
#

yeah same

ruby tulip
#

i was mainly confused about the old sdk linked in open beta

frozen igloo
#

@woven pewter From what I understand it is speculative, which means that when you take ownership, on your client it will assume that the change happened immediately. But if the previous owner denies it, then nothing will be sent out to the other clients and it will be reverted

errant siren
woven pewter
solar depot
#

Aaah yes finally can get my hands on the goods.

grand bobcat
#

P O G

#

!!!!!!!!!!!!

#

im so happy

solar depot
#

Very much pog

obsidian cedar
#

Though any ideas if it works with UdonSharp ? Prob not Merlin is going to have to release update I'd guess

frozen igloo
#

all ownership transfers can be "immediate" in the sense of "taking ownership then immediately setting a synced variable". The only cases where that wouldn't work is if the previous owner denies it, which is something the author of the script would decide

#

udonsharp is already updated

#

30 mins ago

obsidian cedar
#

Oh

#

Lol I am slow

frozen igloo
woven pewter
obsidian cedar
#

Well time to get up from my bed and not sleep tonight

frozen igloo
woven pewter
#

fair enough

#

would be nice if that could be optimized someday for the common case of "anyone who wants ownership can have it" but not critical immediately I guess... though I do wonder if that'll cause visible lag on pickups

frozen igloo
#

I'm not following, what are you asking for?

#

oh I see. I don't think this new method is any slower, even with continuous sync. And when it comes to manual sync, it's even faster than network events

oblique reef
woven pewter
#

so, I don't know what was happening previously, but just from a theoretical perspective, if you have to ask the current owner, you've added a round-trip to the time before the new owner can start transmitting. If that's already happening today, welp, not a regression, but an area for future improvement perhaps.

#

it would also encourage horrible hacks like using pooled objects to transmit without ownership handovers to reduce latency 🙄

frozen igloo
#

having a pooled object for each player is hardly a hack, there are many very good reasons to have such a system

oblique reef
#

As a note in my screenshot it still defaults to a non-existent program type if I haven't imported U# yet lol

midnight kraken
#

Does this branch address the lerping issues with pickups?

woven pewter
#

anyway, it's all a bit speculatey, I remember seeing danly talking about potentially skipping ownership transfer confirmations in the case where OnOwnershipRequest is unimplemented, so mostly I just want to have confirmation of whether that optimization was implemented yet or not

frozen igloo
#

eh, with manual sync the latency should be plenty low enough for transferring ownership, setting variable, and sending a message

woven pewter
#

1xRTT is potentially upwards of half a second :/

frozen igloo
#

That is only true if you use continuous sync because it has a very low network priority. The true latency is within a couple hundred milliseconds, it's just that low priority traffic takes forever. Manual sync and ownership transfers are high priority

errant siren
woven pewter
#

No, I'm referring to speed of light/internet here. With an ownership request model, you have: A -> VRC: Request owner (200-300ms), VRC -> B: Request owner (200-300ms), B -> VRC (200-300ms) Ownership transfer approved, VRC -> A: Ownership transfer approved (200-300ms)

#

and only then can you start serializing. So that's an extra second or so to complete the ownership handover, if you're network-far from the VRChat servers

errant siren
woven pewter
#

this can be avoided (and this was discussed in closed alpha), but it's unclear if that was in fact implemented 🙂

midnight kraken
frozen igloo
#

As manual sync pushes latency down further and further, that bit of overhead may become more apparent. But as it is in this networking beta, it's already a heck of a lot better than live already

woven pewter
#

yep, if this is overall an improvement over live, I'm all for it, I just want clarity in documentation on the latency costs of various operations

#

if SetOwner is "free" (ie, has minimal overhead beyond just manually syncing things) in some situations, that informs my networking design. If it's expensive and takes potentially over a second to complete, that also informs my design.

#

I'll just put this into a canny post I guess 😛

strange gyro
#

Does manual syncing perform any other traffic optimizations such as only sending variable data that has actually changed since the last serialization?

blissful lark
#

it's manual sync, you decide that

strange gyro
#

They only expose UdonBehaviour.RequestSerialization, but that implies that everything about the behaviour is still synced at once, but no details on what data is actually synced at that point

blissful lark
#

?

#

it syncs all the data in the behaviour at once

strange gyro
#

But what I asked is if they perform any other optimizations to reduce wasteful sending of variable data that doesn't need to be synced

woven pewter
#

you have control over exactly when things are synced, and all syncs are received, so you can do those optimizations (or not), right? 🙂

strange gyro
#

If I have 10 synced variables and only update one of them, 9 of them don't need to be sent over the network

#

Unless a late joiner enters the world

woven pewter
#

if you have a mode where sometimes some variables are sent and some aren't, you now have some overhead to describe which variables you're transmitting

frozen igloo
#

you can't pick and choose which variables get synced, gotta sync the entire object

woven pewter
#

you could implement this yourself by syncing a byte[] potentially 😛

frozen igloo
#

however, with manual sync, there is zero networking overhead to have an udonbehaviour just chilling doing nothing. So if you really want to you could have a whole udonbehaviour for the sole purpose of syncing a single variable

#

that being said, I really don't think that's necessary because manual sync can sync a lot of data very quickly

obsidian cedar
#

what does a lot of mean

#

😄

woven pewter
#

Does VRC Object Sync sync all rigidbody settings, or just some of them? (IIRC, previously Drag and Angular Drag weren't synced)

ruby tulip
woven pewter
#

huh, is that manual sync running ahead of IK?

ruby tulip
#

things have changed since the videos so dont take them as 100% accurate.

strange gyro
#

One more question is about the sync limits, the docs say the maximum output is 11kb/s, is that how much you send out to each player individually in the instance, or is it the maximum for up to 80 players in an instance combined?

ruby tulip
#

per player.

strange gyro
#

Alright cool

obsidian cedar
#

Well time to try and rework literally the whole late-syncing process in my world 😄

#

Wait hm.. Gotta ask.. Is string[] sync planned ?

errant siren
#

@obsidian cedar no, it's not.

obsidian cedar
#

:/

errant siren
#

we'll have byte[], but our network engineer would rather no one tries to sync all of the bee movie script

obsidian cedar
#

😄 Understandable I guess

woven pewter
#

Data and Specs says that continuous sync is limited to 200 bytes per sync; is there a limit for manual synced objects as well?

#

and, does the synced string limit apply to manual synced objects as well?

dry zodiac
#

such a call out

obsidian cedar
#

🤔

sand goblet
#

string[] would be a 2D array

#

char[][].

#

This is only 1D array sync.

sudden current
#

well now that you mention it...

dry zodiac
#

the challenge is accepted

sand goblet
#

OH and before anyone asks about str len sync

#

Manual sync has fixed the str max len bug

woven pewter
#

hooray!

sand goblet
#

You can send something stupidly long now

#

As long as it fits in 18 bytes

obsidian cedar
#

can't you theoretically convert string into int 😄 ?

sand goblet
#

yes

woven pewter
#

... 18 bytes?

sand goblet
#

Yeah you have 18b.

obsidian cedar
#

🤔

woven pewter
#

we can send strings of up to... 18 bytes.

sand goblet
#

Yup.

#

Actually no it's like 18.b kb

#

Sorry

#

KB

#

Brain fart

woven pewter
#

that's slightly different

sand goblet
#

Yes

#

It's 1am

#

sorry

obsidian cedar
#

18b that would be bit.. low

sand goblet
#

Also I think data inflates by 2x when serialized so you probably cap out at 9KB

woven pewter
#

probably best to use byte[]

sand goblet
#

Generally yes.

#

If it works