#udon-networking

1 messages · Page 16 of 1

brisk magnet
#

Also there are cases where a legal play is made but then has to be rejected due to the timing. Same thing happens irl.

If there one slot in the cycle remaining and two players try at the same time, the first card to hit the table wins and the other is rejected I suppose in vrchat it will ither have to be the first signal to arrive unless I can track the local utc times at time of click and sync those along with the input

#

Would eliminate ping advantage

#

And individual moves may contain 1 to 4 cards so it's an array of inputs we have to sync and for example for the above reason 3 cards may be accepted and 1 might be rejected and returned to the owner

#

Evan if the local client saw all four as legal in that moment

#

It's a fun game but a pain to code so far lol. The rules form a pretty wide decsion tree.

brisk magnet
#

if a player leaves a world what happens to their player ID in that instance, does it still point to anything. and if they rejoin will they be given their orginal ID or a new one?

twin portal
finite sierra
lone zealot
#

That way you have a per-world unique player id

#

Which is the best middle ground

brisk magnet
#

thanks for the replies @twin portal and @finite sierra, makes what I was seeing make way more sence able to work around it now. but yea a uid for the user would be nice.

Btw as an aside do you know if its possible in vrc persistance for a client to read data for a player that is not currently in their instance, for the purposes of somthing like an in world leaderboard

lone zealot
#

Just store a GUID/UUIDv4 as a string in their persistent data? and check if it is empty when they join and if so, then generate one an save it?

sick gull
#

IDK why we can't acces their VRC Ids... so dumb

#

w/ the persistent thing.

Do you generate a synced seed at world load? and that drives ur UUID thingy?

lone zealot
#

You just generate a random uuid for each user if they dont have one and store it using persistence. I dont know how to put it into simpler words...

sick gull
#

ah so everyone gets their own perm id?

lone zealot
#

Yeah but its only per-world

#

UUIDs are inherently unique (thats what the second U stands for). There is 2 to the power of 122 generatable UUIDv4 so the change of getting the same twice is astronomically small.
However you dont just want a unique string, you want a unique identifier, so something that is unique per player, but always the same for the same player. And thats what persistence allows you to do.

finite sierra
lone zealot
#

No, you just implement it yourself

#

Its not very difficult

finite sierra
#

i know.

twin portal
#

leaderboards have been implemented, in some very creative ways

#

I've seen it where a leaderboard list is shared and synced with every player in the lobby persistently; then when they join another instance, it gets synced with those new players, then again, and again, spreading kind of like a disease, until there's a point where basically everyone is on the list for everyone

fallow mountain
#

Is it possible for VRC to upload (and download) text to somewhere?

twin portal
#

download yes, upload sort of

obtuse echo
finite sierra
#

hmm are there any Music players for worlds premade? that uses no data out for the indivual person? aka Local only

twin portal
sick gull
#

I am attempting to make a moderation panel for my world.

Would giving everyone a player object that stores their permissions be a good idea?

twin portal
#

it would work, but I think stuff like permission levels would be easier to store as PlayerData

sick gull
#

W/ Persistence?

twin portal
#

yes

sick gull
#

Ok, I'll have to take a look.

Is your approach to this

PlayerData w/ all permissions

On world load, you generate a synced seed which will now be like the "key" on whether we reset their permission level or load it up again?

twin portal
#

well the actual mechanisms would be up to you really

sick gull
#

I guess I am looking for a direction. I am currently repurposing Demon Permission System. Just learning a bit as I go.

I just got to selecting a user to do moderation on them.
I repurposed the leaderboard prefab so I could def just store their info there.

twin portal
#

so yeah a PlayerObject with the variables you need on it would technically work, but PlayerObjects are really made for stuff like, every player needs to have a copy of some object in the world, like a sword, or a car, or something.
PlayerData doesn't exist within your world, it's linked to just the player. You could for example add a value to PlayerData to determine if that player is a moderator or not
you'd just be loading and storing whatever values you need, and do checks on whatever values they have to decide what they can and can't access

sick gull
#

Appreciate it gang

fleet arch
sick gull
#

I am well aware 😦

#

I wish VRChat had a framework for this stuff

fleet arch
#

There can't really be a framework when there's no server side udon execution

craggy pivot
#

Hi I'm new to Udon, I've been using UdonSharp in a game world I'm working on. Does anybody know the best way of networking an animator? I have an object that moves around via the animator and its position needs to be synced very closely.

All I can think of rn is to sync the variables that trigger the state transitions, but im worried if somebody's lagging the timing (which is crucial) will be off. any ideas? maybe this would be negligable.

twin portal
#

usually the best you can do is SendCustomNetworkEvent to everyone to play the animation, so everyone will start at the same time. Any more than that would probably take some complicated control of the animation, jumping ahead in it if it's detected someone is behind

craggy pivot
#

gotcha. I will assume for now it will work fine, and hope it doesnt come to that lol

#

thank ya

brisk magnet
#

so in my code it seems I am somtimes hitting some kind of limit of how often I am allowed to request serilizations over a period of time. beacuse some of them wont actualy fire unless I att a seccond of wait time. is there a way to programaticly check if you are at this limit prior to attempting to send?

brisk magnet
twin portal
#

the network could possibly be clogged

#

there is a limit

brisk magnet
#

checked that clogged came back as false not evan close to the bytes per seccond limit

twin portal
#

hmm you could output the result struct from OnPostSerialization, see if you can catch any failures

#

might help narrow down where and when it's happening

brisk magnet
#

on this set of code lines 131 and 132 would run for the owner but no one else

#

but only if there are 3 players in the lobby

#

if there were only 2 in the lobby it would run just fine for both

#

doing this fixed the issue for all cases

#

but im trying to find out if theres a way I can get this to not have to wait a seccond

brisk magnet
twin portal
#

it only runs for the owner

brisk magnet
#

didint see it run on any of the 3 clients

twin portal
#

if that function doesn't run then serialization isn't even being attempted

#

you should at least see it failing

brisk magnet
#

my testing would sudjest its not evan trying and thats what id like to know why on

twin portal
#

in that script, is the player running the function the Owner of both player.hand and session.df?

brisk magnet
#

only the owner runs that code

#

sorry left somthing out

#

the owner of that particular udon behavoir is not runing that code but rather the owner of all those other objects that are requesting serilization

#

the session owner owns the hand and df objects but not the one the script is runing in

twin portal
#

the aren't the owner of the script that function ServerSideProcessInput() is on, but they are the owner of those two they're requesting serialization? ok that should be fine

brisk magnet
#

yea and the code works with the time delay

#

so theres some kind of rate limiting going on

twin portal
#

hm calling ServerSideProcessInput() in OnDeserialization() will cause them to RequestSerialization in the same frame. Serialization doesn't happen on exactly that frame, it happens on the next network tick. So it's possible due to the timing, a serialization is getting skipped because more than one was requested on the same object before the next network tick

brisk magnet
#

whats weird is in other parts of the code I make way more requests without hitting this issue

#

so your saying the issue could be that its requesting a serlization in the same frame it recieived one

#

how often is a network tick?

twin portal
#

documentation doesn't say, it just says it's not every frame

brisk magnet
#

going to try delaying by 15 frames and see what happens

#

the weird thing is why does it work when the player count is lower

#

well in offline vr client it works with 2 clients stops working with 3 and in live vrchat uploaded it breaks with just 2 again

twin portal
#

docs suggest to do the setting of variables and whatnot in OnPreSerialization, as this fires on the network tick right before serialization is sent

brisk magnet
#

hmm would I just be able to call that from OnDeserialization?

twin portal
#

call that? I wouldn't recommend it

#

I also generally try avoiding calling the networking functions directly, I only call RequestSerialization

#

OnPreSerialization runs for the owner, and additionally the Owner does not recieve OnDeserialization, but you're calling it so that they get it
I feel like.... idk. that might be what's breaking things, as OnDeserialization should be coming from VRChat at the proper time, not being called directly

brisk magnet
#

from my understanding calling it will just run that code in your override if you have one for the owner. beacuse Deserialization would normaly not run for the owner if request is called

#

I just do that so I have comen behaviour between the owner and clients

#

ok so interesting development in testing

#

doing this will ressult in the function not being called at all

#

and now that a revert the change back to the old code that was not working its now sudenly working without any flaws but I dont trust it lol

#

yea thought so one more re run and sure enough it breaks again

#

0.33 secconds of wait time seems to be enough and is still responsive enough ill have to do more testing tommorow. thanks for all the info though. its made the issue more clear to understand

finite sierra
finite sierra
#

also if you want something to only run on the owner. just check if the Local player is the owner. and return any other non owner.

brisk magnet
#

Most of my early bugs were a result of those calls being missing

#

But i will look into using post sterilization

finite sierra
#

also you have to have ownership of the object to call RequestSerialization

brisk magnet
brisk magnet
# finite sierra thats because it does not run on the one requesting it. or aka the owner of the ...

I'm curious though about why you shouldn't do it. Nothing in the documentation, hints at not calling it on the owner. Intact i don't see why it would have a from storage parameter without it expecting that to be possible?

What's the negative effect of calling it, and how do you know this effect exists?

As far as I can tell all that happens is the code within your override for it gets called and nothing further

lone zealot
# brisk magnet I'm curious though about why you shouldn't do it. Nothing in the documentation, ...

using PostSerialization guarantees that your "handle data" logic only happens if the data was successfully serialized.
So if your data couldnt be serialized for any reason, and you manually call "OnDeserialization" locally, then you are basically shooting yourself in the foot, by not handling the unsuccessful serialization and proceeding like it was successful.
Its usually not a problem, but when it is, then its not immediately apperant what happened/why something went wrong.

brisk magnet
lone zealot
#

Hmm...are you sure? that would be weird

twin portal
#

maybe VRC never expects a player to run both OnDeserialization and PostSerialization at the same time
so there's some undefined behavior happening

brisk magnet
lone zealot
#

Hmmm strange, but interesting

brisk magnet
#

is there any reason I wouldint want to do somthing like this? other then maybe adding abit of a wait before the retry

twin portal
#

I think that with a delay should be fine

#

currently it will attempt serialization every single network tick until it's successful, might clog it

frozen igloo
#

The only reason not to do that is that if you do it too much, it's easy to overwhelm the network

#

Also the loop is broken if result success is ever false

#

if you want a proper loop to repeatedly serialize like continuous then I'd recommend an independent delayed event loop that allows you to control the interval outside of the serialization process

brisk magnet
#

that stament is only entered if it is false

frozen igloo
#

oh that's not a loop

brisk magnet
#

theres a ! infront that flips the comparison

#

yea its only meant to send if the last one failed

frozen igloo
#

Well why is it retrying without changing anything? Serialization is not a random process, if it failed once it will fail again unless you fix the issue

brisk magnet
#

well its not failing anymore but I added it for redudancy

#

beacuse evan when it did fail it didint fail all the time. it failed more often with more ping and more clients

#

well to be more acurate it wasint evan firing before so there was no failure for it to report

#

XD

frozen igloo
#

I would prioritize putting time into why that's being so inconsistent, because it's likely your own code randomly producing something that can't serialize, not the serialization process failing

brisk magnet
#

its just an array of 6 bytes

frozen igloo
#

If you fixed it in your code already then there's no point in adding the retry

twin portal
#

at any point is the array uninitialized?

brisk magnet
#

no but it is somtimes resized to size 0. but thats never caused an issue before

#

and 100% of the failures have happened while the array was at least 3 or longer in length

brisk magnet
#

Line 131 would cause a blocking behavoir to happen if the comment was taken out

#

but 269 in this other files does not

#

so thats interesting

twin portal
#

you've got quite the knot to untangle

brisk magnet
#

yea the plot just thickened

#

so I got another case of the signal not evan trying to fire

#

Post didint get called ither

#

line 133 sould have at least triggered the log on the left

#

turns out as suspected weather or not I was using post or not had nothing to do with the error just got a lucky few bug free executions after the recompile

twin portal
#

if post isn't called then serialization was never attempted

#

and the only time I see that, is when the player was not the owner of the object, but they called RequestSerialization on it

brisk magnet
#

they are definiatly the owner

twin portal
#

I'd still be worried about it and would be worth investigating

#

I don't see any actual ownership checks for these functions

brisk magnet
#

all ownership of everything in the game is given to one player at the start and then is not allowed to change after

#

I need to check that that function issint missing anything

twin portal
#

you could edit any RequestSerialization to test for ownership; if they are owner, run RequestSerialization, if not, output an error like "player requested RequestSerialization on [objectName], but is not owner!"

brisk magnet
#

oh you mean inside of the override?

#

thats a good idea

twin portal
#

no for the function call

brisk magnet
#

now Im confused about another thing. if there was ownership issues this whole time. Why was it allowing me to have a non owner do it just by waying 0.33f more secconds?

twin portal
#

no idea

twin portal
brisk magnet
#

yes you did

#

about to apply a change and test again

twin portal
#

it didn't run because ServeSideProcessInput is private

brisk magnet
twin portal
#

yes, any function you attempt to call any of the CustomEvents, must be public

brisk magnet
#

good to know

#

well I have nothing to lose by making it public I only made it private beacuse I had no itention of calling it from somewhere else

#

does networking.getowner use an API call?

#

or is it just photon

twin portal
#

don't know what you mean by that

brisk magnet
#

is it going to make a request to vrchat that leaves the world instance

twin portal
#

don't think so.... info on who is the owner is known by the client

brisk magnet
#

beacuse from what I understand if you get a vrcplayerApi object it will do a request outside

brisk magnet
twin portal
#

if this info shows up in the debug, I assume it's already stored locally

#

but who knows, and I also don't know why this would matter

#

the ownership test could go to the moon for all we care, it's the result we're looking at

brisk magnet
#

well it seems all the bugs are fixed now only one odity tho

#

functions called from refs to other objects wont fire from in here

its not nessisary but I wounder why.

peak kindle
#
    [SerializeField] UdonBehaviour[] microphones;
    [FieldChangeCallback(nameof(microphoneOwners))] private string[] _microphoneOwners;
    private bool localPlayerInCollider;

    public void Start() {
        //Initialize on world load, but only once.
        if (microphoneOwners == null) {
            _microphoneOwners = new string[microphones.Length];
            for (int i = 0; i < microphoneOwners.Length; i++) {
                _microphoneOwners[i] = "";
            }
        }
    }
    public string[] microphoneOwners
    {
        get => _microphoneOwners;

        set { //This is only run by the local player, but it should run on all clients
            Debug.Log("RECIEVED");
            //Check all pairs of array elements. If there is a difference between the new and current string, call function
            for (int i = 0; i < microphoneOwners.Length; i++) {
                if (microphoneOwners[i] != value[i] & localPlayerInCollider == true) {
                    OnChangeMicrophoneOwner(i, microphoneOwners[i], value[i]);
                }
            }
            _microphoneOwners = value;
            Debug.Log(microphoneOwners[0]);
        }
    }

    public void NewMicrophoneOwner(int microphoneIndex, string microphoneOwner) { //This is where the network variable is meant to be set
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        string[] temp = new string[microphoneOwners.Length];
        temp[microphoneIndex] = microphoneOwner;
        microphoneOwners = temp;
        RequestSerialization();
    }

I'm having an issue where NewMicrophoneOwner does not call the microphoneOwners setter on other clients. I can't find anything online, and there are no errors anywhere in the logs. Does anyone know why this might be?

twin portal
#

is microphoneOwners synced?

peak kindle
#

I may be stupid

strange gyro
#

Don't use FieldChangeCallback with arrays, it doesn't work how you'd expect

peak kindle
#

What should I use instead

strange gyro
#

OnDeserialization

strange token
#

Networking with arrays is horrible because of that one issue

#

Why not just notice the content changed and serialize properly?

#

The fact that it only detects changes on array LENGTH is insane to me

twin portal
#

well you see. do you know how arrays are actually represented in memory

strange token
#

I believe they’re a reference to a point in memory where the content begins? 🤔

sick gull
#

It's like statically set and whenever you add an item, isn't the array duplicated?

twin portal
#

yes, the array "itself" is just a pointer to the memory location where the array "data" resides.
so myArray != myArray[0]. adding the index is just saying "give me the data at this place the memory is pointing to", similar to dereferencing
So a fieldChangeCallback can only react to a change to this pointer. Changing the Length would require defining an entirely new array, which will change the pointer and register a field change. But changing the content of the array won't since there is no change to the underlying pointer

sick gull
#

Arrays are good for instances where you know the length is static

twin portal
#

in C# the length of an array cannot be changed without defining a new array

raw umbra
#

This may be a dumb question, but is "Networking.IsNetworkSettled" actually functional?

#

I have a script which needs to wait for the whole world to be serialized first, so I have a loop waiting until this value is true

#

What I'm seeing is it gets set true seconds before the actual last objects deserialize

#

Which to me doesn't make sense, is it broken or is there some other factors I need to account for

tulip sphinx
#

are you testing in game? client sim lacks many networking features, may be one of them.

raw umbra
#

With a bit more poking around I do see a false serialization occuring

#

The data for the PlayerScripts is getting filled with blank garbage which may be tripping the IsNetworkSettled, but I'm pretty sure the first serialization is supposed to be the last serialization thats occured in the world which does occur... seconds after I need it to be there ~.~'

#

I'll try and see if this may be an artifact of offline testing or a genuine issue on live

#

If the former I'll make a ticket, if the latter rip us all

twin portal
#

hm yeah I guess IsNetworkSettled is just weird or somethin. I thought I saw a known issue somewhere about it but I can't find it. IsNetworkSettled is always evaluating true for me, even if I'm spamming syncing variables?

raw umbra
#

Ye confirmed its an artifact of offline testing

#

So basically offline testing is accepting junk empty serializations and failing

#

@frozen igloo Is this a known issue or should I file a report about it?

finite sierra
# raw umbra So basically offline testing is accepting junk empty serializations and failing

well first of all you have no Synced Variables otherwise there would be data serialized. and second Offline testing works just fine. third of all waiting for the world to serialize? is not a thing. its per object basis. and its consumed per object. which means if you for some reason would need to wait for the whole world you would have to check every single object that has serialized data.

#

and fourth yes. the IsNetworkSettled is working as intended. it checks if there is any data and if so it wil return true.

#

in the instance that is.

twin portal
#

judging by the description if IsNetworkSettled, it definitely is a thing to wait for serialization to finish.

IsNetworkSettled: Returns true if all the data in the instance has been deserialized, applied, and is ready for use.

finite sierra
#

regardless of that. if no data is serialized that just means there is no data synced.

#

not to mention im sure its not a good idea to have a loop that constantly checks if its settled or not.

hearty vale
#

Anyone have any clue why my manual networking code might work with offline build test clients, exactly as expected...

But then not work on the actual live uploaded map between me and a friend?

twin portal
#

clientsim vs. local test vs. live can end up all being different

#

local should usually be pretty much the same as a live test though

hearty vale
#

apparently not

twin portal
#

depends on what you're doing

#

maybe the latency isn't accounted for

hearty vale
#

would that cause udonsync'd arrays to never update?

twin portal
#

latency no not usually, but arrays specifically won't network under certain conditions

hearty vale
#

I have an array of int, I'm only updating two indices of the overall array

twin portal
#

have you initialized the array at least once before RequestSerialization, and are you checking the array values OnDeserialization or OnValueChanged?

raw umbra
#

It for some reason records the data as zero on the player objects despite successful serializations

#

I was able to confirm with serialization result, and the non late joiner got the update

#

My guess is offline testing isn't able to properly restore for some reason, it does a second later, but a second too late since IsNetworkSettled will accept the false empty serialization as being valid

hearty vale
#

I have a local copy of the array that is initialized to the values of the sync'd copy within Start()

before setting them I'm calling

Networking.SetOwner(LocalPlayer, this.gameObject);

then I set two indices of the sync'd array

then I call RequestSerialization()

the stuff I do with the array is processed in OnDeserialization() and works fine in playmode (solo), and in local build test (2 local clients), but not in live game (me and a friend)

twin portal
#

the one sending the serialization will not execute OnDeserialization

hearty vale
#

I am calling OnDeserliazation manually for the sender right before RequestSerialization

twin portal
#

dont do that

hearty vale
#

no?

raw umbra
#

Sender calls on Serialization, reciever calls deserialization

twin portal
#

don't call networking functions directly except RequestSerialization, you'll get unexpected behavior

raw umbra
#

Depends on what your trying to do but you could either do preSerialization or postSerialization for the sender depending on what your usage is needed

raw umbra
twin portal
#

you can also use OnPostSerialization and output the "result" struct and see if it's actually being sent successfully

hearty vale
twin portal
#

if you have the sender run OnDeserialization, you're assuming that the serialization will be successful, but if it actually isn't, only the sender will run OnDeserialization, as the reciever won't run it due to never receiving it

hearty vale
#

isn't it supposed to be reliable in manual sync?

#

or can vrchat just randomly drop RequestSerializations

twin portal
#

just because it's reliable doesn't mean it will succeed

hearty vale
#

what does reliable mean XD

#

so it's unreliable

twin portal
#

if the serialization is successful then it is guaranteed to arrive. but if it doesn't send at all, then of course everyone else won't receive it

#

and serialization fails under specific conditions that is usually caused by the programmer

hearty vale
#

is there any reference of what these conditions are that it may fail

twin portal
#

there isn't a clear and definitive list, but the most common is uninitialized arrays, the package being too big, or a non-owner attempting to call RequestSerialization or write to synced variables

hearty vale
#

is it possible for Networking.SetOwner(LocalPlayer, this.gameObject); to fail

#

I sometimes feel like I get networking code that just fails randomly with no explanation

twin portal
#

setting ownership can possibly fail if the negotiation fails
either if you have your own custom negotiation, or if you're trying to request ownership of a PlayerObject

#

I generally try not to change owner if I don't have to in order to avoid stuff like this

#

instead of switching ownership, just request the current owner to run the logic

hearty vale
#

hmm... vrchat networking example says I always have to change owner for manual sync

twin portal
#

yes this is true.... if you want to do the manual sync

#

but one client can request the owner to do it.

hearty vale
#

through a NetworkEvent?

twin portal
#

yep, SendCustomNetworkEvent, and aim it at just the owner

hearty vale
#

can't those fail sometimes too

twin portal
#

or wrap your synced variable sets and RequestSerialization in an ownership check

#

SendCustomNetworkEvent is guaranteed to arrive

hearty vale
#

hmmm

#

one other question;

I'm synchronizing a local copy of my array with the sync'd copy of the array (so I can detect changes)

does it make sense to initialize the local copy of the array within Start() to the value of the sync'd copy

twin portal
#

if they're meant to be the same then yeah I assume so

#

I usually just output values to a TextMeshPro on Update so I always see what the value is

#

tbh I would say initialize any array you plan to use, random stuff just breaks if you accidentally feed it an uninitalized array
just setting it with the default constructor (int[] array = new int[7]) is good enough to prevent uninitalized array problems

hearty vale
#

my arrays are SerializedField so luckily already initialized no matter what

#

looks like removing the manual call of OnDeserialization fixed it?

twin portal
#

ayo

hearty vale
#

looks like I need to handle removing the values OnPlayerLeave or whenever

#

XD

finite sierra
raw umbra
#

I then recreated the exact same problem in an older project

#

I also see clear errors from VRC's end about LSM storage issues which may/maynot be how serialization storage is used to pass proton last states to late joiners (Because didn't deserializing every object for each join get fixed a while back)

#

Either way, its not reproducable on live, so my issues fine. I'm just waiting on phase to confirm if its a viable bug

finite sierra
#

oh yea no those LSM storage issues i get on Offline too. but not online

hearty vale
#
    {
        if (!player.isLocal)
        {
            return;
        }

        _WarpRoom_UpdateEnd(-1, previousRoomId);
    }```

so I'm told the person leaving doesn't call this event, meaning this code would never run

so I changed to

```public override void OnPlayerLeft(VRCPlayerApi player)
    {
        if (!player.IsOwner(this.gameObject))
        {
            return;
        }

        _WarpRoom_UpdateEnd(-1, previousRoomId);
    }```

because _WarpRoom_UpdateEnd needs to sync a variable (it subtracts playercount by 1)

so I let the owner of the manager object handle it (there should only be one)

but if the owner leaves... then this would fail too wouldn't it?

and the same problem would happen if I tried to use the instance Master wouldn't it?

how should I do this?
twin portal
#

ownership should transfer before they leave? as every object always has an owner

#

I would assume so at least or this would be a common problem

hearty vale
#

I realized another problem, I need to remove the player who left from the player counter of the room they were in (there are 15 rooms with separate player counters)

twin portal
#

are you counting them based on the player entering a collider? and then subtracting when they leave it?

hearty vale
#

nope, it's based on when they press a button to enable the room

#

but I'm thinking of just switching to that

twin portal
#

you could loop through the room and just check for the player's id or something, then remove it if found

hearty vale
#

hmmmmmmm

#

so an array that holds each player's ids

twin portal
#

yeah how are you storing them currently?

hearty vale
#

maybe if I do that I can remove the network sync stuff too

#

it's just a playercounter for each room right now

#

add 1 when the room is enabled, subtract when it is disabled

#

only 1 room is on at a time for each player

twin portal
#

hm...

#

I can think of a few ways to handle it

hearty vale
#

the end goal is I have a UI panel that tells people how many players are in what rooms

#

or have which rooms active

tulip sphinx
#

ontriggerenter/exit counter will always fail long term, rather make periodical/event triggered checks for Bounds when you need counter/list of players in area

twin portal
#

well if you account for it, it won't fail

hearty vale
#

I can also detect specifically when the players teleport to each room

#

as I am calling that myself

#

or they are by walking into it

twin portal
#

yeah if you use trigger zones it wouldn't need to be networked

#

but trigger zones get a little tricky in some edge cases

hearty vale
#

like the player collider being halfway into the ground? XD

twin portal
#

well as long as their capsule touches it it'll see it

tulip sphinx
#

even easier with bounds then, player pushes button - while zone contains another player, check next zone.

hearty vale
#

hmmm

#

and when they respawn

#

well, I think I can figure something out

#

I'll switch to an array of player IDs

twin portal
#

I did a lot of testing with trigger zones counting players

hearty vale
#

hmm.. but udon# currently doesn't support a lot of those nice array functions :(

twin portal
#

yeah you'll have to resize arrays yourself

hearty vale
#

is there a value for invalid player ID

twin portal
#

do you need to know what specific players are in the zones though?

hearty vale
#

no just count them

twin portal
#

so you wouldn't necessarily need a list of them

hearty vale
#

yea, which is why I went with a playercount at first

#

but I need to handle when they leave too

#

leave the world entirely that is

twin portal
#

but it's really just if 0 players in room > remove the room

#

right

hearty vale
#

rooms are enabled/disabled locally depending on if you choose which room to be open

#

you can leave it empty

twin portal
#

ok cool

#

so I think either trigger colliders or a combination of both trigger zones and Bounds will work

hearty vale
#

ye

twin portal
#

so if you decide to use just trigger colliders, they work fairly well, increment on enter decrement on exit

#

respawning counts as exiting, it'll fire there

#

biggest problem is when someone leaves. It does not count as the player leaving the zone

#

so what I do is just a "recount" whenever any player leaves

#

it works like:
set the playercount of the room to 0
disable the collider
enable the collider

any players that are within the collider zone with then fire OnPlayerTriggerEnter again, effectively recounting who is in that zone

#

since this all happens in one frame you don't even visually see it happening

#

Bounds checking I guess would be the more... professional way to do it. Whenever player enters zone > get player positions, and count how many are within the Bounds

#

either method should work without the need to network it

#

first method would require less checks

tulip sphinx
#

while enter from my experience is consistent, exit fails on many cases like stations, avatar change and sometimes just randomly. thats why bounds, since only reliable alternative is OnTriggerStay which is basically update event so hell no.

#

tho toggling off/on and setting counter to 0 may be nice failsafe for trigger if it does work like that

twin portal
#

it does indeed work like that

frank fjord
#

Reading the Persistence docs, I'm struggling with a few design choices:

  1. When syncing Player Data, updating any key-value pair will cause a sync of the whole Player Data. This seems unnecessary, and creates more outgoing traffic than I'd like for large Player Data lists.

  2. This seemingly creates a situation where it's optimal to use Player Objects instead, but those get synced to OTHER players, which you may not want to do. Maybe for privacy reasons, or simply not wanting to create unnecessary network traffic.

  3. But that doesn't make a difference actually because Player Data ALSO gets synced to other players? Why is this not optional? What if you DON'T want packets with saved player persistence data sent to everyone else in the world? That seems like a lot of extra network traffic for something that may almost never be needed (for Player Data)

finite sierra
#

uh. Persistence data is only your data. no one else. and Player Objects are synced but anything they have on them is not unless you have UdonSynced on them.

frank fjord
#

To me, it seems like there was an 'intent' to differentiate between Player Data as a private, simple list of information that a local player might save off infrequently, for themselves only. Things like preferences and settings, seeds, private progression flags, etc. In contrast to the Player Objects, which fit more neatly into the existing paradigm of UdonSynced objects. For things that involve interactivity and updating between players.

... I guess my assumption is off here, though, what with Player Data ALSO being synchronized to remote players...?

frank fjord
finite sierra
#

well yea. because its synced data.

frank fjord
#

Why is that necessary...?

finite sierra
#

because Persistent data is synced data

#

its replicated for all users

frank fjord
#

I feel like I just got told the moon is white because the moon is white

finite sierra
#

also how much data are you trying to Save?

frank fjord
#

Irrelevant.

finite sierra
#

its not.

frank fjord
#

I'm questioning design choices, it's not a matter of my own implementation right now.

#

But let's say hypothetically

#

that 100% of the data I want to be persistent

#

only matters to the player it belongs to

#

no one else ever needs to see it

#

... Why would I not be given a way to keep that data between the owning player, and the server?

finite sierra
#

depends on what data it is.

#

Local settings?

frank fjord
#

Sure, let's use that as an example

finite sierra
#

or rather local only data i assume?

frank fjord
#

I wanna turn post processing off, change the volume of music, disable colliders, what have you.

#

As an example

finite sierra
#

right so Local Settings yea.

frank fjord
#

No one else needs those flags, but me

finite sierra
#

well no one else will be able to use it. since its not theirs.

#

should only apply to you locally.

frank fjord
#

But they get the information anyways

#

Packets arrive over the network.

#

It IS on their computer

#

Even if the world implements no use for it

#

bandwidth was used

#

VRChat spent money sending that data over their servers to unimportant parties

finite sierra
#

only Data In is being used

frank fjord
#

and the player downloading that information spent their network download on it

finite sierra
#

when you save persistent data it should only go up for Data Out

frank fjord
#

Are you referring to the VRChat outgoing data limit? The 11 kb/s thing?

finite sierra
#

no

#

just more or less that the Data In doesn't really matter

frank fjord
#

I mean, it does 🤔

finite sierra
#

it really does not

nocturne depot
frank fjord
#

I guess I'm unclear on your logic.

finite sierra
#

also here Each world may store 100 kilobytes(KB) of PlayerData and 100 KB of PlayerObject data per player on VRChat's servers.

#

each person has a 100 KB limit. so worst case when someone joins u need to download that.

frank fjord
#

"Similarly, if an UdonBehaviour sets a key to one value and then immediately changes to something else, remote users don't receive the intermediate value."

#

... This implies that remote users are receiving something, nominally, when PlayerData is updated for any user

nocturne depot
#

Right that refers to if your client changes something. If you immediately change it back it won't get updated on the server.

#

It does not imply that the data is shared across all clients.

frank fjord
#

That's what a remote user is

finite sierra
#

When using OnPlayerDataUpdated, consider whether your script can be limited to trigger on changes for the local player, or if it needs to trigger for every remote player, as well.

frank fjord
#

Someone who is not the local user

finite sierra
#

you can tell it to only do it for the local player btw.

nocturne depot
finite sierra
#

it works similarily to RequestSerialization.

frank fjord
#

The paragraph is explaining a similarity between how normal data serialization works with UdonBehaviors, and how PlayerData serialization works

#

I don't get how this doesn't clearly imply that remote players receive networked updates about your PlayerData, when you send PlayerData updates to the server

#

It's literally talking about how if you send rapid updates about your PlayerData, "only the final state is received by remote users."

#

It's the same way RequestSerialization works, yeah.

#

... in which other players receive data, from you

nocturne depot
#

But you only receive your own values

frank fjord
#

... This literally suggests the opposite

#

OnPlayerDataUpdated. "if the PlayerData of ANY player has changed or been received"

#

ergo you can receive the data of other players

nocturne depot
#

wtf

finite sierra
#

you can try. but im sure you actually can't, because it wont match your Unigue ID.

frank fjord
#

I dunno what you mean by Unique ID

#

It gives you a VRCPlayerAPI

finite sierra
#

every person has a unigue ID attached to them.

frank fjord
#

for the player the data belongs to

nocturne depot
#

It returns (VRCPlayerAPI player, PlayerData.info[] infos), so that means if I trigger a value change, someone else receives this tuple.

frank fjord
#

EVERYBODY else (in the instance) receives this tuple.

nocturne depot
#

Correct.

frank fjord
#

which is wild and the whole point I'm trying to make. What a waste of bandwidth

#

Like sure it CAN be useful, but having it be the ONLY option?

nocturne depot
#

You can limit it

#

So you can avoid having the value sent to anyone you don't want

frank fjord
#

I don't think that's actually what this sentence is suggesting

#

I think what it's saying is that when you design interactivity in a world, think about if all players need to do their own setting of values on their PlayerData, or if only the person doing the interaction needs to

#

For example

#

if I update my volume control, only I need to update my PlayerData... but YOU are still gonna receive information about my update, even if you don't do anything with it

#

You could, however, design this dog-petting game where everyone is updating their score based on communal actions.

nocturne depot
#

Right, data is still sent, but the function is not called I suppose.

frank fjord
#

In this case, you would send a networked message to all players - through normal UdonSync channels - telling everyone to do their own updating for their persistent values

#

... This is extra gross btw because that means that in a world of 60 players, a single action that everyone wants to acknowledge in their own PERSONAL persistent data results in all 60 players receiving 59 other player's data all at once

#

Like that's a real thing you might wanna do!

#

You might want everyone to keep a score, for themselves

#

but only they care about that personal score

#

but you can't stop that score from being sent to other players, resulting in geometrically-scaling network consumption

#

Anyhow that's my rant. I'm disappointed and kinda shocked there isn't a way to reduce the network activity when it's not needed. I was sure that was going to be the inherent difference between PlayerData and Player Objects, but it seems like there is no way to have private, local-player-only persistent data that's never sent to other players too

#

Hoped that would change before launch, maybe

nocturne depot
#

Maybe like private and public fields for the json. Then omit the private fields if the Player ID does not match the UserData. This would have to be done backend on their servers of course.

finite sierra
#

if you dont need something to be synced you omit the UdonSync flag.

#

and you can still use the Persistence.

frank fjord
#

Updating PlayerData is a function call

#

it's never paired with an UdonSync tag

#

but still results in outgoing data to the server, which then turns around and sends that data back to all players

#

As for PlayerObjects, I haven't looked closely enough at the docs to see if there is some... nuanced way to have persistent data through those, that doesn't sync with other players

finite sierra
#

i dont think you get what it means..

frank fjord
#

But my assumption was that a PlayerObject only makes persistent the variables on it that are flagged as UdonSynced

finite sierra
#

you can still control who it updates for or not.

#

you can update it locally only

#

and no one else will get the update nor will new people joining get that data

#

since it was only called locally

frank fjord
#

I'm sorry, I don't understand what the gap in communication here is.

finite sierra
#

when you Update PlayerData.

#

you can Locally update it

#

or Update it for all people.

#

in the instance.

#

if you locally update it. that data you upload Will not be updated for everyone else

frank fjord
#

There is nothing in the documentation that I can find that distinguishes between sending a "local only" update for your PlayerData, and a "synced to everyone" update for your PlayerData

finite sierra
#

there is.

frank fjord
#

There is just a list of methods for setting a value

frank fjord
#

I clearly cannot find it

#

what are you seeing that I am not

finite sierra
#

When using OnPlayerDataUpdated, consider whether your script can be limited to trigger on changes for the local player, or if it needs to trigger for every remote player, as well.

frank fjord
#

OnPlayerDataUpdated is an event

#

You don't "use" it to change PlayerData

finite sierra
#

thats not even what im saying lol.

frank fjord
#

It's called automatically by the game when data was changed

frank fjord
nocturne depot
#

You write

void OnPlayerDataUpdated() {
//  Do something here
}

But no matter what the data is received for all players. You can just decide to react to it or not.

finite sierra
#

as i said.

#

you can choose what data is local and or not.

#

on receive that is

nocturne depot
frank fjord
#

Say I do something and score some points. I want to record with persistence, using PlayerData, that I changed my score.

I write PlayerData.SetInt(Score, 100)

This sends off a serialization event containing my PlayerData with the "Score" value set to 100, to the server. There is nothing in this function call that I can do besides that: indicate that value I want to change, and what I want to change it to.

The server, upon receiving this information, then broadcasts my PlayerData to all other players. There is no way for me, the original player that sent the score update, to determine who will or will not get this data.

You, as a remote player, receive a network update with my PlayerData. You can use the OnPlayerDataUpdated() event to react to getting my data, but no matter if you have this event anywhere, and no matter what you write in this event, you DID receive a network update with my information.

And my assertion is that I believe this to not be a very good design choice, as it leads to lots of extra data being sent over the network when it might not need to be in most cases.

#

I'm now going to bed. Hope that makes sense.

finite sierra
#

my guy.,

#

u can still do it locally on receiving end.

frozen igloo
#

You're correct that when you receive OnPlayerDataUpdated, you may choose to ignore certain data sources like remote players. But it doesn't change the fact that PlayerData does transmit everyone's data to every other player, and you do not have the ability to set playerdata to stay private between the player and the server

finite sierra
#

yea for now i hope.

#

are there plans to have local only and remote ?

frozen igloo
#

eh, it's definitely on our radar but it doesn't appear to be making the cut of priorities right now.

finite sierra
#

dam.

nocturne depot
#

If you do, I just wanna suggest again having public and private fields. Only send the private fields if the playerdata is tied to that player.

frank fjord
frozen igloo
nocturne depot
frank fjord
#

Well. What I mean is that the underlying data structure, a dictionary, is one 'thing.' You'd declare an entire dictionary as a public dictionary, or a private dictionary... You would not declare arbitrary elements in a dictionary as public or private, because that would no longer be a dictionary

finite sierra
#

it would honestly be better to just have the data have a Local / Remote flag tied to it lol.

frank fjord
#

Basically, would mean having to totally change the underlying data structure

#

to do the public/private split specifically...

frozen igloo
#

Regardless of the details in how it's implemented, private player data is a pretty clear idea and the interface is not the primary issue holding it back

frank fjord
#

aye

#

okay now I pass out.

#

🍞 💤

finite sierra
#

im guessing its the storage and overall networking cost? @frozen igloo

frozen igloo
#

that's part of it, yeah

#

it's more about choosing where to put the engineering time, and having other things that are more important

finite sierra
#

true.

#

im guessing Soba takes alot of Engineering time atm?

frozen igloo
#

Shrug I'm not the one making those calls

#

but it's rarely "one specific thing vs another specific thing", especially when those things are not even in the same field of development

finite sierra
#

aye

frozen igloo
#

Forwarding to more appropriate channel as #udon-general now has other chatter

frozen igloo
#

And this is without any security or UI code heh

scenic sky
#

Thank you for writing it all out that

#

I feel hopeless again xD

#

So many things in there iv didn't expect and had a hard time understanding

#

Do I truly even have a shot at learning on a level like that?

frozen igloo
#

Which part is intimidating? The networking, the code, the syntax, the comments, the architecture decisions?

scenic sky
#

The entirety of it honestly. I just didn't expect it to be that massive with so many things to account for..

#

I wouldn't even know where to start to learn that

#

I thought i was getting somewhat good at U# but it seems I was horribly wrong

frozen igloo
#

There's only a small number of moving parts here, the boilerplate and comments just make it look big

#

The extensions especially can be ignored, they're necessary but irrelevant to the actual function. In a normal development environment they'd be hidden away in a different file

#

The onplayerleft is just an extra add-on, not critical for the primary function but a separate process that cleans up behind you

#

The OnDeserialization > ApplySerialization part is super simple, just routing messages around

#

so that leaves only two key parts:

  • The code that creates the state (VerifyPlayer)
  • The code that applies the state to the world (ApplySerialization)
#

Those two functions are both pretty small in their own right, just padded with a bunch of comments to describe what's happening

#

but overall, the primary goal of this script is that rather than communicating to a specific player what their status is, it maintains a complete state of what everyone's status is at all times, and only modifies that state to add or remove people. When you do that, it allows you to write much cleaner code that simply applies that state to the world, rather than trying to hold onto some local copy and worry about whether or not you received the message

#

It also means that you could build a UI where you can see who is verified, which is especially good for an admin system. And you can be confident that that UI represents the exact same, true state of the world that everybody else is operating under, not just whatever messages you happened to receive

scenic sky
#

I'll take the time to read this shortly (just at work) thank you for explaining

frozen igloo
#

oh yeah it probably looks a lot worse on mobile, try plugging this into a proper code editor when you get home and it'll be a lot easier

scenic sky
frozen igloo
# scenic sky I want to do my best to understand all of this. I'll be rereading it and trying ...

and that's exactly why I like this video so much https://www.youtube.com/watch?v=Na95i4ZD68I

Presented by Wayne Coles at SDC 2023 as part of the Code stream

Most games have some form of network functionality, and most game-engines come with a framework for serialising across the network.

Network teams will generally focus on friends, matchmaking and other online services.
This talk dives into network practices for games written with ...

▶ Play video
scenic sky
#

Definitely giving it a watch when i get home

surreal slate
#

Can anyone explain to me why the text is not displaying on both clients? I've reread my graph several time but can't seem to find what is causing the issue. It looks like the OnDeserialisation event is now being called at all which is confusing me as it was earlier before I changed the array from 3 components that were "Test1; Test2 and Test3" to 5 random placeholders

twin portal
#

is DisplayText set to be synced?

surreal slate
#

yes

craggy pivot
#

This may be a dumb question... but is there a way to test my networked game world by myself? I have it so when the game starts it divides the players up (based on their playerIds) and assigns their position/role, then teleports them. I did the build with 3 clients and since they're all my own character it only teleported one of me. Is there a way to mock other players with unique ids, or do I have to test it with other people?

twin portal
craggy pivot
#

hmmm I'll have to check it out. I'm using one of the example scripts for the playerjoinzone and it only showed one player in the list, I suppose I either broke it or it's not set up right

twin portal
#

IIRC, when I tried working with PlayerJoinZone for the last jam, it doesn't create a proper list of players for you to look through, it's an all-or-nothing deal

craggy pivot
#

ayy you nailed it. The DataList it keeps of players makes it think the other local players are already in the list when they aren't (since we are kind of the same character i guess). Changing this datalist to accept ints of playerIds instead made it work. Now I gotta gut this file lol

ivory gorge
#

I'm getting a networking error that I don't understand. I'm trying to sync an object using manual sync, and it works well most of the time, but every now and then it stops updating and starts spamming this message in the logs (just for the client thats not syncing). Anyone know what I'm doing wrong?
(the object that's syncing is a 'player object')

twin portal
#

Possibly requesting serialization too often and the behavior is getting limited

fallow mountain
#

what happens to a playerobject when the player leaves the instance?

twin portal
#

It gets removed

fallow mountain
#

can I attach a gameobject to a player's transform so it follows the player automatically, or do I need to update its world transform every frame?

twin portal
#

You have to update its position in Update to follow the player

fallow mountain
#

can I do this to another players playerobject? like a piece of clothing, or a tag above their head?

#

or do I need them to update, and then get synced?

#

I mean can I move it locally to follow the other player

#

even though it is "their" gameobject

twin portal
#

You can yes, if the movement is local
i.e. you don't put ObjectSync on it

#

If you want a quick and easy way to have it follow, just have the local player make their own PlayerObject follow them, then put objectsync on it
It won't follow perfectly (reliant on networking) but in some cases it's good enough

finite sierra
#

ObjectSync isn't required at all. you can have each object store Local Players VrcPlayerApi. and update the position of the object based on that.

#

and use the SendCustomEventDelayedFrames by 1 frame. to create a psuedo update loop that is controlled

twin portal
#

Yeah that's what I said

finite sierra
#

yea i just saw it lol i only read the latest message

fallow mountain
#

Wouldn't it still get updated every frame but one frame behind?

#

I mean what is the advantage of

#

Update ---> Delay 1 frame ---> Move the object above the players head

#

vs

#

Update ---> Move the object above the players head

#

?

twin portal
#

It's so that if you need to it's easier to increase the delay
You can do the same thing within Update but it takes a few more variables to track how long it's been

finite sierra
#

doing it in the Update Loop is also viable. but its common tactic in Udon to use the SendCustomEventDelayedFrames or SendCustumEvent instead of Update loop. to have more control and less overall necessory checks.

twin portal
#

I think it's uh, PostFixedUpdate it suggests to put stuff that follows the player? So it moves the object after the IK has resolved

sick gull
#

PostLateUpdate

#

Or at least that's what I'm using to make an object follow every player

twin portal
#

Ah I knew I felt it was wrong lol

#

FixedUpdate is a whole 'nother thing

sick gull
#

If you want to duplicate an object for every player, you will want to use the vrc player object component. Here's a video showing just how to do that!

So hopefully this is helpful. As always, if you have any questions, feel free to ask in the comments bellow! ^^

Come join the discord! https://discord.gg/jjdnCWVvKg
Wanna help support me in maki...

▶ Play video
#

also new updated tutorial dropped for exactly that

finite sierra
ivory gorge
finite sierra
craggy pivot
#

Is there a built-in way to trigger something at the exact same time for everybody? I need an object's animation to begin at the same time for everybody. The only way I can think of is to set a synced variable representing the future time it needs to fire off, then everybody's client will check in Update until we hit that time. Any other ideas? (also I suppose this depends on everybody's local clock being synced, and that might make it impossible)

twin portal
#

yes, SendCustomNetworkEvent

#

this runs a specified function for everyone currently in the instance; you'd just need to make a custom function/custom event that runs the animation and tell SendCustomNetworkEvent to execute it.

craggy pivot
#

That's the way I'm currently doing it. The issue is when I test the build with three clients, usually one or both of the others can experience extreme latency before their network event fires off locally, then they're all out of sync. I have another custom network event go off halfway through the animation to determine a state change, and this causes some painful interpolation on the slower clients

#

but maybe the bad clients are just more volatile than usual? I suppose if one is slower than the others but at a consistent rate it shouldnt do this

twin portal
#

so you have to ask how important is it exactly to have the timing down to the exact millisecond. Players are generally not going to be playing right next to each other where they can see each other's screens; the delay of network events happening is usually not any slower than everything else that's networked; player position, IK, voice, etc.
If the answer is yes then yes you'll have to perform timing based on the clients' local clocks. But even then you'll have to sync that time for everyone, and before that set time arrives.
Lots of worlds like music animations or something have to put some extra effort into correcting the timing, but something like a door opening or an explosion won't really matter much if it's a second or two behind

#

you could possibly change the setup to use continous sync, which would be faster but may skip intermediate values
you could have a float counting up that's continous, and when it goes over a certain threshold, trigger the next event

craggy pivot
#

You make some good points. I suppose I'll know better what to do after testing with actual players. In the meantime maybe I will break up the animation to wait until it receives a value from the owner to determine its next state instead of proceeding with one and getting it wrong

#

actually playing into what you've said, maybe i could start the owner a second or two before everybody else, then when they make the decision all the other clients will know for certain since they're slower...

twin portal
#

I know it's possible to get real wacky and like get everyone's latency and do delays with it, but I've never needed the timing to be accurate enough for that to be worth the effort

#

maybe could even do no networking at all... take advantage of the fact that all player positions are networked..... start your event when a player fires OnPlayerTriggerEnter, which will (theoretically) run for everyone without any networking

#

sometimes networking boils into a mad science.

craggy pivot
#

very interesting, I had never thought of that. Networking is definitely very hard to completely wrap my head around lol

finite sierra
#

no games have ever had it either. they are doing alot of predictions to make it seem like it does but in reality it never does happen at the same time

fallow mountain
#

What is the most accurate timing? Send network event by someone? Server time?

#

I guess it should be same logic with those synced video players?

ivory gorge
# craggy pivot Is there a built-in way to trigger something at the exact same time for everybod...

While everyone is saying that it doesn't really mater (and in most cases it really doesn't), there is a way of doing it (at least in u#)
The event 'on deserilisation' can have a 'result' value, and that can be used to get the network time of when it was last updated. Then if you delete networking time from it, you get how long ago it was. Then you can just start the animation x seconds ahead. This result value is partly how object sync predicts where the object should be, which helps make it more snappy.

I should mention that afaik this only works with synced variables, and not networked events. You can however just have a synced bool/ byte, that when changed, calls a custom event. Then you just need to change that variable, and everyone will play that event.
Also, use manual sync, as unlike continuous sync, it updates the value immediately instead of waiting for the next sync cycle (~4.5 times a second). Continuous sync also has an added ping, that was added to buffer out and smooth synced values for those on poor internet connections (aka quest wifi). I find this can add an extra 200ping (0.2sec) of delay, which can be brutal for some game worlds.
From my testing, networked events seem to have the same delay as continuous sync, rather than the snapper manual sync

fallow mountain
#

What exactly is "server time"? is it just a "coordination tick"?

#

Or a "coordination timeline"

#

When the owner fires an animation at a certain server time, wouldn't that server time also include his own ping time?

#

Because the owner needs to ask the server what the server time is, right?

#

Or does the owner uses his own copy of server time?

finite sierra
#

that can be used to bring it closer but someone who does receive it before you would always do it before you. even if you remove the networking time. as it wouldn't be possible for the local client to know when someone else receives it or not.

#

for instance if someone has a RTT of 95 ms and a second person has a RTT of 185 Ms. there would be a difference between them of roughly 90 ms. but since there isn't really a way to know this with exact timings its not really possible to fire of any logic at the exact same time. it will always be behind someone else by a small amount or ahead

silver hill
#

Alright were getting there, guns show the true model of what they should be albiet they kinda overlap each other, something Il have to figure out, still having the major issue of people people being able to fire other peoples guns though, hmmmmmmmm

#

So i have it set up so that when it detects you using input down it does a bunch of checks then fires off a non networked custom event

#

Itl then fire off a localally calculated bullet (Which will have collision and will hit the target to trigger hit collision events locally) and then also a networked non important fake bullet (For graphical FX but without having to calculate collisions networked)

#

Does a check to see if the weapon is supporessed or not...

#

Then finally it reaches the end of the line where it does neccesary ammo and magazine checks

#

Im not sure how people are firing other people's guns, really weird :L

#

I could put a check to see if the object is locally owned, but that seems like a patch job to me, would there be a more professional way to solve this ussie?

#

The red bullets that fire out are supposed to be the local bullets for hit detection with white bullets being the non important ones

#

Im assuming the firing of red bullets has something to do with other people firing other people's guns...

dusk shuttle
#

Is there a method that is called specifically when all synced variables have been received by a joining player? I thought OnDeserialization() would do that, but it's not working that way and the script is crashing specifically when a player joins when another leaves at the same time.

#

Nevermind I'm pretty sure OnDeserialization() does call after receiving all synced variables on joining, but I think if a player leaves at the same time it causes OnDeserialization() to not call exactly when I'm wanting it to which is causing issues

#

Time to find a workaround... Lol

finite sierra
#

OnDeserialization is called when someone rejoins correct

dusk shuttle
#

Yeah I've traced this issue back to my own code, pretty sure it's because I have the same array being modified when a player leaves and when a player joins so I just need to prevent them both from trying to run at the same time

nocturne depot
#

This is my code:

public override void ExecuteAction(string buttonText)
{
    Networking.SetOwner(Networking.LocalPlayer, gameObject);

    syncedText = buttonText;
    
    foreach (TextMeshProUGUI text in targetTexts) {
        text.text = buttonText;
    }
    
    RequestSerialization();
}

When someone triggers this function, it updates their variable locally. But if they are not the owner of gameObject, then it does not sync across all clients.

This matches what is writtting in the API

My question is, do I have to do this everytime? Is there some smart way of setting an "owner" from the start where a non-owner whom triggers the update event will still have the update reflected on all other clients?

Cause setting the owner first for every update seems a bit odd?

sick gull
#

Yeah you need to give them ownership of the object before modifying anything synced on it

#
private void SetIfNotOwner()
{
    if (!Networking.IsOwner(Networking.LocalPlayer, gameObject))
    {
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
    }
}
nocturne depot
#

I just set it no matter what. No point in checking for ownership.

It was just smart if there was a way to set the owner to "Network" itself. So no ones own the object but all clients that trigger functions on it will have their varaibles synced.

sick gull
#

yeah. IDK if that is doable with how VRChat works...

twin portal
# nocturne depot I just set it no matter what. No point in checking for ownership. It was just s...

You can sort of achieve what you want if you do it a little differently.
Every synced object has an Owner. nothing you can do about that, it's inherent to VRChat networking.

What you can do, is, instead of changing ownership, just send the request to the owner, have them process it, and send the result out to everyone.
You can do this with SendCustomNetworkEvent, and specify Owner as the target.
Owner runs a SetVars or something to update synced variables, then runs a seperate ApplySerialization function that then uses these variables for whatever is needed
Then if OnDeserialization also runs ApplySerialization, everything will be synced

nocturne depot
#

SendCustomNetworkEvent has a dely. Don't know how long it is.

But if it is sent to the owner, and they perform the ApplySerialization, it would still update for players whom join later in the instance... interesting.

twin portal
#

there will be a delay in any networking you do

nocturne depot
#

So it might not be so great, depending on how long the delay which is mentioned here is

twin portal
#

it's either that or you're transferring ownership and having them change things

sick gull
#

(VRChat is fried)

finite sierra
#

that's how networking in any games works. Ownership is what ensures you only update what is yours. ontop of that Owneship transfer has a delay to and you need to account for the change. and i have seen ownership change fail if to many of them happen.

#

it's much better to have each player own a object by default so you never have to do owneship change. but you can just do the SendCustomNetworkEvent to the owner. if only owners need to know about it.

nocturne depot
twin portal
finite sierra
twin portal
#

but if the "server" was a valid owner, then everyone would have a delay in networking things being set (would have to travel to a server and process it anyway)

#

it would be no different than an Owner

finite sierra
#

everytime u set ownership it needs to validate the changes and then inform you that it changed etc

finite sierra
nocturne depot
twin portal
#

this is why I was suggesting the solution that doesn't require ownership transfer 😭
the result would be the same

finite sierra
#

owneship transfer are fine if you do it very infrequently

nocturne depot
#

I understand. Right now I am just talking about what is most ideal for this. What would be cool if it was a thing.

finite sierra
#

how would that make it more ideal? you stil have to request changes, then verify those changes on the server and check if its allowed. plus more processing would be required by the server if that was the case.

#

which is also why they are not doing it.

nocturne depot
finite sierra
#

again more processing required in general so its not ideal no matter how you look at it.

#

and not to mention server authoritative creates alot of delay.

nocturne depot
#

How is it more processing?

To have a synced variable right now I first have to transfer ownership. Then request an update.

The server right now recieves a request to transfer. Then has to confirm with the owner if that transfership is valid. Then send back to me I am the owner. Then accept an update.

If the server was the owner it would just have to recieve updates, then send out the updated variable.

finite sierra
#

Sever would have to do all the serialization, and Deserializations etc ontop of that checking if the data is valid and have not.

#

right now that is done clientside. only

nocturne depot
#

The server no matter what has to handle all requests.

Person A and B are clients. B owns an object.

Current:
Person A has to request ownership. Person A might also send a variable change along with the request (at least that is how I think it works? API says it is instant change)
Ownership transfer is sent to the server. Server send ownership transfer request to person B.
Server receives answer from person B. Sends it to person A. Updates all clients with the new variable change

Proposed:
Server has ownership of an object.
Person A sends a variable change.
Server confirms it is the owner of the object.
Updates all clients with the new varaible change

No matter with the current or proposed change the server has to validate if the clients are telling the truth or not, right? A client cannot forcefully take ownership of an object. It has to be validated by the server.

Can someone else here perhaps someone from the VRChat team or someone with a lot of experience tell me if I am crazy or not?

finite sierra
#

the server has to Deserlization that data. and serialization it for that to work. has nothing to do with the requests or not.

#

it depends on how much the server needs to do

#

plus doing that just creates a massive amount of extra delay.

twin portal
#

yeah this is currently more checks than the current system does

#

it will just be slower

#

any gains in convenience wouldn't really be worth it

#

also I think ownership is only verified locally. If the client already knows they aren't the owner of something, they won't send out any requests to make changes

#

this is why you can immediately start doing owner stuff as soon as you request ownership; client assumes it's immediately the owner now

restive cliff
finite sierra
#

also changing owner has the thing that two people can be the owner for just a split second.

twin portal
#

which adds up to what you're saying about things breaking if you change ownership too quickly

nocturne depot
restive cliff
#

and the sync mode is set to Manual for the script too?

nocturne depot
restive cliff
#

ok I understand now

finite sierra
nocturne depot
finite sierra
#

thats just what i said.

#

the owner always get OnPostSerialization

nocturne depot
finite sierra
#

which is how it always will be 😄

strange token
#

@nocturne depot your squirrel drawing pfp is great

#

It’s like… exactly what good and cool emblems do these days

#

You should totally pin that on your avi if you haven’t already. Would make a really neat brooch or something

nocturne depot
#

Thanks. I made the logo myself. I haven't made any avatars for VRC yet, cause I haven't had the time. But whenever I do, I am considering putting the logo somewhere on the avatar.

main cape
#

Hello guys, i just started doing networking stuff and I'm practicing variables sync and custom networking events.
I know im not doing it the right way, can anyone tell me if this is what it should look like to sync variables and send network event?

#

Script part 1:

#

Part 2:

#

Part 3 These are the methods im calling from the ui inputs

#

This is the UI im testing with

sick gull
#

I would recommend setting your script to "Manual" behaviour.

Whenever a user changes something that's synced, you should

  • Give them ownership of the object
  • Modify the synced variable
  • RequestSerialization (Tells everyone something changed)
main cape
#

Okay i think i get the first two, how do i do the serialization?

sick gull
#

This video kinda explains it pretty well

main cape
#

Thanks, i'll take a look a it

sick gull
main cape
#

So if im right, a simple variable sync code should go like this:

// Local event.
private void UpdateLocalInteger()
{
    intOutput.text = intInput.text;
    Debug.LogFormat("SyncTest: {0} Updated local integer.", Networking.LocalPlayer.displayName);
}

// Network events.
public void ChangeOwnership()
{
    Networking.SetOwner(Networking.LocalPlayer, gameObject);
}

public void UpdateInteger()
{
    ChangeOwnership();
    RequestSerialization();
    SendCustomNetworkEvent(NetworkEventTarget.All, nameof(UpdateLocalInteger));
}
twin portal
#

very close

#

setting ownership doesn't necessarily need to be in its own function

#

and at the moment this will only run UpdateLocalInteger for the Owner, the person running UpdateInteger. You also need to call UpdateLocalInteger in OnDeserialization

#

as good practice though, I would move the Owner's UpdateLocalInteger to OnPreSerialization instead

#

or maybe to OnPostSerialization only if the serialization was successful

#

but will still work where it is currently.

#

you just require the OnDeserialization

main cape
#

Like this?

public override void OnDeserialization()
{
    UpdateLocalInteger();
    base.OnDeserialization();
}
twin portal
#

yep

#

oh and I didn't even notice in UpdateInteger you're running that with a NetworkEvent

#

just call the function directly

#

Network Events vs. sending serialization, the order they arrive isn't guaranteed, so the event to set the integer may arrive before the value has been updated yet

main cape
#

You mean something like this?

public void UpdateInteger()
{
    ChangeOwnership();
    RequestSerialization();
    UpdateLocalInteger();
}
twin portal
#

yep

#

that should do something

main cape
#

Sounds like UpdateLocalInteger(); is gonna run twice, but i gotta try

sick gull
#

I thought u serialize AFTER you update

twin portal
#

ah

#

yeah

#

I figured the value was already updated for some reason

#

Update Value -> Request Serialization -> Use/Apply Value

main cape
#

Okay, so at this point the code should look like this:

private void UpdateLocalInteger()
{
    i = int.Parse(intInput.text);
    intOutput.text = i.ToString();
    Debug.LogFormat("SyncTest: {0} Updated local integer.", Networking.LocalPlayer.displayName);
}

public void UpdateInteger()
{
    ChangeOwnership();
    UpdateLocalInteger();
    RequestSerialization();
}

public override void OnDeserialization()
{
    UpdateLocalInteger();
    base.OnDeserialization();
}
#

Im sorry all this networking stuff is confusing for some reason 🥴

twin portal
#

don't worry networking is a pretty steep wall to climb at first

#

but if you get into the strats VRChat is optimized for, networking is really easy

main cape
#

didnt work ;-;

cedar crescent
# main cape Okay, so at this point the code should look like this: ```c# private void Update...

Is i the synced variable? OnDeserialization happens when an update is received. Like when another player has modified i. So you should only be reading i, there.

[UdonSynced] private int i;

private void UpdateLocalInteger()
{
    intOutput.text = i.ToString();
    Debug.LogFormat("SyncTest: {0} Updated local integer.", Networking.LocalPlayer.displayName);
}

public void UpdateInteger()
{
    ChangeOwnership();
    i = int.Parse(intInput.text);
    UpdateLocalInteger();
    RequestSerialization();
}

public override void OnDeserialization()
{
    UpdateLocalInteger();
}
main cape
#

Oh, that worked

#

so the only part i was missing was updating the variable

mild hemlock
#

hey i'm in need of help not used to udon scripting, i go to play the scene and i receive these errors can i have help on why this is happening

twin portal
#

you have compilation errors in your scripts

#

if you scroll up it should say exactly what

twin portal
mild hemlock
#

yeah i figured it out after some messing around thank you

craggy pivot
#

Does anybody know why I'm getting an "Object reference not set to an instance of an object."?

It's happening on a line where I call Immobilize(false) on a player. right above it I do an IsValid check on the player, then I do a sanity check to see if the player is null (it's not, and I can get the displayName), but this error is still throwing. Any thoughts?

#

maybe only the local player can immobilize themselves? I didn't see this in the docs

#

Looks like that was it. Sent a network event and it works

twin portal
# craggy pivot maybe only the local player can immobilize themselves? I didn't see this in the ...

it doesn't technically say it specifically for the Immobilize node, but on the page for Player Forces, it states that all player-movement-related nodes can only be called by the local player
https://creators.vrchat.com/worlds/udon/players/player-forces

Here are the nodes relating to forces that act on Players. For nodes that deal with Player positions, see Player Positions

#

so a player can't set another player's walkspeed or jump height

craggy pivot
#

good to know. I can see why that could cause issues lol

finite sierra
surreal slate
#

Hello, I'm currently trying to make a simple truth or dare world to understand how networking in VRChat works. Currently, everything seems to work fine except one thing: Whenever a player that isn't the owner of the object presses either truth or dare, instead of rolling a new one, it displays the previous one that this player got, forcing them to press the button twice. If the player didn't have a previous prompt, then it simply displays nothing until the seond press.

What I'm getting from this is that whenever a player isn't the owner, it simply ignores the "Random Range" and just, display the previous one.

However this also confuses me as the variable should technically be synced (which it looks like it is, as the text does display the same to every player) but somehow it still uses the string that that user rolled, not the previous string that was rolled globally.

I think an example would help explain. If I join and press truth, it'll display "Truth 1". Then Player 2 presses truth as well and it displays nothing, they have to press it a second time to display "Truth 2". Then I press truth again, and it will again display "Truth 1", and I need to press it another time to display "Truth 3". Then player 2 presses it again, and it will always display "Truth 2", until they press another time etc...

This is a weird issue that I have no clue how to fix and would love to receive any help with it

twin portal
#

you have two events that are exactly the same?

surreal slate
#

no, one is for thruths and the other for dares

frozen igloo
surreal slate
#

got it 👍

tulip sphinx
#

ye and if you ever need to merge branches, do it via custom event, ie both braches calling the same event in the end.

nocturne depot
#

Right now I am using a DataDictonary to pair unique object names to their respective index. Because the order of which the components spawn is the exact same for all clients, I will always map the same name to the same index.

I then use a UdonSynced bool array to store the state of the objects.

If I had to use the DataDictonary I apparently had to convert it to a VRC JSON. And on top of that I'd be sending a string as the key too, which is even more data.

I can see the cleanness in just having to both operate and sync the same DataDictonary instead of doing this fuckery I am doing right now. So I wanted to ask if anyone has been in the same scenario I am right now. What did you do? Was the performance loss/gain worth just sending the VRC JSON?

hybrid kindle
#

not really sure why my script isnt executing. Any ideas why anyone?

tulip sphinx
#

why are yuo getting this behaviour (ie i assume, same udon) via function meant for remote ones?

hybrid kindle
#

getting the bool value of that behavior

tulip sphinx
#

just drag bool into canvas

#

from variables

hybrid kindle
#

i did that but its also not working

tulip sphinx
#

well how do you define if theyre banned

hybrid kindle
#

based on a whitelist feature, which then executes a script turning on a ban.

#

aka the bool

tulip sphinx
#

well r u sure it does execute that part. add Log to spit out bool state somewhere

#

also just a reminder that whitelists are allowed, any kind of permanent blacklist is not. but id judt assume youre have some area only for whitelisted.

safe path
twin portal
#

this is correct, you are not allowed to ban players from your world via a blacklist

sick gull
#

shame

safe path
#

Yeah I had that thought too

sick gull
#

nothing in the rules on making doors have a 1/100 chance of opening on interact for your blacklisted players 😏

twin portal
#

ahh I think that would still count lol

sick gull
#

Well I will find out when my world is unprivated 🫡

#

but IK FBT Heaven has a ban thing

#

and it limits access to the world

#

¯_(ツ)_/¯

twin portal
#

can report the world for it, if you can show it in action and how it violates TOS

sick gull
#

i aint no snitch gangie

twin portal
#

I'm sure there's plenty of worlds that implement such a feature that don't even know it's not allowed

sick gull
#

IK midnight bar got into some trouble w/ this area of TOS

#

they would tp you, turn ur avi and move u to a diff world

#

which breaks like SEVERAL of those rules

twin portal
#

oh yeah sure does lol

hybrid kindle
#

It's not a super ban like it breaks everything but it removes some features of the world. More white-list I just worded it wrong lol

safe path
twin portal
#

this is allowed, if you specify what behavior would get them punished beforehand
as long as you aren't detecting a specific player from a pre-defined blacklist to punish, so you can punish them for example if you detect them cheating

#

so you say, "flying isn't allowed in this world", detect them flying, teleport them elsewhere/disable jump/etc. and tell them "you were detected flying"

cerulean zealot
#

Send all the questies to "quest jail" and throw cartoon poopies at them. 😈

foggy jackal
#

Ooga Booga does something like that

#

it was briefly amusing, then the questie got angry

tulip sphinx
#

they already suffer enough

nocturne depot
#

In the VRChat API it says:

Udon scripts with manual sync are limited to roughly 64690 bytes per serialization

But later in the article it says:

Manual sync is limited to 280,496 bytes per serialization.

So... which one is it?

frozen igloo
hybrid kindle
#

would anyone be willing to look at this script someone made and adapt it to what I need? Its c# and I have no clue why its doing the things it is doing.

#

I just need this to send a local event.

twin portal
#

could certainly steer you in the right direction

hybrid kindle
# twin portal could certainly steer you in the right direction

its Mimyqualitys dragon system. When a person sits on the dragon it overrides any PlayerTriggerEnter scripts and forces you to use their ReactiveTriggertoDragon script. It already has an event sender thing in there yet it is global. I just want it to send a local event instead of global so i can have my underwater stuff 😭

twin portal
#

man they sure like compact if statements...

#

so wait you don't want to use this ReactiveTriggerDragon and use something else?

hybrid kindle
#

right now it toggles it for everyone and i just dont know where its telling them to do that

twin portal
#

ah ok....

#

so there's no networking calls in this script, as I can see

#

but remember that OnPlayerTriggerEnter is called for any player who activates the trigger, including other players that you, the local player, observe hitting the trigger

hybrid kindle
twin portal
#

the player trigger isn't in this one, so wherever you have that script, add if(!player.isLocal) return; as the first line in the function
this checks if player (which is the argument of OnPlayerTriggerEnter, cooresponds to the player who has touched the trigger) is not the local player, and quits the function (return;)

hybrid kindle
#

ive tried something like that already and it just wouldnt run the script at all unless there was only one person in the world.

twin portal
#

oooh....

#

hmm...

#

did you set _dragonOwnerOnly to true?

hybrid kindle
#

yes, which does make it so only the dragon driver has the effect, BUT now any passenger doesnt get it

twin portal
#

oh ok. passengers complicate things

#

and it's this "_ReactivateGameObject" that actually does the thing you're trying to do?

hybrid kindle
#

i could use gameobject, but i tried doing the script so i could attempt to make it local there. that isnt working

#

im thinking maybe if i can include the passengers into the owner toggle as well

twin portal
#

that would be pretty much 1 of 2 plans I've got

#

actually no plan 1 won't work

#

plan 2!

#

you'd need to devise a way to have the player mark themselves as a passenger of the dragon

#

then the _dragonOwnerOnly if statement? basically just change that to if(!isPassenger)
(the driver is a passenger too)

#

so if they aren't a passenger, don't do the effects

#

I guess these dragons weren't initially designed to have passengers

hybrid kindle
#

its just they didnt think to make things toggleable for passengers too

#

i have a DragonSeat script, a DragonDriver script, and a SeatInputManager

twin portal
#

so just an oversight

hybrid kindle
twin portal
#

well you shouldn't need the names of the passengers

#

oh it does

#

it stores the playerID in _mounteredPlayerId

#

oh and it kinda has a "passenger" flag, _isRide

#

turns true only if the local player is in the seat

hybrid kindle
#

😭 so what do i type

twin portal
#

I think if you hit your keyboard hard enough, the correct code will come out

hybrid kindle
#

RAHH

twin portal
#

so....

coarse narwhal
#

I heard there is a higher chance if you drop your keyboard face first on the ground at approx 2.4m

twin portal
#

when ReactiveTriggerToDragon fires OnTriggerEnter, we need to do a check if the local player is currently riding that dragon

#

currently the info we need. doesn't really seem to be in an easy place we want it, imo

#

we don't need the seat to know if there's a passenger.... we need to store on the dragon object if the local player is a passenger

#

at least I'm thinking that might be easiest

hybrid kindle
#

in the dragon descriptor?

twin portal
#

just sayin' it's probs not gonna be one line ez fix

#

lemme see

hybrid kindle
#

it might already be there, i really think we just need to implement it into the reacttrigger

twin portal
#

ReactiveTriggerToDragon looks for the DragonDriver script

#

and I don't see the seats storing what dragon they're assigned to

#

unless it's the other way around and DragonDriver does, can I see that one

hybrid kindle
#

so what if we tell reactivetrigger to look at dragon seat instead of dragon driver

twin portal
#

could do, but there's more than one seat on the dragon isn't there?

hybrid kindle
#

yeah

twin portal
#

sooo.... could use GetComponents<DragonSeat>, loop through them, if any of the _isRide is true, then the effects should be played

#

that might be the easiest way to do it without too much modification

hybrid kindle
#

ill take it

finite sierra
#

hmm. after several tests and normal runs of my Udon System. i have been notified that around 54-64 people in an instance it starts to either be heavily delayed and normal udon operations just outright is declined. i wonder if doing SendCustomEvents are subject to failing to?

frozen igloo
finite sierra
#

no nothing of sorts

#

everything is handled locally

#

and every player owns an object them self.

#

but the part that fails is the Teleport. even through that is a Local operation too.

#

and i am using this SendCustomEventDelayedSeconds(nameof(_Teleport), 3f); to delay the telport after clicking

frozen igloo
#

could be an fps problem along with code that is sensitive to fps problems?

finite sierra
#

hmm you know. that could be it.

#

all through

#

with 64 people with heavy avatars. i wonder if something gets skipped. as you load in.

#

would Udon Skip regular Void Start for some reasons?

frozen igloo
#

no, that shouldn't happen

finite sierra
#

this is the teleport button.

#

and i use this to get the local player object.

#

note it only runs once a player joins the world

frozen igloo
#

Have you investigated those conditions inside of ValidateTeleport? Perhaps one of them is mistakenly stopping the process?

finite sierra
#

hmm the only thing i can think off there is that the sync did not happen. because the teleport cannot happen before someone is synced.

#

so the RequestSerialization would have failed in that case.

frozen igloo
#

is that the one that is checking your role is not none?

finite sierra
#

yep

#

by default your Role is None

#

until something else has been set

frozen igloo
#

sounds like you need to add more logging and then see if you can reproduce the bug with logs that you can trace back to a source issue

#

logging all the places where the process might stop is a good place to start

finite sierra
#

the thing is i need to eh. get hold of those people then first 😄 since the instance ran yesterday

#

or yesterday night for me

frozen igloo
#

yeahh

finite sierra
#

something diff tells me that either the Sync did not happen. due to well being over the 11 kb/s limit.

#

which i can see being an issue with 64 people in a world.

frozen igloo
#

that limit is on outgoing data per player, not across the whole instance

finite sierra
#

even through i only have roughly 60 ish bytes max every so often.

#

i know

#

i noticed the outgoing data with 50 people sits around 9-10 kb/s when things are happening.

#

thats why i am saying that

#

on my end i was able to confirm that

#

and also do note that i do everything manually. i have no Continous

frozen igloo
#

Shrug not a lot to go on. Stuff like that doesn't get dropped randomly, though it can interrupt intermediate states which is why we recommend a state-based networking. If you're seeing things get dropped in a way that breaks your code, then my first suspicion is that it's not using state-based networking, and relies too heavily on intermediate states

finite sierra
#

hmm well everything should be State based atm. considering things are updated or happen when OnDeserialization runs. and it only runs one place.

#

@frozen igloo so unless im confusing my self with state based and intermediate states. i don't think that is the issue.

#

are you able to give an example of intermediate state and State based so i can tell you if its one or the other @frozen igloo ?

nocturne depot
#

The function GetUniqueName from Network. It is really awesome, but I just need to know. How is the Instance ID generated? Is it dependent on the Instance Master? So does the ID change if the Instance is transferred to someone else?

frozen igloo
# finite sierra are you able to give an example of intermediate state and State based so i can t...

Relying on intermediate state means that if the owner tries to change a synced variable, you expect and rely on receiving every single change to that variable. For example, if they start with an integer at 0, wait 1 second, change it to 1, wait 1 second, change it to 2, wait 1 second, change it to 3. Under normal conditions you'd expect to receive every single change and everyone can watch it go from 0 to 1 to 2 to 3. However, under heavy networking conditions you might miss the event that said it was 2, so you'd see it skip from 1 to 3.

This is because if it verified every intermediate state, it would be stuck backtracking on old details that no longer matter. It's best to focus on the present and not get bogged down. If your code relies on receiving every single intermediate state then it will likely break under load because there's a chance of not seeing 2. As a result, you need to ensure that your code is not going to get stuck when you see it skipping straight from 1 to 3, without ever seeing the intermediate state of 2. That is the key principle of state-based networking, and it's what VRChat's networking is built to support best.

finite sierra
#

@frozen igloo mine is diff state based. Owner only ever change a synced variable once they click a sync button. and its 4 different synced variables in total in the same place.

#

@frozen igloo 1 : Player joins worlds and a few things runs locally.
2 : Player is required to wait 60 seconds before UI unlocks again locally done.
3 : Player is then required to select a role and interests.
4 : Player then clicks a sync button that in turn causes a RequestSerialization locally
5 : The Data player sets locally gets synced to other players
6 : Other players call the OnDeserialization that then updates the object it happend on.
7 : Local player calls OnPostSerialization to set their own data

#

to give u an idea of the OnDeserialize that is what happens.

#

and it consists of 2 byte variables and 2 uint variables

frozen igloo
#

looks like a lot of abstraction, which is probably a good thing when writing at scale, I respect it. But it does make it a lot more difficult to review from screenshots, so I don't know how much I can help

finite sierra
#

yeea i know. i have abstracted a crap ton of things because thats just how i daily drive in c#, javascript etc.

nocturne depot
finite sierra
#

i am very fond of SOLID Principle. for instance.

finite sierra
nocturne depot
#

Wtf kinda data are you pushing which exceeds the data limit? Are you using the VRC Json thingy?

finite sierra
#

your avatar counts towards the limit, so does the amount of players in the world. each player adds some amount extra. and well some other things to

#

each player only serialize 28 bytes. per time they sync. and thats only done manually when they click sync.

nocturne depot
#

Oh, so if you don't even sync anything in udon. Then each avatar is still counting towards the limit? Or what?

finite sierra
#

otherwise there is a 11 byte SendCustomNetworkEvent that happens twice per person

#

yep

#

anything you have on you counts towards the limit

#

if you have full body, you are in vr. have face tracking counts.

#

when you talk it spikes the data out heavily

nocturne depot
#

You gotta be shitting me. I've totally missed that. Where is that written in the documentation?

finite sierra
#

nope i am not lol.

#

i have confirmed atleast that the data out goes up heavily. with those things

#

hence why i have always been confused my self with it

#

because how in the hell would 28 bytes + 22 bytes that happens maybe once every 30 second. per player ever hit the celling

nocturne depot
#

Alright, sounds like it is something to be pull requested into the docs then, if it is in fact true. It would be very relevant.

finite sierra
#

atleast i think its true. i tested this with just me and a friend in a world.

#

and we both looked at our out data constantly. while we either talked or not

#

and on my end with face tracking my data out was roughly 1 kb/s or so higher.

frozen igloo
#

your outbound goes up if you have more stuff you're sending, but it really shouldn't have anything to do with the number of people in the instance unless you've got some code that is getting in some feedback loop or repeating the same thing once per remote player, which is likely not what you want

finite sierra
#

yea no no thats not what i mean phase.

frozen igloo
#

are you sure your sendcustomnetworkevent isn't like running on all remote playerobjects or something?

finite sierra
#

yep

#

here u can see it

#

Catch runs from the one who interacts with your object.

#

so Person A catches you. it tells Person B hey you got caught.

frozen igloo
#

but then it sends a network event back to run catch, so all non-owners would run it. Isn't that a feedback loop?

finite sierra
#

it sends it back to everyone else after the immobile time is up

#

because of the checks im doing it wont send another.

#

and its because of this isImmobile its only set on the one who is caught

#

sorry i mean isLocalOwnerCaptured

#

the other one is set true on both ends but isLocalOwnerCaptured only the one that is caught

frozen igloo
#

eh, you're probably right but still, that is just one more place where I'd add debug logs to ensure that it's not causing a feedback loop, not just assuming because the code paths should block it.

finite sierra
#

oh i know its not 😄

#

the reason being is u see the log when u do that Rpc call

#

sec

nocturne depot
#

Also real quick to clear up something: Manual sync can send out 280,496 per serialization ~ 280 KB

finite sierra
#

yep.

#

but u can only do 11 kb/s

nocturne depot
#

Right so roughly 25 seconds for each update?

frozen igloo
finite sierra
#

first one is the one that catches, the second one is from the other player who got caught.

#

happens once

#

so yea i really don't know why else the data would hover around 9-10 kb/s with 54 people otherwise.

frozen igloo
#

It's also worth pointing out that the 11 kb/s figure isn't precise. It's a rough observation of the bandwidth limiting system, which has a variety of factors. In general though it's just a thing that measures your output and slows you down if you're going too fast. It's not a flat number because it's designed to allow brief bursts above the limits. It's also not easy to pin a specific number on it because there's a whole pipeline your data goes through in order to prep for sending, and by the end of that the number it uses to penalize isn't always 100% representative of the data you put in. Various overheads, packet sizes, differences in serialization, penalties, recovery rates, as well as real-world network conditions contribute to these numbers being very fuzzy

finite sierra
#

yea.

nocturne depot
finite sierra
#

@frozen igloo also i was notified that this only happens when its under heavy load. aka 64 players. doing things and from what i was told 3-4 people had issues with it not working and they had to rejoin a couple of times to make it work again.

#

also if you do go over the limit how is it udon warns you? @frozen igloo

frozen igloo
#

networking.IsClogged will be true when there is data waiting to be sent out and is stuck in the queue

#

You can use that to slow down your outbound data while clogged, which should help if that's what your issue is

finite sierra
#

what i mean is does not output some warning if u dont check using that @frozen igloo ?

frozen igloo
#

if it did, it would be going off all the time

finite sierra
#

hmm.

frozen igloo
#

it's a bool you can check whenever you'd like. If you want to hook it up to a warning you can

finite sierra
#

hmm. i just find it abit odd that the problems do not happen til x amount of players.

frozen igloo
#

yeah that's not how it should manifest, which is why I'm suspicious of some feedback loop in your code

finite sierra
#

hmm. i can try and do further loggin on it to see.

nocturne depot
#

So if I understand correctly, and just humor me here.
The rate limit is per-client.
So if I call RequestSerialization with some data to sync. Then whatever data I am already sending like voice data, tracking, ect gets sent along with now the data variable to sync. And all that counts towards what I (my client) can output.

Which is why increasing the player count should have no effect. As the limit is not dependent on how much data the server has to sent out. Only what each client is outputting to the server.

finite sierra
#

also to understand it correct if limit is reached can Udon outright decline the Request to Serialize or how is it that is handled @frozen igloo

frozen igloo
#

If you're clogged/suffering/over the limits, then when you try to requestserialization it may delay the eventual serialization and/or overwrite the previous serialization that was in-progress, but it will never completely cancel.

#

What I mean by overwrite is that if you set a byte array to 200K length and then requestserialization, it'll take a while to send out. But if you swap that byte array to just 1k length and requestserialization before the 200k has finished, then it will cancel the big one and skip straight to the small one. Remote users will never see the big one because if you're following state based paradigms, what you're saying is that it's no longer necessary and can be safely thrown away to save bandwidth.

finite sierra
#

hmm okay. so it might be a good thing to always wait til the current Serialize has finished before it can even request a new one? @frozen igloo

frozen igloo
#

well, if you cared about intermediate state then yes that would be a good idea. But also it's not easy to know exactly when your data has been received by the other people. The whole point of state-based networking is to avoid that complication, you shouldn't need to worry about that

finite sierra
#

okay.

nocturne depot
#

I might have missed this in the documentation, but I am confused when/if variables sync.

If a variable has sync on, does it only output data if the variable is changed? Or does it always output the variable no matter what? Manual sync, if that matters.

frozen igloo
#

not sure what you mean by output data

#

variables are data, they always exist and are accessible in any context within udon. Networking just sets/gets those variables to make sure everybody is operating off the same set of data

nocturne depot
#

Right. Let me clarify the question.
If I have a synced variable, for example a bool called "var". var started off with the value false, but is then set to true. I request serialization. var gets outputted and synced.

If I then request serialization again, this time var is still set to true. Does the client still output the data to the server?

frozen igloo
#

yes, when it sends a serialization that includes the complete snapshot of all synced variables on that object

finite sierra
#

@frozen igloo hmm. isn't it normally bad if the Rate is at 0Hz?

frozen igloo
#

the hz is just an approximation based on how often it serializes. When it comes to things that only serialize every now and then with no pattern, that approximation can be wildly inaccurate

finite sierra
#

ahh oki

cerulean zealot
#

@frozen igloo isNetworkedBusy only works for outgoing info?

twin portal
#

did you mean IsNetworkSettled?

frozen igloo
#

I wouldn't use IsNetworkSettled

twin portal
#

that one in my testing was always true even if I tried to max out the network. But Ren the other day was having issues with it spamming the error "network isn't settled!", so I assumed he'd needed to start using it to check for it. What's your advice against using it? Is meant more to be used to find a problem elsewhere and fix it, rather than use it to check for something and do logic different if the network isn't settled?

cold laurel
frozen igloo
scenic sky
#

im trying to make a cube get attached to a player when they join using Player Object, but all the cubes get attached to the same player, im very new to this so im not sure what im doing wrong could anyone take a look?

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

public class FollowPlayer : UdonSharpBehaviour
{
    VRCPlayerApi player;
    public GameObject hitbox;
 
    void Start()
    {
        hitbox = gameObject;
        player = Networking.LocalPlayer;
        Networking.SetOwner(player, hitbox);
        VRCPlayerApi owner = Networking.GetOwner(gameObject);
        string ownerName = owner.displayName;
        Debug.Log("Owner = " + ownerName);
    }

    
    private void LateUpdate()
    {
        TrackPlayer();
    }

    public void TrackPlayer()
    {
        VRCPlayerApi.TrackingData headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

        hitbox.transform.position = headData.position;
        hitbox.transform.rotation = headData.rotation;
    }
}
sick gull
#

Start should check for if the person is a local player or not

#

What is happening is
A player joins -> Object is created -> Start script is ran (even if the object isn't associated with the current player) so then it attaches to them

#
public override void OnPlayerRestored(VRCPlayerApi player)
{
    if (!player.IsOwner(gameObject)) return;
    _targetPlayer = player;
    _loaded = true;  
}
#

I would suggest changing your start script to an OnPlayerRestored.

This is ran for every player that comes in, we gain access to exactly who joined.
So we can just run the starting stuff once for the player the object is associated with

#

And your late update should be a 'PostLateUpdate'

#
    public override void  PostLateUpdate()
    {
        if (!_loaded) return;
        Vector3 position = _targetPlayer.GetPosition();
        Quaternion rotation = _targetPlayer.GetRotation();
        transform.SetPositionAndRotation(position, rotation);
    }

example of my post late update for playerobject footsteps

scenic sky
#

before i read this i changed it to this and it (Seems?) to be working

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

public class FollowPlayer : UdonSharpBehaviour
{
    VRCPlayerApi player;
    public GameObject hitbox;
 
    void Start()
    {
        hitbox = gameObject;
    }

    public void OnEnable()
    {
        player = Networking.GetOwner(gameObject);
        VRCPlayerApi owner = Networking.GetOwner(gameObject);
        string ownerName = owner.displayName;
        Debug.Log("Owner = " + ownerName);
    }

    private void LateUpdate()
    {
        TrackPlayer();
    }

    public void TrackPlayer()
    {
        VRCPlayerApi.TrackingData headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

        hitbox.transform.position = headData.position;
        hitbox.transform.rotation = headData.rotation;
    }

    public override void OnOwnershipTransferred(VRCPlayerApi newOwner)
    {
        player = newOwner;
    }
}
#

not sure if that is better or worse than what you did xd

sick gull
#

That should work fine. I don't think you need to have the 'OnOwnershipTransferred'

scenic sky
#

yeah, i have it because that tutorial you sent

#

now, should i just slap a VRC Object Sync on there to sync it for other players?

sick gull
#

I don

#

don't think so

#

atleast mine doesn't...

scenic sky
#

really? you dont need to?

sick gull
#

No, I think I don't need it since I use "PostLateUpdate" over "LateUpdate"

twin portal
#

you've already set it to follow the owner, so no you don't need ObjectSync
ObjectSync will be slightly delayed anyway so it won't quite exactly follow the player

scenic sky
#

huh...

#

could you explain to me why that is?