#udon-networking

1 messages Ā· Page 23 of 1

rare cloak
#

Does VRChat automatically sync the bools for late joiners?

twin portal
#

yes, pretty much

#

but you still need to do the setting with the bool

rare cloak
#

Yup. Thanks guys this helped a lot!

twin portal
#

with synced bools I like to set them up callback variables

#

so as soon as it syncs to a new value, it does whatever you meant to do with it, automatically

#

rather than juggling OnDeserialization

#

which actually you'll have to use Continous won't you? since you'll be using ObjectSync

rare cloak
#

No idea with that kind of stuff, but I assume so since I want it to be moving around a lot?

#

continuous vs manual still stresses me out a bit lol

#

mostly the wording on continuous saying that things will be "tweened"

twin portal
#

yeah that just means you don't really care about in-between values, so the literal values that get synced may not be the exact same numbers on the other side
which in a lot of use cases is perfectly fine

#

and best part about bools. What are ya gonna tween? they're either on or off

#

think of ObjectSync. You throw a pickup, you don't really care if the arc the player threw it at is precisely replicated, just that the end result is the same
so the pickup might fly in a slightly different way on other people's screens, but the spot it lands will be the same

rare cloak
#

I did have this to track lights stuff as players can upgrade the flashlight as well, but it's specific numbers so I assume that the tweening wont effect that much? Simple as a += .5 or 1

twin portal
#

note that the tweening will only happen if the value is constantly changing

rare cloak
#

Okay, so literally like the transform as you said

#

Perfect lol

twin portal
#

p much

#

if the value is staying the same, continous sync will eventually (pretty quickly) catch up and then be the same

#

if this was on like a slider that the player can change, it'll be tweened if the player is constantly moving the slider, but as soon as they stop it'll sync up

rare cloak
#

When I had just the light itself working, there was a delay when the players moved. I assumed that was from network lag, but was it actually the tweening then?

twin portal
#

if you were using ObjectSync to make it follow the player, then kinda

#

that's the delay of it syncing to their position

#

ObjectSync following a player will always be a bit behind, unless it's in their hand

#

hence why it's usually recommended to have it follow the remote player positions instead

rare cloak
#

instead of objectsync? Like having synced transforms in the script and using GetOwner?

twin portal
#

you wouldn't sync the transform at all, you'd have the local player find where it's supposed to be

#

you have the flashlight that you know belongs to player X; if you want it to follow them exactly, you just tell the local player "find the position (or head bone, etc.) of player X, and set the flashlight's position to it"

#

having the local player set it will prevent the ObjectSync delay effect

#

though if the flashlight mesh is invisible, you might not really notice it being behind

rare cloak
#

I think I get it. Local player just tracks the position based on the owners location, no networking other than getting the owner but that's w/e, just local setting. All I need to do is just make sure the network knows the specific state of the flashlight, and I don't actually require objectSync all the time

twin portal
#

yeah that's what I think Uzer was mentioning earlier: you disable the ObjectSync component if the player is in VR, and set it up so that the local player figures out where it's supposed to be at that point

#

or if they're in desktop disable it. I forget how you wanted it. w/e

rare cloak
#

Yup. Thanks both of you, been bashing my head at this for like a week just trying things

north thistle
#

Well let's check the VRC docs:

#

They might not know either, lol

#

Will have to test it yourself

rare cloak
#

This is my code to get the time and I display it in a UI, I get when the players join and also their current time. I can only assume it's based on your PC clock settings

#

DateTime.now does return your local PCs time.

#

So whatever you set for your PC is what you'd get. Sorry if this isn't at all what you were asking

north thistle
#

I'm under the impression that DateTime is typically a universal time that typically auto coverts itself into the time zone of your local machine. So if you pass it from one machine in one time zone to the next it will display a different time that represents the same real time

#

But I only have passing knowledge on this stuff

rare cloak
#

Yeah, I was slightly wrong. Is purely just DateTime.Now that returns the current local PC time.

#

This is the time it's returning. I'm EST so my normal time is at the top

fallow mountain
#

yeah just testing now, it seems it is getting a UTC from the server

rare cloak
fallow mountain
#

yeah i purposefully made my local time inaccurate to see if it makes a difference, and it does, meaning it is a supposedly synchronized server time, which is good

#

(im also testing the timing issues of delay events to make it change number on the dot)

rare cloak
#

So when I try build and test my world it throws a "network ID error" which I'm pretty sure is from me trying to disable the ObjectSync component

fallow mountain
rigid temple
#

Keep in mind if you're using persistence this will nuke all the saved data for everyone

north thistle
#

Wait, it'll break persistence data of uploaded worlds?

cold laurel
north thistle
#

Is there any way to prevent that? Because it seems random when it breaks.

cold laurel
#

You'll need to program your own network id utility and make it like, not dumb.

frozen igloo
#

like if you add a new udonbehaviour, it wants you to manually accept that change. You don't need to regenerate IDs for the whole thing to do so

cold laurel
frozen igloo
twin portal
cold laurel
twin portal
#

so ideally you record its ID before regenerating

#

but it would be maybe a nice QOL if PlayerObjects' IDs never changed during a regeneration? as this is a really common issue for people to run into

cold laurel
twin portal
#

I'll add it. put me in coach

north thistle
#

How do you manually assign the ID?

cold laurel
north thistle
#

found them; thanks

celest mesa
fallow mountain
#

maybe it is the PlayerObjects that gets nuked, idk

twin portal
celest mesa
#

Ahh, gotcha, that makes sense.

warped latch
#

Does that mean data saved directly to playerData is maintained through regenerating IDs, it's only playerObject persistance that's borked?

twin portal
#

precisely

warped latch
#

Phew

north thistle
#

I'm going to guess the reason PlayerObjects breaks is because the VRC servers no longer know what packets of saved data go to which PlayerObjects objects in the scene

#

I haven't had my tea yet u.u

twin portal
#

understandable, but yeah that's the reason why

north thistle
#

And because world creators are likely going to have an expectation that they can freely add, remove, and modify PlayerObjects at will I don't think there is an easy solution to this

#

I'm under the impression that the real issue is the way that network ids need to be assigned, but I'm also under the impression that the chance to change that has long since sailed.

twin portal
#

yeah I read it as this is the path of least resistance
it's super convenient to have persistence basically magically work by just doing what you were doing before, if you already understood how Synced variables work. It's waaay more effort to rework everything that would be necessary to avoid this issue vs. "hey if you have PlayerObjects just be a little careful if you regenerate network IDs"

finite sierra
north thistle
finite sierra
#

oh yea i mean that has been a thing forever if i recall?

twin portal
#

not everybody knows about it

warped latch
#

I just remember seeing someone say "use PlayerData for the actual data, use PlayerObject for in-world things that every player should get"

#

You can do data through the PlayerObject, but I assumed it was like, the less optimal way to do it,

twin portal
#

I think it just depends pretty heavily on what you're actually using persistent data for

#

both have pros and cons and different mechanics on how they work, so sometimes one solves a problem better than the other one does

minor gale
#

the last paragraph here is the most relevant part of choosing playerdata or playerobjects
https://creators.vrchat.com/worlds/udon/persistence/player-data#networking

despite playerdata being more logical to interact with as a key/value store, any change to playerdata requires sending all playerdata for your world; this is prohibitive on bandwidth in some cases

playerobjects allow chunking your persisted data into sections, but the main criticism i'd say is that it requires interacting with playerobjects for something that would otherwise not need an object per player and as people were noting above your data can be wiped if the network id changes on the playerobject

warped latch
#

That's a fantastic point. I need to move my "last known position" logic to a playerobject, then

#

I care much less about that getting nuked by regening IDs

twin portal
#

it's been suggested before that PlayerData is good for your big data, PlayerObjects are good for your fast data

fallow mountain
#

it seems PlayerData is really just a wrapper for a virtual PlayerObject that is automatically referenced in all Udon scripts, and will virtually request serialization on value change therefore has no timing control like a PlayerObject, and is not network ID specific, and uses its own workflow to get and set data... it just seems there is no special functions that cannot be replicated with PlayerObjects, i mean there is nothing stopping me if I were to store everything in my own PlayerObject, and manual sync request serialization everytime a value is changed... it would behave the same, without all the weird special methods

minor gale
#

the word you're looking for is probably singleton and it doesn't act like a playerobject, it's more like a cache of all the keys and values, it has additional ways to check for change events and context that don't exist on playerobjects

fallow mountain
#

im trying to think of a situation where you have to use PlayerData or it wouldn't work, but I cant think of anything

twin portal
#

-if you have multiple scripts that all need to reference the PlayerData, and you don't want to go through the hassle of setting the PlayerObject to it
-when you don't need a new object in the world for every single player, just something to track the local player's PlayerData
-if you want to check if the saved data already exists or not, and do logic based on that (not as easy to tell with PlayerObjects)
-you run out of available memory in PlayerObjects

fallow mountain
#

hmm

north thistle
minor gale
#

if you want to say you can do similar things i'd agree, but saying a per player instantiated thing is the same as a cache of all key/values isn't really true

you can't dynamically add keys to playerobjects, you can with playerdata

north thistle
minor gale
#

if you want to make some custom way to refer to values within a byte array or a string you json out yeah you could make any number of keys, but if you're comparing them directly you can't add a new persistent variable in the same way that you could add a new key programatically

north thistle
#

you can sync a DataDictionary of arbitrary size and key amount by serializing to a single persisted variable, can you not?

minor gale
#

yes, a string/json in that case unless you make your own way to read and write the dictionary with bytes

you can

north thistle
#

I'd assume that PlayerData is doing the same, although they might be using a proper Dictionary instead

#

The biggest difference is that PlayerData is very permanent, so much so that you cannot delete keys that have been created

#

If you have the ability to serialize all the main core data of your world into a single variable, it's probably best to safeguard that in PlayerData

fallow mountain
#

PlayerObjects are also permanent I'd assume? you'd just be losing the keys to access them forever?

#

I mean if they are nuked, the data is still there, right?

north thistle
#

I presume the server side data allocation matches your in-world allocation. So anything removed in world gets removed server side as well

obtuse echo
#

I'm glad I use PlayerData for everything...

#

I thought PlayerObject would also have dynamic IDs, regardless of what it is on the template.

north thistle
#

Apparently if you go into the the network id manager, it will often tell you the issue so you don't need to regen ids

and if you write down the ids of your PlayerObjects you can reassign them manually

obtuse echo
#

Writing IDs down is also not exactly a user friendly thing. Not to mention how slow the UI for the manager gets when you have many objects.

#

Well, I should definitely export the ids just in case.

lament coyote
#

Quick question, as i could not find any documentation for it, Who is the instance owner when the instance is a group instance

tulip sphinx
#

theres no suchšŸ¤·ā€ā™‚ļø so you just ignore it in your logic

#

group instance owner is the group

lament coyote
neon chasm
#

Dont know If this ist right in here, but how woud you go about finding per script the profilepictures of Players in the current world for use in a Playerlist Display

foggy jackal
#

I'm not certain, but I think you'd need to use the actual API for that, which you can't do from Udon.

neon chasm
#

currently we have a c# script using the player API to display Names but are not certin how to get the profilepicture data

foggy jackal
#

I didn't realize you could make those API calls from U#

solar crescent
#

anyone knows how to network animation sync? It's not just something like putting vrc object sync on an animated object yes?

Because stuff in my worlds is animated and I want it to stay in sync for late joiners. It's easy for static objects just to activate or deactive them. But how can late joiners catch up with all animations in a world?

cold laurel
#

This can actually be a bit complicated, so if you can provide more information about the setup of your animations and animator controllers it will be much easier to help you.

solar crescent
cold laurel
#

Unscaled Time keeps animations running at real-time speed, unaffected by time scaling.

#

We'll be using an U# script to initialize the animator to the right position in the animation once on Start.
The script looks like this:

[SerializeField] private Animator animator;

private void Start()
{
    AnimatorStateInfo stateInfo = animator.GetCurrentAnimatorStateInfo(0);
    float animationLength = stateInfo.length;

    float normalizedTime = Mathf.Repeat((float)Networking.GetServerTimeInSeconds(), animationLength) / animationLength;
    animator.Play(0, -1, normalizedTime);
}
#

This does not need UdonSync! We're relying on Networking.GetServerTimeInSeconds() as the time source, which will probably be precise enough for our purposes here.

solar crescent
#

Oh? Is that possible with Udon Graph? So far everything I did with Udon Graph before, because it's so visually accessible for a non-coding person šŸ˜„

cold laurel
#

It's probably possible in Udon Graph too.

solar crescent
#

hah I just found something like that

cold laurel
solar crescent
#

if I drag and drop it into my scene, I get this :0

cold laurel
#

Wonderful

cold laurel
#

Lol

#

Find the AnimatorUpdater.asset file in your project and delete it

solar crescent
#

So if one dead script lays somewhere in Unity, everything stops working? xD I found and deleted my try to create something like that and it's working now

solar crescent
cold laurel
#

And it will only work if that layer only contains a single looping animation clip.

solar crescent
#

I see, but I can at least sync those loops...whenver a state changes via a bool I can send it in Udon Graph as a networking event and everything that just does movement on start I can sync with your script when putting stuff on base layer in default state...that is at least solving my problem! So thankya! >x<

cold laurel
solar crescent
#

I meant something like that. Someone interacts with a lever, and the sound and opening animation will happen for everyone :3

cold laurel
#

If you click it once, and then someone joins, it will be desynced for the late joiner.

solar crescent
#

Yep! That I know. So I looked for dozens of videos on YouTube and the best ones kinda agreed that you should just let the master send that everyone checks something's state to sync it to the master :0

#

so it would redo all the scripts that're already done in an instance at once for a late joiner :0

cold laurel
#

:(

solar crescent
#

A variable that's synced means...after changing that thing in a world you request serialization so everyone has the same? And on start for a new player if would automatically onDeserialization do the same?

cold laurel
solar crescent
#

Means just the one joined person would get that Deserialization on start because for everyone else nothing changes and not every single person would get the question "are you master" and "did it already happen"? :0

cold laurel
#

The fact that there are tutorials out there that tell you to misuse SendCustomNetworkEvent in this way makes me sad.

solar crescent
cold laurel
#

Tragic

tulip sphinx
solar crescent
#

So I could not use Network event...and just create a synced bool that is set on using a button and instead of custom event that was sent, I use OnDeserialization and it does the same, plus I can save all that OnPlayerJoin > ask questions to everyone blah bla? o.o

#

oh wait...probably I need to ask first if that bool now is true to do the action then...

cold laurel
#

Yes!

solar crescent
#

because in future there may be more than one bool if the scrift develops

tulip sphinx
#

check the vid, you need to set the owner, and you need to play same event for him (interacting person) since ondeserialization wont fire for the owner

solar crescent
#

I think what went wrong back then...was the declaration of ownership about an object. Network events kinda force something to happen without any ownership transfer, that's why everyone (out of here) tell to use NetworkEvent, because it seems simpler on the first glare

#

tho creates more problems later

twin portal
#

yeah that last point is the important takeaway

#

the NetworkEvents make it fairly easy to just, in general do networked things, but their drawbacks aren't as obvious; at first everything seems like it's working perfectly, so why consider doing something different?

solar crescent
#

mhm. Well I try to learn that sync variable magic with that new lil map project to start clean with that world >x<

twin portal
#

a secret third option that is useful when networking is a variable's Change event, which you can create by holding ALT while dragging the variable onto the graph

#

this is an event that fires whenever the variable has been updated to have a new value

#

which includes if it was changed via network syncing :)

solar crescent
#

so that kinda is a specified OnDeserialization? :0

cold laurel
# solar crescent so that kinda is a specified OnDeserialization? :0

One note about variable change events though! They fire immediately when the variable is changed, so if you have multiple synced variables you want to check you should use OnDeserialization instead of the variable change event since the other variables might not be ready yet. But variable change events can be great if you're only going to check that one synced variable.

solar crescent
#

I see...something might need more than one information and that extra information could differ if you just ask that one variable to push a button for everyone instantly~

twin portal
#

you can optionally choose for the variable to not send its change event if you need it to, I think it's disabled by default (in graph)

#

but yeah its usefulness all depends on if you need it for other things. I like to use this event for bools that I'm using to track its own state and change stuff based on it, when it doesn't have to care about other things

solar crescent
#

I blush a bit. I already did stuff like creating empty gameobjects and setting them active or not active to save something happened or not and do the "onJoin ask every not master to copy the state of the master" - what kinda is just what a synced bool does hides x'''D

twin portal
#

I've seen that done before lol. It's still a boolean, in spirit
I feel tracking a boolean like that makes sense for those that are more analog-minded

solar crescent
#

Mhm it's just - whenever I asked friends, they told me they don't know, because they just puzzle together a nice lighted showcase for VRC and done. No code. If I asked heavy world creators with all fancy stuff, they told me "eeeeeeeew you're not using U#, then you're a pawn and should not bother with problems". But I wanted to make fancy stuff with Udon Graph too T_T

So I just puzzled around and followed YT tutorials. Definitely learned something tonight tho >x<

heavy spindle
#

Well… U# is a lot more… How do you put it… Friendly I guess. A lot of developers are text based which in itself is valid. Doesn't exclude being able to convert U# to graph, but U# does a lot of things for developer convenience which would add a lot of boilerplate in graph

solar crescent
#

I never learned how to program, but many programs use some kinds of visual programming. Blender also has nodes for everything. So I of course started with visual programming in Unity. Also all the tutorials on YT use nodes, because they target people with not much knowledge. I learn more and more about how programming kinda "thinks" and works, but I couldn't produce code from scratch now.

twin portal
# heavy spindle Well… U# is a lot more… How do you put it… Friendly I guess. A lot of developers...

I used to believe the same thing, U# being more friendly, but I ended up finding out that this is because I already have many years of traditional programming experience, even primarily in C#, so U# comes completely naturally to me.
But for anyone I've run across that don't know how to code, this ends up being the opposite. I often see people finding a way easier time understanding nodes vs. trying to learn the C# syntax.
U# is definitely worlds easier to work with "big", complicated stuff though. Those 1000 line U# scripts literally wouldn't even fit in a Graph node before hitting the node limit.

cold laurel
#

U# allows you to write almost C# while using modern IDEs which have been refined for literal decades. This is a massive advantage.

heavy spindle
# twin portal I used to believe the same thing, U# being more friendly, but I ended up finding...

I think the barrier to entry mostly comes with the assumption that you need to learn the words rather than understanding the underlying types. Like, once you understand that something always has a type and you can only do so much with a specific type then the rest becomes naturally, what something is named doesn't really matter. Just some ways methods are named matter if they're out of your control like with built in types

twin portal
#

I certainly wouldn't be interested in Udon if the Graph was the only option lol

twin portal
#

they often devolve into the technical jargon a smidge too much

cold laurel
#

I wonder what the bottleneck in the current pipeline is

twin portal
#

most people I went through school with described as coding at some point just "clicks", and you just get it from that point on

heavy spindle
#

I feel the same way which is why I decided the best way for me to get into it was to just dive head first into some project and try to make sense of it as I go. I think it helped me a lot that I used Visual Studio Code as well for my first language of choice (JavaScript). That first class integration and telling me when an error may occur was monumental in getting some early hints in what I can and can't do

twin portal
#

what causes the click? ĀÆ_(惄)_/ĀÆ

cold laurel
cerulean zealot
#

@twin portal @heavy spindle I can tell you exactly what the problem is:

Lesson 1:
-what is a function?
-what is a variable?
-basic "hello world"

Lesson 2:
-backend architecture of mainframes
-Algorithmic Solutions to Obscure Math Concepts
-Advanced Raytracing to discover god

twin portal
#

literally

cold laurel
#

You may have a point

heavy spindle
#

lmao

twin portal
#

I have some future plans to try and solve this problem...

cerulean zealot
#

That would be like me anding you a pencil. Showing you had to draw a circle. Then pointing to a stack of paper and say "ok were drawing bugs bunny on model today. I need this scene finished by later this week." Hands you the scene folder with layout charts and all.

cold laurel
#

y e a h

heavy spindle
#

You also have to get a working competitor with ChatGPT done by the end of the month

cerulean zealot
#

In my senario... You are left with a stack of paper, an animation disk, pencils, erasers, scene folder, and a lamp. THERE IS NO COMPUTER IN THE ROOM. I've shut the door.

foggy jackal
#

> light lamp

timber ferry
#

i’ve definitely had to learn the syntaxes and common practices over time, but initially learning wasn’t too hard for me. maybe because C# is a pretty high level language, and maybe because i already knew graph really well

#

a lot of things ā€œjust clickā€ for me though. like getters and setters, overflows in methods, return types… a lot of those i didn’t really understand well at first, but at some point i just realized, ooooh THAT’S what those do

north thistle
#

Unity does offer a free online 'course' for teaching yourself how to use Unity and C#. I had an education in programming but nothing for C#, game design, or Unity, so I went through that to get myself a good foundation. This might be it: https://learn.unity.com/pathway/junior-programmer

Unity Learn

Free tutorials, courses, and guided pathways for mastering real-time 3D development skills to make video games, VR, AR, and more.

north thistle
#

Also as of last night finished rewriting my world's networking to use a state based, eventually reliable approach. It... took a bit of work (that is a 1620 line file and there are a handful of other files that also got touched, replaced, or created as well)

cerulean zealot
#

What is that image im looking at? @north thistle

north thistle
#

oh, also it's the scroll bar for the file

solar crescent
#

So I changed my stuff to using changing variables now instead of firing network events for events. OnDeserialization was not working, but pressed Change works! But why does the Deserialization not work? I Requested Serialization before :0

twin portal
#

Have you tested it in-game? Was doing some tests earlier today and I noticed all of the serialization events don't fire in ClientSim

twin portal
cedar crescent
solar crescent
#

so kinda like that? Deserialization for remote players and variable change for me?

minor gale
#

they mean something more like this (using an event here isn't necessary, but it's probably more clean in graph)

solar crescent
#

hmmmm I see

#

so instead of on Variable Change, I fire a local event...kinda the same then :0

#

But what if there are more variables that use Serialization?

minor gale
#

in the resulting event, assuming you mean multiple bools, you'd set whatever states the variables correspond to

#

you could do it on variable change instead if that's easier in some way, it has other implications but if the variables aren't tied to each other in any way it's not the worst thing to do

#

i think you're working with animators, but the idea would be the same; you could use a block if it's more organized that way or just run them in sequence directly

solar crescent
#

what is the advantage to fire an event after Serialization instead of putting Deserialization and the changed Variable directly into the stuff that happens? Is it for making the nodes cleaner? :0

north thistle
minor gale
# solar crescent so kinda like that? Deserialization for remote players and variable change for m...

if you're asking why the thing i'm showing is preferred to your picture here, it's because the variable change event fires for remote and owner (the owner being the one who changes the variable)

deserialization only fires for non-owners

as a result, non-owners are enacting the logic twice because they'd run both deserialization and variable changed. if the states are absolute (true or false here) and simply set something, it's not the end of the world if they run the logic twice, but it's not logically correct

if you're asking why i call a send custom event, it's because it's more clean in graph (and code) to run the same logic on both owner and remote if they're simple/absolute states and it's more clean than flowing directly into the resulting changes

just to be clear the event is a local event, it's for organizing logic here

north thistle
#

Also note that "Built & Test" is more-or-less "in-game"; it is not a local test but actually a world uploaded to the VRC servers with your clients connected to said server

stone badger
#

This dropdown is from the VRC Quick Launcher tool. Is there a way to locate and/or clear the references that appear there? Oddly (it seems to me) some of the old ones still work. Can't figure out where is it keeping these or how to make it forget them

north thistle
#

But note that that event will not get triggered in ClientSim unless you do something that I think is U# only

cedar crescent
#

OnDeserialization is mostly helpful when you have multiple synced variables that are related to each other. And the order you apply changes might be important. Like you have to check one variable and do something different with the second variable.

But if your variables are unrelated to each other, then changes events are fine.

north thistle
north thistle
minor gale
north thistle
solar crescent
green falcon
#

One message removed from a suspended account.

minor gale
#

have you designated it as network callable and setup the input parameter? here's an example of what a network event might look like when called to self

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

minor gale
#

do you have the networkcallable attribute above the function? i think that is actually required when using params with network events, unlike ones without params that just require it being public with no underscore

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

minor gale
#

not really sure, have you tried it on something that isn't an overridden method?

green falcon
#

One message removed from a suspended account.

minor gale
#

if you want to target another behaviour i think the typical way would be to reference it and call it like this

public UdonSharpBehaviour otherBehaviour;
otherBehaviour.SendCustomNetworkEvent

i don't know if targeting through the first argument works the way you were trying

green falcon
#

One message removed from a suspended account.

cold laurel
green falcon
#

One message removed from a suspended account.

cold laurel
#

Sorry, I should've read more into the context of what you're doing.

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
green falcon
#

One message removed from a suspended account.

minor gale
#

is the base class method [NetworkCallable] too?

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

minor gale
#

you're overriding the method so i'm assuming it's an inherited class, like it's defining a virtual function somewhere?

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
#

And you've tried with having the attribute only on the overridden version of the method, right?

green falcon
#

One message removed from a suspended account.

green falcon
cold laurel
#

nameof(OtherBehaviourType.Method)

green falcon
#

One message removed from a suspended account.

cold laurel
green falcon
#

One message removed from a suspended account.

cold laurel
#

It's a wild shot in the dark, but, who knows! 🫠

green falcon
#

One message removed from a suspended account.

cold laurel
#

y e ah

green falcon
#

One message removed from a suspended account.

cold laurel
#

I mean, you could look at the U# compiler source code

cold laurel
#

does it work in-client though?

#

Or have you only been testing in client sim

green falcon
#

One message removed from a suspended account.

green falcon
solar crescent
#

I tried to create a door that can change their state from open to close with a simple animation. I made it like that and locally everything works fine, but if I create two clients to test it multiplayer, nothing happens for the player that is not using that door. Where is my brain-twist? :0

cold laurel
solar crescent
#

But then it will automatically fire if it is enabled as a GameObject? Because there is a closed door before and if you use the key, it's interchanged with the door that can be opened (without a big Lock on it) and if I activate the door that is able to be opened...will it then automatically fire the OnDeserilization? >.<

cold laurel
#

No

solar crescent
#

oh :0

#

like that kinda? o.o

cold laurel
green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
#

Occala please save me

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
#

Wait, holdon

#

OHHH

green falcon
#

One message removed from a suspended account.

minor gale
#
Network callable method 'DataReloadUdonSharpBehavior.OnDataLoadReloadedFailed(string)' cannot be virtual or abstract
cold laurel
#

oh

minor gale
#

i get this error if it's not an abstract class

#

it can't flag that at compile time because abstracts don't have an equivalent udonsharp program asset

#

going to guess that's the issue at least

cold laurel
green falcon
#

One message removed from a suspended account.

cold laurel
green falcon
#

One message removed from a suspended account.

green falcon
cold laurel
#

did you cast it to IUdonEventReceiver?

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
#

that's extremely sus

#

what type is target?

minor gale
# solar crescent like that kinda? o.o

is DuSelbst the object with this graph program on it? the set owner call is going to that object specifically (which isn't necessarily the object with this script on it)

green falcon
#

One message removed from a suspended account.

green falcon
cold laurel
#

not U# behaviour?

green falcon
#

One message removed from a suspended account.

cold laurel
#

šŸ˜…

green falcon
#

One message removed from a suspended account.

cold laurel
cold laurel
#

It's in the docs

green falcon
#

One message removed from a suspended account.

solar crescent
green falcon
cold laurel
minor gale
cold laurel
#

oh

green falcon
#

One message removed from a suspended account.

cold laurel
#

yeah, uh, I think I remember something from [redacted]

#

one sec

green falcon
cold laurel
#

😩

#

I know

#

This is why we cast it to IUdonEventReceiver

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

minor gale
solar crescent
#

openState is public and sync and default off, it is to check if the door is opened or not and it starts closed in animation and state. BlockerCOL is just an invisible cube so the player can't go through closed door.

green falcon
#

One message removed from a suspended account.

minor gale
cold laurel
cold laurel
#

The solution in that case would unfortunately be to not use abstract or virtual for the networked method.

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

minor gale
#

without params it might handle the call differently, it might only search for a public method with that name

solar crescent
minor gale
#

for instance this compiles, but not if they're tagged with the networkcallable attribute

#

and i wouldn't be surprised personally if these could be called through legacy network events

minor gale
# solar crescent so that should kinda worky? :0

it looks correct from what i can tell, though if the blocker collider's active state is meant to be based on the door state i think it'd be preferable to set it directly from the synced bool instead of flipping the active state

cold laurel
green falcon
#

One message removed from a suspended account.

solar crescent
cold laurel
#

You're in U#

#

You don't need SendCustomEvent with parameters

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
#

You're making an interface

#

Okay

#

can you try yeeting the abstract class for a moment and go back to hard-coded strings

#

so no override methods

green falcon
#

One message removed from a suspended account.

#

One message removed from a suspended account.

cold laurel
#

Just call the method on the base class like normal?

green falcon
#

One message removed from a suspended account.

cold laurel
#

You can literally do this

public class MyBehaviour : UdonSharpBehaviour
{
    [SerializeField] private DataReloadUdonSharpBehavior[] broadcastTargets;

    private void Start()
    {
        foreach(var target in broadcastTargets)
        {
            if (target) target.OnDataLoadReloadedSuccess("Permissions");
        }
    }
}
#

And if you want to save yourself the effort of fetching all the scripts that inherit from your base class you should consider using VRRefAssist

#

In which case you could do:

using UdonSharp;
using VRRefAssist;

public class MyBehaviour : UdonSharpBehaviour
{
    [SerializeField, HideInInspector, FindObjectsOfType] private DataReloadUdonSharpBehavior[] broadcastTargets;

    private void Start()
    {
        foreach(var target in broadcastTargets)
        {
            if (target) target.OnDataLoadReloadedSuccess("Permissions");
        }
    }
}
green falcon
green falcon
#

One message removed from a suspended account.

solar crescent
#

hmmm a difference...I checked sendChange, but the person in that video didn't

#

also no obj linked to the slot, weird...also I wonder what instance in RequestSerialization means~

minor gale
#

sendChange just allows you to use the changed event for the variable
if no object is set for something like SetOwner it will just call on itself which is what you want a lot of times
the instance in RequestSerialization means you can call RequestSerialization on a program that isn't the one you're currently in i believe

minor gale
solar crescent
minor gale
solar crescent
cold laurel
solar crescent
#

That is the key that can be grabbed and it's always on, but will need to be disabled later, to not be grabbed anymore x_x that key thing works in network!

#

Then the closed door (active) and the opened door (inactive on start) both not working for network but perfectly fine locally T_T For other players the door stays locked and closed, whatever the local one does...

minor gale
solar crescent
#

I mean I could create a trigger that gets access to the objects then...not putting the code on objects that will disappear...otherwise I'd have to manually switch mesh renderer and trigger collider and blah and need to workaround more and more and more...

#

I see I see, so kinda what I just typed. Creating an own trigger for the logic OR accessing collider and mesh renderer instead

minor gale
#

you could also make a little hierarchy for DoorNoLock, where the parent is the program and below that is a child with the collider and visuals under it, that way you could interact with the visuals and collider through one setactive call on ActiveStateObject without needing to disable the synced program object, that'd be another way to accomplish it if it's easier

solar crescent
#

OKay I will not switch the ActiveStates, I will now switch Mesh and Collider and try

#

I die, it finally works...the problem was....I am not allowed to deactive a synced Udon script ever...didn't know that...I always went for the GameObjects, cuz I always asket ten times each script on every Join if everything works like it should xDDD

#

If I want something to happen 6 times...do I need to make six events that hand over each other...I want to make a for loop, but I also need those events to always wait a bit and not brrrrrrt fire all 6 in a millisecond...there is no sleep/wait function in noodles mhm? oxo

twin portal
solar crescent
#

But in a For loop? :0

#

So if I need something for effect to do it 6 times, but with a slight delay...I need to copy over the same "play sound and kill object" code 6 times in a waterfall with EventDelayedSeconds and can't make it tidy with a for loop mhm? Cuz when coding with text you'd just say Sleep.Time(750) for 750 milliseconds or so in the loop

minor gale
#

you could try something like this, where you define a delay per loop (DelayPerCall is a float variable); you may want to add 1 to the index prior to casting it to a float though if you want the first call to have a delay too

solar crescent
#

which value is DelayPerCall? Isn't it rising cuz the index rises? :0

minor gale
#

DelayPerCall is just a float variable i added, i made it 0.5 in my case, so each event would fire with a ~0.5s interval

#

i assumed you wanted them to be spaced out, or is it that you want all 6 to fire at once after a delay?

solar crescent
#

aaaaaa I got it, makes sense...you cast all at once, but every next one with a longer delay cuz the *

minor gale
#

that's right, the delays would look something like this when called in the for-loop (0, 0.5, 1, 1.5, 2, 2.5)

solar crescent
#

I do that! Seems not important when 6 things...but when I do it like you showed, I have it modular and could reuse that thing later cuz it always can grab the length of the array to do the thing °0°

#

aaaaaaaaaaa vibrates

#

thankies~

#

I learn things today, but I also whine that I needed 5 hours for a frickin door

finite folio
#

Guys, who knows how you can add your group to the map in the form of a label?

finite sierra
#

if you are using UdonSharp you can do it like this. otherwise it should be fairly easy to copy it for UdonGraph @solar crescent

north thistle
#

I really hope they give us coroutines or at least local events with parameters

#

On a side note, does Udon support any async stuff?

minor gale
#

you can make something coroutine/task esque that runs on the main thread by spacing the logic over multiple frames and caching the state, something like tracking how long it's been running before deciding to defer to the next frame

solar crescent
#

Hm for changing states via ownership that's all kinda easy now, but I wonder what if you want to switch a state back after 60 seconds. If you just cast an eventDelayedSeconds after 60sec nothing would happen. I bet because who knoes who the owner would be. Noone. Noone did something, it's automatically...even if I pick the master as owner after 60sec to change the object's state back to active...nothing happens...

minor gale
#

passing back to the original owner isn't really necessary unless you need/prefer that for a specific reason

you could have the new owner change it back after 60 seconds, that'd be the easiest way by the sound of it, but it wouldn't change back if they left during the interim

to make it leave resistant you could record the server time it changed and listen for it exceeding 60s since then if you wanted a way that was safe through leavers

solar crescent
#

oofff sounds not so easy

minor gale
#

i think for a simple attempt you could add a delayed event call targeting 60s after you do the initial change, like after request serialization for example

in that event that fires after 60 seconds, you could change the state back and request serialize again

solar crescent
#

that didn't work so far either

minor gale
#

could you show the graph?

solar crescent
#

I set it on 3s for testing and ActiveCoin is 1 by default

minor gale
#

i don't think coin visibility should be a network call, just a local event

#

and after the request serialize in coinback, the owner should go to the event CoinVisibility again

solar crescent
#

I just want the coin to be gone when someone gets it but not active for someone late joining when there is no coin for the others for some more seconds :0

minor gale
#

the ondeserialization will handle that for late joins, but it shouldn't be a network event imo

solar crescent
#

oh I see....it's not Deserializing for toe Owner automatically if they does the change...

minor gale
#

yeah the owner doesn't actually fire ondeserialization

#

you could use the value change event if it's easier in this case to automatically go into the coinvisibility logic

solar crescent
#

but without networking that, it couldn't be that the coin's state is always the same for all, mhm? :0

minor gale
#

OnDeserialization will fire for non-owners after the owner requests serialization and the data gets to them

#

so at that point they just want to go into CoinVisibility to check the synced bool

#

it being a network event probably doesn't technically make it perform incorrect logic but it will fire multiple times per player

solar crescent
#

ah so 'OnDeserialization' could just be named 'ListenMaster', and 'RequestSerialization' could be named 'TellPeeps'...would be easier to understand x3

minor gale
#

yeah the request serialization just informs udon that you want to send the synced variables, if you're the owner it will take those variables and send them to the server, which gives them to all the other players in OnDeserialization

solar crescent
#

Am for a language pack in which SetOwner is called 'GibGib' and PlayOneShot 'Yell' and stuff. Would be funny xD

#

But how would that Graph do the same without being a networky thing telling all players stuff? :0

minor gale
#

do you mean without the custom network event?

solar crescent
#

oh that is my bad! That was from the old code before I learned the variable stuff during the last days....I missed changing it to a SendCustomEvent x_x

#

Sometimes my eyes are not seeing an obvious thing, sinking in all those noodles and things and bwah x'D

#

das better x_x

minor gale
#

yeah i think that looks like it'd work

solar crescent
#

And Network Events I just use for single few-second shots of stuff that's fired from time to time but not important and not changing a state...like an enemy always rolling down stairs a few sec if a person gets up x3

minor gale
#

network events are good for things that are much more temporary, like maybe someone firing a firework

solar crescent
solar crescent
north thistle
#

for example, I wanted to do bullet trails in my game world. Looking it up online this is how I saw someone doing it with coroutines

#

And here's the U# code I had to write to get something equivalent

private void RenderShootingLine()
{
    //LogDebug($"Starting {nameof(RenderShootingLine)}");
    _isRenderingLineArray[RenderingLineIndex] = true;

    _trailArray[RenderingLineIndex].transform.position = _fireStartPositionArray[RenderingLineIndex];
    _trailArray[RenderingLineIndex].Clear();
    _trailArray[RenderingLineIndex].emitting = true;

    //LogDebug($"_trail stats; enabled: {_trailArray[RenderingLineIndex].enabled}, emtting: {_trailArray[RenderingLineIndex].emitting}");
    _renderLineTimeArray[RenderingLineIndex] = 0;
    _renderLineEndPointArray[RenderingLineIndex] = _fireStartPositionArray[RenderingLineIndex] + _fireStartForward * _maxRange;
    if (_hasHitArray[RenderingLineIndex])
    {
        _renderLineTargetArray[RenderingLineIndex] = _hitPointArray[RenderingLineIndex];
    }
    else
    {
        _renderLineTargetArray[RenderingLineIndex] = _renderLineEndPointArray[RenderingLineIndex];
    }
    _renderLineTargetDistanceArray[RenderingLineIndex] = Vector3.Distance(_fireStartPositionArray[RenderingLineIndex], _renderLineTargetArray[RenderingLineIndex]);
    _renderLineTravelDistanceArray[RenderingLineIndex] = 0;
    RenderingLineIndex++;
    if (!_isRunningRenderShootingLineLoop)
    {
        RenderShootingLineLoop();
    }
}
#
public void RenderShootingLineLoop()
{
    //LogDebug("Entering _RenderShootingLineLoop");
    _isRunningRenderShootingLineLoop = true;
    bool hasLinesItIsRendering = false;
    for (int i = 0; i < _maxTrails; i++)
    {
        if (_isRenderingLineArray[i] == true)
        {
            hasLinesItIsRendering = true;
            //LogDebug($"_renderLineTime: {_renderLineTimeArray[i]}");
            if (_renderLineTimeArray[i] < 1f && _renderLineTravelDistanceArray[i] < _renderLineTargetDistanceArray[i])
            {
                Vector3 nextPosition = Vector3.Lerp(_fireStartPositionArray[i], _renderLineEndPointArray[i], _renderLineTimeArray[i]);
                _renderLineTravelDistanceArray[i] = Vector3.Distance(_fireStartPositionArray[i], nextPosition);
                if (_renderLineTravelDistanceArray[i] > _renderLineTargetDistanceArray[i]) { nextPosition = _renderLineTargetArray[i]; }
                _trailArray[i].transform.position = nextPosition;
                _renderLineTimeArray[i] += Time.deltaTime / _trailArray[i].time;

                //LogDebug($"_renderLineTime: {_renderLineTimeArray[i]}");
                //LogDebug($"Continuing {nameof(RenderShootingLineLoop)}");
            }
            else
            {
                //LogDebug($"Ending {nameof(RenderShootingLineLoop)}");
                _isRenderingLineArray[i] = false;
                _trailArray[i].emitting = false;
            }
        }
    }

    if (hasLinesItIsRendering)
    {
        SendCustomEventDelayedSeconds(nameof(RenderShootingLineLoop), 0.1f, EventTiming.LateUpdate);
    }
    else { _isRunningRenderShootingLineLoop = false; }
}
minor gale
# north thistle for example, I wanted to do bullet trails in my game world. Looking it up onlin...

you're right yeah, it would be more convenient

i think you're going for something a bit more visual over time than what i normally do and mine are more for debug than aesthetics, but have you considered using particles instead if it's visual alone; or running the lifetime logic on the object itself? not to say one approach is better, but i find it's relatively easy to manage a pool of line renderers and particles for a shot effect, where each line has a script that manages its own lifetime

it's more object level, but only active lines run logic

i think if i were doing it at manager level i'd probably prefer to use binarysearch to insert and maintain a sorted list of trails to lifetime, where the earliest entries are the closest to expiry; it's more complex, but it works well in practice for lifetimes imo. it doesn't require iterating over every trail while any are active would be the advantage

finite sierra
#

hmm. do we know how Hitches Per Net Tick affects the world?

north thistle
north thistle
#

So I could be wrong, but it appears that when a remote client leaves, the master gets that player's OnPlayerLeft event before OnOwnershipTransfered events.

But when the master leaves, the new master gets those events in the opposite order....

How annoying.

brisk magnet
#

I'm curious though what problem is that creating for you.

north thistle
# brisk magnet I'm curious though what problem is that creating for you.

My code has a list of players in world that gets depopulated by the OnPlayerLeft event. OnOwnershipTransfered uses this list to know who is actually in the world to 1) know if this transfer was due to the last owner of the object leaving and 2) know who to redistribute ownership of objects to

brisk magnet
north thistle
#

from my testing, Networking.Master gets updated first

brisk magnet
#

So are you saying that by the time on player left has been called, the player who was master would no longer return true on a is master check

#

If it is the case we could detect a master leaving by keeping the network id of the last master in a variable. It wouldn't need to he synced because all clients could easily ask for it

#

So you could have an alternate branch of code to handle that edge case

finite sierra
north thistle
#

the issue is that when the master leaves, the new master 1) doesn't know that the objects transferred to them was due to a player leaving because that player is still in the "in world" list of players, and 2) will try to incorrectly assign ownership to that leaving master because they show up in the "in world" list

finite sierra
#

uh its not exactly a good idea to have Reliance on a Master etc.

north thistle
#

There are ways to get around this (I used the OnPlayerTransfered event on a high priority singleton script on an object that will only transfer ownership on master leaving to force OnPlayerLeft to trigger for the leaving master), but the fact that there is inconsistent behavior like this for no obvious reason is legit annoying and a problem. And it's something I'll likely make a canny post about.

finite sierra
#

OnPlayerLeft is called for all no matter what you cant exactly change who it calls for or not .

#

and it will always tell you who left and if that person was the master or not can be checked.

#

so you should honestly validate it on someone leaving and then run whatever you need to run.

brisk magnet
finite sierra
#

well that is an odd thing to do. considering its still gonna call everything in the back. all you are doing is potentially causing issues

#

or having delayed information that is incorrect

brisk magnet
minor gale
#

there is an event that fires when master is transferred if that helps in any way

finite sierra
#

yea OnMasterTransffered or whatever its called

north thistle
#

"OnOwnershipTransfered relies on logic that runs in OnPlayerLeft so when the master leaves I need to manually make OnPlayerLeft run first" is a pretty straightforward concept, right?

finite sierra
#

eh?

#

no

#

it should just run the other one first

#

and thene on leave

brisk magnet
finite sierra
#

considering that vrchat is verifying you actually left etc

north thistle
#

And the player variable in OnPlayerLeft contains the information that I need

brisk magnet
north thistle
#

That's what I'm doing...

#

And the fact that the order of events arbitrarily flips when it is the master leaving is the issue that creates an annoying edge case to work around

brisk magnet
#

Thst seems like the only visible route with the structure you have

finite sierra
#

well i mean it makes Sense Vincil.

north thistle
#

Just to clarify, I have designed a solution to the issue it was causing. My issue is that I even needed to do that in the first play.

finite sierra
#

?

#

wait so give me the order again

#

someone leaves it calls OnPlayerLeft as always

#

but you are saying OnOwnerTransffered happens before that?

north thistle
#

It's an unintuitive gotcha that happens semi-invisibly that requires log printing variables to discover and requires you to create edge cases in your code which adds inconsistency to your own code

brisk magnet
north thistle
finite sierra
#

could be a bug or not. but then again it shouldn't pose a problem.

north thistle
#

you're free to think that I suppose, lol

finite sierra
#

well. Considering that when a Master leaves it needs to change the master relatively fast and before anything else. hence why it most likely calls OnOwnerTransfered first and perhaps even OnMasterTransfered before that. and before OnPlayerLeft.

#

atleast i see it like this The networking layer may have different event queues or priorities based on player roles:

Normal player:

    OnPlayerLeft -> OnOwnerTransferred

Master player:

    Ownership is critical → OnOwnerTransferred is given priority, so it fires first.
#

also its likely something that happens to prevent objects from ever not being owned. as that is fairly critical within networking

north thistle
#

I have my own theories on why this happens. But my point still remains.

finite sierra
#

you may have have so. but in reality im pretty sure every single Networking API does this. for that specific reason.

#

and then again you can just have code that triggers seperate for when its a master and a non master and no extra changes or other things should pose issues.

timber ferry
#

this would work fine right? since i'm returning if the player isn't local, using the VRCPlayerApi from OnTriggerEnter should be fine?

minor gale
#

if the player is valid, at the point of setowner that is the local player yes

timber ferry
#

i realized i need a reference to the localplayer anyway because i have a differnt method that needs it, but good to know

north thistle
#

Networking.LocalPlayer works for that

#

Also correct me if I'm wrong, but I believe SetOwner can be used by anyone, even by a non-owner transferring ownership to someone else. Still for this use case only letting the player to take ownership do it is a good idea to prevent everyone from making redundant SetOwner calls

minor gale
#

setowner can be called by others yes, in their code it can only be called by the local player, but i would agree that for readability it makes sense to pass it more explicitly

north thistle
#

in the context of just the code they shared here, this event (OnPlayerTriggerEnter) will be called by everyone; unless the trigger is on a layer that doesn't interact with non-local players

minor gale
#

they do an early return there
if (!player.isLocal)

only the player entering the trigger will continue beyond that

north thistle
#

Yes

minor gale
#

i'm not sure i understand what you mean, it checks if the player entering the trigger is local, while everyone will see this call, only the player actually entering the trigger will proceed to the setowner calls

north thistle
#

I think I just misunderstand what you mean by "for readability it makes sense to pass it more explicitly"

minor gale
#

by readability, i mean option 2 here makes it more apparent at a glance to anyone writing/reading the code that it's intended to set ownership on the local player. option 1 isn't wrong, but it is slightly less apparent what the intent is

// Option 1
OnPlayerTriggerEnter(VRCPlayerApi player)
{
  if (!player.isLocal) return;
  Networking.SetOwner(player, gameObject);
}

// Option 2
OnPlayerTriggerEnter(VRCPlayerApi player)
{
  if (!player.isLocal) return;
  Networking.SetOwner(Networking.LocalPlayer, gameObject);
}
north thistle
#

Ahh I see what you mean. Personally I feel that is pretty minor, but readability best practices is an area where I wouldn't consider myself too knowledgeable

grim osprey
rare cloak
#

I'm trying to play an audiosource when a player presses a button but I'm having trouble implementing it right now.

I have a player object with a "manager" script referencing an audio source child attached to it and I'm trying to play a sound clip referencing that players specific audio source on an interact. Having trouble getting the audio to play for everyone else. If anyone is willing to help again I'd appreciate it. I can show code or w/e

young thunder
#

Sounds like you want a network event.

#

This'll let you trigger an event for every player in the instance, not just the local player

rare cloak
#

Yeah I'm trying that but it's not working for some reason and I've been stuck on this for 2 weeks also just trying to figure it out. Doing something wrong just can't see it

plush crag
#

Hi

rare cloak
#
public class SpawnConsumableFromPool : UdonSharpBehaviour
{
    public VRCObjectReference objectReference;
    public string itemType;
    public Transform spawnPoint;
    public int cost = 0;

    private PlayerManagerScript playerManagerScript;
    public ConsumablePoolManager poolManager;


    public override void Interact()
    {
        if (Networking.LocalPlayer.isLocal)
        {
            playerManagerScript = objectReference.GetPlayerManager(Networking.LocalPlayer);
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
        }

        SendCustomNetworkEvent(NetworkEventTarget.All, nameof(PlayAudio));
        if ((cost == 0) || (cost <= playerManagerScript.GetPlayerWallet()))
        {
            poolManager.SpawnItem(itemType, spawnPoint.transform.position, spawnPoint.rotation);
            ChangeCurrency(playerManagerScript);
        }

    }


    public void PlayVending()
    {
        playerManagerScript.PlayOneShotSFX("VendingMachineItem");
    }

    public void PlayButton()
    {
        playerManagerScript.PlayOneShotSFX("ButtonClick");
    }

    public void PlayAudio()
    {

        if ((cost == 0) || (cost <= playerManagerScript.GetPlayerWallet()))
        {
            if (poolManager == null || spawnPoint == null || string.IsNullOrWhiteSpace(itemType)) return;

            SendCustomNetworkEvent(NetworkEventTarget.All, nameof(PlayVending));

        }
        else
        {
            SendCustomNetworkEvent(NetworkEventTarget.All, nameof(PlayButton));
        }
    }

    public void ChangeCurrency(PlayerManagerScript script)
    {
        if (Networking.IsOwner(script.gameObject))
        {
            playerManagerScript.PlayerCurrencyChange(cost, false);
        }
    }
}
#

is my current code on the button

rare cloak
#

I think I've figured it out, needed to figure out who pressed the button and assign the script using an event also so then it would know who to play the audio on

minor gale
rare cloak
#

The audio source is a child of a player object that I have following their respective owner and then play audio either globally or locally depending on what I want. In this case is when they press an Interact button I want it to play globally from that specific players audio source that pressed the button

minor gale
#

unless you have different audio per player somehow, i think it'd be much more straightforward to specify the audio clips on this script and pass the play one shot + position over the network event. it looks like you're using the playerobjects for persistent currency possibly, so if it's working well already i don't think it's imperative to change

as an aside, this check in interact isn't really necessary
if (Networking.LocalPlayer.isLocal)
interact only triggers locally and the check itself always returns true (the local player is always local)

young thunder
#

I have a bunch of global bool/float settings that change very infrequently. I currently have them set to sync continuously.

Should I switch these over to manual sync?

My only concern is that i'll spam serialization requests while a user is dragging a slider around.

#

I see that each of my float values is constantly taking up around 0.25kB per second (which seems kinda high given that the size is 20 bytes and the update rate is 4Hz)

#

it looks like it's working after switching the floats to manual

#

i see network traffic flowing when i'm wiggling the slider around

minor gale
#

you can make some internal throttling if you're concerned about the slider itself, but even just calling request serialize every time the slider event fires is arguably better than using continuous for a value that changes very infrequently and then in bursts

young thunder
#

yeah, i saw that it never got above like

#

6hz

minor gale
#

i'd also point out that calling request serialize doesn't necessarily serialize that frame

foggy jackal
#

I have a comment like // TODO: make this manual sync before release at the top of one of my scripts that's a backend for a UI thing šŸ™‚

young thunder
#

it'd be nice if i could make these things default to manual sync

#

I can't force manual sync because some of my FloatValue/BoolValue/etc. components are meant to be unsynced

#

e.g. values for graphics settings

minor gale
#

what do you mean by default to manual sync?

young thunder
#

the synchronization method on the udon sharp behaviour

minor gale
#

above your class you can attribute with [UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]

#

which will enforce the sync type

young thunder
#

i have a mix of manual sync and no sync

minor gale
#

are you referring to individual variables? only variables flagged with [UdonSynced] are synced

young thunder
#

I'm talking about the entire UdonSharpBehaviour.

minor gale
#

oh you mean sometimes you use FloatValue for synced things and sometimes for unsynced things

young thunder
#

Correct.

#

e.g. this is a graphical setting that is not synced

#

It's not a huge deal; i'll just need to remember to set them to Manual as I create them

minor gale
#

personally i think i'd move that to a serialized bool isSynced that branches into using sync or not and enforce manual sync; if i was mixing their usage often

young thunder
#

would it use two completely different variables for synced vs. unsynced?

#

or would it just never call RequestSerialization

minor gale
#

i don't actually know if you can even use udonsynced variables on None

#

but it sounds like you're doing that currently?

young thunder
#

most of it can be ignored

#

i realized that I can just do Networking.SetOwner(gameObject) if I'm making the local player the owner

#

...er, no, I can't

#

I must be thinking of something else

minor gale
#

i'm getting 'someSyncedVar' cannot be synced on an UdonBehaviour with sync mode None in my own compile

#

i suppose it's because i'm enforcing it to none on the class

#

but i'm not sure if it will be happy with udonsynced vars on a none script in practice

young thunder
#

which makes sense, since that means that the behaviour should never be synced

#

it's nonsense to have an UdonSynced attribute in it

foggy jackal
#

yeah probably use manual in that case, right?

young thunder
#

Currently, I don't use the UdonBehaviourSyncMode attribute at all

#

Some FloatValue instances are set to Manual, and some instances are set to None

#

and that's fine

minor gale
#

i think going back to how i'd branch, i'd probably enforce manual but early return on the deserialize event and never call request serialize or ownership related things

#

then again i don't know if i'd trust udon to not set the synced variable back, maybe using a different var would be valid

young thunder
#

I'll have to see:

  • what happens if a non-owner tries to set an UdonSynced variable on a behavoiur with a sync mode of None
  • what happens if a late-joiner shows up -- do they wind up receiving the instance master's values, even though RequestSerialization never got called?
minor gale
#

for the 2nd part, no, a value that hasn't been serialized will never propagate like that in manual

young thunder
#

Currently, you always take ownership of the object, even if the behaviour's sync mode is none

minor gale
#

for the 1st thing, i believe non-owners can set synced variables, but i don't know if udon will at some point try to set it back (on manual) though you're asking about none, i don't think i've tried [UdonSynced] on None, but if it compiles and works i assume it'd be okay

young thunder
#

I'll give this a whirl

#

I presume I can just do build-and-test and spawn two clients

minor gale
#

yeah that should let you test it, i'd mostly be concerned with the behaviour just halting if there's UdonSynced vars on something you set to none, but maybe it doesn't matter

young thunder
#

That part has worked fine in-game

minor gale
#

oh if it works then i think you're fine

young thunder
#

this has me curious

#

and allows you to use the behaviours on GameObjects that use either Manual or Continuous sync.

#

does that mean that the entire game object has a sync mode?

minor gale
#

yes, for instance if you place multiple behaviours on a gameobject they must share the same sync mode

#

requesting serialize on one manual behaviour will end up serializing all of them on the object

young thunder
#

interesting.

#

so having an udon behaviour with a sync mode of anything other than "None" will cause that object to become networked

cold laurel
#

If there's a disagreement it uses the last syncmode

#

Aka. the bottom component in the inspector.

young thunder
#

I'm wondering if I'll be creating any overhead by having objects that have an UdonSharpBehaviour set to manual sync mode

#

(when those behaviours don't actually sync anything)

#

it sounds like VRChat will have to start keeping track of the owner of those objects

minor gale
#

my instinct would be yes on it introducing some overhead, but if it's easier to not separate your types, i don't think it will matter much in practice unless you're making thousands of them

#

that part isn't free

young thunder
#

Manual synchronization is good for variables that are updated frequently, but quickly. It is intended for data that changes infrequently and where intermediary values matter; like the positions of pieces on a chess board.

#

oops

minor gale
#

manual is still best for a slider imo unless you don't want to handle the interpolation yourself, but in terms of bandwidth i wouldn't use continuous personally

young thunder
#

i'm not too concerned about interpolation

#

most of these things are either instantaneous (e.g. turning off lightning) or just controls for a process that takes a while anyway (e.g. setting a target rainfall rate)

minor gale
#

are you noting a specific part in that quote?

young thunder
#

it's good for variables that are updated frequently [...] it is intended for data that changes infrequently

minor gale
#

you're right lol

#

frequently, infrequently

young thunder
#

"but quickly" is also mysterious

minor gale
#

that might be referring to how far back they buffer the data, for reference this is how far in the past a packet from each type is on desktop

young thunder
#

So far so good

#

Everything's on manual sync now

#

although, hm, one thing I just realized...

#
        public float Value
        {
            get => value;
            set
            {
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (this.value != value)
                {
                    if (synced)
                        Networking.SetOwner(Networking.LocalPlayer, gameObject);
                    
                    this.value = value;
                    
                    if (synced)
                        RequestSerialization();
                    Notify();
                }
            }
        }
#

this would cause remote users to try to take ownership and request serialization

cold laurel
#

yes

minor gale
#

ah ):

cold laurel
#

I personally don't like field change callback

minor gale
#

fieldchangecallback is kinda sad compared to the actual deserialize event imo

foggy jackal
#

yeah that thing annoys me the way it's designed

young thunder
#

I'll have to split it up

foggy jackal
#

I really wanted to like it, but I don't.

young thunder
#

Now that I'm using manual sync, though, I can just react to deserialization

cold laurel
#

You can use OnDeserialization with Continuous sync too.

minor gale
#

i think they might just mean relative to none

cold laurel
#

oh

minor gale
#

but yeah you can use deserialize on continuous too

young thunder
#

i guess that makes sense

cold laurel
#

It calls all the same events

young thunder
#

So I'll do it like this now...

#
public override void OnDeserialization(DeserializationResult result)
{
    Notify();
}

public float Value
{
    get => value;
    set
    {
        // ReSharper disable once CompareOfFloatsByEqualityOperator
        if (this.value != value)
        {
            if (synced)
                Networking.SetOwner(Networking.LocalPlayer, gameObject);
            
            this.value = value;
            
            if (synced)
                RequestSerialization();
        }
    }
}
#

although, this would make it less smooth looking locally

minor gale
#

why's that?

young thunder
#

since it'll only send out events (that's the job of the Notify method) each time serialization is performed

cold laurel
#

Because Notify() doesn't gett called locally

minor gale
#

oh that's true if they were relying on it locally

#

you can call notify in the setter

young thunder
#

does OnDeserialization not get called for the owner?

cold laurel
#

Yeah, it doesn't deserialize

#

because you're the one serializing

young thunder
#

Oh!

#

I missed the SendCustomEvent at the end of the "Send variables" block

#

Okay, that makes sense.

#

I was worried I'd wind up notifying twice.

cold laurel
#
public float Value
{
    get => value;
    set
    {
        // ReSharper disable once CompareOfFloatsByEqualityOperator
        if (this.value != value)
        {
            this.value = value;
            if (!synced) return;
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
            RequestSerialization();
            Notify();
        }
    }
}

public override void OnDeserialization() => Notify();
young thunder
#

Perfect, that'll work

#

I was also wondering if I needed to take ownership before setting the value

#

but I imagine that only matters when it's time to actually sync

#

it would be a bit silly if udon aggressively checked that the moment you set the variable

cold laurel
#

as long as it's the same frame it doesn't really matter afaik

minor gale
#

i don't think it actually matters, but logically i think it's better to put it before the set

#

in terms of reading it

cold laurel
#

If you set a synced value as a non-owner without changing the ownership the value will still change.
Your RequestSerialization will fail ofc. though.

young thunder
#

yeah, and then the value will eventually get replaced (either by continuous or manual sync)

cold laurel
#

I don't remember if the value gets fixed the next network tick or if it gets fixed the next time you receive sync.

young thunder
#

this means i can move the sync logic into my base Value type

#

less duplication, yay

#

base class:

        public override void OnDeserialization(DeserializationResult result)
        {
            Notify();
        }

        protected void TrySync()
        {
            if (!synced)
                return;
            
            Networking.SetOwner(Networking.LocalPlayer, gameObject);
            RequestSerialization();
        }

derived class:

        public float Value
        {
            get => value;
            set
            {
                // ReSharper disable once CompareOfFloatsByEqualityOperator
                if (this.value != value)
                {
                    this.value = value;
                    Notify();
                    TrySync();
                }
            }
        }
#

and i tossed the callback attribute

cold laurel
#

what

young thunder
#

what about it?

#

looks like it's behaving itself in-game

cold laurel
young thunder
#

I am already using that!

#

I hadn’t considered using generics

#

They do make handling the base Value type more annoying

cold laurel
cold laurel
# young thunder base class: ```cs public override void OnDeserialization(Deserializatio...

Thank you to @minor gale for testing this for me

public abstract class SyncedValue<T> : UdonSharpBehaviour
{
    [SerializeField] private bool synced;

    [UdonSynced] private T _value;

    public T Value
    {
        get => _value;
        set
        {
            _value = value;
            TrySerialize();
        }
    }

    private void TrySerialize()
    {
        if (!synced) return;
        RequestSerialization();
        HandleSerialization();
    }

    public override void OnDeserialization() => HandleSerialization();
    protected abstract void HandleSerialization();
}

public class SyncedBool : SyncedValue<bool>
{
    protected override void HandleSerialization()
    {
        // SetValueWithoutNotify on your ui elements here or something
        Debug.Log("Bool was serialized! Value: " + Value);
    }
}
#

Instead of making the class SyncedBool I would instead make classes like CheckboxField, FloatSlider, IntSlider, etc.

young thunder
#

I separated the actual value from the UI control

cold laurel
#

šŸ‘

young thunder
#

There could be many ways to set the same value (notably, a portable menu)

cold laurel
young thunder
#

I generate a menu at runtime based on an array of values

cold laurel
#

Nice, that's neat

young thunder
#

It’s very close to what I’ve done in standalone games

cold laurel
#

Oh, you have a centralized value and multiple UIs that change and read it

young thunder
#

There’s only one value. There can be many menus that control the value

cold laurel
#

I see

young thunder
#

Yeah

cold laurel
#

yuhh

#

I did this for a prefab I made a while ago

young thunder
#

I may have fun physical controls, too

young thunder
#

like a weathervane that controls the wind

cold laurel
#

wha

young thunder
#

the Weather Machine has been set to 44

cold laurel
#

scary

young thunder
#

Can I send networked events with parameters in U#?

#

I see that they're available now in Udon Graph

minor gale
#

yeah, the namespace is
VRC.SDK3.UdonNetworkCalling;

#

you attribute a function with [NetworkCallable]

foggy jackal
#

I think "annotate" is the word there

twin portal
#

Unity refers to those doohickeys in brackets as attributes though right

minor gale
#

i think it's technically an attribute

foggy jackal
#

wait, really?

#

huh.

young thunder
#

Ah, neat

#

I'm using the U# beta, and I figured that would need to be updated to allow for this

young thunder
#

Would you like to hear me recite the entire section of the C# standard

foggy jackal
#

haha

young thunder
#

fun fact: you can write both [NetworkCallable] and [NetworkCallableAttribute]

foggy jackal
#

I'm not really from the C# world

#

"attribute" seems very much the wrong word, but hey, whatever.

young thunder
#

They can be applied to many different things

minor gale
#

you can attribute something to someone, something can also have an attribute, they don't really have the same meaning

young thunder
#

and they describe an attribute of the thing, yes

minor gale
#

like did you get u#1.2 from releases or latest?

young thunder
#

I just saw that the NetworkCallable attribute exists; i haven't actually tried to do anyhthing yet

minor gale
#

do you actually have access to the new network calls?
i.e.
NetworkCalling.SendCustomNetworkEvent((IUdonEventReceiver)this, NetworkEventTarget.All, nameof(PrintMessage), someParam

young thunder
#

I do

minor gale
#

does it compile šŸ¤” ?

young thunder
#

I'm guessing that the U# code won't actually work out correctly

minor gale
young thunder
#

I presume that's part of the World SDK, and not provided by U#

#

I'm just a little confused about what part is U#'s job

minor gale
#

it compiles u# to udon assembly afaik

young thunder
#

right

#

and NetworkCallable exists, since it's part of the VRC SDK

#

But I presume that U# will not correctly convert a NetworkCallable method with parameters into udon assembly

#

(until I update it)

twin portal
#

no, any custom event that does not have NetworkCallable will be considered a "legacy" event, and will only work how the old events do (with no params)

young thunder
#

right, but I can currently slap NetworkCallable onto a C# method (with parameters)

minor gale
#

it probably doesn't interpret the method itself any differently without support for it

#

like u# probably ignores the attribute if it doesn't recognize it

young thunder
#

actually, wait -- do I have to use NetworkCallabke.SendCustomNetworkEvent to invoke a method on an UdonSharpBehaviour over the network?

minor gale
#

i use the old syntax normally because it's less verbose

#

you just add params after the method name

#

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

young thunder
#

If so, then this makes more sense to me

#

it's not like U# has to magically turn this.Foo(123) into a network event

#

But I'm just really fuzzy on what's going on here

twin portal
#

you can either use NetworkCalling.SendCustomNetworkEvent or just the normal SendCustomEvent
(as the normal one just calls NetworkCalling.SendCustomNetworkEvent under the hood anyway)

minor gale
#
EXTERN, "VRCUdonCommonInterfacesIUdonEventReceiver.__SendCustomNetworkEvent__VRCUdonCommonInterfacesNetworkEventTarget_SystemString_SystemObject_SystemObject__SystemVoid"
#

this is what it's doing with 2 params passed in, it passes them by object

young thunder
#

Oh yeah, I understand that much

#

I think I'm getting it. UdonSharp doesn't actually have to do that much to "support" network events with parameters

#

Most of this commit is just adding convenience methods to UdonSharpBehaviour

#

It's not UdonSharp's job to even understand that networked events exist, really

twin portal
#

this really says a lot about society

young thunder
#

I've been treating U# as a very mysterious magic box

#

and it seemed natural that it'd need to do a lot of work to support custom networked events

#

either way, i can still update U# to the latest commit

north thistle
#

I'm pretty sure U# doesn't do anything more than convert C# into the udon assembly that runs on the Udon virtual machine

#

updates to U# are not updates that what Udon can actually do, for example

young thunder
#

Yeah

#

U# does need to update to correctly allow NetworkCallable methods to be invoked (by emitting the appropriate metadata), but that's about it

north thistle
#

and just to clarify, VRChat's version of U# auto updates with the SDK update, so you don't need to worry about that in that area

young thunder
#

i'm thinking a bit about security

suppose I have an admin panel that lets you control synced map values, like time of day. I only want to let certain users control these things.

The most obvious option is to hide the panel unless you've been granted permissions (by having an event sent to you by someone who already has permissions).

Of course, someone with a modified client could just turn that variable on and then interact with the panel.

But, at that point, is there anything I can do? Surely they can just take ownership of whatever objects they want and update synced values.

#

So, is there any point to doing anything beyond hiding the controls?

#

If there isn't, it will save me a lot of work!

#

This world is going to be used for group events where this is a non-issue, but I do want to try to design my systems more correctly if I can

minor gale
#

since this release they include signatures to stop modified scripts when joining at least, in terms of networking and someone maliciously calling your permission sets it might be possible if they were persistent enough. i don't think it's something i'd design around

young thunder
#

I'm unclear what that even protects against

#

I guess it makes it more annoying to load a modified version of a world?

minor gale
#

yes, they can't check the bool beforehand and load in with it already set

young thunder
#

I guess loading a modified world is easier than getting around the anti-cheat and modifying your client

young thunder
#

the instance master would decide if that was acceptable and then update the value + request serialization

minor gale
#

imo that might be best practice anyway to prevent race conditions that come from setting owner + vars

brisk magnet
young thunder
#

I want to be able to tag players with specific roles and then check if they have those roles later

minor gale
young thunder
#

hm, so synchronization can still happen even if the instance master isn't responding?

minor gale
#

there's a backing server/relay yes

#

in vrc's ideal world you'd use ownership acquisition to allow your logic even if the master isn't responsive, but you can have race conditions as a result

#

like if Player A decides they want to give permissions to Player C

if at a similar time, Player B decides they want to give permissions to Player D

they both request ownership and update the synced array

one of those hits the server later and ultimately wins, if we imagine that B's change "wins"

Player D now has permissions, but C does not because the change from Player A was dropped

#

maybe dropped isn't the correct word, but Player B's winning synced array didn't include the changes from Player A

young thunder
#

ownership acquisition doesn't make much sense to me

#

you instantly acquire it without having to wait

minor gale
young thunder
minor gale
#

central logic is great for centrally held information

young thunder
#

i'm unclear if vrchat's networking architecture makes that any more secure than just winging it

minor gale
#

i think at the point of what you're worried about they could gain access in either case (via a faulty ownership call and variable update or a faulty network event)

#

though you could reject their ownership and the server wouldn't respect it if you were using OnOwnershipRequest to deny it on the original owner's side

crimson shadow
#

cant figure out why my gameobject wont disable if another player walks through it... im trying to make multiplayer collectibles

// Collectible.cs

// this isn't doing its job properly!!!!
public override void OnPlayerTriggerEnter(VRCPlayerApi player)
{
    int index = transform.GetSiblingIndex();
    collectibleManager.Collect(index);
}
// CollectibleManager.cs
    public void Collect(int index)
    {
        if (((collectedMask >> index) & 1) == 1) return;
        if (!Networking.IsOwner(gameObject))
            Networking.SetOwner(Networking.LocalPlayer, gameObject);

        collectedMask |= (1 << index);
        count++;

        if (count >= collectibles.Length) lockedObject.SetActive(true);

        RequestSerialization();
        UpdateAllCollectibles();
    }

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

    private void UpdateAllCollectibles()
    {
        for (int i = 0; i < collectibles.Length; i++)
        {
            bool isCollected = ((collectedMask >> i) & 1) == 1;
            if (collectibles[i] != null)
                collectibles[i].SetActive(!isCollected);
        }

        if (count >= collectibles.Length) lockedObject.SetActive(true);
    }
minor gale
# crimson shadow cant figure out why my gameobject wont disable if another player walks through i...

the trigger enter event will fire for everyone who sees a player walk into it which probably isn't what you want; it looks like you're trying to unlock some object when count meets the collectible amount?

i think using what i assume is an active state bitmask is a bit overkill while you're debugging, if you know that part is working for sure then fair enough, but i'd probably go for a synced bool array to ensure it was working as intended

north thistle
#

You'll have to view it as an eventually reliable system, which tbh is probably the best way to view your networking systems in general

waxen cobalt
#

Does anyone know why Object Sync is bugged all of the sudden? Started noticing it on my props and I tested it by adding an obj sync to this random sphere. Locally the object is fine, as soon as someone else grabs it however it lags. Has anyone else encountered the same issue?

north thistle
heavy spindle
fallow mountain
#

I don't know why it isnt being interpolated tho

#

which it should

waxen cobalt
fallow mountain
#

can u post your vrc pickup in inspector?

waxen cobalt
#

I will when I get home

fallow mountain
#

do you have Allow Collision Ownership Transfer? it should be off

#

but it doesnt fully explain why

waxen cobalt
#

Yeah think that's on by default too, I'll try disabling that once I return

fallow mountain
#

but turning it off will rule out any ownership issues

#

you might also have Force Kinematic On Remote turned on by accident

waxen cobalt
#

I remember that one being off so it's probably not that

waxen cobalt
north thistle
#

if suffering is anything over 0 for the current owner of the object, everything synched they send out will be laggy

waxen cobalt
fallow mountain
#

when you open debug menu 4 how many bps does the object have?

#

or is it menu 6 I forgot

#

and what is your global Kb/s output?

waxen cobalt
#

oh wait I think I found it, around 1.700

fallow mountain
#

try menu 4 there is some numbers at top

waxen cobalt
#

its KBytes Out right?

fallow mountain
#

yea, and total output throughput is good reference, 0.5 is 50% which is what serializations are capped

young thunder
#

(possibly after appearing for other players?)

minor gale
young thunder
#

so, if the owner of an object is currently non-responsive, taking ownership and setting a value won't propagate to other users until the original owner becomes responsive again?

#

i'm unclear on how the data is moving around here

minor gale
#

this is only the case if you override OnOwnershipRequest, that explicitly requires the original owner to authorize the transfer afaik (by returning true); i don't know if there's a timeout

#

outside of that, the server just allows the transfer of ownership. you can even set ownership on other players

misty ermine
waxen cobalt
#

Yeah cuz for me the problem literally appeared out of nowhere, all I did was add new models to the world and boom the jittery suddenly became an issue

misty ermine
#

Did you update your SDK to the latest version?

waxen cobalt
#

yeah with creator companion

misty ermine
#

Yah I do so as well. I believe that's is when I noticed the issue.

#

It might be wise to uninstall the latest version and install that last one. Ill do that to see if it fixes it.

waxen cobalt
misty ermine
#

I see that...

#

Well that's frustrating.

waxen cobalt
#

I'm sure there's some explanation, we def can't be the only ones dealing with that

misty ermine
#

It happens in my other worlds as well. I still think this is a VRchat wide thing.

#

That would suck because it any world used a item or phys object it wont look great.

north thistle
misty ermine
minor gale
misty ermine
#

I just want to make cool car now it broke! Love vrchat. Hope it gets fixed soon.

#

All we can to is wait.

north thistle
misty ermine
north thistle
#

here let me load up my project where I can have over 100 object synced objects and see if anything has changed within the last day or two

young thunder
misty ermine
#

Load up a 2 client build and test you should see the jitter on remote clients.

north thistle
#

Because what you are describing is different from what that canny is describing

#

Yep... it is broken...

misty ermine
#

Well every pickup, that you want synced, uses object sync so its the same issue im just not using the pickup part.

north thistle
#

You can use player pickup without object sync if you want.

The actual issue I suspect is triggered by an object sync changing ownership.

#

Actually I have a way to test this!

#

wait... that was some unexpected results! I'm suffering at levels that were previously significantly within VRC's limits

north thistle
#

Hopefully they fix it soon because I was hoping to playtest my world with a friend tonight

brisk magnet
#

OK so I have a weird one today. I have a bug that I only see when I play my game with one of my friends in Australia. at first I thought this was a bug related to ping but science proven that is not the case. I used clumsy to bump my ping with vrchat up to 900.

and while playing with 900 ping with other people the game worked flawlessly with no bugs. if played with other NA players.

a bit about the nature of the bug itself. in my game a to make a move local client side validation is done and then the move is sent via the new beta networking calling function with parameters. The receiver then runs the exact same validation check as a redundancy. if the check is valid it accepts the move if the check fails it drops the move.

Sometimes specifically on an Australian network regardless of witch player is the sender or the receiver. the client side validation will pass. it will move to the receiver, and the receiver will get the correct data, no race conditions. no functions are firing too soon. but somehow will make the incorrect choice in the if statement even though it made the same calculation with the same parameter as the other client.

I have no clue how network conditions can change the result of an if operation but what im mainly looking for is ideas on how to reproduce it without needing a player from Australia. Any ideas to what the trigger is if not packet loss or ping the only other info I have is that the other player was also running on linux at the time.

north thistle
#

bit of a shot in the dark, but you aren't using a player's local time anywhere, are you?

minor gale
#

from a networking standpoint, if a client considers a move valid and enacts it, you shouldn't reject it on other clients at that point imo unless you wait on authorization on the initial client (more like a pending move)

don't know why it would be different, but float precision comes to mind

brisk magnet
minor gale
#

i really think you should consider running all the moves through a central source (like the master) if that's the case

brisk magnet
minor gale
#

i thought you were describing something where Client A enacts a valid move, but Client B rejects it, leading to desync?

#

unless you have Client A revert the move

north thistle
#

Did you try your game with the other settings on clumsy enabled? Mainly the "Drop" one although the "out of order" and "duplicate" ones might also be worth it.

brisk magnet
#

well in my senario one of those two clients is the owner of the game. and the other is just a player

#

but even when the owenr is making moves it follows the same structure for consistancy it just sends the request to itself

minor gale
#

oh so you make the request to the owner and they adjust the game state?

brisk magnet
#

exactly and then the owener seralizes it back to everyone

#

so this is a log from when I caught the bug in action

#

and ill paste some relavant code in a sec

#

this is the one thats returning false when it should not those extra logs at the bottom are not present in the above screenshot I added them after the fact so I can get a clearer view the next time I see the bug

#

when it says card played 14 4

14 refers to the calculated value of the card and 3 refers to the suit diamonds in this case

#

the log card not accepted would run if the above function returns false essentialy. and right after that it prints the values of what went into the function

minor gale
#

is the suit an enum?

brisk magnet
#

yes

#

and as a reminder this is a case where 1 client got true and another client got false runing the same check

north thistle
#

Are you making sure that every single value you receive from the networked event/sync is correct, even those derived indirectly?

minor gale
#

it's hard to tell without seeing where you deserialize* the data to the resulting card i think

brisk magnet
minor gale
#

it occurs before you get the data? sorry i should clarify, i didn't mean OnDeserialization, i meant where you get the synced data over the event and construct the card

brisk magnet
#

this is where the request gets sent

#

this is where the owner gets it

#

ive collapsed a non relavent if statment that we do not traverse though when we are going down the bugged route

minor gale
#

i think i'd use and pass them as ints instead of bytes while debugging

this casting makes me uncertain, but i can't tell

brisk magnet
#

I dont think any of us will figure this out unless we find out what the reproduction conditions are. I know if we were to play it right now the chances of us hitting this bug are close to none. but when I play with my friend from austrailia its garenteed to occur about 80% of the time.

Id like to focus on how to cause it so I can farm more data to learn how to fix it

minor gale
#

are you sure they aren't just making a move as a remote client without the correct picture of the game state? you were describing using clumsy to inflate your latency, but if you were the owner you would never reject your own moves

brisk magnet
#

I thought about the casting but logs confirmed both clients casted the same ressult and got differant answers anyway

brisk magnet
#

I have a feeling it has somthing to do with the network calling system specificaly. beacuse before I had a differant method to do the same thing. and this same player was testing for me back then too. we never had this issue. but there were many others

#

Id would most like to know the netowrk conditions nessisary for the bug so I can more freely reproduce it and adjust logging to get the info I need

#

but as it stands right now I cant reproduce the bug whenever that player is not around. so I litteraly cant even test if ive fixed it or not. thats why Im more intrested in reproducing it rather then fixing it right now

minor gale
#

do you know that the move they made was valid at the time of the owner receiving the event?

brisk magnet
#

yea they sent me their logs. and I also expeerianced the bug from both positions

minor gale
#

but from the owner's perspective

#

their move could be valid but behind by latency if a game state update was in flight

brisk magnet
#

yes I played several rounds from the owners perspective and several from the clients perspective

brisk magnet
#

its the owner that makes the wrong decsion

minor gale
#

i'm saying if some client makes a move they believe to be valid, but the owner receives an update or changes the game state before that request hits them, the requested move may no longer be valid; which sounds like what your system is meant to stop, but i'm probably misunderstanding if you're saying it's acting counter to that

brisk magnet
#

like let me give you an example

#

lets say the defender has 1 slot remaining

#

and there are 3 players who all have cards that can fit in that slot. only one of them will be able to place their card

#

so if player a clicks and the 0.1 secconds later player B trys to click they may have not gotten the packets from player a's move yet so they will still think theres room left

#

but this is a case where that clearly did not happen

#

but like I said right now a solution means nothing without a means to reproduce as theres no way to test the solution otherwise

#

Can anyone think of what characteristic an aussie network might have talking to an NA network, other then ping or packet loss that I might be able to artificualy create?

#

again was unable to reproduce the bug with 900 ping and 70% packet loss. so its not beacuse the code is sensitive to those

fallow mountain
#

was the owner accidently set somewhere else in the project?
is there any checks or loops anywhere that happens at a certain delay or frequency in the project?

brisk magnet
fallow mountain
#

all this lag related issue points to something is being done wrong at a specific time

#

so finding "time" will narrow things down

brisk magnet
#

ive allready tested the arival time and execution time of all the functions everything is happening at the correct times. Ive added more logs that would help me better understand where its going wrong but. I don't know how to reproduce the bug. is the main issue.

I dont think there's enough data to understand the issue yet. I intialy thought it was a timing issue however disrupting the timing of events seems to lead to correct execution regardless so thats led me to rule out timing as an issue

#

if I shoot the ping up to 900 the code will correctly wait before proceeding

fallow mountain
#

(what was the original issue? i have goldfish memory, like gpt)

brisk magnet
# fallow mountain (what was the original issue? i have goldfish memory, like gpt)

i have one play tester who plays on linux and is in australia. during my last test with him we descovered a bug that only happens if he is in the game.

If he is in the game it happens to all players regardless of who the owner of the table is.
if he is out of the game the bug does not occur
the bug only occurs when a non owner makes a move
the offending code is running on the owners machine

the bug is as follows

non owner preforms a validation check, it passes correctly, the owner then gets all data exactly as it should, then runs the exact same validation check but gets a differant result from the client despite preforming a seemingly identical calculation.

#

again the reason for two validation checks is somtimes the non owner can have a slightly out of date view but this test case is a reccorded case of the client having the correct up to date view at the time of pasing validation

#

other side notes I have a suspsion there is somthing happening under the hood with the network calling. as this bug emerged after introducing it to the system. but I cannot prove or disprove this. I am seeking to find the conditions that make this bug possible

#

I might just have to wait for that particular tester to become available again to collect more data

young thunder
#

this is some serious "500 mile email" weirdness

brisk magnet
#

yea my project is rather large and i regularly find and fix bugs quite often im fixing 4 other less serious ones as we speak. I only come in here mainly for the real big wtf ones XD

#

and I never expect to find an answer but somtimes somone says somthing that leads me to look at it another way

fallow mountain
#

did u check if this was null?

brisk magnet
#

no but if it was null we would crash when we try to do anything with the DurakPlayerV2 Object

#

I welcome and encourage you to keep speculating down that line. but evan if you landed on the correct reason. we would be unable to varify if we cant steadily reproduce the issue. we would litteraly have no idea if the fix worked or not

fallow mountain
#

so this is the difference?

brisk magnet
#

yes thats the one value that ends up opsite from what it should be

#

everything else including the values that go into getting that ressult are correct

#

basically what seems to be happening is a weird situation where 2 + 2 = 7 somtimes (as an analogy)

fallow mountain
#

lets back trace it... i can see this being set to false, where does it get set to true?

brisk magnet
brisk magnet
#

however weather its line 30 that is returning false is unknown to me at this time

#

I would like to add a log there and check but again I dont know the network conditions required for this to happen

#

if we ignore line 30 all the other numbers should pass all the other checks.

so there are two posiblities. theres a weird network state that causes the owner to do wrong math. or there is a weird network state that causes the owner to have a more out of date view of the value on line 30.

both posbilites seem very unlikely to me yet theres no evidence for anything else yet

fallow mountain
#

is arkCards synced?

brisk magnet
#

and cards is totaly static never changes set at build time

young thunder
#

i don't see a variable named cards in that screnshot; are you talking about atkCards?

brisk magnet
young thunder
#

oh, there it is

brisk magnet
#

cards[atkcards[target]]

#

atkcards is just an array storing indexes that point to a card in cards

fallow mountain
#

how and when is atkCards synced? I mean that seems to be the variable that can be different

brisk magnet
#

the failure point is on the owner side validation

#

so the serlization shouldint be part of this problem. as its doing its job correctly

fallow mountain
#

why would owner fail validation?

brisk magnet
#

in a normal case. maybe the clients view was out of date and made a wrong calculation

#

so in that case the clients paramaters would differ from the owners

#

but this is a case where they agreed but still got a differant validation ressult

fallow mountain
#

I can see other parameters being send (as part of the event parameters) but I dont see atkCards being sent

brisk magnet
#

they dont need to be sent as they are exlusivly managed by the owner the client can has read only acsess

#

atk cards represent cards being placed againts the defenender.

as a defender you need to beat them one at a time

#

so lets say theres 3 cards infront of me so atkcards might look like [20,15,7]

#

and I want to play the card 2 againts that 20

#

so my request would send

2, 0, true

#

2 for card ID that I am playing

#

0 for index in atkcards to fight againts

#

and true to say it should be beating the card and not attemping a transfer (another mechanic we dont need to talk about for this bug)

fallow mountain
#

the only difference in that code that can produce a different cardAccepted is atkCards, as far as i can see

brisk magnet
#

but if there was anything wrong with atkcards there would be way bigger script crash level issues

#

this is basicly the operation that is happening

#

if atk cards was wrong on ither end then we wouldint even get correct card textures showing

#

this screenshot is the game working as intended in the case of the bug the card wouldint be able to be played