#udon-networking

1 messages ยท Page 9 of 1

rose rain
#

Because when player joins it needs to check if "IsBoxTriggered" is true or not.

#

When player interacted before, its saved.

#

Then what happen is, the event is then propagate to other players via RequestSerialization.

#

Then the player locally will check if "isBoxTriggered" is enabled or not.

#

This also works if people Just joined

#

What ever i say here if its wrong pls do correct me.

#

Together we learn in progress.

#

bruh.. Just bruh. my eye blind.

#

Bruh theres issues.. ๐Ÿ˜ฆ

rose rain
#

it seem slike no need "On playerjoin"

rose rain
#

i still cant fix the issue..

First player toggle the hidden box

Second player still can see the box.

Why.

#

I am very confused.

rose rain
#

Can anyone explain why this dont work?

#

This shit is getting out of hand for me.

#

@humble girder

tulip sphinx
#

wha, its no bug, disabled object doesnt run a script on it

rose rain
#

Okay so i checked.. it seems like its not sending infomation to other user / player.

#

why is that so?

obsidian python
#

@tulip sphinx but then why I can transfer the ownership to another player of a disabled object, but not back and forth? It doesn't make sense to me

#

in the video I sent, player 2 recieves the ownership, but he can't give it back

rose rain
#

So it seems like the stuff is not send to other users.. in the world.. why is that so?

#

I test it.. 3 player in the world.

#

first player interact the hidden box.

#

The other player dint recieve any notification or any updates..

#

why is that so?

#

hmm

obsidian python
#

isn't it because you didn't change any value?

#

isBoxTriggered sendChange isn't ticked

#

it won't send any changes to other players

#

also SetOwner and RequestSerialization isn't a good thing doing it both at once, you can't be the owner immediately then sync all the variables, first you have to recieve the ownership transfer

rose rain
#

give me in step by step.

obsidian python
#

so im not too sure, but maybe if you don't change any of your synced values, then I think the OnDeserialization won't run for others

rose rain
#

ahh

#

wait i now testing.. i updated some stuff.

rose rain
obsidian python
#

it has to be ticked, if you want to send out changes for other players

rose rain
obsidian python
#

is it still not working?

rose rain
#

nope.

obsidian python
#

isBoxTriggered Change, you need to put it the "bool newValue" to SetActive()

rose rain
#

like this?

#

but why.

#

When the isBoxTriggered is true.. why do u need the "bool newValue" LOL

obsidian python
#

then put it on the unaryNegation

#

but you want to use that new value

#

that comes from there

#

there are also a lots of example udon graphs of networking in your Packages/Samples/UdonExampleScene/UdonProgramSources folder that you can use to learn

rose rain
#

so.. here the thing

obsidian python
#

some of them actually useful, like button sync, slider sync, toggle sync

rose rain
#

In this picture when u interact, u set box triggered to true.

#

When box is set to true

#

It will do the things it needs to do.

#

While at the mean time, the box is set as Owner and request Serialization for other player.

obsidian python
#

so you wonder, why you need Set IsBoxTriggered and RequestSerialization too to send the data?

rose rain
#

no i am just trying to make myself clear if i am doing anything wrong..

#

Explaining my understanding.

obsidian python
#

but it wouldn't run if another player would like to interact with the box for the first time, because he isn't the owner

#

that player would need to press it twice

rose rain
#

so what is wrong.. what can i do to understand? to make it right?

#

how do i fix it?

#

All i need is a simple, 1 person press button, 1 thing gets hidden, 1 thing get shown, to everyone.. even those who join late.. is so Damn hard.

rose rain
#

i tried setting if its not "Owner" then do the shit..

#

but it just dont work.

obsidian python
#

this should work, but let me test it too

rose rain
#

Wait what once interact straight custom event.. intresting.

#

Heres the full screenshot

obsidian python
#

yes, because it does matter who calls it, if a non owner interacts with it, its getting the OnClick called twice, once in the non owner, and once in the owner too

#

it's my graph, you can use it

rose rain
#

erm..

#

i want to understand it..

#

because i need to.

obsidian python
#

test it first, and see if it fills your needs

rose rain
#

cause this is just 1 part.

#

hmm is it the same as the one u send?

#

i would rather follow via screenshot

#

that i would be able to understand how the logic flow.

#

but thanks once again.

#

been spending like a day for this.

obsidian python
#

i just updated the variable names, so it less confusing

rose rain
#

erm lets says if any Toggle Bool change, this "Toggled Bool Change Event" will update or play right?

#

So.. basically

obsidian python
#

it gets updated for late joiners too

#

because it's a synced value

rose rain
#

hmm.

#

so i dont need OnDeserialization

obsidian python
#

they are both the same thing, but OnDeserialization, you recieve every synced value there, but if you prefer to use "value Change", you can do it that way too

rose rain
#

i dont need this 2..

rose rain
#

So this is my current Graph.

#

this red box.. i dont think need right?

obsidian python
#

you still need it, if you would remove it, it wouldn't update for the owner

#

but it would update for everyone else

rose rain
#

hmm then i can just.. simply.. Event it?

obsidian python
#

you can do it that way too

rose rain
#

So when isBoxTriggered Changed > play custom event.

#

ok.

#

hmm

#

i tried.. and its still not working.

obsidian python
#

can you show your graph?

rose rain
#

Same issue, i have 3 instances.

#

Player 1 touch the hidden box.

#

Hidden box disappear and key appear for player 1 only

#

Player 2 and 3 still unable to see the key

obsidian python
#

can you try replace the isBoxTriggered Change with OnDeserialization?

rose rain
#

like this?

#

alright i will do a test

obsidian python
#

yep

rose rain
#

3 mins to build so gotta wait.

obsidian python
#

3 mins? but you can try it in the editor too

rose rain
#

nah if i try on editor. i cannot control player 2 / 3 and check their response.

obsidian python
#

oh, actually true, i forgot

rose rain
#

Oh shit bruh.. player 2 / 3 clicked on the box

#

straight crash.

#

The issues goes beyond what i am trying to fix here..

#

i did a oppsy..

rose rain
# rose rain

this is a game, spot the mistake i did.. if u see it.. you will face plam.

#

While at the mean time i cook another 3 instance.. try figure out what happen XD its really funny.

obsidian python
#

you didn't call HideShowObject on the owner?

#

but that still wouldn't lead to a crash

rose rain
#

this whole chunk should be deleted.

rose rain
obsidian python
#

ye but it's not connected

#

so it doesn't do anything

rose rain
#

its crash so.. whats the issue. hmm.

obsidian python
#

i have these flying around everywhere xD

#

i usually don't remove my junk codes

rose rain
#

okay simple .. instead of..

#

i will just use "constant bool"

#

lets get cookin.

#

so.. i have no idea whats happening.

#

so its still crash.

#

"COULD THIS" be the issue?

#

For me to know for me to find out.

#

lets get cookin.

obsidian python
#

it just makes the non-owner execute the code on the owner

#

it's needed

#

you could try this too

#

plus you had it target: "All" on that picture, it needs to be Owner

#

in SendCustomNetworkEvent

distant thorn
#

Does vrchat have pure server side scripting?

rose rain
#

Lets get cooking.

obsidian python
#

you aren't changing it for the owner of the object

rose rain
#

Oh ok

#

so set to "All"

rose rain
obsidian python
#

it's fine, but you didn't have it on owner before

rose rain
#

i tried just now also crash.. now i trying "All" with the new updates.

#

lets see

#

i am curious.

#

why and how does it just crash

#

without any error

#

what makes the game just "Crash" like that?

obsidian python
#

infinite loop? xD

#

idk

rose rain
#

bruh now its not crashing. yes

#

but funny..

#

its like swapped.. lmfao

#

For example a player interact the box, the key is showned.

#

the second player doesnot see the key,

#

and when they interact the box, the first player keys is hidden

#

bruh.

#

i think the issues lies on this part

#

When cusom event play, it will check if the ower is pressing or not.. if lets say the owner plays..

#

it will go to true, and will set "IsBox Triggered" bool to True and then RequestSerialization.'

#

While at the mean time when the box triggered bool is set to true. The box changed gets things should be toggled on and off .

#

And only after if its settled, then its Request Serialization.

obsidian python
#

so it works, but not for the owner?

rose rain
#

i think its like doing 2 things twice..

rose rain
obsidian python
#

then change the initial value of the bool, plus you haven't used SetActive after Set IsBoxTriggered for the owner

#

he won't see anything change

rose rain
#

i try like this

obsidian python
#

The OnDeserialization only runs for non owners

#

it doesn't gets called for the owner

#

or value change too, they only run on non owners

rose rain
#

okay crash again

#

what will happen if i move this to there.

#

it will check if its owner, if its owner then do everything.

#

hmmmmmm

#

oh yah but if itsn ot owner nothing will happen this means new joiner touch nothing will happen.

#

Okay seems like it crash again

rose rain
rose rain
#

Could this be the "ANSWER"

#

it dint crash.

#

It seems to work..

#

Everything and everyone seems to see what its suppose to see..

#

okay so what happen is once i clicked.. this happen.. yep everything works.. but its sending SO many network

#

i think i know

obsidian python
#

but if i think about it, it's maybe wouldn't be able to work, if you are trying to disable the gameobject that should also send notification to another object too to enable itself

#

if the object is disabled, i think it cannot do that

#

but you could disable the meshrenderer, not the entire game object

#

thay way, you wouldn't stop your scripts running

obsidian python
#

btw, it turns out the "value Change" event happens on both the owner and non owners too, i was wrong about that

#

only the OnDeserialization runs on the non owners

#

this approach actually works, but i only disabled the meshrenderer, you would still need to disable the collider and interact text

#

Is it what are you trying to do?

rose rain
#

Yes, but u need to check for this .. instead of player 1 toggle, player 2 toggle

cold laurel
rose rain
#

player 3 will restart game and check.

obsidian python
#

@cold laurel but @rose rain wants to interact with that same object too, then disable it and then that script would enable another object

#

@rose rain it probably works, if the non owner can change it, then it's more likely the owner can do it too

cold laurel
obsidian python
#

btw, how can I get the component of the gameobject? in the bottom, that wouldn't work

cold laurel
#

do you just want buttons that disable themselves and enable something else and is synced

#

is that all?

obsidian python
#

yeah, basically

cold laurel
#

ait, gimme 5 minutes

obsidian python
#

mine was already working, but go for it, if you can write a better one

cold laurel
obsidian python
#

i think that's what @rose rain wants, he opens a box, and gets a key from it, then the box should disappear as my understanding

cold laurel
cold laurel
#

Here's the example

#

as you can see, I just set the active state depending on the trigger

#

if it's true then the button is disabled and the key is enabled

#

if it's false it's the other way around

#

the button is just another graph that looks like this

#

it needs no sync

#

so it can be disabled

rose rain
#

Well after all this.. it works.

#

It flippin works.

#

This is the code

obsidian python
#

well, it only took 6 hours to make an object disappear and another appear xD

#

but that 3 min build time is pretty long, I can test my changes in less than 30 seconds

rose rain
#

well. this is the first part.

#

Theres the second part.

#

Touching the key with the lock, and then hiding both of them

#

I am pretty sure its gonna be copy and paste..

#

which i will do that later

#

gonna rest.

obsidian python
#

i think that will be much easier than this

cold laurel
#

this will cause a massive feedback loop :D

#

please set the target to Owner

rose rain
#

Heres the Code again but with instructions.. correct me if i am wrong.

obsidian python
#

im not sure if it's safe from late joiners, you don't plug the "bool newValue" nowhere

rose rain
#

hmm.

#

what do u mean?

obsidian python
#

try open the box first, then join with another player and see if it's synced correctly

rose rain
#

Well i checked again its bugged. it seems like its not working.

obsidian python
#

its not working for late joiners?

rose rain
#

no not working even when in game.

#

i loaded 3 instances.

#

second player press the cube

#

1 and 3 player dont see the key.

#

then i tried player 1 pess the cube, player 2 and 3 cant see the second key.

#

i think this part i need to Unary Negation

#

gonna do one final test before i go to bed.

obsidian python
#

do your key have the VRC Object Sync component?

#

but maybe it's not that necessary

rose rain
#

so i removed it.

#

hmm we need call the expert..

#

also i gonna go bed.

obsidian python
#

mine script was working well

#

kitkat is showed you a script too, why don't try those?

#

alright, have a good sleep then

rose rain
#

Oh will try that later then

rose rain
rose rain
#

i tried this and it dont work.. with sync on..

#

i now trying it with sync off.

#

I tried and it does not work.. gonna try your method.

rose rain
#

Alright its still bugged.

obsidian python
#

you just need to assign the mesh renderer and collider to your script for the box

rose rain
#

hmm

#

i was wondering.. if set active to off.. does it mean everyone have the same?

rose rain
#

gonna try CyanTrigger

rose rain
#

guess i found the issue.

rose rain
#

This 1 sentence.. solved this entire issue.

obsidian python
#

that's what my code does, instead of disabling the object, it disables everything else, mesh renderer, collider and interaction

#

that's why it works

#

yesterday i mentioned it

#

i also had to found it in a hard way, like wasting several hours just to notice I can't transfer ownership of a disabled gameobject too

distant thorn
restive cliff
#

Nope. The client will run the Udon scripts provided by the uploader

#

that uploader is the person who uploaded the world

cold laurel
distant thorn
rose rain
rose rain
#

i am using cyan trigger..

fresh stump
#

Hey guys, I am using a gun script to call in a game object from an object pool, then play an aniamtion and return it to the object pool.
however i am encountering an issue.
there is 3 beacons in the pool. when i spawn all 3 beacons they spawn in correctly and they return correctly. the animation works correctly. when i try to spawn in a beacon the 2nd time for either 3 of the beacons it will be sent back to the object pool immediately. then when i try to spawn each beacon for the 3rd time it works perfectly as intended just like when i spawned it the first time. then the cycle repeats, when i try to spawn for the 4th time it doesnt work, then the 5th time it works. you see what im saying?

I think im having issues with the animation reset somehow not resetting correctly.

anyone got any ideas?

#

ideally i want to completely reset the state of the object so i can reuse it

obsidian python
#

it's maybe not the problem, but you don't need to call SetActive in pool objects. by default, they all turned off, when you try to spawn them they gets turned on, when you return them, they gets turned off

#

You are using it wrong "objectPool.Return(this.gameObject);" you disable the pool, not the gameObjects in the pool

stone badger
# fresh stump Hey guys, I am using a gun script to call in a game object from an object pool, ...

I can't answer the question as to why something isn't working BUT I can offer some advice that might help remove 10% of the code. You are testing for null on objects that cannot be null and testing twice in some cases. If for instance the beaconAnimator is null you world is simply not going to operate. You could test it once in Start if you really, really wanted to but again the fix isn't to skip over code it is to "fail fast" so you can assign it in the editor and get it working. You test if localPlayer is not null twice. You test if objectPool is null. What happened that most of the objects you rely on have not been assigned? You don't things to continue as if there is no problem.

fresh stump
#

Thank you for the feedback @stone badger & @obsidian python

#

I'll see what I can change

obsidian python
#

Is there a limit how many networked object can I have in a scene? is 10000 is a lot? they wouldn't be all active at the same time

cold laurel
#

Also, yes 10000 is an extreme amount

obsidian python
#

another approach would be to instantiate 1000 objects in the fly, then I probably wouldn't need transfer too much data to sync them if I only want to just toggle them on and off, but idk how efficient would be that, instantiate is a very costly operation as i know

cold laurel
#

As long as it's used wisely.

tulip sphinx
#

whatd be a proper way to send it tho, mod 2 over x ints?

#

arrays are still not syncable right?

cold laurel
#

Arrays are very syncable

cold laurel
tulip sphinx
#

love vrc docs

#

so much versions on same topic

cold laurel
#

yes

#

This might also be outdated, as the docs usually are.

obsidian python
#

I'm thinking about a game btw that has multiple minigames in it, like fall guys and crab game where the blocks falls off under the players foot if they stand on it and other minigames, where you need to run around to paint the cubes below you, and others can paint yours too, and the player who has the most painted blocks wins, so they would need a lot of gameobjects, idk why noone recreated this in vrchat, or i have no idea if there's anything similar in the game

cold laurel
tulip sphinx
#

theres a game where theres 3 layers of honeycombs and you throw balls under other players while trying to stay yourself. so like fallguys level but with players breaking stuff themselves

obsidian python
#

i know, i would only need 1 master object who controls them all

tulip sphinx
#

also ofc there vrware with simplified version

obsidian python
#

i wondered if i could have 10 minigames in my game that's rotating randomly

obsidian python
#

@cold laurel alright, thanks for the help, maybe it will take a month or two to make it happen, and i think, it would be a cool game too

timber ferry
#

how can i make this global?

#

it just cycles between gameobjects that are different pool prefabs

#

but if it isn't global, both people would need to make sure they're on the same style of table to play, so i want it to change for everyone

fresh stump
# timber ferry how can i make this global?

Use a synced variable for your int and when someone Click they become the owner of that gameobject, set the variable and call RequestSerialization. Then in OnDeserialization you can have your OnClick method. So everyone will call the same switch

lusty pagoda
#

whats the sorting of getplayers()

cold laurel
lusty pagoda
#

ok so that why i had my own

#

should still work pretty sure

#

wait does that mean getplayers is pure random?

#

or should i mix players myself as its not random enough

tulip sphinx
#

probably while noone joins/leaves it will be the same order each time?

lusty pagoda
#

i create new player array each time

#

unless its server will be passing me same sorting

mighty raptor
#

Does anyone have an infographic of the Udon networking loop? Something people can glance at to reference?

The hardest part I find about networking in Udon is remembering all the steps or constraints. I know the concept of serialization and deserialization, but I want to have a visual way to reference it, instead of having to re-read the docs and formulate it in my head.

I will probably make one myself if there is not one that actually exists.

prisma stratus
hybrid kindle
#

which one is causing the error and how tf do i fix

cold laurel
heavy spindle
#

If somewhere DestroyImmediate is called in your code, replace it with Destroy instead. Though since it doesn't look like it, some logic might have to be pushed to the next tick for anywhere in callbacks the error specifies
Of course, not much can be done if its an sdk thing, just for you

hybrid kindle
#

Great thank you

quick timber
#

hey hey, hopefully quick question about object pools and networking

Have a button trigger to spawn objects from a pool, standard VRC ObjectPool component, nothing fancy. But since updating to Unity 2022, late joiners aren't able to see any spawned objects from before they join the world.

Just wondering how to remedy it, or even just to get a better understanding of what changed to cause the desync on the newer unity. The world is almost a year old and never had this issue until the move.

Is sync OnPlayerJoined handled by the pool (should it be?)

cold laurel
quick timber
cold laurel
#

That sounds normal

cold laurel
quick timber
cold laurel
#

That looks fine too sweat

quick timber
#

I be struggling, like I said it's been fine, even an older build of the same world with nothing changed is fine. it's only the 2022 build (of the same scenes with nothing altered) that has the late join desync issue ;-;

cold laurel
#

and it's fine for players that are already in the instance?

#

does it get fixed for late-joiners when you spawn additional objects?

quick timber
#

it is, totally fine for everyone in the instance, if someone joins late and an object is spawned after they join its fine too

if another object is spawned, sometimes the desynced one will appear, but will be in a different location and will not be interactable until the person who spawned it picks it up

#

Gonna open VRC to get a more definitive answer, will update in a few mins

quick timber
# cold laurel and it's fine for players that are already in the instance?

okay, so I redid all the tests, it looks like the spawner isn't the issue, and not a late join issue either

More that the objects themselves aren't syncing once spawned. If a player spawns an object, its only visible to them until they pick it up, then other players can see it.

I'm thinking it has something to do with the object sync method, being manual instead of continuous o.o

But they're stuck in manual, can't change it, the option is greyed out

cold laurel
quick timber
# cold laurel How are you syncing the position of your objects?

The spawner doesn't have the option. Spawning isn't a networked event, but once the object is called, the spawned objects themselves are VRC pickups with object sync. (Recently switched to MMMAellons smart object sync) and that carried it before.

It seems that it only syncs once interacted with. Which i guess is in line with how manual sync method works on the object sync component.

I'm just trying to wrap my head around what changed between unity versions honestly.

But yeah no networked event nodes on the spawn button itself ._.

fresh stump
#

Does anyone know why OnDeserialization is not called?

        public void Init()
        {
            //Make sure the master is owner of that object
            if (!localPlayer.IsOwner(gameObject))
                Networking.SetOwner(localPlayer, gameObject);

            GetPlayers();

            if (players.Length > 1)
            {
                RequestSerialization();
                Debug.Log("PING?");
            }

            //Repeat the request
            SendCustomEventDelayedSeconds(nameof(Init), refreshRate);
        }

        public override void OnDeserialization()
        {
            Debug.Log("PONG!");
            var playerCount = VRCPlayerApi.GetPlayerCount();
            players = new VRCPlayerApi[playerCount];

            for (int i = 0; i < playerCount; i++)
            {
                players[i] = VRCPlayerApi.GetPlayerById(playersID[i]);

                if (localPlayer == players[i])
                {
                    fPSProxies[i].FetchLocalFPS();
                }
            }
        }
#

its been happening on 2 scripts what just stopped all of suddenly and I can't find where is the problem, sometime if I remove and re-add the udonsharp script in the gameobject it magically starts working again but it's inconsistant

#

What is this line

[Behaviour] RPC SanityCheck/TargetPlayer on SceneEventHandlerAndInstantiator 50e506e7-e632-4720-a134-0325e31c98b3 blocked for Fairplex (local master owner)

Is it what is blocking my RequestSerialization?

strange crane
#

I have a local UI they will choose from one of the answers and if its wrong I'll update this UdonSync variable isWrong. How could I do this?

    public class PlayerData : UdonSharpBehaviour
    {
        [UdonSynced] public bool isWrong;
    }
fresh stump
strange crane
fresh stump
lone zealot
#

I have Player A and Player B.
A is currently Master and owner of some Object that has a synced integer i = 0, on Manual Sync.
If I do:

Networking.SetOwner(Object, B);
Object.i = 5;
Object.RequestSerialization();
Networking.SetOwner(Object, A);

Will that work? Im thinking it wont, but dont have the capacity to fully test this and maybe someone already has...

heavy spindle
#

The hearing it works is just hearsay though

lone zealot
#

Yeah I thought about it again and opted to just not retransfer ownership back. It doesnt really matter who owns it.

heavy spindle
#

I guess another option would be if your value has a finite number of values it could possibly have, could have clients call methods to have the owner set the value

cold laurel
#

Later on when it tries to serialize (if it even gets that far) it will realize you're no longer the owner and just skip it.

stone badger
lone zealot
#

Yeah I was aware. Was kinda hoping VRChat does some weird internal magic that stores who is owner at which point when wanting to change variables...but yeah my hope was slim anyway.
But as I said, Im now doing the "right" thing now, so it doesnt matter to me anymore.

grim stream
#

E

broken rampart
#

is there a way to detect if the instance is a private or public one?

cold laurel
broken rampart
#

big rip

olive cairn
#

Instantiation

Instantiation is currently (2020-06-17) not networked. Instantiated objects cannot be correctly synchronized. The only workaround is to use object-pooling. (Note: Please write a more detailed guide on that)

#

has this changed? if not can someone explain object pooling?

wintry bear
#

https://creators.vrchat.com/worlds/udon/networking/network-components/

VRC Object Pool provides a lightweight method of managing an array of game objects. The pool will manage and synchronize the active state of each object it holds.

To make an object active, the Owner of the pool triggers the TryToSpawn node, which will return the object that was made active, or a null object if none are available. Objects may be returned to the pool by the pool's owner, and automatically disabled, via the Return node.

Late joiners will have the objects automatically made active or inactive where appropriate.

This doc covers Networking Components, Properties and Events you can use in your Udon Programs.

wintry bear
olive cairn
#

oh thanks!!

tulip sphinx
#

instantiating itself wont be 'fixed' since its not broken, just every network object needs to have an id on upload. pool is the most common way around - but it still needs all the objects to be already present in the scene, but you can also create your own sync from the outside (some invisible networked cube handling sync of X instantiated objects)

obtuse echo
#

Any clues on how to combat quest's sleep mode? It's kinda annoying how they can just take off their headset and essentially block some crucial objects from changing ownership.
Like imagine them just blocking your object pool so any new player doesn't even get an object assigned so they can't even use your world.

olive cairn
#

a bit of a hacky solution is only let pc users have prolonged ownership, and have quest users take ownership, change values, and send it back to the original owner

#

or you could have the owner of something send a networked event "pinging" every few seconds and if it stops responding have another user take ownership

#

prevent crucial objects from changing ownership
you mean if a quest in sleep mode owns something nothing else can take ownership? oh

#

the 2nd thing wont work then

obtuse echo
olive cairn
#

they could still go to sleep before finding the pc player
quests take a second after being set down before going to sleep, really hacky but you could watch head velocity?

obtuse echo
#

Is that a thing that can be done?

olive cairn
#

are you using udon graph or sharp

obtuse echo
#

Sharp, but I do know how to actually code it. I'm just questioning whether watching the velocity would help me detect the sleep mode

olive cairn
#

wait nvm, i swear i found something on velocity but cant find it

#

if you have a pc player with ownership at all times, and the ownership is only transferred on user interaction itd be a bit before the quest goes to sleep

obtuse echo
stone badger
obtuse echo
#

I'll look into how the pool works later, maybe it's because of how it does things? But I did try adding a button that takes pool ownership while those quest players were in sleep mode. I saw my debug message, but the usual "setting owner" messages did not appear.

stone badger
obtuse echo
lusty pagoda
#

what proper way of sharing info to other players without giving each player its own object or putting 50 same functions in a script

lusty pagoda
#

i see its not possible ok

vapid pagoda
lusty pagoda
#

that is custom code in end of the day

#

what code exact

delicate bridge
#

Hey guys. I need some help: can I make instantiated game object synced and global without using object pool? I have like 850 game objects that I want people have access to, but making everyone their own object pool with 850 game objects is... well... not a good idea.

vapid pagoda
tulip sphinx
delicate bridge
tulip sphinx
#

@delicate bridge not really, never done it and it supposed to depend on your goal. but basically instantiate object and store it in array so you can find it later, store it position in a synced array. for late joiners spawn as many as you need and assign the position on each one, same for when theres a change

fresh stump
#

Anyone got objectpool experience with udonsharp? Im having an extremely peculiar bug with it.
Client A, the first user, Joins the word. The object spawns and is attatched to them.
Client B, the second user, Joins the world. He can see the object on Client A, but Client B's object spawned for only a moment (according to the logs) and then was destroyed through some unknown secondary route.
Client A can still see the object on Client B.
If Client C joins, Client C can see Client A and Client B's object. Client A and B can see everyones object, including their own.

This makes literally no sense to me

obtuse echo
#

This affects Omegle VR which uses Cyan's Object pool to do most of it's work. And guess what, it relies on the master to handle its objects.

I also visited No Time Two Talk and it seems to have the same issue. I'm 90% sure @sharp solstice is the creator of that and might want to know about this. Sorry if the ping isn't relevant or I'm mistaken, but hope it's okay since you're part of VRChat afaik.

vapid pagoda
#

although im not sure if fax is having this exact issue, but there is a possibility

obtuse echo
#

Kicking them instantly solves it btw

vapid pagoda
#

im sure back in unity 2019, the sleep mode would take up to 5 minutes(?)

obtuse echo
vapid pagoda
#

fax had his issue occur around 1st December afaik

obtuse echo
obtuse echo
meager meadow
faint osprey
#

should i have posted this here? #udon-general message i am trying to make a zombie that comes to you and you have to fight it with a catana but... i have no idea how to make the zombie move

vapid verge
#

Hello everyone, im having this error which i believe it implies that im not the owner of the object im trying to request serialization for, which i dont understand because i have a networking.setowner right before on the same function, any idea of how to fix it?

vapid pagoda
fresh stump
wooden tulip
#

hello im trying to use Github to have a text URL that i can use in my world
ive read that i have to turn my repo to a page , and now that ive turned it into a page
and clicked
https://MyUsername.github.io/Test/
it just brings me into a

heavy spindle
#

you shouldn't use github as a file hosting service but if you really need to, use raw githubcontent

wooden tulip
wooden tulip
heavy spindle
#

Its probably in VRC's blacklist

wooden tulip
heavy spindle
#

I host my own website so I wouldn't know

wooden tulip
heavy spindle
wooden tulip
pearl folio
#

raw.githubusercontent.com is not in the allowlist
the string loading allowlist is currently:

*.github.io
pastebin.com
gist.githubusercontent.com
api.fynn.ai
api-dev.fynn.ai
*.xr-marketplace.com
*.v-market.work
*.vket.chat
*.poly.jp
*.vazar.jp
*.catsudon.net
*.vazarapi.com
wooden tulip
wooden tulip
#

when i go in settings > Pages > Your site is live at (my link)

wooden tulip
#

sucks that i have to do it that way , ;P

#

should be easy to have a button on a github that makes that url

humble girder
wooden tulip
# humble girder What are you trying to solve?

i basicly want to use github to load url text file ,
i used to use Pastebin Unlisted url

but ive gotten githubs link to work n everything , the only issue i have now , is that my repo has to be public , so anyone can yoink my text files through my profile

humble girder
#

Even pastebin is public. It's just unlisted as in not being publicly announced its existent in pastebin website.

wooden tulip
pearl folio
#

not sure that's possible

#

using a gist might be closer to what you want? they're not as prominent on your profile as a normal repo

#

actually i forgot, you can make them kinda "unlisted" like you want

wooden tulip
delicate bridge
#

Hey, everyone. Can I create my own class that can sync? I tried this, but U# compiler says "Cannot sync type 'FitBox.PunchClass[]'"

#

tf with screenshots

humble girder
delicate bridge
humble girder
random parrot
delicate bridge
#

k, thx

random parrot
humble girder
lone zealot
#

Enums in U# are replaced by ints at compile time btw. Enums dont exist in Udon, so they are merely a compiler feature.

obtuse echo
cold laurel
humble girder
pearl folio
wooden tulip
pearl folio
#

there is some way you can get a persistent link, i can't remember how but i did it for YTS

#

as far as collab, yeah fair point

zenith jetty
#

Pay for GitHub, then you can have private repos which deploy Pages sites using a custom domain. Then nothing ties your account to the URL people use to download the files unless GitHub complies with a court order

#

If you use an "apex domain" setup for GitHub Pages you make an A record to their servers not a CNAME to your .github.io

#

So it's fairly stealthy, but not foolproof obviously

#

@wooden tulip ^

wooden tulip
zenith jetty
#

Register domain name, set up DNS per this guide, then change your custom domain to the one you registered in GitHub repo settings for Pages, then you should be done

wooden tulip
zenith jetty
#

On the GitHub side this is what it will look like

#

Note the Custom Domain field

#

Just to be clear, whatever you're working on is NSFW but not illegal, right?

#

I'm all for helping someone hide their furlust from their friends, but if this is something other than that you may want to seriously reconsider hosting it on GitHub, review their TOS to be sure you're not violating it by posting violent or extreme content, I believe they have a few rules there

humble girder
#

Isn't using github.io domain a sole purpose for being in vrchat whitelist? Otherwise you could use amazon S3 to host files.

wooden tulip
zenith jetty
humble girder
#

Pretty much just skip a custom domain and that should be enough for loading into vrc without having to enable untrusted urls.

zenith jetty
#

So maybe the best of both worlds is, pay for GitHub so you can make the repo private but use the github.io domain

#

It won't show up on your list of public repos

#

But if someone guessed the repo name they'd know it was yours

#

๐Ÿคท๐Ÿผโ€โ™‚๏ธ

humble girder
#

If someone could guess the repo, that would be worse if using custom domain. Because they would have to use their real name to register a domain name. Cant say about "free domain names" though, those are also sketchy.

zenith jetty
#

WHOIS privacy services are very commonplace - my registrar includes it for free on all domains they sell, they will only give over your information in response to police requests

tranquil hull
#
solar crescent
#

If someone is leaving a map I work on, can I force everyone to spawn in a lobby again to recalibrate roles? Never did that...to let everyone on a map hop back into entrance. Maybe on leave checking the role of the leaving bean and if it was the important role that needs to be put to someone else...activating a trigger that teleports everyone on playground? x_x

timber ferry
shy path
#

what you could do is put what you currently have in OnDeserialization() into a new function and call it inside OnDeserialization() and after changing value in OnClick()

timber ferry
#

that works, thanks

delicate bridge
#

hey, am I missing something? It should be able to sync, no?

cold laurel
#

It's telling you that you can't sync the variable of type PunchClass[]

delicate bridge
#

there's literally nothing...

cold laurel
fresh geode
#

I'm hoping someone can point me to a tutorial I've not seen yet. What I have is a boat as a child of an object with a hinge joint on it and Use Motor enabled. This makes the boat move in a circle, but the boat is in a different location for every player and I'd love for the boat to be in the same location for every player. Can this be networked?

humble girder
fresh geode
#

awesome. easist fix to what a thought was a complicated problem. thanks!

wispy arrow
#

How is one intended to sync a jagged array in UdonSharp? I absolutely need to sync a Color[][][] (for a game mode in my game), however I don't know what to do instead of a single Color[][][]?

humble girder
hot shale
#

I'm currently unable to test my code, because the offline-test does not let me join in my offlineworld for some unknown reason

#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using UdonSharp.Video;
using Mono.Cecil;


namespace SaphiAssets
{
    [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
    public class SetPlaylist : UdonSharpBehaviour
    {
        public USharpVideoPlayer video;

        public VRCUrl[] playlist = new VRCUrl[0];
        public bool loopPlaylist;

        public bool streamMode;

        void Start()
        {
            
        }

        public void setPlaylist(){
            if (!Networking.IsOwner(gameObject))
            {
                Networking.SetOwner(Networking.LocalPlayer, gameObject);
            }

            if (video.CanControlVideoPlayer())
            {
                video.TakeOwnership();
                SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "setPlaylistEvent");
            }

            
        }

        public void setPlaylistEvent()
        {
            video.playlist = playlist;
            video.loopPlaylist = loopPlaylist;
            if (video.CanControlVideoPlayer())
            {
                if (Networking.IsOwner(gameObject)){
                    video.TakeOwnership();

                    if(streamMode){
                        video.SetToAVProPlayer();
                        video.SetNextPlaylistVideo(0);
                    }else{
                        video.SetToUnityPlayer();
                        video.SetNextPlaylistVideo(0);
                    }
                    video.PlayNextVideoFromPlaylist();
                }              
            }
        }

        
    }
}

This should set a playlist of a UdonSharp Video player, and sync it to all players.
"setPlaylist" is invoked via a button

#

the line "using Mono.Cecil;" caused an issue

wispy arrow
#

Is OnDeserialization() called on the client that called RequestSerialization(), or no

frozen igloo
wispy arrow
#

I see, whilst I'm here, what is the average latency for Manual synchronization (if it's being called once per second or something close to that)

frozen igloo
wispy arrow
#

I see, if it's just a boolean or a basic integer, it generally shouldn't take long then, I'd assume

frozen igloo
#

yeah, manual is the fastest way to do that

wispy arrow
#

I'm pretty new to networking so this is one hell of a learning curve to get a hold of, but I'm hoping I can get it to work.

Speaking of, would it be possible to make a system to detect once everybody has received the data that has had serialization requested? I have a large array (2304 elements) that might take a moment to sync and I can't let the game start until everybody has it

distant abyss
frozen igloo
wispy arrow
#

I'm uhhh, a little dumb, how would I use a player pool for that?

stone badger
#
VRC Object Pool provides a lightweight method of managing an array of game objects. The pool will manage and synchronize the active state of each object it holds.

Objects are made active by the pool via the TryToSpawn node, which will return the object that was made active, or a null object if none are available. Objects may be returned to the pool by the pool's owner, and automatically disabled, via the Return node.

When objects are enabled by the pool, the OnEnable event is fired, which an UdonBehaviour on the object may listen for. Note that the OnEnable() event fires before the udon Start() event.

Late joiners will have the objects automatically made active or inactive where appropriate.
#

You can see if you have a pool and each player spawns one in response to your sync event you can count the number of OnEnable events that occurred. After a little time each player could return the object to the pool so it was available the next time you needed it.

wispy arrow
#

That's an interesting concept, I'll definitely look into that

frozen igloo
# stone badger ``` VRC Object Pool provides a lightweight method of managing an array of game o...

I would not recommend that, that's not what I meant. vrc object pools still have a limiting factor - only one person can own it at a time. If multiple people try to take ownership and spawn things at the same time, they will overwrite each other. It is not guaranteed that each and every person's change would be accounted for. This would have all the same limitations as a simple manual synced behavior with a synced int

What I meant by a player pool is a system that assigns a unique object to each player, so everyone owns their own separate unique object. If you're not fighting over objects, you can be certain that all the data is intact.

this is one example of a player pool: https://github.com/CyanLaser/CyanPlayerObjectPool

GitHub

A VRChat system that will assign a unique object to every player in the world. - CyanLaser/CyanPlayerObjectPool

wispy arrow
stone badger
obtuse echo
distant abyss
#

Vrchat

strange token
#

Does IsUserInVR work correctly when checking remote players, or is it supposed to be a local method?

#

A VR player didnโ€™t seem to notice I was desktop when some code ran on his end last night, but when I checked with two desktop players it seemed fine

cold laurel
strange token
#

๐Ÿ‘ knowing that is good enough for me, but Iโ€™ll double check it tonight ig ๐Ÿค”

#

@cold laurel I feel like I never heard of you then you appear in Argus and now youโ€™re one of the most active code helpers I see ๐Ÿ˜‚

#

Thanks for all the support ๐Ÿ™

rocky summit
#

Question:
A player who is not the owner of a networked switch (with a synced boolean) toggles it.. between these two methods:
โ€ข Transferring ownership to the local player and then activating the switch
โ€ข Sending a networked event to the owner to toggle it

What is the comparison between these, Is one method notably better than the other?

Or is this negligible?

shy path
#

because if he had to send network event to the owner to toggle it there would be tiny delay for him to see the toggle for example open or close the door

rocky summit
#

Right, so essentially it would be better to just transfer ownership, I imagine the owner transfer runs on all clients in order to update who the owner is, but the cost of that action is probably minimal

So I think Method 1 is better in the mass majority of cases

heavy spindle
#

@shy path @rocky summit This is typically incorrect. Ownership transfers take more time as the instigator sends a request to the Object Owner and the Owner can either approve or deny the transfer request. All of the clients then have to be notified of the ownership transfer and then the instigator can send events to other clients.

If the ownership is going to be kept for a long time and the instigator is going to do a lot of event sending and receiving, then the transfer can be beneficial beyond the initial cost, but for a simple network synced toggle, sending the owner a request to do something is the fastest thing you can do for everyone. The only case I can see it necessary to transfer ownership in this case is if you need access to the instigator's player object.

frozen igloo
# heavy spindle <@725782488571445681> <@951570510490271814> This is typically incorrect. Ownersh...

What you're describing is the behavior when you have implemented OnOwnershipRequest. When a script has this event implemented, it changes the behavior of ownership transfers to make them require sign-off by the original owner. But, even in that case, the person taking it will still see themselves as the owner immediately and be able to change values with no delay. It's just that a moment later they will receive a response back from the previous owner, and either they will be confirmed as the new owner or they will be denied and the object will be returned with variables reverted.

When you do not implement OnOwnershipRequest, there is no confirmation or extra round trip, so the cost is minimal.

Regardless of which way ownership transfers happen, they both share something in common - when you take ownership, you have it immediately and can set variables directly. This is good for giving players instant feedback when they click something, as the state of the world can match the state of the synced variables directly. Synced variables are guaranteed to be eventually consistent which means that it's possible for clients to have a desync momentarily, but eventually, they will settle. As long as you are properly using the synced variables to drive the state of the world.

The problem with using network events is exactly as @shy path said - latency. When you send a network event to the owner and tell them to change it, you don't get that immediate feedback, you have to wait for them to send the state back. Unless you fake it, and set the state early, before they have gotten back to you. The problem with doing that is that you would be throwing away the guaranteed eventual consistency. There are likely certain race conditions and orders that things could happen where you could get permanently desynced.

This is similar to why I would not recommend just using network events for syncing state without variables entirely. They do not have the same guarantees that variables do, and you're entirely on your own to deal with that problem.

I would not recommend network events for simple toggles because you have to choose between latency or potential desyncs. A quick ownership transfer and setting the variable is best. That being said, if this object is more than just a simple toggle, there are other factors to consider. Having more synced variables on this object would increase the overhead of taking ownership and sending variables. Frequently transferring ownership may also present problems for certain systems that constantly need to account for that. In those cases where transfer is not wanted because it is just a single toggle embedded within a larger system, I would likely go with the network event solution and just eat the latency cost, without trying to sneak out of it.

heavy spindle
#

My world's risk for that happening is next to nothing so I can tolerate something like that which I do, I guess it could come down to how tolerant someone is to these types of things. Beyond that, for my network toggles, I have the owner set a state bool that is synced, so it's eventually synced and what's on remote is preferred though this only happens on deserialization on a manually synced object. If the object is never toggled again, then yeah "permanent desync"

stone badger
# heavy spindle My world's risk for that happening is next to nothing so I can tolerate somethin...

So many posts about hypotheticals in a world where we are able to demonstrate reality. I and many others use synced variables. The system is documented, well understood and works. If there is a better solution, i.e. simpler, faster, more reliable would you (or someone) post an example? That way we can all learn the better system. I for one do not understand what "my world's risk" means. What is present or lacking such that synced variables would be the inferior solution?

heavy spindle
#

I think you misunderstood my system. What my system does is a user sends a custom network event to the owner who flips a bool to toggle something. That bool is udon synced. My world doesn't have much risk associated with a client locally changing the state before the owner sends the actual state for an instantaneous effect. This is in opposition to a user taking ownership over an object to change the bool.

#

Perhaps I also did a bad job at explaining what I do

frozen igloo
# heavy spindle I think you misunderstood my system. What my system does is a user sends a custo...

Right, if you are not setting the state early then you are correct, there is no risk there. But that adds extra latency. By contrast, taking ownership and setting variables can set it instantly with no latency. And you would be right that that could have risks associated with it, but synced variables and ownership transfers have been built precisely to fix that problem and ensure eventual consistency

#

either way you do it, setting the state early before you've confirmed the change can result in desyncs. The difference is that network events do it blindly, while synced variables are heavily controlled and built to handle exactly that problem

heavy spindle
#

and I'm okay with accepting that risk

frozen igloo
#

it's.. not.. what confused2

heavy spindle
#

Here Ill just send code

#
using UdonSharp;
using VRC.SDKBase;
using UnityEngine;

namespace Murder
{
    [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
    public abstract class SyncedInteract : UdonSharpBehaviour
    {
        [UdonSynced] private bool state = false;
        [HideInInspector]
        public bool _local_state = false;
        private bool _waiting_for_remote = false;

        public override void OnDeserialization()
        {
            SendCustomEventDelayedSeconds(nameof(_TriggerOnDeserialization), 0.1F);
        }

        public void _TriggerOnDeserialization()
        {
            if (_local_state == state)
            {
                // The variable is now updated to match remote.
                if (_waiting_for_remote) _waiting_for_remote = false;
                return;
            }
            // The local state does not equal the remote state immediately after interact. This should be checked to provide a smooth experience.
            if (_waiting_for_remote) return;
            _local_state = state;
            _OnStateFlip();
        }

        public override void Interact()
        {
            _local_state = !_local_state;
            _waiting_for_remote = true;
            SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, nameof(UnaryNegateState));
            _OnStateFlip();
        }

        public void _ResetState()
        {
            if (state) SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, nameof(UnaryNegateState));
        }

        public void UnaryNegateState()
        {
            if (Networking.IsOwner(gameObject))
            {
                state = !state;
                _TriggerOnDeserialization();
                RequestSerialization();
            }
        }

        public abstract void _OnStateFlip();
    }
}
frozen igloo
#

good lord that's just way more compliated than it needs to be. The network event is also just a generic flip, and does not specify which state to change it to, which means you could easily end up fighting the latency and flip it the wrong way if multiple people click it at once

heavy spindle
#

I did experience that, yes though that's how I want it to be

frozen igloo
#

WHY

#

multiple people fighting over a switch is terrible

heavy spindle
#

It's meant to be chaotic

frozen igloo
#

look, you're welcome to make that design decision for your own projects but it's incredibly important that you don't spread that to other people's projects where they don't want that element

cold laurel
heavy spindle
#

I will relent that yes I can very easily just have events to set to specific states and that will resolve fighting

#

Alright ๐Ÿ‘

#

How would you have it, then?

frozen igloo
#

this is all you need, seriously it's this easy



using UdonSharp;
using VRC.SDKBase;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public abstract class SyncedInteract : UdonSharpBehaviour
{
    [UdonSynced]
    private bool _state;

    private void Start()
    {
        _OnStateFlip();
    }

    public override void Interact()
    {
        if (!Networking.IsOwner(gameObject)) Networking.SetOwner(Networking.LocalPlayer, gameObject);
        _state = !_state;
        RequestSerialization();
        _OnStateFlip();
    }

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

    public abstract void _OnStateFlip();
}

heavy spindle
#

How does VRC handle multiple people trying to take ownership at the same time?

frozen igloo
#

it automatically compares the timestamps and the one who did it last gets authority

heavy spindle
#

and if people continue to try to take ownership? Does it do this every network tick?

frozen igloo
#

no, it handles it when it receives messages that people try to do it

#

if they continue to try to take ownership, there will be temporary desync. But the moment everyone stops, it will settle on the last message

#

I'd probably also throw in a ```
private void Start()
{
_OnStateFlip();
}

to ensure that the state matches the variables at the beginning
heavy spindle
frozen igloo
#

Every message you send comes with a timestamp. There is a server in the middle that relays messages back and forth between the players. The server uses those timestamps to track who did what and at what time. If multiple things happen within a short time span, it can discard old messages that have since been overwritten. But it will never discard the latest message, and will ensure that everyone has received that latest state

stone badger
#

As an aside... one of the measures of code is the level of effort to do what are considered routine things. The developers of languages and APIs don't go out of their way to make adding numbers and rotating objects hard (or impossible) so if one finds themselves writing all sorts of code to handle "cases where this could be wrong" it may be time to revisit one's code.

fresh stump
#

Are there any know issues with checking component objects on synced stuff? I have a toggle that enables something on a gameobject component that is on every avatar, in 2019 it works fine but in 2022 it will CTD any vrchat client that isnt the person who clicked the toggle.

fresh stump
#

Yea after a bit more testing, its a 0 error instant CTD and I literally dont know why

#

and I just confirmed it happens to every client that isnt the one to click the button

#

same script functions flawless on 2019

frozen igloo
fresh stump
obtuse echo
fresh stump
#

For all I know, this is a weird test thing where running 3 clients from the same user just confuses 2022 when changing the owner from "Zack3D" to "Zack3D" and it just... blows up

obtuse echo
last remnant
#

Hey there, I haven't wrote udon in a while but I can't figure out why this script isn't working.
It's a manually synced toggle in which a player interacts, takes ownership, changes variable and requests serialization. Then the player calls a method to do stuff and the remote players call the same method triggered by onDeserialization. The code works fine for the owner of the object but any remote players instantly crash when the player interacts with it.

Any thoughts or solutions would be much appreciated ๐Ÿ˜„

vapid pagoda
# last remnant Hey there, I haven't wrote udon in a while but I can't figure out why this scrip...

have you tried debugging the cause of the crash? have a look at this https://udonsharp.docs.vrchat.com/runtime-exception-debugging/

You will often find yourself with programs that can only be debugged in-game. In order to catch these errors and make them easier to understand, U# includes a runtime exception watcher that will look for exceptions from VRChat's output log. The watcher will then output the script and line that threw that exception to your editor's log.

last remnant
#

I will give it a go thank you!

stone badger
# last remnant Hey there, I haven't wrote udon in a while but I can't figure out why this scrip...

It would be a lot easier to read and comment if you were to post the code with code markdown. I'm not going to type all that code into an editor. You have several odd choices. The most notable is your insistence on handling OnPlayerJoined with a custom event. It isn't necessary and there are no cases where VRChat "bugs" and does not sync on join. If it did you can report it but in any case requesting serialization isn't a fix.

#

Note also that your Toggle method only varies by a single value. SetActive is true or false depending upon StartingState. Nothing else is different so the if is not needed and simply setting the active and toggle to the value of StartingState is equivalent.

last remnant
#

It used to bug in the past, players would fail to sync on join

#

This code is old

#

I believe it's fixed now, just a quick copy paste edit

#

One sec I'll include the code

stone badger
#

Your issue could have something to do with your setting of the UI toggle. One must be aware that setting the value like that will fire the toggle event. If you handle that somewhere it can end up in a loop.

last remnant
#

Oo I see

#

Ah thank you I will check. I forgot there was a way to toggle without triggering the event I think. That is probably it! ๐Ÿ˜†

stone badger
last remnant
#

โค๏ธ

#

I appreciate you so much

#

I've been scratching my head

#

Will update if it works

last remnant
#

It worked!

#

Thanks :3

#

Tom is the goat

fresh stump
violet mist
#

hey, does anyone know if player tags are synced? like, going off the example in the documentation, if a new player were to join, would that player be able to see the fact that someone else in the instance had previously been given the "chef" role? or are these simply local tags

also, if they are synced, does anyone know at what time they are synced ? OnPlayerJoined ? the first OnDeserialization call ? etc.

Documentation page mentioned: https://creators.vrchat.com/worlds/udon/players/getting-players/#setplayertag--getplayertag

frozen igloo
violet mist
violet mist
#

oh btw, does anyone know if the whole "variables won't sync immediately after setting an object's owner" bug has been fixed yet? (since I know some sections of the docs can be a bit outdated)
like, can I just assume that

Networking.SetOwner(localPlayer, gameObject); syncedVariable = value; RequestSerialization();

will work reliably, or do I have to implement some wonky Update loop to wait/check for successful Ownership transfer requests for sync to be reliable?

the bug in question: https://udonsharp.docs.vrchat.com/networking-tips-&-tricks/#known-issues

frozen igloo
#

It is now entirely safe to take ownership, set variables, and request serialization all at once

violet mist
patent robin
#

Hello, very beginner question but we can't mix sync modes on a single behavior right ?
I have a behavior with a float property that should be updated continuously and a Vector3 property that should only be set at specific times, so the ideal solution would be to have the float on "continuous" and the Vector3 on "manual", is that an option ?

tulip sphinx
#

no, use two behaviours or accept the overhead. are you sure you need float as continuous? not the most popular data type for that.

#

oh sorry had a brain fart

#

for some reason float registered as bool in my head

patent robin
#

Haha np. About the types, this is for syncing a rope's visual, so I need its length (the float) to be updated constantly as the player moves, while its target position (world space) can be set only once the rope is attached

#

Right now the behavior is synced continuously, since this is only visual it's not a problem if some data is lost

#

but I was wondering if there was a "cleaner" way to do it (answer seems to be no)

meager meadow
patent robin
# meager meadow You have the rope attached at one end to the Vector3 and at the other to a playe...

I should probably try that at some point !
Will make a bigger post later with 1) what I'm trying to do, 2) what I tried and 3) how it doesn't work, but just to summarize I have a shader that draws the rope using a target world position and a length (using its own transform as the origin), so I thought I could use a VrcObjectSync to sync the rope's transform and a U# script to sync the target and length (and update the materials).

echo pasture
#

I have an issue i've been trying to figure out. I have an gameObjectA that gets spawned by a VRCObjectPool and within gameObjectA is another gameObjectB with and udon script that is set to UdonBehaviourSyncMode manual. Within the same update cycle I am spawning gameObjectA, updating a UdonSync variable in gameObjectB and then sending a RequestSerialization. The result is the gameObjectA being spawned, but the variables in gameObjectB are not synced.

I believe the reason for this is because both changes occur in the same network update so the gameObjectA (and gameObjectB) get spawned but since the udon script for gameObjectB hasn't started up yet it isn't able to receive the variable changes.
I've tried to make a workaround where the owner of the object will send a RequestSerialization every second (as a less frequent version of continuous sync behavior) in an attempt to update gameObjectB variables after the game object has spawned. However when testing this it seemed like take multiple resync attempts to finally sync up between players. My testing had an average of around 103 gameObjectBs that need to be synced and took as long as 3 minutes before everything looked like it was synced up. The variables that needed to be synced were two bools that effected an animator on gameObjectB.

Has anyone else had this issue when trying to sync variables with a freshly enabled gameobject? or know a good workaround for it?

obtuse echo
# echo pasture I have an issue i've been trying to figure out. I have an gameObjectA that gets ...

Are your synced objects disabled by default? I think there is some kind of initialization that happens when the object is enabled for the first time. So you should try to leave them on by default so it does the initialization on startup. This way, when the pool enables the objects, it might actually work without delay, and maybe even sync without having to resend data.

Although the VRCObjectPool always had some quirkiness to it in, my experience at least. You might want to write your own if all else fails.

echo pasture
# obtuse echo Are your synced objects disabled by default? I think there is some kind of initi...

The synced objects are part of an object pool, so they get disabled by the pool at the start. Whether that happens before each object has a chance to startup or not I'm not sure. I believe I enabled all the objects in the pool, but I'll have to double check. I guess another thing I could do is spawn every object in the pool once before despawning them so that they have a chance to startup.
Thank u for your input

echo pasture
#

after checking my scene the synced objects are enabled, but they are disabled by the VRCObjectPool when playmode starts.

obtuse echo
echo pasture
obtuse echo
violet mist
# echo pasture The sub objects (gameObjectB) are always enabled locally, however they do get di...

So while idk the exact details of your networking setup or the type of world you're trying to make, apologies if it's a bit of an obvious solution, but I'd also like to suggest the classic "if possible, try moving all your sync logic to one, always-enabled GameObject that controls all those other GameObjects" just in case you haven't considered that.

i had a similar issue in my world recently, and that was my solution. maybe have arrays for the variables of each object, have the objects and the controller interact with each other, etc.

echo pasture
# violet mist So while idk the exact details of your networking setup or the type of world you...

I hadn't thought of an always-enabled GameObject, that definitely sounds like it might work. One of my concerns with that solution though is that my project is a kind of tool that other users can use. The number of GameObjects the always-enabled GameObject would need to keep track of would be alot (my testing example had around 103 of them) which could potentially lead to a huge DataDictionary that could exceed the limits. The idea seems like it would mesh well with another idea I had for a future feature so I'll trying testing out the limits for this. Thank you for the suggestion.

violet mist
#

Btw, has anyone used [FieldChangeCallback] with synced arrays? I know I have to change the entire array for the callback to fire, so I do, and that works locally, but it doesn't even try to run OnDeserialization() on remote clients despite the owner successfully firing RequestSerialization() and OnPreSerialization() after that first local callback successfully fires.

When an array is synced, does Udon just update the relevant elements in the array that have changed? Or does it assign an entirely new array and fire callbacks properly? And regardless, would anyone happen to know why OnDeserialization() wouldn't even bother firing like that?

Notes: The object with the sync logic is always enabled. Relevant code snippet attached in case it's any help (The code in OnDeserialization() is just meant to print log messages that communicate whether or not it ran).

violet mist
#

Update: It only fires OnDeserialization() if the array is initialized to something like syncedIndexes = {"!!!", "!!!", "!!!"}. For whatever reason, new string[3] doesn't seem to work

But now it's still not triggering the FieldChangeCallback, which leads me to believe that arrays just get modified when they're synced, and not replaced...

Oh well, I can work with this now at least, but I'd still like clarification on that if anyone knows

cold laurel
#

And VRChat refuses to sync arrays that are null, or have null elements

violet mist
#

do you know if it replaces the array OnDeserialization tho ? or if it just updates the elements of the array that have changed ?

lone zealot
frozen igloo
frozen igloo
#

that used to be how it was to be fair

#

it changed to reduce allocations like 2 years ago

violet mist
frozen igloo
#

right, it doesn't trigger fieldchangecallback when you change a value. It never did. It only triggers the callback when the array itself is switched to a different array. On remote users, that only happens if the length of the array changes. If the owner changes it to a different array of the same length, the owner gets the callback but remotes don't.

It used to just trigger the callback on all deserializations because it was always making a new array, so people wrote code for that assuming that it was indicating some value inside the array changed, which was never the case.

slender moat
#

i am not in play mode ._.

#

How do I detect when two player colliders, well, collide?

tulip sphinx
#

place generic triggers on players

frigid dragon
#

I need a little help with my system, I don't know the correct way to do it

I have the following, my system uses an Synced int to control the activation of objects.
When someone clicks on a button, I want the owner to process the ID and then send a custom event so that the object with a certain ID is activated.

my first approach was to the Owner change the ID, then RequestSerialization and then send a SendCustomNetworkEvent.
The problem I encountered was that sometimes the send custom network event was received first than the ID change, thus breaking the system.

my second approach was, do a FieldChangeCallback for my ID int.
then when the Owner changes the ID and the ID change was detected, it executes.
This solves the problem, but now when a LateJoiner enter the world after a object is activated the last object is activated erroneously.
the expected behavior is that the person only sees the object when someone presses the button
.

humble girder
frigid dragon
#

OnDeserialization dosen't Trigger when the Late joiner enter the world?

frigid dragon
#

Hum interesting
Thank you, I think I can solve this now

#

;D

frigid dragon
frigid dragon
#

How can I do it so that it doesn't activate the object erroneously?

#

that only activates when someone presses the button

#

i think i figure out of a way*

humble girder
#

What "activate the object erroneously" really does?

frigid dragon
humble girder
frigid dragon
#

basically what I need is SendCustomNetworkEvent that carries some data

#

=/

humble girder
#

SendCustomNetworkEvent can't carry data.

frigid dragon
#

I know ;-;

#

I'm trying to access the DeserializationResult
but I don't know how to do it ;v

#

public override void OnDeserialization(DeserializationResult dr)

frigid dragon
#

The documentation says that DeserializationResult have sendTime
that is The time in seconds at which this message was sent

basically I can know how long ago it was sent.
I can use this to know if I need to activate the object or not

humble girder
frigid dragon
#

I am getting this error,

error CS0246: The type or namespace name 'DeserializationResult' could not be found (are you missing a using directive or an assembly reference?)

I'm looking in the documentation for what I should include to be able to use the DeserializationResult

frigid dragon
#

Thank you

#

I just thought of a really dumb way to solve this.
always ignore the first OnDeserialization;

wispy arrow
#

If I'm intending to network a lot of values, does using smaller data types (i.e. short instead of int) allow me to continuous sync more values, since a short is smaller in memory than a regular 32-bit integer?

frozen igloo
#

It will use less bandwidth

wispy arrow
frozen igloo
#

Per object. If you have multiple scripts on an object it's shared

#

Does not extend to children

wispy arrow
#

Is there any upper limit for how much bandwidth a world can use in total for syncing?

#

Or can you just have as many syncing behaviours as you want (up to the point that either Photon or the player's network gets overloaded)

frozen igloo
#

Manual sync can handle much, much more per serialization. You're not limited to 200 bytes, it's more like 65000

cold laurel
#

Also depends on how many serializations you make per second.

#

almost 0 data with many serializations will still clog the network

frozen igloo
#

Well yeah, there's the overhead of the sync itself. Just because you don't have any user data doesn't mean you're sending nothing

cold laurel
#

Mhn

#

Also, why is SimulationTime closer to Time.realTimeSinceStartup for VR players than desktop players?

frozen igloo
cold laurel
#

yes

frozen igloo
#

How much?

cold laurel
#

vr players are generally less than 0.25 behind

#

while desktop is generally more than 0.25

frozen igloo
#

Oh right you mean further ahead yes. I thought you were implying VR was behind

#

Yes that makes sense because desktop players sync at 5hz, vr players sync at 10hz

cold laurel
#

ah

#

that's unfortunate

#

I guess I could crank up the serialization rate to compensate

#

but uh, I'd rather not spend 1/4 of my serialization budget per object

#

So I ended up making my own SimulationTime that lags behind just enough for 4hz

#

Which desyncs the movement compared to the locomotion animations

#

but eh

frozen igloo
#

Well, it depends what your purpose is if using simulation time. If it's to match the player then that's still what you want. If it's behind that's because the player is behind too

cold laurel
#

I'm manually (de)syncing player position and rotation

#

because the world isn't in world space

frozen igloo
#

Then yeah I'd use the players simulation time because you want the player's ik to match their position. It's higher latency yes, but that matches desktop players

cold laurel
#

but then I have to spend 10 serializations per second just for player sync if you're in VR

#

Along with any pickup you might have

#

so I can have a whole total of 3 pickups before hitting 40 per sec

frozen igloo
#

Yes? That's what you're committing to if you want to sync your own player position

cold laurel
#

Fair enough

#

I just wish we had another sync mode

#

like, and unreliable manual sync made for high frequency and low bandwidth

frozen igloo
#

This is why objectsync switches to a higher rate while held and doesn't allow udon to just arbitrarily set it to use that high rate

#

Which is something that people have wanted for a while but can't be done because bandwidth limits

#

We're all beholden to the same masters - photon

cold laurel
#

Wait really?

#

Are you able to elaborate on what those limits are set at?

#

It just seems ridiculously low at the moment

frozen igloo
#

The systems which limit bandwidth are pretty arbitrary and do not have human-readable limits. We're still discussing ways that we can translate or measure that to be more meaningful to creators.

slender moat
#

Hi there, I'm also working on a system for my world, here are my intentions:

After two players are near each other and collide over a certain amount of time, GameObjects will instantiate around them in an explosion, do a little bounce animation, then return to the play and the world will keep a count of how many GameObject each player's collected and a world total.

Here is my Code so far :

#

Are there any suggestions or tips, I believe I also need to develop the Follow player/Return count system.

#

Please Ping me <3

slender moat
#

My code does not seem to be working, I think it has to do with the colliders. Does anyone have alternative

meager meadow
slender moat
slender moat
slender moat
#

My 'Game objects' do not seem to be spawning/Instantiating and I'm not sure why.

Full Code:

meager meadow
slender moat
#

There are triggers:

https://creators.vrchat.com/worlds/udon/players/player-collisions/#physics

Then theres the VRCPlayerAPI:

https://creators.vrchat.com/worlds/udon/players/getting-players/#setplayertag--getplayertag

these are the documents i used, but i cant seem to find a solution

Udon has three ways to detect when a Player and an Object Collide - Triggers, Physics, and Particles.

These nodes are useful for getting an individual Player, a group of them, or all of them.

slender moat
#

I write new code, Unity crashed when i attach it to the udon Behavior component :( when does it eeend

fresh stump
#

OnTriggerEnter must be attached to the same gameobject which have a trigger component, and you can't access to the players gameobject via Udon. Also note that remote player trigger looks like this image. This is still something that they have to fix afaik so meanwhile you might have to calculate distances manually in your update method

slender moat
#

So what youโ€™re saying is that since I cannot access the Playerโ€™s Collider I must make a new game object with a collider. Attach it to each player in the instance and detect collision with those?

dusk basalt
#

question, if i make someone the owner of an object, does it affect the children of the object too?

dusk basalt
#

alright thanks!!!

fresh stump
timber ferry
#

how do i make this synced for late joiners? it works for people who are in the instance, but if someone joins late, the Unlocks[] won't be enabled, and the button itself won't be disabled

#

these are the relevant variables

humble girder
humble girder
timber ferry
#

alright, i can mess around a bit more then. The main reason i used a network event was because i was translating a graph to U#, and i didn't account for that part

humble girder
timber ferry
#

i did make it about a year ago, so i knew even less about networking than i do now

humble girder
timber ferry
#

so, should i put the

money -= cost;

moneyManager.SetProgramVariable("money", money);

into the Buy() method instead?

humble girder
timber ferry
#

ok this is what i have now, it seems more correct but did i do everything right?

#

(i changed line 76 to SendCustomEvent(nameof(EnableUnlocks)); because i realized it makes more sense)

timber ferry
#

so, while it does mostly work, it seems that a lot of things will already be bought when a second player joins (for that second player) even though they shouldnโ€™t be. and if i have a button that unlocks other buttons, all of those will already be bought aswell, even though they shouldnโ€™t be either

harsh pebble
# timber ferry (i changed line 76 to `SendCustomEvent(nameof(EnableUnlocks));` because i realiz...

Yeah so that's a good call, you don't have to call OnDeserialization yourself, it's automatically called when the network owner changes the variable and requests serialization. So when the other players receive the new value from the server it will execute whatever is in OnDeserialization. This is where you'd have logic to check the states and values of your synced variables and execute your other methods to have their end match the client that changed it

#

What you could do if I'm understanding this right is, within your custom EnableUnlocks, have that event check the udon synced variables and enable/disable things accordingly. That way when it detects a change and runs OnDeserialization, it'll send the local event but within that event it references the synced variables to enable/disable stuff accordingly in theory . Not sure if your using many udon synced variables but that's what I'd play around with and your setters can set the states of objects based on those vars

timber ferry
#

well, the money varible iโ€™m getting from another script has [Udon Synced, FieldChangeCallback] and the โ€œboughtโ€ variable only has [UdonSynced]

#

otherwise the other variables arenโ€™t synced

#

iโ€™m not really sure what you mean, cause i still donโ€™t fully understand these getters, setters, and serialization events, but i added a check at the beginning of EnableUnlocks, where if โ€œboughtโ€ is false it does nothing. is that about right?

stone badger
#

Second you might take a day to better understand C# code conventions. It isn't that not following them creates a direct problem but rather inventing a new convention generally doesn't help. So I don't know if you copied the code but take the Debug.Log statement for example. What is the benefit of the markup? I know it will display in color but if coding is the issue then markup is just getting in the way of being able to drop lots of Log statements in your example.

#

It looks like the Buy method could be private. The { return; } statement at the top doesn't require the braces.

#

And more ๐Ÿ™‚

#

Keep things simple to reduce unintended issues.

timber ferry
#

iโ€™d be happy to learn

humble girder
timber ferry
#

alright

stone badger
# timber ferry do you have any good sources on that youโ€™d recommend ?

The docs are definitely a place to hang around but it won't "teach" you stuff. I think it is more about practice and that doesn't have to be a game or a world or anything. It is just setting up a situation, a problem that you need to solve Resize something, change it's color, position, rotation, etc. Make it bounce, have it make a noise. And that has to all be networked. Code eventually starts to make sense because of the repetition.

timber ferry
# stone badger There are a few steps you should consider in an effort to better understand code...

this is the code as a text block btw, so someone could actually help

[UdonSynced, FieldChangeCallback(nameof(Bought))] private bool bought = false;
private float money;

public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
    if (!player.isLocal) return;

    money = (float)moneyManager.GetProgramVariable("money");

    if (money >= cost)
    {
        Bought = true;
    }
    else
    {
        Bought = false;
        Debug.Log($"<color=lightblue><b>{this.name}:</b></color> <color=orange><i>Player did not have enough money!</i></color>");
    }

    Buy();
}

private void Buy()
{
    if (bought)
    {
        money -= cost;
        moneyManager.SetProgramVariable("money", money);
    }
    
    Networking.SetOwner(Networking.LocalPlayer, this.gameObject);

    RequestSerialization();

    SendCustomEvent(nameof(CheckBought));
}

public override void OnDeserialization()
{
    SendCustomEvent(nameof(CheckBought));
}

public void CheckBought()
{
    foreach (var item in unlocks)
    {
        item.SetActive(bought);
    }

    if (previousObject != null) { previousObject.SetActive(!bought); } 
    if (soundEffect != null && bought) { soundEffect.PlayOneShot(soundEffect.clip); }

    this.gameObject.SetActive(!bought);

    Debug.Log($"<color=lightblue><b>{this.name}</b> bought was {bought}!</color>");
}

private bool Bought
{
    set
    {
        bought = value;

        CheckBought();
    }
    get { return bought; }
}
#

also, i just add the markup cause i find it kinda fun. it's not really necessary

#

(i also do it after i finish everything else, so i'm not actively adding markups while making the logs)

timber ferry
#

so, i changed the code a bit to what i thought was better, and edited the code block above, but now it just isn't synced at all somehow..

humble girder
stone badger
#
public override void OnDeserialization()
{
    SendCustomEvent(nameof(CheckBought));
}
#

what is the point of a custom event here? It does far more than check whether something has been bought and it is called as part of the Bought setter? Quite atypical.

#

I've never understood why people call GetProgramVariable either. I've never, ever done that once.

timber ferry
#
  1. my goal is i want to enable the Unlocks[] and disable PreviousObject if the money is greater than or equal to the cost, and have it synced for all players and late joiners.

  2. do i not need GetProgramVariable? the reason i used it, is because i used graph for much longer than U#

  3. i have OnDeserialization call the "check bought" event because i was trying to copy from the picture below.

stone badger
#

I don't write graph but I think there are peculiarites due to the graphical nature of the code. Assuming it has been converted to UdonSharp I don't think GetProgramVariable is necessary. You can reference the value of object properties directly in UdonSharp. And I don't believe that raising that event in graph was needed (maybe I don't know) but rather it was a choice that was made. No need in UdonSharp however because you can just call the method directly.

#

I don't get what you are doing but notice how OnPlayerTrigger is written for example. The if test can be written a bit more succinctly but importantly you get a log message in either case (bought or not) for debugging purposes.

#
Bought = (money >= cost);
Debug.Log($"{name} Bought={Bought}");
#

You then call Buy (whether bought or not) and sync (whether changed or not). It's confusing.

timber ferry
#

so, i think iโ€™m gonna sort of restart with the script, and go from there. i also feel like a lot of it is unnecessary and overcomplicated, so iโ€™ll re-write it how i would if i wasnโ€™t thinking about syncing yet

timber ferry
#

okay, back to basics. here's my script, how should i make it sync the right way?

private bool bought = false;
private float _money;

public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
    if (!player.isLocal) return;

    _money = (float)moneyManager.GetProgramVariable("money");    // I'm using GetProgramVariable right now, because "money" is private.

    if (_money >= cost)
    {
        bought = true;

        _money -= cost;
        moneyManager.SetProgramVariable("money", _money);

        EnableUnlocks();
    }
    else
    {
        bought = false;
    }

    Debug.Log($"<b>{this.name}:</b> <color=cyan>Bought = {bought}.</color>");
}

public void EnableUnlocks()
{
    foreach (var item in unlocks)   // Enable the Unlocks[]
    {
        item.SetActive(bought);
    }

    if (previousObject != null) { previousObject.SetActive(!bought); }    // Disable the previousObject if it isn't null

    if (soundEffect != null && bought) { soundEffect.PlayOneShot(soundEffect.clip); }    // Play the soundEffect is it isn't null, and bought = true


    this.gameObject.SetActive(!bought);    // Disable self so this button can't be activated multiple times

    Debug.Log($"<b>{this.name}</b> <color=lime>EnableUnlocks was called</color>");
}
humble girder
timber ferry
#

what exactly i want to be synced, is the enable unlocks method

#

so when a player enters the trigger, i want the money, and any objects that get enabled or disabled to be synced for everyone and late joiners

humble girder
timber ferry
#

well the biggest thing that matters is that all the objects that should be enabled or disabled

#

the money is already synced for late joiners, cause thatโ€™s handled in a different script

#

so i need the active/inactive state of the unlocks, previous object, and โ€œthisโ€ to be synced

humble girder
timber ferry
#

good point, maybe all that matters is the โ€œboughtโ€ variable, since all the objects active state are set based on that

timber ferry
#

so should i simply add [UdonSynced] and use request/ondeserialization, or should i use the equivalent of OnVarChanged? thatโ€™s what i didnโ€™t know what to do in the beginning

humble girder
timber ferry
#

ok so, with my understanding, i thought this would be correct, but the things don't enable for everyone. ( @humble girder )

[UdonSynced] private bool bought = false;
private float _money;

public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
    if (!player.isLocal) return;

    _money = (float)moneyManager.GetProgramVariable("money");    // I'm using GetProgramVariable right now, because "money" is private.

    if (_money >= cost)
    {
        bought = true;

        _money -= cost;
        moneyManager.SetProgramVariable("money", _money);

        Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
        RequestSerialization();

        EnableUnlocks();
    }
    else
    {
        bought = false;
    }

    Debug.Log($"<b>{this.name}:</b> <color=cyan>Bought = {bought}.</color>");
}

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

public void EnableUnlocks()
{
    foreach (var item in unlocks)
    {
        item.SetActive(bought);
    }

    if (previousObject != null) { previousObject.SetActive(!bought); }

    if (soundEffect != null && bought) { soundEffect.PlayOneShot(soundEffect.clip); }


    this.gameObject.SetActive(!bought);    // Disable self so this button can't be activated multiple times

    Debug.Log($"<b>{this.name}</b> <color=lime>EnableUnlocks was called</color>");
}
restive cliff
#

maybe try disabling the renderer component or a child gameobject with the renderer instead of the game object the synced script is on?

stone badger
# timber ferry good point, maybe all that matters is the โ€œboughtโ€ variable, since all the objec...

All the code seems to be getting in the way of your understanding UdonSynced variables. I would put this particular attempt aside for a moment and simply sync a single Bolean value. Have the action of the sync display/hide something or perhaps display the value as a string. You want to be sure that the basic mechanism is understood and working. That gets obscured when you introduce arrays of objects and moneyManagers and all the other stuff. If one of those parts is mucked up the thing doesn't work and you aren't 100% which part is faulty.

#

You can't be setting bought = false like you have done. It is a synced variable whether you choose to sync it or not. If you change the value you sync it, not sometimes, always.

#

It looks to me that you have _money defined as a property and are using it as a simple variable. If it only used in the OnPlayerTrigger method it doesn't need to be and shouldn't be a property.

timber ferry
timber ferry
#

well then i'd need to disable the renderer and collider, which is why i simply tried disabling the gameobject, instead of each thing separate

stone badger
#

One should avoid two things that are commonly done. The first is directly thinking in terms of properties like SetActive and game objects, renderers, colliders and such. Think in terms of concepts and you would set the game object to "un-buyable". How that is done is encapsulated in a method. If that takes 1, 2 or 3 properties on 1 or more components it is all in that method. And it is where you can make it buyable again by reversing those settings.

#

The second one is don't write code in the OnPlayerTriggerEnter method. It is an event that signals something needs to occur but it shouldn't be the container of that code. It means if you wanted some other event to take care of it you would have to move all the code instead of moving one method call. It also means you could theoretically test it without having to actually set off the trigger.

timber ferry
#

alright. i'm pretty sure i know why this isn't working. i changed the code to what i have below, and considering everything works fine for the player who steps on the button, it seems that either OnDeserialization simply isn't running for the other players, or bought isn't getting set for all players

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class UnlockButton : UdonSharpBehaviour
{
    [UdonSynced] private bool bought = false;

    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        if (!player.isLocal) return;

        CheckBought();
    }

    private void CheckBought()
    {
        if (!Networking.GetOwner(gameObject).isLocal) {
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
        }

        float _money = (float)moneyManager.GetProgramVariable("money");    // I'm using GetProgramVariable right now, because "money" is private.

        if (_money >= cost)
        {
            bought = true;

            _money -= cost;
            moneyManager.SetProgramVariable("money", _money);


            if (!Networking.IsClogged) { RequestSerialization(); }

            OnDeserialization();
        }

        Debug.Log($"<b>{this.name}:</b> <color=cyan>Bought = {bought}.</color>");
    }

    public override void OnDeserialization()
    {
        foreach (var item in unlocks)
        {
            item.SetActive(bought);
        }

        if (previousObject != null) { previousObject.SetActive(!bought); }

        if (soundEffect != null && bought) { soundEffect.PlayOneShot(soundEffect.clip); }


        this.gameObject.SetActive(!bought);    // Disable self so this button can't be activated multiple times

        Debug.Log($"<b>{this.name}:</b> <color=orange>OnDeserialization was called</color>");
    }
}
#

is there a way to have a console in-game that shows logs? it would be helpful to test networking

#

(i have the !Networking.IsClogged and !GetOwner.isLocal, SetOwner things, because i copied those from a networked script i have that i know works

stone badger
#

Good work on CheckBought... see now nice it keeps OnPlayertriggerEnter? Now you have to do the same with OnDeserialization. I'll suggest a method named Apply() and always put the stuff you need to be applied on the OnDeserialization there. That way you always know to call Apply and the player that sets the values will call Apply() rather than OnDeserialization().

#

There is no benefit checking for the owner before setting the owner whether the player is the owner already or not doesn't matter overall. But you shouldn't do it where you have since you haven't decided to change bought yet. You only need to assign the owner if you update bought.

#

I have no idea what IsClogged i checking for but I would remove it. What value can there be in skipping the RequestSerialization "sometimes"? The world (and software in general) must work or fail not skip over stuff.

#

Is it likely that soundEffect will be null? Again, set it and play the sound or test it once when starting.

#

As for debugging, some folks have a panel viewable in-game. I always thought that would be worthwhile but I've not implemented it. If you test in PC VR you get all the log statements in a file which is handy.

#

As a general rule I add a lot of logging to methods. It helps me track what is happening and the order of the method calls. But I recommend when you can to call them at the start of the method. A failure in the method will mean you don't get a log message if you do it as you exit.

restive cliff
#

I highly recommend keeping the gameobject with the synced script active at all times to ensure that code will run

timber ferry
#

i do also have a little bit of documentation in a ReadMe which explains what each script does, so the user will be informed that removing the audiosource reference is fine, because of the null check

timber ferry
#

i also can remove the โ€œIsClogged,โ€ iโ€™m not sure what it does either, but i only had it temporarily since i copy+pasted.

as for the checking owner before setting, in the script i got that from, it had a comment which said this: โ€œRemoves warnings when setting owner if you were already the ownerโ€

#

also, from what i gather, i only have to do SetOwner after i change a synced variable, and not before?

stone badger
timber ferry
#

got it

timber ferry
#

well, i have this now. still doesn't work somehow, so i'm still thinking it's bought not syncing right, or OnDeserialization not running. i tried looking for in-game loggers, but the one i found was broken, and i've tried Varneon's, but there's no documentation on how to log with his console.

i posted the full script this time, in case there's else something i'm doing wrong that wasn't seen in the slightly cut versions

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class UnlockButton : UdonSharpBehaviour
{
    [SerializeField] private MoneyManager moneyManager;
    [SerializeField] private AudioSource soundEffect;
    [SerializeField] private GameObject meshObject;
    [SerializeField] private GameObject displayObject;
    [SerializeField] private UnityEngine.UI.Text titleText;
    [SerializeField] private UnityEngine.UI.Text costText;

    [SerializeField] private string unlockName;
    [SerializeField] private float cost;

    [SerializeField] private GameObject[] unlocks;
    [SerializeField] private GameObject previousObject;

    [UdonSynced] private bool bought = false;
    private BoxCollider thisTrigger;

    private void Start()
    {
        thisTrigger = this.GetComponent<BoxCollider>();

        if (costText != null)
        {
            costText.text = cost.ToString("$#,####");
        }

        if (titleText != null)
        {
            titleText.text = string.Format("{0}:", unlockName);
        }
    }

    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        if (!player.isLocal) return;

        CheckBought();
    }

    public void CheckBought()
    {
        float _money = (float)moneyManager.GetProgramVariable("money");    // I'm using GetProgramVariable right now, because "money" is private.

        if (_money >= cost)
        {
            Networking.SetOwner(Networking.LocalPlayer, this.gameObject);

            bought = true;

            _money -= cost;
            moneyManager.SetProgramVariable("money", _money);


            RequestSerialization();

            Apply();
        }

        Debug.Log($"<color=lightblue><b>{this.name}:</b></color> <color=cyan>Bought = {bought}.</color>");
    }

    public override void OnDeserialization()
    {
        Debug.Log($"<b>{this.name}:</b> <color=orange>OnDeserialization was called</color>");

        Apply();
    }

    public void Apply()
    {
        Debug.Log($"<color=lightblue><b>{this.name}:</b></color> <color=orange>Apply Started</color>");

        foreach (var item in unlocks)
        {
            item.SetActive(bought);
        }

        if (previousObject != null) { previousObject.SetActive(!bought); }

        if (soundEffect != null && bought) { soundEffect.PlayOneShot(soundEffect.clip); }


        thisTrigger.enabled = !bought;    // Disable these, so that you can't buy the same thing multiple times
        meshObject.SetActive(!bought);
        displayObject.SetActive(!bought);

        Debug.Log($"<color=lightblue><b>{this.name}:</b></color> <color=lime>Apply Successful!</color>");
    }
}
restive cliff
#

could you elaborate how it's not syncing right? For example, people already in the instance not seeing the changes and or late joiners not seeing the changes

timber ferry
#

iโ€™ve been mostly just testing with2 clients in the same instance, and the way it doesnโ€™t sync, is that nothing in the Apply method happens for anyone except the player who stepped on the button

humble girder
timber ferry
#

in unity yes, i get every log except the OnDeserialization one

humble girder
timber ferry
#

i figured

humble girder
real timber
timber ferry
timber ferry
humble girder
grand orchid
#

So um, given the pins are 2021 whats the latest best place to learn to network sync an object so that late joiners see its state. E.g. enable/disable an object. Looking to learn what i can just not sure on what is the best method or place to find that info. Cheers.

vapid pagoda
tulip sphinx
#

@frozen igloo pin it already, hard to search for it every time. ๐Ÿซ  you can always update later

grand orchid
#

AHhhh very helpful thank you...

strange crane
#

I forgot exactly how to go about dealing with a local input field and then send the input out to everybody.

timber ferry
#

oh wait, i have found a different log

#

so it's trying to work, but just doesn't do anything?

humble girder
timber ferry
#

yeah i just wasn't sure which log that was at first

timber ferry
humble girder
timber ferry
#

good point, no there isn't. i'm gonna try making a new log real quick though, cause i'm not sure if those are from before or after i made the Apply function

#

hold tf on, i just tested without changing anything, and it worked perfecly. i'm gonna try late joining now

#

bruh

#

it just somehow works after nothing changed since wednesday

#

only one issue though, if the non-instance owner steps on a button, money does not go down. i probably just need to SetOwner for the money manager though, because i'm not

#

(oh, and the sound plays once for every button purchased for a late-joiner, so it's really loud)

humble girder
timber ferry
#

true

stone badger
#

Exactly... you need to determine for yourself what is not sync'd, what is sync'd for current players and what is also sync'd for late joiners. You write the code to handle them individually.

timber ferry
#

yeah i just hadn't thought thoroughly about where to put the sound, because i was testing so long

stone badger
#

Playing a sound seems like it is part of your "bought" processing but it is just something you choose to do at that time. Make it work independently and then you decide where to make it happen.

timber ferry
#

i was actually just adding it to CheckBought

stone badger
#

Right but it isn't part of "buying".

timber ferry
#

well, CheckBought is where this happens, so i figured this is where it should be

public void CheckBought()
{
    float _money = (float)moneyManager.GetProgramVariable("money");    // I'm using GetProgramVariable right now, because "money" is private.

    if (_money >= cost)
    {
        Networking.SetOwner(Networking.LocalPlayer, this.gameObject);

        bought = true;

        _money -= cost;
        moneyManager.SetProgramVariable("money", _money);

        SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, nameof(PlaySound));

        RequestSerialization();

        Apply();
    }

    Debug.Log($"<color=lightblue><b>{this.name}:</b></color> <color=cyan>Bought = {bought}.</color>");
}
#

also, i don't really remember, does NetworkEventTarget.All mean the owner sends an event to everyone, or the other way?

cold laurel
timber ferry
#

oh okay. so what does the Owner target do again?

cold laurel
#

It sends the network event to the owner of the object.

timber ferry
#

okay, thanks. also thanks to the others who helped with this script, i definitely learned a good bit

timber ferry
timber ferry
#

i think

stone badger
#

It's lego blocks

timber ferry
#

well, i do want the sound to play for everyone in my case

stone badger
timber ferry
#

well, having it in that CheckBought method only plays it for in-instance people. i was thinking about a toggle to only play it locally though

timber ferry
#

i have this, and it works exactly how i want

// this is in the CheckBought method
if (globalSound)
{
    SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, nameof(PlaySound));
}
else
{
    PlaySound();
}

if globalSound is true, it plays for everyone in-instance, and not for a late-joiner
and if it's false, it only plays the sound for the player who used the button

stone badger
hushed ginkgo
#

Is there any way to check to see if a player any kind of instance permissions such as the ability to kick players from the instance?

main hill
#

Looking for a leaderboard/scoreboard example - does not have to be across instances just for the duration of the game. My current experiment is a number of players shooting at targets and I just want to display the top, say 3, players on a leaderboard. I've been searching discord and the interwebs and have not been able to find anything useful (yet). Any pointers would be appreciated - I'm OK with either Udon Graph or UdonSharp examples. Thanks!

vast agate
#

On a different note, is there a way to check udon overhead on a world? I used build and test and there is a big delay on some things, but I don't know if its the world or my PC as I've been having memry related issues

main hill
timber ferry
#

i had a friend tell me about some sort of replay system a couple days ago. he said it records every udon event, and when a player joins, it will replay each event in order so they everything gets synced properly. does anyone know what he was talking about, or have extra info about it?

humble girder
lone zealot
nimble prairie
#

im trying to make a day night cycle and most of it is already done, just having issues with applying the quaternion parameter to late joiners
this setup does serialize the value but applies it to the master/other players instead of the player that just joined

#

or at least thats what it did, now it doesnt do anything

tulip sphinx
#

request serialization is called by object owner, other players recieve ondeserialization event

#

is it animating itself somehow then and you need to set rotation only once?

nimble prairie
#

exactly

tulip sphinx
#

well as a simple getaway you can onplayerjoin - local player is Master-set rotation (variable)-request serialization, on deserialization - set obj rotation

#

this will update rotation for everyone when someone joins

nimble prairie
#

like this?

rancid depot
#

you dont need request serialization at all if you set the variable to continuous sync

#

you only have the master actually do the rotation, then whenever the data comes over the network you rotate the cube for everyone else

#

Also I would use FixedUpdate instead of LateUpdate, just because fixed update will ensure that it will always rotate at the same rate

rancid depot
nimble prairie
#

which is why im doing it with manual

#

fixedupdate is actually a good idea

rancid depot
#

Yeah but also calling RequestSerialization every LateUpdate isn't a great idea.

#

That's alot of networking data.

#

I figured out a solution anyways.

#

Use a Master Variable and Local Variable. If the local variable gets too out of sync, then force it to sync.

#

in the example here, if the sun is 3 degrees off from the master, than it syncs the rotation to the master variable.

nimble prairie
#

genius

#

thanks both of you

#

only needed to know how to sync the rotation

#

even if it were just an approximation

#

because it rotates so slowly

rancid depot
#

Unfortunately networking is hard ๐Ÿ˜”

nimble prairie
#

but this is even better

#

checking if the rotation is too far off, then syncing if it is

#

actually cool

#

thanks again

nimble prairie
rancid depot
#

yes

nimble prairie
#

alright

rancid depot
#

oh yeah @nimble prairie the thing i made wasn't properly syncing with late joiners. i removed this and suddenly it worked so if you have issues i would try that

nimble prairie
#

ahh good catch

tulip sphinx
#

not like the sun is going to move faster or change direction

rancid depot
#

it hypothically only ever syncs once

#

then from there it should never need to do it again

#

there is probably still a better way of doing it but regardless it should still work

#

actually i see what you mean now

#

technically you're right you dont need to have a continuous sync variable

tulip sphinx
#

animator+setting motion time once probly most efficient, no need for an update event at all, tho there will be a small desync but for daytime should be negligible

rancid depot
#

if the update is just turning a transform its not too horrible but ultimate yeah a animator would probably be better

#

not only just because it would run better, but it gives you more options to do more things

nimble prairie
#

it gives me the option to work with euler angles lol

#

might switch to that

#

but i dont know how to operate an animator with udon

#

maybe just trying stuff out will work

rancid depot
#

i usually just drive animation parameters with udon, kinda like how you would with avatars

nimble prairie
#

thats the thing im stuck at

#

how do i modify animator parameters with udon?

rancid depot
#

You would make a animator variable, then use Animator.SetBool, Animator.SetFloat, or Animator.SetInt depending on the type of variable you're using

#

kinda like this

nimble prairie
#

wait i need to use that node???

#

i was skipping over it all this time

#

because i thought it was just a bool to toggle the component

rancid depot
#

no thats done with this

nimble prairie
#

even though its using fixed time

rancid depot
#

Here i'll just DM you the asset for it, a little easier than remaking it off a image.

nimble prairie
#

yo cheers

#

gonna test it out later cus im online with friends in that world that uses it currently

rose forum
#

hello I have a problem with my deck of cards, it works perfectly with one person in the instance but as soon as anyone joins the cards disappear and when you try to spawn a card they appear for a second and disappear,
im sure that this is a sync issue, but i dont know how to fix it, i have tyred adding in RequestSerialization node at the end but that's about it..
any help would be greatly appreciated!

nimble prairie
finite folio
#

Guys, can you help me please? How can it be done in such a way that when a player walks through a fiery anomaly, it starts to ignite and at the same time all players see the player burning. What do I need to do? ๐Ÿ˜…

I have a different type of trigger

https://sun9-80.userapi.com/impg/3hb4vnvFS5ETA0TIvThFgUspVqJvrgXHtWzK_A/f-NUe1aEXYM.jpg?size=1574x639&quality=96&sign=1b02d077796c075370b3b1d75f517a11&type=album

https://sun9-36.userapi.com/impg/jvc0VUSFQqIm36Y7Ol3AIFMfIj_4Yh9Ijkcbow/HdGjysByhBw.jpg?size=1147x689&quality=96&sign=785e4ea1a0c6bc965b6c82634b222927&type=album

tulip sphinx
#

@nimble prairie using utc would make it precise only for 3% of world's population thovrcAevSip

nimble prairie
#

thats where this question comes into play

crimson matrix
#

Ok so, how would I go about telling the owner of an object to update it's value? Working on an FPS world and I'm a bit stumped on how to properly handle players damaging each other.

#

Players have objects assigned to them from a pool that contains the relevant values like health.

#

Currently, my implementation only works for if a player gets hit by a projectile on their screen. That's not ideal, I need it so the player that shot the projectile sends the hit, passing that by the owner to apply it.

#

In a way that allows tracking who sent the hit ideally, for stuff like scoring and killfeed.

cold laurel
crimson matrix
#

I'm using an object pool.

cold laurel
#

Great!

#

Every time you hit someone you'll want to add that to a buffer of "events"