#udon-networking

1 messages Ā· Page 8 of 1

hollow wagon
#

and the function itself works, its just not networking to other players.

#

Handle serialisation is just activating and deactivating gameobjects. And for the local player it works. It never gets to the other players.

sweet wolf
wispy turtle
#

Hello, I am programming a VRChat world using UdonSharp (with SDK3) that includes a gaming table. I'm looking to implement a system that saves a player's preferences in VRChat so that when they return later, they can find and add to their score. Ideally, I'd like to be able to store a string containing "lastVisitDate/score/pot/cardObtained/etc" (to.string). šŸ˜‰ Another option would be to upload/download this string to a directory on my Google Drive or NAS. Does anyone have any suggestions? I've tried using: PlayerPrefs.GetString(playerScoreKey), but it wasn't accepted. Thanks in advance.

tulip sphinx
#

@wispy turtle you cannot arbitrarily store and request the data, you cannot use PlayerPrefs, its not in udon. All the urls to store/get data online should be either made on build (so its a constant link and readonly) or be entered "manually" via url input field by player every time (so in theory you can format this link automatically and make player submit it via urlfield like mysite.com/?user=amogus&score=356 but nothing stops the player from not submitting it if he lost some points from the last time or smth, let alone crashed without saving). Talk about persistentcy in worlds was for years now but nothing yet.

#

thas how i get it at least

wispy turtle
tulip sphinx
#

@wispy turtle you cannot upload, you can only request some link. Some nodejs or smth server then can parse the data from that url and store it. But for this link to be custom it needs to be submitted by a player, you cant just do in udon "get 'mysite.com/'+PlayerName" or smth, it should be constant.

wispy turtle
#

In UdonSharp, it's quite straightforward. Here's a simple example using Random.Range to pick a random number between 1 and 10:

    int randomNumber = Random.Range(1, 11); // Random.Range is inclusive for the min, exclusive for the max.

is that you'r question ?

wispy turtle
tulip sphinx
#

@wispy turtle generally yes, each instance is unique and theres no dedicated methods to store the data between them or upload smth outside.

wispy turtle
fresh stump
cold laurel
spiral blade
#

hey, im trying to use this package : https://github.com/Miner28/NetworkedEventCaller, but in the "Your code setup" section, it says to inherit from NetworkInterface. does that mean replace the UdonSharpBehaviour inheritance with NetworkInterface?

spiral blade
#

ok, do I need that on a seperate script? the script i want to call and recieve the networked event from needs udonSharpBehaviour

#

wait nvm, i was looking at the wrong script lol

cold laurel
spiral blade
#

ok

#

whenever i add [NetworkedMethod] to a method that inherits from NetworkInterface, it says the attribute doesnt exist

spiral blade
#

namespace?

cold laurel
#

Can you share a screenshot of your code?

spiral blade
cold laurel
spiral blade
#

ok

cold laurel
#

Your editor was a little too helpful and guessed wrong

spiral blade
#

ohh i see

cold laurel
#

You need using Miner28.UdonUtils.Network;

spiral blade
#

it implemented the wrong interface

#

thank you

obsidian cedar
#

I do wonder how many people use the prefab these days vrcAevSip

#

https://github.com/Miner28/NetworkedEventCaller
I did release a new version today as well HappyWiggle

Uses variable integer encoding, meaning less data transfered over network
Next up's gonna have to be a project clean up and soonTM I plan to work on "TCP" and priority support as well as multi-method sending and player targeting
Once all that's done it'll be able to entirely replace the entirety of SendCustomNetworkedEvent xD currently it suffers with the limitation of about 8 events per second and it's "UDP" design

GitHub

Contribute to Miner28/NetworkedEventCaller development by creating an account on GitHub.

frank fjord
# obsidian cedar https://github.com/Miner28/NetworkedEventCaller I did release a new version toda...

I'd love to know more about how this works under the hood! How does it handle the issue with vanilla Udon networked events not being lockstep with synced variable updates, for example? Does it solely rely on synced variables to operate?

And when you say it's limited to 8 events per second, do you mean actually 8 discrete event calls? Or some larger number of calls, but only processed in batches 8 times a second? (Sort of like how normal Udon network serialization events occur 5 times a second)

obsidian cedar
# frank fjord I'd love to know more about how this works under the hood! How does it handle th...

It solely relies on synced variables, from my testing ~8 serializations per second is something the UdonNetwork can handle and catch up to if its not for too long of a sustained time.
It currently is made without reliable networking in mind (meaning there is no checking for skipped events) However, me and a decent list of people have been using it extensively in our worlds and the drop-late is sub 1% for normal use-cases.

I plan to solve this issue of it having a chance of skipping events in future update someday in the coming weeks, however its not an super easy thing to do. I also plan to implement multi-method sending as I mentioned which will serialize multiple network methods in 1 batch, meaning if you in 1 frame send 100 network calls, they will all arrive at once, no 8m/s, I already have code partially ready for this but still expect ~week before I get that done.

frank fjord
#

Ah okay, so it sounds like the limitation is more a bandwidth limitation. I imagine it's still actually doing the standard serialization call 5 times per second to send the custom 'events' you're encoding? Just that it uses a fair bit of data...

#

In either case, I'm super interested in seeing where this goes. A reliable way to send networked events in GENERAL would be a huge step up from what we have right now, and being able to send data with those events is game-changing.

obsidian cedar
obsidian cedar
frank fjord
obsidian cedar
#

But first step is gonna be organizing the code bit more, due to some micro-optimizations I'm writing this in a way where both sending and receiving method have around ~1k+ lines which gets bit crazy to navigate though next update is gonna be organizing that a bit, maybe by abusing partial classes or somehri7

obsidian cedar
frank fjord
#

Okay, gotcha.

frank fjord
obsidian cedar
#

It's actually optimized when it comes to performance, just not when it comes to working on it

frank fjord
#

Hahah. Fair.

#

Wishing you good luck on furthering this project. Good networking is definitely a huge obstacle for world development...

obsidian cedar
#

Nod I love figuring out all the ins and outs and challenges of networking, it's fun (until VRChat breaks)

frank fjord
#

I'm glad someone likes it!

lusty pagoda
#

meanwhile back to networking

#

what is the way of syncing event around 1000 times in span of 3 minutes making them as fast as possible as well making sure not a single of them drops

tulip sphinx
#

youre tryin into dmx arent you

lusty pagoda
#

hell no

twin nacelle
#

as well as making sure not a single one of them drops
first, you'll need a perfectly reliable network.
nobody's figured that part out yet.

hollow wagon
#

Is there any way to transfer instance ownership to another player?

tulip sphinx
#

each object has its own ownership that can be transferred. unless you mean a nickname near instance's info, i dont think that can be changed

vapid pagoda
#

make sure sync mode is not set to None

hollow wagon
vapid pagoda
#

oh object sorry misread

#

you cant transfer instance ownership

#

instance master is always the player with longest time in the instance

finite folio
vapid pagoda
finite folio
vapid pagoda
vapid pagoda
#

you can then use something like

[SerializeField] Transform cameraView;
VRCPlayerApi localPlayer;

void Start() {
localPlayer = Networking.LocalPlayer;
}

public override void PostLateUpdate() {
VRCPlayerApi.TrackingData headData = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);
cameraView.SetPositionAndRotation(headData.position, headData.rotation);
}

and attach a transform to the players face, then attach the canvas as a child object with some forward offset

finite folio
vapid pagoda
# finite folio Damn, I didn’t imagine such a complex concept.

haha sorry, just create a new U# script and add the code, and create a gameobject, add the script and attach the canvas as a child

VRCPlayerApi localPlayer;

void Start() {
localPlayer = Networking.LocalPlayer;
}

public override void PostLateUpdate() {
VRCPlayerApi.TrackingData headData = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);
transform.SetPositionAndRotation(headData.position, headData.rotation);
}```
#

should probably work, untested

vapid pagoda
#

youre missing the class

finite folio
#

True

#

I'm not a programmer.

vapid pagoda
#

sorry i didnt include it

finite folio
#

But everyone speaks easily

vapid pagoda
#

let me set it up for you

vapid pagoda
# finite folio But everyone speaks easily
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

[UdonBehaviourSyncMode(BehaviourSyncMode.None)]
public class aaa : UdonSharpBehaviour
{
    VRCPlayerApi localPlayer;

    void Start() {
        localPlayer = Networking.LocalPlayer;
    }

    public override void PostLateUpdate() {
        VRCPlayerApi.TrackingData headData = localPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);
        transform.SetPositionAndRotation(headData.position, headData.rotation);
    }
}```

make sure your script name is not just numbers
finite folio
#

I just took udon from a Japanese guy, but he didn’t show how it should work for VR

finite folio
#

done

vapid pagoda
#

just make sure the file name is the same as class name in this case "aaa"

finite folio
#

I understand

vapid pagoda
#

you can change it though

finite folio
#

What's next?

vapid pagoda
#

create a gameobject, add the script and attach the canvas as a child

#

you might want to move the canvas a little forward, so that the player will look directly at it

#

you might need to experiement around with it

#

you can test it in play mode though

finite folio
#

work

#

Now I’ll redo it and then look in VR

vapid pagoda
#

šŸ‘

finite folio
#

From PC on site, to VR on other sides

vapid pagoda
vapid pagoda
#

once you get it set up, you can design it however you like

#

if you need numbers, you can try this on your canvas

finite folio
#

Just in case, I’ll say that I saw 2 of them on the left and right sides of the lenses.

vapid pagoda
finite folio
vapid pagoda
vapid pagoda
#

ah, not sure if you can use canvas scaler and raycast wont work

#

or well, you probably dont need it

finite folio
#

Everything is confusing and it goes on and on

vapid pagoda
#

why do you have multiple of these? you only need one

#

or do you plan to change show different images?

lone eagle
#

can someone help, and tell me whats going on 😭

#

91 errors..

finite folio
vapid pagoda
finite folio
#

Same lyrics

#

Except the name

vapid pagoda
#

the service is no longer available

lone eagle
#

ohhh oki-

#

ty

vapid pagoda
#

unity switched to plastic scm if you require it still

vapid pagoda
#

maybe try using one for now to see if it works in vr?

#

and unparent the FollowUI_Simple from it's parent

lone eagle
#

im guessing i gotta press no?

vapid pagoda
lone eagle
#

mkk

vapid pagoda
#

you have a weird set up xD

lone eagle
#

Idk what i did to set it up wrong-

#

EDIT: I now wholeheartedly recommend using World Creator Assistant to set up your VRChat world projects! It's now the way I set up all of mine!
https://youtu.be/F1Tr3Nc9Rxs
https://ask.vrchat.com/t/world-creator-assistant-automate-vrchat-world-project-management/7571
https://github.com/Varneon/WorldCreatorAssistant

Download Unity - https://docs...

ā–¶ Play video
#

to learn how ot make a world

#

oh wait

#

im stupid

#

its a year old-

#

damn im slow..

vapid pagoda
#

are you using vrchat creator companion?

lone eagle
vapid pagoda
#

yeah dont use manual installation

#

click the link right above

lone eagle
#

ohhhhhhhhhhhhh, damnit, i gotta redo this-

#

kinda

#

ish

#

how do i delete the package-

#

thing

#

the manual one

#

how am i this slow..

vapid pagoda
#

dont worry about it for now

#

just get the creator companion, install it and click create project and select world

#

thats it! you should be able to follow the tutorial after (maybe)

finite folio
vapid pagoda
lone eagle
#

to fix the errors i go up to the collab thing right?

vapid pagoda
#

no

#

wait

#

why is collab on again

finite folio
#

I'll try to make it bigger then.

vapid pagoda
#

maybe this is enough

finite folio
vapid pagoda
#

maybe turn it on and and turn it off right after?

vapid pagoda
vapid pagoda
sweet wolf
vapid pagoda
#

im not talking about it removing vrchat sdk, im talking about it messing up the packages that need to be shipped with the sdk

sweet wolf
lone eagle
vapid pagoda
vapid pagoda
lone eagle
sweet wolf
lone eagle
#

I need help in vc or smth, cause thats so much easier

vapid pagoda
#

what do you gain from being rude and misleading?

lone eagle
#

Whats happening?-..

vapid pagoda
lone eagle
#

alot less often

#

let me clear it and see what happens

vapid pagoda
#

does the collab button still exist?

#

xD

lone eagle
#

no

#

it doesnt lol

#

omfg, here comes the errors...

#

JEEZ

paper gyro
#

networking networking. hate it lol.
is this how you do manual sync?

#

(at bottom)

vapid pagoda
#

you dont need to call network events in OnDeserialization

#

instead just use Activate()

#
using System;
using UdonSharp;
using UnityEngine;
using UnityEngine.UIElements;
using VRC.SDKBase;
using VRC.Udon;

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]

public class NewYearsTheme : UdonSharpBehaviour
{
    public GameObject[] toggleObjects; // Objects to controll 
    [UdonSynced]public bool status;   // Status of the theme
    public Toggle toggle;            // the override toggle in menu.



    private void Start()
    {
        DateTime dt = DateTime.Now;                                                  //
        if (dt.Day < 25 && dt.Month != 12 || dt.Day > 5 && dt.Month != 1) return;   // Checks date 

        status = true;    //
        RequestSerialization();
        OnDeserialization();
    }

    public void Activate()   // Activates/disables theme objects
    {
        for (int i = 0; i < toggleObjects.Length; i++)
        { toggleObjects[i].SetActive(status); }
    }

    public void ForceToggle()   // Override toggle in world for MASTER
    {
        if (!Networking.IsMaster) return;

        status = toggle.value;
        RequestSerialization();
        OnDeserialization();
    }

    public override void OnDeserialization()
    {
        Activate();
    }
}```
#

network events are meant for things that happen once, and can be forgotten right after, for example playing a sound

paper gyro
#

thank you

#

makes sense

raw roost
#

Have you guys found that only an owner was updating a udon synced int[]? I have been trying to use RequestSerialization and FieldChangeCallback and it’s kind of weird…values are updated but not all of them in the array. I don’t transfer ownership on the class that manages this array, should I be passing that ownership around? Thank you for any help on it as int[] have been very handy.

fresh stump
raw roost
#

Oooooh yah that makes sense… thank you for confirming this! I will tweak my code to either send a network event targeting the owner or transfer ownership…hmm may have to transfer ownership since I can’t pass variables around either. Ack!

frozen igloo
paper gyro
#

if i only do SencCustomNetworkEvents. how would i do it with manuall sync?

#

requestserialization after/before any NetworkEvent functions?

sweet wolf
#

NetworkEvent replace with requestserialization
It is not recommended to combine them.

paper gyro
#

i should add there is no variable syncing going on

sweet wolf
#

It doesn't matter whether you place it before or after in the code.
In reality, it is unknown whether OnDeserialization or NetworkEvent will work first.
The variable may not change in fact, but the event will work and vice versa.

#

They cannot be combined.
The result is unpredictable.

sweet wolf
cold laurel
paper gyro
#

Ah thanks

#

I were just wondering since the tooltips on the udon component are a bit vague

#

Oh that. Script. I redid it properly. What I made at first was so bad ehe

#

Sleep deprivation, i blame it on that

devout mountain
#

My Networking is not working. Im calling my method like this: "SendCustomNetworkEvent(NetworkEventTarget.All, nameof(OpenMainStage));" in a interact, but it does not get synced to other players. Players would have to rejoin to sync again. How would i fix this?

frozen igloo
shy path
#

^

frozen igloo
#

it's a work in progress šŸ˜…

#

glad to hear you like it

tulip sphinx
#

great vid, was ignoring network cause it made no sense and used some cursed stuff when needed one

#

now do u#😈

hybrid dagger
#

How would I go about making a udon graph that when a player enters a trigger area a sound effect plays which doesnt loop?

hybrid dagger
#

This doesn't work, what am I doing wrong? I do not understand

frozen igloo
frozen igloo
#
  • use onplayertriggerenter
  • onplayertriggerenter gives you a player
  • plug that player into a "playerapi.islocal" node
  • plug the result of that into a branch
  • also plug the flow of the onplayertriggenter into the branch
  • plug the "true" side of the branch into the playoneshot
frozen igloo
#

don't forget to connect the onplayertriggerenter to islocal

hybrid dagger
#

ok just did ill test it out

hybrid dagger
tulip sphinx
#

i have an animator with one long looped animation. i want to network sync it. my current idea is to send network event every time it loops and event just sets animator bool to true, causing transition to the same animation as other state. So late joiner sees anim1 (unsynced) and on network event instantly transitions to the anim2 roughly the same time as owner, and stays there forever ignoring all the next events. sounds sane? i dont need much precision and i dont mind one-time tearing

sweet wolf
tulip sphinx
#

@sweet wolf well yes, animation event -> network event -> trigger animator for everyone

#

hows continuous sync works in this case, doesnt it just updates variables in behaviour?

#

also do i need to care about checking the ownership or i can just send custom network event by default and non-owners will just ignore that part

sweet wolf
#

The load on the network is a little higher, but everything is working right away.

tulip sphinx
#

oh shi, theres playbackTime? thanks, never seen it, makes things easier i guess... UTC sync also looks great and totally would work.

gilded depot
frozen igloo
#

that depends entirely on who is generating the events though. You don't really get to just distribute that evenly most of the time, because if every client already has the information they need to "take turns" syncing events... then why do they need to sync it at all?

frank fjord
#

Continuing from Udon General...

TL;DR. Multiplayer (4p) base defense game. Classes, abilities, unlocks/upgrades. Waves of enemies that approach the base in a MOSTLY deterministic fashion and then attempt to damage your monument. This deterministic behavior can be upset if players apply certain statuses, such as a slowdown or a stun, from their abilities.

I'm trying to come up with a way to

  1. locally simulate enemies per client, without using VRCObjectSync, so that players 'see' one another taking actions at accurate positions in space instead of round-trip-delayed last positions of enemies

  2. create a system where players can send messages about the actions they're taking and the targets they've hit, when, and with what effects, accurately and reliably to support goal 1

#

Basically, the 4 players are the ones generating 95% of the events. Outside of player attacks and ability use, there's a small amount of gameplay information from SOME enemies buffing each other, or executing attacks on the players' monument.

#

... as well as like, non-time-urgent information such as wave setup synchronization and unlocks between waves

#

but I'm not worried about the non-time-urgent stuff. I'm focusing on in the middle of a wave, where there are enemies moving around and players taking actions, shooting things, using powers

gilded depot
#

for this i'd have a few objects maintaining modular mostly systems
unless the enemies are randomized mid-wave they shouldn't need much if any synchronization (a list of who shows up where and when at the start would do)
classes and unlocks could be handled by the instance master, since they're data-critical but not necessarily time-critical
hits should be determinable locally with collision bring pretty well syncretized by position, though having a slower back-up sync would ensure consistency

frank fjord
#

I would like players to have local authority about if/when/what they hit

#

Too much frustration could come from a player aiming at one target, thinking they hit it, and then the instance master going "Ah actually on my screen you were slightly off because your pickup didn't sync at the same rate as the event messaging system, so you hit nothing/someone else"

#

I would do visual effects locally, though

gilded depot
#

alright, object pool'd weapons can be owned by the wielder and synced with enemies being struck
dunno if enemies being owned by the last one to hit them would be good or bad in terms of network bandwidth

frank fjord
#

Was intending to like. Have a message say "start a projectile/hitscan here, with this heading/velocity/whatever" and just let it go. The visuals just go where they go, and another message arrives later to say "Okay here's actually who this player thinks they hit"

frank fjord
frozen igloo
#

oh this is actually quite similar to something I've made. Except it was flying enemies and the players controlled turrets.

The master simulated and synced the enemies invisibly, then displayed their position even to themself back in time by the same amount as the other players are seeing it. As a result, everybody saw the enemies in the same place at the same time, even the master.

Then the guns have a looping circular buffer of events with relative timestamps stating how far in the past each buffer location was shot. When the local player shoots, the bullet just travels normally. But when a remote player receives that shot event, it takes the current time and compares it to the time the bullet was actually shot, and speeds the bullet up. Every frame, it simulates an extra fraction of a second of "pre-simulation" time, which speeds the bullet up in order to catch up to the "real" position faster. As a result, once the bullet has consumed all of it's pre-simulation time, everybody sees the bullet at the same location at the same time.

When both the enemies are synced up in time, and the bullets are synced up in time, everybody sees the bullets hit the enemies at the exact same time at the exact same location. This was actually close enough that under good network conditions, I didn't even need to sync health. However in order to make it more robust under bad conditions and also for late joiners, it does sync the health of the enemies.

frank fjord
frozen igloo
#

also, the players are on a moving ship so there's additional latency compensation and timestamps added for where the ship was when the player made the shot

frank fjord
#

I wonder how you decide how far back in time to simulate the enemies? Considering each different player has a different simulation time delta, and that simulation time delta is fluctuating constantly

#

OH fuck, moving ship. ā¤ļø

#

This is reminding me of my airship game idea from earlier this year. That wound up being too much to bite off on my first game world attempt. Maybe I'll come back to that some day.

frozen igloo
#

at least it is for the owner of the enemies

#

for the remote players, it's networking.simulationtime

frank fjord
#

Oh, so you just pick an amount of time that is hopefully always enough for any amount of simulation time lag for the master

#

and then on remote clients, use simulation time to lockstep the enemy movements?

frozen igloo
#

and I use simulationtime of the player instead of the objects so that it is more stable and consistent, as well as synced between all objects that player owns

frank fjord
#

Hm. I can't immediately intuit the easing/rubber-banding logic needed to keep that lockstep, since the simulation time fluctuates

#

but I can imagine it abstractly

frozen igloo
#

the bullet catch-up part?

frank fjord
#

Well, the enemy movements

frozen igloo
#

oh, that's just another circular buffer of positions, and linearly interpolated between them based on simulation time

frank fjord
#

hmmmm

#

Okay. Still seeing it abstractly. I understand, but I just can't grok it in my head without sitting down and looking at it all work šŸ˜›

frozen igloo
#

could make it look nicer with a non-linear interpolation like objectsync does but meh

#

to be fair I made this 4 months ago and would have a hard time following everything too now heh

#

it was a manic couple of weeks

frank fjord
#

It sounds like, one way or another, I'll have to do SOMETHING vaguely like that. I wonder how much of a difference there is between having the enemies be master-owned, vs everyone owning their own local versions and 'talking' back and forth to make corrections or compensate for "Hey player 3 just hit this group of enemies with a stun so roll them back this amount of time"

frozen igloo
#

the implementation is complex, the theory is simple. I still remember the theory at least

frank fjord
#

Also, this isn't mission-critical RIGHT now, but I am also trying to keep it in the back of my head that I want there to be some contingency logic to prevent the ENTIRE game from bricking if a player, or god forbid the instance master, disconnects

#

It's such a pain to be playing an hour or two-hour game and then lose everything because VRC or SteamVR decided to go "Ah, nvm!"

frozen igloo
#

yeah I mean that's why you just don't store too much entirely locally on one client. Keep everything in sync and it can be seamless

frank fjord
#

Ownership and synchronization has to be able to be transferred safely

#

yeah

#

that's one of my big concerns about having most of the game logic be "Okay instance master controls this, instance master controls that"

#

Having everyone have the state and talk back and forth feels... safer. But harder šŸ˜›

frozen igloo
#

also something that will be difficult is handling any kind of scenario where the enemy's movement gets changed by the shot. I'm concerned about this because at the moment, the enemies move in a lockstep delayed manner. If the master sees a bullet hit and as a result changes some state in the AI to make it do something different, that will have a built-in delay which doesn't feel great. I'm already slightly cheating in this way when it comes to the final destruction. The enemy gets disabled on the last shot even before you have received the synced health confirmation from the master

#

and I think making the enemies dynamic and reacting to hits in this way is very good game design ā„¢ so I'm gonna have to figure it out somehow

frank fjord
#

In my game, enemies will not 'change behavior' when being hit, but the RESULTS of their otherwise deterministic actions can.

For example, stunning an enemy will cause it to pause on its path, and it will also have to roll-back any attacks the enemy has made in the 'lag' time between players.

Also if I slow an enemy that can buff other nearby enemies, the available "nearby targets" for its buff will change since it slowed down and other enemies nearby kept going at full speed.

frozen igloo
#

mhm

frank fjord
#

Also, no pressure/obligation, but if this would be interesting to like, hop on a call, dig into some code, make some test cases for at some point, I'd vibe with that. Regardless, I appreciate your time chewing through this with me.

frozen igloo
#

I should really get back to work šŸ˜…

frank fjord
#

Yeah, of course šŸ˜›

frozen igloo
#

But I'd love to chat some time after work

#

I'm on pacific time 9-5 hours

frank fjord
#

I still have a lot to think about, but your thoughts on manually time-delaying enemies for everyone, and the mention of buffer arrays or stacks and "acknowledgement" messages for resizing, have given me some direction to explore at least.

#

Currently unemployed myself, unfortunate layoffs back in June. x.x But I'm central time.

cold laurel
frank fjord
cold laurel
#

I'm very sure you wouldn't want that lmao

frank fjord
#

I explicitly want enemys to be locally authoritative so that that DOESN'T happen, and players get successful hits when it looks like they got successful hits locally.

cold laurel
#

Ye, that's how zombie survival does it.

wispy seal
#

I can't find it said explicitly in the docs but does VRCObjectSync handle late joiners on it's own?

#

pretty sure it does but wanted to be safe

cold laurel
#

Yes

wispy seal
#

sweet ty

tropic pollen
#

So i made a syncd toggle script that works and I then added a portion where after the part confirmed working finishes set the bool value of a animator to true. However, when I test it. The value change and works for the one who clicked but no one else. (When the script was already setup to work globally and still works) its like the animator is denying the change from the udon in play for others.

#

Here is the setbool portion i added

#

Here is me setting the value and syncing it

#

I have even done it this way manually with no sync since a syncd variable leads to this anyway and still nothing

#

this is to show that a sync variable is already leading all players to the right event. But the animator still rejects changes

tropic pollen
#

So for both players to be here means the sync toggle prior to the set bool worked. This also shows how the left pressed the button sees things moving. On the other hand the right does not and animator isnt firing.

tropic pollen
#

So for anyone else that has similar problem. I was unable to find a suitable fix for this. You essentially have to work around unity being weird and parent your animator on a toggle that is not a child to to a disable/enable object.

narrow saffron
#

can anyone explain why vrc station made avatar broken everytime sit on it?

devout mountain
#

Im kind of new to networking. How would i properly sync the colliderenabled bool? In my current code the OnPlayerJoined doesnt sync it properly. Late joiners wont get the updated variable

cold laurel
#
  1. Use Manual sync instead of Continous.
  2. There is absolutely no guarantee that the synced variables are up to date when OnPlayerJoined is called. Please override OnDeserialization instead.
  3. Never use Network Events to sync state.
#

When setting a synced variable:

  1. Take ownership Networking.SetOwner(Networking.LocalPlayer, gameObject);
  2. Set the variable(s) colliderEnabled = !colliderEnabled;
  3. Call RequestSerialization(); to mark that VRC needs to sync the variables.
cold laurel
devout mountain
cold laurel
# devout mountain I have a collider in my club world so that players can not enter the DJ booth wh...
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class LockBooth : UdonSharpBehaviour
{
    public DJBoothMaster djScript;
    public Collider boothDoor;
    [UdonSynced] private bool colliderEnabled = true;

    public override void Interact()
    {
        // Please just update your djScript to either take no params or a VRCPlayerApi
        if (!djScript.isDJ()) return;

        Networking.SetOwner(Networking.LocalPlayer, gameObject);
        colliderEnabled = !colliderEnabled;
        RequestSerialization();
        UpdateCollider();
    }

    public override void OnDeserialization() => UpdateCollider();
    private void UpdateCollider() => boothDoor.enabled = colliderEnabled;
}
#

There are probably syntax errors since I wrote this directly in discord

sweet wolf
sweet wolf
#

You have examples in your project. in the Udon directory.

#

Look at everything and do what you need.

sweet wolf
#

The master is the player who has been in the instance the longest, and is no different from others.
There is no sending queue. instance master store doesn't exist either.
Whoever is the owner of the object is the current server for the rest.

dawn juniper
#

Im working on a UdonGraph that makes it so when a couple of people are in a specific area when this Trigger is enabled or turned on where all the players are, It will teleport all the players to a specific area but only one player by random will be teleported to another area but all the other players go to the same spot except one. i have the teleporting trigger down, i just need help with the teleporting one by random to another location while the others go to the same spot. Could someone show me an example udon by chance please?

wispy seal
#

does anyone know if late joiners have OnDeserialization() called when they join? I'm needing to make my own object pool system and wondering if just having this in OnDeserialization() is enough for late joiners.

for (int i = 0; i < gameObjects.Length; i++)
{
    gameObjects[i].SetActive(gameObjectStates[i]);
}
frozen igloo
solar crescent
#

While a player in my world holds an item, the gravity should be superlow for them. But on drop it should be reset. But when the player drops the item, the gravity is low forever. How can I fix that? x_x

vapid verge
#

Hi there, im having troubles while syncing a string array. I have this code that works fine with int[] but when i do it with string[] it doesnt work, i would appreciate any help.

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

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class SyncTest : UdonSharpBehaviour
{
    [UdonSynced, FieldChangeCallback(nameof(TestArr))]
    internal int[] _testArr = new int[10];

    public int[] TestArr
    {
        set => _testArr = value;
        get => _testArr;
    }

    public override void Interact()
    {
        if (!Networking.IsOwner(Networking.LocalPlayer, gameObject))
        {
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
        }
        int[] test = TestArr;
        test[0] = 1;
        TestArr = test;
        RequestSerialization();
        OnDeserialization();
    }

    public override void OnDeserialization()
    {
        Debug.Log($"Message Received: value 0: {TestArr[0]}");
    }
}```
frozen igloo
vapid verge
#

it does sync and fire it for local player tho

#

i did this

frozen igloo
#

FieldChangeCallback only happens on remote users if the size of the array changes. Reaasigning it back to itself will not count as a change

#

Use Ondeserialization to respond to when you receive data instead of fieldchangecallback

#

Properties are great for controlling variable access as intended, but I would not recommend using them for sync, especially with arrays

vapid verge
#

i see, thanx you!

golden wyvern
#

what exactly GetPlayerId is getting? Is it some constant vrchat id or just instance number that changes every world?

frozen igloo
golden wyvern
#

thank you

#

ā¤ļø

iron burrow
#

Got a question~
So in UdonGraph you usually call RequestSerialization(); and the owner that requested will ALSO call the Variable Change Method. I usually put all the necessary logic that is affected by the variable in the Variable Change.

I recently got into U# and the owner is not automatically calling OnDeserialization(); when requesting Serialization.

Is it a bad idea to call it manually then?

Soo it makes sense to me, so I don't have to have multiple method calls. Example, if I set a Bool of an animator to true, that'd make more sense to do it once instead of repeating that line twice. I rather have one spot where I do all the things when a variable changes.

wispy seal
#

the owner also doesn't get OnDeserization(), that is the event that gets called when a remote player receives new data over the network

#

if you want to know if serialization has finished on the owner's side you want to override OnPostSerialization(SerializationResult result)

rare vine
#

Im trying to test my networking and syncing on my world but I cant do offline testing with multiple clients

#

I get this error and only one client opens

#

I feel like this would be a common problem but I couldnt find anything on it

sweet wolf
iron burrow
wispy seal
# iron burrow so if you where to change an animator parameter for both local and remote, you w...

kinda? you would do something like this

string myParam = "foo";
[UdonSynced] float myValue = 0f;

Animator animator;

void MyFunction()
{
    Networking.SetOwner(Networking.LocalPlayer, gameObject);
    
    myValue = 1f;
    RequestSerialization();
    #if UNITY_EDITOR
        SetParameters();
    #endif
}

void SetParameters()
{
    animator.SetFloat(myParam, myValue); 
}

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

public override void OnPostSerialization(SerializationResult result)
{
    if (result.success)
    {
        SetParameters();
    }
}
#

at least that's the safest way to do it, in reality you can also just do this and it should be fine too

string myParam = "foo";
[UdonSynced] float myValue = 0f;

Animator animator;

void MyFunction()
{
    Networking.SetOwner(Networking.LocalPlayer, gameObject);
    
    myValue = 1f;
    RequestSerialization();
    SetParameters();
}

void SetParameters()
{
    animator.SetFloat(myParam, myValue); 
}

public override void OnDeserialization()
{
    SetParameters(); 
}
#

@iron burrow sorry I had to make some edits, does that code make sense?

iron burrow
wispy seal
iron burrow
wispy seal
#

I don't think it will break anything on it's own but it's just bad practice

#

and you need to call a function anyway, might as well make it SetParameters(), it's just much cleaner

iron burrow
#

but what if i need to call like 10 functions after I make one variable change- am not gonna type 20 lines for that xd

wispy seal
#

then it sounds like you need to refactor you code lol

iron burrow
#

I could create a new function called smth on variable change and have the 10 in there~ that would work xd

wispy seal
#

ya I was about to say that, or you could make one big function that does everything you need

wispy seal
iron burrow
#

yee~ I just wish there was more documentation on network related stuff and good practices vrcTupDead thank u for ur time!

wispy seal
#

npnp! general rule of thumb is you shouldn't ever really need to call virtual methods, especially in udon. Udon should handle everything for you

iron burrow
#

Sooo why is can't I change the value of a Data List to int? I always the error that I'm attempting to access Double token as int.
Documentation says that I can do that with .Int tho?
playerManager[1].Int is not working for me although it's 100% an int

Any ideas? <-<

frozen igloo
iron burrow
wispy seal
#

hey if I request serialization on a game object is OnPostSerialization guaranteed to get called even if no new data was serialized (I didn't change any synced variables)?

frozen igloo
wispy seal
#

sweet ty

sour trout
#

Silly 6am question, is networking limited to 11 kilobits or kilobytes per second?

frozen igloo
sour trout
#

for reference i was looking into pedestrian and ai traffic systems. thinking about the networking side of things

wispy seal
humble girder
wispy seal
#

Hm I didn't know that, the more you know

iron burrow
#

Does OnPlayerLeft always trigger before OnOwnershipTransfer, in case the ownership gets transfered?

sweet wolf
#

OnOwnershipTransfer always triggers after OnPlayerLeft.

granite sonnet
#

Anyone have any idea what Networking.IsObjectReady(gameObject) is for? The docs just state "Returns if the object is ready," but I'm unsure what exactly that means. It returns true in Start (for both Owners and non-Owners) and OnDeserialization. Is it just some old method that shouldn't be used anymore or am I just using it wrong?

granite sonnet
# peak elm might help?

Hmm, I though instantiated objects couldn't be synced though. I tried instantiating a networked object (UdonBehaviour with Manual syncing) and IsObjectReady still returned true for that object despite it not being able to be synced. Not sure what it does

cold laurel
woven trail
# granite sonnet Anyone have any idea what `Networking.IsObjectReady(gameObject)` is for? The doc...

Most likely this is to test objects if they are ready to receive and send networking data like it's "ready for the network". This might return false in OnPlayerJoin for the local player and during some other events that can happen before Start. This is probably an old function that's not necessary for regular use though I'm sure someone will find a use case. With Instantiated objects they can send out and receive data however you'd need to match the network ids between clients which isn't possible afaik. Might relate with Networking.Instantiate(gameObject) but idk, go test it!

timber ferry
#

would this be synced for late joiners?

cold laurel
timber ferry
#

how do i sync the animator's bool for late joiners in that case?

timber ferry
#

and to connect the sound parts of the graph, would i add a block after the ā€œSet boolā€?

timber ferry
#

how would i apply that same sorta late-joiner sync for this RNG variable?

#

networking is where i'm least knowledgeable in udon

granite sonnet
# timber ferry how would i apply that same sorta late-joiner sync for this RNG variable?

What if you changed the SendCustomNetworkEvent to just SendCustomEvent so it's just the owner (remote players don't set RNG). Then on RNG Change (or in both the 'tp' event (for the owner) & OnDeserailization (for non-owners), run some event to react & update whatever depends on the value of RNG. That way the Owner decides what the RNG value is (if everyone ran Random, it would be different for each player), and also supports late join as whatever depends on that value is updated as soon as it's received. Also, I think the 'RNG -> Set RNG' is redundant, as synced variables can only be changed by the Owner. (unless that's doing something else, I'm not too familiar with UdonGraph specifically). RNG would also need to be a 'synced' variable if it isn't already. Hope this helps, if you need anything clarified let me know ^^

#

Something like this I think would work (assuming I'm understanding correctly) (note that RNG's 'oldValue' may be inaccurate if you're a late-joiner):

timber ferry
#

alright, that seems like it’d work

sage trail
#

Hey everyone, I've been working on an Amplify area script using OnTriggerEnter, but I'm facing some challenges, especially when it comes to syncing with late joiners. Has anyone successfully implemented this before? I could use some advice or maybe even a script example that has worked well for you. Your insights would be greatly appreciated!

sweet wolf
sage trail
sweet wolf
sage trail
#

If its. One player not list of players I have to move throw

frank fjord
#

I'm trying to create a basic system in which remote-players click a button to make a request to join a party slot. The requests are vetted by a manager object that the master-player owns, and if verified, the manager object assigns ownership of a party-slot object to the remote-player.

It's proving difficult to come up with a solution to this that doesn't suck?

Attempted solutions:

  1. Remote players blindly attempt to seize ownership of the party-slot object. This is unideal because the remote player sees themselves briefly as the owner before the master returns "false" for the ownership request. It also creates issues when the master player leaves and the world state needs to be juggled/repaired.

  2. Remote players call a networked event on the manager object to make the request. This doesn't work because networked events carry no data or signature that the specific remote player called it, so the manager object doesn't know what player wanted the party slot.

  3. Remote players press a button and gain ownership over the button. Then, all clients - but most importantly, the master-player - sees OnOwnershipTransferred() fire, and call a function on the manager object to request a party slot. Non-master-players return out of the function instead of fulfilling the request, and the master-player runs the request function as normal. This doesn't work because OnOwnershipTransferred() fires when the button returns to the master player after the remote player leaves the game, resulting in the master player eroneously 'taking over' the last slot the leaving player was in.

  4. Same as above, but the button uses OnDeserialization() to call the function on the manager object, instead of OnOwnershipTransferred(). This still doesn't work, because OnDeserialization() is called when players join, resulting in new joins erroneously asking for a slot (all slots) immediately upon joining the world.

#

...
5) Be really obnoxious. When a player clicks the button, they take ownership, set a synced bool "ButtonPressed," and then request serialization. On all clients' local OnDeserialization() event (but again, only really important that the master player sees this happen), if ButtonPressed is true, make the request call to the manager object. Then, have the master re-seize control of the button immediately after, to reset ButtonPressed to false. This seems wildly inefficient? Like, I don't think it TECHNICALLY breaks anything. There's a possible edge-case where someone joins RIGHT when ButtonPressed is true, before the master resets it. But since the late-joiner isn't the master, it doesn't result in any unwanted behavior anyways. I just feel like there has to be a less obnoxious, more streamlined way to do this...

stone badger
# frank fjord I'm trying to create a basic system in which remote-players click a button to ma...

I haven't quite figured out what exactly is involved in requesting a party slot but I don't think it is much different than assigning a pooled object (which I'm doing). I'll suggest that a player not take ownership of anything related to administering the slots. My object that allots objects isn't even network aware. The game objects it spawns aren't either those they each contain a child object that performs manual syncing. So maybe you can "hand out" a "party slot" when requested by a player and they can interact with it.

frank fjord
# stone badger I haven't quite figured out what exactly is involved in requesting a party slot ...

It basically is pooled object assignment, except it's manual (players can choose how or when to join or leave, and also there are only a limited amount, instead of 1 for each possible player in the world).

I definitely don't want players to take ownership of the management object that's doing slot assignment. But it is 'technically' network aware, because only the master gets to run its important functions, and it calls ownership assignment on the 'pool' objects when it assigns or un-assigns them. I also do some syncing of the list of slotted players, so that other players have a consensus on 'who' is in 'what' slot in one central location.

#

The addition of the 'unrelated button whose only purpose is to send a request function to the manager object' was so that no ownership juggling had to occur, of the manager object itself.

... but now ownership juggling occurs on the request buttons instead =u=;

stone badger
#

The buttons don't care about ownership except to fire the click event. The system I mentioned apportions "flight sticks" which could just as easily be a ticket to a party. Once assigned all the actions made on the flight stick are networked. So appearing/disappearing, movement, changing color when clicked, etc. Perhaps something grabbable would work for you. So long as the player is holding onto it they are in control of it. In theory they can select options, on it, confirm the invite, etc.

frank fjord
#

Unsure I want to require a player to grab something in order to click a button on it. Just thinking about basic interface design, most worlds with 'world options' tablets don't require you to hold them to operate them, and most players don't want to hold them to operate them either.

stone badger
#

I (think) you could send a message to the instance master (if you mean master) or owner if you mean owner by simply syncing the value and letting the method check what the status of the LocalPlayer is. I do that a lot both for who can interact with something and who should react to that interaction.

stone badger
frank fjord
#

That's basically what I'm doing right now. The person that clicks the button assumes ownership (of just the button's script, which is NOT the manager script), changes a bool, and then syncs. Then all clients run deserialization, and if the bool is true (it was clicked), attempt to run the request function on the manager script with the button owner's VRCPlayerAPI.

The manager script then discards all function calls not made by the instance master, and runs the logic to determine slot join/leave status if they are the master. And also then resets the button sync variable to false so it can be clicked again.

#

I honestly want to get rid of the synced bool entirely because I'm worried about the possibility of it accidentally getting stuck in the TRUE state if interactions and network traffic resolves in exactly the wrong time

#

But udon behaviors won't even run OnDeserialization() if there's no synced variables to sync

#

Maybe I don't care about the state of that boolean at all and just use it as a way to assure OnDeserialization() fires...

#

It's dumb but it'd work I think šŸ¤”

stone badger
stone badger
frank fjord
#

I can rationalize in my head that it 'makes sense' yes.

#

Some of the behaviors and edge-cases I've seen with Udon make more and less sense than others... which makes it a little hard to predict for sure what's going to happen before I run into it face first šŸ˜›

#

For example: I haven't tested yet whether or not OnDeserialization() will fire if there ARE synced variables in the object, but their values haven't changed yet. Based on OnDeserialization() not firing when there just aren't synced variables at all, I'd assume not. But I don't know yet.

stone badger
# frank fjord For example: I haven't tested yet whether or not OnDeserialization() will fire i...

I was under the impression that if the values did not change they would not be sync'd which makes sense for automatic sync'ing (they are sync'd already). OnDeserialization will fire on a new joiner however as they would have only just received the values. Reading the docs I was made aware of: OnOwnershipTransferred(VRCPlayerApi player) which you may be able to use. One would know which player just became the owner.

#

I would suggest (if you haven't done so) to create a world that is just used for all sorts of testing. No need to mess with a world that you are relying on.

frank fjord
#

using onownershiptransferred had problems when players left and ownership returned to the master (though the master didn't click the buttons)

#

and yes, i've got a test world i'm doing all this scrappy testing in.

#

In either case, I did get the slot thing working. Just finished testing all the weird edge-cases with users leaving at different times. Hopefully it's robust, I guess we'll find out x'D

rocky summit
#

Let's say I have an object that's owned by player 2/3/4 etc., and I need it to tell an object owned by player 1 to send a custom event to all, what's the best way to go about that?

rocky summit
#

That's not quite what I mean; An Owned object, needs to tell an object that's not owned by the same player to send an event to all, I don't think I can transfer ownership of the second object because it would be passed around too frequently for what I'm doing

sweet wolf
#

Perhaps so.
But the objects themselves do not send or receive anything. You can only check the owner, and the player can do something.

frank fjord
#

Alright, I have an apparent gap in my understanding of udon networking, and don't know what I'm missing.

I ran a test with two players. In this test, player 1 clicks a button, requests serialization, and OnPreSerialization, starts a clock. Player 2 receives this message and calculates the amount of time the message took to receive them using the OnDeserialization result (result.receiveTime - result.sendTime). They then start their own clock, starting at this 'offset.' Both players now have a running clock, and I PRESUMED that these clocks would be 'in sync' if you corrected for the time it takes to send messages back and forth.

To test this, I then let each player send one another messages containing their local clock time. When each of these messages are sent, the clock time is recorded OnPreSerialization (to account for the variable timing between serialization events). The receiving player then compares their local clock with the received 'timestamp' (once again corrected using result.receiveTime - result.sendTime).

When the player that started the clock (we'll say P1) sends a timestamp, the other player (P2) gets an 'error' between their local clock and the corrected timestamp of about plus or minus 1ms or less. Acceptable.

However, when the player that DIDN'T start the clock (P2) sends a timestamp, the P1 gets an error of about negative 130-150ms, indicating that P1's clock is about 150ms "behind" P2's clock.

Out of curiosity, I measured what the serialization delay (result.receiveTime - result.sendTime) was at the original clock-start event and noticed that this original offset was about 100 to 160ms, but DIDN'T regularly correlate with the negative 130-150ms of 'error' calculated when the timestamps were sent.

... What's going on here? What am I missing?

frank fjord
# frank fjord Alright, I have an apparent gap in my understanding of udon networking, and don'...

I had a hypothesis that simulation time was the missing link here. I'm not sure that's true because the docs say that simulation time is used for **players **and **VRCObjectSync **- NOT manually synchronized objects. Which is what this is. But I tried the following anyways:

  1. When a player sends their current running clock time, they SUBTRACT their 'simulation time delta' from the clock (I calculate this as Time.RealTimeSinceStartup-SimulationTime)
  2. When a player starts their clock using this received information, they add back on THEIR simulation time delta (calculated in the same way, but from their reference point), in addition to the time taken for the message to arrive (receiveTime - sendTime).

While running two local clients, I noticed that this results in the two clocks being almost perfectly in sync about 95% of the time, as long as I don't bungle a window and freeze the game momentarily.

However! My 'error' checking math - which I adjusted to take simulation time into account - still shows a frustrating asymmetry. When the clock-starter is the one sending the timestamp check, the second player sees 1ms or less of 'discrepancy,' but when the second player sends the timestamp check, the clock-starter sees 130-150ms of 'discrepancy.'

This now feels like I have a dumb math error...? But I can't identify it.
Either that or I just fundamentally misunderstand how time is or isn't "synchronized" across clients in multiplayer games. Which is also possible, I guess.

Here's the math:

#

local OnPreSerialization():
Start clock at 0
float simTimeDelta = realTimeSinceStartup - simulationTime(gameObject)
syncedTimestamp = localClock (which is 0) - simTimeDelta

remote OnDeserialization():
float simTimeDelta = realTimeSinceStartup - simulationTime(gameObject)
float deserializationTime = result.receiveTime - result.sendTime
Start clock at syncedTimestamp + deserializationTime + simTimeDelta```
#

local OnPreSerialization():
float simTimeDelta = realTimeSinceStartup - simulationTime(gameObject)
syncedTimestamp = localClock - simTimeDelta

remote OnDeserialization():
float simTimeDelta = realTimeSinceStartup - simulationTime(gameObject)
float deserializationTime = result.receiveTime - result.sendTime
float error = (localClock - simTimeDelta) - (syncedTimeStamp + deserializationTime)

// When clock starter sends a timestamp check, player 2 measures an error of about 0.001

// When player 2 sends a timestamp check, the clock starter measures an error of about -0.130 to -0.150```
#

God, I really wish there was thorough documentation and examples for synchronizing clients in time.

frank fjord
#

Simulation time was a red herring and actually introduced new problems. Ultimately removed the simulation time adjustments from the sync and check timestamp functions.

Turns out, something about send and receive times gets fucky when you test locally with multiple clients. This clock-sync-and-timestamp-check system works as expected with very small ~1ms error when testing with other actual players over a real internet connection.

I... do not know how to feel about that. It means there's a lot of shit that I cannot test locally at all because time-sync will just entirely break.

restive cliff
#

Same gripe here. Never resolved
I went back to using time = cachedAtStartGetServerTimeInMilliseconds + (Time.realtimeSinceStartup - cachedAtStartRealtimeSinceStartup) for the send and receive times, however, Networking.GetServerTimeInMilliseconds() can be negative for some clients.

#

For my case, why not just use simulationTime? I wanted a "raw" enough variable for latency between two clients so that I could implement my own non-linear networking interpolation.
R = simulationTIme, A = R * 0.5 (lol), C = the method I mentioned above which seemed good enough until the server time goes negative

stone badger
#

Not arguing here but what is the issue people are trying to solve? Multiplayer games across disparate networks, hardware, operating systems, et. al. is inherently problematic. https://gafferongames.com/post/deterministic_lockstep/

pearl folio
#

but i will avoid going offtopic :p

frank fjord
# restive cliff Same gripe here. Never resolved I went back to using `time = cachedAtStartGetSe...

Here are some of my ... plausible understandings, from the tests I ran:

  1. Server time can be negative, and it can roll over from positive to negative in the middle of a session, and that's weird. It may be a good source of truth to use, but I found some unusual inconsistencies with it last time I did this kind of testing and so right now I avoid using it until I can get around to running a better test.

  2. Time.RealTimeSinceStartup is how long since you started the VRChat application.

  3. Deserialization result appears to give you an estimate for when the serialization was sent, but already adjusted to be from the frame of reference of YOUR LOCAL RealTimeSinceStartup - and the RealTimeSinceStartup when you received the serialization.

  4. When running multiple local clients for testing, something about the OnDeserialization result is foobar. I don't know what though. Nothing LOOKS wrong. Just looking at the raw numbers, everything seems right, but as I discussed in the gigantic wall of text above, I was getting weird results where the two local clients were getting asymmetric 'errors' when comparing half-ping-corrected timestamps to their local synced clock.

  5. Simulation time, like deserialization result sendTime, is a timestamp that exists in the frame of reference of YOUR LOCAL RealTimeSinceStartup. However, it's some amount of milliseconds back in time (for example, if your RealTimeSinceStartup is 1783.953 seconds, you might see another player's SimulationTime is 1783.643 seconds), and that 'delta' changes frequently based on what the game thinks is needed to smoothly interpolate a networked object. This is used for players and objectsync, and may be useful for custom, frequently-updating interpolation, but in my use case, it introduced timing/error artifacts that I didn't know how to account for. I get the impression that for most manually synced objects, simulation time is not a good thing to use.

#

...
An example of an issue I was having with simulation time:

When I sent a timestamp, I would remove what the sending player thought their simulation time (for the OBJECT sending the message) was from the timestamp.

When a remote player received the timestamp, I would add back on what THEY thought THEIR local simulation time (for the object) was, to the timestamp.

When serialization events were spammed, the receiving player's simulation time for the object would slide further back in time as part of whatever its 'mechanism' for compensation was. But because either A) the serialization events weren't ACTUALLY coming any later, or B) because receiveTime - sendTime already accounted for the serialization events coming later, this extra delay on the simulation time caused the timestamp comparison to become more and more incorrect the more often serialization events occurred.

...

Another issue I had was that, very reliably, the FIRST time I sent a 'start the synced clock' message (in a given world load), the sender or receiver's simulation time would be non-nominal, resulting in about 60-80ms of extra error in timestamp comparisons. I know this error was in the original synced clock start event, because all timestamp comparisons after that carried this error.

However, when I stopped and restarted the clock, this 60-80ms of extra error would vanish, and go back to about 1ms or less for the rest of the play session.

Removing the simulation time math from the timestamp comparisons all together solved this one-time anomaly.

frank fjord
# stone badger Not arguing here but what is the issue people are trying to solve? Multiplayer g...

At a high level, I'm just trying to learn how to take time-sensitive networked messages and correctly 'line them up' in time on the receiving client, both in general, and specifically using VRChat's framework. Even if I had a general understanding of network design, there are/were certain aspects of VRChat's implementation - like the player-to-player-ish model, or the specifics of what Deserialization result does or doesn't give you, or how the heck to properly use simulation time - that I don't fully understand.

I'm working on a co-op monument defense game where 4 players shoot a bunch of moderately slow-moving enemies with a variety of weapons and abilities. Some hitscan, others projectile, etc etc etc.

When a player shoots an enemy or uses an ability, they need to send some kind of networked message to other players that they did so, along with a bunch of related information about what or where they shot, what effects they thought were active, etc. Unrelated to this current discussions, I'm experimenting doing that using a message system that syncs a size-dynamic array of bytes that encodes all of this information in tokens.

When a player receives that message, they need to know when in time that event actually happened, for multiple reasons:

  1. If the message was "The wave started!" they need to 'catch up' with the client that started the wave, so that both players see enemies in the same place
  2. If the message was "I shot a projectile!" they need to know how much to catch-up the projectile so that it hits at about the same time and place that the sending client thought it hit.
  3. If the message was "I killed this enemy!" they need to know if the enemy was killed before or after the enemy took certain actions, like buffing nearby enemies or attacking the central monument, so that they can 'roll back' those actions and maintain visual parity/synchronicity in the game state
  4. (and more...)
#

...
And yeah, of course multiplayer networking is inherently problematic. But it's been problematic for decades, and yet we still have multiplayer networked games, so people have come up with lots and lots of different solutions for things in lots and lots of different situations and environments.

I, unfortunately, don't have decades of experience as a multiplayer network engineer under my belt, and so I'm trying to learn some of that shit for the first time.

restive cliff
#

Folks this is before implementing any kind of network representation such as lockstep, extrapolation, etc.

I just wished there was a less padded simulationTime so that we can implement our own interpolation. It frustrates me that we have to implement our delta of send and receive time just to have it be lower than the observed ~1000ms in the screenshot above.

#

Latency difference between object sync (textured) and manual sync (red)

stone badger
#

As for syncing time across players, it might be a good idea to produce a shared library. That way there is a baseline and something that other devs can review and perhaps improve upon. The library would get better over time as people used it. If we use C# or Node as examples there are libraries for everything.

obtuse echo
cold laurel
obtuse echo
restive cliff
#

I was thinking to have it branch to simulationTime() if it ever goes negative

obtuse echo
stone badger
#

It sounds like one would want to use Epoch Time representations so there is no rollover to deal with

cold laurel
stone badger
#

long 64-bit signed integer -9,223,372,036,854,775,808 to 9,223,372,036,854,775,807

cold laurel
#

same diff

obtuse echo
cold laurel
obtuse echo
#

So we know that 1 millisecond passed in this case, which we can use for all sorts of things, especially if everyone has the start time synced. Alterntively, you could always sync the current server time of the action and always be in the clear.

cold laurel
#

If you save the timestamp before the rollover, and then try to get the delta after the rollover, you get the wrong answer.

#

You need to detect and handle the rollover

#

there is no way around this

obtuse echo
#

We get the right value for the delta, which is 1

cold laurel
#

Which makes perfect sense

obtuse echo
#

Oh god

cold laurel
#

since you have a really small number, and are removing from it.

obtuse echo
#

I think I get it now. The delta also overflows, but ends up right in the end lol

cold laurel
obtuse echo
#

I was just purely testing the values in code but that fact completely escaped me.

frank fjord
#

I wonder if Networking.GetServerDeltaTime() accounts for server clock integer rollover...

obtuse echo
frank fjord
#

Oh sorry

#

Networking.CalculateServerDeltaTime()

frank fjord
obtuse echo
timber ferry
#

i'm not really sure why this isn't synced between players

#

(bought is a synced bool)

obtuse echo
#

Also, I think it would be better to check if they have enough money before you even send the "bought" change.

timber ferry
obtuse echo
#

I'm also realizing that you are using the player who enters the trigger as the new owner. On Trigger enter fires for every player who enters it. So player 1 will execute the logic for player 2, if they enter the trigger. Usually, you don't want to set ownership for someone else. You want to check for only the local player to execute the code in this case.

timber ferry
#

actually, in my specific case, i'm making a roblox-like tycoon game. so i want anyone to be able to step on the trigger to send this event

timber ferry
#

oh, actually i understand now

obtuse echo
#

You don't want player 1 to trigger something for player 2, so you have to make sure it's only player 1 (the local one here) to execute the logic.

timber ferry
#

yeah so, only the localplayer sets off the change, and everyone else would recieve it because of the synced bool

#

i previously had the whole GreaterOrLessThan thing connected to OnPlayerTriggerEnter by itself, and it was synced, but sometimes it wouldn't buy for everyone. so i'm just improving it now to make it reliable

obtuse echo
#

And definitely only set owner to the local player right before you do set change, it will make it easier for yourself.

timber ferry
#

yeah, i've got this now

obtuse echo
timber ferry
#

yeah, it's like a co-op tycoon rather than multiple separate ones

obtuse echo
hollow wagon
#

how can I get the udon behavior of a gameobject? I just want to iterate through some gameobjects and send a customEvent. For some reason I cant use an array of udon behaviors or it will cause a unity error.

timber ferry
#

you have to get the component from an array of gameobjects, since the UdonBehaviour[] is bugged

hollow wagon
random parrot
#

just to check, non-owners can send networked custom events on an object that's owned by someone else, right?

tulip sphinx
#

@random parrot network events can be sent by anyone, to everyone or only to the owner of the object

rare vine
#

Is it possible to toggle the object sync component on/off by script? I dont see a checkbox on unity and using newBall.GetComponent<VRCObjectSync>().enabled = false; doesnt seem to work

#

I have the 'newball' object parented to a dropper object and the ball seems to lag behind when the dropper moves to other players because of the object sync. I was wondering if I could turn off the object sync while its parented to the dropper still

humble girder
rare vine
rare vine
#

if someone is a network owner for an object, are they also owners of that objects children?

#

if I use the dropper example from before, I have a ball with object sync as a child object to a dropper, who ever owns the dropper will also be the owner of the object synced ball? if I change the owner of the dropper with scripts will it also update the ball owner to that same person?

humble girder
rare vine
#

okay thank you

buoyant ginkgo
#

Hello! I need some assistance with a networked timer.

As of right now, I have successfully implemented a 1 hour countdown timer into my world. It's designed in UdonSharp, the timer itself is displayed as a TextMeshPro component, and the countdown script is called using a networked event in an udon graph. It works like a charm for any players already in the instance, however I need this to work for late joiners too. I have already experimented with OnDeserialization(), and I've managed to get the timer to start from the beginning for anyone who joins late. but obviously the late joiner's timer will be desynced from the people who are already in the instance. I need some way to pull the time from the instance master and carry it over to the late joiner.
How would I do this?

tulip sphinx
buoyant ginkgo
#

gotcha, but I forgot to mention. The timer is designed to start using an OnInteract() method. so it won't start right away when the instance is first created.

tulip sphinx
#

does it matter? check ondeserialization+og timer not 0

#

then it would start for both joiners and peeps already there

buoyant ginkgo
#

oh alright then, I'll give that a shot and see how it goes.

#

How would I achieve this in the udon graph though? would you mind providing a template?

tulip sphinx
#

vrpill not me, im on phone

buoyant ginkgo
#

fair enough lol
dw, I'll figure it out. Thank you for the advice! šŸ‘

buoyant ginkgo
#

got it working ✨

timber ferry
#

is this synced between players already, since the object has an ObjectSync script?

#

if not, (because i don't think the explosion would sync), how could i make it so it is?

sweet wolf
frozen igloo
# timber ferry is this synced between players already, since the object has an ObjectSync scrip...

OnDrop does not happen on remote clients, but onplayertriggerenter does, so it would be partially synced but not really work. I would recommend:

  • Have a synced variable which indicates whether or not it is active
  • Use ondrop to set it to active
  • Use OnDeserialization to set the animator to match the synced variable state of whether or not it's active
  • OnPlayerTriggerEnter, check if islocal and if it's synced variable is active. If it is, then do the following:
  • Respawn the player (Or whatever damage thing you want to do)
  • Take ownership
  • Delayed event to clean up the object (respawn, set to inactive, return to pool, whatever)
  • Send a network event to play explosion effects (So everyone will run the explosion effects, but only the owner will clean it up)
timber ferry
#

alright, i can try doing that

frozen igloo
#

hard to tell, can't read everything at that size. But it looks about right. I'm not sure where the cleanup step is, but also I don't even know what you want to do for that in the first place, if at all

untold crag
#

anyone have advice for testing networking? if i launch two test clients do i have different display names, or id's or something? do i need a friend?

cold laurel
untold crag
#

pog

#

does the id ever change under any circumstances? like if a player leaves does that id get replaced?

cold laurel
#

if you create an instance, join it (you now have ID 1) and then rejoin 299 times you will have ID 300

untold crag
#

awesome, thanks!

timber ferry
#

i'm still having trouble getting this to sync

#

what i want is:
on drop, play the sound and after 6 seconds, turn on the collider, set pickupable off, and set the animator to the state of the active bool

then, when someone enters the collider that was turned on, it respawns that player, turns the collider back off, and plays the second sound and particle effects

and after the second part happens, i want it to wait 3 seconds and set the active state to off, turn the animator bool to false, and set pickupable back on

#

and i want that to be synced between all players

sweet wolf
# timber ferry i'm still having trouble getting this to sync

Why should it work?
For synchronization, the OnDeserialization event is needed for non-owners. Or OnVariableChanged for everyone. Remove RequestSerialization, switch synchronization to continuous. The set owner should be in front of set bool, not just anywhere. In the set bool, enable the SandChange option and most likely it will work right away.

buoyant ginkgo
#

question: what is a functional way to pull PlayableDirector (Timeline) time data from the owner of an instance, and give it to late joiners?
im not sure if I have the right idea here

sweet wolf
#

I think this is how it should work.

buoyant ginkgo
#

gotcha, ill give that a shot

sweet wolf
buoyant ginkgo
sweet wolf
buoyant ginkgo
#

gotcha!

timber ferry
#

the whole explosion event part is completely local to whoever enters the trigger

buoyant ginkgo
#

im not sure what to do, because your version didn't seem to give the timeline data to the late joiner

#

hmm

sweet wolf
#

Or better yet, two log nodes.
One for transmitting and one for receiving the variable.

buoyant ginkgo
#

like this?

#

oh wait hold on

sweet wolf
buoyant ginkgo
#

also, it doesn't seem to work either šŸ˜”

sweet wolf
#

Replacing playergined with interactive. Add a box collider to the object. and test in accelerated mode

buoyant ginkgo
#

got it, and also, what is "accelerated mode"?

#

ok, i might've got it to work, let me try testing

#

the timeline value shows in the console now

sweet wolf
#

I don't know what you're doing, but there's no reason why both options wouldn't work.

timber kayak
#

Hi, hope this is the right channel for this - I have an issue with manually syncing variables, and want to check what i'm misunderstanding.

So I have a player, spawn an object from an object pool, when they do this;

  • The local player is set to the owner.
  • They get a udon script on that object, and set 2 synced vectors, synced 2 ints and 1 synced float.
  • It then RequestSerialization,
  • Using OnDerialization on clients, I snap the objects positions, rotation, scale, and other data, using the 5 synced variables above to match the owner.

My understanding is RequestSerialization and on OnDeserialization, while maybe a bit delayed, it would make sure to send the data from the owner, to be acted out after they are received on the clients, and can be triggered immediately after the values are changed on the owner. Since I only need to update the objects position once on spawn, I wanted to avoid continuous updates with vrcObjectSync.

However when I try using manual updates, the data doesn't get synced to the clients. I have to do at least 2 delayed 'RequestSerialization' calls after the initial spawn for things to take effect on clients.

Guess my question is, does RequestSerializaion have to be delayed? Am I trying to sync too much data at once, too soon after changing ownership, or am I misunderstanding how the manual updates are meant to work? Sorry for the wall of text, I seem to have a work around for now, but want to know what i'm getting wrongĀ aboutĀ this.

humble girder
timber kayak
#

In my test, I only have one player attempting to claim the ownership of the object. They locally tryToSpawn from the object pool, get the spawned object and when accessing a udon script on said object, change the synced variables and take ownership at the same time before pushing a serialization request.

However I only seem to get those variables pushed to clients, if I add a delayed RequestSerialization a bit of a second after this all takes place.

humble girder
timber kayak
#

This is the parts of the code on the spawned object, which is called from the code that takes it out of the objectpool, that handle calls and syncing. From my debugging, ownership get's set fine, even on clients, but the synced vars only seem to update, if called at least .3f of a second, after spawning in.

    {
        //Claim ownership after being taken out of the Object pool
        Networking.SetOwner(Networking.LocalPlayer, gameObject); 

        //Udon Synced Vars
        pos = NPos;
        rot = NRot;
        power = NPower;

        typeID = NTypeID;
        ID = NID;

        //Used for delayed requestSerialization call in local update
        counter = 1;
        updateCounter = 1;
        RequestSerialization();
        //Local call for function called OnDeserialization
        SnapPos();
    }

    public override void OnDeserialization()
    {
        base.OnDeserialization();
        SnapPos();
    }

    public void SnapPos()
    {
         transform.position = pos;
         transform.eulerAngles = rot;
         transform.localScale = Vector3.one * power;

        lr.startColor = spellMaster.playerList[ID].playerColor;
        lr.endColor = spellMaster.playerList[ID].playerColor2;

        if(typeID == 0)
        {
            rend.material.color = Color.blue;
        }else if (typeID == 1)
        {
            rend.material.color = Color.red;
        }else if (typeID == 2)
        {
            rend.material.color = Color.green;
        }
    }
#

As it is, I can get updates to go through to clients, but only if I call them on the owner, a second after spawning in again. The initial request, seems to be ignored, or missed.

#

Which I can work with, but I'm just wondering what I'm missing, since from my understanding of the docs, this should work without the delayed call is all.

meager meadow
timber kayak
#

Yeah, that seems to be what I'm getting, happy I'm not the only one. For version 1 I think my plan will be to stick with the delay call.

I think in the future, if I were to rebuild this system, I would have players take a object from the pool at spawn, and then hide it, to keep in their own storage till use. Then have them top up again, that way the item can be ready well in advance of use, and hopefully no longer have any spawning based delays to var syncs.

Though, I also wonder how much of this, might be due to testing two builds on one machine, over being truly over the net, but oh well, at least I seem to have a work around for now, hope it's something that get's ironed out with vrcobjectpools in the future.

meager meadow
timber kayak
#

Sadly not, multiple items per user potentially which is why I wanted to use the pool in the first place but thinking is, if the problem is a delay before syncing works, then giving each player 1 item in advance, not perfect, but could work maybe.

And yep, the cyanplayerobjectpool has been really useful, been using it to store player info, and as a middle value holder when needed.

faint rock
#

I'm setting a user as the owner, writing a value, requesting serialisation, then doing a network event to users that uses the value, but users don't ever appear to get that updated value. Is there anything I'm likely doing wrong there? (the script is set to manual sync)

rapid oak
#

Set the variable as synced? Difficult to know unless you post your script

sweet wolf
faint rock
cold laurel
#

Use OnDeserialization to do stuff after you have received an update to the variables

sweet wolf
faint rock
cold laurel
cold laurel
faint rock
#

Ahh, interesting...

cold laurel
#

if you get the difference between them you can figure out how stale the data is

faint rock
#

Yeah, that feels a lot more sane, ta.

cold laurel
#

np

faint rock
faint rock
#

Cool, thanks.

stone badger
# cold laurel `DeserializationResult` contains `sendTime` and `receiveTime`

Speaking of which... I'd be interested in a discussion that might standardize this type of thing. Much like the one we had about sorting and the one about delayed start calls I'm looking for a pattern that can be used to "simply and reliably" adapt to cases where the sync'd property should be ignored.

cold laurel
faint rock
#

Does Deserialisation immediately run for the person that requested Serialisation, or only other users?

#

and on a related note, I assume I'm missing something here because the value doesn't update when triggered by the non-owner...

#

(there's a request serialisation further down the chain)

humble girder
faint rock
vapid pagoda
stone badger
# cold laurel Can you give an example of such a case?

I have several and there are definitely other postings here by others that relate to what I will term "actions" rather than "states". I want my NPC to "jump" so I set the synced value to indicate that. It jumps for all the players in the room. A new player joins and since that is the last "action" received the player jumps for the new player. Nobody else sees that particular jump. I would rather not concentrate on the particular example however. There is no way to set a Boolean to true, have the current players act on it and then to sync that value to false so players don't perform the action.

cold laurel
meager meadow
stone badger
#

I've reviewed the code by Miner. Quite the undertaking but I haven't bit-the-bullet yet to implement it. I'll try to abstract the age check into something that can easily be set and monitored.

#

Meanwhile scriptable object support would be marvelous šŸ™‚ https://www.youtube.com/watch?v=raQ3iHhE_Kk

Scriptable Objects are an immensely powerful yet often underutilized feature of Unity. Learn how to get the most out of this versatile data structure and build more extensible systems and data patterns. In this talk, Schell Games shares specific examples of how they have used the Scriptable Object for everything from a hierarchical state machine...

ā–¶ Play video
warped latch
#

When using an object pool, do you have to set owner to the pools game object before doing requests? Trying to understand how it works with U#

tulip sphinx
#

@warped latch yes only the owner spawns and returns the objects

#

so either the object itself calls a return network event to the owner or you transfer the ownership of the pool first

warped latch
#

I hope that makes an easy discord search for future people

tulip sphinx
#

its in the docsvrcAevSip

stone badger
# meager meadow Would an event provide what you are needing in that case (for a bool in particul...

I swapped out my udonsync stuff with my actions class and made them CustomNetworkEvents. I like this much better, the boolean problem is easily handled with ActionOn and ActionOff events. That leaves us with how best to handle parameters when they are needed. I am loathe to tie in sync'd properties and some arbitrary waiting period even if it worked in the majority of cases. Have you tried the solution from Miner?

#

Parameter values could be "pushed" to a service but that's a fair amount of overhead in both directions.

meager meadow
meager meadow
#

Also, I should add that for bool you probably just need "Action". When you receive it, you perform the action. No need to maintain a bool.

stone badger
meager meadow
stone badger
stone badger
#

It can already be "tricky" formulating patterns for sync'd state but incorporating custom network events adds a wrinkle. Eventually I'm going to have to update my standard Udon class structure to handle additional combinations. (That probably sounds odd) but what I mean by that is there are states that need to be initialized, some of those need to be sync'd with new players. Action type events can include a sync'd UI component (a check box for instance) that lets me know I have called the event for players already in the world. New players won't receive the "on" action (and we don't want them to or it would have been state-based) but they will receive the "off" action when I change it again. None of this is particularly hard to write but does involve a lot of thought to coordinate.

#

I may have to investigate Miner's library sooner rather than later. He is basically mimicking what the Photon library does under the hood with RPC's which is fundamentally how Photon (and VRC) sync'ing works. I think It is easier to transmit state directly than to set it and then to coordinate it among the players.

undone ridge
#

I got syncing issues
I basically have the following code, but foo is not getting synced across clients

[SerializeField] private TextMeshProUGUI tmp;
[UdonSynced] private float foo;
public void Increase() {
  foo += 0.5f;
  RequestSerialization();
}
public void Decrease() {
 foo -= 0.5f;
 RequestSerialization();
}
private void Update() {
  tmp.text = foo.ToString();
}

(My implementation is very different, but this simpler version produces the same issue)

Every player can locally change the value using UI buttons that call either methods, and the change shows up correctly in the TMP Text as well. But other players do not see any changes made by other players and only have their own unique, isolated value.
The script on the game object is set to manual syncing mode.

What am i doing wrong?

frozen igloo
# undone ridge > I got syncing issues I basically have the following code, but `foo` is not get...

only the owner can send synced variables, so you need to add Networking.SetOwner(Networking.LocalPlayer, gameObject); to tbe Increase and Decrease functions. Also, using update to print the text is very inefficient, use OnDeserialization instead. This is an event that happens when you receive synced data. Though it does not happen for the person who sends data, so you should print the text on Increase/Decrease as well

undone ridge
#

But during the testing, one person mustve been the owner. Why didnt their change get synced to the others?

static crest
#

Can someone help me understand on how to make a certain toggle in the game network synced? Like when someone joins the world that same world toggle is enabled for them too

tulip sphinx
#

@undone ridge interact is called only for person who clicks the button

#

so they must be an owner in order to update smth for everyone (or call a network event to the owner but its not the best idea)

#

@static crest theres already u# network toggle if you want to keep it simple

#

just add is as component on interactable object

#

and populate the array of objects to toggle

#

synced toggle? dont remember the name

static crest
tulip sphinx
#

@static crest to the object that has interact, so button.

static crest
#

So I've got cyantrigger setup for that button, do I add a new component

tulip sphinx
#

no idea what and how cyan does.

static crest
#

Where it says 'anyone' 'send to all' that sounds like whatever state the button is at, it should show for other players?

undone ridge
humble girder
undone ridge
# humble girder Are you testing with the code you provided as the sample?

Tested some more and the sample by itself works fine. But i am using Instantiate() to create new objects (which hold that UI) and it seems those are not synced and only created locally. And Network commands dont affect them, or something.
If i have one of those objects in the world from the start, it works fine and the value is synced between clients.
Is there any way to Instantiate a "synced" object?

humble girder
undone ridge
#

Thanks

earnest oriole
#

I'm really new to udon and I'm trying to sync an animation across players but I'm not really sure how to go about doing so. Currently I toggle the blade based on a boolean that plays the animation when the player uses the pickup.

// Current blade state
public bool isExtended;

public override void OnPickupUseDown()
{
    toggleBlade();
}
compact ibex
#

hi someone help me , im try U# about teleport with other player same time , how it work ?

cold laurel
compact ibex
#

yes

cold laurel
compact ibex
#

okay i will later thank you

warped linden
#

Extremly new to coding and Udon, I have this prefab, thats supposed to be used in actual games, Blaze AI, however when ran in VRChat it doesnt seem to work. I fear its a problem with the actual scripts, and now im scared im gonna have to start editing it myself

#

These "Jolly Rancher Elites" as my server calls them, are supposed to attack the red box, but in VRC, doent even move.

frozen igloo
#

at minimum, that means changing all MonoBehaviours to UdonSharpBehaviours, and adding the UdonSharpProgramAsset. But most likely, they will be using some additional features of C# which are not supported in Udon, such as native lists, inheritance, custom structs, non-behaviour custom classes, or scriptable objects

warped linden
#

Just change this?

#

and these?

frozen igloo
#

If that's using unity events and system.collections.generic, let alone whatever's happening in BlazeAISpace, then it will require someone knowledgable with udonsharp to go in and do a bunch of manual work to replace it with equivalents.

warped linden
#

I dont know how to code im kinda stressin here

frozen igloo
#

You could watch this udon-specific tutorial to build something from scratch https://www.youtube.com/watch?v=xVXXS7HX7Og

TLX

In this TLX Spring 2021 session, Centauri focuses on how to create simple local and synced AI, and different ways to sync it between multiple players.

Check out other talks from the TLX Spring 2021 event at https://www.youtube.com/playlist?list=PLTgqlzYxsEMxiUvVaqBcD5OL9MpdmkiSH

Learn more about Prefabs TLX at https://tlx.dev

Follow TLX on Tw...

ā–¶ Play video
warped linden
#

I tried that.

#

The issue there is its TOO simple

#

I need to be able to combat these AI, which is why I use Blaze, for the cover shooter functions

#

and the general open endedness and it just feels easy to use

frozen igloo
#

not like blaze would be networked anyway

warped linden
#

I also dont have to watch an hour long video just to figure out how it works

frozen igloo
#

I don't know what to tell you, what you're asking for is complex and requires a lot of know-how. You're gonna have to either learn it yourself or hire someone

warped linden
#

I assumed Udonsharp did it for me, isnt it supposed to convert C# to something VRC can use?

frozen igloo
#

UdonSharp is a subset of C#. It does not support everything

#

VRChat is currently working on Udon 2, which will have far better performance and support the entire C# standard. You're welcome to wait for that. But again, it's still very unlikely that this AI package will work out of the box, as things like network syncing are still VRC-specific

daring spire
#

Hi, can someone help me to modify my sync toggle so it will work for animations of blenshapes as well? Like I want to make an elevator that is synced.

compact ibex
cold laurel
compact ibex
#

how that check ? only who in zone ?

cold laurel
compact ibex
#

i did add use public VRCPlayerApi[] playersInTrigger = new VRCPlayerApi[20]; and OnPlayerTriggerEnter

cold laurel
#

you don't need to keep track of all the players

#

just if the local player is in the zone

compact ibex
#

you dont mind you can little how code ?

cold laurel
compact ibex
#

U#

#

because I'm a new developer

cold laurel
# compact ibex U#
using UnityEngine;
using VRC.SDKBase;
using UdonSharp;

using VRC.Udon.Common.Interfaces;

[DisallowMultipleComponent]
[AddComponentMenu("KitKat/ZoneTP")]
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class ZoneTP : UdonSharpBehaviour
{
    [SerializeField] private Transform targetPos;
    public bool _inZone;

    #region API

    public void _TeleportEveryone() => SendCustomNetworkEvent(NetworkEventTarget.All, nameof(TeleportLocal));
    public void TeleportLocal() { if (_inZone) Networking.LocalPlayer.TeleportTo(targetPos.position, targetPos.rotation); }

    #endregion // API

    #region TRIGGER OVERRIDES

    public override void OnPlayerTriggerEnter(VRCPlayerApi player)
    {
        if (!Utilities.IsValid(player)) return;
        if (!player.isLocal) return;
        _inZone = true;
    }
    public override void OnPlayerTriggerExit(VRCPlayerApi player)
    {
        if (!Utilities.IsValid(player)) return;
        if (!player.isLocal) return;
        _inZone = false;
    }

    #endregion // TRIGGER OVERRIDES
}
compact ibex
#

ah , okay i need read for learn how that work , thank you so much ā¤ļø

#

i see i see i see i got it !

stone badger
cold laurel
#

The Utilities class is part of the sdk btw

stone badger
#
public static Boolean LocalPlayerIsInstanceOwner()
{
    return LocalPlayerIsValid() && Networking.LocalPlayer.isInstanceOwner;
}
cold laurel
#

That unfortunately has a fair bit of overhead

stone badger
#

no where near the overhead as someone with a large avatar or 50 people in a world

#

part of the build process could be to in-line all the static calls and remove the class should it become an issue.

valid rock
#

Quick question with UdonSharp.
Has the issue regarding synced variables not being set immediately after Networking.SetOwner() been resolved?

frozen igloo
valid rock
#

Under networking tips & tricks.

lost tapir
#

[[ quick networking help ]]

i dont normally use UI for buttons, ive always just done mesh collider trigger but wanted to try UI this name. but it seems all my regular global scripts ive used forever arent global when on UI? this is how i have one set up, it is supposed to play an animation globally, which works when gameobject is the trigger, but isnt showing the animation global, just local on UI. would like some guidance pls!

heavy spindle
lost tapir
obsidian python
#

@lost tapir Do your button have the VRC Ui Shape script too? You can't send Custom Events without that

lost tapir
cold laurel
obsidian python
#

It's good to know, I have put it on all on my child objects, except the canvas, ty

cold laurel
vale prawn
#

Ok, so I have a door controll system that allows for locking the doors, I have the 'Locked' state set to UdonSynced, but it seems to not function for late joiners.
Script is set to 'Continuous' synchronization method.

#

Been a while since ive done networking for Udon, and testing for this quirk is somewhat difficult

#

Additionally in the Start method I check the synced variable and handle it as needed.

obsidian python
#

@vale prawn Is your script contains the OnDeserialization() or value Change functions where you handle the late joiners?

vale prawn
#

I dont use OnDeserialization at all, is that now required for this?
Never used to be like a year ago when I last worked on this script

obsidian python
#

You don't have to, you can use custom network events too

vale prawn
#

I use 2 custom network events, Lock and Unlock. I use a single ToggleLock function on the person locking or unlocking, which determines which event to send

#

That all works perfectly fine. It is just anyone that joins while the lock is in the non default state, in this case it is initially unlocked, so anyone joining once the door is locked sees it as unlocked

obsidian python
#

when a new player joins, he should request the actual door state from the owner of the object, that can be done with Custom Network Events, but using OnDeserialization() can be good for dealing late joiners, because it gets called every time if someone joins to load all the synced variables

vale prawn
#

This is making less sense, I thought they received the synced variable upon joining, and would then have it when the Start() method is triggered?

#

if thats how things work now whats even the point of [UdonSynced]???

obsidian python
#

They do recieve all the synced variables, but not the logic of your game. you still have to call the OnDeserialization() and set the value that is stored in your udonsynced variable

vale prawn
#

Hol up, so they receive it, but its not automatically set into the variable like it used to be??

obsidian python
#

yes, you still need to call the gameObject.SetActive() method when they join, even if you use udonsynced variables

vale prawn
#

I do

#

I use the start method to handle that, should I instead be using the OnDeserialization method for that?

obsidian python
#

yeah, i think when the game launches, it won't initially have all the synced variables, it recieves a bit later after the Start() method

vale prawn
#

Wait, do I not have to use seperate custom network events for toggling things anymore???

#

Or is it still best to do that for people currently in the instance and use OnDeserialization to handle it otherwise

#

I havent touched udon since all the networking update

obsidian python
#

if you are using UdonSynced variables, you don't need to send custom network events to update the variables, players receive the variable updates when the OnDeserelization() method happens

vale prawn
#

How stable/fast is that though?

#

I know back when udon was sort of new it was impossible to rely on that

obsidian python
#

I didn't do experiments on it, but you can also change between manual or continious mode. manual means, you have to call RequestSerialization() on your script, otherwise your synced variables won't update on that script

vale prawn
#

Reading about manual means only the owner of the object can do that though, and since this script is on an empty object I have no clue how it would change hands to whoever triggers it

#

It shouldnt hurt to just keep running custom events to trigger specifics

stone badger
obsidian python
#

you also have a Global Toggle Object script by default in your scene probably, that you can use to toggle your doors globally

vale prawn
stone badger
obsidian python
#

What's wrong with it? it works perfectly

stone badger
#

If you'd like a few simple examples.Start() is setting an UdonSynced property which (if they are a late joiner) not going to keep that value. Only the master needs to set that when the world starts.

#

No benefit (in my mind) to check if the gameObject is already owned by the player who Interacted just set the player. It causes no issue if they were the owner. "Simple is better".

#

You have toggleObject.SetActive(isEnabled) twice. OnDeserialization won't be called for the non-owner and the owner should (probably) set something active "after" it has called RequestSerialization.

vale prawn
#

I can see certain cases (Based on past experience with how Udon used to work at least) where calling SetActive would be reasonable on the interact and when the variable is synced

stone badger
#

I personally would add two methods. One is called by Interact to do whatever that class needs done. It keeps Interact pretty empty and permits other code to call that method without calling Interact.

#

The other is a method I add to any sync'd class which I now name Apply. OnDeserialization will simply call it and the player that sets the value and calls RequestSerialization will call it. Everybody calls the same method resulting in the same behavior.

obsidian python
#

but this script also transfers the ownership of the object, that's why it's checking if you own it or not. when you transfer a door, on the first door open, it will open up slowly, because you didn't own it, but if you keep opening/closing the door, it will be faster for you, until someone else start interacting with it too

stone badger
#
private void SetPressed(Boolean pressed)
{
    AppApi.LocalPlayerSetOwner(gameObject);

    _isPressed = pressed;

    RequestSerialization();
    Apply();
}
#

You won't have my AppApi library but it clearly sets the gameObject owner.

stone badger
#

if( x != true) x = true;

#

there is no reason to check that

vale prawn
#

Ok so one last question, is there a way to test udon networking Without loading VRChat (I only ask cause Im on a network that I should not be uploading or logging into VRChat from)

#

Clientsim gets close it seems, but not close enough

#

If there isnt (And I dont expect there to be) then Ill just have to wait a couple hours to run some tests

pearl folio
#

not really

stone badger
pearl folio
#

you can use local test which avoids the upload, but you're still talking to vrc servers since the clients are open. The sdk may also talk to vrc servers already even if you're not logged in fwiw

vale prawn
stone badger
#

Oh definitely test before uploading the world. Much faster turnaround for what will almost certainly be unforeseen errors.

obsidian python
# stone badger if( x != true) x = true;

yeah, i just had a thought it would notify all the players if you don't check the ownership, so if you would have 30 players online, they would recieve an ownership transfer notification even if no owner was changed, but actually, in game it blocks you sending ownership transfer to yourself once you already the owner. so yeah, the check is actually not necessary

vale prawn
#

Yeah, Ill test later tonight when im not on my work vpn

vale prawn
#

Oh wow, network is much simpler now than it used to be

#

Just stripped an old script that was ~100 lines down to closer to 50

vale prawn
#

HOOOOOLD ON Let me run this idea by here quick,

So, since VRC has 'Allow Untrusted URLs' lets say I join a world with a script that pulls from an untrusted URL, and sets the value to a synced variable, then someone else in the world joins and does not have untrusted url's enabled, if I understand correctly, the same data that is pulled by one user is then able to be shared to all others who would not normally be able to access it?

#

If this actually works as I expect the implications and very strange abilities of it are immense

cold laurel
vale prawn
#

Agreed, and im not saying its a bad thing this is possible, I am actually heavily interested in it and the realization that I could do something weird like host a local server only accessible by me, which would allow me to change data and be the only possible person to change that data externally. I can think of at least a few things that would be extremely interesting with that

stone badger
#

If it is "dangerous" I would like to read an example of what that danger is and it would be nice to see how the current implementation prevents such a danger. Lots of people are hosting REST services accessible via VRC.

obsidian python
#

Does it expose your IP address, when you recieve data from an untrusted url?

pearl folio
#

only if it's your client who made the request

#

in the scenario where client A requests the data via http and uses udon networking to send to client B, client A's ip would be exposed, client B's would not

pearl folio
stone badger
stone badger
pearl folio
#

you can still spoof it locally

#

https or not

stone badger
#

But again it is simple question... how is what VRC provides now keeping people safe?

#

That doesn't have anything to do with REST services does it?

#

I'll point out that VRC currently has a "player option" to enable untrusted URLs. This is an on or off switch "for every world in VR Chat". If security was important it could be on or off on a per world basis. Someone might trust you but not me or vice versa.

pearl folio
# stone badger But again it is simple question... how is what VRC provides now keeping people s...

IMO it barely is, there's no user feedback on http requests, the untrusted url control is way too coarse (trusted domains [which gets updated at any time without warning by vrc] or Literally Everything), there are so many worlds that require untrusted urls to function at all that people just leave it enabled forever, and despite all the restrictions there have been quite a few "creative" methods of exfiltrating user data

stone badger
#

I find this an interesting conversation. So what "user data" might people with VR Chat world know about me?

pearl folio
pearl folio
cold laurel
stone badger
#

My display name is not a secret is it? Position as in "where I'm standing"? So the "Coffee Shop" knows that I clicked on a cup and when I dropped it, it was floating in the world and someone else picked it up and dropped it several times. The Coffee Shop (example) has no idea who I spend time with only who was in that world. But let's use a video playing world (anybody got one of those?). Now that it knows I used to drop in every night with 3 or 4 of the same people (and sometimes a few other people) but I haven't in several weeks... they take that information and do what? Redesign their world maybe? Doesn't sound like user statistics would be such a bad thing.

#

@cold laurel So you have untrusted URLs turned off? So as to not be tracked?

cold laurel
#

nah, I have it on

pearl folio
#

i don't think it's inherently a bad thing, and it would be nice to see some of it added to vrchat natively at some point. even the simple stuff like the pc vs quest user percentage would be good to know. average instance lifetime. etc. and vrchat doing it at the platform level would help alleviate some of the privacy concerns - it can be guaranteed anonymized that way

cold laurel
stone badger
cold laurel
#

more so the restriction on constructing VRCUrls at runtime

#

because that would make it ridiculously easy to send data out

stone badger
#

Yes and I think that restriction should be removed in most cases. Not hard to institute a "developer" subscription with a legally binding agreement. If a world builder is found to have broken the terms they can be fined, their deposit will be lost and they lose access to VRChat.

pearl folio
#

i'm sure something like that is in place for the allowlisted services like vrcdn. not sure how well it would work for individual creators though

stone badger
#

Other systems have found ways to do it. AltSpaceVR prompted the user once per world when the call was made as did NEOS (and now Resonite).

pearl folio
#

it is also proactive rather than reactive

rose rain
#

need some help here

#

If String Equals is true, to is valid object then "SendCustomNetworkEvent" would run

#

else it wont run right?

#

But the shit is, even i have it false. it still runs.

#

whats going on.

rose rain
#

O

rose rain
#

Is this correct?

#

@sweet wolf @humble girder

#

Does this set Key 1 and Key1 hidden box location to DefaultLocation 1?

rose rain
#

yes the position went like wrong

humble girder
#

Of course that isn't correct.

rose rain
#

so.. whats wrong..

humble girder
#

TranformVector. You have to use Get Position instead

rose rain
#

i am grabbing the location of default location

#

like this right?

#

damn when i use that node.. i feel something is off.

humble girder
faint rock
faint rock
faint rock
# stone badger I don't "know" of course but if they can ask for $10 so I can store more avatars...

Charging world creators for access to the creators own services is just a kick to the face. You're charing the people who make the content for your platform which is why anyone is there in the first place for them to be able to access their own services, which they're also likely paying for out of their own pocket. That's an insane idea. Having some sort of unlock or agreement would be fine.

#

(unless I'm misunderstanding what you meant)

#

Resonite allows for dynamic URL generation and it lets me keep things in world updated without having to touch the world, allows for per-user customisation, etc. It feels like VRChat is HTML before the advent of dynamic page generation became a thing, but only due to it's own self-imposed restrictions.

pearl folio
rose rain
#

How do i play an event for a set duration?

cold laurel
rose rain
#

this logic is flawed.

#

its gonna loop 25 times all at once

#

to this Event.

cold laurel
#

šŸ’€

rose rain
#

LOL

#

i wanted it to play this Event every 0.2 second for 25 times.

#

yeah i know whats wrong.. lmfao and i am trying to figure out.

cold laurel
#

make an int variable

#

subtract one from it each time the event happens

rose rain
#

wait

#

but how do i do that?

cold laurel
rose rain
stone badger
# faint rock Charging world creators for access to the creators own services is just a kick t...

Content creators often don't seem to realize that without the server there is no host for their chill-out world. A store pays the mall owner because the mall itself brings in customers. The mall does not pay the store but in an extreme case might charge less per square foot because the store is an anchor and will attract a) other stores and b) customers. I can pay someone to create a VCR world ... how much would you be willing to pay someone to build and maintain VRChat?

#

Additionally Resonite (and NEOS) worlds are hosted by the person who instantiates the world. Resonite doesn't (in so far as I know) direct all the traffic.

faint rock
#

You're saying I should spend all my time making worlds, paying for assets, then pay for servers to run backend stuff but also I should then pay VRC to be able to access my own backend? That's absolutely ridiculous.

#

Keep in mind I pay for and maintain those servers which again is more time and money on my side.

stone badger
faint rock
stone badger
#

You shouldn't spend any time doing anything you don't want to do. I should be able to buy more bandwidth, server space and stuff if I want to.

faint rock
#

It sounds like you're suggesting paygating peoples own content from themselves.

stone badger
stone badger
#

That isn't how VRC works which is what I was saying.

faint rock
#

I don't think I'm the one not understanding here. We're talking about world creators ability to have their world's connect out to the USER'S own services. Not services run by VRC. This would also be benefical to VRC as it would allow content to be updated in world without the owner having to upload a new copy and users having to all download new copies, thus cutting down on bandwidth usage.

stone badger
faint rock
#

Sounds like you're working against yourself and all other world creators by encouraging features that require us to do all the work to be pay gated, I'm not sure why you'd do this but sure.

stone badger
faint rock
#

But anyway, I'm done. I'm not going to humour these outright fucking stupid suggestions any further.

rose rain
#

@humble girder remember that stencil thingy? Is it possible to like set a range that what can see through?

stone badger
humble girder
rose rain
#

like lets say i see through the magnifying glass

#

i want to see 10 meter of hidden stuff etc.

#

how do i make that?

humble girder
stone badger
rose rain
#

@humble girder @sweet wolf Hmm how do i fix this issue.

#

okay i try to explain.

#

When a player in a list joins a world, a tag gets lit up.

#

When the second in the list joins the world, their tag gets lit up, however they also have to tell player 1 to lit up their tag too.

#

How do i do that?

obsidian python
#

Are you trying to enable a specific GameObject if both the GameObject's name and player's displayname matches, then sync them for all the players?

rose rain
#

now the question i am is how.

obsidian python
#

you can just call the OnPlayerJoined and OnPlayerLeft events, iterate through all the GameObject's and check if the player's name matches, then enable/disable according to it

rose rain
#

See. i explain to you..

#

when a player in the list joins. their tag is lit.

#

player 2 joins, their tag is lit too but how do i player 2 tells player 1 to lit their tag in their screen?

#

same goes if player 3 / 4 ...........

#

how do i tell a player to tell another player to check if if that partiular player is on or not.

obsidian python
#

I'm not sure, what are you trying to do, do you have a staff list in your server, so you would like to enable more stuff for them?

stone badger
# rose rain how do i tell a player to tell another player to check if if that partiular play...

The player joins and checks "a list" so does that list contain user names or something else? A second player joins it checks to see two things. If it should light itself (by checking the list) and whether any other player that is already present is on the list. Each player is responsible for itself and "knows" that if other players are on the list and in the room they will have set themselves. Will that work?

obsidian python
#

This isn't too reliable, is it? Even if the "playerTurn" is a UdonSynced variable, it doesn't update for other players

#

On the other player's OnDeserialization method it doesn't update

frozen igloo
obsidian python
#

it seems the other players runs the OnOwnershipTransfered first, then later the serialization, i had a thought it could be a problem

#

changing the owner on the OnDeserialization? sadly it just adds more latency to the game, but if it's that's the only case, i will try it.

cold laurel
#

So, trying to get the player with the ID equal to playerTurn + 1 is not very productive.

#

Setting that player as the owner of the object for sync is also not productive because the local player needs to be the owner of the object for the synced data to be sent.

obsidian python
#

have you played the among us game? mine is going to be somewhat similar, where people need to enter in a zone first, then those players are teleported to the game

cold laurel
obsidian python
#

i already made a system for that, I'm making a card game btw, I just want the turn owners to interact with the things more seamlessly that time, like drawing new cards, placing cards down etc.

#

probably not too efficient, but it gets the job done xD

#

but it's manual sync, and they only get called when player draws a card, places it down

#

so it doesn't have that much impact on network traffic

frozen igloo
# obsidian python This isn't too reliable, is it? Even if the "playerTurn" is a UdonSynced variabl...

oh I just realized I misread this - I thought the third line was sendcustomnetworkevent, and my response was tailored to that situation.

It's actually SetOwner, and in that case my response is slightly different but still it's not going to work because if you set data and try to send it, then immediately send ownership to someone else, the ownership transfer will stop any data you were trying to send.

#

if that setowner was always to the localplayer, then it would work

obsidian python
#

yeah, but it's also strange the other player receives the OnDeserialization too, becuase it's gets called too, but it doesn't actually change the variable

#

so it just prints out the last known value

frozen igloo
#

probably received serialization from the new owner

obsidian python
#

but the new owner is himself

#

and he couldn't call that method when he's the owner

#

I think when you call RequestSerialization() and SetOwner(player, gameObject) at the same time to the new owner both at once, the new owner will still run the OnDeserialization(), but it doesn't update the udonSynced variables, but the OnDeserialization shouldn't even run in the first place

#

if the ownership already got transfered

rose rain
#

How do i make an object that i can hold, place and step on..

#

It seems that my collider keep getting bugged up.

#

When i touch the cube.. i keep get flung, or just sink

#

Let me explain..

#

I spawn pillows.

#

I pick up the pillows, i can place anywhere in the world.

#

I step on it

#

I get flung like 20 meters.

#

Why is that so and how do i fix it?

rose rain
#

Anyone have any idea how to fix such issue?

obsidian python
#

I think you can't really have a collider on it while you are also holding it, because it would cause physics problems, but you can disable the collider while holding, and enable it again when you place it down

frozen igloo
timber ferry
rose rain
#

so how?

timber ferry
#

well, i don’t know why you get flung away when stepping on it

#

they’re set to isKinematic right?

#

if not, try that, if they are, try without it

#

just to see what might work

rose rain
#

why i set isKinematic because i want it to stay in place in the mid air.

#

And i dont want people to move and drop and get the pillow wander off the world..

#

hmmmmmmmm

hot shale
#

I want to make a Lockable door.

I was thinking about it:
If I look the door, I set the Owner and a locked bool.

Then I woould just block any non owner interactions.

But what happens If the owner leaves the world?
Is the owner then set to null?

timber ferry
#

i believe that in that case, the owner moves to the next player who has been in the instance the longest

#

and i think you’d need an OnOwnershipTransferred event to tell it what to do

hot shale
#

I will look into that, thank you :3

shy path
#

Is there any way to get currently/last spawned item from object pool for late joiner? Because for late joiner when the script starts I need to determine which object from the pool is currently active but no matter if I run my way of checking on Start() or OnPlayerJoined() it never finds the active one because ObjectPool haven't made that object active for him yet

here's how I check for the active object, by default all of the objects I have in the pool are disabled in the scene (I'm also using this when Owner spawns object from the pool and it works without any problem for others)

public void SyncNonOwner()
{
    for (int i = 0; i < this.transform.childCount; i++)
    {
        if (this.transform.GetChild(i).gameObject.activeSelf)
        {
            carObject = this.transform.GetChild(i).gameObject;
            SetCollisionArea();
            Debug.Log(carObject.name);
            return;
        }
    }

    carObject = null;
    
}
#

I could technically attach script to objects in pool and just set value of currently spawned object with OnEnable(), but I hope there's some other way which I don't know

rose rain
#

This may sound stupid but in udon graph, how do i tell GameObject A collided with GameObject B ? Object specfict..

rose rain
#

In this 2 script, i have this issue where when i join the game, the second player who joins triggered all the chest and stuffs.

#

how do i prevent that?

#

something is defo causing when player joins something.

rose rain
#

i need to understand Ondeserialization / Request Deserialization..

#

Where do i place them

#

When do i use them

#

how do i use them

#

The differences.

vapid pagoda
# rose rain The differences.

RequestSerialization to send data, only object owner can do this
OnDeserialization is called for other clients when data was received

#

sadly i cant help you with udon graph, but for U#, youd simply call RequestSerialization(); to send UdonSynced variables, which may require at least one changed variable

#

once data is received by others, it will automatically call OnDeserialization(), which you can use to process data if you need to

#
            Debug.Log(someFunnyVariable);
        }```
rose rain
#

like as u can see i set the object owner to themself which i think its wrong..

#

if u can explain how i can grab the "Master" who has the most time spend in the current instance and just copy what instances that player have.. that would be much easier.

vapid pagoda
rose rain
tulip sphinx
#

vrc is pseudo p2p, having all stuff on master is just doubling the delay, sinve you first send the data to master, then it sends it to everyone, instead of becoming the master.

#

not to mention how everyone loves being a master of 100 pickups and having all this rigidbodies to be simulated on their pc

vapid pagoda
#

is that what you mean?

rose rain
#

ahh.. i not good with Udon sharp..

fresh stump
#

Do you need ownership of a vrc object pool in order to spawn things from it?

heavy spindle
#

Not necessarily. The child objects should already be part of the scene and you can just request ownership of the child object you want from the client's end

rose rain
#

Okay let me explain my issue. Lets say u got yourself a lock and a key.

While holding the key everyone should be able to see it.

When the key is collided with the lock the key and the lock will disappear adding 1 to a variable.

When do i request Event OnDeserialization? or UdonBehaviour RequestSerialization?

Who should i set owner to? or dont need?

humble girder
# rose rain Okay let me explain my issue. Lets say u got yourself a lock and a key. While h...

One key thing you might not know is: each player run copy of vrchat client on their own machine independenly. Therefore each player script will not interfere with each other.

OnDeserialization is an event that react on new data arrived when a player isn't an owner of object and the data is updated by object owner.

RequestSerialization has to be called when object owner want to update and propagate value to other player.

SetOwner to a player who want to update and do RequestSerialization

obsidian python
#

Do anyone have any idea why does a player refuses the ownership transfer, because it thinks it already owns it, but when I actually pick that object up, then it finally transfers the ownership?

#

Here, it doesn't transfer Y7-077 back to me, because it thinks I already own it, but when I pick it up, it transfer it to me

obsidian python
#

this is the only place where i transfer all the ownerships

#

it works fine for player 2, but for player 1, it doesn't

obsidian python
#

i guess, there's a bug, if the gameobject isn't currently enabled, it cannot be transfered or something

#

because if I enable it, I can transfer the ownership

rose rain
#

Is there anything wrong here?

#

Guess this will work.