#udon-networking

1 messages · Page 33 of 1

frozen igloo
#

just have a synced bool and if it's true that means it's playing

#

and when you start it playing, do a sendcustomeventdelayed by the audioclip length to turn that bool back off

#

and then instead of transmitting it by a network event, you would check the bool in ondeserialization. That's the event that happens when you receive synced data

#

however if this is not an urgent project, you could also use the open beta to get access to onvariablechanged, which simplifies that use case a bit

sullen vector
frozen igloo
#

it's just the time in seconds

sullen vector
#

Ah, alright

#

just wanted to make sure I was using the right customeventdelayed

#

I assume the sendcustomeventdelayed is attached to the interact?

frozen igloo
#

yes, but more than just there. What happens if someone clicks and then leaves? You need to make sure that everyone does the sendcustomeventdelayed, but then when it happens you just check if you're the owner before setting it to false

sullen vector
#

If someone clicks and leaves it just plays for the rest of the people there

#

which is how it would work on the original TF2 map

frozen igloo
#

yes, but it would never turn the synced bool off. If someone joins later, they would be told that it's currently playing when it's not

sullen vector
#

Ah, right

#

I can't seem to find the node that sets my bool's value anywhere

frozen igloo
#

it's not in the search menu, you get it by dragging the variable into the graph and holding ctrl

sullen vector
#

How's this so far? not finished yet but this is what I've done

#

I know I still need to get rid of the network event, just wanted to get the main part sorted out first

frozen igloo
#

sendcustomeventdelayedseconds is not a "wait" function, so it doesn't interrupt the flow. Instead you give it a completely different function and that function will be called after the duration specified

sullen vector
#

so, what needs moving?

frozen igloo
#

well right now you're just blindly toggling playing, I don't think that's what you want

#

you need to explicitly set it to true or false

#

in the place it is currently, you would set it to true

#

and then in the event that gets called by sendcustomeventdelayedseconds, you would set it to false

sullen vector
#

I looked it up and people were using unary negation, didn't know there was a specific node to enable and disable

frozen igloo
#

unary negation would be used for a mirror toggle. It just flips the bool from true to false or from false to true

sullen vector
#

what's the node I should be using then?

#

the hard part about googling udon is that it comes up with really old versions

frozen igloo
#

you don't need a node, set variable comes with a toggle

sullen vector
#

all that's there is a drop box and an input

frozen igloo
#

oh guess not

#

in that case you need a bool const

sullen vector
#

so the order should be set playing, customeventdelay, and then another set playing?

frozen igloo
#

no, customeventdelayed does not interrupt the flow. Everything that follows the white line happens immediately

#

you need to make a new custom event and then have it call that

sullen vector
#

Alright, this is what I've got so far. How would I set up the OnDeserialization part?

frozen igloo
#

instead of sending a custom network event on interact, you need to first setowner to the local player, then call PlayJukebox, and then call requestserialization

#

you can also move the set playing true to the interact, after setting owner

#

also make sure that playing is a synced variable and the udonbehaviour is set to manual sync instead of continuous

sullen vector
#

Aren't I getting rid of PlayJukebox though?

frozen igloo
#

not the event itself, just the network event

#

it's good to keep that separate from the interact because you need everyone to call playjukebox whether they received it from the interact or from the ondeserialization

#

so you'll also need to ondeserialization > if playing > sendcustomevent playjukebox

#

also in stopplaying, you'll need to check if you're the owner and also requestserialization in order to sync in manual mode

sullen vector
#

just to be clear, where does the first requestserialization go?

#

the one for PlayJukebox

frozen igloo
#

anywhere in the interact

#

after setowner

#

requestserialization is how you say "I have new data that I want to send to other people"

sullen vector
#

and then you call PlayJukebox after set playing?

frozen igloo
#

yeah

#

interact happens for the person clicking it, ondeserialization happens for everyone else

#

so you need to make sure both call playjukebox

sullen vector
#

Does this look good for the interact?

frozen igloo
#

yep

#

the serialization doesn't happen immediately (thus it's just a request) so that's why it doesn't matter where it is. But it may make more sense logically to happen after setting the bool to true

#

like "you take ownership, you set the value, and then you sync the data"

#

just to be more readable and easier to understand what's actually happening

sullen vector
#

I'm confused where this ondeserialization goes, everything I've done so far seems to have a place already

frozen igloo
#

ondeserialization is what happens when everybody else receives the synced data

sullen vector
#

So it'd be attached to another set playing, and a sendcustomeventdelayed

frozen igloo
#

you already have sendcustomeventdelayed in the playjukebox, so that's not necessary

sullen vector
#

ah, right

frozen igloo
#

so just call playjukebox

sullen vector
#

just the set playing then?

#

and the event

frozen igloo
#

no, set playing is a synced variable so in ondeserialization you are receiving that, not setting it

#

you need to plug playing into a branch, and only call playjukebox if it's true

sullen vector
#

Like this

frozen igloo
#

yeah

sullen vector
#

This is stopplaying by the way

frozen igloo
#

you need to plug the localplayer into the isowner

#

and also when you modify a synced variable, you need to call requestserialization

#

that's pretty much it. The only other thing I can think of is that you probably want to block the interact while it's playing. To do that you can just set DisableInteractive true in playjukebox and then set DisableInteractive false in stopplaying before the branch

sullen vector
frozen igloo
#

yep

sullen vector
#

I assume disableinteractive would only apply to the button it's applied to, and not the other buttons with the script

frozen igloo
#

well this script is the one that has interact, so that's the one you want to disableinteractive

sullen vector
#

the TF2 map makes it so you can't change the song at all until the current song is done, but considering the effort to get this far I think I can ignore that part

frozen igloo
#

no it's really easy

sullen vector
#

to disable interaction for all buttons?

frozen igloo
#

oh hm it might be more annoying in graphs because udonbehaviour array isn't a thing

#

oh wait actually I think it will cast dynamically, one second

#

there, do this

#

oh wait wrong node, getcomponentsinchildren not just getcomponents

sullen vector
#

Isn't this one udonbehaviour array?

#

I thought [] meant the array version

frozen igloo
#

udonbehaviour array doesn't work

#

this will set disableinteractive on all the children of the "parent" object

#

if anything it's simpler than udonbehaviour array since getcomponents doesn't give you the proper type it just gives you a component array

#

I'm actually surprised, this is a lot less messy than I thought it would be. Casting like this is annoying in U#

sullen vector
#

How would that connect to the rest of the event?

#

the For?

frozen igloo
#

it would probably be cleanest to make this a separate event entirely

#

and have one version for enabling, another for disabling

#

and you would disable interactive in playjukebox and enable interactive in stopplaying

sullen vector
#

Oh, just remembered

#

how do I check it's in manual mode?

frozen igloo
#

it's not something you modify in graphs, you do that in the udonbehaviour component

sullen vector
#

I think I've missed something somewhere

#

I tested with 2 instances (with the go button so I can delay the other joining)

#

and it doesn't seem to do anything

frozen igloo
#

can you zoom all the way out?

#

what do you have so far

sullen vector
#

This is everything

frozen igloo
#

jukeboxsource and clip shouldn't be synced. You can't sync references like that

#

I don't think that would necessarily break things though. Are you sure those are both plugged in on the inspector?

sullen vector
#

Yeah, all of them are

#

I'm definitely using the thing to disable all buttons by the way, you can disable all 5 buttons one at a time

frozen igloo
#

can you check the log to see if anything is crashing? You can find it in appdata/locallow/vrchat

#

search for "halt"

sullen vector
#

theoretically you could hog the jukebox by pressing one button, waiting to the last second, and then pressing another

#

and since the thing never stopped playing, the ones you've already pressed stay off

#

so yeah, that part will come in handy

frozen igloo
#

what you could do is add a couple seconds if you're the owner. Then if multiple people are trying to click it at the same time, it will always go to someone new

sullen vector
#

I'm surprised it's this complex to be honest

#

I was going to make a second event that just always played the audio source locally for the person who joins

#

and then edit the playjukebox event so that it clears the clip once it's done

#

does that make sense? it didn't work but you can see where I'm coming from

#

if nothing's playing, than the local play thing does nothing

#

if something is playing, the local play thing would play whatever was picked

frozen igloo
#

I'm not following, sorry

#

but from what I understand, I don't think that's necessary. You might be overthinking it. If someone doesn't like the music they'll just turn down world audio

sullen vector
#

hmm, still not sure why it's not working

#

no errors in the logs

frozen igloo
#

try adding a debug log right after calling audiosource play

#

make sure it's reaching that point

#

if it is, then it's some other issue like maybe the audiosource's volume/range is too low

sullen vector
#

it plays the audio

#

it just doesn't play it for other people now

frozen igloo
#

do the other people see the interact disappear?

sullen vector
#

let me check

#

hm, taking its time to build this time

frozen igloo
#

oh, do you not know about last build?

sullen vector
#

Oh right, forgot that was a thing

frozen igloo
#

in the settings tab, enable "show extra options..."

sullen vector
#

for some reason I completely blanked that out on the menu

#

It's on there, I just missed it somehow

frozen igloo
#

you can also use that to delay a second client without just using the go button

#

they will always go to the same instance

sullen vector
#

do they end up in the same session?

#

ah, neat

frozen igloo
#

even if it's two completely different worlds, your PC will always use the same instance

sullen vector
#

I'm going to let it build anyway, I've had a lot of worlds break trying to cancel a build

frozen igloo
#

yeah for sure

sullen vector
#

You only make that mistake once

#

alright, just need to check for you now

#

so the button stops being interactive and for some reason the sound plays on both clients now

#

just need to check about joining while playing

#

Oh weird, it kinda works but it plays the wrong song

frozen igloo
#

did you click multiple buttons?

sullen vector
#

I did the first time, misclicked a song

#

One of the songs has a very distinct sound at the start so I've been using it to test

#

clicked the wrong one and then overrode it with the new one

frozen igloo
#

yeah that's why you need to disable interactive on all of them. There is no guarantee they will arrive in the right order

sullen vector
#

That's probably why they did it in TF2 now I think about it

frozen igloo
#

if you wanted to harden it against that issue even more, you could just set playing false on all the other ones

sullen vector
#

This is awkward on a modern game engine and a plugin designed for a multiplayer game, let alone an engine from 2004

#

no wonder they did it that way in 2008

frozen igloo
#

eh, it's pretty straightforward. And tbh if I knew there would be multiple songs I would have suggested a different approach to begin with

#

like instead of a series of synced bools on separate behaviors, you could just have one behavior with a synced integer and an array of clips

sullen vector
#

I thought I mentioned that 😅

#

Either way, as long as it's not horribly inefficient I'll stick with this one for now

sullen vector
#

I assume the parent variable has to be public and not synced

frozen igloo
#

yeah that looks right. Unfortunately it's a lot more complicated than it should be. In a perfect world you wouldn't have that many nodes duplicated, but udon graphs don't support custom events with variables yet so ¯_(ツ)_/¯

#

oh wait, you need to plug the component array into the component[] get

sullen vector
#

I knew I was missing something, it was acting weird

#

Hmm, still acting the same

#

the button I press will only press once, but it still has the outline as if it can be pressed

frozen igloo
#

make sure to hit compile after you finish. Compile happens automatically every now and then but if you immediately make a change and go straight to a build and test, it might not take effect

#

it's probably crashing from the missing component[]

sullen vector
frozen igloo
#

yeah

tardy kiln
#

i tried creating an animation that opens the door and even checked a tutorial i did nothing wrong but whenever i put the udon script the door stops moving

lone zealot
#

When a scripted component that implements the animator events is on the same gameobject as an animator, the animator assumes that it is now controlled by the script. I forgot what exactly you have to do in your graph to make the animator run as normal, but you can google it I think.

tardy kiln
#

i got it same way as two tutorials without any single difference

#

however whenever i do it and run play mood it doesnt work at all and it stay still

tardy kiln
#

i figured this out but how can u set networking to can pick multiple variables at once

pliant cairn
#

Hi, total newbie to networking here; and honestly I’m not even sure I understand all of the possible use cases for it. I’m wondering if Udon Networking can be used to create object-property persistence in a world? What I mean by that is “once a player manipulates the properties of an object, it’ll retain those properties unless modified by another player. The object will snap to it’s last saved state when someone new loads into a new instance of the world.” Obviously multiple instances pose an issue; so additionally, I’m wondering if it’s possible to put an instance-cap on your world? My default assumption is no, but you never know.

north mountain
#

so instance caps no. not posable anyone in vrc can create new instances

#

within a single instance an object can have propties that are syncronized to other clients and new joiners, most pickups already do it

errant siren
frozen igloo
#

Udon is slow, so it's likely that the automatic serialization will have less of a CPU cost than whatever method you make running in udon

#

Now that we have synced arrays, I don't think there's much of a reason to do your own serialization unless you're doing something like exporting to an input field that can be copy/pasted

obsidian cedar
#

Still missing string[] sync though :/ but we're not getting that.. sad

obsidian cedar
# errant siren it's planned

AnimuThinku I though you said network engineer said that he'd like people to not sync bee movie script AnimuThinku That's why I thought it's not coming

#

But that's great news.. hopefully I won't have to do so many stupid things to sync my string arrays 😅 😅

languid snow
obsidian cedar
#

May or may not have done that too when UNU was in Open beta

#

Synces quite nice

#

I mean we were supposed to test limits back then So I did

#

I remember I tried syncing megabytes of data at one point..

errant siren
#

it's based on Network ID, which is currently based on path of the gameobject, yes.

obsidian cedar
astral raven
#

I and ||(dupe)|| (2 users in world) try spawning an object, it's fine (I'm using take ownership then spawn.) and all code work PERFECTLY fine.
But in some situation (world with lots of people? or sth, IDK.) the code gone broken. IDK what actually happened.

Can anyone have some answer?

This is the code, if you wish to read. Also, as you can see, The RequestSerialization() on Update() is SUPER bad pactice, but If I use continuous sync. It doesn't work. any reason why also?

north mountain
#

certianly not the most readable code iv reviewed before

astral raven
#

True ;-; I read my code and it's f***ed my eyes.

#

This is old though.

north mountain
#

well if i go peice by piece, OnOwnershipRequest can be removed as that the default behaviour
in start() you probaly dont the ownership check, you can just initialise it with a default array like PieceColor = new Color[PieceObjectPool.transform.childCount] (as color is a struct so will default to color(0,0,0,0) anyway and for manual behaviors it will override the value with the correct one one network data is send

#

to enumerate over childs of you object pool you can use .Pool rather then get childs

astral raven
#

About Array, I thought that to sync, size must be same to all players first because is allocated dynamically ;-;.

So I misunderstand so much.

#

Or I write too much C.

north mountain
#

the size of the array is now made up by the about of objects in the pool, which should never change at run time, only thier active states change

#

for which can use PieceObjectPool.Pool.Length

#

i notice here for (int i = 0; i < PieceObjectPool.transform.childCount; i++) if (SpawnedObject == PieceObjectPool.transform.GetChild(i).gameObject) you try to get the id of the object that has just spawned this can be simplified to Array.IndexOf(PieceObjectPool.Pool, SpawnedObject );

#

infact i should not complain so much about the code itzelf sorry, i just have a hard time to see what going on

astral raven
#

The concerning is still RequestSerialization() on Update() thing.
and
Where or why the code break, in unknown case.

frozen igloo
#

the color array is probably just too big for continuous sync

astral raven
#

I see, but is do it on Update() just f*** them more? Should I use brand new OnVariableChange thing on beta?

frozen igloo
#

yes, doing it on update is not a good idea

#

onvariablechanged would work but if you're just changing the variable every frame the same way then you're going to get the same issue

#

I have no idea what you're doing because it's impossible to read when you have everything in the same line like that

astral raven
frozen igloo
#

I would love to give a more intelligent answer but your code style is breaking my brain

astral raven
#
for (int i = 0; i < PieceObjectPool.Pool.Length; i++) 
  if (PieceObjectPool.Pool[i].gameObject.activeSelf && Networking.IsOwner(Networking.LocalPlayer, PieceObjectPool.Pool[i].transform.GetChild(0).gameObject)) 
    { 
      PieceObjectPool.Pool[i].transform.GetChild(0).GetComponent<PieceProperty>().PieceColor = PieceColor[i]; 
      PieceObjectPool.Pool[i].transform.GetChild(0).GetComponent<PieceProperty>().RequestSerialization(); 
    }
north mountain
#

well basicly you only need to request serialisation when made changes to any of the synched variables on the PieceProperty
fun fact you never actuallly seem to call RequestSerialization() after moddifing the PieceColor array

#

you shoulds only call it when a change is made

astral raven
#

I may tried it again.

Or maybe refactor the whole code ;-;

frozen igloo
#

well there's a difference between setting the synced variable on the owner's side and the other players applying that variable to some objects

north mountain
#

it seems you need to RequestSerialization(); in your spawn, i see it there
but its missing from ResetPieceColor & DestroyAllPiece

frozen igloo
#

ondeserialization happens when you receive synced data, you probably should use that to do stuff with the synced variables

#

but you could also use onvariablechanged

north mountain
#

i refactored the code a bit to a point where i think its easyer to spot the problem

    void Start()
    {
        PieceColor = new Color[PieceObjectPool.Pool.Length];
    }
    void Update()
    {
        if (AdvancedPaletteParent.activeSelf) 
            ColorPreviewRawImage.color = new Color(ColorValueSlider[0].value, ColorValueSlider[1].value, ColorValueSlider[2].value, ColorValueSlider[3].value);

        for (int i = 0; i < PieceObjectPool.Pool.Length; i++)
        {
            var piece = PieceObjectPool.Pool[i];
            if(!piece.activeSelf)
                continue;

            var piecePropertyHolder = piece.transform.GetChild(0).gameObject;
            if (Networking.IsOwner(Networking.LocalPlayer, piecePropertyHolder))
            {
                var pieceProperty = piecePropertyHolder.GetComponent<PieceProperty>();

                pieceProperty.PieceColor = PieceColor[i];
                pieceProperty.RequestSerialization();
            }
        }
    }
    public void SpawnPiece()
    {
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        Networking.SetOwner(Networking.LocalPlayer, PieceObjectPool.gameObject);

        if (!Networking.IsOwner(gameObject) || !Networking.IsOwner(PieceObjectPool.gameObject))
        {
            StatusText.SetStatusText(3); return;
        }

        Color color = GetColor();
        if (CheckColorDuplication(color))
        {
            StatusText.SetStatusText(2); return;
        }

        GameObject SpawnedObject = PieceObjectPool.TryToSpawn();
        if (!Utilities.IsValid(SpawnedObject))
        {
            StatusText.SetStatusText(1); return;
        }

        Networking.SetOwner(Networking.LocalPlayer, SpawnedObject);
        Networking.SetOwner(Networking.LocalPlayer, SpawnedObject.transform.GetChild(0).gameObject);

        var pieceId = Array.IndexOf(PieceObjectPool.Pool, SpawnedObject);

        PieceColor[pieceId] = color;
        RequestSerialization();

        StatusText.SetStatusText(0);
    }
    public void ResetPieceColor(GameObject obj)
    {
        var pieceId = Array.IndexOf(PieceObjectPool.Pool, obj);
        if (pieceId == -1)
            return;

        PieceColor[pieceId] = new Color(0, 0, 0, 0);
        RequestSerialization();
    }
    public void DestroyAllPiece()
    {
        if ((Networking.GetOwner(Core.gameObject) != Networking.GetOwner(gameObject)) && Core.isLocked) 
            return;


        for (int i = 0; i < PieceObjectPool.Pool.Length; i++)
            PieceObjectPool.Return(PieceObjectPool.Pool[i]);

        for (int i = 0; i < PieceColor.Length; i++)
            PieceColor[i] = new Color(0, 0, 0, 0);

        RequestSerialization();
    }
    Color GetColor()
    {
        if (!AdvancedPaletteParent.activeSelf)
        {
            for (int i = 0; i < BasicPaletteParent.childCount; i++) 
                if (BasicPaletteParent.GetChild(i).GetComponent<Toggle>().isOn) 
                    return BasicPaletteParent.GetChild(i).GetChild(0).GetComponent<RawImage>().color;

            return new Color(0, 0, 0, 0);
        }

        return new Color(ColorValueSlider[0].value, ColorValueSlider[1].value, ColorValueSlider[2].value, ColorValueSlider[3].value);
    }
    bool CheckColorDuplication(Color color)
    {
        for (int i = 0; i < PieceColor.Length; i++) 
            if (Mathf.Abs(color.r - PieceColor[i].r) < .2f 
                && Mathf.Abs(color.g - PieceColor[i].g) < .2f 
                && Mathf.Abs(color.b - PieceColor[i].b) < .2f 
                && Mathf.Abs(color.a - PieceColor[i].a) < .4f) 
                    return true;

        return false;
    }
#

probaly unrelated but i have no idea how CheckColorDuplication is seposed to work that is either broken or some high level math i cant grasp

astral raven
north mountain
#

oh i see now, yes that will work, you check if the new color is more than .2f different from any existing color

#

well for your problem, if it break with a lot of poeple it can indeed the that your calling RequestSerialization for each PieceProperty that is both active and your the owner of, if you try to serialize to much you hit throttling

astral raven
#

So If I just put the color in PieceColor[] - synced manually and let PieceProperty get the color from it - unsynced. Should it will work in more dense condition?

north mountain
#

i see. well the better way is to get rid of PieceProperty completly than

#

keep PieceColor[] manuelly synched, and make sure you always RequestSerialization() when you moddify it (so also inside ResetPieceColor & DestroyAllPiece)

#

then after each call to RequestSerialization() add a call to OnDeserialization()
so you get

RequestSerialization();
OnDeserialization();
#

and in OnDeserialization() (it gets called on all other clients as soon as new information about the PieceColor[] is recieved) you can there update the materials

#

and then in the deserialization do

    //inside PieceSpawner 
    void OnDeserialization()
    {
        for (var i = 0; i < pool.Pool.Length; i++)
        {
            var piece = pool.Pool[i];

            BaseRenderer.materials[0].color = PieceColor[i];
            BaseRenderer.materials[1].SetColor("_EmissionColor", PieceColor[i]);
            ConeRenderer.material.SetColor("_EmissionColor", PieceColor[i]);
        }
    }
#

or you could do a call to PieceProperty instead

    void HandleDeserialization()
    {
        for (var i = 0; i < pool.Pool.Length; i++)
        {
            var piece = pool.Pool[i];
            var pieceProperty = piece.GetComponent<PieceProperty>();

            pieceProperty.UpdateColor(PieceColor[i]);
        }
    }

    [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
    public class PieceProperty : UdonSharpBehaviour
    {
        [SerializeField] Renderer BaseRenderer = null;
        [SerializeField] Renderer ConeRenderer = null;
        void UpdateColor(Color pieceColor)
        {
            BaseRenderer.materials[0].color = pieceColor;
            BaseRenderer.materials[1].SetColor("_EmissionColor", pieceColor);
            ConeRenderer.material.SetColor("_EmissionColor", pieceColor);
        }
    }

that way you can still keep the references to BaseRenderer & ConeRenderer inside the PieceProperty but get rid on the update() there as it will now only update the color when new color information is received

astral raven
#

Thanks for the idea and coding. Hope this works.

heady flint
#

How can i ask for a variable from the Master? i wanna ask for a Int when the someone starts the world

north mountain
#

well you cant ask for a variable, they variable need to be marked as syncronised, and then it will be send to other users

#

depending on whether or not you set the syncronisation to manual or continues

#

also the variable will be controlled by the owner of the object the udon behaviour is on, this does not neccerly needs to be the master

astral raven
# north mountain then after each call to RequestSerialization() add a call to OnDeserialization(...

Should I put OnDeserialization(); after RequestSerialization();? (I've already set for self.)

When I didn't put OnDeserialization(); It doesn't sync most of time.

Put the setcolor in Update() make it worse.

Didn't try when put it on yet.

        public void SpawnPiece()
        {
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
            Networking.SetOwner(Networking.LocalPlayer, PieceObjectPool.gameObject);
            Color color = GetColor();
            if (CheckColorDuplication(color)) { StatusText.SetStatusText(2); return; }
            GameObject SpawnedObject = PieceObjectPool.TryToSpawn();
            if (!Utilities.IsValid(SpawnedObject)) { StatusText.SetStatusText(1); return; }
            int id = Array.IndexOf(PieceObjectPool.Pool, SpawnedObject);
            PieceColor[id] = GetColor();
            RequestSerialization();
            SpawnedObject.GetComponent<PieceProperty>().SetColor(GetColor());
            Networking.SetOwner(Networking.LocalPlayer, SpawnedObject);
            StatusText.SetStatusText(0);
        }
        public override void OnDeserialization()
        {
            foreach (GameObject gobj in PieceObjectPool.Pool) 
              if (gobj.activeInHierarchy) 
                gobj.GetComponent<PieceProperty>().SetColor(PieceColor[Array.IndexOf(PieceObjectPool.Pool, gobj)]);
        }

This is the some part of code.

north mountain
#

yes OnDeserialization after request serialization

astral raven
#

aww so reason it's buggy because I didn't called the function?

I tought it'll called automatically after synced data is sent 🤣🤦‍♂️ .

north mountain
#

so OnDeserialization is a bit wierd that it gets called when new synchron7zed variables are received over the internet, however for the owner who request the new variables to be syncronised it never gets called as he already has the data

#

therefor if you want some processing to happen when new vales are available you would put that in OnDeserialization, but ypj have to manually call it for the object owner

astral raven
north mountain
#

yes so in on deserialization is when a remote clients gets new color info and should update all colors

astral raven
#

Still not latest sync,

Case (1) 2 pieces spawn from a player who is already owner. (Cyan and red.)

#

The weirder is it's white, not 0,0,0,0.

#

Spawn the third onemake it sync the first 2 properly, but the third one is white.

#

Case (2) Alternate the owner in each pieces, act same as first case.

#

White color comes from original prefab's material color.

astral raven
#

Right now, I'm solved by adding delay function to sync the color again.

tawdry plaza
#

Hello! So, I'm really trying to understand how syncing works, but as much as I try I can't understand it in any way. So, I'm trying to do something really simple, when someone press a button their name will show on a board for them and everyone else (obviously even for late joiners); my idea for now is to have 2 synced variables, one is an int array where I store the id of the player (for what I've read strings are really heavy and slow to sync, that's why I'm using the id) and one to know how many have pressed the button. So far I've successfully made it that the owner can press the button and their name appear and it appear for late joiners, but I can't manage to transfer the ownership/send data to the owner and send to everyone in the instance the name. What's the best way to do this?

#
public class SettingsUno : UdonSharpBehaviour
{
    public UnoGame MainScript;
    public int maxPlayers = 4;
    
    public Text[] playerList;
    
    [UdonSynced] private int[] playerOrder;
    [UdonSynced] private int playerCount;
    VRCPlayerApi localPlayer;
    
    void Start()
    {
        playerOrder = new int[maxPlayers];
        localPlayer = Networking.LocalPlayer;
    }
    
    public void joinGame() 
    {
        if (playerCount < maxPlayers) {
            Networking.SetOwner(localPlayer, gameObject);
            playerOrder[playerCount] = localPlayer.playerId;
            RequestSerialization();
            SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, nameof(sendNamesAll));
            playerCount++;
        }
    }
    
    public void sendNamesAll() 
    {
        playerList[playerCount].text = VRCPlayerApi.GetPlayerById(playerOrder[playerCount]).displayName;
    }
    
    void OnDeserialization() 
    {
        for(int i = 0; i <= playerCount; i++) {
            playerList[i].text = VRCPlayerApi.GetPlayerById(playerOrder[i]).displayName;
        }
    }
}
#

This is the code so far

heady flint
#

Das OnDeserialization work? i mean on my code it just create a loop

tawdry plaza
heady flint
#

And i need a void RequestSerialization() ?

#

And that will run Globally?

tawdry plaza
#

Look at the code I've posted before your message, you just need to put RequestSerialization() when you need to update the synced variables, but well, my script works only for late joiners, not globally, so take those info with a grain of salt, I'm here because I need help too lol

heady flint
#

ok let me test!

#

Yep still

#

is a loop

#

i don't get it

#

i'm just doing a

 void OnDeserialization() 
    {
        Debug.log("Test")
    }

and a RequestSerialization(); on start

errant siren
# tawdry plaza Hello! So, I'm really trying to understand how syncing works, but as much as I t...

Take a look at the SyncButtonBecomeOwner example in the UdonExample scene - this shows how to easily have anyone take ownership of an object and change a value on it, in this case a counter for the number of times it's been clicked. Note that if you're only syncing the id of the player, they might be gone when someone else gets the data, so you wouldn't be able to resolve from that id to their displayName. I'd recommend syncing the displayName string itself if that's what you want.

heady flint
#

@errant siren Do you understand my problem? when the world runs the OnDeserialization() is being call every second

#

and i have a RequestSerialization(); on start

frozen igloo
#

ondeserialization happens frequently if you have the udonbehaviour set to continuous sync, yes. That is intended

#

continuous sync does not require requestserialization

heady flint
#

i'm not able to understand why that is not working

frozen igloo
#

manual sync is the one that requires requestserialization and will only happen once when you manually call it

heady flint
#

i need to change this?

#

it's set to Manual by the code

frozen igloo
#

ehhh well it looks like you have other issues

#

do you have an objectsync on this object?

analog mica
#

someone help me with avatar stuff dm me

frozen igloo
#

or other udonbehaviours?

frozen igloo
heady flint
#

Do i need that one on Manual?

frozen igloo
#

you need to make sure that all udonbehaviours on this gameobject are set to manual sync if you want to use manual sync

#

you cannot mix sync types between udonbehaviours on the same gameobject

heady flint
#

uhhh

#

let me check

#

if it works you just fix my life haha

#

Still same thing

frozen igloo
#

can you show the whole gameobject?

heady flint
#

doing that every update

#

The inspector?

frozen igloo
#

yes

heady flint
frozen igloo
#

you have no other components?

heady flint
#

and a Mesh Renderer

frozen igloo
#

you checked really quickly, are you actually trying this ingame or did you use cyanemu?

heady flint
#

in game

#

With 2 VRC

frozen igloo
#

and you're getting that debug log "Test" frequently?

heady flint
#

The Main is good

#

But a Client has the Update every second

frozen igloo
#

well update is supposed to happen every frame, that's what update does. Or are you talking about OnDeserialization?

heady flint
#

OnDeserialization is happening every frame

tawdry plaza
# errant siren Take a look at the SyncButtonBecomeOwner example in the UdonExample scene - this...

In the end I solved the problem thanks to Phasedragon, the script was already kinda working but I had to check the validity of the player, so the script was crashing, and thank you for the information! Just out of curiosity, the ID are unique for every player in the instance or they will be assigned to another player in the instance when they left? I'm not sure if this can be a problem for what I need, but just to make sure

frozen igloo
#

and you know that because of the debug.log("Test")? That's a pretty generic debug log, are you sure you don't have another script printing that as well?

#

or maybe you have something in your script calling OnDeserialization directly?

heady flint
#

Yep

heady flint
#

i just have a RequestSerialization();

#

But now i don't havbe a Debug.log("Test") any more

#

i have the actual thing that it has to do

frozen igloo
#

Where exactly are all the places you are calling RequestSerialization? Is it at all possible that you are making that happen from update?

heady flint
#

void Start()
{
RequestSerialization();
{

#

only at start

frozen igloo
#

could you share a bit more of the code? I have no idea how this is possible with how you've described it

heady flint
#

Can i do on priv

#

😛

frozen igloo
#

sure

short grotto
#

Sorry if this is a silly question, but are events like OnPickup() and OnDrop() only called on the client that’s doing the picking up and dropping, or do they run for everyone?

frozen igloo
#

they only run for the person who grabbed it

short grotto
#

That’s a relief! Is there a good reference or rule of thumb for what events execute locally vs universally?

quaint rain
#

Most things are local apart from some aspects of video players and stations

gritty rampart
#

OnPlayerTriggerEnter is only really triggered when the local player enters the trigger volume right? Like if client A and B are in the world, and A enters the trigger volume, then the code will not execute on client B's local version of the world right?

quaint rain
#

It will trigger when any player enters it on the local client

#

You can gate whether it triggers or not by checking if the player that entered is the local player

gritty rampart
#

Thanks, was wondering if I needed to branch on Get isLocal or not!

stark pendant
#

Alright. So I've created a menu that follows every player around in a map, one of the options is to edit strings that can be seen by other players, using a manual serialization.
Now the problem is that the master's synced values can be seen by others, but that others' values can be changed, but only be seen by themselves. A bit of a shot in the dark, but does anyone have any suggestions on what it could be?
vrchat's networking page mentions that you should try a setowner before doing the change, but that doesn't seem to work.

errant siren
tawdry plaza
#

Hello again! Still struggling with networking and the VRC Object Pool, so for context, I have the cards in the object pool, all the cards have Object Sync, and if I make the owner of the game (player 1) spawn and position them it works correctly, but I have only one problem with this. The cards are made with an UI, so each player have a canvas where the cards go, so I can use a grid to align them. Now, I can't actually make the event networked because of the Object Pool, it throws error because the other players are trying to spawn when they are not the owner, and even if the owner spawn the cards, I can't parent them on the canvas on the other clients because I don't have a reference of the object spawned for the other clients. Hopefully it's not too confusing, but long story short, is there a way to parent a spawned object for all the clients or at least for the right player? I've tried even switching the ownership when you spawn the cards, but for some reason I can't make it work, I just really need that each player have the ownership of their cards and they are parented for their screen 🤔

frozen igloo
#

You can add OnEnable and OnDisable events to the cards, those will happen when they get spawned and despawned by the pool. You can then do whatever you want during that event and everyone will see it

tawdry plaza
#

But how do I know from the card on which screen should it go? I mean, for the parenting, not the position

frozen igloo
#

you could have a synced int array on the same object as the pool which represents some information about each object

tawdry plaza
#

Oh, right 🤔 I wanted to use less synced variables but well, I guess I don't have other choices, I've tried for 2 days now with the method I was trying lol
Thank you so much for the help!

frozen igloo
#

I would recommend just having a "version" number somewhere and if players disagree with the master, put a message somewhere that they are not on the same version and they should rejoin

#

well obviously it's not going to work for players that don't have the version number. But once you have established it, any further version upgrades will use the same synced variable

#

it would help to have the version number gameobject at the top of your hierarchy, since it assigns network IDs from the top down

clever merlin
#

What's a good resource to learn all the new Udon Networking Update stuff?

gritty rampart
#

Networking question; say I have a custom event I plan on sending over a network with SendCustomNetworkEvent - will that event's code execute x amount of times, where x is the number of clients that receive the event? Like for instance if the network event has code that teleports player A, would player A be teleported 3 times if there's 3 players on the server at the time that event is fired?

north mountain
#

yes to multiple executions, however you cant teleport other players only the local player so you wont be teleported 3 times

woven pewter
#

hm? Are you sure? I seem to recall hearing that teleporting other players does work...

north mountain
#

oke i might be wrong than

gritty rampart
#

I mean the teleportto API will teleport any player that you feed into it

lone zealot
# gritty rampart I mean the teleportto API will teleport any player that you feed into it

No it does not. Its confusing because it even accepts a player api, but it only works locally. If you try to teleport a remote client you will get a message saying something along the lines of "failed because client x was not local" or something like that.
VRChat has a lot of these smaller inconsistencies and weird design decisions in their public API unfortunately.

coral silo
#

Any way to get a player's ping using Udon? My best guess is Networking.CalculateServerDeltaTime but I really can't find any documentation on it

#

No wait I just remembered what deltatime is that's not it

north mountain
#

No you cant get ping

errant siren
#

The latest UdonExampleScene in the Open Beta has a simplified video sync program which does this to sync video players

lone zealot
#

Wow. Thats an unconventional way to sync lol

errant siren
lone zealot
#

Using ping to sync

errant siren
#

you would prefer to sync video players without accounting for delay?

lone zealot
#

I have a much better method. And so does the U# player

errant siren
#

there's more going on than just that - you're welcome to look at the graph to see the logic

lone zealot
#

Also an easier way to calculate your own ping is to set a boolean, set a timestamp (using the timedate stuff from C#), send a custom network event to all, and only respond to the event if the boolean is checked. Im pretty sure that Network events are bounced no matter if you locally receive it as well. Then you just compare the current time to the previously saved timestamp.

errant siren
#

that doesn't tell you anything about someone else's ping, though. If someone joins your world 5 minutes after you started a video with a delay of 200ms from you...

#

The new example prioritizes:

  • Simplicity - so it can be understood / modified
  • Low-bandwidth usage - if no shuttling / pausing is performed, you can sync everyone with a one-time manual Vector2 per playback
#

Many video worlds are synchronizing WAY more often than necessary, sending ridiculous amounts of data

lone zealot
#

Well most of those are also still not updated to manual sync

#

And I dont even understand why ping matters at all. The way the "old" example and also my player works is that you get the time delta between when the owner started playback, and the current time. Which means that ping doesnt matter. Youre simply skipping over the first few hundred milliseconds of the video.

errant siren
#

yep - that's very similar to the new example. It sounds like the difference may be in using a Vector2 instead of a single variable - with x being the network time when the variable was updated, and y being the video time. So the owner can jump to another spot in the video and update the variable to get everyone in sync to the new point

lone zealot
#

Yeah thats pretty much the same method I use, but I call them "SyncTime" and "PlaybackOffset".

#

And I dont like bundling them in a Vec2, because thats confusing. They do belong together, but they shouldnt be treated like a vector.

errant siren
#

Agreed that it's a bit of a hack but it works well

lone zealot
#

With manual sync I have never seen variables that are changed and serialized together, not arrive together

#

Ideally you would be able to make your own struct

#

but yeah...thats gonna be a while.

errant siren
#

that's gonna be never - IL2CPP doesn't allow it 🤷‍♂️

lone zealot
#

Could also use a float[2]

errant siren
#

Arrays don't work with OnVariableChange events

#

since it can only detect a change to the reference and not the members

lone zealot
#

Well yeah I dont use OnVariableChange, because I want to rely on VRC's API as little as possible. Simply so I can predict the code better.

#

However it does increase the execution time, which is probably not worth it.

#

Also I use Unix Time in form of a Long as my sync time, so I cant use a Vec2 ¯_(ツ)_/¯

humble girder
north mountain
#

then the devs will hunt you in your dreams

weak mirage
#
    public void loadUrl()
    {
        videoPlayer.Stop();
        videoPlayer.LoadURL(URLField.GetUrl());
        SendCustomNetworkEvent(NetworkEventTarget.All, "loadUrlNetwork");
    }

    public void loadUrlNetwork(VRCUrl url) {
        videoPlayer.Stop();
        videoPlayer.LoadURL(url);
    }
``` how do I pass an argument through a custom network event?
lone zealot
#

(Maybe at some point in the future this will be possible, however at the moment it is not. Your next best option is manual synced variables.)

woven pewter
#

just keep in mind manual synced data can arrive more times than it's sent

celest mesa
#

The trick to do it is set a value on the receiving Udon Behaviour, and then fire a network event at the receiving Udon Behaviour telling it to do whatever with the value.

#

Eg; If I have five different ways something can add to a centralized game score with different point values, from the scoring object I apply its internal value (say; 500 points) to a generic AddValue int in the receiving Udon Behaviour handling scoring. I then shoot "UpdateScore" at it, and in UpdateScore it can play with the value however (eg; calculate against multipliers, run anything fancy displaying the score increase, etc).

lone zealot
weak mirage
#

how do I use manual sync in udonsharp?

frozen igloo
#

take ownership with Networking.SetOwner(Networking.LocalPlayer, gameobject);

set a synced variable

call RequestSerialization();

#

And yeah, definitely don't rely on manual sync to arrive first, especially with large amounts of data like a string or a URL. If the network is clogged and lots of other data is going through, the manual sync will be delayed but the network event will not.

#

If you want to detect when the manual sync, arrives, you would use OnDeserialization. When that event happens, you can safely read synced variables and do whatever you want to do with them.

#

Alternatively you can use OnVariableChanged if you care about a specific variable changing instead of just any variable, though it's a bit more complicated in udonsharp

weak mirage
frozen igloo
#

it will delay the arrival

weak mirage
#

so if I want to make a video player should I make it report back to the owner that the URL was received, and only start playing once everyone in the room has received the URL?

frozen igloo
#

That would be a good safety measure to have, yes. In addition you may want to wait until they have actually finished loading the video.

#

some people have much slower internet than others and this can make multiplayer video watching very complex

lone zealot
#

My current main video player script has 1300 lines of code and its still not quite finished. (granted about 20% of that is empty lines or braces, but still)

weak mirage
#

I need to trigger it playing and stopping from a different script and need to constantly get the time elapsed on the video to make it sync with something else in my world, so I thought I might as well make it myself, it doesn't need any features like volume adjustment or skipping around

#

is it a lot more complicated than implementing the load confirmation to make it work reliably? if it is then I might just use something else

lone zealot
#

It is a whole lot more complicated than that. In essence its quite simple. But there is a lot of situations in which it can break, if you dont prepare for them.

#

Im still working on my modular player, otherwise I would have referred you to that. But I mean its always good to take on a challenge, cause you will always learn something from it

weak mirage
#

is there anything already made I could use then? something like U# video player works well but has stuff like pausing, changing the video time, ect... which is nice for a normal video player but not for what I want to use it for

lone zealot
#

Well I mean you can just strip that stuff out of it...if you can figure out what is and what isnt needed :P

#

If you want something super specific, then yeah you will have to make it yourself. But another option is to take something generic and shape it into what you need, but taking bits off and adding new things onto it.

#

Unfortunately Merlins player isnt super modular, and not very well documented. Which is why Im working on a video player myself.

weak mirage
#

alright well when you finish it let me know, I'll try to make this work in the meantime

lone zealot
#

I have the core part of it working. I just need to do some more exotic stuff, like supporting livestreams, handling protocols like RTSP, Making it so that other people can take control over the player, making an options UI

And ofcourse documenting the entire thing...

weak mirage
#

I don't really need any of that, so if you want could you send me what you have atm? you don't have to of course if you don't want to

lone zealot
#

Its not polished and tested enough for that yet, sorry.

weak mirage
#

alright, let me know when you finish it then

errant siren
#

handles:

  • Anyone changing URL loads new URL to everyone else (can turn on/off from checkbox on program)
  • Syncs time between everyone, with variable rate (every 10 seconds, every 5 seconds, etc)
mental mountain
#

If I make a variable synced(manual) and set it with send changed disabled, then some other udon behaviour change the variable, does on variable change triggers for everyone?

frozen igloo
#

setting a variable from another udonbehaviour requires using setprogramvariable (or in udonsharp, it would be compiled to that anyway) and setprogramvariable always triggers a change anyway

#

however, triggering a change does not necessarily mean it will be synced to others unless you do requestserialization

mental mountain
#

forgot about saying, request serialization is set

#

I had a very strange issue with late joiner

frozen igloo
#

also you should be aware that sendchange is really only a local preference. For remote players receiving synced variables, it will always cause onvariablechanged even if you have sendchange disabled

mental mountain
#

On variable changed worked every time for existing people whenever late joiner come in

#

I made a node with when a boolean changes to true On variable change trigger, and although I set the boolean to false, whenever late joiner come in boolean become true for existing people and on variable change worked

frozen igloo
#

did you request serialization after setting it to false?

mental mountain
#

No but I changed via send network in other nodes

frozen igloo
#

is it a synced variable?

mental mountain
#

Boolean is sunced manually

#

Synced

frozen igloo
#

then you should use requestserialization to sync it, not network events

mental mountain
#

I checked the log and it saids set properly(log after on variable change)

#

I think It is fixed by requesting serialization

#

But log says send network works same way til someone joins the world

frozen igloo
#

if the owner tells you it is true, then you receive a network event that causes you to set it to false, that doesn't actually set it properly. The reason it resets back to true is because you will re-apply synced variables back to whatever the last time you heard that it was, which is true

#

not when it comes to setting synced variables

#

you should never set synced variables if you are not the owner

mental mountain
#

Oh

frozen igloo
#

just because you received an event telling you to set it, doesn't mean that the owner set it

mental mountain
#

I got it

#

That’s exactly what happens

#

Thx and I have one more question

#
  • Calls to SetVariable with sendChange turned on will now actually become SetProgramVariable calls under the hood so that both methods of triggering OnVariableChange events work the same now. Fixes an issue where the 'old' variable value was incorrect on first access, and an issue where value types were never copied over
#

I experienced the last line “value types never copying” and this happened when I make set variable by other variable, const worked fine. Is there a way to bypass this bug? Its fixed on beta sdk but I can’t wait for 2019..

frozen igloo
#

you can just use setprogramvariable instead of setvariable

mental mountain
#

On same node?

frozen igloo
#

no, different node

#

called setprogramvariable

#

search for it

mental mountain
#

And making event for deserialization will work..

#

Thx

lone zealot
#

So how do people generally handle multiple users trying to change synced variables on the same object?
Im still working on my Video Player and Im not sure how to handle say 3 people changing the URL at roughly the same time.
The best way I can envision is a first-come-first-serve policy, where you only allow the first user to take ownership, let them change the variable, and only then accept ownership changes again on their end. But Im not sure if that really is the best way to handle that.

half sail
#

I cant get objects to synchronize. someone told me to just add a udon component but didn't help. Should this really be it or should I do it another way?

woven pewter
half sail
#

Do I still need the udon component ?

#

also yes, thats what I meant :>

woven pewter
#

no, you don't. It used to be that you set this on the UdonBehaviour but these days you only need VRC Object Sync

half sail
#

cool cool, Thanks :D

errant siren
# half sail cool cool, Thanks :D

If you want to learn more about networking, you can find lots of info here: https://docs.vrchat.com/docs/udon-networking

half sail
#

Perfect thanks

dry zodiac
#

If the owner of an object calls RequestSerialization a massive amount of times in a short time, then that's not an issue right?

#

Because the owner won't actually do any more work than serializing once per network frame

#

As I understand it, "request" just means it schedules serialization to happen at the next network frame. So if I call it 40 times between network frames, the networking burden (and CPU burden) is still the same as if I'd called it once?

north mountain
#

sounds sketchy, and a waste of cpu time. but you might be right about it not affecting network traffix

#

but also be aware that manuel sync is faster then continues sync, it sends its data basicly almost directly

frozen igloo
#

That's correct. It's just a request, and flags it to be serialized later. Requesting more times doesn't do anything

lone zealot
#

So I think I found a new "Networking Quirk":
I tried to set a synced variable on a manually synced behaviour and call RequestSerialization() immediately in OnOwnershipTransferred()...

It only worked locally. However when delaying the event that does the setting and requesting by 1 second it works for all players.
So seems like there is a problem with that, or I just did something wrong. But Im fairly certain at this point that there is something not working as intended.

steel igloo
#

Just wondering what happens if you claim ownership right before requestserialization?

frozen igloo
#

it will just work

#

the typical flow is to take ownership, set a variable, then requestserialization

#

so that is very normal

mental mountain
#

Can I use on variable change in udon sharp?

#

can't find the method

frozen igloo
#

yes, it's a little bit different though. There is documentation

#

the basic way of doing it is to add FieldChangeCallback

#

however, the tricky part is that if you just set a variable by doing x = y, this will not trigger a change. If you use SetProgramVariable, however, it will trigger the change

#

if you want to trigger a change without using setprogramvariable, then you can instead run it through a property, which is a new feature that udonsharp supports and you can see the example there as well

#

properties allow you to do things when you try to set or get a variable

mental mountain
#

ok thanks

north mountain
#

i though x = y did work in udonsharp as it compiled down to setprogramvariable

#

ah i see the documention on this was updated

mental mountain
frozen igloo
#

no, it does not

#

graphs compile into setprogramvariable and there was a changelog about that, that may be what you're referring to. But udonsharp does not

mental mountain
#

He is talking about the udon 'node' changelog in beta right? got it

mental mountain
#

Does request Serialization affects other udon behaviour(or u# behaviour)? I have a strange acting deserialization on two udon behaviours on both udon node and #

frozen igloo
#

It does if they are on the same gameobject

#

Udonbehaviours on the same object will be paired and share networking

mental mountain
#

I have two seperate object and seperate udon behaviour(lets say A, B with manial sunc) A have int value ‘a’ synced B have boolean value ‘b’ synced, changing a to like 1 to 10 syncs fine and the problem is after that if I change b like false to true, changing b only works for owner of b and later someone changes a than a, b is synced together

#

Solution was

class B : Udonsharpbehaviour{
public B _self

Void dosomething(){
_self.RequestSerialization()
}
}
Like this and put B itself in inspecters public B solved this in u# but udon node didn’t worked for me

frozen igloo
#

You're gonna have to rephrase that, I'm not following at all

#

But I can say that _self.requestserializstion is not necessary. You can do just requestserialization and that will always refer to itself

#

It sounds like you're saying the problem is that non-owners can't change synced variables? If that's the case, then yes that's exactly how it should work. You need to take ownership before setting variables

sharp tinsel
# mental mountain I have two seperate object and seperate udon behaviour(lets say A, B with manial...

I'm not exactly sure what is the problem, but basically the "RequestSerialization()" will request sync for once for the UdonBehaviour it called on. Sync variables value can only be modified by the owner of the object, so like Phasedragon said, you need to use Networking.SetOwner() to set its owner to local player to change the sync variable value(s).

And I'm not sure but I think this request sync function will only work if being called on the client of the owner of the object.

steel igloo
#

I'm having an issue where I have 1,000 brokered sync objects (things that don't have any updates and it can run at 144 FPS) but, sometimes after cycling through a a bunch of players, the positions of some objects are lost to new players. Is it possible that calling a Networking.SetOwner( Networking.LocalPlayer, gameObject ); then having that player leave could leave the object in an unsyncable state? Is there an event when this happens, so that I could own the object back to the instance owner?

frozen igloo
#

I've been looking into this recently and it can definitely take some time before you successfully receive all manual syncs when you have a large amount. A good way to see this happening is to add some kind of visual thing that happens when each object gets OnDeserialization, like a particle burst or a material change. If you do this, you'll see it slowly move in a wave across your objects. It does so in a predictable order, probably based on network ID which is based on the order in hierarchy.

#

I'm not sure how you have it set up, but if the unused objects are doing requestserialization at any point then that would definitely cause a bottleneck. You might want to consider putting your objects in a pool so that there's no chance that the unused cubes will use up your bandwidth

solar depot
#

Friendly general purpose reminder related to above: Put the most important objects that require syncing at the highest point on the hierarchy.

frozen igloo
#

eh, yeah technically but it only really matters if you have a lot of manual synced things

#

also that is definitely not defined behavior, don't rely on it staying the same

solar depot
#

Maybe not defined, but strongly anecdotal.

frozen igloo
#

sure

solar depot
#

at least at this point.

steel igloo
#

We are testing another build, but, what I was seeing was the objects, if they were going to update would have been updated at start. Otherwise they literally never update. Still going to see on this new build, though.

steel igloo
#

Yeah, not sure what's up there. Just letting masters slowly sync all their objects fixes everything.

woven pewter
# frozen igloo I've been looking into this recently and it can definitely take some time before...

FWIW, on live there are certainly cases where Object Sync misses syncing some objects as well. My otakaze mahjong world seems to repro this frequently - if you have four people playing mahjong, late joiners will usually see a large fraction of the tiles in their original positions - a significant fraction will sync almost immediately, the rest will not sync even if you wait for tens of seconds, at least. Moving the tiles (actually, rotating them) by hitting the resync button usually fixes the issue (note that this rotates all tiles).

World in question: https://vrchat.com/home/world/wrld_685838b2-dc34-47c7-8adf-92d5016075dc
Once 2019 is out I plan to be working on this world a bit more, so if I can find a consistent repro procedure I'll put in a canny.

inland aspen
#

Having way too much trouble getting a simple toggle synced. Basically I have two main objects, with two associated UdonBehaviors.

SteeringWheel: A VRC_Pickup which has a reference to the Particles Udonbehavior. OnPickupUseDown it sends a true value to the Particle Object. OnPickupUseUp it sends false.
Particles: A Gameobject with 3 children particles gameobjects. It checks the ParticlesState variable. and enables or disables the children

frozen igloo
#

pickup events are not synced, so you'd have to either make them network events or use a synced variable.

inland aspen
#

the variable I'm updating is on the Particles, and is marked Synced

#

does that not make them a synced variable?

frozen igloo
#

are you sure you're the owner of that object?

#

also it's very wasteful to constantly set it on update, that's every frame. It would be better to just use onvaluechanged.

inland aspen
#

ah good call.

#

So I should set owner of the particles object when I pickup the steeringwheel?

frozen igloo
#

yes

#

also might as well make the particle object manual sync so it's not constantly using bandwidth. If you do that, you'll have to call requestserialization after setting a variable

inland aspen
#

I think I'm switching the particles to use CustomEvents and I'll call them from the steeringwheel on use down/up

#

should be lighter that way

main sandal
#

OK this is getting a bit maddening, I'm trying to have a youtube link set to a button, so when the button is clicked it sends the URL to the video player and starts playing it. I'm using WolfeVideoPlayer and a script called KaraokeNorixMod that should pass the URL over to the video players URL input field. For experimentation, I have used jetdogs synced switch prefab, that should trigger a basic cube that turns on, with the script attachedto it. I cannot get it to do anything, despite having no compile errors, at a complete loss as to what I'm doing wrong.

#

(Cube appears) video player does nothing

#

alternatively, I guess the only other way is to make a video player for every URL I want, and have it trigger a new video player for each one...seems terribly inefficient to do that though

frozen igloo
#

it's unlikely that all those prefabs made by different people are just going to work together without any modification. It's likely that the video player requires more than just setting the URL. maybe it needs some event to tell it to play, idk. Depends entirely on how it's set up

main sandal
#

the script was made for this particular player (no instructions of course) I'm just using jetdogs script because it's 'easy' and I don't want to re-invent the wheel to just turn something on and off (that works) Is there any way to actually 'see' what udon is doing in the background step by step? It's really hard to troubleshoot these networking issues when there are no errors

frozen igloo
#

not ingame, no. But you could look at the video's script and see what it is expecting

main sandal
#

The video player itself works, when i type/copy/paste the URL into the field. I just want the button to populate that field because i'm growing sick and tired of having to pull off my headset to put in a URL from a web browser constantly :D

frozen igloo
#

right, so look at the current input field and see what events it is sending to the video controller

main sandal
#

ok I'll take a look

#

ugh way beyond my skill level....I'll just forget this idea and have it spawn a new video player for every URL, and remove the other one when a new one is chosen, way too difficult to try to figure this out (thought this would be simple, but I guess it isn't)

frozen igloo
#

could you at least take a picture of the input field's inspector?

main sandal
frozen igloo
#

no, I mean the input field that's built into the video player

main sandal
frozen igloo
#

the inspector of it?

main sandal
frozen igloo
#

I don't think that's the input field

main sandal
frozen igloo
#

wait what

main sandal
#

yeah I don't get it either XD

frozen igloo
#

that doesn't have any events, it shouldn't work

#

unless the video player is constantly looking at it waiting for it to change

main sandal
#

yeah might be

frozen igloo
#

can you try the udonsyncplayer in the udon example scene? It's built into the SDK

#

this is what that one looks like

main sandal
#

Yeah, I think maybe that would be better, I'll modify the script to work with that one

frozen igloo
#

it sends a custom event "OnURLChanged" to the video player

main sandal
#

I'm just using this one because someone recommended it to do this sort of thing...it looks overly complicated

frozen igloo
#

a lot of video players are

main sandal
#

allrighty, I'll give that a shot XD

languid snow
#

what are you trying to do?

frozen igloo
#

make a button that changes a video player's URL

main sandal
#

Looking at it, I think it's going to be far easier to just put a seperate video player with an autoplay URL pre=coded into it, and just make toggle buttons to turn on the appropriate player, and turn off any others that are already on. Thanks for the suggestions though.

frozen igloo
#

then you'd have to sync which video player is active

gritty rampart
#

I have another question about synced variables and object sync stuff:
I have a prefabbed object in my world, that if you press a button, a script will instantiate a clone of the object. The object has that VRCObjectSync on it to update its location and stuff. If player 1 joins the world and presses the button which creates a clone, and then after that clone has already been instantiated, will it exist for player 2 if player 2 joins after the fact?
Also, if it does not exist for player 2, if the object fires a network event in player 1's world, would that cause errors for player 2 if the object does not exist?

frozen igloo
#

instantiated objects do not support syncing

gritty rampart
#

They don't? Dang

sharp tinsel
# gritty rampart They don't? Dang

There's a workaround for it though, instead of instantiating, you can have them in an object pool and SetActive() them to do the same thing. But to achieve the sync you are looking for you also need another sync variable that keep track on which object is active and which is not. So when the new player join, they can receive this sync variable information and set active/deactive based on the info.

frozen igloo
sharp tinsel
#

😅 Okay, didn't know such a thing.

#

I just very don't like any auto sync functions delay so I coded all my system based on manual sync.

gritty rampart
#

vrc object pool script? I'll need to look at that

#

I've been wrestling with a system of watcher objects for players in my world, I need a watcher that follows a player around and tracks their position, which is simple enough, but I need someone so that players can join/leave a world instance frequently without breaking anything

sharp tinsel
#

^ ikr, that happens all the time. Player missing null reference, player in the world but didn't get recorded. I spent like a week trying to eliminate those weird errors but in the end I made a self-check-fix function to do that for me automatically. 🤪

celest mesa
#

What does object pool DO exactly? I haven't been able to find any documentation on it.

celest mesa
#

Yeah, that doesn't actually tell me how to do anything with the actual object pool. The example's for working around not having one yet.

errant siren
# celest mesa Yeah, that doesn't actually tell me how to do anything with the actual object po...

That points to the legacy docs for some reason, here's the up-to-date version: https://docs.vrchat.com/docs/network-components#vrc-object-pool

#

Between those docs and this example, I hope you can learn how to use it: https://docs.vrchat.com/docs/udon-example-scene#objectpool

lone zealot
#

so basically its a glorified synced bool[]? 😛

errant siren
frozen igloo
#

it's more efficient than just a bool[] because it packs the bits more efficiently. A normal bool[] actually uses up a whole byte for each bool

celest mesa
dusk marlin
#

Quick question, is there a way to get the VRCPlayerAPI of a player who recently called an SendCustomNetworkEvent?

#

Morning brain is going brrrrrrrr

dusk marlin
#

Yeah I'll go ahead and upvote those. Guess I gotta default back to my "OnPlayerJoined" userdata, and get when a userdata does the thing, we know which userdata can receive the playerdata.

#

Bleh

#

(I was secretly hoping since VRChat literally displays the user who called the event in the debug log, that we'd have access to that by now.)

quaint rain
#

A jank workaround would be to take ownership of the udon behavior and then send the custom event

#

You could then query who the owner of the object is

dusk marlin
#

Jank indeed. My issue is what if multiple users attempt at the same time. I've had a snafu there before. x3

quaint rain
#

You pray

dusk marlin
#

Having the host machine assign userdata objects to new players makes this way easier. X3

quaint rain
#

But ownership should be pretty reliable

dusk marlin
#

And I get that. But I want 100% certainty

lone zealot
#

Ownership changes are not instant remotely either. So that would create a race condition.

dusk marlin
#

Yeah, in my case here, we'd just be assigning each new player joining the world one of the possible WorldSize * 2 userdata objects, that retains our playerdata reference.

#

Thus we don't have uncertaintly

lone zealot
#

Well that is a whole lote more complicated than you might think. Without risking race conditions yet again that is.

dusk marlin
#

I've made it work before. :P

#

The host machine receives a OnPlayerJoined() event, give the UserData to that player. Now I have a trackable solution running around.

#

A joining player would ever call that once, and upon leaving, we just empty out the userdata.

#

In my case here, I am almost 100% certain that this code beats the whole race condition

#
    public override void OnPlayerJoined(VRCPlayerApi player)
    {
        if (Networking.LocalPlayer.isMaster)
        {
            // Let's give the new VRCPlayer a UserData to track them properly.
            foreach (UserData user in UserData)
            {
                if (user.VRCPlayer == 0)  // We found a UserData that is not currently assigned.
                {
                    Networking.SetOwner(player, user.gameObject);
                    Debug.LogWarning($"Player {player.displayName} has joined and has been assigned UserData {user.name}");
                    return;
                }
            }

            // No empty UserData was found.  Sad face.
            Debug.LogError($"Player {player.displayName} has joined, but no UserData can be assigned to them.");
        }

        // Non Room Master code goes here.  Join messages and UI events.
    }
#

Our UserData file contains the reference to the players VRCPlayerAPI index and t he PlayerData they would be assigned.

weak mirage
#

is it possible to see from who a custom network event was received in U#?

quaint rain
tawny nymph
#

Opening multiple clients does not work in the same way as being in a published world with friends, at least for me. I'm using the onDeserialisation Event to sync a mirror's active/inactive state for all players. When I test it in Build and Test with 2 clients, it works perfectly. But as soon as I upload online and have have a friend tell me if the mirror is synced, it's not. I thought the multiple clients should behave in the same way as actually having the world published... 🙂

north mountain
#

always test with 3

#

one who first joins and thus becomes owner, a second person who interact and maybe or maybe not becomes owner, and the 3rd one should join later to see if its correctly synced for late joiners

#

you can simulate late joining by disableing the "Skip GO button" on map load and then clicking go much later, after the first 2 players have already interacted with it

tawny nymph
#

@north mountainThanks, I just checked with 3 clients and the result was the same as when I tested it with 2 clients: the mirror updated for all clients. When I upload the world to VRChat's servers the mirror will not update for anyone else.
Has anyone else had issues with the clients not behaving in the same way as an published world? I'm so confused as to why it won't work when I build and publish

solar depot
#

VPNs ftw

errant siren
#

Yeah, variable serialization/deserialization order is not guaranteed. If you absolutely need variables to be updated at the same time, you'll need to use a struct that can include them both, or an array. This is how the new Video Player Example works, keeping two floats in a Vector2 to ensure they are always updated together: https://docs.vrchat.com/docs/udon-video-sync-player#update-time-and-offset

frozen igloo
#

I don't know exactly for vector3's, but the limit is around 60k bytes. If my math is correct, 60,000 / (32 * 3 / 8) is 5000

#

but it may be slightly off depending on how they get serialized. Not entirely sure

#

if you use onpostserialization, the serializationresult will give you the number of bytes which will be the most accurate way to know if you are approaching the limit

#

as for playerids, yes all players will agree on all playerids

lone zealot
#

Can you sync object[] ? Im assuming you cant, but I want to make sure.

frozen igloo
#

nope

#

that can contain basically anything, from a float to a transform

lone zealot
#

Sad. So sometimes its impossible to ensure that certain data arrives togethre?

frozen igloo
#

if it's manual sync I'm pretty sure they'll all arrive together

lone zealot
#

"variable serialization/deserialization order is not guaranteed." ?

#

Ohh I see order

#

But they should arrive together right?

frozen igloo
#

that's probably because the example is using onvariablechanged, not ondeserialization

lone zealot
#

Yeah thats why I dont like that event lol, and other reasons

frozen igloo
#

onvariablechanged will fire in a random order, ondeserialization fires after everything

solar depot
#

Thank goodness that I decided to finish scrolling before replying with concern to momo lmao.

solar depot
#

👏 magic

lone zealot
#

Yeah I had that issue too, but it makes sense once you understand how ownership works

lone zealot
#

The ownership request probably doesnt get handled in the same frame, so youre not owner yet when you request serialization. However youre right that that would be weird behaviour and probably not intentional...so I dunno either

tawny nymph
zealous prawn
#

Bit of a stupid question, but what is the easiest way to achieve a synced vec3 array? I have an array the same length as the number of players, and for each index, one player is writing to it every frame, and every player is reading the entire array every frame. I dont think I can use the built in synchronization. Also these vec3 are a type of custom position I need.

#

because rather than using a 16 length array. I could just have 16 individual vec3 and that would definatly work, but its so akward. was wondering if theres a better way

frozen igloo
#

the vector3 array isn't the problem, that's fine

#

literally just make an array and mark it synced

#

most likely the problem is instead that you are having multiple players trying to write to it at the same time. You need to transfer ownership first, then set it, then call RequestSerialization

#

this process takes a bit of time and if two players do it at the same time they will conflict

zealous prawn
#

yeah, essentially I want each entry in the vec3 array to have adiffernt owner, which is not the default beheavior of checking synced

frozen igloo
#

the only way to do that is to assign a completely different object per player

#

you cannot do this with a single object

zealous prawn
#

didnt think so but wasnt 100% sure. thank you.

#

I'm just going to add 16 vec3 variables and a lot of if statements, it wont be pretty, but it will work

frozen igloo
#

that's completely unrelated to your problem though

#

you can't have a different player own each variable

#

you have to have one unique owner for the entire object, that means the entire udonbehaviour and even multiple udonbehaviours if you have them on the same gameobject

zealous prawn
#

hmmmmm, oh, your completly right

#

I'm going to need to majorly rethink some stuff

fresh stump
#

does anyone know how to fix your inv and req inv, like I see my mic and emm notification but I dont see the invs and req invs

#

even when I open my menu

frozen igloo
#

This channel is for questions about Udon Networking. That sounds like a support question. But if by "emm notification" you mean "emmvrc" the modded client, then you should know that that's breaking the terms of service and is not supported.

Most likely it is not compatible with the current version of vrchat and you will need to clear it out by following the steps in #vrchat-support

frozen igloo
#

This channel is for questions about udon networking. That is a question for support. Please follow the steps in #vrchat-support

shrewd finch
#

How does vrchat handle instance owners and object owners leaving an instance? Is a remaining player assigned as instance/object owner, is the owner ID left attached somehow, or does the instance/object just become ownerless? Maybe I'm blind but I'm not finding that info in the documentation

north mountain
#

A new owner is selected

frozen igloo
#

It will always transfer to the person who has been in the instance the longest

shrewd finch
#

Got it thanks!

summer forum
#

I don't know if it is possible to use VRC's object pool and locally have each player control it. It's having some weird unintended behaviours when it cycles through the first loop of objects

summer forum
#

Actually, regarding TryToSpawn() from VRCObjectPool, does it also alter the position of the object in some way once that function runs?

meager mountain
#

I just want to send a simple string with an rpc, HOW

frozen igloo
# meager mountain I just want to send a simple string with an rpc, HOW

udon does not support sending variables with network events. If you want to set the string to a finite number of possibilities, you can just make a unique event for each possibility. If you need the string to be fully dynamic (or you don't want to bother with events) you will need to make it a synced variable

meager mountain
#

O god, well I need to sync the name of the player who interacted, so now I just change the owner when interacting and syncing the name up with the owner

#

Thanks for the quick response

#

What was the Udon sharp network code generator all about then?

frozen igloo
#

the code generator is if you have a lot of possibilities, but it's still a finite number

#

like if you want to have 100 events or something

meager mountain
#

oooo Man I was looking at that github page for so fucking long just confused of how the fuck they send the variable lol

frozen igloo
#

when you do SendCustomNetworkEvent, it just takes a string. You can construct strings dynamically, so you can do something like "event" + int to make event1, event2, event3, etc

raven pollen
#

I have a bit of a problem, I am trying to enable and disable some pickup objects with a button but that seems to only enable them for the instance owner or the local player, I am not sure which, but when someone enables them latter it spawns them at their spawn location and they are not networked at their correct position. How do I fix that problem?

#

Do I need to use on deserilization for this?

#

This is how the buttons spawn the objects at the moment. I did try the player api branch =false approach but that didn't spawn them at all as that boolen is allways set to 0

errant siren
raven pollen
#

will this work if they are disabled locally?

#

So say someone else enables the pickup objects

#

but you have yet to do so

errant siren
#

I can't see what else is going on in that graph - are you actually calling SetActive on the GameObjects to change their active state?

raven pollen
#

yes

errant siren
#

If you want to make objects visible and invisible for other players, you will need to use a Synced Variable to change the active states instead of just changing it directly. ObjectSync does not modify the active state of objects, it just moves the Transforms and Rigidbodies

raven pollen
#

ohhhhhhhhhhhh

#

those variable settings that they didn't explain at the begining of udon

#

ok hold up let me see if that works

#

the gameobjects cannot be synced

#

is active bool can though

#

Will test that out now

errant siren
raven pollen
#

I did see a download link for these though I will probe the examples as well that come with the sdk

#

actually nvm I just read the link

#

nope that didn't work

#

wait no it kinda worked?

#

nvm it did, thank you very much for the help momo

weak mirage
#

if I initialise a synced variable like [UdonSynced] bool test = true; and give it a default value true but someone sets it to false later will it get synced for late joiners as well or will it use the initial value?

#

okay thanks

lone zealot
#

It always starts as the initial value locally and then gets overriden.

wanton steeple
#

Hey all, so does Manual Sync mean I have to manually tell the clients that the variable has been updated? I've got an udon synced array of ints that's populating properly on the host, but all clients are returning an array just filled with 0.

#
public class Example : UdonSharpBehaviour
{

[UdonSynched]
int playerIDs = new int [48];
VRCPlayerApi[] playersBase = new VRCPlayerApi[48];

public void FillArrays()
{

  VRCPlayerApi.GetPlayers(playersBase);

   for (int i = 0; i < playersBase.Length - 1; i++)
            {
                if (playersBase[i] != null)
                {
                    playerIDs[i] = playersBase[i].playerId;
                }
            }
}
}
#

Here's my logic

#

So later in my code when I send a Network event with target All, that just prints the playerIDs array in each client's log, the host is correct, and each client just has 0s

frozen igloo
#

whenever you change a synced variable, you need to have ownership and then call RequestSerialization

#

this is the meaning behind manual; by doing RequestSerialization you are telling it that there is new data to send to the other players

wanton steeple
#

Okay that's exactly what I was missing, haha.

#

Thank you!

errant siren
wanton steeple
#

Thank you as well! I was looking at that, but I knew I was just missing the function that made manual.. well.. manual.

weary girder
#

Am I right in saying there's no simple way to send data along with an event?

lone zealot
weary girder
#

@lone zealot I've been working on collider impact sounds for props but of course, they only play locally. I'm looking to send events so they'll have some playback for non-owners, but seems I'll only be able to play them at a fixed volume rather than sending the volume data along.

lone zealot
#

The best approach to that is to sync the objects themselves and then detect collisions locally on each client

weary girder
haughty shuttle
#

thats exactly how it works. As long as you can see that object moving in your friends control, playing the audio and having it heard by all near it is just about your play method. try using a simple collision check that sends a net event to play audio.Play(); works without a hitch for me every time. Granted the sound might get delayed by a tick or two.

weary girder
#

That should hopefully be close enough. I mean, physics on objects once they've been released is very haphazard. It was curious. Throwing a object between myself in the UK and a friend in California on a EU origin server, we were mostly able to catch the item as catching an item favours the grabber as long as they successfully grab it in their simulation.
However something like just observing someone releasing an object and letting it drop to the floor, objects will often just hang in their released position for a while before suddenly getting a positional update, rather than letting local physics take over until another positional update is available.

#

The object certainly knows enough locally to know it should stop tracking with the other player's hand, that update comes through fine, but the fact it doesn't also switch back right away to letting gravity grab it is odd.

celest mesa
#

Just make impact send a network event that fires the collision audio and sets the volume from a synced value.

weary girder
main kayak
#

how can i know/where can i see why an attempt to send serialized data has failed?

haughty shuttle
main kayak
#

hmm, so what i'm trying to serialize is serializable, i seem had to add SerializeField bc they're private variables (also ps. i'm using U#) but that didn't help, any other info there is a bit confusing (i guess all that is not that important in this context here)

#

unless devs' claim that string[] can be now serialized is false

haughty shuttle
#

You tried tracking the movement of the value with Debug.Log?

main kayak
#

i'mma try that

#

ughh hold up

#

i saw something about null, couldn't it be the reason it fails to sync?
like my variable string[] will be allocated but i won't be using it fully immediatelly, as in i do new string[32] but i'm only using first 4 strings, the rest have null

#

also the data looking as expected

lone zealot
main kayak
#

yep, i've just tested it by putting "" in every string, now it does sync

#

ffs, that took me couple days to find out why my OnDeserialization wasn't getting called

sterile bison
#

For quest syncing, to clarify: I can remove every non-syncing script component under a gameobject as long as its name is identical in hierarchy between standard and quest versions?

#

Even say, different udon scripts, provided scripts on appropriate game objects, have identical [UdonSynced] variables?

frozen igloo
#

removing components should be fine, yes

#

especially if they're not udonbehaviours

#

if they are udonbehaviours, I thiiiink yes but maybe no

sterile bison
#

so i should just keep empty udon behaviours that have a script, but serve no purpose without their underlying colliders?

frozen igloo
#

huh, maybe

#

try removing them first, I don't know

sterile bison
#

probably a better test to keep them first, then remove them after if syncing does work.

frozen igloo
#

I'm much more confident that keeping it would work

#

removing them is what I'm unsure about

mental mountain
#

Isn't there post late update in U#?

frozen igloo
#

yep

#

it's an override

mental mountain
#

oh thanks

nocturne arch
frozen igloo
#

vrchat doesn't have a web panel, that was removed years ago for security concerns

#

it only has a video player

summer forum
#

Do we have any information on why a SendCustomNetworkEvent could fail? I'm currently executing it on a script where I am the owner, master and local for the script, yet it says it's blocked

frozen igloo
#

does the function start with an underscore?

summer forum
#

Nope

#

I made sure I didnt from what I read in the documentation

#

Its just getting randomly blocked ; ~;

#

at first I noticed it getting blocked by client, so I thought "okay, non-master, lets see if I can try as the master" but it also gets blocked, usually thought this happens when you aren't the owner, but each one is owner of their script

frozen igloo
#

I'm not aware of any way that network events can be blocked aside from the underscore

#

in the open beta, "none sync" was just added which would prevent network events, but it won't cause that log message

#

and if you instantiate an udonbehaviour, networking won't function but again, I'm pretty sure it won't result in that log

summer forum
#

Oh I saw that actually! Though, my intention is to send the event, not just to get rid of the blocked event

frozen igloo
#

do other network events work or is it just this one?

summer forum
#

I dont have any others that do sendcustomnetwork but... you did make me think of one thing

#

Let me try something real quick

#

Aha!!

#

Wow, this is weird, but okay sure I'll take it.
Turns out, because my scripts for every player (called Player_Slot0) were parented to a manager script

#

That kind of messed up the network calls? I'm surprised that messed up the master too, considering they are the owner to the manager of player_slots

pseudo creek
#

So, (hopefully) simple question; I have an object with an animator using an integer value, and a couple simple scripted buttons to assign the animator int to a certain value depending on which button's pressed... if I wanted to make it into a synced integer so it works for late-joiners, would I need to do that on the buttons, or the object with the animator itself? edit: nvm, I'm an idiot who didn't originally think to check with discord search if someone else had already asked the same thing >.>

solar depot
#

|| can hear tupper yelling somthing about forums in the distance ||

native quail
#

Hello, I am currently a novice at Udon and trying to understand some functionalities.

Currently, I want to make an interact function a global action for everyone in my world. I want to make it so that everyone can see a door open/close when I interact with a door handle. I saw that using a SendCustomNetworkEvent can work with this, but I am not sure how to implement it.

The following screenshot is how the Udon graph looks like right now:

#

The functionality itself does work, but it is currently local.

native quail
#

Ah, I just found out what went wrong. I should have made a custom event and connect it to where the SetBool arrow is at. Then, I should connect the Interact event to the SendCustomNetworkEvent.

upbeat iron
fossil kite
#

just to confirm: a pickup shouldn't need anything more than a VRCPickup and an Udon Behaviour in order to be synced, right?

#

ok wait, I just found a google result about 'vrc object sync' and that fixed it.

#

why did I think it needed an empty udon script..... did that change recently?

#

wait no yeah, I've got something else in the same room that just uses an empty udon script

haughty shuttle
#

Yeah that was sometime last year that the blank script/graph was used. Sync has been improved for a really long time.

fossil kite
#

ahh, OK, good to know, thank you!

errant siren
#

@fossil kite - FYI there's lots of documentation about how Networking works here: https://docs.vrchat.com/docs/udon-networking
That video at the top explains exactly what you discovered - that the simplest synced object is a VRCPickup and a VRC Object Sync

celest mesa
#

How exactly is the new "None" synchronization option supposed to be used?

errant siren
celest mesa
#

Yeah, I tried applying it to an existing script and it seemed to break or disable it.

drifting abyss
#

yea, I had a few scripts that are purely local with no networking whatsoever and it broke them outright.

raw umbra
#

Specifically atm

#
  1. Scripts with networking.none do not have start()/update() and can not recieve networked events
#

The first part is a bug though, so really they are kinda identical to local only scripts, unless there is some other use intended by VRC

celest mesa
#

I was trying to apply it to a script with interact() that sends a custom event to another script for the local player and it still broke the script.

woven pewter
#

Yeah, as far as I can tell currently all non-custom events are broken for None-synced objects. We'll have to wait for VRC to fix it before really making use of it (if you have UdonBehaviours that are purely for data storage or which only have events invoked via SendCustomEvent it may be usable for them though)

drifting abyss
#

I do wonder how that was missed in testing...

frozen igloo
#

set to none sync
syncing no longer works
pass
🤦

haughty shuttle
#

When you script I cant find a use for it unless its something special. If you want something local you just dont script for sync. period. Thats how I would miss it while testing, not having a reason for it.

frozen igloo
#

the purpose is to reduce the number of components that are doing things. It has an impact on performance

fresh stump
#

yes we need maximum performance

#

i am doing extreme number of computations in my mirror world

fresh stump
#

i have turned my vrchat world into a cloud service hehe all your base are belong to me

obsidian cedar
hearty sail
#

Hi! I'm trying to have a light turn on after 3 seconds after pushing a button, I have made this Udon graph and it almost works because it does turn on after 3 seconds... But then it turns off again. And on again. And so on every 3 seconds, what can I do to make it light on only one time? Thanks!

rapid oak
#

You are looping an event every 3 second. Try connecting the custom event to the Set Active only, and remove the flow from the delayed custom event to the Set Active

hearty sail
magic hornet
#

Hewo, i'm trying to make an exit player trigger (for disable a mirror) but i'm using "onplayertriggerexit" it takes all players in the map and i would want it only local, can someone give me some helps about that ?

magic hornet
bright mesa
#

How does property synchronization work? I mean in the assembler it is possible to specify .sync vector3Variable->x, linear, will this only synchronize the value of x field of the variable? Or is this functionality not implemented?

errant siren
#

the assembler does not have property sync, that's sugar added by the UdonSharp compiler

bright mesa
#

I checked and re-imported vrcsdk again, it looks like built-in functionality

errant siren
#

could you explain the problem you're trying to solve? Are you writing assembly code by hand?

bright mesa
#

I'm writing a compiler and decompiler for udon assembler, so i don’t understand what to do with this functionality

#

I would like to implement the full functionality if possible, so such moments are confused

errant siren
#

Ah, I understand. I'm afraid we don't have documentation on how to implement sync at the assembly level yet. You can find our basic assembly info here: https://ask.vrchat.com/t/getting-started-with-udon-assembly/84
And you can look at UdonSharp, UdonPie code, etc to see how others have done it.

#

looking at some assembly, it looks like you just need:
.sync symbolName interpolationType
where symbolName is a valid symbol (aka variable) that you define separately, and interpolationType is none, linear or smooth

bright mesa
bright mesa
errant siren
#

Ah ok - I think I understand now. You're looking through the code and you see that it's possible to specify the property of a struct for .sync like vector3Variable->x to sync just the x value of the given variable, and you're wondering if it's been implemented or not because you haven't seen any compilers that make use of it?

bright mesa
#

Yes

errant siren
#

If that's the case, then I'm sorry that I don't know if that particular syntax is fully implemented or supported, but you're welcome to give it a try and let me know!

bright mesa
#

Okay, thanks for the help anyway

twin iris
#

Will using Update event for RequestSeriilization cause problem?

#

I'm trying to sync some array between owner and other player but it didn't seem to work

twin iris
#

or Seriilization didn't work for arrays? even only one dimension?

strange oriole
#

It does

#

Don't serialize every frame though, do it only if the data changes.

#

Also do you make sure your player trying to serialize is the owner of the game object ?

twin iris
#

is this make the player the owner of the game obejct?

strange oriole
#

If data storage game object is the object with the Udon behaviour, yes

twin iris
#

it is

#

do I have to make the role variable and role_sync both 'sync', or I have to leave the local one not checked?

cedar escarp
#

Hi any possible reason the OnDeserialization wouldn't get called?

#

I've set the UdonBehaviourSyncMode to BehaviourSyncMode.Manual. Besides I have the similar set up for another gameobject in the scene and it worked just fine. It is a empty object I made into a prefab with a UdonBehaviour component whose OnDeserialization is not working. I used VRCInstatiate to spawn the prefab as a gameobject in the scene.

lone zealot
cedar escarp
twin iris
#

is there a limit for function like getprogramvariable or sendcustomevent?

lone zealot
cedar escarp
cedar escarp
lone zealot
cedar escarp
strange oriole
lone zealot
frozen igloo
#

object pool isn't an udonbehaviour

strange oriole
#

Pretty sure it works in udonbehabiours

#

Actually My experience is with udonsharpbehabiours, not sure about udonbehaviours

twin iris
#

can I use two ondeserialization nodes in same project but in two different udon program?

frozen igloo
#

yes of course

#

ondeserialization happens when the object receives any synced data, so it would be quite limiting if you could only have one in the entire project

twin iris
#

got why mine serilization didn't work...just used array.copy and array.copyto in a wrong way....

bright mesa
twin iris
#

I can't sync int array....

#

so when player2 died, he will be set as owner of the Data cube, and set his status to 0(IsAlive[1]), which means he's dead, then request serialization

#

and on deserialization, player1 should be sync with the IsAlive data sent by player2, but it stays the same

strange oriole
#

Not regarding your problem, but I don't think you can use GetPlayerId as an index for synced arrays.
If i remeber correctly the player ids are different for different users. NetworkIds are the same, but cant use those directly either since they keep growing if player leave and join

twin iris
#

GameID[] is an int array that store playerID when they join the game

#

I use some display to make sure player2 is set to be the owner and set the correct value for the array, but it didn't sync to player1

#

everything I put behind OnDeserialization just didn't work

strange oriole
#

Oh, i see. I would try adding some debug output to the on deserialization method. Check if it fired, if Totalplayercount is the right length, maybe even iterate over both arrays and look what's inside.

#

Try to narrow down where it fails

twin iris
#

that's what I already did

#

I put a debug output just behind deserialization, before anything else

strange oriole
#

What exactly is data storage game object? Is that a variable you defined yourself ?

twin iris
#

just a cube that I run the udon program

strange oriole
#

You should be able to do something to the equavalitent of this.gameobject

#

That way you can make sure you set the ownership for the object with the script

twin iris
#

I also did that with Isower() if true ,set text to 'owner'

strange oriole
#

Did you confirm it sets the array correct on the owner side ?

twin iris
#

yes

strange oriole
#

Also did you try plugging the gameoebject into the request serialization method ?

twin iris
#

no, i don't put object into that, leave it blank the udon program will fill in itself

strange oriole
#

Yeah I know, but everything else looks correct, so that was my last guess.

#

Just to make sure cause it's the last thing I an think of, your udonbehaviour is set to manual sync ?

twin iris
#

yes

#

OK I see, I need OnPreSerialization event

#

not DeSerialization event

#

However I use requestSerialization with OnDeserilization in other udon programs and they did work.....

#

....

solar depot
#

PlayerIds are consistent across clients per instance.

strange oriole
#

ah yeah, i was wrong. Player ids are the players network ids.

main kayak
#

how does one instantiate a prefab on all clients? like i know there's VRCInstantiate but it does it locally only

main kayak
#

so i thought

#

the problem i find with object pool is that it has fixed count

errant siren
#

right - you'll want to decide the maximum number of objects you'll allow

#

this would be the case even with Instantiation

main kayak
#

well it should be at least like couple of hundreds but it would be wrong to have couple of hundreds of prefabs spawning at the beginning of joining the world

errant siren
#

they won't spawn when someone joins, they'll already be there, but set inactive

#

so rather than experiencing a hitch as an object is created, they do all the loading up front

main kayak
#

but then like i have to put like hundred of these prefabs in the scene and manually put them into that pool array

errant siren
main kayak
#

yeah, uhm, i find that lame

errant siren
main kayak
#

ok nvm, i found another solution for my problem

errant siren
main kayak
#

the thing is, i also need the synchronize some data, and as with my testing, trying to do VRCInstantiate at the same time and do some syncing doesn't work, i thought to have one synced data, and when i change it, it sends the data to other clients, and on OnDeserialization i use VRCInstantiate and set the value locally.
but again, thinking of that, it won't do anything for the late joiners

errant siren
#

right. You could sync an array of data to update things for the late joiners, but you'll have to either set the size of the array to the max number of items you'll have, or recreate it if it's expanded beyond its original size.

main kayak
#

anyways for the context, i'm trying to make my own pens that synchronize the lines

errant siren
#

That's somewhat like how the Udon Pens work

#

oh haha - what do you want it to do different from the existing pens?

main kayak
#

to have a ui on pens instead of the triggers, like the QvPens has it

#

i already did it before, but i did it in classic way, just sending the events of starting and ending the drawing

errant siren
#

you could just duplicate and modify the provided pen prefab or the fancier one from the VRChat Sketchbook Jam

#

that one uses synced arrays to update line points for late joiners

main kayak
#

yeah, the thing is, i also want to understand how the whole thing works

#

but that's like array of array of Vector3?

#

and array of arrays is not (yet) available?

errant siren
#

and this one explains some of the more complex ones included in the Sketchbook Jam Example: https://www.youtube.com/watch?v=LHwmlU3ZZTc&t=518s

Check out the example world for our first World Jam!
You can find more info and join in at https://itch.io/jam/vrchat-sketchbook-jam

0:00 Welcome
0:09 Theme Reveal
0:32 Trying each Drawing Tool
1:31 Build, Test, Publish
3:31 Changing the Lines
6:44 Changing the Color Picker Graphic
7:48 Changing the Models and Textures
8:11 Intro to Udon Progr...

▶ Play video
errant siren
wary inlet
#

I want to make a script that opens a door while players are standing in the trigger area and closes it when nobody is in the trigger area

#

I should also note that the doors in question are double doors and I want them to open by using animations

solar depot
#

Have a script that increments a counter everytime OnPlayerTriggerEnter is called and decrements said counter when OnPlayerTriggerExit is called. Then do a check each time to see if the counter equals 0, and change the door state accordingly.

wary inlet
#

Do you have a visual aid I could look at?

solar depot
#

Not on hand. I'm on mobile atm.

errant siren
# wary inlet I want to make a script that opens a door while players are standing in the trig...

this tutorial walks through making a door, controlled by an animator, which reacts to player enter/exit. Should be a solid start for you: https://www.youtube.com/watch?v=95jRByYHE4Y&t=663s

These features are currently available only on our Open Beta version - check our Discord for more information.

Learn how to make doors that automatically open and close to let players through. This tutorial will use the Udon Graph to work with Player Triggers, Haptics (aka controller vibration) and controlling Animators with Udon.

Music i...

▶ Play video
supple cradle
#

Hi, if A sent a custom network event to all, then B sent one immediately, how would others recv these events? is it guaranteed that msg A would be recv first by everyone?

#

one way to make sure everyone having the same result is sending a msg to the owner then the owner send it to others, but there will be one or more seconds' delay when using manual sync.😂

solar depot
#

Manual sync is faster than custom network events.
There is no way to guarantee order of network events received from separate clients.

flint cedar
#

What are the rules for Instance and GameObject Ownership in Udon, particularly if an instance or GameObject owner leaves the world?

  • How does ownership automatically transfer in this instance?
  • Is OnOwnershipTransferred called in all cases regardless of whether you facilitate the ownership change or VRChat due to players leaving forces the change?
frozen igloo
flint cedar
frozen igloo
#

Then it will transfer to the new master. The master is always the person who has been in the instance the longest

flint cedar
#

Phew, the rules are nice and straightforward. Thanks ^-^

supple cradle
solar depot
#

Mainly cause of general global network delay.

fiery grove
solar depot
#

Also there are different priorities of various network activities.
Manual sync is on the highest priority. Custom network events are on the (for lack of better term) medium priority. Continuous sync is on the lowest priority.

#

So you have general network overhead and internet delay, plus the "medium" priority limitations of a custom network event, doubled cause of the round trip to pass data back.

#

It all adds up.

supple cradle
#

i tested this on one PC with 2 VRChat clients, there is still an obvious delay. 😂

#

and, if i change it like this. the delay gone.

#

A is client and B is owner (Manual sync)
client A -> become owner -> SendCustomNetworkEvent(target.Owner) -> client A (new owner) change values -> RequestSerialization -> client B OnDeserialization

#

thus, the delay comes from SendCustomNetworkEvent ?

frozen igloo
#

yeah, custom network events are usually around 0.5 seconds

#

manual sync is about 0.2 seconds and continuous sync is minimum 2 seconds

fiery grove
#
[UdonSynced] bool _active = false;

public bool Active
{
    get => _active;
    set
    {
        if(_active == value)
            return;
        
        _active = value;
        if(activeParamId != -1 && anim)
            anim.SetBool(activeParamId, _active);
        
        RequestSerialization();

        foreach(var device in devices)
            device.Active = value;
    }
}

public override void Interact()
{
    if(!Networking.IsOwner(gameObject))
        Networking.SetOwner(Networking.LocalPlayer, gameObject);
    Active = !_active;
}

public override void OnDeserialization()
{
    Active = _active;
}

Is this going to result in an infinite loop of serialization and deserialization?

#

I'm using manual sync.
Not sure about RequestSerialization in there, but I want to sync with late joiners

#

I'm syncing a light switch (at the moment) and also need to sync everything it toggles so the device.Active property looks the same as this one

frozen igloo
#

That should work, but Active = _active is not necessary. You should instead add [FieldChangeCallback(nameof(Active))] to _active

#

The requestserialization in the property isn't going to do anything if you're not the owner, so it'll work. But I think it will log an error or warning so you might as well check if you're the owner first

fiery grove
#

Ah, thank you

#

Is it worth caching Networking.LocalPlayer?

#

or should I just pass Networking.LocalPlayer every time

#

(since I guess it's cached in there)

lone zealot
#

caching saves you an extern

frozen igloo
#

Getting it from networking is probably an extern. The extern itself isn't expensive, but it would have to be scanned by the blacklist which is. If it's stored as a variable it doesn't need to be scanned anymore

#

Still, it's a minor thing that wouldn't make any difference unless you're doing something dozens of times every frame

fiery grove
#

I'm not, but I'm thinking there might be lots of scripts in the scene

#

so every little (simple) bit wouldn't hurt I'd think

#

Thank you vrcAevSlap

strange token
#

Not expecting lots of scripts at some point is bad programming 😛

#

Especially if you start the project intending to define your scope eventually, like me!

fresh stump
#

having lots of code with very little scripts might seem like a good thing but trust me it's not and you should never fall for that trap

solar depot
#

It's a balance. Some might even call it a form of art.

fresh stump
#

it is... interesting

lone zealot
#

However that's only for "real" C#. Udon is...well quite different

fresh stump
#

having to scroll more than three times in a single script is a no from me

#

for some cases it's understandable

#

like if you were making some binary format reader

fresh stump
#

I create 1 file per variable

lone zealot
fresh stump
#

it is in the Manifesto for Agile Software Development With Udon

fiery grove
#

I'm making a state machine without inheritance

#

It's bound to be a big script vrcChicken

#

Are there any attributes to tell the compiler how to handle certain method calls, like inline it?

lone zealot
#

No its not necessary since Udon is simply a VM. The difference would be a single JUMP instruction, which costs nothing at all compared to any extern.

#

Functions that are called in the same behaviour are jumped to, behaviours called via reference are called with SendCustomEvent

fiery grove
#

Ah, I see

#

So to optimize try to pack everything into a behaviour on an object instead of multiple on the same object talking to each other

lone zealot
#

Technically yes. Architectural thats bad for encapsulation / seperation of concerns. However in Udon, design principles kinda go overboard anyway.

solar depot
#

Udon aka thicc spaghetti.

flint cedar
#

slow spaghetti

fiery grove
#

What happens if I have a few scripts running on the master only (like the server in most games) and the master leaves the world?

#

I know the next oldest person gets set as the master but the values get lost if I didn't sync everything right?

#

So does it mean I need to sync even values that the client isn't going to make use of in case they become master?

frozen igloo
#

yes, that's correct

fiery grove
#

oof, I guess that makes sense

fiery grove
#

How would I go about having a circuit breaker that enables and disables power for a bunch of devices without referencing every single device on the circuit breaker

#

Rather thinking of referencing the breaker on the device

#

Is there a way to send a network event for all udonbehaviours of a type?

#

Or would I just need to shove all the devices into the breaker script

#

I want when a device gets turned on to tell the breaker that it's using some power and when too many devices are on it should trip, which is simple, but how I talk back to the devices to turn them all off

frozen igloo
#

you could have an array of "connected devices" on the circuit breaker, and when a device is connected it will be added to the array. When it trips, the breaker will loop through all it's connected devices and tell them the power is out

fiery grove
#

That could work, but what about the other half of power draw then

#

Do I just reference the breaker on every device, and all devices on the breaker..?

frozen igloo
#

the device has to reference the breaker, but it should be added to "connected devices" automatically

fiery grove
#

Oh so should it just add itself to the breaker's array on device's Start()

frozen igloo
#

yeah

fiery grove
#

How would I do that without a list?

frozen igloo
#

just have a fixed length

fiery grove
#

Do i just declare a big array and hope it's enough

frozen igloo
#

a breaker only has so many slots anyway, right?

fiery grove
#

Yeah but not sure how many just yet

#

A little annoying you can't just GameObject.FindObjectsOfType<>()

obtuse echo
#

You can still do stuff like GetComponentsInChildren<>. I'm assuming those devices will be synced somehow? Then it's probably a good idea to keep them at the same parent anyway.

fiery grove
#

I haven't really decided but that's a good idea