#udon-networking

1 messages · Page 19 of 1

finite sierra
#

and who would be the one that syncs it all?

cold laurel
#

That depends on a lot of factors.
For example a vr player holding a pickup with continuous sync will bump its rate up to like 10 per second afaik.

timber parcel
finite sierra
#

you diff can but then you need to keep track of who does what etc

#

the Hz thing sesems to not really matter lol. even when you do a few syncs per so often at 20-30 bytes it goes to 0 lol

timber parcel
#

Hmm, if we design the game in such a way that there is about 40 enemies per player, each player is sending 10 vectors a second.

We could have 4 vs 160 with each individual enemy getting updated once every 4 seconds and simulated between.

That's definitely feel like a epic battle.

Working out how to efficiently simulate all of those would be a separate also hard issue

fallow mountain
#

it is not practical for vrchat to sync hundreds of enemies individually as you quickly run into bandwidth limit, but you can however design the game to be much more deteministic (e.g. spawn enemies waves being a single event and have enemies behave with a predictable pattern), or, make it less important to have two players see the same thing (e.g. make enemy count so massive it does not matter if individual enemies are in the same place or even with the same health count). Like vacuum cleaner simulator which is largely a single player experience, and the "co-op" happens at a more macroscopic scale rather than individual particle enemies.

finite sierra
#

not to mention you have to set ownership of them all which also requires abit of wait

timber parcel
fallow mountain
#

What you can do is combine Vacuum Cleaner Simulator, with individual boss monsters that you need multiple people to kill, that will give you the full experience

timber parcel
finite sierra
#

eh. Udon is just not made for it. it can be done but the real problem comes to when you need to detect who hits what etc

#

and you then need to decide on how things sync

timber parcel
finite sierra
#

and to you give to an idea. of it i have a world with roughly 50-64 people using it now and then. at 64 people it runs into a wall for data output and it slows down sync a crap ton.

#

even through in my world every person only syncs 20 bytes every 30 + seconds.

#

and if u take the total amount of request being done its only at worst 128 request per 30 seconds. but that's a unreasonable amount since they can only take an action if u will every 30 seconds

#

and not everyone does it at the same time

timber parcel
#

I mean, that's a separate issue. We players send a lot of data. I wouldn't run a game with a hundred enemies without limiting it to like 4 players

fallow mountain
#

What player hit can also be locally determined (not precisely) using where the player is looking at. But remote player look direction is very sluggish and only updates about every half a second. But you can design the game around it.

timber parcel
#

Lots of options.

#

None perfect

finite sierra
#

best call is to try and see how udon fairs if u have a constant Manual going off with say 100 bytes in each.. and have 4 people join you

cold laurel
#

One big request rarely is preferred over smaller requests more often.
This is because you incur the header cost on each request.

finite sierra
#

well

#

not really possible when all the data you have is small 😄

#

build in delays and other things so people cant repeat the same actions for gameplay reasons

#

buuut yea. that 12 byte overhead for just having something sync is on the higher end

cold laurel
finite sierra
#

2880 bytes per 30 seconds at worst in my world. at 80 people. but eh. it diff is ALOT higher then that. with 50 people i would often sit around 10-11 kb /s without doing anything. that said thats with face tracking and fbt and talking.

#

without that it would sit around 8 kb/s again 50 some players.

#

which i still find odd that the amount goes up so much with each player joining

#

and that is Data Going Out from my side.

#

which also concerns me because we never really got a clear answer as to if more players in world increases data out per person. because that seems to be what is going on.

cerulean zealot
fallow mountain
#
  • VRChat network specs page says udon scripts can send 11 kB/s (KB/s?), is this per script or per object or per client?
  • The Time Estimation tab on the sheet, is it a duration of sending, or duration waiting before send, or a roundtrip time? Is the time in seconds?
  • What happens if network is clogged, is the queue still going to send? Or is the queue abandoned? (I assume you cannot add to the queue anymore, but what happens to the stuff already in the queue?)
  • I assume manual sync means only sending once, what if I update the variable before it is serialized, does the old data get overwritten, or will it add to data size?
  • Continuous sync how often does it happen? Does it only send data when variable is changed, or is it always sending at a certain frequency?
#
  • Is continuous sync "limited to roughly 200 bytes per serialization" per object, or per script? or per client?
#

Or per variable?

#

(If my player stands still, therefore no new vector3 player position, does it "save bandwidth" for other scripts?)

#

Thanks

#
  • In the estimator, on the Time Estimation tab, why is there five different times for 64 Byte? (~0.11 to ~0.18 s?)... and why is it going up and down?
fossil kite
#

what's the motivation for reusing a single VRCImageDownloader to download multiple VRCImageDownloads, rather than just making one downloader for each?

frozen igloo
# fallow mountain - VRChat network specs page says udon scripts can send 11 kB/s (KB/s?), is this ...
  • outbound 11kB/S is per-client. Also that number is very rough and depends on a lot of factors, in most cases it's "up to" that speed but realistically lower
  • Time estimation is duration after sending, there is no roundtrip. I don't know the exact measurement used for that though
  • If network is clogged, variable sync will never be thrown away. It'll take some time to work through large messages, but small messages can slip through without too much delay.
  • When you requestserialization, it takes a fraction of a second before the network tick comes around and packages up your data. If you make changes before that happens, they will be reflected in the sent variables. When this happens, you'll get the OnPreserialization event which is the last chance you have to make tweaks before sending. After that, you'll get OnPostSerialization which tells you information about how it went.
  • Continuous sync repeats whether or not the data has changed. Under normal conditions, it's about 5 times per second, but while clogged will slow down.
frozen igloo
silver hill
#

So Im starting to learn how Object pools work, I assumed a setup like this would work but it causes a null reference exception.

The context is that the udon is part of a spider which when triggered, will "spawn" a web trap that lies on the floor for the player to avoid/shoot so the idea is to On command, take a web trap asset out of an object pool and the resulting game object is to copy the location of "SELFgameobject" (The spider) Can I get some guidance on this?

fallow mountain
#

maybe your pool doesn't have available object, so it is null

silver hill
#

To be fair I only put in the first 10 of 100 objects I plan to have in there but I assumed it would attempt to grab object 0 first then 1, onwards?

twin portal
#

if you attempt to TryToSpawn, but there isn't an object available, then the function will return null

#

so you'll need to add a check for null there

silver hill
#

So every slot has to be filled in? uhhh what a chore :L

#

I just wanted to test before commiting lol

twin portal
#

ah if only there was some sort of way to add many objects at once into an array....

#

sadly you cannot add multiple objects at once into an array of a graph script, only works in U#

twin portal
# silver hill

you can lower the pool size if you really wanted to test first

silver hill
#

Yeah just done that, Imma test now

#

Ah it works as intended

#

So I assume the object pool will always attempt to grab the highest item in the list?

#

if it for example was returned?

twin portal
#

not sure, based on the docs the order does not seem to be guaranteed

#

maybe only if you're spawning, but if you also return things to the pool it might change the order that it spawns objects in

fallow mountain
#

i guess it grabs the first object that is inactive

silver hill
#

Im testing now, it grabs the next one in line, regardless if an earlier object in the pool was returned

#

wondering what happens when it reaches end of the line, lets see...

#

Ah, it cycles

#

goes back to the top once it gets to the botto,m

twin portal
#

makes sense

silver hill
#

Welp, from everything Ive experimented and learned, I think this game might become a reality, I just hope people will actually play it :L

fallow mountain
#

interesting, why would it cycle through the list, rather than starting from the top?

wooden saddle
#

any one know how use VRC Enable persistence i cant fined any videos or AI help

twin portal
wooden saddle
#

@twin portal but is is always enbled or i need turn it on some how ?

twin portal
#

you'd need to write a script that would use persistence, or use a PlayerObject with persistence enabled

wooden saddle
#

so AI wrong then

#
  1. Setting up Persistence:

In your Unity project, go to VRChat SDK -> Show Control Panel -> Builder.

Select your world scene.

In the VRC World component (on your world descriptor GameObject), find the Player Persistence section.

Check the Enabled box. This grants your world permission to use the persistence API.

twin portal
#

of course it is. It's AI.

#

don't trust any AI answer regarding VRChat development

wooden saddle
#

looks like the did not train AI much on Vrchat systems

#

@twin portal good to know thanks

meager crystal
#

Is it possible to make it so that the more players that join the world the more cars will spawn into this parking lot? I'm trying to make it seem like the players are visiting this business in a more immersive way. and if it is possible, how would I do this?

woven pebble
meager crystal
#

maybe instead of spawning an object, it instead toggles objects on and off?

woven pebble
#

PlayerObject
It was called.

woven pebble
woven pebble
meager crystal
#

well, it'd have them placed in the correct spots and orientation

twin portal
fallow mountain
#

VRC PlayerObject automatically spawns (a copy) when someone joins, it's meant for situations like this, when you want to give out copies of an object to each player

#

You can simply have an onEnable-->move to an unused parking space

fallow mountain
#
  • You have have an empty gameobject to be a ParkingSpaceManager for managing parking spaces, and have the PlayerObject talk to it.
  • Setup variables:
    • In your PlayerCar, make a variable: parkingSpot[] (Transform array, public, where you store a list of empty gameobjects for each parking spot)
    • And then make a variable in ParkingSpaceManager (synced): parkingSpotOccupiedBy[] (playerAPI array, default null, when someone takes the spot, store their playerAPI)
  • When a car spawns, have it choose a spot and ask the ParkingSpaceManager if parkingSpotOccupiedBy[123] is null (not taken), if so, the car can move to the parkingSpot[123]
  • When someone leaves, their spot inparkingSpotOccupiedBy[] should become null (idk if it does this automatically, you can test) and becomes available for a new car
#
  • When a car wants a spot from ParkingSpaceManager, you set local player to be owner ParkingSpaceManager, update the parkingSpotOccupiedBy[123] to be local player, then request serialization to sync it to other people and late joiners
    • Do this with a custom event inside ParkingSpaceManager, call it TakeASpot or something, make it do the spot choosing logic, record a non-synced integer variable called localPlayerSpotIndex, and update and sync as mentioned
    • PlayerCar can then read the integer from localPlayerSpotIndex and set transform to parkingSpot[12345]
woven pebble
sick gull
#

Yeah PlayerObjects overcomplicate it if the ONLY goal is for a car to show.

#

If you wanna add anything ontop of it like...

  • Custom license plates
  • Custom cars/colors

PlayerObjects would work better

twin portal
#

I suggested that method over PlayerObjects bc you've already got all of the cars placed nicely... PlayerObjects always spawn the new object at the exact spot the original is, so your script would have to also manage placing the car. In most ways you'd kinda have to redo the work of placing all the cars, so simply hiding/unhiding lets you use the work you've already done
Even if you wanted custom stuff for the cars, it'd be easier to save data into PlayerData instead, and simply load the info onto the already-placed cars

fallow mountain
#

Oh yeah if it is only "show more cars based on players count" then you don't need PlayerObject, it can be done locally turning objects on and off as suggested, no networking required.
I assumed it is drivable cars each player can drive away/customize hence the PlayerObject suggestion, but you don't need it if it is just background decoration.

meager crystal
foggy jackal
#

what part of that are you stuck on?

sick gull
#

Add a script to your parent that holds all the cars

#

and have that script toggle X cars on when a user joins

meager crystal
#

like I said, I have never touched the graph

#

I always use CyanTrigger as that makes things far less complicated

twin portal
#

believe it's in PlayerApi > GetPlayerCount

sick gull
meager crystal
#

yeah, I got no idea what I'm doing

fallow mountain
#

before doing anything, what do you want to do?

#

like in detail, what is logical steps you are doing

#

describe in plain english

#

what effect you are trying to achieve exactly

cerulean zealot
#

Whats the best way to destroy an object if a player leaves?
And does "OnDestroy" actually work?

#

this is in my instantiated object. PlayerOwner is stored at the start when it's instantiated.

fallow mountain
lone zealot
#

If however it is locally instantiated then you can just use GameObject.Destroy

cerulean zealot
#

this is for a locally instantiated object to add a random color. And a color sphere above the head of players. Then it uses the stored color to paint the color of any NPC that is owned by that player. Im trying to make a debug mode so, at a quick glance, I can see how my ownership system is handeling things.

lone zealot
#

Then you can just destroy the root gameobject with GameObject.Destroy and it will automatically destroy all children as well

cerulean zealot
#

oh ok.

#

didn't konw there were two different places

lone zealot
#

Networking.Destroy is an internal API as far as I know and should not be used

cerulean zealot
#

I do not see destroy under gameobject

lone zealot
#

Ahh my bad its under UnityEngine.Object.Destroy

cerulean zealot
#

found it. thanks

meager crystal
# fallow mountain what effect you are trying to achieve exactly

all the car objects are disabled by default. upon a new player joining, one additional car enables. total number of cars is 25 for all parking spots. once the player leaves, the car that enabled upon their join gets disabled. I wanna make it so that the players "drove" to the location for a slightly more immersive feel

fallow mountain
#

"drove"? u mean actual driving mechanics?

#

or just spawning next to a car

#

Since you want cars to be assigned to player, probably PlayerObject is easiest

#

So all you need is a script on the car to position itself once spawned, with a parking spot manager like mentioned before

twin portal
#

this was the simplest way I could think of doing it

#

every time someone joins or leaves, loop through an array of the objects you want to enable or disable. Whether or not the object is enabled or disabled is determined by player count

cerulean zealot
#

If I want to make a "network clogger" button for testing purposes. What would i do?

#

I want to purposely clog my network.

#

And can I have 1 client try to send too much data.

meager crystal
frozen igloo
cerulean zealot
#

@frozen igloo uh.... is there a "make garbage data" node?

#

or can i just send a massive array with random numbers in it?

twin portal
#

We've already got that, it's SendCustomNetworkEvent

heavy spindle
#

dont try to use a for loop to send all of them on the same tick. Your client may hit the 10 second max tick time then crash the script

finite sierra
frozen igloo
#

send it to some event that does nothing

silver hill
#

Having a slight issue working with the object pool system, trying to spawn some enemies that ive made using a debug tool, it works great but after the first frame of them spawning at the desired spawn location (Udon pictured) they teleport to somewhere else that isnt intended, very weird

silver hill
#

Seems the issue lies with the nav agent itself, it was teleporting itself to a part of the map which it deemed compatable so now forcing it to spawn where I want it to be causes it to error out even though there is a nav mesh for it to use...

#

Lol, managed to fix it myself by simply telling the nav mesh agent to warp to its own current position 😛

fallow mountain
#

is your spawnposition not on the nav mesh

silver hill
#

It is but it was treating it as invalid

#

I basically just told it to teleport, then when it checks its on a navmesh which it fails, it then tells itself to just teleport to itself again but using AI nav mesh and then it works

fallow mountain
#

is it close to the edge or something

silver hill
#

Nope, in the middle of the platform, clearly plenty of room

#

Anyways it works now

cerulean zealot
#

ok... so i may be dumb here... but if a player joins an instance with people already in the instance. Do that player get an OnPlayerJoined for everyone already in the instance?

#

so like... if someone joins a lobby full of 40 people. They get 40 OnPlayerJoined events plus their own onplayer joined making it 41?

twin portal
#

yes

When you join an instance, you execute OnPlayerJoined for every player in the instance, including yourself. When another player joins your instance, you only execute OnPlayerJoined for the player who joined.

foggy jackal
#

it's why some worlds spam you with those stupid notices about joins when you join

sick gull
#

You can stop that from happening w/ playerID. If < local players playerid, retur

#

At least I would imagine that's how you'd fix those spamming moment

fossil kite
#

what is the value returned by GetPlayerId()? is it universally tied to their account, or just an integer for the current room?

tulip sphinx
#

just increasing id

#

rejoin will set new id as well

fossil kite
#

do all the users in the room see a given player as having the same id?

tulip sphinx
#

yes

#

and id 1 owns all the scripts/objects by default, doesnt matter if hes instance master or anything

fossil kite
#

oh interesting....

#

but what if that player leaves

#

I assume the IDs don't change, so I guess it's just whoever has the lowest id?

tulip sphinx
#

then other player gets all his objects. but not always next one, questies/high ping people can be skipped in populated instance. so just dont try to predict it

fallow mountain
#

is it always starting from 1 and goes 2 3... ?

tulip sphinx
#

yes

warped latch
#

Does that mean there's no way to get a permanant reference to a particular player? Just store displayNme and hope for the best?

twin portal
#

pretty much

#

we don't have access to their account ID or anything

#

though players don't change name that often

warped latch
#

Gonna have to change my racing records format

twin portal
#

I have seen a strat to generate an ID yourself, then save that persistently

#

persistent data is another way to "save" a player

warped latch
#

I'm trying out sort of a client consolidated records things: each player saves race records when they're in the instance, and when they join or have someone else join, the records are combined and only the top 10 are retained

#

Which means you could be racing vs a player you don't know

#

I thought IDs were like, global IDs, not instance, so I just have to change to saving the displayName. That personalID idea is neat though

twin portal
#

nop. IDs are great at referencing specific players within one instance, but are only unique to that instance

fossil kite
#

is there any way to detect whether someone has untrusted URLs enabled?

#

I guess just firing off a request to an untrusted URL and seeing if it goes through, and hoping the problem doesn't happen to be on the server's end

twin portal
#

I think that's the best idea, the video player will return an error but I don't think there is one specifically for it being blocked due to being untrusted

fallow mountain
hearty vale
#

will vrchat persistence work with sync set to none

twin portal
#

yes

frozen igloo
# hearty vale will vrchat persistence work with sync set to none

If you mean per-variable interpolation mode, then none just means no interpolation, so it will work perfectly fine.

If you mean per-object sync mode, then it depends which type of persistence you're asking about.

PlayerObjects save data through networking associated with the object, so setting sync mode to none on a playerobject will disable persistence for that object as well.

However, playerdata is different - it's handled by an independent set of objects which are always available, and any script can interact with them. So setting sync mode none on some random script doesn't prevent playerdata from working, nor does it prevent that random script from interacting with playerdata

sick gull
#

So if I understand this correctly.
You can psuedo sync via playerdata...

#

Like it isn't ACTUALLY synced, it is just pulled and then repulls data whenever the PlayerData is updated (as long as you have it setup correctly)

frozen igloo
sick gull
#

I mean the sync mode on the object

#

I guess my phrasing is improper

frozen igloo
#

the syncing does not go through the object which is interacting with playerdata, playerdata does all its own syncing

sick gull
#

Yeah okok

#

PlayData -> Saved data that auto syncs without needing to tell everyone to request serialization

#

instead, you just do the dataupdated thingy and check if the player is the owner of the PlayerObject to update said variables

frozen igloo
#

yeah, it has it's own internal requestserialization that it takes care of automatically so you don't need to do it, but it still definitely operates off the same principles

sick gull
#

Yeah ok. Cool. Good to know 🙂

fossil kite
#

what is the order of events for a non-owner loading into a room and receiving synced udon variables? does the udon script not start executing until the synced values have already been received, or is there an event that I need to wait for before ever looking at a synced value for the first time (as a non-owner)?

#

I guess you just wait for the first OnDeserialization?

honest lance
#

it's what I'd do

#

order of events may change in a future update, even if by accident

twin portal
woven pebble
#

Hi.
I want to synchronize player objects.
I want them all to copy the position, rotation and velocity from the owner's version.
How do I do this?

fallow mountain
#

slap on a VRC Object Sync, it does it automatically

woven pebble
#

Nice.
Will that not interfere with my code that directly alters the velocity?

woven pebble
fallow mountain
#

it doesnt alter your velocity, it just tells other people what your velocity is

#

no adjustments

woven pebble
keen briar
#

Hello everyone!
Sorry if this question has already been asked a thousand times. I’ve been searching but couldn’t find the right keywords to get to a proper solution.

I’m working on a script for catching eggs in a VRChat world. The idea is to make it competitive and fully synchronized in real-time, so players are racing to collect the most eggs.

However, I’m running into a race condition when two players grab the same egg at the same time, both end up getting the points. To fix this, I modified the script so that points are only awarded after the player gains full ownership and deserialization is complete.

The issue now is that the egg doesn't get caught immediately after the ownership transfer. After some debugging, I found a strange behavior in Udon: when a user gains ownership of an object, the OnOwnershipTransferred event triggers for everyone except the new owner after the ownership has changed. But for the owner themselves, the event fires before they actually gain ownership, so the race condition still happens locally.

I’m not sure why it works like this, or how best to handle this properly. Has anyone found a reliable pattern or workaround for this kind of issue?

Thanks in advance for any help!

finite sierra
keen briar
#

so in that case my user never get owner of the object...
i did a simple:
public override void OnOwnershipTransferred(VRCPlayerApi player)
{
if (Networking.IsOwner(gameobject))
{
Debug.Log("is Owner");
}
}
the log is never triggered when i do a setOwnership. it sometimes get triggered on the old owner but never on the new
it match that picture i've seen on the vrchat wiki where it clearly show that th event is fired before the ownership is fully transfered. but right before,
so another ownership request can be processing in the same time...

#

i know i can do :
public override void OnOwnershipTransferred(VRCPlayerApi player)
{
if (player == Networking.LocalPlayer)
{
but it won't fix my issue that waym because he still not is trully the owner

twin portal
#

that chart is more for how the logic works to negotiate an ownership transfer (if needed, as by default there is no negotiation), and not so much for how to deal with simultaneous ownership requests

#

which is a difficult problem to have a solution for

fallow mountain
#

Maybe have them record the time of pickup using server time, and compare the two in events of double pickup

#

And if they happen to be at exactly the same server time (very unlikely) then, compare their latency (idk how) and pick the one with longer latency (the logic being, if playerA has lag and still click at the same server time as playerB, playerA probably clicked first in real time)

#

And if still the same, randomly pick one

keen briar
keen briar
twin portal
#

forgot to hit enter but was also going to second the idea of getting the server time and comparing, I believe you get it through Networking.GetServerTimeInSeconds() or GetServerTimeInMilliseconds()

#

but I'm not really sure how you'd compare one player's time to another

#

maybe something crazy even like a DataList, that stores the playerID, egg number, and timestamp they collected that egg?
then you just search through the list, and whoever has the lowest timestamp for a particular egg, then they're the one that gets the score for it

#

might get kinda too big to sync

#

oh I remember now my plan B, have a central script that only ever has one owner, then have clients send an event to the Owner whenever they collect an egg
whoever the Owner receives first, they get the credit

#

PlayerObjects could be used to store the timestamps for each player, then the Owner can loop through all PlayerObjects and check their values

#

there are many ways to cook an egg....

drowsy jackal
#

I have a general question, if you guys don't mind. I have a prefab game object that is a pickup item and has object sync script. I also have a script that generates the prefab game objects. Would the generated objects be synced with everybody? Is there a special way on how to do this?

twin portal
#

depends on how they are generated. If they are being instantiated, then ObjectSync will not function for the objects

#

if you have an ObjectPool of the objects and spawn them from the pool, then they can be networked

drowsy jackal
#

Yes, what I am working on now, the game objects are initialized when both players are ready and one of them would press start. The game object owner generates a random seed and then send that to all the other clients. Then the game clients generates the game objects with the see. But from what you said just now it sounds like that won't work.

finite sierra
#

that is to say this is determined by the current owner and only allows one to go through

#

and then once the new owner takes well ownership they do the same if another person needs to. take ownership

vapid pagoda
drowsy jackal
#

Is there a limit as to how many items in an array I can use? Getting the feeling this being caused by large arrays.

twin portal
#

believe you've just gone out of bounds of the array

frozen igloo
drowsy jackal
#

No wonder I as out of bounds

cerulean zealot
#

is there a timing issue with instantiated udon behaviours?

#

do i need to wait a frame?

frozen igloo
# cerulean zealot is there a timing issue with instantiated udon behaviours?

you can run functions on them before they've had their own start, so if you're relying on that to get components and stuff it might break. But there's nothing stopping them from running code immediately after, so what I usually do is implement an "Initialize" function which if needed, runs at the beginning of every function received from an external source

cerulean zealot
#

So.. like a custom event in them? @frozen igloo cause this is an issue that is popping up recently.

frozen igloo
#

I'm just spitballing what it might be based on what you said - if that doesn't cover it then you're gonna have to go into more detail on what you're experiencing

twin portal
#

Does Awake run during the same frame an object is instantiated? Maybe that would work?

#

Reading through this to try and guess

frozen igloo
#

Udon doesn't have Awake, unfortunately. It's definitely on our radar though

twin portal
#

Oh...didn't know that wasn't available. Guess I never tested it in-game

#

I think this paragraph implies that you could have issues depending on when an object is instantiated

obtuse echo
cerulean zealot
#

Tested last night. No yeeting to the error world?

open mist
cerulean zealot
#

is it safe to say that Ownership is handled by VRchat realtime server but calls to Ownership is client side?

#

like... does VRChat realtime server prevent two clients owning the same thing?

#

or is that a situation I need to be aware of in scaling?

twin portal
#

Phased might know more or be able to explain better, but from what I remember, ownership is technically handled client side. The info on who is owner of what is sent alongside synced network data, essentially going "this data you just got, this player is owner of it now, so use their data instead of what you currently have"
This can cause issues if two clients request ownership simultaneously; which one becomes owner, and who's data is used?
I haven't done extensive testing on it, but both client's ownership change and their data will eventually be received by the other players, but the order isn't guaranteed, so as one object fights for ownership, it could create unexpected states in the data, depending on the implementation

frozen igloo
# cerulean zealot is it safe to say that Ownership is handled by VRchat realtime server but calls ...

The server maintains the source of truth of who the owner is, but when you transfer ownership the client will briefly override that while the message is being sent to the server. In most cases, the server then comes back and either confirms the transfer or says "nah it's actually owned by somebody else" but in practice there are rare cases where that can break, particularly when a bunch of people are trying to take ownership at the same time. That said, if it's just as simple as 2 people at once usually that doesn't trigger it. In my testing I've only seen it with 4+ people

cerulean zealot
# frozen igloo The server maintains the source of truth of who the owner is, but when you trans...

Ok in my NPC system ownership transfers happen after serialization where current owner is like "I'm transferring ownership to ID n"

And player goes "I'm ID n set ownership to me!"

Everyone else is waiting for the next Serialization after OnOwnershipTransfer (or whatever that event is called) for continuing logic.

Yes, its kinda redundant and there is a slight pause in noc behaviour but it works REAALY well when animating NPC issues dynamic group behaviour.

After that checking ownership of the ownership module is the only gatekeeping from split brain syndrome.

strange token
#

Trying to work from OnDeserialization to try and learn other ways of networking, but is there a way for me to check the old value of a variable to see if I even want to run code based on its state? I usually use properties to trigger the changes I want, which automatically only run if there's a change to that variable, but here I don't have that

#

wait a dang second, actually I think I don't need this and I'm confusing myself

cerulean zealot
#

@strange token I have a "byte" counter in my code that just counts from 1-223 then back to 1.

If byte counter is 0 that means person has just loaded, and network not ready.
every action it checks it against what byte owner is giving it and what it's recieved. It used as a buffering or timing pulse.

strange token
#

neat :3

#

really complex to wrap my head around but I'll eventually understand since I'm working with that stuff now xD

cerulean zealot
#

@strange token what are you trying to do, perhaps I can help.

strange token
#

I already figured out the above question because I was just overcomplicating it :3

#

I'm currently troubleshooting ondeserialization not running in my editor testing

cerulean zealot
#

does serialization work in your client sim?

strange token
#

nupe

#

it's borked lol

#

That's what I'm workin on atm

cerulean zealot
#

yeah it doesn't work in client sim

strange token
#

time to die

#

welp thanks for the info, that saves me a headache

cerulean zealot
#

hang on. tagging @meager quiver to ask if that script they gave me will work for @strange token

strange token
#

what's it do O.O

cerulean zealot
#

makes Serialization work in client sim. but it's kinda specific to the way I set up my programming in my NPC project. so IDK if it will work for yours.

strange token
#

ohh okie

#

I think I'm fine with all my network testing having to be in-game, it'll make sure I make less changes that are broken out of editor

cerulean zealot
#

you can test them in client sim by manually activating the events in the inspector when client sim is running.

#

@frozen igloo is this a good fix? ^ @meager quiver wrote it.

#

Tap and PhaseDragon know WAY more than I do.

frozen igloo
meager quiver
# cerulean zealot im gonna give you the script anyway. hopefully it fixes it.

The script I made here has some edge cases - it doesn't perfectly replicate networking, it just does it correctly enough to work with the networking style that your script uses - it may fire events incorrectly for some people depending on how they designed their netcode.

The tricky thing is having synced variables behave as expected, since you only have one copy of the script running, so to simulate this correctly you have to stick with a single way of signalling stuff, and that can break with other peoples prefabs etc.

Still, worth a shot, if nothing else.

#

The ultimate issue is data appearing before the events fire, as well as specifics around how long it takes for events to get through given this (immediate vs next frame), which for some scripts can result in a malfunction. Yours doesn't with this script.

#

It's just close enough that it works for your needs.

cerulean zealot
#

@strange token There you go ^ theres your answer.

hoary frost
#

how long in average does it take for a player to fully gain ownership of an object?

#

im using cyan object pool to give an object to each player, and then set them as the owner

#

but once that player becomes the owner, i need to set the owner as a variable on the object for it to be used in an update loop shortly after (since i wanna keep it optimized, instead of always calling getowner)

#

im considering just delaying the setting of that variable to once the transfer of the owner is finished, so just a timed delay should do

fallow mountain
hoary frost
#

or if a player left and now all remaining objects that dont have a player for some reason go back to the master?

#

im not sure how to capture all these unknown factors

#

this feels too bug prone to my liking

fallow mountain
#

what are you trying to achieve? why not VRC PlayerObjects?

hoary frost
#

so im avoiding player objects until i really really need them, and even then ill probably make a system to nuke them in editor until its been built

fallow mountain
#

?_? just fix your unity bro, you are hamstringing yourself and then trying to work around it

hoary frost
#

yeaaaaaah youre not wrong.
But i dont wanna turn on domain reloaddddd

#

what should i do?

fallow mountain
#

Disabling Domain Reloading

To disable Domain Reloading:

Go to Edit > Project Settings > Editor
Make sure Enter Play Mode Options is enabled.
Disable Reload Domain
hoary frost
#

what i meant is if i put player objects in my scene, play mode refuses to start properly unless i turn on domain reload

fallow mountain
#

strange, i dont remember ever turning it on even

hoary frost
#

yet it works for you? odd

#

lemme try to reproduce that bug, maybe i can show you more

#

well uuhhh it seems to work just fine right now????

#

maybe it was just an issue in the persistence beta or something

#

how confusing, i remember spending multiple days scratching my head around it 😅

#

ill let you know if it pops up, thank you!

fallow mountain
#

lol

hoary frost
#

yeah no i restarted it a couple times

#

only got some weird one off invalid unity objects but nothing outright preventing me from starting play mode

hoary frost
#

@fallow mountain i got the bug again

#

MissingReferenceException: The object of type 'VRCPlayerObject' has been destroyed but you are still trying to access it.
This is the first error im getting, then all the scripts referencing the local player break if i saw that correctly

#

so basically everything

#

and i cant move my character in play mode so i imagine the local player didnt instanciate

fallow mountain
#

VRCPlayerObject' has been destroyed ??? you gotta find who destroyed it

hoary frost
#

all i did was to add the playerobject component to a collider

frozen igloo
hoary frost
#

i see

#

double clicking the error redirects me to this line
In ClientSimNetworkingUtilities

frozen igloo
#

You just need to open the network ID panel and confirm whatever message it's asking

hoary frost
#

oh is that so

#

i have the panel open now, its not asking anything

frozen igloo
#

can you take a screenshot of it?

hoary frost
hoary frost
#

i tried regenerating scene ids, no luck

frozen igloo
#

huh, that's odd. Usually that does it

hoary frost
#

oh wait

#

i cleared the ids, then tried regenerating them again

#

and i got this message

#

MissingReferenceException: The object of type 'VRCSceneDescriptor' has been destroyed but you are still trying to access it.

#

💀

frozen igloo
#

where's that coming from?

hoary frost
#

well, the console

#

upon trying to regenerate scene IDs

#

this whole mess only happens when i have a player object in my scene

frozen igloo
hoary frost
#

copy paste is probably better haha

fallow mountain
#

what script is it? what does it do

hoary frost
#

VRCNetworkIDUtility

#

which is the network utility most likely

hoary frost
fallow mountain
#

i mean what script are you running

hoary frost
#

wym?

hoary frost
#

im just clicking on regenerate scene IDs

#

oh

hoary frost
#

which is, weird, since that didnt happen yesterday

#

😅

fallow mountain
hoary frost
#

the entire script?

#

you can find it in your project

fallow mountain
#

ClientSimNetworkingUtilities?

hoary frost
fallow mountain
#

oh, i thought it is a script you wrote

hoary frost
#

it is not, both errors are from scripts that come with the vrc sdk

#

cant enter play mode nor regenerate scene IDs with player objects in the scene, if i have domain reloading disabled

fallow mountain
#

is this latest SDK? and 2022 unity?

hoary frost
#

yep

#

3.8.0

#

unity 2022.3.22f1

hoary frost
# hoary frost

but it seems like this is the root of the problem @fallow mountain

#

coming from this line

#

in VRCNetworkIDUtility

#

i dont exactly understand this, but if i were to guess, its probably trying to assign a network ID to an object and fails, but inserts it into the array anyway

#

so when that gets referenced later, it crashes and burns

#

if that is correct, then something about domain reload fixes this

#

i mean, there is this network IDs array inside the scene descriptor

#

hmmmmmmmmmmm

fallow mountain
#

hmmm

hoary frost
#

oh hey look what i found

#

thats our answer i believe

#

sigh

fallow mountain
#

yeah looks like it, SDK problem, congrats (on end of identifying problem)

fallow mountain
#

it's not your fault

#

sometimes

hoary frost
#

the funny thing is, i remember going up this chain of events all the way back when player objects were introduced

#

but you convinced me to look into it again XD

#

hopefully this convo helps those who have the same problem

fallow mountain
#

lol it is not the ending it is the journey

#

or, it is not the result, it is the process

#

i forgot what the saying goes

hoary frost
#

maybe the sdk bugs were the friends we made along the way

#

i ironically really need the system im trying to make to work eventually, itll really make my game more responsive and fluid

fallow mountain
#

and we get to blame VRC devs at the end of day

hoary frost
#

haha

fallow mountain
#

can you not test in-game?

hoary frost
#

but yeah, tough choice
Do i take the player objects shortcut, and suffer the curse of x3 longer play mode loading times forever?
Or do i take the harder route and take the hassle of making my own system to mimick player objects

hoary frost
fallow mountain
#

what system are you developing, can you not do it in a new project?

#

or new scene

#

on its own

#

so its fast

hoary frost
#

im making local colliders for every player

#

my items have functions that do things when theyre inside a player collider

#

at the moment im using OnPlayerTriggerEnter/Stay to detect when an item is inside a player

#

but the issue is that it only detects it on the "victim", not on the attacker

#

so due to vrc lag, its pretty common for the attacker to wonder why their hit didnt register, because the victim simply didnt see the item touch them on their end

#

i want to change this system to attacker focused instead of victim focused

#

and for that, ill need each player to have local colliders on every other player

#

pretty sure worlds like blackout have similar systems

#

since i never noticed hits not being registered when attacking

#

another option would be to use cyan object pool

#

but then i run into my original problem i posted about days ago haha

fallow mountain
#

hmmmmm why not just use one local collider to detect? it follows local player and detects any remote player and send custom event when needed

hoary frost
#

the victim would still need to be the one seeing the hit happen instead of the attacker

fallow mountain
#

no difference, you just need one collider, on the attacker locally, when attacker triggers, check if the player entering is the victim, then do whatever it needs to do

hoary frost
#

yeah

hoary frost
#

players are gonna be chasing each other and theyll wonder why their hits didnt connect

fallow mountain
#

no because the detection happens from the attackers pov

hoary frost
#

oh? then i did not understand your explanation

#

how do i check the victim being inside the object if there is no trigger to detect it

fallow mountain
#

the trigger is done by the attacker, rather than by the victim

#

or rather, by the attacker computer, rather than by victim computer

hoary frost
#

hm, lets make sure we have the same definitions
What do you mean by trigger?

fallow mountain
#

my understanding of your problem is, if the victim lags, the hit doesn't register even the attack can see him attacking the victim, because on the victim's client, the attacker is lagging behind

hoary frost
#

so the attacker needs a way to check on their own if the hit went through

#

without relying on the victim seeing it

fallow mountain
#

so, do it on attacker's computer, so if a victim lags, they die easier

hoary frost
#

yep

fallow mountain
#

yes

fallow mountain
#

well that solved the problem of hit not registering

hoary frost
fallow mountain
#

you can just use one collider for the local players, which can detect any player

hoary frost
#

what how?

fallow mountain
#

the collider is entirely local, no need to sync, the only thing it needs to network is send custom event (victim dies or something)

#

and there is only one collider in the entire scene

#

and it is on the local player

#

on the attacker's computer, it is activated

#

on the victim's computer, it doesn't need to do anything, it can be disabled

#

the collider follows the attacker, locally, and detects any player entering it, when someone enters, do stuff

hoary frost
#

detects any player entering it
so how?

#

wait

#

wait a gosh darned second

fallow mountain
#

OnPlayerTriggerEnter...?

hoary frost
#

onplayertriggerenter is a global event isnt it???

fallow mountain
#

?

hoary frost
#

ive been using an islocal check on it for so long i forgot it was globally fired

#

💀

#

yea your explanation makes a lot more sense now

#

major blind spot from my part, thank you for pointing it out!

fallow mountain
#

happy hunting (?)

cerulean zealot
#

Yeah onplayerentertrigger is global because it outputs playerapi. No need to do that on s local only script.

hoary frost
#

yeah, i always knew that but been so used to not using it that way that i forgot about it

cerulean zealot
#

I REALLY wish that vrchat would have flagged global vs local events in the sdk. At least some different color coding im graph.

hoary frost
#

true

#

ive resorted to doing this

cerulean zealot
#

That will fire every frame they are within the trigger.

hoary frost
#

yeah i know, i meant using the groups like this haha

#

makes it easier to debug networking when quickly reading through code

#

like comments pretty much

cerulean zealot
#

Oh ha ha. I've resorted to a very strict network calling system procedure.

hoary frost
#

oh?

cerulean zealot
#

Yeah.. but it really only works well for my npcs..

hoary frost
#

fair enough

cerulean zealot
#

👀 that's all I care about... my little creations....my npcs

hoary frost
#

i totally understand that hahahaaa

hoary frost
#

i feel the same way

cerulean zealot
#

I can't wait till I get my trex up and running. 😈

#

Trying to get the combat system and sensory programs more refined though.

hoary frost
#

ooooh

#

im interested and listening

strange token
#

I'm kind of having trouble understanding where/when OnDeserialization is supposed to be "powerful" as all I'm finding so far is circular code that I can't straighten out lol

#

I don't understand how to cleanly set up a button that updates an udonsynced variable that does some things for both players while also having code that only runs for the person who updated the variable itself, without writing the same code in multiple places that seems like it'll become spaghetti code quick

#

I guess more specifically what doesn't make sense is why you'd run code in OnPostSerialization when that will always run every time you sync anything on a script

#

I'd rather put the sync-er's code responses directly after the code that triggered it, but I'm apparently supposed to just sync the values and run essentially the same thing other players run in OnDeserialization, but in OnPost, so that you run the exact same thing as close as possible to when other players receive it

#

but that whole "runs every time you sync anything part really confuses me on how you're supposed to really do anything in there

#

If someone could explain how this works and how you're supposed to pick out when code actually updates in order to only respond to changes to actively synced variables in OnPost that would be great 🙏

hoary frost
#

so lets say youre serializing multiple variables on the same script and you need all of them to be up to date before running logic

strange token
hoary frost
strange token
#

I thought OnPost was specifically to allow you to try to synchronize any synced variable updates with other players time-wise

hoary frost
#

idk i never used onpost

strange token
hoary frost
#

ye

strange token
#

because most active folks here recommend onpost

#

but now I'm trying and actively dont' get it

hoary frost
#

what i do is just send a custom event after ondeserialization and also on the local player

#

basically does the same thing as onpost

#

i guess onpost is cleaner when you think about when things happen but in the end i dont think it matters too much

cold laurel
strange token
#

yeah so you skip onpost and just run the changes directly after requesting to sync

twin portal
#

field callbacks are perfectly fine if you need to change a condition any time a variable has a new value

If you run your code directly after RequestSerialization, you will be assuming that the serialization was successful. If it wasn't, only the owner will see things working
With OnPostSerialization, you can check if the serialization was successful or not, and change logic depending on the success. Not only can you output the result for debugging, you could potentially "cancel" the changes if the serialization was detected as failed

#

it's a healthy way to keep things synced, and a singular place you can update and make any changes when the owner is meant to have it
running the code right after Serialization also makes the logic run that frame, and not when the serialization actually happens, which is the next network tick

strange token
cold laurel
#

You're misunderstanding OnPostSerialization

twin portal
#

OnPostSerialization only runs for the sender. Everyone else gets OnDeserialization

cold laurel
#

It gets called for the owner after they have serialized data

#

Not for the receiver

strange token
cold laurel
#

Having duplicate code is rarely a good idea.

#

But I guess you could call the same method.

twin portal
#

unless it's just function calls

strange token
#

Yeah I'm searching around but not having much luck finding a tutorial that explains how and when to use the two methods lol

twin portal
#

you should have a separate function that updates your states based on the current synced variables
then just call this function in OnDeserialization, and in OnPostSerialization if it was successful

#

what function you use all depends on timing, really, when you want things to happen

strange token
cold laurel
twin portal
#

and if your arrays are null

strange token
#

kinda sounds like I've never had a good enough reason to switch networking methods because there isn't one xD

cold laurel
#

I always declare my synced arrays like this, which prevents that issue.

[UdonSynced] int[] _playerIds = System.Array.Empty<int>();
twin portal
#

yeah that's all it takes

strange token
#

well now I have like 3 or more fieldchangecallbacks to write to make my code stop shitting its pants lmao

#

it's been nonstop sync looping because I didn't understand onpost lol

#

thanks for the answers all o/

cerulean zealot
#

Here is how I view it.

Request serialization: you call the mailman and tell them to come get your letter.

Preserialization: mailman is at your door waiting for your letter. You are jotting down last minute notes on your letter.

Mailman takes letter to mail distribution center.

Deserialization: mailman delivers letter to all your customers.

Postserialization: mailman delivers your letter back to you with a few things stamped on it.

#

Then everyone does happy dance 🕺 💃

foggy jackal
#

Networking.DoHappyDance() ?

cerulean zealot
#

Yeah looks like this^

foggy jackal
#

I'll have to practice that.

cold laurel
frozen igloo
fallow mountain
#

is it possible to have the letters sent out by mailman / OnPostSerialization success, but other people don't get the mail / fail OnDeserialization?

frozen igloo
fallow mountain
#

What happens when OnPostSerialization result unsuccessful, does it automatically request serialization again, or is the data abandoned (and have to manually request serialization again)?

twin portal
#

you have to request again

frozen igloo
#

if it fails one time, there's basically no chance it'll succeed just by trying again. There is something about your data that is invalid and you need to fix

hoary frost
#

So, OnPlayerTriggerEnter/Stay does not seem to fire whenever the trigger is on a VRC pickup, if it was a remote player entering the trigger

#

is that intended? if so how am i supposed to go around this?

frozen igloo
hoary frost
frozen igloo
#

remote players have a different collider, it's a small sphere centered on the feet instead of a capsule extending all the way up

hoary frost
#

hmm, what could i do then? Am I forced to generate a new collider for every player that matches its size

frozen igloo
#

if the default colliders for remote players are insufficient for your use case, then yes making custom colliders would work. PlayerObjects make that fairly easy

hoary frost
#

yeaaah well, you remember the issue i had with player objects yesterday XD

#

guess ill just make my own system

#

with cyanobjectpool or smth

frozen igloo
#

Why is domain reload such a deal breaker? It's an unstable optional process that has the potential to break things, it's not too surprising that the sdk is one of them because a lot of the sdk was designed before disabling domain reload was a thing

hoary frost
#

because it adds two minutes to every play mode entry (my world is pretty heavy)

#

and i like to play mode a lot to playtest things

frozen igloo
#

you should have a minimal test scene for cases which require going in and out frequently

hoary frost
#

youre not wrong actually

#

id need to set that up to cover all edge cases, i have a feeling im gonna have bugs that wont be showing up in a test scene due to their in world context

#

and then... yeaah itll be annoying to test

frozen igloo
#

It's helpful to make sure your scripts can survive the jump between scenes because that shows you what is fragile and what the dependencies are, which makes for a more robust, reliable script in the end result

hoary frost
#

i guess i could start working only with prefabs from now on, that would make transferring anything from main scene to test scene trivial.
But then udon graphs wouldnt update properly (references often break inside prefabs), so id need to mass refractor all my graphs into sharp, time consuming task

hoary frost
#

i had no idea graph scripts would make it so hard to refractor

cerulean zealot
#

Like errors to logs

frozen igloo
#

ye

brisk magnet
#

Just Wana confirm something, when we request serialization, does udon check if data has changed or does it sync everything even if the data has not changed

brisk magnet
meager quiver
#

Huh, it does build. There ya go. I swear for a while it didn't, maybe that was unity 2019 era.

#

or maybe it was only on private stuff it doesn't? idk

#

Ah! It's just not available at runtime, right. Works fine in initial heap.

cold laurel
hybrid kindle
#

OK so i have a network event that tells everyone to update the button owner's voice to be louder so ppl can hear them throughout the map. But its not updating for everyone and the voice never changes. Locally it does. I am confused where am i going wrong.

tulip sphinx
#

@hybrid kindle youre missing an actual network event and all this runs only for owner/button pusher. make each block into its own custom events (like, 'mute'/'unmute'), and after branch just call them via send custom network event - all.

hybrid kindle
tulip sphinx
#

then its done in a wrong way. once again, left part up to branch should run only on new owner. right part (blocks) for everyone. so it cant be a continuous flow.

hybrid kindle
#

i see

#

so call network events there too before the blocks?

tulip sphinx
#

idk why you call network event initially. for me feels like it should start with just Interact (or local event if its ui)

hybrid kindle
fallow mountain
#
  1. Just a nitpick, why is mute=true going to louder volume?
  2. Can you show the networked event?
tulip sphinx
fallow mountain
#
  1. I suggest renaming mute to isLoud (not a problem, just a personal preference)
  2. You gotta set owner before sending network event, because now everybody will run the event mutelogic and tries to set themselves as owner.
  3. Maybe u can do something about the on/off status not resetting between people, right now if someone turned it on, another person clicks it, it will become off (and do nothing)
#

And I am not sure owner update will be fast enough for other people to change volume on the new owner

fallow mountain
#

It may be more reliable if

  1. make s a variable "currentUser" and "isLoud"
  2. on interact (or custom event) to set local as owner, and
  • if not already owner, set "currentUser" as local player and set "isLoud" to true, and request serialization
  • if already owner, toggle "isLoud" and request serialization
  1. (for owner) and then custom event "UpdateVolume" which changes volume of "currentUser" based on "isLoud" true or false
  2. (for other people) ondeserialization->custom event "UpdateVolume"
faint rock
#

Why does the SDK care about None set UdonSync objects now?

#

And now ClientSim doesn't work anymore either... despite the networking tool now saying everything is fine?

fallow mountain
#

Do you have objects with the same name under a shared parent?

#

Change them to Object1 Object2 Object3 and so on, and then regenerate IDs

silver hill
digital oriole
brisk magnet
silver hill
#

The animation file itself, it also controls the sound effects (It only sounds off because of the compression output because I gotta keep the video file less than 10mb)

#

And the compression affected the audio lag for some reason lol

runic depot
#

Anyone have any good documentation on how to handle networking for moving vehicles? I want things to be handled locally as much as possible and only sync important things such as direction changes. For context, a vehicle that doesnt turn and only goes forward or backwards. I want to do that, but I feel if I only sync the changes of torque, there will be small differences between all local players. I just don’t want to have any unnecessary loads on networks and I’m not sure if VRCObject synch is what I need because this vehicle has many other moving parts. (E.g a boom for a forklift or crane)

silver hill
#

Object sync would be suffice for a vehicle, but yeah the forks would be a mind bender

#

You could sync the float that controls how high the forks are going but Im not sure how the physics would react

#

Assuming you would do something like that

runic depot
#

Im sure there are better, more optimized options

silver hill
#

You also have the issue of dealing with owner changes, the forklift might be owned by the local player but if the cargo you are lifting is owned by someone else, you will likely have physics issues

#

Make a script that will auto update the cargo to become your object to counter this, maybe when the forks touch the object, get the owner of the forklift truck then copy/paste that to the cargo

silver hill
#

Are you a graph guy or a programmer

brisk magnet
#

oof looks like Im going to have de optimize my network usage beacuse I cant find a way to garentee the execution order of my network stuff without having to make the host wait 3 plus secconds betwen sending out syncs

#

It would be nice if you could bundle serilizations together and specify an order to read them in.

runic depot
fallow mountain
#

Vrc object sync will sync transform and works for a vehicle. But if it has a predictable path, then yes u just need to a networked event to tell it to start or stop i assume

cerulean zealot
finite sierra
finite folio
#

Guys, who can help improve dropdown? One person helped me make a dropdown, but I would like to be able to take it all by any number, but here I can show a spoiler how I did it in my own way, I want to do a language translation, but here I got completely unoptimized.

fallow mountain
#

this graph made my dog cry

#

translation of what?

#

just one object?

drowsy jackal
#

So how well is the TeleportTo function in the vrc object sync?

#

What I mean is, how reliable is it?

fallow mountain
drowsy jackal
fallow mountain
#

probably because of the smoothing makes it "overshoot", the solution is using FlagDiscontinuity()

drowsy jackal
#

Yep, that's probably it. I am learning. Thanks for the advice. 🙂

finite folio
# fallow mountain just one object?

I meant in a format where you type in as many numbers as you need and paste them in, I think it's pretty difficult to do this. After all, I want to do more and more translations in different languages.

finite folio
timber ferry
brisk magnet
brisk magnet
#

how is it that my post serilization is showing that it was sucsefful if none of the other clients are getting any of the data.

No ownership issues not exceeding any limits and network is not clogged. But never happens with 2 clients. add one more client and it becomes an issue.

fallow mountain
#

need more data

cold laurel
#

Are you absolutely sure the GameObject is enabled at all times?

brisk magnet
# cold laurel The GameObject with the synced script has to be active in hierarchy for everyone...

I dont have access to the code where I am now but I'll try to describe the setup.

All network objects are always active and never disabled.

One client owns all the objects except a few and is the "session owner" All other clients only own there input handlers.

When a client makes a game input they serialize the object they own and the session owner only will preform the needed operations on the objects it owns by reading the clients input handler. A network event is sent back to the orginal client to reset there queue to a no input state.

There are 3 main code pathways that follow this model. Card play. Cancel attack. Pickup cards.

When 2 players are in game all pathways work at all times.

When 3 players are present all pathways work without issues except for play card.

Play card stops working on all clients except for the session owner. However I'f the session owner is the instance owner all pathways will work for everyone again but only 80% of the time for play card.

I have varafied through logs that. Post serlization is firing on the client requesting the input and 72 bytes are being sent. And that all clients actually own the specific object they serializeijg. I have also verified that no other clients receives the serlization event.

But the behavior tells me there is an ownership issue of some kind somewhere.

The only thing that stands out to me is that the working pathways start there execution from a script that has no network ties and the failing pathway is initiated from inside a script that is manually synced and not owned by the client using it. However the client is not trying to serialize that object it's simply using it as a way to talk to the one it is trying to sync data for.

#

Its also suspicious to me that the client is sending 72 bytes though beacuse the object its trying to sync only contains 1 byte so that may be a clue

#

I'm also thinking this may be an undocumented udon bug or behavior. Beacuse I've noticed some types of code entry points can changes udons tollorance for certain actions. I'm thinking I need to delay frames to make sure the scope of the event starts insides of a network neutral object like the other 2 paths

#

But it's hard to know when udon is not reporting on why it's not sending the data

#

But I'f any of those things were issues then I don't understand why the bug wouldn't be happening with just 2 players? I can't figure out what in the codepath changes just by adding an extra idle player

fallow mountain
#

what are the objects?

#

can you list the objects

brisk magnet
# fallow mountain can you list the objects

Root object game play state. Contains most of the data and functions.

Each card has a networked udon behavior. But the only synced value is witch player "owns" it on the gameplay side of things the session owner still has network control of it regardless of who owns it.

Each player also has a hand object that has the cards in their hand. Again session owner owns all of them on the network regardless of who the hand is assigned to.
A player object that holds some state data about the players status like are they still in the game or did they win.

And lastly the input handler. Each client takes and maintains owner ship of the handler corresponding to their player. Once the game is started there are no transfers of ownership for any objects

#

There are also several other client side udon behaviors that don't touch the network directly but are used to interface with it

#

For example the pickup and end attack functions are called from a local ui object where as the problem pathway of play card has been moved directly onto the card so that users can just click on the card itself to play it

#

In the last version of the game this functionality worked fine when the system was click card to add it to queue then click localui button to play to actually request serialization. But for some reason making this a one click prosses as broken it

fallow mountain
#

are the card picked up and moved around?

#

cards

brisk magnet
#

The clients will each move them to the correct position client side only and look at what array the card id can be found in to decide where on the screen to move them

#

The position is not synched

fallow mountain
#

i think you need someone to look at the project itself

#

probably too complicated for discord

brisk magnet
#

The more I talk about it the more I think it's an undocumented issue with udons call structure. I think if I move the input back to local ui and just have the button teleport to the card when needed instead of having a play button on each card it will likely start working again.

I'm not realy expecting anyone to have a solution for me here I'm mainly trying to brainstorm possible reasons. So that when I get home later today I can have a list of changes to try

#

And that's the updated broken one it's literally the same code runing both the only thing that changed is what object initially calls it

brisk magnet
#

Key questions:

Why are we trying to send 72 bytes of data to sync a single byte.

Why is it being reported as sent successfully when no clients get it.

What impact does the player count have on this occurance.

Why does this not occur when the same code is simply called by a different object. (Speculation is welcome)

brisk magnet
#

Also wondering if there's a way to tell if it actually didn't get sent or if the receiver is not listening. Might have to break out wire shark for this one

twin portal
#

you can use OnDeserialization to check when the receiver gets it

#

have that print to console

brisk magnet
#

I have confirmed that in the specific instance when the bug occurs no client not even then client that requested the serialization ends up entering there Ondescerilization functions. There is a log at the very top that never prints

twin portal
#

the sender will never fire OnDeserialization

brisk magnet
#

For testing purposes i put a call right after to see if it would run and it just stops there no script crash though

#

On post does run and reports a sucsess with 72 bytes sent

#

But there's only 1 byte to sync so I'm confused about that number too

twin portal
#

iirc, serialization packages all udon behaviours on an object and sends them all together

brisk magnet
#

Well in that case then there's only 5 bytes total

twin portal
#

are multiple objects requesting serialization in the same frame?

brisk magnet
#

Nope just one

#

Although that info does help and it's created a lead I'm going to follow up on

#

Still when I think about it we should only have one byte

#

So we have a card object with a 4 bytes of data on it that could be synched

#

We enter code execution through the card via clicking on it

#

We do not attempt to sync the card but we insert its id into an array of size 1 that exists on input handler the data type for that array is byte btw.

Then from inside the scope of the card we request serialization on the input handler

#

That handler is on its own game object with no other scripts

#

I also for most of my scripts I don't call request serialization directly. I mark them as dirty and at the end of every cycle it calls ones for each dirty script so no double calling is possible.

#

In the case of input handler only a players click can trigger its request serialization

twin portal
#

72 bytes sounds like a lot more data is being synced, like an array or something

brisk magnet
#

The only script that has that much data is the root play state script.

But none of that code is Evan getting the chance to fire off yet as it basicly stays dorment until the session owner runs Ondescerilization for the clients input queue witch is proven to not Evan get entered.

#

We basically have a simple function that looks something like.

Public void OnClick()
{
If(VALIDATIONPASSES()
Handler = state.GetplayerbyId(localplayerid).inputhabdler

Handler.queue[0] = id
Handler.request serlization()

#

Is essentially what's happening although trying to type it on phone didn't work out perfectly

#

So in the error use case we don't end up interacting with very much of the project

#

We only ever touch the state in the form of a helper function that helps us find the correct input queue we make no attempt to modify its data

twin portal
#

and the player clicking is also the owner of the Handler script?

brisk magnet
#

Yes

#

They don't own the card

#

But they own the handler they are requesting on

#

And it's the same deal on the server side the server does not own handler but it operates from inside its on deserilization and is able to sync the stuff it owns while running in there

#

And there's no bugs on that side of the runtime in addition there's 2 other pathways using the same model working 100 percent as intended

#

I've said this before but there's kinda contradicting evidence.

On one hand it's acting as if we have an ownership issue. Beacuse the bug does not occur if the instance owner takes on the session owner role of the game.

However then why is only 1 in 3 parts of the system being affected if that's the reason?

On the other hand it seems like an entry point issue but again if that's true why is it not an issue 100% of the time

twin portal
#

when manual syncs get fiddley like this, I sometimes wrap the RequestSerialization in an additional ownership check
I do a check if the local player is also the owner of the UdonBehaviour I'm about to request serialization for; if true, request as normal, but if false, log an error like "attempted serialization without being owner!"
maybe good to print further info like who really was the owner, etc.

brisk magnet
#

Yea I've got that going too but it's. Not tripping

#

Some how owner ship of the session owner is affecting the behavior of objects that it's not supposed to and never owns or trys to modify

#

I wish udon would log more of it's decisions

twin portal
#

do you have a debug that shows what player is the owner of the important scripts in-game? Or can just RShift + ~ + 3

brisk magnet
#

Is do the shift plus 3

#

But the way I have it set rn is the session owner is always the player on the south side of the table

twin portal
#

that makes sense

#

I was worried the master was taking ownership of something unexpectedly

brisk magnet
#

Nope at the start ownership of everything it set to the session owner. And then after that players find and take ownership of their own input handler no more transfers hence fourth

#

So if there is an ownership issue there's exactly 1 function to look at

#

But I couldn't find any issues with it

twin portal
#

and this is breaking when there's a third player in the world, and works fine with just 2 players still? or was that an earlier condition

brisk magnet
#

Clarification a 3rd player can join the world and it will work if there's only 2 playing at the table

#

But as soon as a 3rd joins card play functionality stops working for all except the session owner

#

Funny enough all players can still pickup cards witch runs the same way as playing cards

#

I could mess with ownership of the input handler ping pinging between the session owner and it's player but I'm not sure if that will have an effect

#

Are ya going to be around in 5 hours from now @twin portal

twin portal
#

I'll be free to be in-game in about 6 hours from now

#

I'll hang out in chat here all day though

brisk magnet
#

Also thinking of pushing the lasist version up to the hosted world to test live with

#

The orginal old version of the game will still be there to so won't stop anyone from playing the working version

finite sierra
#

@brisk magnet are you making a card game? or what are you making with cards

brisk magnet
brisk magnet
brisk magnet
#

@twin portal found the reason but not sure how to fix it.

so whats happening is in this function the array is ending up a null with no length and thus causing the syncs to fail. and im still extra confused on why the player count is affecting weather this ends up with a value or not. any ideas?

twin portal
#

any arrays you want to sync should never be null at any point

#

like during declaration

brisk magnet
twin portal
#

even before syncing, at any point in the code is it null

#

ideally it only matters if its null when you sync, but I've had issues with synced arrays if they were null at ANY point of operation

brisk magnet
#

well its set to new byte[0]

#

so technicaly no but has no values

twin portal
#

that should be good enough

#

it would be obvious if that was the issue anyway bc the serialization would fail, now that I think about it

#

but you said it was succeeding

brisk magnet
#

it is now

#

but as you can see the session owner on the top window didint get a single thing

#

theres debugs in every single post pre and onDesc

twin portal
#

hold on

#

you're calling OnDeserialization directly

#

didn't we suggest like, not doing that

brisk magnet
#

thats not executing in this case as that condition is false in this patheway ironicly it works fine on the paths where it will hit that

#

This bug happens only for clients that are not the session owner

#

in anycase it dosint matter so I updated it

#

and no change. that hand on data call was from the previous move that player was able to make before the bugged player attempted to move

#

I think I might just sawp back to my old UI its starting to look like I cant figure out why its behaving how it is. And realy dont understand how a simple UI change radicaly changed how the network behaved

brisk magnet
#

does udon have a max call depth?

brisk magnet
#

so interesting development.

this change allows the code to work on the client but not the server. in theory I can just make an if statment and then It would work for all clients now but this feels so wrong there has to be a better way then this

frozen igloo
# brisk magnet does udon have a max call depth?

Udonsharp does not, because of how it has to do recursion through stuffing each layer into an array.

The way that udon 1 operates as a C#-level VM, it never truly goes that "deep" on anything, as it's backing out and then coming back in on every single operation.

All of these technical decisions contribute to the overall speed of udon having large overheads above and beyond most standard C# implementations. As a result, each iteration costs dramatically more than a traditional call system which does all that on the stack, but the weird upside is that it makes udonsharp able to handle waaaay more recursions and call depth than most implementations.

That said, I wouldn't be surprised if other languages have their own ways of dealing with call depth and stack overflows, but I'm not intimately familiar with what's been happening out there.

Regardless of where we're at now, this all means that the eventual successor to udon 1 will very likely take the form of something with a more traditional callstack, which would bring significant performance improvements but at the cost of losing that kinda useful relatively-infinite callstack that we have here

#

Udon graph technically has native recursion support to insane depths simply because of how all communication from one method to another goes through a class-level event. It's clunky without sendcustomevent with parameters, but it's been there the whole time.

brisk magnet
#

it seems to realy not like this location as the entry point for the script im talking to

frozen igloo
brisk magnet
#

somthing about the call structure is just going very wrong

#

and for some reason being the owner of an object not part of the equasion or shouldint be part of it at least is somehow affecting witch clients can use this one

frozen igloo
#

Fascinating, what's the full picture of events flowing into each other in that case?

brisk magnet
#

Would it be possible to pull up a screen share and show you?

frozen igloo
#

Ah not at this moment but I'd be able to find some time for that later tonight

brisk magnet
#

ok in the mean time ill try to give an overview

#

so the main thing that holds the game together is a class called DURAK play state.

One player is selected as the session owner they get control of all udon behaviors except for 3.

There are no ownership changes once initial ownership is assigned. each player has a input handler object. they write the server reads

so when I play a card. I click on the card that the server owns, then the card looks for that players input handler and tells it to serilize after inserting itself into a synched value.

then the player acting as the server will read the handler and modify the state from inside the input handler. this works fine beacuse we are only reading it. while requesting syncs on stuff we own.

theres 3 pathways for this. Play card. Pickup, end turn

Play card runs correctly on the server only.

Pickup and end seem to run perfectly on all clients.

I skipped over allot but thats the basic gist of the situation. On post is firing on the client but the server never gets the event for the data

#

id also like to note there was a previous version of this game where all of these features with the same code worked without issue. but I changed the UI for playing the card and thus had to move the script entry point

#

Im trying to figure out why it was happy with the other one but un responsive with this one

frozen igloo
#

Oh, your callstack for that is jumping back and forth between a couple people, does that mean sendcustomnetworkevent is utilized as a core piece of the callstack?

#

In other words - is that more of a characterization of how it operates between scripts, or is that a direct description of the callstack bouncing between scripts?

brisk magnet
#

no I only inserted it here beacuse im just shooting in the dark to see what happens no where else in the code is it used like this

#

It seems to be helping in the particular case for some reason

#

we request on the input handler. server responds all other clients ignore the event. server seralizes another object. all clients take it and react to the data

#

so its just one quick ping pong

#

however ive found for the clients in particualr specificly on the play function delaying the call by 30 frames allows the signal to get through

#

where it would normaly report 70 bytes sent but not actualy send anything

#

im also woundering why its costing 70 bytes to synce a byte array of size 1

frozen igloo
#

Ok, I think the most thorough way to answer this question is to link a couple hours of GDC sessions on gameplay networking - if you're down for that let me know!

If you're looking more for a quick fix to this specific thing, I would also be down to walk you through how I would approach your specific situation. If that's more of how you operate, I'm down to follow that lead further.

brisk magnet
#

id honestly like to take both options. on one hand id like to get this fixed soon. on the other id also like to know exactly what was happening long term.

#

I plan on making a few more worlds and there not going to get any simpler XD

#

side note I made abit of progress

#

the server is actualy getting the event now but no data still

frozen igloo
#

Ok, I'll be able to screenshare with you in a few hours if you end up wanting to do that, but in the meantime while you wait, here's a couple videos to watch:

https://youtu.be/h47zZrqjgLc?si=fE1mRahMV3sfu7S
https://youtu.be/Na95i4ZD68I?si=MQu-ON9faV3RYBBoi

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

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
cold laurel
brisk magnet
cold laurel
#

I'm not certain about the exact contents of VRC's headers.

frozen igloo
#

Header is one part of it, but byte alignment is another that takes up more

brisk magnet
#

I need to test more to confirm but I think this fixed the bug

#

do you have any idea why this worked?

#

forgot the bottom

#

again session owner is just the player the owns all the non input handler objects

#

(the reason its an array is im considering allowing multiple inputs per sync)

#

but its confirmed that it works now so thats a step forward at least

brisk magnet
frozen igloo
#

Must have been going down the right track somewhere then hehe

brisk magnet
#

I mean I had no doubt I would eventualy find a solution. I mainly struggling with understanding why udon does what it does in certin situations.

but in this case Im not realy ready to accept this as a solution beacuse it comes with an ugly 30 frame wait and I dont realy know why it works.

#

and for all I know theres somthing wrong with it thats going to cause more issues in the future

frozen igloo
#

I mean I had no doubt I would eventualy

blissful lark
# frozen igloo Udonsharp does not, because of how it has to do recursion through stuffing each ...

A lot of languages including C# actually support a thing called tail calls https://en.wikipedia.org/wiki/Tail_call which means if you're doing a recursive call as the final call of a method, you can actually just discard the stack since you won't need to use any of the old values from the previous call. This lets you do infinite recursion on functions that are written to allow it and it ends up being required for a lot of languages that do functional programming in order to allow iterating over sets of arbitrary size using recursion.

twin portal
#

I remember learning about that in college on how to optimize recursive calls

brisk magnet
#

In some ibm systems I've worked on they lose track after like 7

twin portal
#

poor things....

brisk magnet
#

Working on an as400 was like the the weirdest thing

twin portal
#

no please not as400

#

I've had to use that at my job

brisk magnet
#

You needed 4 languages per program beacuse each labguage has such harsh limitations

#

Yea you know the pain then

#

Of having to go back and fourth between rpg clle dds and sql lol

#

And piping it all down a websocket talking to something running c++

twin portal
#

we certainly take a lot of modern software development for granted

brisk magnet
#

Oddly enough certain specific things in udon have been giving me more grief then the ibm stuff ever did but it's not an un familiar thing. There's a saying "the reason so many languages exist is beautcuse all of them are garbage in some way" lol

#

The grass is always greener ya know

twin portal
#

stares longingly at Nanite....

brisk magnet
#

I can't say I've had the pleasure or pain of using that

#

Btw @twin portal or anyone elss interested. Would you be down to help debug in an hour i got a long gg list of tests to try and having another pair of eyes take a look could helo

twin portal
#

I won't be available unfortunately

brisk magnet
#

That's ok

brisk magnet
hoary frost
hoary frost
twin portal
#

I sorta already thought Udon did tail recursion lol
of course never tested or proved it

brisk magnet
#

I need at least 2 people other then myself to be fully sure. beacuse when I first had the bug there needed to be at least 3 players to trigger

#

also if possible enable your debug UI before you join. if anything weird happens a screenshot of the logs will help me out

hoary frost
brisk magnet
hoary frost
#

allows you to start multiple clients

#

essential to debug networking

brisk magnet
twin portal
#

a little bit

#

it's like that, but with a few extra features

brisk magnet
#

and is there ping simulation. beacuse ive had bugs that dont show up unless theres a little bit of latencey

hoary frost
#

but if you suspect something to behave differently with ping, i can help you by pointing it out in your code

#

ive had a lot of issues with it myself in the past so i think i have decent experience in finding em

brisk magnet
#

thanks that info will defintly. will still want to do some live tests for final validation.

ive allready done an hour of testing with multi cleint and it all checks out but I know theres a chance in the real network somthing will still go sideways

#

and theres kinda 4000 lines of code its not exactly a quick scan over XD

#

although its planned to be cut to 1700 after some more refactoring

hoary frost
#

fair XD

#

ngl at this point youd think it would be encapsulated into easy to digest functions

brisk magnet
#

well funny thing is it was

hoary frost
#

i see

brisk magnet
#

but then I flattened it beacuse the bug I was hunting was to weird

#

and the bug itself seemed to be partly from to many function calls from other referances

#

so I think refactoring the code might just bring the bug back

#

ill have to see

hoary frost
#

like i said i havent read it all, but from what ive seen, if youre having issues with race conditions and networking, using OnDeserialization may help to make sure you have all your variables in order?

#

just shooting that in the dark in case it helps

brisk magnet
#

yea if u want I can share screen the project and give you a little overview of the differant execution pathways

hoary frost
#

customnetworkevents are just a bad idea when you rely on things coming reliably or on time

brisk magnet
#

Id love any feedback

hoary frost
#

sure! im busy atm but ask me again later!

brisk magnet
#

allright

glossy scarab
#

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

public class Coil_Pedestal_Logic : UdonSharpBehaviour
{

    [SerializeField, Tooltip("Pool of Objects to be used.")]
    private VRC.SDK3.Components.VRCObjectPool objects;
    private int CoilType = 0;
    private string userDisplayName;
    void OnPlayerJoined(VRCPlayerApi player)
    { /* When a player Joins, we should first check a hardcoded list to figure out if they have a special coil. if they aren't apart of this list, we spawn in the normal coil. */
        userDisplayName = player.displayName;
        Debug.Log("Local Player Name: " + userDisplayName);
        Debug.Log(userDisplayName.Equals("Galexion"));
        GameObject PlayersCoil;
        if(userDisplayName.Equals("Galexion")) {
            CoilType = 1;
            PlayersCoil = Instantiate(objects.Pool[1]);
        } else {
            PlayersCoil = Instantiate(objects.Pool[0]);
        }
        PlayersCoil.SetActive(true);
        Networking.SetOwner(player,PlayersCoil);
    }
    void OnPlayerLeft(VRCPlayerApi player)
    { /* When the player leaves, we need to destroy their coil. */
        
    }
}

I am having issues trying to sync objects, I've added the correct Components to the item I am creating. I'm able to pick up and interact with the object(s) but others are not able to. above is the code I use to create these objects, using a object pool as a way to reference multiple objects without adding a additional variable for each item I want to add.

The reason why I am NOT using VRC Player Object is due to how I need to spawn the coil, as I don't want to try swapping the mesh at runtime, and I have Special SFX & Particles for each Coil, which I don't think I can switch out effectively.

Expected Result:

  • Coil Pedestal Spawns a Coil and sets the Object Owner to the player who just Joined.
  • Player is able to pickup the item and use it.
  • Other Players are able to see the item be moved.

Result:
✅ Coil Pedestal Spawns a Coil on Player Join.
❎ Only the Instance Owner can grab and use all Coils Spawned, instead of just the coil they were assigned.
❎ Other Players are unable to see the item be moved.

low herald
#

Hi. I was wondering if there's a way to fix this.

I think the recent udon network update broke my map since how my script works is like this:

AVelocity = new Vector3(24 1, 11);
RequestSerialization();
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, nameof(DropObject));

Basically i tried to sync my velocity and call **SendCustomNetworkEvent **after. This way i don't need to use **OnDeserialization **etc since before the network event is called, the synced variables gets synced first.
Now **SendCustomNetworkEvent **gets send without the variable syncing first.

I know this is not the proper way to do it so is there a way to fix this? Thank you

twin portal
# glossy scarab ```c# using UdonSharp; using UnityEngine; using VRC.SDKBase; using VRC.Udon; p...

you are using Instantiate to spawn the object. Instantiated objects cannot be synced.
You could possibly use TryToSpawn from the pool, but this won't give you a specific object in the pool, it will return a sort of random one. ObjectPools are designed for multiple copies of the same object, like a single type of soda from a vending machine. It doesn't matter which one gets dispensed, TryToSpawn just gives you one and syncs its state with other players

twin portal
# low herald Hi. I was wondering if there's a way to fix this. I think the recent udon netwo...

the order that a serialization arrives vs. a custom event is not guaranteed. If you need variables to be synced before running a function, you have to wait for OnDeserialization. Otherwise you'll get the behavior you're describing; the CustomNetworkEvent arrives before the variable has been synced
running RequestSerialization(), and then a CustomNetworkEvent, does NOT guarantee the data will be synced. Because the data is not synced that frame, it is synced on the next network tick, which is usually a few frames later

glossy scarab
twin portal
#

there's a few ways

#

if you want it to kind of act the same, you have an array of GameObjects, and just at start have these objects hidden away somewhere. Either put them really far away (easier to implement, but if you don't put them far enough away, people could just boundary break and go grab them), or have the objects hidden and start and sync if they should be visible or not (basically manually do the job the ObjectPool is doing)

cold laurel
hoary frost
#

Like being insistent on eating soup with a fork and wonder why it isnt working half the time

fallow mountain
fallow mountain
#

btw, anyone notice network events feel faster after the update, or is it placebo

twin portal
#

it's not! there was some network optimizations in one of the latest updates

#

Several internal network optimizations.
Observed behaviour for users and creators (in Udon) should not change. Please open a bug report if you encounter any problems!
This includes a full rework of how SendCustomNetworkEvent works internally, which is a pre-requisite for Udon Events with Parameters (check our dev update for more). For existing content, you may notice slightly improved throughput or latency, but otherwise full compatibility should be maintained.

fallow mountain
#

network events with params is gonna be revolutionary

timber ferry
#

i feel like regular SendCustomEvent with params would be more useful, because i rarely use SendCustomNetworkEvent

#

especially DelayedSeconds

#

i often need DelayedSeconds with params

#

i used to use SendCustomNetworkEvent in almost every project, but that’s because i used to do my networking improperly, and i thought sending network events to sync a bool was fine

hoary frost
#

fr, i dont know if there is a way to delay execution without eventsdelayedseconds/frames but if there isnt its our only way of doing it

fallow mountain
#

you can wait in fixedupdate using fixedtime, which is a little different than update (not really related to networking)

#

or... OnPreSerialization

#

if you are syncing stuff

#

i guess it dpends what you want to delay for

low herald
twin portal
#

that optimization in the latest update may be what "broke" your script. The SendCustomNetworkEvent is now more optimized and faster, so it arrives sooner than the serialization, compared to before

low herald
magic spade
#

THis has been driving me crazy I have done the same previously to network datalist data and Im am not sure why this just keeps not syncing the data I have been messing wi it for a day at this point

public class RuneCircleTrigger : UdonSharpBehaviour
{
    public GameObject cloudRunesHolder;
    public GameObject pillarRunesHolder;

    public Sprite[] AllRunes;

    public GameObject[] cloudRunes;
    public GameObject[] pillarRunes;

    [UdonSynced]
    private bool runesAdded = false;

    public DataList runes;

    [UdonSynced]
    private string _runesJSON;


    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        SetPillarSprites();
        cloudRunesHolder.SetActive(true);
        pillarRunesHolder.SetActive(true);
    }

    public override void OnPlayerTriggerExit(VRCPlayerApi player)
    {
        cloudRunesHolder.SetActive(false);
        pillarRunesHolder.SetActive(false);
    }

    public override void OnPreSerialization()
    {
        if (VRCJson.TrySerializeToJson(runes, JsonExportType.Minify, out DataToken resultQueue))
        {
            _runesJSON = resultQueue.String;
        }
        else
        {
            Debug.LogError(resultQueue.ToString());
        }
        base.OnPreSerialization();
    }

    public override void OnDeserialization()
    {
        if (VRCJson.TryDeserializeFromJson(_runesJSON, out DataToken runesJSONResult))
        {
            runes = runesJSONResult.DataList;
        }
        else
        {
            Debug.LogError(runesJSONResult.ToString());
        }

        SetPillarSprites();

        base.OnDeserialization();
    }

    public override void OnPlayerJoined(VRCPlayerApi player)
    {
        if (player == Networking.LocalPlayer)
        {
            SetPillarSprites();
        }
    }

    private void Start()
    {
        runes = new DataList();
        if (Networking.LocalPlayer.IsOwner(this.gameObject))
        {
            if (!runesAdded)
            {
                DetemineInstanceRunes();
                SetPillarSprites();
            }
        }
        SetPillarSprites();
    }


    public void DetemineInstanceRunes()
    {
        runes = new DataList();
        for (int i = 0; i < 6; i++)
        {
            runes.Add(new DataToken(Random.Range(0, 10)));
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
            RequestSerialization();
        }
        runesAdded = true;
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        RequestSerialization();
    }


    public void SetPillarSprites()
    {
        Debug.Log("---------------WHY MOFO----------------");

        int i = 0;

        foreach (GameObject pillar in pillarRunes)
        {
            if (runes.TryGetValue(i, TokenType.Int, out DataToken index))
            {
                pillar.GetComponent<Image>().sprite = AllRunes[index.Int];
                i++;
            }
            else
            {
                Debug.Log(runes.ToString());
            }
        }
    }

}
frozen igloo
magic spade
#

Yep

cold laurel
#

I highly recommend forcing the sync mode on your class with this class attribute [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]

magic spade
#

I use manual out of the gate in most cases but, yea i checked that a few times lol to make sure i wasnt crazy

cold laurel
magic spade
#

Yea its on the trigger there isnt anything that toggles that object or anything like that

#

Actually moved that logic to only try to use the data for when entered trigger too so it would clearly be active at that point too and still the same thing.

frozen igloo
#

Ah, here's why: Datatoken numbers serialized through JSON lose their tokentype, they will always become doubles because JSON doesn't store what number type it is

#

when you do runes.TryGetValue(i, TokenType.Int, out DataToken index)) that always fails because remote users will never have ints, they'll be doubles

#

I'd use the TryGet that doesn't specify type, then do something like MathF.RoundToInt((float)index.number))

magic spade
#

Gahhhh, that's a rough one. I can fix around that for sure. Thanks Phase lol. Let me play around with it a bit.

fossil kite
#

is synchronizing an array of 128 bools the same as synchronizing an array of 16 bytes, in terms of how much data it sends over the network?

twin portal
#

no, a bool takes a full byte when being sent over the network

fossil kite
#

even in an array?

twin portal
#

would assume so

fossil kite
#

I was kinda hoping it would automatically combine them

#

I might as well test and see

cold laurel
#

Unfortunately.

fossil kite
#

yeesh... alright, thank you!

#

ok yeah, I couldn't resist checking -- 128 bools is 192 bytes, 16 bytes is 80 bytes. so interestingly, it definitely compresses to less than a full byte each, but, not as much as if I manually pack and unpack them myself before transmission. that's too bad

#

actually, I wonder how much of that is built-in overhead. lemme try with bigger numbers

frozen igloo
#

the built-in serializer cares more about speed than packing size, so yeah it's not too surprising that a manual pack can make it tighter

fossil kite
#

ahhh, I guess that makes sense

#

huh, when I turned the byte array size up to 2048, it still only says 80 bytes in SerializationResult, even if I fill the array with random numbers so there's definitely something to send?

brisk magnet
#

trying to make a simple report anyone know why instance_owner is ending up with a null value?

frozen igloo
#

If you want a consistent client to hold ownership of something, you probably want the instance master instead. Instances always have a master, because when one master leaves the responsibility transfers to someone else in the instance (and avoids quest users if possible)

brisk magnet
#

ohhhh I thought instance owner was what instance master was I see now

frozen igloo
#

structuring networking around the master is usually not something I'd recommend but if it's unavoidable or you're already locked into that structure, go for it

brisk magnet
#

yea my network is designed to not care who master is but for some reason the master is having an impact it shouldint hence why im making this to confirm somthing

fossil kite
#

ok yeah, 2048 bytes is 2112 bytes, and 16384 bools is 16448 bytes, that makes sense. if it's for performance reasons then I guess I'll just pack it myself

brisk magnet
#

If im getting a sync failure but cant identify the cause, are there any more detailed logs that might tell me why that I cant get in the client? Post serlization is reporting that the sync was sucsessful but it definitly failed.

meager crystal
#

Is it possible to have a script that mimics the player api?

I recently got inspired by the recent Minecraft horror mod known as The Broken Script. Where in it, your world is haunted by old minecraft players who got trapped in the game and slowly corrupts the world. You'll get player join messages, entity encounters, random structures built on the world, etc.

I wanna do something similar with one of my worlds. I wanna make it so on a very rare chance, the player join notifier says that a player joined. Their username is just a jumbled mess of numbers and letters. You'll occasionally get cryptic imagery and messages on the walls and floor like as if they're using stickers to communicate. You could even occasionally see them lurking outside the boundaries, watching you. Their nameplate bugged, their avatar never loading.

Is this sort of thing possible? Have a script that triggers other scripts that detects when a player joins, and have it display a custom name?

fallow mountain
#

you can simulate with your own custom ui, custom nameplate, custom models etc

#

but you cannot make playerapi actually malfunction as you describe

tulip sphinx
#

@meager crystal youre not really supposed to mess with game's existing ui in any way by tos

timber ferry
#

maybe have a custom join message thing, like M.O.O.N’s join system, look messed up instead of the official one. because that prefab was very popular for join messages

drowsy jackal
#

I am wondering if I should use OnPostSerialization and OnPreSerialization. I guess it only gives a result back and doesn't really help with network sync?

twin portal
#

you'd use it if you need to use it

#

OnPostSerialization at least is good to have it print out the result of the serialization, so you can get a log if something is going wrong

drowsy jackal
twin portal
#

you don't call these functions directly, they are events

#

OnPreSerialization runs after RequestSerialization anyway

scenic sky
#

If you guys don't mind I'd like to put an idea i have here

Iv been thinking about adding players to a list/array again, something iv never been able to crack in years. Iv bene trying to think of work arounds that avoid the whole list thing and just focus on disabling game objects instead like this

turning on a trigger and having a player step in it to trigger the event for them (will probably work but isn't really clean or efficient)

Another one was maybe making using of player objects to stick a trigger to a players wrist or something then using a separate game object that collides with it to send a event to the owner of that object (not even sure if that will work)

Maybe for the list I can Use a foreach loop or whatever the method is to get all vrcplayerapi in the instance. Then construct an array of player ids
Pressing a right or left arrow will cycle through the array and display the name of the player associated with that ID

On player join/leave will reconstruct the array

Have a manual button for reconstructing too

Pressing the button in the middle that shows the players name will.. make them the owner of a game object then send out a networked event targeting the owner of that object to make them disable/enable some game objects

Some concerns I'm having too is what happens to player ids after someone leaves, if player 2 leaves does player 3 become player 2 in the id sense? If so im assuming you would need to reorganize the array/list

Putting that all aside i need to break it all down and do things one piece at a time

The first thing I need to figure out, how do I find players?

I know i can use a trigger with ontriggerenter to find them
I know there's a way to get vrcplayerapis but I'm unsure how to do that one

If anyone is willing to help it would be appreciated

twin portal
#

You use OnPlayerTriggerEnter to get the player that has touched a trigger zone. This event returns the VRCPlayerApi that touched it

#

You can also use GetPlayers to get all players currently in the world

#

yeah I'm not.... entirely sure why you'd need this system if you can just GetPlayers whenever you need to

meager crystal
scenic sky
#

i want to target a specfic player

#

so that i can do things like disable/enable some game objects for them, and stick em on a list

finite sierra
#

and beside that the broken script is a banned mod for a good reason too lol. it does a bunch of things that violate Privacy

meager crystal
#

But it won't appear to be the ghost of a vrchat player without the nameplate and loading diamond

#

Sad

meager crystal
finite sierra
scenic sky
twin portal
#

then all you'd need to do is run GetPlayers when a player joins and when a player leaves, and store their playerID

#

I guess?

#

still unsure why you'd need an array

#

if you'd need to separate the players playing a game vs. all players, then it'd make more sense to have a list

#

but if you're adding and removing from the list when they join or leave, you're just recreating the results that are in GetPlayers

scenic sky
#

i believe I need an array for the idea i want to do.

I want to have a < button > (left arrow, main button, right arrow) and cycle through players. clicking the arrow will change the button text to the next player in the im assuimg array

#

not sure if this is even a good approach

strange token
scenic sky
#

im trying to think of the approach i need to take in order to make this happen

#

is an array needed in order to do this? if so how do i add and remove from it and does it need to be synced stuff like that

#

my knowledge on this topic is iffy, im used to doing other stuff but iv always struggled with getting players and doing stuff like lists/arrays, teams or staff access

strange token
#

Yeah you’d use an array

#

You can either make it an array of strings for each player name or ints for their playerId

twin portal
#

so the hard part isn't gonna be getting the actual list of players, it's working with the array itself, it sounds like

strange token
#

If you wanna save the list you’d use their name so it works between instances

scenic sky
#

as each instance will do its own thing

strange token
#

That helps, saving the names was a pita for me lmao

scenic sky
#

here' ill explain what im trying to do

#

I got my world Club Kitsune, I want to create a system where a player can become a staff member (add themselves to a list assuming they are a patreon or similar) then they will be able to add/remove other players to this list as well. it seems simple but iv never been able to crack it

fallow mountain
#

I guess if you are making a list, it would be array
The simplest list maybe a dropdown menu
Simplest way is add/remove is OnPlayerJoined->add to the array and OnPlayerLeft->remove from array
It will populate the list when you join the world with everyone, etc
But it cannot persist in a difference instance, however if the list is sorted by playerID then it should remain the same if you rejoin the instance (except yourself getting a new playerID but everyone else should have same from before you rejoin)

scenic sky
#

being added to that list will allow them to do things like press buttons or access certain areas

strange token
#

Yeah I tried setting up that exact system in my other world 😛 I’m a bit nervous to assist because idk if I even got the right approach or if I eventually got stuck with that too 🤔 my stress tests showed multiple names in one row occasionally and I don’t think I ever figured it out

scenic sky
#

i feel ashamed to say iv tried this on and off for like 2 years and have never succeeded

strange token
#

My idea for this would be to GetPlayers every time a player joins or leaves, then loop through and compare that list to your known staff members list and null out the player from the GetPlayers list if they’re staff, then you can loop through and display each non-null element to get an updating list of all non staff members

scenic sky
#

i just can't seem to see the bigger picture

strange token
#

That would accomplish the first half at least

strange token
#

I’m pretty sure that’s already like a third as much code as I wrote to get that behavior 😂

scenic sky
#

what is your thoughts on this on the button with a left and right arrow to cycle through the names and display it one at a time

strange token
#

How the buttons are selected and displayed is a bit of a UX decision, in my system I settled for two vertical lists with buttons in between to swap the selected button to the other column, which were essentially “allowed” and “not allowed”

#

Not telling you what to do, just giving more info so you can better decide how you want your UX! 😛

scenic sky
#

thats what my older one looked like too xD maybe it would be wiser to do it that way as it is more useful to know who is or isnt stuff

strange token
scenic sky
#

does the int[] need to be UdonSynced?

twin portal
#

no no, your UI should be a fully playable game of minesweeper. whichever player wins first is the one that becomes the admin

scenic sky
twin portal
#

that's worse than giving it to nobody