#udon-networking

1 messages · Page 22 of 1

north thistle
#

that's why the advised practice is to add _ in front of every public method that doesn't need to be called over the network

#

prefix the name of the method, that is

heavy spindle
#

VRCPickup.Drop is network callable. There is a parameter to pass a VRCPlayerApi as the instigator and I believe this is for ownership transfer requests if you have custom logic. Though even in my public project, I just have a method anyone can call over the network to tell the owner to drop it themselves

north thistle
#

well more specifically I'm talking about like OnPickup()

#

I want to know if OnPickup() can be maliciously called over the network

heavy spindle
#

Ah. I don't believe so since that's an VRC internal override method

#

probably why OnPickup is only run for the local player that picked it up and to get that pickup networked, you'd need to send a custom network event to all

#

If you wanted to be extra careful, you can do an ownership check against the local player

#

While clients have been able to call methods, they haven't been able to modify the body of the methods afaik

north thistle
#

what sort of networking does it do anyways? I'd like to use it as a non-networked object where only one exists in the scene and every player has a local use for it

strange token
#

In my experience OnPickup and OnDrop do not network

#

I’ve always had to manually add a synced bool for others to receive a pickup event

#

Unless that’s not what you meant!

north thistle
#

Ahh, I have a good way of expressing it: would SendCustomNetworkEvent(NetworkEventTarget.All,"OnPickup") work?

#

But from what you're saying, it does not

heavy spindle
minor gale
#

pickups will automatically try to owner transfer when picked up, that's like the main issue i can think of in a networking context; you'd just use synced mode none if you wanted local pickups (or they could be manual/continuous if you didn't have object sync or something relying on ownership on the object, that'd effectively be local too)

cold laurel
elfin pike
#

I'm having a problem with a world I have where I need a synced animation that plays once every time a button is pressed. I was trying to toggle the animation parameter on and off but something's not working and there's no way to indicate what it is

#

Maybe this is better for the general channel but just tag me and I will respond

twin portal
#

your "SendCustomEventDelayedSeconds" node is missing the event that it was calling previously

elfin pike
#

Weird that was put in there just earlier

#

I'll try it again I'm pretty sure it's still not going to do much

twin portal
#

you also aren't using a networked event

#

so none of this will sync

elfin pike
#

Nevermind actually, I think it works. How do I make it sync for everyone?

twin portal
#

instead of SendCustomEventDelayedSeconds, you can use SendCustomNetworkEvent instead

elfin pike
#

Oh yeah that might make sense

#

I was doing that because I was trying to delay the time between the boolean switching but that might be better

minor gale
#

is this meant to play the animation and then reverse the state? like i'm not sure i understand the delayed event unsetting the bool again

#

unless you're using the true bool as the condition for the animator between two states

elfin pike
#

If I only set it once, it will not change back when the button is pressed again

twin portal
#

I think you can just play the state directly rather than flip a bool to make that work a bit easier, not sure

elfin pike
#

Yeah I tried doing that but it wasn't synced. So sending the network event and playing the state off it might work?

minor gale
#

you should try to structure it with exact states like this if you can, using true each time isn't as safe

twin portal
#

oh right, it won't be synced because you're only setting the bool true for the person that pressed it, and not everyone else

#

so sender sets it true -> false, but everyone else just sets it false

minor gale
#

and if the intent is to get an animator that stays in some position and syncs to everyone you should prefer using synced variables over networked events, mostly for the sake of late joiners

elfin pike
#

Let me try triggering the animation with the network event and see if it does anything first

#

It works, but should this sync for everyone?

minor gale
#

this is probably the clean/vrc style way to do it, assuming you have two distinct states and can go between them with true and false in the animator

#

the sync mode should be set to manual if this style is used

elfin pike
#

Ok I'll try that if this method ends up not functioning

fallow mountain
minor gale
#

not sure what you mean

finite folio
#

Hello, who knows how to change the color of the fog through the UI? That you can switch from the standard to a different color and then everything is the other way around.

fallow mountain
twin portal
#

Looks like this time it's fine, I think the issue happens when you split the flow, and then combine the flow back together
So it's generally recommended never to combine flows to prevent the issue in the first place

silver hill
#

@fallow mountainIt seems to be alot better now but I was having issues where the monsters worked fine on the hosts side, but on a joined users screen the attack animations and even walking animations wernt being networked, its still a bit janky now, made a little preview of how well it plays hosts side vs a joined players side

#

FPS for the host goes down from 110 to about 70 in the lobby when a player joins and goes down to about 60 in game

fallow mountain
#

are the attacks and walking done with send networked custom event?

#

going from 110 to 70 when someone joins is likely related to playerobjects

silver hill
silver hill
fallow mountain
#

u might want to check the network throughput and usage etc... in debug menu 4 ingame

#

maybe clogged

silver hill
#

Well before it wasnt working AT ALL! But in this it was working perfectly

#

I guess the only thing I can note is the positioning of the Giant hand boss being a bit delayed from the fast movement special attack

#

It was one extreme or the other

#

Oh and this only worked in continuous sync mode, manual it didnt do anything either

#

I dont really know the difference other than manual needs joiners to serialize?

#

I still need to understand the differences in these scenarios

fallow mountain
#

you might want to make it manual, and only send a starting pos and ending pos... (optionally starting server time) so everything can be caluclated remotely...... and minimize network usage
both continuous and manual will work for late joiners, the difference is continunous is interpolated (i.e. not precise)

silver hill
#

Starting position and ending position of the nav mesh agent? I wouldnt even know how to do that

#

I did have the foresight of designing the health system of the enemies to not care about where their physical body is in the game or if they are synced, so it should still provide a fun experience for all players

#

The attack triggers are locally triggered to trigger a networked event so even if an enemy is delayed but hit someone on their local client, should still attack

fallow mountain
#

dev menu 7 should tell you what is using the most network

#

and maybe it is related to your fps drop

silver hill
#

Il give that a try next time I get on

#

What were the controls for that, shift plus F...... something

#

Been a whilse since I last used debug

fallow mountain
#

Rshift + ` + 7

#

not F7

#

number 7 on top of the abcs

silver hill
#

Got it

twin portal
# silver hill I dont really know the difference other than manual needs joiners to serialize?

Continuous: Any synced variables that you have will be "continuously" synced, meaning whatever value the Owner has, the value will be synced with all players without you needing to do anything else. It'll share the value every... second or so? But you can set this value to automatically interpolate, so if a moving object is being synced, you'll see it move smoothly. mostly.
Manual: Any synced variables will only be synced if the Owner calls RequestSerialization. You'd then use OnDeserialization on the receiving clients to "set" whatever those synced variables are for.

Makes sense that the script stops working if you switch it to Manual, as it requires a bit of setup to make it work

#

but weirdly, in my latest experiments, Manual can actually sync a bit faster compared to Continuous

fallow mountain
#

The other day I tested manual sync, looks to be capped around 8.5 kB/s (docs says 11 kB/s so not too far off). (measured by observing the new network stats Stats.BytesOutAverage and looking at dev menu 6)

  • If you manual sync less than 8.5 kB/s, you can sync (and be received) multiple times a second in real time without issue, but still it jitters quite a bit (+- > 50 ms with a 10/9 hz frequency) (in dev menu, the delay seems to be always 0.05 seconds).
  • If you manual sync close to 8.5 kB/s or just above, your network will start showing suffering slowly building up to 100, but still able to serialize multiple times a second in real time (measured with OnPostSerialization), but on the receiving end it will deserialize in one-second bursts, exactly every second, so it no longer is "real time". (maybe this is "hitching" in action but hitchesPerNetworkTick reads zero... idk)
  • If you manual sync something much larger than 9 kB/s, it is throttled and it can take many many seconds or tens of seconds to arrive/deserialize.
  • Curiously the new network stats "throughput" shows that it throttles to around "0.5", but not sure if this means 0.5% or 50%.
  • Screenshot:
#

I have not tested continuous, so idk if it is receiving in one second bursts or otherwise, but the "network tick" does seem to be exactly one second

#

I can share the testing script if you want

#

but you need the beta SDK

#

for network stats

fallow mountain
#

looks like internally to VRChat the maximum frequency is 20 hz? to be confirmed

finite sierra
#

and also looking at the Bytes in on the Receiving side. it says 17325 bytes aka 17.3 kb/s which is why the suffering is as high as it is. ideally you dont want that to be so high

#

which indicates you are outputting Way more then the 8.5 kb/s

fallow mountain
#

I guess the 16k was probably before the network started queueing up so the first burst was 16 kB,
which seems about right because I am sending two dummy string variables, each 400 characters, each char is 2 byte
at delay of 0.1 seconds ( which is less than 10 hz because delayed events are delayed more than the waiting time because of Update timing)
2 x 400 x 2 x 10 = about 16000 = ~16k
But in dev menu 6, the out is 8.5 kB/s

Curiously, if I use dummy size 300, which should be ~12k, my out is actually at ~6.8 kB/s
Also, the max seems to be MUCH smaller (almost half??)
(screenshot of sender)

finite sierra
#

wait are you using the CustomSendNetwork event? or the Deserialize method?

fallow mountain
#

manual sync, RequestSerialization
in a custom event loop 0.1 seconds

finite sierra
#

hmm.

#

@fallow mountain you are right. at 8.5 kb/s out it suffers. that is not a good thing.

#

just tried my self and it indeed suffers at 8.5

fallow mountain
#

this is even lower than the doc's "11 kB/s"

finite sierra
#

question beta or release ? @fallow mountain

fallow mountain
#

beta sdk

finite sierra
#

seems to be that with the beta we indeed are getting a lower amount of data .

fallow mountain
finite sierra
#

cause in release its 11 kb/s

fallow mountain
#

interesting

finite sierra
#

i tested it my self with a uint[] and yea. it diff did struggle.

#

with a 1 request per second

#

now the problem is that people with face tracking and full body will struggle even further....

fallow mountain
#

Curiously, the 8.5 kB/s corresponds to Stats.ThroughputPercentage showing about (or just below) 0.5
I don't know if 0.5 means 50%, or 0.5%

#

And in Udon Stats.ThroughputPercentage seems to be the only thing we can reliably track the throughput, in Udon (without opening dev menu 6)

#

The bytes out average is running average (not real time) and I guess the max is also just historical max (not real time)

#

So maybe if we stop sending stuff when Stats.ThroughputPercentage is above say 0.4 or something, we can ensure network don't suffer (at the cost of dropping packets)

twin portal
#

beta docs say 8-10KB is to be expected

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

finite sierra
finite sierra
fallow mountain
twin portal
fallow mountain
finite sierra
#

but considering the Suffering can reach over 100 it could be something different.

fallow mountain
#

At lower usage, the Stats.ThroughputPercentage actually drops to 0.4x or 0.3x close to 0.4 (at about 6.8 kB/s) (forgot exact number)

#

So it should be a "used percentage"

#

8.5 x 2 = 17... close to the "hard cap of 18 KB/s"... could it be the other 50% is reserved for networked events with parameters?

#

if 0.5 actually means 50%

#

maybe i should ask in beta discussions

finite sierra
#

hmm.

minor gale
#

this isn't new to the beta, the doc has said 11kb/s, in practice that's been more like 8 - 9kb/s

you should probably measure the incoming rate in addition to outgoing if you want an accurate representation of hz for something you're doing

you might want to look into a decrement style send timer if you want to achieve a specific rate, not sendcustomeventdelayed that effectively zeroes out the remainder

fallow mountain
#

oh yeah i measured the incoming rate, it seems even if the sender is sending at the correct hz, if sender is suffering, the receiver will get the packets in one second bursts (no longer real time)
and yes, i should adjust the timing for accuracy

#

if sender is not suffering, the receiving will receive ok at the real time Hz

silver hill
#

Do variables on a continuous sync Udon have to have the "Synced" tick enabled?

#

or will they sync regardless of setting

twin portal
#

yes, they need to be set synced

silver hill
#

Ok thats good

#

So the only things that should sync is the output of network custom events

#

I want all the AI logic to be calculated by the host

minor gale
#

if it's just networked events you can just use manual instead

silver hill
#

I tried manual but then it stopped sending the networked events

twin portal
#

as I was saying earlier, it takes a bit more setup to make manual work

#

if your script is setup to work for continous, it's not going to work at all if all you do is flip it to manual

minor gale
#

if it's on an object that has multiple synced scripts, they can't be different types, so i'd assume you're using vrc object sync on the object as well or something, which uses continuous

silver hill
#

At first the AI enemies were all one object under a continuous, that worked perfectly but the host was getting hammered in framerate so i tried a manual sync, no good, because the objects need object sync, so I make them all a child of a parent which handles the nav mesh agent which is object sync and then the child under manual would handle everything, again worked, but only for the host, every joined player saw the enemies in idle animation while moving around, so now Ive switched them to continuous under parented object and they seem to work for now

#

The framerate is acceptable, at least under 1 joined player

#

I hope the load doesnt scale with more players :3

minor gale
#

are you checking for nearby players every frame or something heavy on the host? it being continuous or manual isn't going to change performance that much unless you do a bunch of logic on receives or try to send large arrays you create every frame or something

silver hill
#

The enemies have a sight system which every 0.2 seconds increases the volume of a search sphere trigger collider, once it touches a player it thrinks back down to 0 then begins to reexpand again, the location of the found player is sent as a vector 3 to the AI's nav mesh agent

#

I do this to provide a (hopefully) non taxing way to find the closest gameobject with name

#

I know theres more accurate ways using the nav mesh agent to do crazy stuff and I found tutorials but that was a bit much for me, I also cant imagine it being ran well if theres like 30 monsters in the arena at once

#

Ive also had bad luck using rays so I didnt even bother trying lol

#

But anyways instead of per frame a monster just expands its search sphere outwards till it finds someone then proceeds to advance on that position

#

The only downside of this system is that my arenas would have to be relatively horizontally designed

minor gale
#

do you continue to send if someone remains in the 0.2?

#

oh sorry that's the interval you increase it, not the radius, but i think the question is still relevant

silver hill
#

Once the sight system collides with a player it immediately shrinks back down to a size of 0 then begins to expand outwards again, every 0.2 seconds it increases the sphere size by like... 20 i think, cant remember but it does the sizing in chunks instead of linearly expanding in size

#

If a player is really close to the monster, it will update the players position every 0.2 seconds, if its far away, it will take a few seconds for the monster to get a vector 3 on the player

twin portal
#

You could use that profiler thing to possibly see what scripts are taking up the most resources to run

north thistle
#

having my internet ko'ed by lighting, it's occurred to me there is a really great way to test how your world performs under unideal networking conditions: do your world testing while connected to a phone hotspot

foggy jackal
#

Oh yeah - there are some tools to simulate slow networks I've used for professional work stuff, absolutely a good idea

twin portal
#

gonna dust off my dial-up modem

foggy jackal
#

huh I wonder if I still have a modem

north thistle
#

@silver hill the LoS checker that I'm using that seems pretty performant

Takes the range to check, FoV to check, transform of the monster's eye, and a list of players current alive in the round

looping through the list of players it first checks if the distance between the eye and the player are within the range; then it checks if it can linecast to the player; then it checks if the player is within the FoV; if all true it adds that player to a list of "seen" players

then that list gets sent to the monster

#

limit the amount of colliders/triggers you're using; they can be expensive

#

and I suspect resizing colliders is expensive as it likely involves making a brand new collider

silver hill
#

Interesting...

#

I dont really wanna make this a stealth game using Line of sight though

#

I recorded this, Im not too sure what to make of this information, can anyone provide some insight?

#

Me and a friend just watched the monsters in the test arena then killed all the monsters and just waited around to see how the game performed

#

Lag slowly got worse and worse even after all the monsters were killed and returned to their object pools

fallow mountain
silver hill
#

I dont know what to make of that

#

KBs sound small

fallow mountain
#

very simply, you are sending more than ~8.5 KB/s, so the queue builds up continuously until it gets worse and worse

silver hill
#

queue?

fallow mountain
#

yea like unsent data

silver hill
#

So theres like a hard limit per second that VRChat can handle?

fallow mountain
#

yes, around 8.5 KB/s

#

to be safe you should aim lower

silver hill
#

Righto, so Im guessing the list states the objects that are the biggest culprits?

fallow mountain
#

i guess

silver hill
#

So all these objects sending 12b... some of them are off, why would they be sending data? :L

fallow mountain
#

they are not currently sending, it may be historic data

silver hill
#

I see, that makes sense

twin portal
#

that "Size" is how much that script would send if and when it is serialized

silver hill
#

I guess maybe scripts that dont need consonst serializing could be turned to manual

#

But then im not sure how the manual mode will affect network custom events...

twin portal
#

is this debug menu 6 or 7?

silver hill
#

7 didnt do anything when I pressed it

#

this is 6

twin portal
#

they show the same info, but 7 sorts it so the objects with the highest impact are at the top

#

that's odd. should be able to use both

fallow mountain
#

(7 didnt work for me either)

silver hill
#

Maybe VRChat updated so that 6 is just the default and only option?

twin portal
#

would be odd to remove such a thing bc that sounds useful to have

#

the network clogging and lagging should kinda be two different issues though

#

networking alone shouldn't be causing performance drops

silver hill
#

Yeah, the drops only seem to come when someone joins

#

It doesnt seem to stack with more people joining, at least from what I can see

#

I had 2 joiners wait around while I did some testing in a game

brisk magnet
#

ive run into a very strange issue and just want to see if anyone notices somthing silly I may have missed.

I have a old function PlayBtnClick() there is nothing wrong with this function and works exactly as needed.

I have a new function I am migrating too called playBtn()

in this new function it is casuing an out of bounds issue with an array on the object owners side, only if a non owner runs the function. testing as revealed that both functions provide identical arguments to the server. so there must be some other reason for the crash not directly related to the code itself.

attached images are of the code of both functions and the crash location the location of the out of bounds crash is line 1105 in the 3rd image

fallow mountain
north thistle
fallow mountain
brisk magnet
#

both functions end up running through that code and both provide the same arguments so im trying to figure out why one is causing the array size to end up differant in some way

fallow mountain
#

what does it say, which array

north thistle
#

also for debug menu 4, the "suffering" there seems to represent the amount of network syncs that haven't gotten sent out and are stuck in the queue; you ideally want this at a solid zero; if it's hovering around like ~100 or below, it's unideal; if it's growing then there are likely some network syncs that will never ever get out

brisk magnet
brisk magnet
silver hill
#

the enemies perform there networked attacks on time

north thistle
#

Can you define the "lag" you are encountering? Is it network or fps lag?

silver hill
#

FPS

#

but only the host gets lag, joined players remain smooth

north thistle
#

you're probably running host-only logic that is tanking the host's fps

that is completly seperate from network performance

silver hill
#

Ye

north thistle
#

network performance should have zero impact on player fps in VRChat

silver hill
#

I made a gameobject destroyer script that lets me single out stuff thats lagging

#

the player hitbox was a big hitter but cant seem to find anything wrong with the logic

north thistle
#

are you manually giving players a hitbox that you move onto their location every frame?

silver hill
#

I was but now its every 0.1 seconds

north thistle
silver hill
#

I also iumplemented changes suggested by Tekton, that helped a bit

#

The hitbox also acts as a visual representation for the host to target their AI enemies with

#

it does a few things

#

revive mechanics

#

Incase you wanna have a look

north thistle
#

I take it that's a VRC Player Object?

silver hill
#

Yep

north thistle
#

moving it onto the owning player's current position should be relatively cheap and should cost equally as much for everyone in the instance

fallow mountain
north thistle
#

my main advise from the little I've seen is to try making the monster chase based off a distance check to living players in round instead of a collider you're changing the size of

brisk magnet
#

looks like its a perfectly valid array index so wounder why it thinks its out of bounds

#

I think maybe the function might be getting double called somehow

fallow mountain
#

1105,62 you sure it is h.cards?

#

just asking, i dont know

north thistle
#

yah, what is at that line?

brisk magnet
#

that "i" is right on col 62

#

its 1107 now that we added logs moving it down though

north thistle
#

which i?

brisk magnet
#

h.cards[i]

#

the i in that line is on col 62

#

after checking closer it does apear to be double calling

minor gale
brisk magnet
#

it played card 46, sucsessfuly prosssesed it and imeditaly tried to play card 46 again onto the same spot it allready exists

north thistle
brisk magnet
#

So now the question is why does the new function end up double firing?

north thistle
#

or is some of their code looping over the queue?

minor gale
#

if it's a list it could be pretty expensive to pull things from since it'd shift everything i think? if it's a queue i don't know what they're doing

#

i don't think it's memory either way

north thistle
#

at the very least it doesn't seem like a single queue as some things can get stuck forever while other behaviors are allowed to go straight through (but that could be explained by each individual behavior or group of behaviors getting its own queue)

prisma lance
#

so I have this object pool with manually synced scripts on the objects but when I call RequestSerialization it doesn't serialize nor does it sync for late joiners unless the objects have been turned on and off at least once

random parrot
#

Are manually synced behaviours synced to late joiners, or will that first happen on the next serialization?

prisma lance
#

they are synced

random parrot
#

ah, that's nice, was kinda expecting them not to be

prisma lance
#

When someone joins your world, the OnDeserialization event will fire for every Networked Object in the world with the latest data, and they'll run whatever logic you have in place to update things based on that data.

random parrot
#

yup, that was what i was looking for

prisma lance
#

well that's what's supposed to happen at least, mine aren't doing that

cold laurel
prisma lance
#

what do you mean

#

of course they are not always enabled otherwise I wouldnt have an object pool

#

I enable them before calling RequestSerialization if that's what you're asking

cold laurel
#

You're using the built in VRCObjectPool component?

prisma lance
#

yes

cold laurel
#

coolio, can you send the contents of the script that is refusing to sync?

#

or is it too big

prisma lance
#
namespace Diplomacy
{
    [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
    public class PlayerNameDisplay : UdonSharpBehaviour
    {
        [UdonSynced] private int playerID = -1;

        public TextMeshProUGUI DisplayText;

        public override void OnDeserialization()
        {
            Debug.Log("Deserialized ID : " + playerID);
            UpdateDisplay();
        }

        private void UpdateDisplay()
        {
            if (DisplayText == null)
            {
                Debug.LogError("PlayerNameDisplay not linked to a DisplayText!");
                return;
            }

            if (playerID == -1)
            {
                DisplayText.text = "Loading...";
                return;
            }

            VRCPlayerApi[] players = new VRCPlayerApi[VRCPlayerApi.GetPlayerCount()];
            DisplayText.text = VRCPlayerApi.GetPlayerById(playerID).displayName + " " + playerID;
        }

        public void SetPlayerID(int id)
        {
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
            playerID = id;
            UpdateDisplay();
            Debug.Log("Serializing " + name);
            RequestSerialization();
        }

    }
}
#

OnDeserialization never gets called unless it's been returned once

#

they are enabled by default in unity as well

cold laurel
prisma lance
#

yes

#

as you can see in the logs there are 2 players there

cold laurel
#

ah, oops

#

I missed it

prisma lance
#

those are the first players logs

cold laurel
#

do you have any other script components on the same gameobject?

prisma lance
#

no only the canvas renderer and the textmeshpro

cold laurel
#

This is.. interesting

minor gale
#

disabled gameobjects or scripts don't receive deserialize right?

prisma lance
#

I wouldnt expect them to the problem is that they behave differently whether they had been activated before

#

anyways this was supposed to be a quicker way to do it than doing it myself but at this point I'll just do it myself

#

yeah it works great now I should have just done it to begin with

#

but now it leaves a gap..

#

since the text isnt getting disabled

prisma lance
#

I can just make it ignore the layout when it's blank

minor gale
#

i tested it just now and disabled scripts do receive deserialize, but not if they start disabled (they need to have fired start)

vrc's pool disables the objects initially, prior to start presumably, so that might explain what you were seeing

finite sierra
prisma lance
#

I don't set the owner in OnDeserialize

finite sierra
#

oh nvm it was hard to read it since the formatting in discord. where are u calling SetPlayerID ?

prisma lance
#

in an event

finite sierra
#

thats runs when?

prisma lance
#

when you press a button

#

it runs locally

finite sierra
#

and what are you trying to do.

prisma lance
#

as I said i've already gotten it working, it's just a list of players that have clicked a button

finite sierra
#

why exactly are you setting the owner and having a UdonSynced on a private? you can do it without needing networking.

prisma lance
#

how do you suggest I do it without networking

finite sierra
#

since you are using Vrc Player Object. you can manage it all with a Manager. that only exist once and is always owned by the master / instance owner etc.

prisma lance
#

I am not using player objects no

finite sierra
#

o? i thought i read that further up

#

any reason why you are not?

prisma lance
#

because it would make no sense?

#

there's a pre defined finite number of players that can join the list

#

using player objects would also mean I'd have unecessary objects for everyone who didnt click the button

finite sierra
#

how many people are you thinking of? in terms of how many can be in the world versus joining?

prisma lance
#

80 vs 7

finite sierra
#

and what are those 7 gonna be doing?

prisma lance
#

playing a game

#

using player objects would also make it needlessly complicated to have multiple instances of it running

finite sierra
#

only those who have joined would cost anything.

#

the other 73 wouldn't require extra and their objects would be disabled. but then again with 80 people its likely not gonna be synced considering the Data limit of 8-11 kb/s 8.5 kb/s with the upcoming update we have in beta atm.

#

unless those other people cant see the game? but i presume they can?

prisma lance
#

they can

finite sierra
#

also what kind of game? a card game?

foggy jackal
#

I just want to say I hate that game but also it's awesome and I think it's great that you're making a VR version 🙂

finite sierra
#

ahh that type of game.

#

do you know how many objects each player will own @prisma lance ?

#

that needs to be synced.

prisma lance
#

every piece is properly synced already

silver hill
#

So I changed around the enemy Ai Udon behaviours to manual sync again, I did a playtest using both my accounts in a game so i could see their perspective and it was working just fine, a little bit of delay but that will be fine for all I need, but then after that game I opened up this test arena to watch to see if the enemies were animating correctly, for the joined player they were in idle animation for most of the recording then at the end I saw a few of them begin to do animations, very strange.

#

Im guessing in manual sync networked events just dont work?

#

I had the thought maybe if I send out a networked event to tell everyone to request a serialization that could update their animation but how can i do that if networked events dont send under a manual sync

minor gale
#

they should work in either, i've only used them under manual. i'm not really sure what you mean by telling everyone to request a serialization, only the owner can serialize synced variables and everyone will receive the latest udonsynced variables when it's distributed

twin portal
#

network events send under manual.... but only the owner can RequestSerialization

frozen igloo
#

if you're having trouble with synced data not getting applied correctly on the receiver, you should NOT solve it by asking the owner to send it again. There's two possibilities:

  • The owner failed serialization and it never got sent at al
  • The late joiner has the data but applied it in the wrong order

The former should be obvious and doesn't sound like what you're getting since it is generally working, just one small bit isn't. That points to the latter. And in that case, you just need to review your codepath coming from OnDeserialization and ensure that it's applying things correctly in the right order

silver hill
#

Im currently not using a deserialization node

frozen igloo
#

are you using onvariablechanged?

silver hill
#

nope

frozen igloo
#

then how are you applying synced data you receive from manual sync?

silver hill
#

Just using networked custom events to tell everyone "This animation is now playing, play it"

#

it works perfectly under continuous sync but the performance drops for the host

frozen igloo
#

yeah don't do that, it's redundant and may arrive out of order

#

the reason it works under continuous sync is because it blindly sends over and over again which technically makes it work but is wasteful

silver hill
#

I had the idea of after every behaviour change it would send a network event to start a request serialization

#

But now Im not even sure of the correct way to use serialization lol

frozen igloo
#

Synced variables are one thing, network events are another. If you receive an event saying "an animation is playing!" and then you go to check the data and it's empty, you won't be able to do anything. Then half a second later you receive the data but you never apply it

#

That's what OnDeserialization is for, it fires when the data arrives. You don't need to send a networked event to tell people they have received data, because by definition the network event has no idea whether or not they have actually received that data yet

silver hill
#

So sending a custom networked event telling everyone to change variables and play animations is wrong? :L

frozen igloo
#

requestserialization is something you want the owner to do when they set data. It kicks off the process to send data. It's not something that receiver clients need to concern themselves with

silver hill
#

So... request serialization could be sort of considered a networked event in itself? and then on serialization is the output once received by joined players?

fallow mountain
# silver hill So I changed around the enemy Ai Udon behaviours to manual sync again, I did a p...

Re the video: Your sender is suffering, meaning the send queue is building up. In my own tests if sender is suffering, I can observe on the receiver side the deserializations will no longer happen in real time (or real frequency) but will be in bursts at variable intervals, I guess probably because the queue is sending big packet followed by some smaller packets. And since your queue is building up, it means you simply are sending faster than your bandwidth allowed, at least for a period of time, and everything afterwards are delayed or queued up. Which explains why your late joiners are not receiving the latest information in time.

frozen igloo
#

There are a few reasons why requestserialization isn't exactly a network event, like how requestserialization is a 'request' which just flags to the internal system that stuff needs to be sent. It doesn't directly send a network event which means the number of ondeserializations that get received are not guaranteed to be the same as the number of requestserializations. If you fire it rapidly, it will throw away most of them because all it cares about is the most recent state, not every intermediate state

#

But that's what you want because most intermediate information is unnecessary for the purpose of syncing the world. In the rare case where you do need to explicitly define intermediate events to show how you got from point A to point B (such as firing a gun), that is what network events are for

silver hill
#

im just strugling to figure out why like 8 enemies walking around can cause a network snag, how optimised do I gotta be damnit! lol

frozen igloo
#

if you're suffering with 8 enemies you've probably got something wasteful hogging bandwidth when it doesn't need to

#

how often are you doing requestserialization in the most extreme case?

silver hill
#

Almost never

#

ive strictly been using custom networked events to trigger the animations/attacks

frozen igloo
#

how many network events do you send per second?

silver hill
#

2 per enemy at most

frozen igloo
#

that should be fine

frozen igloo
silver hill
#

the Ai goes through a host computized cycle every 0.4 to 0.6 seconds, everytime it goes through a cycle it increases an integar by 1 and goes up to like 40, once it gets to 40 it resets to 0, as it increases if it goes to a certain number count it will trigger an attack

#

The gamestarter shouldnt be doing anything during a game?

frozen igloo
#

it appears to be sending once per second

silver hill
#

Just doing a fixed update for debug display data

frozen igloo
#

once per second 54 bps isn't a problem though

silver hill
#

I can only think the enemies are going through their ai cycles at a non uniform time so maybe the constant mini updates are doing something?

fallow mountain
#
  • Request serialization is for syncing (you can call it sending) variables, as in stored data like int or float or bool. As in sending a parcel. When the receiver / late joiner gets the parcel, their Udon will automatically fire OnDeserialization for you, so you can so stuff if you want. These data are available for late joiners.
  • On the other hand "sending" a custom network event, is not sending anything, there is no parcel, it is just telling the other guy to do x (i.e. Event X is triggered). Late joiners won't receive these if they are not there when Event X triggered.
  • The two are distinctly different ways of "sending stuff", they are for different things. Just wanted to repeat this just to say, you have OnDeserialization to let know you have received data. You don't need another Event to tell them.
silver hill
#

I dont know the capabilities of computers really so Im not sure

frozen igloo
silver hill
#

I dunno man, pretty much every object is just 12b I assume thats small

#

and thats just the ones that are active

fallow mountain
#

start with deleting all the enemies, put only one and see if you have problems

#

you delete half of the world to find what is hogging, and then repeat basically

frozen igloo
#

yeah, the enemies sound pretty light weight

silver hill
#

Il start it up and just lounge in the lobby and see what happens

fallow mountain
#

can you send all your scripts

silver hill
#

Just recorded a benchmark

#

The giant hand in fast motion sounds like a machine gun that also splatters spiders 😛

#

Looks like it is the enemies causing the issues

#

I hope these network issues dont stack the more players there are? :L

#

I like to think the host sends out the data in parralel rather than one at a time?

fallow mountain
#
  • how many enemy types are there? just two?
  • no they dont stack with more players per se
  • parallel or one at a time: depends on your script...
silver hill
#

I dont know the terminology I meant I assume the host sends out the updated data to everyone at once rather than one at a time

#

Each enemy type is different and i plan on having many different enemies

#

As you can see by the debug spawner Ive already implemented 8 enemies

#

They all use a different script but they all work very similarly

fallow mountain
#

why is this networked?

silver hill
#

So the hand has 2 momvement animations, normal walk and charge, that networks (hopefully) the 2

fallow mountain
#

can this be triggered many times in a single frame?

silver hill
#

should only go off on trigger enter for the attack trigger

#

and even if it did i made an isattacking bool to gate more than 1 attack at once

fallow mountain
#

hmm i dont see anything obviously network hogging in the scripts

silver hill
#

ok

fallow mountain
#

i think it has more to do with your player joining, it jumped from 0.5 KB/s to 1.5+ KB/s
which means every player takes up 1/8 of your bandwidth, that seems a lot

silver hill
#

oh

#

is that before i started spawning enemies?

fallow mountain
#

at the beginning of the video "a player is joining"

#

it jumped

silver hill
#

i see...

fallow mountain
#

the out: 0.5 KB/s jumped to 1.6 KB/s

silver hill
#

well the hitboxes will be running but those too arnt doing much

fallow mountain
#

but apperantly they do

silver hill
#

oh? i think i uploaded the hitbox script earlier if youre interested

fallow mountain
#

or why is the host sending so much data to a new player

#

are there other scripts running? for networking

silver hill
#

hmmm

#

player hitbox and player persistent object are all i can think of...

#

perhaps all the debugging is uneccesarily using data?

#

but thats all local i would have thought...

fallow mountain
#

btw in your spider, none of the variables are marked as synced, so nothing is sent when you request serialization

silver hill
#

its intended only for the host to use, thats why

fallow mountain
#

then you wont need request serialization

silver hill
#

ye thats what i thought, i probably addedit trying to fix the issues

fallow mountain
#

ok on your P HITBOX 2...

silver hill
#

what about it?

#

oh

#

didnt see the ...

fallow mountain
#

every 5 frame... you are sending a bunch of network events, that is a lot

silver hill
#

hmmmm, but theyre gated arnt they?

fallow mountain
#

ok at least one, in lobby

silver hill
#

i gated all behind an isowner bool, so i thought everything would be ignored for everyone except the owner

fallow mountain
#

idk, maybe there are other scripts

frozen igloo
#

if you have a script sending enough to cause clogging, and you gate it so only one person does that... then you're still going to clog that one person

silver hill
#

the game is fine locally, just dialing in the network issues really

#

very functional game in singleplayer

fallow mountain
#

why would the host suddenly generate an extra 1 KB/s when someone joined... u need to look at all the scripts i think

frozen igloo
#

vrchat reduces some outbound networking when you're alone so that could account for a small amount. But if it continues to add 1KB/s again for every new player, that would be a problem with your stuff

silver hill
#

damn... gunna have to parsec another account CAUSE I HAVE NO FRIENDS! :`(

fallow mountain
#

why not launch 2 clients in test

#

or 3 or 4

silver hill
#

would that be accurate since its essentially an internal LAN?

frozen igloo
#

local test still goes to a server and back, it's accurate

fallow mountain
#

it goes through actual server i think

#

^

#

And btw, using frame count as tick rate can be inaccurate because one person can have 40 fps while another have 200

#

for the P HITBOX 2 in particular

frozen igloo
#

I see the hand and spider scripts, where's P HITBOX?

silver hill
#

i just did it to reduce local load, didnt need to be accurate

fallow mountain
#

@frozen igloo it was from a bit before #udon-networking message
@silver hill Well you are still sending network events based on it, and judging by dev menu 6, the max rate vrchat can network seems to be 20 Hz at most, so if anyone is running at >100 Hz it will exceed the limit quick, and send events faster than it can handle

#

That is assuming the packets are small enough, and under ideal conditions

silver hill
#

i see

frozen igloo
#

20hz is the base network update rate, but it can bundle multiple messages per update. That's not where the limit is coming from. That said, yeah it still seems like an excessive number of network events

#

seems like you're using network events for things that really shouldn't be

#

lots of wasted bandwidth doing it that way

#

anything where you are repeatedly sending the same network event in order to ensure that everybody has heard the message is a huge red flag to me. Those should be variables

#

similarly, anything where you receive a networked event and use it to immediately set a variable and do nothing else... should just be a synced variable

#

This is a pretty small, reasonable amount of variables. But by sending them through network events you are making your own architecture less reliable AND more expensive

silver hill
#

interesting, ok

fallow mountain
#

can i suggest a duct tape method:

#

check if clogged or throughput bigger than half before doing stuff
and only do stuff if it is not
(the graph is wrong but you get the idea)

silver hill
#

ooof, will need to learn what those nodes are

frozen igloo
#

please do not repeatedly requestserialization at a fixed rate Cry

#

that defeats the whole purpose of manual

#

just... requestserialization when a variable changes

silver hill
#

ok

fallow mountain
#
  • my understanding is, isClogged means the queue is forming and you are no longer sending stuff as fast as possible
  • throughoutPercentage is a new node only in beta SDK, 0.5 means it is maxed and being throttled (and queueing, you dont want to start queueing at all)
  • there is also a suffering stat node, which seems to go up to 100 and related to queue size
  • what it means is, stop doing things when you are over a self imposing limit, you will never suffer
silver hill
#

ooooooooh! saucy! so i could make it so worst case some attacks wont trigger

fallow mountain
#

yeah something like that, make the mobs slower or something

silver hill
#

along with proper optimisation of course heh...

fallow mountain
#

yes this is really a duct tape method, it dont fix your problems, it just hides it

silver hill
#

is there a way to just yeet the queue alltogether?

fallow mountain
#

no way, you gotta wait it out

silver hill
#

boooooo... i guess inter game time could do that

#

got it, il spend tomorrow implenting changes based on your feedback, thanks for your time so far, @frozen igloo @fallow mountain @twin portal

silver hill
#

I just updated my SDK and noticed this, I assume a value of 0 means unlimited? or should I set it a finite value for it to work at all?

minor gale
#

it's 5 by default if it's related to network events (i'd assume 0 means 5 in graph)

twin portal
#

no, 0 means it is a "legacy event", and the custom event will operate in the same way that the "old" custom events did

silver hill
#

Definitely improved the situation, I can have probably 4 times the enemies in the arena now and it can keep up

#

Just the slight issue of the suffering increasing even when I kill all of the enemies... wonder whats causing that to happen

minor gale
#

with the new network event rate limits it will display suffering if they're trying to send more than they're rate limited to; your main networking isn't actually clogged there, it's some specific event or events

silver hill
#

uh?

#

So Im good?

#

:L

minor gale
#

you're sending some events too often

silver hill
#

I mean the FPS dont go down

#

When you say events I assume you mean networked events?

minor gale
#

unless you actually need them sent that quickly, but i'm not sure what you'd need in the lobby

#

yeah networked events

silver hill
#

With no enemies walking around I dunno what else can be causing it to grow

#

I adjusted the hitbox to have a slower update rate

#

since it doesnt need to go so fast, i also gated more fixed update events thought that should only really improve local FPS performance...

twin portal
#

the beta also lets you view how many events are in the queue, so you could use that and post it somewhere and see if the queue is continuously growing

silver hill
#

Oh? how do I do that, that sounds hella handy

#

Does it also say what objects are sending them?

twin portal
#

kind of

#

you can use those two functions to either view the entire queue, or just the queue for a specific event

minor gale
silver hill
#

Just a simple "Do you own this object" check

#

if you dont, you dont have to do all the other stuff

north thistle
#

why would a hitbox impact the networking?

silver hill
#

Cause it does alot more than just act as a hitbox

#

The game will have revive mechanics so it also needs to tell other players that the owner is dead and needs reviving

#

It also externally tracks the players status

north thistle
#

What you're describing sounds like a player manager

silver hill
#

Sorta

#

I might change how it works, its an early implemented feature that Im not sure even works anymore

north thistle
#

the hitbox itself shouldn't have any networking tied to it; for creating a revive trigger you can use a combination of player position and a "isDead" and/or "canRevive" bool to know when and where to trigger it

silver hill
#

Yeah will likely change it

muted onyx
#

hey i'm new to this style of networking, i've watched a few tutorials and saw some code but essentially whenever there's a state change for a variable in U# is the pattern:

Networking.SetOwner(Networking.LocalPlayer, gameObject);

// Critical Section Changing Variables Here

RequestSerialization();

So any time a different player wants to change something, it needs to request ownership because only the owner can modify variables? How does this work if both do SetOwner at the same time, would it just not update properly? Should there be a mutex on the set owner? or does it wait?

minor gale
#

the setowner will assume it succeeded if you just call setowner

race conditions can happen, but generally one player will "win" and the other will roll back their synced variable changes that weren't valid i believe

there's a way to reject ownership transfer requests detailed here, it's a graphic a little bit lower
(it's important to note that i believe this still assumes the ownership succeeds, but fires back OnOwnershipTransferred if someone rejects it)
https://creators.vrchat.com/worlds/udon/networking/#requesting-ownership-advanced

if you have some important state you want to modify and can wait for the owner to update it, it's better in some cases to pass the intended change to the owner via network events with parameters (which allows you to send data up to the owner)

you could probably also explicitly ask them to transfer ownership to the new intended owner for a bit more control over it yourself

this is on the beta currently though
https://vrc-beta-docs.netlify.app/worlds/udon/networking/events#sending-events-with-parameters

muted onyx
#

so for things without a lot of data if i want to ensure both messages get through (right now) i could do something like

while(Networking.LocalPlayer != Networking.GetOwner(gameObject)) { // should only be a frame or two 
  Networking.SetOwner(Networking.LocalPlayer, gameObject);
}

// critical section

RequestSerialization();
minor gale
#

i'm not sure if that'd just hang your game or not, but it should succeed regardless of you winning the race condition or not. i personally don't like the idea of putting that on a while-loop. i believe people would still receive the variables you sync out after an ownership change regardless of who wins, but synced variables are a singular state

so if you had something like a score counter and incremented it on two players fighting for ownership it'd fail to account for their scores sequentially and just apply once if that makes sense
i.e.
player A increments from 0 to 1
player B increments from 0 to 1
the resulting score is 1, not 2

if you do need something like that (a delta instead of an absolute change) it'd probably be better to send that delta to the original owner

muted onyx
#

could always do just a for loop with like 3-5 retries

i'd want that to be 2 though :/

#

yeah server client could be a better approach

#

the [[UdonSync]] variables don't seem to be atomic

minor gale
#

they are atomic if you read them in OnDeserialization, not if you read them via the variable changed callback

muted onyx
#

thanks for the help

north thistle
#

Also if you want multiple players to be able to affect a variable without throwing leadership around you can try using the new events with parameters that's in beta; although as race conditions will 100% occur it is best to use it in cases where that will not be an issue (for example a counter that everyone can add or subtract from and the order of these subtracts/adds aren't super important)

cold laurel
prisma lance
#

when accessing a vrc object pool's object through it's index am I guaranteed that it's the same object for everyone?

severe radish
north thistle
#

You using the VCC?

severe radish
#

I tried sending the var to the owner but the pool HAD to be owned by the returner that was calling the function. Yes I'm using vcc

north thistle
#

are you using the beta version of the sdk?

severe radish
north thistle
severe radish
#

Beta docs, awesome 👌🏻 thanks

#

Uuhh will this be good for changing a var or calling a return to a pool for multiple players?

#

I think the variable was working but not the returning to pool, I will for sure test it but just wondering

north thistle
#

you can send an event that tells the networked pool owner to spawn objects from the pool or return them

#

returning to pool, you can send an object id with the event

#

ReturnToPool(int id)

severe radish
#

Oohh I can send the id. Ok I will try it. I did try that to tell the owner to return it but for some reason didn't work maybe is that! But this seems exactly what I was doing, talk about timing right? lol for once the code gods smile at me 😂

#

Thanks for the help 🙏🏻 I'm on the right direction now for sure. I'm doing a FPS style system with health and all. And actually is working now but this will make it more polish for sure

#

I didn't like the ownership change one bit, 3-4 frames of pure caos and bugs

#

I had to place like 3 blocks of code to avoid and sync stuff after every return

north thistle
#

Just note that atm VRChat is limited for pvp where the player's position matters; the latency on player position is pretty massive and the only way I know to mitigate it is by making players move really slow and probably also limiting network load as much as possible

severe radish
#

Oh thanks. Forgot to say is pve so far looks good but the disclaimer is there bc I saw quite a bit un desync between players, but is not that serious is more of a casual shooting system so all good 😁

#

Still i picked up VRChat dev like week and a half ago and have been really impressed with the modding capabilities feels like a sandbox I love it

north thistle
#

it's basically unity with some features disabled and some added

#

And I've been making a horde survival game, myself

severe radish
#

Yeah and the enviroment setup was a breeze I love the VCC so friendly, not gonna lie a tear rolled down my cheek bc of how easy it was

severe radish
#

Do you found a way to not have to pool all enemies before hand? Or that's impossible? I really don't know many network enemy pooling patterns or tricks

north thistle
#

Everything that you attach a networked behavior to has to be present in the scene at build time so you can't instantiate anything like that unless the networking is handled by another object already in the scene.

Also you're going to need to sync its active state anyways so I doubt you'd be reducing your code complexity that much

severe radish
#

Mmm true, yeah I was all happy using instanciation at the beginning, big surprise 😅. Also my AI is tracking the players via collision, I liked the way you see the sensor zones, so I'm adding a player tracker to each player spawning(a collision box), is there like a default collision on each player I could use instead?

#

Last question I promise 😂

north thistle
#

Also I use distance to player for detecting players, myself; that might be faster and you can create a sphere wireframe or add a sphere mesh with the distance radius if you want to a debug visual

#

the advantage of a distance check is that you can choose how frequently the check happens

severe radish
severe radish
#

Do you do iterations on all players for all AIs?

north thistle
#

I have a DataList that contains a reference to all players that are currently alive in the round and I loop through that

severe radish
heavy spindle
# north thistle Just note that atm VRChat is limited for pvp where the player's position matters...

Was reading through and noticed this and felt like adding that this is largly only true for people not on the PC platform. There are outliers where PC players are extremely laggy, but generally, you can get away with more tight networking sensitive gimmicks if the lobby is PC only.

This has been tested by me quite extensively where I have made two versions of a world called Murder Classic wherein I have a version that is PC only and another where android users can play. On the PC only version, the death logic is calculated by players themselves seeing if they are within kill boxes and on the mobile compatible version, the logic is if your assailant sees you within a killbox like their knife or gun, they tell you to die… Eh… Forcibly respawn? Yeah forcibly respawn might be a better way to put it.

I wouldn't exactly recommend knife fights, but the latency actually is not bad and feels a lot more fair than say running away from a quest user in murder 4 when they're the murderer, having some distance away from them and still dying somehow (assuming they don't throw the knife)

#

Even quest users being on the PC platform through like virtual desktop or hard wired via quest link is so much better for latency

north thistle
#

How many people were the the instance at the time?

heavy spindle
#

Iirc more than 5

#

There have been cases where the soft cap of 12 was hit in both cases

#

I played my worlds a lot when they were new

north thistle
#

It might work fine at lower player counts (like sub 16-20) and worlds that aren't too network heavy and where all the players live reasonably close to the relay server and on the players are on the slower side and not moving too erratically

heavy spindle
#

Thats a tall order

#

The thing was this was consistent. If you don't believe me, I'd recommend doing an experiment

#

Would personally like to see more data on this like if worlds should have platform aware combat logic

minor gale
#

there's not really a perfect tradeoff, if you're basing it on the receiver's perspective a knife might not hit at all when an attacker grazes them because of latency and interpolation; the attacker also has to wait a lot more time for the receiver to understand that they've been hit and send the respawn/death over network if you can't reliably inform the attacker that they succeeded, maybe that helps pacing in some cases; as opposed to firing some sound/particles on the attacker and sending a kill event

for melee i think either can work, for shooting i don't think you can really get away with receiver logic as easily

#

i don't know that there's a specific distinction between quest and pc when it comes to their send rate, but it could be the case; though it could also be that the average quest user's latency is higher being on wifi? you could verify it with the simulation time of a player when they're on pc vs quest i guess

north thistle
#

also note that people you aren't actively looking at will have significantly higher latency; so when entering vision it could have a couple or so second delay

#

I know Terrors of Nowhere's pvp gamemode is an extreme version of VRC's player position synching not playing well with pvp

High player speeds in fairly open maps allowing for erratic movement combined with receiver-side detection and a network heavy world. Saw someone with bad fps/internet be unkillable.

heavy spindle
north thistle
#

I'm pretty sure the way it works, VRC will prioritize what is within your vision for faster network updating (on the receiving side).

minor gale
#

they definitely use distance (you can observe this pretty easily by having someone far away teleport near you); i haven't personally noticed directional

north thistle
#

I could have sworn I read the other day in the docs that it was based on vision

But the docs are so scattered that it's going to be hell to find it again

#

good thing I took a screenshot; found it:

minor gale
#

definitely possible

north thistle
#

testing it using build & test, my attempts to create latency spikes were so inconsistent that it's impossible to tell

minor gale
#

assuming you can pass a player to that like you can with sim time

north thistle
#

The information we are looking for is likely in debug menu 4, but half the things in that menu don't match up to the docs

#

What are all these "Q" values, for example

north thistle
#

it's still super inconsistent, though

minor gale
#

you're right

#

from what i'm seeing here they start scaling from > ~0.3 dot to the player, i think it modifies where they start their distance scaling

north thistle
#

I can believe that

I imagine they want to prioritize good networking for the social aspect of VRC where people near you > people not close who you are looking at > people not close who you aren't looking at

fallow mountain
#

Was just testing the new network events with parameters, I am a bit surprised by its performance
I could send an event carrying a few parameters (floats and doubles) at at least 60 Hz (limited by my own framerate)
The sending and receiving characteristics are very similar and good delta consistency from one event to the next
This is much more responsive and with predictable timing than serializations (much lower Hz and much more variation in deserialization delta times)
It could improve the game a lot for a lot of things

north thistle
#

Is there any way to prevent VRCObjectSync from overwriting the position set by the object owner? This is something VRCObjectSync is pretty aggressive about doing on newly activated objects and it's super annoying to deal with.

I see there is a TeleportTo method but it takes a transform, which I don't have for what I am trying to do; just a Vector3 and Quaternion

minor gale
#

like you're trying to activate an object and you position it at that time?

#

you can try FlagDiscontinuity()

north thistle
#

I have tried that

#

the position gets overwritten even if I delay it a frame

#

I suspect when an VRCObjectSync gets activated it waits until it gets the last know position sync, updates the transform to that position, and THEN starts respecting ownership

#

Which means I have to wait an arbitrary amount of time, then set the new position, and I guess pray that an edge network spike doesn't screw me over

minor gale
#

you could write it yourself in manual sync if you actually want that control, but it might be a bit annoying if you're using vrc's object pool in tandem

north thistle
#

I've built my own object pool

rare cloak
#

I think I could be having a similar problem lol. Trying to spawn items from a vending machine and it's not syncing well at all for me

twin portal
#

from what I can tell, the Object Pool needs to work in a kind-of specific way, and tends to break if you push it too far

#

like there's an assumed way it's meant to be used and starts to break down if you go outside of that

severe radish
twin portal
severe radish
#

Just as im using them, god timing xD

north thistle
north thistle
#

So I'm trying to determine if an object's ownership transfer was due to the previous owner leaving. Now I had assumed that checking previousOwner.IsValid() in OnOwnershipTransferred would work, but turns out the leaving player is still considered valid at this point.

Would I be able to put into a singleton script a list of players in the world populated/depopulated with OnPlayerJoin/OnPlayerLeave? Or in other words, does OnPlayerLeave always trigger on all scripts before OnOwnershipTransferred can trigger?

minor gale
#

i think if they fire in a specific order you might not be able to get around that very easily, i don't know that there's a good solution for that specifically without some sad arbitrary waiting around or checking after the fact. maybe you can work out some way to defer the leave event to the object and check against it (leave fires, you push an event to all relevant objects and check at that point if their cached owner happened to be that leaver)

maybe it works in some way that can consistently check for that, so i don't think you should give up if that's more applicable

not sure what you're doing exactly, but i think you can try to design around like some positive flag so you can infer that transfer if needed

like designing around ownership as the sole factor isn't very clear compared to designing around something like "well they're holding the pickup and they're also the owner"; considering a state more like that on something you're implementing might help

OnOwnershipTransferred(VRCPlayerApi player)
{
  isOwner = player.isLocal;
  if (!isHeld && isOwner)
  { // Player became owner without a positive event/trigger }
}

OnPickup() { isHeld = true; }
OnDrop() { isHeld = false; }

Update() 
{
  if (isHeld && isOwner)
  { Some sync logic or something }
}
#

i guess i didn't really answer the question and i don't know the answer as to the order, but i'd assume it's consistent (one firing before the other and gets sent to all objects subscribed to that event i'd think); so maybe in your case it's more clean to just check in the leaver event if the leaver == cachedOwner and decide what to do at that point

OnPlayerLeft(VRCPlayerApi player)
{
  if (player == cachedOwner && Networking.IsMaster)
  {
    // Some logic for a leaver's object, master should become the new owner if master check works as intended here
  }
}

OnOwnershipTransferred(VRCPlayerApi player)
{
  cachedOwner = player;
}
north thistle
#

what is working so far is this bit of code withing the OnOwnershipTransferred:

if (!_gameManager.IsPlayerInWorld(_lastOwner))
{
    //Stuff
}
else
{
    //Other stuff
}

meanwhile in the GameManager singleton:

public bool IsPlayerInWorld(VRCPlayerApi player)
{
    return Utilities.IsValid(player) && _playersInWorld.Contains(new DataToken(player));
}

where _playersInWorld is a DataList the populates/depopulates with OnPlayerJoin/Leave

minor gale
#

i think personally i'd check the contains against their player id rather than creating a reference to their player, are you saying that ownership transfer works properly then?

north thistle
#

Also my OnPlayerJoin is a bit funky to support late joining and edge cases; haven't properly tested it yet:

public override void OnPlayerJoined(VRCPlayerApi player)
{
    if (player == Networking.LocalPlayer)
    {
        _playersInWorld = new DataList();
        VRCPlayerApi[] playersArray = new VRCPlayerApi[VRCPlayerApi.GetPlayerCount()];
        VRCPlayerApi.GetPlayers(playersArray);
        foreach (VRCPlayerApi p in playersArray)
        {
            if (Utilities.IsValid(p))
            {
                _playersInWorld.Add(new DataToken(p));
            }
        }
    }
    else if (_playersInWorld.Contains(new DataToken(player)))
    {
        LogWarning($"Player {player.displayName} already in world");
    }
    else
    {
        _playersInWorld.Add(new DataToken(player));
    }
}
north thistle
minor gale
#

yeah it makes no difference really, it just looks nicer than doing an inline new datatoken i feel

north thistle
#

I've long, long ago given up on trying to make DataToken stuff look pretty, lol

minor gale
#

does your bool function work as you'd expect? like player leave fires before the ownership transfer?

north thistle
#

That's how I got the idea. When I had the test player leave, the OnOwnershipTransferred errantly tried to access information that had already been removed by my OnPlayerLeave

north thistle
#

I'm going to try a new networking design principle: all objects with networking behaviors on them should be active on scene load and never be disabled. If that causes issues, find a way to work around it.

minor gale
#

that's how i tend to handle things that can become "inactive" either through setactive or a combination of components

i usually cache the transform i treat as the main transform and it becomes pretty much the same as operating on the transform if you remember to replace transform

severe radish
#

    [NetworkCallable]
    public void ReceiveSync(Vector3 pos, Quaternion rot, Vector3 vel, int state)
    {
        Debug.Log("[AI] ReceiveSync triggered on player ID: " + Networking.LocalPlayer.playerId + "Position " + pos);

        syncPosition = pos;
        syncRotation = rot;
        syncState = state;
        velocity = vel;
    }```

So im trying the new events and im trying to send this 4 variables over the event, on my client they are changing(im loggin the receivesync on all players) the other clients are logging the recivesync event that is called on the lateupdate excluisively. but the values on the params im sending remaing the same does anyone know why? im doing something wrong?
fallow mountain
#

transform.position is the position of the game object the script is attached to

#

not the player

severe radish
#

YEah this goes into my AI object, so thats good, im using that position to move itself the one calculating the "destination" is the master and is passing teh resulting movement here

#

So I only calculate the navmesh on the master, and this are synced over the new events... but Im even jsut debugging like pos alone and see if it changes but only on the local/master player sadly

north thistle
#

Oh quick tip, if you're using VRCObjectSync, have it as the only networking script on the parent of your object group and put all other network scripts on children objects

severe radish
#

That was a doubt, I really dont have a objectsync bc I was "manually" updating its position, but Im not even able to send the position properly, like it prints no changes on the clients

north thistle
#

VRCObjectSync has some capability to turn off networking for its object and having other networking scripts on it can mess up its ability to self-prioritize, severely reducing networking performance

severe radish
#

Do I need to make my AI like a child of an empty with an sync to work?

severe radish
#

The actual function is being called I can see the log activating it from the master but no params are sent

#

im only calling it from behind this if (Networking.LocalPlayer != null && Networking.LocalPlayer.isMaster) so i know is being called properly

north thistle
#

on debug menu 4 this should be zero or hitting zero occasionally

severe radish
#

ok will do one sec

#

my god it only goes up xD why is that?

north thistle
#

because you're trying to send out networking data at a rate faster than VRC allows

#

so unsent networking updates pile up more and more

severe radish
#

mm only on the master tho still not normal?

#

I assume only the master can make it go up since is the one sending it

north thistle
#

if this number is never hitting zero, you can have network updates that will NEVER get sent out

severe radish
#

Oh god it nevers goes 0 is going up almost as fast as my bills

north thistle
#

you want to have this at a solid zero during periods when up-to-date networking is desired

frozen igloo
severe radish
#

Maybe is bc im calling the event every frame?

frozen igloo
#

yes that would definitely do it

severe radish
#

is sending just like a vector 3 tho

#

lol xD i read it could send 4 bites easily and ssumed wrong 😛

frozen igloo
#

it can, just not every frame

north thistle
#

I've been experimenting with getting around the limit by distributing my ai among the players in the round

frozen igloo
#

I'd recommend aiming for 10hz max, at least to start. And if you need more than that, pack multiple sets of data into one event at a time

severe radish
#

mmm so what is a good practice when calling this event? like mine is just sending this SendCustomNetworkEvent(NetworkEventTarget.All, nameof(ReceiveSync), transform.position, transform.rotation, velocity, (int)currentState);

north thistle
severe radish
#

mmm I see rn my clients were on suffering 0, but I only had 1 AI, before asking more I will set this to send 1 event every 60 frames and see how it goes

north thistle
#

when it comes to positional data, my own experience leads me to believe that events are the worst way to sync that data

frozen igloo
#

network events are designed for events, synced variables are designed for state. That has a variety of implications in how they are implemented and what they are best at being used for

twin portal
#

probably just want that position to be continuous synced and set it to lerp

north thistle
#

I'd personally recommend starting out with VRCObjectSync and maybe going with a manual sync solution if you have a specific need

severe radish
frozen igloo
#

I shall once again link the sacred texts
Events vs State: https://www.youtube.com/watch?v=Na95i4ZD68I
Precise timing: https://www.youtube.com/watch?v=h47zZrqjgLc

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

In this 2011 GDC session, Bungie's David Aldridge discusses the programming that drove Halo: Reach's online networking.

Register for GDC: http://ubm.io/2gk5KTU

Join the GDC mailing list: http://www.gdconf.com/subscribe

Follow GDC on Twitter: https://twitter.com/Official_GDC

GDC talks cover a range of developmental topics including game des...

▶ Play video
north thistle
#

what I'm doing in my own project is having a VRCObjectSync and NavMeshAgent in the parent of my AI object, and then putting the AI script into a child

frozen igloo
#

The most important thing is to not consider network events as raw packets. They're not, they have a bunch of infrastructure on top to ensure that they are reliable. That makes them awesome when you need a singular, reliable event that you can guarantee the other side receives - but they're waaaaay overkill if you just want to sling some position data over

north thistle
frozen igloo
severe radish
#

So idk what is making it go up mmm I guess I need to look somewhere else

frozen igloo
#

lock it down to a specified frequency and then play with that frequency to see how much you can get away with

#

or build safeguards that listen to Networking.IsClogged to stop or slow down what they're doing

severe radish
twin portal
north thistle
#

If the data you're sending out is over a certain size, it will turn from one event into multiple behind the scenes

severe radish
north thistle
#

wait no, I'm wrong, lol; ignore what I said

severe radish
#

so this is my net use on the staggering local player no info is being sent if im nto mistaken?

#

or im reading it wrong?

frozen igloo
#

I think that readout only shows synced variables

#

it's primarily documenting "serializations" which is where it packs up sets of synced data and sends them off. Network events are a little bit outside that system so this readout doesn't cover them

severe radish
#

Oh no events got it, btw @frozen igloo I didnt noticed we are on the chat with haven... im working on their thing

frozen igloo
#

yeah you found the right place after all hehe

severe radish
#

I didnt want to bother you and here im lol

frozen igloo
#

well better to ask in here because if I'm not around other people can chime in

severe radish
#

I actully got a functioning one with udonsync stuff work okish, but I want to make it more robust so here im xD

#

But is like 8 scripts lots of crap I put it up as fast as I could bc I didnt want to let them hanging but now that there is a working prototype I want to take my time with this one

#

Like you look at it for too long might crash xD

frozen igloo
#

yeah, that's the perfect place to be for watching those two videos ^^

frozen igloo
# severe radish YEah I read that but is like 4 vectors 3 and an int, and for this purposes it wa...

4 vector3s plus an int is 52 bytes. if "every frame" means 60hz, then that's 3 kilobytes per second for the data raw. The overhead on top of that of serialization, headers, string for the event name, it adds up quick so it's probably a lot more than just 3KBps, probably more like 5KBps. The global limit is flexible and hard to put a single pin on it as it too varies depending on the structure of the data you're sending over, but a general guideline is that over 10KBps is way too much, and avatars already take up 3-5KBps too

severe radish
#

Mm yeah I jsut implemented a 1 per second interval lets see how it goes

north thistle
# frozen igloo That's not a bad use, yeah. As long as you occasionally sync the whole thing and...

Also it seems pretty deterministic without the need for any extra synching

The owner on the object pooler is still the only one allowed to pull stuff out of it to prevent race conditions. When an object is requested from the pool, the owner selects an index and then puts that index into a networked event. The network event is sent to everyone, including to the owner, and it is that network event that activates said object by the index and sets the correct value for the parallel bool array.

fallow mountain
#

oh nonono, it is because he didn't do [NetworkCallable(maxEventsPerSecond: X)]
it defaulted to 5
so the queue just builds up without actually using the bandwidth

minor gale
frozen igloo
#

if synced variables get clogged, they start throwing away some packets (though they do ensure that the latest state is synced, they throw away old packets that are no longer relevant). If you use network events for position data it's saying that you care so much about this position data that you NEED everybody to know not only the latest state, but also it's entire history, even if there was a brief hiccup in yours or their internet, you need them to have EVERYTHING.

If this is a card game, yeah, absolutely! Individual events can be super important. But a large amount of data for games is not. Even in some situations where you think it's important enough for that, I'd encourage you to still attempt to bake your high-bandwidth items down to be state based, because that indicates to the systems getting your data from point A to point B that a lost message here and there is fine, as long as the current state is correctly received

fallow mountain
#

i could send at 60 Hz with a few parameters easily (with the limit set to 100), so the bandwidth should not be a problem, my frame rate was actually the bottleneck

north thistle
frozen igloo
minor gale
#

it does actually increase suffering if you push more events to something than you're limited to

#

theirs being 5 that's why it said suffering

twin portal
#

I think in my testing it still calls the event and queues it, but the events only leave the queue at the MaxEventsPerSecond rate

frozen igloo
#

oh yikes, well don't do that lol

minor gale
#

it doesn't globally suffer

#

it just displays suffering, other networking isn't limited

#

from what i observed

north thistle
#

Yah, from what I've seen it appears that suffering more-or-less just represents the number networking events that failed to get sent out on the last network upload

frozen igloo
#

I guess events behind that limit are counted in the thing that calculates suffering, which is not something I would have expected to be done but it's probably not a bad idea

severe radish
#

Ok pls dont hit me guys xD.

It turned out when I limit it to 1 per second it was solved, I was just launching "test my last build" LOL but stuff is going through, no suffering is happening and all is good thanks guys. Now my AI is not actually moving but that I can solve

frozen igloo
#

overall philosophy on network events vs state still stands, but yeah it did seem a bit overly tight to what you were trying

minor gale
north thistle
frozen igloo
severe radish
#

Is all fixed and I love it 😄 thanks again guys, I was just sending data like a maniac that was all (im kinda new to networking and I abuse the web like is my local machine xD)

north thistle
twin portal
#

the order is guaranteed as long as you aren't hitting the rate limit

north thistle
#

the thing that gets "synched" in this situation is the bool array; the object array is a constant

minor gale
minor gale
#

vincil it's like 38 bytes vs 300 bytes if you use raw bools for the array compared to packing the bits

#

the system method isn't exposed from what i remember, they have a way to pack a bool array to byte[] or int[] i think, i ended up implementing it myself in my kinda helper static stuff

fallow mountain
#
  • Custom events arrive in order, docs says its guaranteed
  • It seems there is no real way to reliably measure bandwidth in udon. With just serialization, it throttles at throughput 50% but if I send custom events on top, it goes above 50%. So I can actually set it to send lots of events and make throughput go up to 70+% and still serialize without throttling. So throughput is no good.
  • Suffering only slowly builds up to 100 for serializations, but even at 1 suffering, it is already too late, serializations are being throttled.
  • IsClogged is basically useless because it only returns true when suffering reaches 100.
  • it seems there is no way for serialization to limit reliably at this moment because for some reason custom events are taking up throughput while not contributing to the throttle-triggering bandwidth...
north thistle
#

I think VRC has multiple different bottlenecks you can hit in the background and you aren't told which one you are hitting

frozen igloo
#

there was a whole chunk of networking debug information exposed recently that I haven't gotten around to playing with yet, but I'm certain that a significant amount of deeper understanding of rate limits and throughput could be gleaned from them

north thistle
#

I think what they exposed is the same info that we've already been able to see in the debug menu 4, right? What is the doc page for that again? It's so hard to find this stuff sometimes.

twin portal
fallow mountain
#

that is actually how i find out how it is throttling, using the new network stats

#

that was my test results

frozen igloo
#

like graphing over time and comparing directly with what was sent, for one example

fallow mountain
#

also, btw, curiously, it is not just the sender who generates traffic, the receiver will also output (send out) about 25% of the sender's out (not sure whats going on)

frozen igloo
twin portal
#

two generals' problem moment

north thistle
#

There is new per-object stuff, but every global stat listed is also present in the debug menu 4, right?

frozen igloo
north thistle
north thistle
#

But actually maybe the debug menu 4 also got updated

#

On the doc page for it (listed lasted updated in August of last year), you can see those values present; the only addition seems to be time in room

fallow mountain
#

the bytes in/out... do they correlate to the dev menu 6 numbers? (in/out) because i remember seeing them very different

north thistle
fallow mountain
#

you mean the one on 6?

north thistle
#

debug menu 6 I think only lists your own networked objects

#

as in the ones unique to the world

#

I'm pretty sure the stuff that is synching your position in the world won't appear in debug menu 6 but will impact the outbound data you see in debug menu 4

#

Actually I change my mind; I don't believe debug menu 4 shows you much if any of the networking being sent out by VRC's internal systems

That would explain why you get throttled way before hitting 100% throughput

fallow mountain
#
  • Anyhow, we know the serialization starts throttling at about (just below) 9 KB/s which is half of the 18 KB/s hand cap. (Confirmed by dev previously.) We can use Stats.ThroughputPercentage to see how much we are using (it throttles at 0.5), but once you start sending custom events, it will increase this number without actually using the 9 KB/s allowance for serialization...
    • Considering in practice you don't want to start throttling because it will no longer serialize in real time i.e. lag and visibly desync...
    • Therefore the only way to really control it is by manually calculate and predict and hard wiring your scripts to not send out more than x KB/s.
  • For both serializations and custom events, it seems receiver will output say ~25% of the sender's output. (Maybe someone can test independently to confirm) Which means, if two people are sending stuff together, they will each use up x * (1 + 0.25 * n) of bandwidth, where n is the number of people, assuming this scales up linearly.
    • If there is 40 people in the instance trying to serialize (and send events) (say in a massive battle game), on average, each of them will have have a hard limit of x * (1 + 0.25 * 40), or x * 11 = 18 KB/s, meaning (18/11) KB/s = 1.6 KB/s hard cap, of which 50% = 0.8 KB/s is the throttle limit of serializations, and the other half is for custom events and voice and other stuff.
  • Conclusion: 1. Calculate->test->hard code your output KB/s and don't rely on stats to throttle yourself, 2. be very conservative if you don't want throttling/desync in your game, especially with more people.
#
  • And taking network lag and jitter into account and gameplay variations, you don't want to cap at the theoretical max, maybe aim to use about 50% of the bandwidth on average will give you enough head room for deviations. Therefore you really only have a "time averaged" 0.4 KB/s for each player in a 40 people instance.
north thistle
#

2 players, each with 35 AIs with VRCObjectSync:

#

meanwhile 8 players with 271 of those AIs spawned in the world

fallow mountain
#

Ok I just did a little test, I have a player object so every player is sending out a large serialization payload (2 dummy strings at 300 characters each) at 10 Hz, and custom event with a few parameters at 10 Hz, so all the players are sending the same amount of data at the same frequency. Some observations:

  • Player count 8: Interval Q is red, Hitch Q is red and yellow, the Delays are very red and uneven and many seconds
    • KB in about 55, KB out about 9.5 (bottlenecked and/or throttled?)
    • in Menu 6, the Hz are very uneven and clearly not 10 Hz, showing 3..4..6..7 Hz
  • Player count 6: Interval Q still red, Hitch Q is yellow and generally better, Delays are still red but more even and 1 or 2 seconds
    • KB in about 55, KB out 10.5 ish (bottlenecked and/or throttled?)
  • Player count 4: Interval Q yellow at 0.7 to 0.8, Hitch Q is green near 1.0, Delays are green and white abd about 0.35+ seconds
    • KB in about 55, KB out 12 (seems much healthier and data is actually being sent out)
  • Player count 2: Interval Q yellow at 0.85, Hitch Q is green as before, Delays are ~0.32 seconds
    • KB in about 20, KB out 10.8 (scaled down nicely)
  • Not sure how much this is caused by my own CPU bottlenecking (probably only for 6-8 players) but these numbers do seem to scale down as player count goes down (these also appear in your test)

#
  • In both our test, the KB out seems to be capped at 12 KB.
  • In my test, exceeding this cap probably contributed in network being throttled and making the stats red, the more people, the worse. This can be explained by added people also increased the output for everyone.
  • Between 2 and 4 player count, the "KB in" was more than doubled (as expected), but the "KB out" also increase by about 1.2 KB... so the increased output per player count isn't as big as expected, but definitely non-zero and is significant enough to take up usable bandwidth... 1.2 KB is 10% of the 12 KB observed cap. This is just 2 people.
  • From 2 to 4 people, the "KB in" increased by say 25-30 (which is more than the extra "KB out" from the two people so maybe a fluke), but KB out is also increase by the 1.2 KB. The ratio is say nominally 5%.
  • The theory usable bandwidth (without player overheads) may be... x * (1 + n * 0.05) = 12 KB
    • Applying to our cases as test (assuming my actual usage is about 10.5 KB/s) which might explain the observations.
      • 2 players: x * (1 + 2 * 0.05) = 12 KB x = 10.9 KB/s <-- I am sending less than the limit, network ok
      • 4 players: x * (1 + 4 * 0.05) = 12 KB x = 10 KB/s <-- I am sending at the limit within margin of error, network ok
      • 6 players: x * (1 + 6 * 0.05) = 12 KB x = 9.23 KB/s <-- I am sending above the limit, network bad
      • 8 players: x * (1 + 8 * 0.05) = 12 KB x = 8.57 KB/s <-- I am sending way above the limit, network very bad

  • In any case even at small player count, because of how VRChat syncs, even at low "KB out" the game will introduce delay of at least 0.3 seconds on other players (and can go up to infinity) in order to smooth out the intervals to make things appear smooth or at a realistic frequency. Therefore VRChat is really not suitable for fast pace shooter PVP gameplay (where 0.3+ seconds lag is literally unplayable).
  • Screenshots are representative:
finite sierra
fallow mountain
#

Just discovered there is an undocumented limit... a hidden hard cap put on Network Events on PlayerObjects, firing faster than 10 Hz will be queued up and suffer, regardless of player count. Even 0.099 second intervals will queue up, but 0.1 will not.

  • Non-PlayerObjects do not have this limit and is tested to fire at 60 Hz at least without problem.
  • But there is a workaround... make a copy of this Player Object (2 objects) and they will (together) fire twice as fast without queuing.
    • Make a pool of them for even higher frequencies...
  • Curiously the deserialization rate limit is tied to the Hz of the object in Menu 6 and can be like 12 Hz i.e. more frequent than Network Events on one PlayerObject.
#

TLDR how to prevent Delay increase and make your networking smooth:

  • Step 1: Calculate your "non-delaying bandwidth x" using x = 12 KB / (1 + n * 0.05) where n is the expected max player count in your instance.
    • E.g. Your game is 8 players, therefore it has 12 / 1 + 8 * 0.05 = 8.571 KB/s non-delaying bandwidth.
  • Step 2: Test below using 2 clients, so Network Events will use actual bandwidth. Both clients should be sending and receiving at the same time, to simulate a live game.
  • Step 3: Don't fire Events, only firing serializations, tune it to be below x * 0.5 by adding up the per object Bps in Menu 6. Less is better.
    • Note: The "Bps" in Menu 6 is only for serializations and do not include Network Events.
  • Step 4: On top of the serializations (keep it on), start firing Network Events at maximum frequency your game allows, to see if the total Out: KB/s (at the top of Menu 6, or KBytes Out in Menu 4) is still below x.
    • Now if you are still below x, your game should have minimal Delays up to the player count you used in your calculation.
    • This test simulates the moments of activity spike where the output will cause VRChat to add Delay to remote players, causing lag and desync. You are basically testing for the worst case situation so it won't happen in a live instance.
      (I have tested this method to be pretty spot on for a 4 player instance, I could toy with the point of Delay to make it Delay/Suffer or not)
north thistle
# fallow mountain Just discovered there is an undocumented limit... a hidden hard cap put on Netwo...

"Non-PlayerObjects do not have this limit and is tested to fire at 60 Hz at least without problem."

I don't believe it is possible to send anything over the network at that event. If you are referring to manual sync, you can call "RequestSerialization()" all you want, you're only requesting it to happen, not making it happen. It appears that manual sync works on a tick rate outside your control where every tick it asks "has serialization been requested between now and the last tick?" and if so, it sends out the data.

"Each manually-synced object is rate limited as a factor of the data size. The more it sends, the more its send rate is limited. Scripts can call RequestSerialization as often as they want, but Udon will wait until enough time has passed before calling OnPreSerialization, sending the data, and calling OnPostSerialization with the result." - https://creators.vrchat.com/worlds/udon/networking/network-details/#manual-synchronization

Networking in Udon can be challenging! Try to keep things simple until you're more experienced.

minor gale
#

they're referring to events i think and you can actually achieve very high send rates with events

north thistle
#

I'm just confused as they are talking about a "more players adds extra networking consumption" that I have not observed in my own network saturating world

minor gale
#

manual and event networking are reliable, due to acks presumably it does actually raise another player's outbound when someone is sending more data, i can record this happening if you'd like a view of it

north thistle
#

I can only assume is uniquely a manual sync thing as my world's network capacity is being used up via VRCObjectSync and events

minor gale
#

continuous might be unreliable as it's expected to emit continuously (as the name suggests) but i don't know for sure and rarely use continuous myself

north thistle
#

Do we have the tools to change the update rate on continuous and/or make it sleep yet?

#

Actually it might already automatically change its own update rate; but iirc we can't make them sleep

minor gale
#

i think it does actually sleep with just vrcobjectsync when the rigidbody sleeps? but i could be wrong about that

north thistle
#

vrcobjectsync will sleep itself after a period of no movement

#

but iirc last time I checked, custom continuous Udon scripts will not have the same behavior

minor gale
#

yeah i'd expect them to just constantly blast variables, i think moving away from continuous is ideal in most cases

north thistle
#

if what is said about manual is true, doing what I am doing with my world would be impossible with manual sync

minor gale
#

which part?

north thistle
#

Having several networked, nav mesh agents distributed across the players (and by several I mean it can reach 280 networked nav mesh agents at 8 players)

minor gale
#

maybe continuous works out better there. i tend to sync destinations instead, i think zombie survival does that as well to support a large number of agents

north thistle
#

I thought about that but the system is way too chaotic and the nav mesh tricks I'm employing are too dependent on the accurate position of other nav mesh agents that I need to sync current position instead of destination

minor gale
#

have you tested the upper limit you can support? like i'd assume continuous adjusts their interval across all scripts to try to support smooth playback, but i haven't used it enough to know

north thistle
#

around 40 is when suffering starts fluctuating

minor gale
north thistle
#

yah, ~4hz while moving

#

Also found an annoying networking caveat with SendCustomNetworkEvent targeting the owner of an object.

If you assign ownership of an object to another player and on the same frame target the new owner with a SendCustomNetworkEvent using NetworkEventTarget.Owner, it will work correctly under most circumstances.

However if you are doing a lot of these ownership reassignments at this time, it is very consistent that while your script will still correctly recognize the remote player as the correct owner, your SendCustomNetworkEvents will start coming out before all ownerships have been correctly assigned, causing some of them to go to the wrong person.

minor gale
#

i don't think i'd rely on that, sounds like unfun race condition territory, i think i'd probably prefer to send an event to all players with the intended target as an int and have them take ownership themselves when they receive it

north thistle
#

the warning message here is triggered by a custom event being send to the master instead of the newly assigned owner

#

It's actually VERY consistent; it's always 7 custom events that end up going to the wrong player when it's 32 x 2 ownerships + 32 events being sent out to a remote player

#

13 ownerships transfers happen too late, which means 51 made it in time

fallow mountain
#

(But Menu 6 will report 11 to 12 Hz... so I guess practically you don't want to go over 10 Hz)

north thistle
#

oh thinking about it, while you can generate events at up to 100hz, the rate they're actually sent out over the network is probably still limited by a network tick rate

#

or rather, they won't be sent individually instantly, but rather as a batch

fallow mountain
#

in my case it was limited by Update() frequency i.e. framerate, and it did go out "instantly" as in the receiver can receive it at about 60 Hz intervals as expected (but with some delay)

#

so there is no observable "tick rate" that i can see at least

#

However for serializations if you serialize at say 10 Hz but more than say 8.5 KB/s (throughput 0.5), the receiver will receive in 1 second bursts, that could be the "tick rate"
But it didnt apply for events

north thistle
#

does debug menu 6 hz stat get effected by events?

#

And for the receiver, update rate will be HEAVILY impacted by what group that networked object belongs to in that moment

#

what you are seeing in debug menu 4 is the delay for their avatar sync I'm pretty sure

fallow mountain
fallow mountain
#

(but probably also their events and serializations, i suspect)

north thistle
#

you can see how much delay is impacted by having your two players close look at eachother and then far away looking away; while you are close and looking at the other player:

#

and then when looking away at a distance:

#

and the more networking activity is going on, I suspect the smaller the steps between the fastest updating groups and the more delayed groups is going to be

#

Also note that this behavior can be pretty inconsistent

fallow mountain
#

interesting, then Menu 4 could be just avatar... does it affect objects they own? wondering if objects are grouped similarly (distant objects can't serialize as frequently? or send events frequently?) (what about distant player owned object that is in front of you?)

north thistle
#

They seem to be grouped by a combination of distance and if their mesh is being rendered by your headset and/or camera

#

"Udon's networking prioritizes synchronized game objects that are currently visible to the local user.

Udon periodically checks the visibility of all mesh renderer children of synchronized objects. This is used in the quality of service behaviour of Udon's network load balancing."

#

Actually thinking about it, will a player camera trigger a mesh as being visible? It seems like it should.

fallow mountain
#

so it is periodically checked for distance and visibility...
I guess vrchat would use Renderer.isVisible for visibility checks because that is the most straightforward method, if that is the case, Unity docs would suggest yes, any camera should work.
Which also explains why visibility check is not done on player avatars because they are never culled, so they are always "rendered" I suspect

cedar flume
#

how bad is it if I exceed the synch limit? like using 400 bytes instead of 200?
Or should I utilize manual synch at 10Hz instead?
the manual synch is from serialization?

fallow mountain
#

400 bytes instead of 200 bytes? Neither should exceed the limit... how frequent are you syncing? What matters mostly is the Bps of your objects (for serializations)
How often you want to sync depends on what you use it for, if it doesn't need to be synced often (like game mode selection) then you only sync it once every few minutes

#

(Or as frequent as it needs to be, maybe it only needs to be synced once)

#

And which limit you are talking about? The frequency limit (~10 Hz)? The self imposed Bps limit before raising Delay? The hardcoded Bps limit before throttling?

cedar flume
#

the hardcoded limit, I am wanting to synchronize float arrays.
Ima just say that there will be three arrays of 17 floats, and an additional array of possibly 10 floats...

#

I plan on synchronizing this to have essentially a dmx show run off of an in world controller and be synchronized to everyone in the instance, so it would need to be synched fairly often, but it isnt the raw outputs, it will be processed a bit. this is just the part of the system that has the least amounts of variables

#

so.. perhaps at 20Hz?

#

not sure how much I can do before it would start throttling in an instance of 80 players

minor gale
fallow mountain
#

what are those floats for? positions? if it is something transient like positions, yes, use continuous, so vrchat can manage it internally

cedar flume
#

even if the fixtures have their own smoothing applied sometime after the networking? i.e. the network variables goes through some stuff, gets applied to a texture via shader, which is then read by VRSL, which moves the fixtures with its own smoothing?

fallow mountain
#

if you sync with continuous mode, you can even select if it is interpolated like

    [UdonSynced]
    public bool synchronizedBoolean;

    [UdonSynced(UdonSyncMode.Linear)]
    // This float will be linearly interpolated
    public float synchronizedFloat;

https://udonsharp.docs.vrchat.com/udonsharp/
which can be None Linear Smooth

in your case it will be None because the numbers (representing textures) cannot be interpolated
but why you syncing at 20 Hz? you want each image to play an animation?

cedar flume
#

i see....
well.. yea an animation, the texture it will apply to is essentially an artnet gridnode

fallow mountain
#

I don't know what that is, but it does sound transient, so continuous is the way to go
I just dont know if you want to interpolate between your floats or keep them distinct numbers
Because I dont know what they are fo

#

for*

cedar flume
# fallow mountain I don't know what that is, but it does sound transient, so continuous is the way...

ok, so...
the variables are set up like this in each of the arrays.
RGB hue
RGB distance (the circular type)
dimmer (intensity of the light)
strobe
pan
tilt (pan/tilt is the movement angles)
Cone angle (width of the light beams)
smoothing (for VRSL's internal smoothing)
GOBO speed (rotation of the light pattern)
GOBO select (rotation pattern selection)
RGBAS delay
RGBAS delay power
RGBAS delay offset
pan/tilt delay
pan/tilt delay power
pan/tilt delay offset

Probably... too many variables. these are all floats
One of these could control 16 13CH fixtures, and the delay will affect how they respond.
VRSL will handle the smoothing, so interpolation is not really needed

#

these are the output values from a controller signal generator in world.. though I feel like I should synchronize the controller inputs at a much lower frequency, though it would likely be more variables

fallow mountain
#

And regarding player count, even if there are 80 players, if it is just one DJ (?) sending out the data, you can treat as if there is only one BUT, the question is, what sort of data output do you expect to see from other people in a typical situation, and what other the DJ maybe sending, because that also affects how much bandwidth you want to allocate globally, and between scripts

#

How... dynamic or responsive do you need them to be? Can they just be updated every half a second? and let your smoothing do the magic?

cedar flume
#

they need to be responsive... though I feel that some parts, especially the delay, doesnt need to be updated as much, like twice a second...
Should I split this array up into smaller arrays by how much they need to be updated?

#

also, is the 11kb/s limit globally for the entire instance?

foggy jackal
#

are you trying to recreate VRSL?

cedar flume
#

effectivley, I am trying to recreate a VRSL gridnode video input, where this system could replace the video stream input with a in-world generated gridnode texture input

foggy jackal
#

ah, neat

cedar flume
foggy jackal
#

not sure why you are asking me?

cedar flume
#

hm.. not sure, was wondering if you knew, as the vrchat udon networking page doesnt really specify

foggy jackal
#

there's a lot it doesn't specify

fallow mountain
#

11 KB/s is per client outputing serializations

#

but really it is more like 8.5 ... 9 KB/s

cedar flume
# fallow mountain 11 KB/s is per client outputing serializations

outputting? its for putting stuff into the networked?
So the values I have in my case would be outputted from one client at maybe 7 kB/s, then the other clients get the values on deserialization?
So if I were to output pan/tilt at 10Hz, this is for serializing at 10Hz, not deserialization?

#

so therefore, since the input of the controller has several values that change only occasionally, I can serialize on value changed? unless im thinking of it wrong?

fallow mountain
#

You can think of serialization as sending, and deserialization is receiving
If you serialize (the sender), you don't deserialize, only other people (who are receivers) deserialize
If your values only change occasionally, you can just send (serialize) when they are changed, yes
But for any object, if you serialize, you send all of the synced variables on that object at the same time, regardless of whether any or all or only some of them are new values

north thistle
#

successful test of 280 independent, synced AI nav mesh agents across 8 players:

finite sierra
cedar flume
#

With my script, it would be one person sending the maximum, or it being spread over a few people if multiple were on the controller, though I decided to go with networking the controller input variables on value changed as those would need to be networked anyways for the sliders and toggles

fallow mountain
#

one object can only be synced by the owner (one player)... so it depends what do you mean by multiple people on it

#

you mean at the same time, or rotating out after a while?

#

one by one?

north thistle
finite sierra
#

ngl VRCObjectSync might not even be necessory. you could prob do it manually and get away with less data use

fallow mountain
#

yeah if the ai paths are predictable, you really just need to send like the starting point and target point, and let remote clients figure out the entire movement sequence

north thistle
#

the ai paths are not predictable

fallow mountain
#

if the ais are predictable, you dont need to sync anything other than the conditions the ai is based on really
oh ok
btw how does it look like on Menu 6? are your NPCs in groups with different delay times?

north thistle
#

I'm going to assume so

fallow mountain
#

and does continuous sync generate traffic if the npc is not moving?

north thistle
#

iirc VRCObjectSync update rate is partly impacted by how fast the object is moving; and VRCObjectSync will sleep itself after a period of inactivity

finite sierra
#

i mean you can do predict alot. and do alot of calculations based of different values. cause otherwise the price in data is gonna be roughly 48-60 bytes per second per AI which is Alot lol

cedar flume
tulip sphinx
#

one object with udon script(s) on it. if scripts are on different objects, theyd have different network ids and can have different owners.

cedar flume
#

ah, yea there will be multiple objects then...
is it simpler to make networked buttons/sliders in udon graph or U#?

#

I did try to make a networked button/slider in a previous world, but it just.. didnt work

fallow mountain
#

personal reference really
i learnt graph first because i cant code
which later gave me the needed concepts to learn coding in u#... but really personal preference
graph is "easier to read" for non coders i guess

warped latch
#

Silly question, if you have VRCObjectSync on an object, can you have a second script set to manual sync, or would it want to be continuous?

cedar flume
#

hm.. I plan on coding it in U#

strange token
#

I have networked buttons and sliders in U# atm but I can’t compare it to graph for ya @-@

#

I even have an object that updates its position to the slider handle pos when the value is updated so it looks like you’re grabbing a physical slider instead of the flat UI one lol

cedar flume
#

that is interesting, though im fine with flat ui, as the controller will be like a touchscreen

twin portal
#

the logic will be the same

cedar flume
#

i see, though.. to call networked variables in my U# scripts to use them, how should I do that? cant seem to figure that out

twin portal
#

you mean, the networked events with parameters?

twin portal
# cedar flume i see, though.. to call networked variables in my U# scripts to use them, how sh...

there's 2 ways to do it in U#, this section details an example (have to switch the tab to the "UdonSharp" example)
https://creators.vrchat.com/worlds/udon/networking/events/#sending-events-with-parameters

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

#

your function needs to have parameters, and then you need to give it the [NetworkCallable] attribute

cedar flume
#

I see....
looking at it, I must not have more than 8 callable parameters per event? so if I have an array of 11 floats, I should split it into two so it can be sent in two events?
Although, looking at it, it would be unlikely to have more than 4 parameters per event if I set it up right...

twin portal
#

an array is 1 parameter

#

if you pass in the array itself, that is

cedar flume
#

ah..

north thistle
# frozen igloo I shall once again link the sacred texts Events vs State: https://www.youtube.c...

Just watched those videos last night and the "I Shot You First" video is really good. Having time to think about it and my own project, I could fully switch over to this kind of architecture in my own game but there is one VRC limitation that currently makes it impractical and another more open ended question that gives me pause:

  1. There is no ability to tell VRC that you want a remote player to have the fastest possible position update rate regardless of visibility and distance. (At least as far as I know. If there is a way please tell me!) My project has monsters that can spot and then chase and attack a player. Because a remote player's position could be delayed by over a second, keeping ownership the same could result in the monster damaging the remote player while on the remote player's end they are clearly out of range of the monster. Instead the current solution is to reassign ownership of the monster to the player being chased, with all the complexities and pitfalls of that approach.

The ability to get short delay information on that player's location would hopefully make ownership transfer unnecessary and would probably be the #1 biggest improvement to my game's networking.

  1. The chart towards the end of the video is a little confusing but it appears that they were able to accomplish their architecture with only a 31.25KB/s upload on the host side. 31.25KB/s is greater than 18KB/s, but not by that much. I can already imagine all the host-sided optimizations of what data gets sent out, but even then it is a struggle to imagine accomplishing anything remotely similar even if we had an equivalent upload limit. Maybe the way VRC handles networking is too general purpose and inefficient compared to the specialized approach in Reach? Or maybe I could accomplish way more than I realize.

I'd love to give it a try, but again the big limitation mentioned above makes that a moot point. A distributed approach is a necessity.

tulip sphinx
warped latch
#

@tulip sphinx Is it the same deal with stations? I noticed that the example chair has the interact script set to continuous

tulip sphinx
#

@warped latch uh, does it even has any synced vars? im not sure but Continuous is just a default state when you create new behaviour

warped latch
#

Ah, cool (I have like 600 stations, I really don't need the network load)

minor gale
# north thistle Just watched those videos last night and the "I Shot You First" video is really ...

just to add some context, reach's multiplayer he discusses involves mostly discrete states. their own game does not use this same network model for the pve mode with ai involved. a lot of his discussion is around tooling and how they handle state which isn't applicable in vrchat (specifically semi-reliability of data, while this is kinda similar to eventual consistency, this lower level of control isn't available in vrc)

the most applicable portion is his mentions of the client netcode, but it's not a focus of the talk (showcasing how they originally approached grenades and what they ended up doing to minimize perceived latency)

that isn't especially applicable in vrc as it'd be odd to run that through the master (their concern is more on cheating, which they mostly prevent by validating things through the host instead of allowing clients to push their own changes)

in vrc it's difficult to make meaningful prioritization in the same way, data must be serialized if you anticipate the host dropping or ownership changing hands; this differs from reach where the host is managing the server end effectively (deciding what data is relevant to who and how important it is)

the comparison of data isn't 1 to 1 because in vrc you're only sending the data out one way, you're not handling it to all clients; the amount of upload just isn't directly equivalent

north thistle
#

I've tried it before. It was surprise, semi-invisible issue after surprise, semi-invisible issue.

strange token
#

I’ve done all this except the smoothing which I plan to do soon

#

Players update the pos/rot synced values much faster than their actual movement

#

But you would get slightly desynced animations since that would still come from the normal vrc response

#

You may be able to solve the delayed animation problem by just rebuilding the walk animation on the controller on the station but that is probably too complex for me 😅

heavy spindle
#

This is giving me ideas which is horrible for my sleep schedule

north thistle
warped latch
#

I love reading every idea that can be described as "VRC doesn't support this/do it well, let me use VRC to simulate the right behaviour"

north thistle
#

For this host-sided logic, I'm more worried about the host having accurate hard data about the player's current position than it being visually up-to-date

strange token
#

Well then yea why not just serialize pos/rot for each player?

north thistle
#

Having a monster swing at thin air and hitting some other person clearly out of range is way less of an issue than a monster in the distance swinging and you being the one getting hit

minor gale
#

i think in vrc it's most fair to run that hit detection on the receiver unless you have a small amount where you can keep the picture relatively in sync (with smaller intervals between updates)

ownership also can't change hands on playerobjects so dynamically trying to hand off the units isn't really a thing you can do

north thistle
minor gale
#

i think that's more fair to the player than running it on the host at a low update rate unfortunately, i don't think either way is great

north thistle
#

that's why my current method involves a distributed approach

#

this is also how I can get 280 networked agents in a single world at 8 players

#

(although the need to pass around ownership in real time lowers the practical number to something closer to 200)

heavy spindle
#

An idea kinda popped into my mind wherein the master can determine the rough location of an Ai and occasionally sync transform and possibly goals of the Ai and then once within a specific range, the syncing can "detach" for a set period not necessarily transfer ownership though this would require your own interpolation code unless you have control over the goals and can mask the delay between sync steps with local code

minor gale
#

i think that's valid, but i would say imagine that a player running an ai is lagging and stops seeing position updates from others; they could have an ai send multiple hits to a player during that time

alternatively, imagine the targeted player is lagging, they've now lagged and during that time were hit multiple times despite being nowhere near units on their end

i think the latter is acceptable, but you have multiple players you're relying on in a distributed approach, with a single host you only have one; though i'm not against a distributed approach and i think it's probably the most valid way to run them in realtime

north thistle
#

well to clarify, my approach is using receiver-sided hit detection with one important caveat: if a monster is chasing someone, the chased player needs to be the owner of the monster

minor gale
#

transferring ownership to the targeted player introduces complexity and at worst one player is running every unit, but if you can make that work it's probably more fair

north thistle
#

yah, and why I'd like more accurate player positions so remote-sided hit detection can actually feel good. Sure lag spikes can cause issue, but if a player is having a good time and then a lag spike kills them, they'll likely be more angry at their internet than the game.

fallow mountain
#

The thing is, vrchat uses a delay to act as a smoothing period for remote player movements, which is at least ~350 ms or more and can vary unpredictably (the Final D on Menu 4), so you are always viewing the player with a very uncontrollable latency... so ideally ALL hit detection (or any quick paced gameplay really) should be local to the player
So yea setting the chased player as owner seems the best strategy, no worries of latency and position accuracy

#

In PvE game it is a bit easier to run things locally, but in PvP games you gotta design away the problem, make it so latency matters less

north thistle
frozen igloo
#

What you're looking at is simulationTime. It is a timer which runs slightly behind to allow synced data to have time to arrive. It automatically adjusts up and down depending on network conditions and other factors, and is exposed as a getter for both players and objects

north thistle
#

Actually I'm curious if FinalDelay actually represents the time between when the sender sent the data and the receiver received it; the description is kind of vague.

I can think of a way to test this.

fallow mountain
#

btw what is difference of "Linear" and "Smooth" interpolation in UdonSyncMode?

#

and how are they applied exactly? smooth between missing information? smooth towards new information?

#

(is there a world that demos this perhaps?)

frozen igloo
twin portal
fallow mountain
#

is it smoothstep or smoothdamp? if you know

north thistle
#

so looks like FinalDelay does not at all represent how long it took for the data to get to you:

minor gale
#

finaldelay is likely the sim time offset, sim time requires you to do some math operation to get the resulting delay, finaldelay doesn't; if you want to align a lerp with ik you could use finaldelay directly as the interval from what i saw

north thistle
#

On the plus side, it looks like you can actually get some reasonably fast updates on a remote player's true position

#

And from what @strange token said, you have some ability to override a remote player's visual representation. That means you could design a visual representation of players in your world that works better for pvp than VRC out of the box

minor gale
#

if you use stations and advertise their position at some faster rate you could, but it's not great on bandwidth

#

that rate is already 10hz for a vr player that's near you i'm pretty sure

#

for desktop players it's more like 4hz

north thistle
#

<70ms seems workable for a pvp game though, does it not?

fallow mountain
#

70 ms? sync a player object as target?

north thistle
#

I'm doing a more proper test right now

fallow mountain
#

i wonder if using network events with parameters to sync will bypass all the background delays

north thistle
#

Unfortunately using manual sync, the delay balloons at higher player counts; like 200-350ms

fallow mountain
#

in udon

north thistle
#

you'll send to add extra code to make sure you don't oversend events during periods of network instability, however

fallow mountain
#

How is your timeToArrive calculated? using server time difference?

north thistle
#

yep

#
    [NetworkCallable]
    public void GetPositionSync(Vector3 position, double SendTime)
    {
        syncedPosition = position;
        timeToArrive = (float)(Networking.CalculateServerDeltaTime(Networking.GetServerTimeInSeconds(), SendTime));
    }
fallow mountain
#

so 6x ms difference... seems to be slightly more than your previous screenshot?
was your FinalDelay just SimulationTime?

north thistle
#

maybe; didn't look into it that deeply; was more interested in seeing actual latency

fallow mountain
#

and how is your ping? just wondering if the 6x ms is approximately the (RTT of the sender + receiver) / 2

north thistle
#

~42

#

also note that events will occasionally come in late under heavier network load

fallow mountain
#

Maybe you can try to check if Suffering is 0 before sending the event, to make sure it don't add to queue (by dropping the event)
Or NetworkCalling.GetAllQueuedEvents is 0

north thistle
#

On a side note, would it be possible for VRC to give us the ability to mark our behaviors with different sync priorities?

fallow mountain
#

not that i am aware

north thistle
#

Because manual sync is structurally a way better way to handle this position sync, but the lack of priority control has me wanting to use events instead to force high priority

twilit pewter
#

Got a couple of canny posts that may interest any other security minded folks, working within the limits of what VRChat provides:

https://feedback.vrchat.com/feature-requests/p/modifiable-queue-for-defaulting-network-ownership-when-players-leave-or-add-a-sy
Got another alternative since I brought up making a Well Sync System:
https://feedback.vrchat.com/feature-requests/p/allow-disabling-of-the-initial-sync-for-joining-players-with-manual-sync-scripts

PlayerObjects are amazing. They allow everyone to sync data without worrying about Network Ownership being an unpredictable variable.

Allowing the initial synchronization to not happen for joining players with Manual Sync scripts would give us the capability to assemble our own Wells for

pulsar panther
#

Does anyone know how to get the value of a tag set on a player

twin portal
pulsar panther
#

Yes but how do I check the tag value

twin portal
#

with.... GetPlayerTag, it returns a string for the value

#

oh wait they don't really have a value

#

they either exist or they don't

#

or am I misremembering... have to look at it

pulsar panther
#

This is what I have but I have no way to compare it on a toggle

twin portal
#

you still don't have GetPlayerTag yet

pulsar panther
#

I was thinking this

#

But I want to get it from a set source not master

twin portal
#

a set source? what do you mean by that?

pulsar panther
#

As in when the local player has this tag do thing

heavy spindle
#

You can use Networking.LocalPlayer as a ref to the local player

#

Though you should also cache the value of LocalPlayer as it's an extern

twin portal
#

give me a sec I can figure out what you're trying to do

#

I believe the output string will be null if they don't have the tag, so you can check for that

pulsar panther
#

It’s effectively an admin only button using tags

twin portal
#

alright so if a tag isn't set, GetPlayerTag will return null or the empty string

pulsar panther
#

ok and if it is set

twin portal
#

if you use the node String > IsNullOrEmpty, it'll be true or false depending on if the tag has a value or not

#

if it is set, string will be the value of the tag that you had set previously

pulsar panther
#

ok

#

I just havent used strings before so thank you

twin portal
#

do note that these tags are not synced, they're local-only

#

and are generally considered kind of outdated

#

but sometimes have interesting uses

pulsar panther
#

I thought they just updated them?

twin portal
#

tags? no

#

latest update was custom events with parameters

pulsar panther
#

ah

#

Well if I check tags then set owner then serialize it should be fine

north thistle
#

Are player tags really not synched?

#

Really a system for a different time

twin portal
#

no, you have to network the tag-setting to everyone manually

#

which is probably a lot easier to do now thanks to the network events with parameters

north thistle
#

Oh while I'm thinking of it, "NetworkCalling.CallingPlayer" can be used as an extra security feature for your open, network-callable events. You can use it to check if the network event call is coming from who it should be.

twin portal
#

smart, didn't think of using it in that way

north thistle
#

I've transitioned my world to a system with no "live" ownership transfers and the lag of a remote owned monster hitting you doesn't seem at all bad

\0/

Thanks for the suggestion @strange token

strange token
#

Glad I could help! 🫡

fallow mountain
#

does GetNetworkDateTime() return the actual date and time (which timezone?) or is it just an elapsed timer converted from GetServerTimeInSeconds()?

rare cloak
#

I'm having a lot of trouble trying to make this little flashlight gimmick.

Trying to make it so desktop players have a flashlight that is just attached to their heads and VR players have a flashlight that uses VRCPickup (this part works fine)
Trying to get it to sync properly is my biggest issue atm because of the way I want the players to unlock the flashlight (I think)

I'm trying to make it look like you unlock the flashlight from an interactable "flashlight" object you find on the ground. Nothing is syncing, and I've broken it so now only the first person to click it gets anything then nobody else can interact with it

#

I can show everything if someone is willing to help, just don't wanna clutter more than I am

fallow mountain
#

or is it a "give me a flashlight" button, and it gives a flashlight to anyone who pressed it

#

so you are giving multiple flashlights to multiple people?

rare cloak
#

So they're supposed to get their specific flashlight when they press it

fallow mountain
#

ok PlayerObject yes
VR players, you want it to be Object Sync, but nonVR players, you disable Object Sync and VRCPickup and just attach to the players head (no need networking)

#

The "unlock" interactable should just be responsible for enabling the PlayerObject owned by that player

rare cloak
#

Yeah, the issue is mostly just networking the light so other players can see it, and then networking the actual flashlight model with just VRCPickup/ObjectSync so that everyone can interact and see that for VR users.

I think just typing it out kinda helped? I have the flashlight game object disabled and then am enabling it and moving it into position when the player clicks the unlock, but the enable isn't networked. So that could be it?

Does VRCPlayerObject or ObjectSync track enabled/disabled states?

rare cloak
twin portal
#

I think you've got the concept of what you need to do down honestly

#

Just needs ironing out the kinks

#

You could set up synced bools for if the flashlight is unlocked, what mode the player is, switch things around based on that

#

With PlayerObjects makes things easier, as the Owner is always the player the flashlight belongs to

fallow mountain
#

on the pickups, you might need to disable pickup for non-owners

#

(not sure if it is automatic)

rare cloak
#

Is SendCustomNetworkEvent viable for enabling it or is it better to just use a synced bool?

twin portal
#

it almost is, but without a synced bool, it becomes much more difficult to sync it for late joiners

rare cloak
#

currently on interact with the spawner if you're on desktop, I'm disabling the meshrenderer, box collider, and the pickup script. So need to create synced bools for each of these?

#

and the flashlight itself

fallow mountain
#

You can use event, and let the PlayerObject themselves handle turning on (and sync a bool e.g. IsUnlocked), maybe they are all enabled (gameobject) and only the components are turned off in the beginning
This way you dont need to make an array to remember the bools and sync it seperately

twin portal
rare cloak
#

true just one named something like "flashlightDesktop" or something that does all 3 lol

twin portal
#

exactly

#

I'd probably do one set of states for the flashlight locked vs. unlocked, and another set for desktop player vs. VR player