#udon-networking
1 messages · Page 13 of 1
Network Ownership is a 5 way handshake with all players and I can't be requesting a new owner for every shot that gets fired between 20 players and 50+ enemies. This is the most performant alternative to resort to using SendCustomNetworkEvent over attempting to rapidly update a variable from local only projectiles.
I don't know what you mean by tower.
your litterly creating a tower. cannon whatever it is
what exactly are you trying to make even?
The result is a unique cannon and damage method for each combo of cannon and damage.
what exactly are you making? or trying to do. each cannon is what? and what do they do to a player?
The hit enemy basically calls the corresponding function to relay how much damage it has taken and how much enmity that player must now have for that enemy.
you dont need to do any of that. what you are trying to do is well odd. you never change ownership of a projectile.
as everything else is
The enemy being hit needs to share over the network that it was hit with how hard and by who.
for what purpose?
if you hit an enemy it just needs to locally know it has been hit. and update it based on that
HP and Enmity for each cannon/player
That won't work if multiple players are shooting it and needs to respect that its been hit by each. With projectiles being local only, I don't need to sync projectiles. Projectiles will not be accurate anyway given latency, which would cause desync if I tried relying on them. It must be shared via SendCustomNetworkEvent when the local player has managed to have a projectile from their cannon hit the enemy.
it will work. if you update it when you locally hit it. just update the Hp of that enemy. based on that you dont need to update projectiles or show other peoples projectiles.
also no games ever sync projectiles. its based on various hit scans and other methods
You can't tell if other players hit the enemy in that case.
Yep, this is accounting for that.
Basically it boils down to an enemy being hit.
I hit the enemy with my local projectile, now the enemy must relay to other players that I hit it, both with how hard I hit it and that it was me who hit it.
yes you can... you update it.. SendCustomNetworkEvent. that it was hit
That's exactly what I'm doing ^.^
SendCustomNetworkEvent cannot contain arguments, so that means there muat be a unique named method for each combination. This script generates those.
I'm looking for something that doesn't have to generate a new script with these via a string and duplicating compiles.
Like this is super cursed and I deeply wish for a better solution.
While it works reliably, I wish no package to ever include it.
there is no need for that either.
you just need to update it locally. and whenever a change happens to something make sure to sendcustomnetwork event
That's what I'm already doing.
That's why unique methods for SendCustomNetworkEvent is necessary.
its not..
again
that many methods is extreamly bad and not going to work in the end. it only clutters everything and most likely will overload udon.
It works and keeps 90fps in VRChat with 30+ people
That's 20 people shooting cannons that may be the same target.
These aren't one hit kills
I'd use synced variables if they weren't as costly or prohibitive via needing a change in ownership
that just shows me its one person and locally.
It's the recording I have on hand, I can share the world id for you.
it will never work in an actual online setting.
a cannon does not need to know how many times its hit or who. all it should be concerned about is when it gets damaged to share its health to everyone else.
It does
I think you're misunderstanding given how you formed that sentence.
no
what is Enmity
Enmity is a priority list of who the enemy needs to target.
and thats based on what
Based on who has damaged it and by how much.
Each shot isn't strictly 1 damage. There's 4 values of damage that it could be hit by.
that can still be done locally. you just check against a threshold that type of an npc has. when X has dealt enough dmg to go over the threshold send out to everyone else who the new target it and they will target that person
If I use just one single SendCustomNetworkEvent, how will I manage to share what value of damage it should take and who is doing the damage?
that doesnt matter. you check that locally.
when someone locally has done enough damage
if someone else has done locally that much dmg it would switch to that person
If I'm not tracking other players hitting the enemy, how will I know they hit it?
locally.
you just make sure that each npc is the same across all people in the world.
I love what you're promising and I trust that you're heading in a good direction, I'm just struggling to follow.
What you seem to be reaching is using a race condition?
sorry i am not always good at explaning lol.
imagine you have 4 players okay?
and lets say 32 npcs
you start the round and let them do what they need to by it shooting a player or something else.
lets say all 4 players shoot a different npc each
and say that player 3 has done enough damage to a single npc to meet the threshold
then that npc sends out a networked event to everyone else that it and every other npc is now targetting player 3
Right!
you just need a single string or a int. that is UdonSynced
Who is updating the synced variable in that case?
and check against that against a list of players in the world to find the proper target
the local person
who dealt the dmg
That means changing network ownership is necessary.
well everything in a world is by default owned by the first person in the world.
Yes ^.^
That's a 5 way all player network call each time it needs to be updated.
That's way more expensive than using a SendCustomNetworkEvent
Ah!
everyone else gets updated based on whatever that local person updates it with
So SendCustomNetworkEvent is a relay to the owner to update the synced variable. I've done that before.
you can target Owner or all
Yep
the local npc targets you. the owner. which then sends out to everyone else what needs to be updated
That checks.
and every other person then updates it based on it
you can also try to use https://github.com/Miner28/NetworkedEventCaller which i am using. it works quite well but has a upfront cost sadly
How do I tell the Network Owner how much damage I did and that I'm the one who hit the enemy? As is SendCustomNetworkEvent is anonymous.
that one allows to use parameters
locally you do that. its all known locally only until you tell it otherwise
since u techincally dont need to know how much dmg someone else did . unless you want to track that to.
but that might not be possible with vrc
That means the Enmity list can't be facilitated then.
If I'm the network owner, get the SendCustomNetworkEvent, how will I know how much damage to sync and who shot it?
I do, that's why generating functions for SendCustomNetworkEvent was the goal.
if you want to keep the health updated for each npc you will run into a limit of vrc.
we can only do roughly 200 bytes continuously which isnt that much
and roughly 11 kb a second
but i suggest you try to use the thing i linked above
There's a lot to digest looking at the code.
This is why I leaned on SendCustomNetworkEvent as it seemed to be the least taxing on network traffic.
Was a best guess essentially.
Compared to a byte for Health and more, seemed to be worthwhile to minimize network traffic as much as possible given how rapid enemies could be hit with a lot of players.
Changing Network Ownership > Updating a Synced Variable > SendCustomNetworkEvent
You dont require ownership to SendCustomNetworkEvents
Network event callers works nicely if you index every npc and simply sync the index and damage parameter, then apply it on every client
Afaik it has also been optimized to reduce as little bandwidth as possible
That's another great idea tbh.
Its what im doing in zombie survival
My thought was that even updating a variable was more costly than SendCustomNetworkEvent.
I do imagine that would be more accurate and less prone to desync.
Dont over optimize, too much, only where it really matters
That's why I didn't care too much about desyncing. Just a best effort.
And thats mostly the world geometry itself
Hmm, i think changing ownership constantly has its own downside, especially if you sync positions too
I agree. I'm not changing network owner and just updating the health and target essentially. There's an enmity list I keep local only.
The current target just pulls from the network owners local enmity list.
Logically, the player in the instance the longest should be the most accurate anyway.
The Network Owner gets the SendCustomNetworkEvent, and then updates everyone else ideally.
Takes what would have been a 6 step network handshake and lowers it to 2.
Hmm interesting! Though youd need to create a new method for every damage variable
But if you only have a few, i suppose it should be fine
you do not need to create a new method what so ever.
Desync aside, this is all besides the point. The topic was side barred to what I was originally asking here. I'm still looking to automate script generation for SendCustomNetworkEvent until I can wrap my head around a better solution.
I'm thankful for HostileLogOut's effort and I'll be learning more about that NetworkedEventCaller in the meantime.
I was assuming the use of SendCustomNetworkEvent
I want to agree with you, but what you've described thus far isn't a full picture.
It does make me want to go back to the drawing board and see where I could rely on UdonSync more, but that isn't feasible in the case of what I originally asked.
I know I can use UdonSync more and have practice in that. I'm hoping to reduce the network handshakes from 2 to 1.
even with that its totally possible. but there is so much to explain to make that work. and honestly i dont have the time sadly to do so since i am working on my own stuff atm
SendCustomNetworkEvent = 1 handshake
Updating an UdonSync Variable = 1 handshake
Changing Network Owner = 5 handshakes
Very understandable ^.^
I suppose you could sync the weapon id, and set the damage locally, but still have to deal with delays, for a technically better solution, assuming no use of network event caller, only SendCustomNetworkEvent, youd create new methods for each damage, of course this is incedibly cursed, but the shooter could send out the exact damage they dealt
You're spot on to what this is all about! lol
This is the cursed automation in question.
dunno, but ive heard of people create python scripts for those
Thats even worse I'd imagine lol
but keep in mind, more public methods, create more look up time in udon
Right. Another cursed alternative that provides two variables still, explicit deny on RequestOwnership with further scripting. Not humoring that though since it understandably generates network garbage.
Really just need a simple argument in SendCustomNetworkEvent
Would make this far more reliable and avoid this discussion entirely.
I do think Udon 2 has a solution though. Native Player Networked Objects would give us a proxy we could use.
Absolutely can't imagine there'd be a better alternative and makes arguments in SendCustomNetworkEvent moot. Just sync variables that the player already owns and relay that to the targets.
I do think that's what HostileLogOut was building up to, but no use of SendCustomNetworkEvent is needed in this case, keeping the handshakes to 1.
Super hyped for Udon 2 since this will be rendered obsolete for what will be made native.
my health system for my NPC works entirely different lol
I base it off D&D where the DM is the owner of the NPC and keeps track of damage. but in an action cycle kind of way.
can someone help me pls. i want to make it so this "punisher" mesh spawns on the for every person who joins my world but its not tracking the player. It's spawning i a clone but not tracking
Instantiated objects can’t be synced over the network
That might be your issue here
instead using the Instantiate, VRC object pool would be better for that I think
It doesn't need to be synced, and it doesn't need to be in a pool. Instantiating is the correct plan if you want to be able to see other people's, but those nodes are just not properly handling it
create all the necessory objects in the editor. assign them locally to each person when they join and store the VrcPlayerApi to the local person that join for each local person.
@frozen igloo btw i dont assume there is a way to have the data sync that happens when someone rejoins to be disabled? so you can handle it yourself instead? or is it possible to overwrite it?
what do you suggest i replace, i was hoping for everyone to be able to see the punisher mesh attached to each player globally
would this make it so everyone can see the object on other players, if so whatshould i replace?
what should i use instead?
for everyone to see the punisher on each playe gobally
Oof ima wait for phase cuz I’ve no clue tbh, I don’t read graph very well
just assign a object to the joined player. and update it locally. based on where the other player is
i managed to achieve that in other script actually the only issue was other player couldn't see it. do u know how i can make it so everyone can see it
precreate all objects in the editor in unity.
each player then should have a array of those objects. and when someone join. then get the array of VrcPlayerApis. and assign the objects based on the order that has.
then you can locally for each person update your their local objects position to where they are
oh and remember to set Network.setowner for each object to that person to
i'm very sorry, i am a bit new to vrc world creation so i am a littl confused of 2 points. When u say pre create them, i assume u mean have the prefab of the object ready in the hierarchy ? Also For the player Api's, do i directly assign it to the object? Sorry if i missed it coding can be a little hard for me
eh yea. you just Create a 3d cube in the editor. and copy it til you hit the desired amount
also if you need to learn how to code you may need to look up some tutorials on youtube @random breach
no yeah i definitly know the basics but the only think i was struggling with is which node makes, the object that spawns on each player, global so everyone can see.
it was local when i made the correct code
thats because you either did not have a object for that other person and you prob did not set the ownership that that object to the other person.
does this look right for everyone to be able to see the object globally?
no. cause u only update local. u need to update the non local person
which u can get through who owns it
ohhhhh ok so which networking node is for non local players ^_^
Should I avoid setting synced variables on an object if the player is not the owner of said object? As in should I instead rely on the deserialization logic?
you cannot set any synced variables on object you dont own, be it continuous or serialization.
Good to know, I was under the impression that the variable would just be set locally until the next deserialization occurred
I've been reading the docs, and I'm a little confused about preserialization
In the past I've made local sliders that update the value of a separate material with a single manual synced float. Only the master could use the sliders, and I didn't use preserialization, just manual sync, request serialization and ondeserialization.
On this new setup, I'd like to have a single trigger that pulls all the slider positions of the master, updates a bunch of floats based on that, syncs them to everyone else, and updates materials based on the floats. Which step of that would I want to use preserialization on?
If you want to make it so you see objects floating over everybody else's head, then what I would recommend is this:
Create two datalists: one for tracking all players and one for tracking all objects
OnPlayerJoin
- Add player that joined to the player list
- Instantiate an object from a template
- Add that object to the object list
OnPlayerLeft
- Find that player's index in the player list
- Remove that player from the player list
- Use that index to find the associated object in the list
- Destroy that object
- RemoveAt that index in the object list
Update
- Use a for loop to go through both lists at the same time
- For each item in the list, set the object to the player's position
Let me know if you have any specific questions about how to do any of these steps
You are correct, that is what happens. Technically there's nothing stopping you from doing it, but it is quite messy. Usually if you need to have some kind of local cache that can differ from the synced data, you'd be able to handle it much better if you had those be two separate variables. Then when a serialization comes in, you can compare the synced data with the cached data and decide how to handle the disagreement
Thanks for the context! My main reason for setting the variable locally was to make things ever so slightly more "realtime" by avoiding the latency between the event hitting the owner, the owner setting the variable, and the owner sending that update to everyone else. But tbh I'd rather just do things the simpler way and take the latency than make VRC network handling even more complicated
if it's a really simple system where you always want the incoming data to override your local state with no additional considerations, yeah go for it
OnPreSerialization is just saying "I am about to send data" which means it's your last chance to grab the latest data or package it into some format you want. You don't need to use OnPreSerialization, the alternative is just grabbing that data at the same time as you do requestserialization. One reason you might want to use OnPreSerialization for that is if grabbing data is kind of expensive and you're doing requestserialization a lot, so you don't want to cause a bunch of hitches every time you might send data, only cause a single small hitch when you actually send data
Preserialization is great for scripts that grab variables from other scripts when activated.
Like packing things into a neat box for the postman.
I then use PostSerialization (only executes for the owner of the object) and Deserialization so things execute on clients "at the same time"
omg dragon 🥺 🌺 Thanks for the explanation ❤️ you too pika~ I didn't know about post~
So my flow should be more like:
**Interact **-> request serialization
preserialization -> get variables from sliders and set the new synced floats
on deserialization -> set materials to match variables
postserialization -> Same chain as on deserialization
If you don't have a strong reason to, you don't need to use onpreserialization. Could just set synced floats inside the interact.
Also, you don't need postserialization, that is simply a confirmation that things have been sent. It's like a receipt and only the sender gets it. So similarly, you could just set the materials to match the sliders directly in the interact as well.
Or, alternatively, I like to have an "ApplySerialization" function, which is not an official thing, it's just a name for a custom event. In that function is where I'd set the materials to match the variables. Then you can call that function both from the interact and from ondeserialization, and everyone will run the same code all in one place
So I have an udon script that is supposed to steal ownership of an object. Now two players can steal ownership from each other rather quickly (within a fraction of a second). I've found that after stealing ownership from each other several times (i think around 8 times) the ownership breaks down and both players becomes owns of the object (so it becomes a local object) and ownership can no longer be taken because any attempts to take ownership are ignored with the following message "Ignoring TrySetOwner attempt on [GameObject] because [playerName] already owner". Has anyone else experienced this issue?
sadly it can happen. you have to put in a delay for it. so its not spammed and you can also just ensure that its not the owner by checking if its the owner or not before u well change ownership
unfortunately i don't think i can add a delay because being able to take ownership quickly is a crucial part of the behavior i want to emulate. I do my own check to see if the player is the owner before taking ownership, however it also appears the the SDK also does this check as well because it gives me the message about ignoring TrySetOwner (in my previous post). I think the best i can maybe do is bank on a third player coming by and stealing ownership from the other players if such a situation ever occurs, and also give a warning that such a thing can happen.
Is it critical to take ownership quickly, or is it just critical to send data quickly? Perhaps you might get better results when the two people have their own separate objects which they own, and then the data can be combined into one thing
it is critical to take ownership quickly. The behavior i'm trying to emulate is a weeping angel kind of behavior where the object can move and hunt down players that have looked at the object. The last player to look at the object is the player that gets chased so it is critical for that player to have ownership of the object and receive the most accurate/up-to-date position. The situation where ownership becomes a problem is when two players are looking at the object and one player (lets say player A) rapidly looks away and then back at the object. In this scenario Player B (who is still looking at the object) becomese the target/owner of the object, and then Player A becomes the new target/owner when they look back at the object.
I'm going to suggest that folks endeavor to create test projects and/or game objects that can be used to test these sorts of networking things. I see questions similar to this but never (I believe) see any definitive answers. If there are limits (and there are) then a test system that a) demonstrated it, be) could be tested by others and c) used as a basis for workaround solutions would seemingly be useful.
Whether a solution works (or not) or works well can depend upon a lot of factors, not the least of which is the code being used. Doesn't it sound reasonable to develop these types of standardized test systems?
Have you tried adding a delay? Make them look away for a bit before you change ownership.
Otherwise yeah, I'd agree to use player owned objects and then use everyone's is looking states to resolve the weeping angel state
Hey how do make it so a bunch of different triggers change an int in an animator? I tried this but its not working? the whole thing im trying is having different parts of my world teleport a tv to it using an int animator (im new so anything would be great!)
I looks fine to me. Except that you set the value to 1 in both enter and exit.
Did you set your states up correctly in the animator? I also don't think it's the best approach to teleport objects with an animator, you could just keep a list of transforms of the teleportation locations, and you could set the object position and rotation by script
this is how your animator should look like
Im changing the way i didd the animator
yeah thats what i mean by teleport. I made a bunch of animations of the tv moving from location 1 to 2 and another 1 to 3
Gonna try your animator now
is there way make world Udon script where visitors cant join or put any rank visitor or below in jail room by default?
no, you can’t access info about players through udon
and that sounds like it would be against TOS anyway
that's sad because that would solve crashers problem if Vrchat only take note from my request to add group shields us the did for avatars the can do it for group instances edit ranks that can join 😑
You'd be better of setting your Safety settings so that it doesn't show the avatars of Visitor rank users
that dont help clients can crash you even if you in safe mod
and banning them dont help the can always make new account so i have to always ban any one that got visitor rank every time my group ban list getting big lol
I’ve never been crashed by a robot avatar… what
all the need join lobby and crash every one in that world
happen to me many times
or brakes world colliders and no one can click on any one
Moderating inside of a world through Udon is only allowed in specific cases see: https://hello.vrchat.com/creator-guidelines under "Worlds"
The most important point being that you are only allowed to "Apply a moderation to a user that is misbehaving in that given instance"
If you have problems with a user like that, then I recommend opening a ticket with the VRChat Trust & Safety team and not try to take matters into your own hands
Also this is the wrong channel for discussions like this...just fyi
So ive made plenty of worlds in past but im just looking into a whole new segment of networking and NPC's, trying to start basic with statcis NPC's heads tracking a player in proximity, anyone tackled this before or have some insight?
Oh? Super! please enlighten me to it, im struggling to find any major source on the matter, and my tests have been less then succesful
ok, first things first, what do you want to achieve?
so my want atleast currently is to have npcs look at the player within a vicinity, i have them all animated as i have 6 around a world but to add some interactivity im wanting them to look at a player if they get close, local ofc
So players will see the NPC looking at them, but not NPC looking at others, correct?
Mhm, i think it would suit better in this case
The code for that is this simple.
ok, so, obviously there is a threashold that players will cross, or get near, where there is a boolean flipped that will allow all this to happen.
you want a aim constraint on the headbone of the NPC, and you want to use the GetBonePosition of the head bone on VRCPlayerAPI
and have that be a target of the aim constraint.
This is your LERP that will adjust the time from 0 - 1 and then back to 1 - 0 this will allow you to set the weight of the aim constraint between look at the target to default neutral.
from there it's just setting wieght
All of this you want to make sure it's run on POSTLATEUPDATE because that is after when the IK solver has been executed on vrchat.
I admit im regretting my choice here, ahh its been too long since i touched udon.
though by looking through this is a much more interesting method, i was using an idea of adding a look at constraint on the npc and using a get.postion of a player to activated based on a local collision or radius, but this seems far more accurate, not that i fully understand it admittedly
This is a method of having the NPC turn their heads toward a player and look at them in the eyes. Then turn their heads away when done.
if you want your NPC's to follow the player, reguardless where they are in the map, you can go with your method.
there is a second part of this code, that checks for distance between the NPC and player, and also checks for angle difference betwen neck and head bone, that will issue the exit command when a threadshold is reached. This prevents heads from spinning 360
I think your method is far superior here, and moderatly less terrifying, i dont suppose by chance you have a slightly clearer pciture of the left half do you? i cant fully read which some are for reference apologies!
or by sheer chance if youd be up for helping guide me through this crash course on hand XD
🙏 thank you so much there!
Here is the additional code that checks for distance and angle to switch off the aim constraint if a threashold is crossed.
it needs to be on update for some reason. It has to do with reading transforms in unity
strange indeed 
well for my rather small knowledge on all this, alot of these must be variables with custom names to help differentiate their use and context through the graph, I think i can can do this..staying positive
a tricky "Gotcha" trick with Constraints is that you have to set transform that is going to be looked at as a constraint source, THEN set it as a constraint source on the aim constraint. THEN set the weigth of that constraint source. It has to be in that order.
im glad your doing local only cause getting other players to see NPC looking at other players is a WHOOOLLLEE other bag of worms
This already is a massive bag of worms pika....like dear god ive made a mistake in wanting to try this
this is currently putting my brain on meltdown mode
haha...yeah...

this is rather simple compared to...uh.... getting players to see NPC looking at other players...
nah, i lie, that is just the code for "NPC to navigate to pickup object that has been thrown and interact with it."
🤔 I should make a wall.... in my world that has all the scripts layed out...
that would be helpful definitly, also I saw, thats quite a feat indeed! clearly an expert in udon at this point lol
Code for "Animation Root Motion Drives the motion of the NavMeshAgent of the NPC"
and once more, i think my brain just poofed
yep, im already part way lost in the graphing, ah i have much to learn on this
The animator actually has some baked in IK stuff, at least for humanoid rigs. You can call Animator.SetLookAtPosition so it looks at a position and then Animator.SetLookAtWeight to even adjust how much of the body follows with the head or what the constraints should be.
@sinful mango if you are more familiar with text based coding you can do that.
@obtuse echo wait....wut?
There is even some arm and leg IK methods too.
hrrrrmmm???!! 👀
Oh im not familiar with that at all XD
im just trying to work out what some parts are if there variable or things i have to separately connect and add
@obtuse echo is this used in conjunction with blending layers in the animator?
@sinful mango yeah that feeling never quite goes away. That's why it's fun, its a giant puzzle to solve.
This puzzle is beyond me, but..if i get this figured ill be able to get it all working im sure in the end
Kinda? I don't remember if you have to do anything special for it work or not. Oh, you might need to call those methods inside of OnAnimatorIK (it's an event like Update)
Ahh its killing me, what are the Set isNotActive and Set isActive? im assuming a few are there like it but i cant figure it out
@sinful mango when isActive is true, it will lerp the TimeElapsed from 0 - 1 when set active is false it will lerp from 1 - 0
When isActive and isNOTExiting is both set to false. The unarynegation makes them both true, so the logic AND will only output true if both inputs are true. that allows the "gate" to be open to check when the AimConstraint weight is 0. when that happens it proceeds to the exit code.
Logial AND works like this:
false + false = False
False + true = False
True + Flase = False
True + True = True.
Booleans are like minecraft redstone. if you disregaurd the strength of a signal.
Hmm, I meant just to add them in, in the search function for now, im no where near the ending parts, the rest i think i can find
like this is all i have so far in recreation, trying to add onto the "Is Valid"
yeah the "isValid" is only there for my script so it doesn't crash if the player being looked at leaves the world while they are being targeted.
because your script is only for local. It shouldn't be an issue.
That makes sense then, though how am i actually adding them? since those nameings dont exist i assume there custom? back with the "IsActive and IsNot existing" since im trying to follow the code as Im honestly still at a loss with this, it could be just not getting it or misunderstanding here im not sure since searching for them they didnt appear
ah forget it i think im jsut realising now XD oh lord, a whole learnign curve here, apologies i got it
you have nothing to appologize for, this is all part of learning.
lets take a few step back. Do you know about different data classes?
like booleans, floats, integers, and that stuff
@sinful mango
Yeah ive got some general understanding, ive had the vrc creators guide up too incase, but I realise its the whole aspect of points ahead beign called back further, just took a moment to realise, though no doubt ill find something im clueless towards after, this is still the first section afterall, i havent even applied anything to the npc or player yet
yeah, most of the reasources i've been using have been unity scripting API, Microsoft C# documentation, VRC documentation for specifically VRC related stuff, and ChatGPT to bounce ideas and learn syntaxing off of.
the two booleans in my code is to prevent the code from executing all the time when it not needed.
Definitely well practiced and delved into it then XD, ah can't say he same for me, ive had some udon graph use for teleporting and object spawns etc the normal stuff, trying to expand into newer stuff
I think my next goal would be dialogue appearing but have it randomised
@sinful mango yeah I haven't touched dialog yet. that's a whole thing of like... combining strings? perhaps? Idk.
I have a few potential ideas to try but it's a far concept currently lol.
Also with this headtracking system will it break any pre existing animations ive done on heads or will it exclude them while it looks at a player and return when a players out of range?
Oh for here, where are you getting the OnExit naming? is that a custom event or variable?, i havent seen a normal function that isnt a collision based one
thats a custom event
@cerulean zealot getting other people to see a npc look at someone else is pretty easy and fast. can be done with 2-3 lines of code
it's just more code to handle turning off the script
@finite sierra you gotta isolate who is making that call and to who it is going to look at.
well u dont even need to do that.
yep thats easily done if have have a object owned by a player that the npc is looking at
there are a million ways to do anything.
Finally i think the first section is done
out of curiosity here, how do i add a getbone to the VRCPlayerAPI?
im managing to work out the most part of this, but applying in the scene is the next step
The only odd steps to use Unity's IK are that you have to enable "IK Pass" in the animator controller. And the script with OnAnimatorIk has to be on the same object as the Animator. I wrote a head look script that looks at the player when they're in vision range. (Also I could translate to graph if this U# is hard to read)
do i apply this in the same graph as the previous stuff or a whole new one btw?
@sinful mango afk will reply. L tr
@sinful mango so this is where the nuances of programing and code start to come into play. with @cedar crescent offering their solution, and im offering my solution to the same problem.
The code I presented is something I came up with, and it works for my project because it's a small part in a MUCH larger system. Vavassor solution works because it's just focusing on "head tracking player head"
Vavassor and My solution are not compatible with eachother though.
I see I see, so to a fine point it really comes down to a whole factor of trial and error too, based upon the circumstances of use and application, atleast how im seeing it
exactly! everyone comes up with their own solutions to fit their needs.
now, i'll be honest, there are people here that know a lot more than I do when it comes to this stuff.
Ah well theres always bound to be someone who'll know something to a deeper level, though in the case of my testing, ive got more work to do in making it function clearly lol
though its admittedly nice trying something new despite the challange it is
lol, I find it fun that the challenge never ends. I have a cow that stops suddenly, and doesn't navigate to where it needs to be for some people and im trying to dig through my code to find out why
Also my solution only works on humanoid rigs because Unity's IK doesn't support generic rigs.
There's a third solution I've also done. Which is to manually update the bone position/rotations using U# in LateUpdate. LateUpdate is after all animator stuff is updated. So this method overrides whatever the animator is doing. It's a little more math. I only did this because I already needed to manually modify bones for other reasons.
ah lucky in my case to a degree, since ive done a ton of animations ive had to switch to generic rigs, plus i find its working a little better but future tests could prove otherwise.
though so far granted most my work has been remaking the graphs, the npc im testing just staresblankly in a direction which, is definitly interesting, like its unable to locate the player, but issues for tomorrow lol
my solution requires to manually find the bone and axis that you are going to aim at the target becasue I work with so many generic rigs.
yeah
guess ive got work to do, but all part to the fun, gotta big brain this
hmm i am actually wondering if there is a way to tell udon not to sync something when someone rejoins. like the late joiner sync thing. but manually do it?
how about settings the udon script sync mode to manual? and when you want it to sync, you do the RequestSerialization?
but on second thought, it wouldn't be good, it would sync for everyone when you call it
no Manual still does sync atleast it does so when i check its values. which i find odd. but i am wondering if the NoVariableSync allows me to do it. and also i am using https://github.com/Miner28/NetworkedEventCaller which works really well.
it seems like the onVariableChange method gets called whenever the player joins, even if you set it to manual sync
but it's still possible, but it depends on how do you want to use it. because the owner can sync it everyone when he wants, and the local player could turn it on and off the sync easily, but if you want the owner of the object to enable and disable the sync for a specific player, that can be a lot more challenging
Why do you want this?
What are you syncing that is temporary?
@cold laurel could be useful in delivering history in batches.
What's the correct way to manually sync variables across multiple udon scripts at the same time?
do I have to run request serialization is each of them? or just one after i've run the events in each to get the synced variables where we want them?
Yep run RequestSerialization on each behaviour that has their variables changed then each behaviour will fire off its own OnPre/Deserialization events
They're not guaranteed to all happen at the same time though so coordinate changes to data accordingly
because nothing needs to be synced back unless i tell it. and also its not working with their automatic late joiner sync. it litterly breaks the world
The automatic late join sync breaking everything is quite concerning. It suggests that you're architecting the system in a fragile way.
If you describe what you actually want to do I might be able to help you.
History? Like a chat history?
Sync happens per GameObject. If you RequestSerialization(); on one script that will mark the whole GameObject for sync. If there are multiple behaviors on that GameObject then those will be synced as well. This is the reason we can't have mixed sync modes on one GameObject.
nope not fragile. taking everything into account to ensure that isnt the case.
however since i am using https://github.com/Miner28/NetworkedEventCaller it could be that one causing the issues.
I can't help you determine if you are misusing NetworkEventCaller and or normal Manual sync if you don't tell me what your goal is.
But from everything that has been stated so far it sounds like you're misunderstanding how to synchronize state in a robust way.
i am not lol? how do u even abuse it lo?
also no. because everything is fully synchronized lol. its only when you leave and rejoin. even something as simple as a button that has a inverse check on if its enable or not stays disabled. even if its suppose to be enabled.
but to give you an idea. of what i am doing. everything in the world is by default not synced by design. however there are a few things that are. one is a sync button that well syncs you to others. another thing is some Text that floats above you when you sync. and third thing is a collider that gets enabled based some rules i created that determines who can interact with who etc.
when someone leaves it breaks those things for the rejoined person.
i use no Contiounes cause its uncessory. i use manual purely
It's very easy to abuse.
As an example I'll be incorrectly syncing a bool.
public override void Interact()
{
bool currentState = gameObject.activeSelf;
SendMethodNetworked(nameof(SetEnabled), SyncTarget.All, !currentState);
}
[NetworkedMethod]
public void SetEnabled(bool enabled)
{
gameObject.SetActive(enabled);
}
That's the thing. If you sync things correctly it shouldn't break for late joiners.
And if you need special handling for late joiners, you're most likely overcomplicating something or doing it wrong.
... a collider that gets enabled based some rules i created that determines who can interact with who ...
This should be manual synced on a player object.
and it is. everything is manually synced
Without any funny business such as different logic for late joiners? Or discarding received data if it was sent too long ago?
Are you doing anything else than this?
[AddComponentMenu("")]
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class Example : UdonSharpBehaviour
{
[UdonSynced] private bool _canInteract_Synced;
private void SetCanInteract(bool canInteract)
{
if (!Networking.LocalPlayer.IsOwner(gameObject)) return;
_canInteract_Synced = canInteract;
RequestSerialization();
HandleSerialization();
}
public override void OnDeserialization() => HandleSerialization();
private void HandleSerialization()
{
Debug.Log("Can Interact: " + _canInteract_Synced);
}
}
The usual way to do this is to detect if the event is old in OnDeserialization() - you get an argument out of it that contains both send and receive time. If receiveTime - sendTime > 5 or something like that (5 seconds since value sent in this sample) you can tell it's a late joiner sync and ignore the change, if you are performing changes from within your OnDeserialization.
However, since you are using a custom RPC system/layer as you mention - Miner28's NetworkedEventCaller - you may need to modify it to support this use case. As it stands, the code appears to re-run events when late joiners join, so you need to design your systems in such a way that late joiners are properly handled, or modify the code to add a way to signal that an event should not run if the aformentioned condition (or whatever other threshold you like) returns true.
In general, by the way, I'd avoid using such systems as a blanket way to do things unless you truly understand both vrchat's networking model (including how late joiners behave) and fully understand the architecture of what you are building. Most RPC systems implemented in VRChat have certain limitations or situations where they can fall over, because it's difficult to make them truly general-purpose - even when making your own. You really need to make sure what you are using is fit for purpose, and this system you are using looks more useful for game worlds than anything - most game worlds do not deal with late joiner sync, and just lock players outside until the round ends. You absolutely can use something like this, but it's easy to misuse it if you don't fully understand its limitations.
nope not doing anything funny business
With your example of a button here, it sounds like you are either using network events, or using this system to send the flip state - this is not going to work with late joiners.
The way to do this in a late joiner-safe way is to store the state in a synced variable, and either use the FieldChangeCallback feature or OnDeserialization() to actually update its state. Any other method is ephimeral - i.e. after it's happened, every client forgets about it, so it won't be late joiner synced.
In short: NetworkedEventCaller for a toggle button will not work correctly for late joiners, or anything else that needs to be late joiner synced in a way you need to be able to depend on the behavior of.
You might want to share your affected code, itll probably make it easier to figure out the issue
^^^^^^^^
to much to share lol. i get back to u both when i get back to wanting to finding it out since its not a crucial thing atm
Omg it's per object 🤯 thanks for taking the time to reply on this ✨ super helpful 💐 will save a lot of stress on this project knowing that 🌸
I have a question about a turned based game (for example a turn based card game), it would seem like it's the correct way to do to reduce the latency for the players, but I don't really know if it's reliable, because this way I would use the SetOwner() and RequestSerialization() together. But I don't know what could be happen, what if one packet arrives faster than the other? Let's say is it possible that SetOwner executes faster than the RequestSerialization for the other player? So the RequestSerialization would be ignored? or am I overthinking the possibility that it would break?
So far, I didn't really have issues in my game, it works fine with this networking system, but I didn't test it enough in a real world scenario where people can have unstable connection
because If I think about it, it can reduce the network latency by 2 compared to if the game wouldn't change owners in every turn
You don't need to worry about that, pretty sure it's specifically done in a way where you can just set owner and immediately request serialization. You will only get issues when two players do it at the same time, but even then it usually just resolves to the ownership+request combo of one of them and not a mix.
I just remember, there was a staff member, and he told me it's not recommended to do SetOwner and RequestSerialization at the same time
That's exactly the opposite of what is usually suggested though
Never seen especially staff saying this for what it's worth.
i found it
but if I would use the onDeseralization, it would defeat the whole purpose of trying to speed up the ownership transfer
when waiting for the onDeserialization to happen, it can take up to 200ms or even more, depending on where you play
also it's more faster if the owner of the object is the one who's making the ownership transfer, otherwise, the transfer time also doubles when you would do it on the OnDeserialization if the player would request the ownership from someone else
I always just have the new owner set ownership on themselves
I can't conceptualize why I would ever need to "requestownership"
It's better to make the transfer request made by the owner, not by the non-owner, whenever possible, it reduces latency
if a non-owner wants to get an ownership of an object, they must require permission from the owner who can decide if it's grant you or not
in a turn based game and maybe in other situations, it would make sense to transfer the ownership of the actual turn owner, because the game is predictable, you know what player comes next
If you change it so P2 takes ownership when it's their turn it will be much safer.
You should have a synced int for whose turn it is.
When you receive the synced data you compare if the id matches the local player's id, if it does. Take ownership.
^yeah that's what I do
there is a deserialization that happens between ownership transfer. The new owner takes ownership
I just have to make sure that the ownership transfer doesn't happen often in my code.
its like... gated behind a state machine
if that makes sense
but that would require the non-owner to make a request to the owner to get the ownership? at that point, I'd prefer to just not transfer the ownership at all, because the latency would be same anyway
Networking.SetOwner(Networking.LocalPlayer, gameObject) happens instantly (from the local player's perspective)
@obsidian python how often are you wanting to transfer ownership on things?
every turn in my card game
but that would require the non-owner to make a request to the owner to get the ownership?
No it wouldn't.
it's unpredictable, until the player places a card
yes, usually 10+ seconds
because players too lazy to put down the cards
so I really wouldn't worry about latency then if it's under 2000ms
headpats kitkat
is it really true? so a non-owner can instantly broadcast variable sync changes even before he would get the ownership transfer?
what if the owner of the object refuses the transfer?
is just adds way more confusion to it
This is the officially endorsed and supported way to use manual sync.
private void Sync()
{
Networking.SetOwner(Networking.LocalPlayer, gameObject);
syncedVariable = newValue;
RequestSerialization();
HandleSerialization();
}
public override void OnDeserialization() => HandleSerialization();
private void HandleSerialization()
{
// Do stuff with the synced variables!
}
yeah, but I prefer to optimize things whenever possible
That whole system can be ignored if you're not using it.
yeah...but.. keep in mind, this is for a card game.
you have lots of wiggle room
a card game around the world, where the data center from you are sometimes 10 thousand kilometers away or more
If you haven't explicitly implemented an override for OnOwnershipRequest() you can simply ignore owners being able to "refuse" ownership transfer.
Because they can't in that case.
i see, it's good to know
well, that explains a lot of things, then yeah, I should use the OnDeseralization method to safely transfer ownership if it doesn't adds any more latency
Yup!
As long as you prevent players from placing cards before it's their turn you'll be fine
Hmmm that has to be a different context or some kind of misunderstanding. From my personal experience setting owner to local player and then immediately requesting serialization makes the data propagate to everyone's OnDeserialization call 100% of the time. That is the recommended way. Your example is different as you are setting the ownership for somebody else, which always caused issues for me. I haven't even tried doing that in a while so I can't speak about details and can only recommend the first way I mentioned.
^
Also seems like people gave you the example already, that's exactly what you should be doing
also, even the documentation isn't saying about that you actually own the object when the OnOwnershipTransferred happens, what can cause a little bit of confusion, but yeah, thanks a lot for explaining
it only says "ownership may change back" but it doesn't confirms that you own the object already or not
question about VRCObject Pickup and VRCObjectSync. If I have an udonscript on the same game object as the two other components, will setting that udon script to manual sync cause issues?
they work differently I think, you can have almost unlimited amount of udonscripts on a single gameobject
so they shouldn't affect each other
ah wait, but if I change the sync mode on one of them, all of them changes
i'm not sure then, but I guess, they shouldn't affect them, and even if you have manual sync, your CustomNetworkEvents would still work, just like if you pickup an object, it would use an event or something
Yes, VRCObjectSync is Continous
Well, CustomNetworkEvent does not work on objects with sync mode None.
yeah I know, I spent like an hour figuring out why someone's code isn't working, because his script syncing was set to none
but you can't use a manual syncing udon script and vrc object sync together anyway
Correct, it needs to be Continuous
@cerulean zealot if you need any help just ask! Networking can get annoying but VRC has this handy hive mind that lives here and boy do they fix all your problems
lmao
Basically the rule is that you can't have mixed sync modes on the same gameobject
dont share multiple behaviours on same object, ez
I do share multiple behaviours on same objects. But of course they are None sync. Other than than I just group them by Cont, and Manual sync.
So my agro state of my npcs were not transferring ownership.
🫠
Vrcplayerapi.getplayerbyid is not the same as index number of getallplayers
And holy love of udon..
Having someone who is more knowledgeable about udon than you to test the world is a GODDSEND 😭
me testing multi-player, I've been just relying on my friends and people I know. They don't make worlds or program, so all feed back was very basic understanding.
well considering that GetAllPlayers just gets all players and copies them to a collection. and the GetPlayerByID gets the VrcPlayer based on what ID they have. which is the PlayerID that each person gets when they join. so it should be the same as in the GetAllPlayers.
it'd be impossible for the index to be the same as id in most cases I'm pretty sure; I don't believe the ids of people who leave are reused
IDs are never reused within an instance.
If you leave and rejoin you'll get a new ID.
playerId can be a very very large number. It's always increasing.
most worlds it wouldnt go that high. and even if it did. basicly we would never hit the capacity of a single 32 bit int. and its only 4 bytes too
eh the index and id is always going to be hitting the same a couple of times. but the Index is just where something is in the collection. in case of vrchat that is. otherwise no
well if the first 3 people in a world leave and there are three people in a world, they will never match
well yea. but thats just how that is
That sounds like a challenge.
hmm? a world wont be up enough to hit 2.14billion
You'd need 256 players joining instance every each second for 15 years continuously to get to that number.
🤔 is it against TOS to test this?
Depend on how you'd do it.
I'd be surprise if you have enough resource to do it.
🥺🙏 "pwease can everyone in the world join my instance at the same time? Thank you"
And then I need 2.15 billion participants. Easy
It would need to be in one continuous instance
@cold laurel I know back in one of the first furralitys there was a gap between "click to join" and before world being initialized, where that person didn't count towards the instance. And the check if you were allowed to join was only on the "click to join" part. So the instance allowed all 400 people to join in and stack ontop of eachother.
oh dear
I’ve seen discussion around “instance restarting due to its age” I wonder if PlayerID cleanup triggers that message
In which case you’d just get the instance refreshed if you tried overloading the playerID size
As mentioned the integer max value is 2,147,483,647 and even if someone would join that instance every second of every day that would still take about 1600 years
I dont think that any instance could outlive the amount of joins needed here...
i mean, most likely instances are getting closed in a week because some value eventually overflows and devs cant be bothered to fix it. but def it is not player id.
This may sound like a broad question, but just how much better does your syncing feel when you have all players including the local player react to a change in OnDeserialization instead of changing it locally and just serializing it for other players?
Like, if you were teleporting a group of players including yourself, and you moved that process to OnDeserialization, would it actually appear that all players are teleporting at the same time, or would there still be some amount of "you teleport first, others arrive after"?
OnDeserializationdoes not run for the person that is sending the data.- No it still wouldn't match up.
The only way to do what you want is to override the remote player's positions locally.
any time :)
hmm is the VrcPlayerAPI GetPlayers a ordered array or is it not ordered based on the ID?
so im trying to get it to sync for late joiners but its not and i dunno why
oh wait i broke it up one sec lol
also how would i make this a request serlization
If you want an event to happen at the same time for all players you can try delaying the event for the local player and using OnDeserialization(DeserializationResult)'s sendTime property to sync the delay for everyone. Still even if if the teleport event triggers at the same time there is still a network delay until the local player sees the remote players' movement (it should be a bit less, though)
oh shit that's a great idea
@north thistle do you know how to fix this?
Hello,
I have to make an asset for one of my worlds, the goal is to make a tablet to manage permissions and access on the map. The first to arrive must have all the permissions and access the tablet to give the permissions to the other ( so far I manage ) but the problem is that when he gives the permissions to another person he must have the list of players synchronized with the owner but I can't do it... Even if I follow the VRchat documentation...
So I'm looking for a kind soul to help me by private message!
what are you trying to achieve? just to make a button that is only pressable by admins?
and maybe if an admin opens up a door, or toggles a gameobject, it should be visible for the late joiners?
because if that's the case, you can just make an udonSynced boolean, and listen to the variable change events where you toggle your object. and you don't even need to deal with the late joiners this way.
So like only whitelisted players can add visual effect that anyone can now use it like unlocks it but I wanna be able to just press it and leave kinda thing like if my friend wants me to give it to their instance I can do it and leave and I'm really only doing it to learn how to do this stuff in the future
And use it on more important stuff
and do you mean like this is a separate bool type or just a synced bool?
yeah, you can use your existing bool and make it udonSynced, but I think your code wouldn't even run, if the player don't have ownership of that object, because you missing the SetOwner node from there
the player needs to own that object if it want to change the synced variable
like this?
you want to use the bool newValue for the SetActive, and you can remove the LateJoiners variable, I don't see a reason what are you using it for
im trying to make it sync for late joiners and which bool?
the tunred on one?
the TunredOn Change event gets called automatically for the player when he joins, you don't need to worry about the late joiners
but basically, what you are trying to do is: have a button that only the whitelisted players can press, that enables another button for all the players? in that case, it's supposed to work
are all scripts with syncing went over when a player joins?
yeah, but they don't update as long as you don't call a specific method that would update your objects, unless you have the synced variable in the Update or FixedUpdate loop, or as you used before, it's gets updated in the variable change events
so, all of your synced variables update itself whenever you use the requestSerialization or use the continous sync, but you need to listen for the VariableChange events or use it in a Update() or FixedUpdate() loop to have them synced with your objects
for the button would they need to click the button?
cause its on interact rn should i make something for on player join?
if the secondary button of yours only enables the visual effects, then it should work completely fine, because it gets enabled on the TunredOn Change event
you don't need to
have you tested it?
not yet for late joiners and is there a way i can like pause loading for one like make it so they dont auto join when im testing?
i think if you click on build and test last build, then it will join to your existing instance
okay ill try that thanks
one sec
yea it worked thanks for that that makes stuff sooo much easyer instead of trying to get a friend to join
is it even possible for your friend to join your instance that you haven't even published? or you tested it with a published private world?
no they cant thats the problem i have to upload it and hope i didnt break something in the world lol
and i would just use the world itself so everytime id have to go over the world and make sure nothings broken
yeah, that's hella a lot of pain, but you can use the editor's clientSim for smaller things, it's definitely not as accurate sometimes compared to the game, but it's usually works
if i make like complex moderation systems is it going to have trouble cause thats why i even added it to get good with networking so i can get to the point i can do that
the clientsim is not useful for anything beyond making sure you dont have invalid objects here and there. otherwise its useless. even the offline testing you can do is useless as its not the same as being online and you will have issues in the online that you dont see in the offline regardless of how much you try to test
Testing networked stuff in play mode isn't all that reliable, I usually launch a couple of VRChat clients with different accounts to test syncing in local build and test mode with some powershell commands:
# Launch build and test client with main account
C:/path/to/VRChat.exe --no-vr --enable-udon-debug-logging --watch-worlds --enable-sdk-log-levels --enable-debug-gui "--url=create?roomId=2213&hidden=true&name=BuildAndRun&url=file:///$([uri]::EscapeDataString("$($ENV:USERPROFILE)\AppData\LocalLow\VRChat\VRChat\Worlds\scene-StandaloneWindows64-MyProjectName.vrcw"))"
# Launch build and test client with alt account
C:/path/to/VRChat.exe --no-vr --enable-udon-debug-logging --watch-worlds --enable-sdk-log-levels --enable-debug-gui --profile=1 "--url=create?roomId=2213&hidden=true&name=BuildAndRun&url=file:///$([uri]::EscapeDataString("$($ENV:USERPROFILE)\AppData\LocalLow\VRChat\VRChat\Worlds\scene-StandaloneWindows64-MyProjectName.vrcw"))"
Replace C:/path/to/VRChat.exe with your VRChat client path and MyProjectName with your project name to match the file path at C:\Users\<username>\AppData\LocalLow\VRChat\VRChat\Worlds\scene-StandaloneWindows64-<MyProjectName>.vrcw
why, theres nice launcher in vcc that do that
Never used it before, does it handle the build and test URL as well?
uuuh it has option to launch each time you build for 0 in sdk
otherwise you just select whatever vrcw you got (i beleive the latest build is selected by default) and launch whatever clients you need in one click
Ah nice looks like it does, guess I'll start using that instead:
https://vcc.docs.vrchat.com/tools/vrc-quick-launcher/#launch-all-selected-on-build
i assume the local on in there is just the same as offline testing?
Yep, but you can launch it with multiple clients on different accounts
guess i need to make multiple accounts to use the online function.
otherwise the local is pointless
If your world logic doesn't rely on every player having a unique display name you can still launch multiple clients with the same account for testing, otherwise yeah multi account is the way to go to be sure everything's gonna work correctly
eh i mean as the offline testing != the same as having the online world. because i have tested things that works in offline but in online it messes up completely
like for instance when there 10-15 users it messes up some things
and i rely on ID's not display names
afaik only chairs are still unreliable in local test, at least was a thing year ago
otherwise its just some code flaws
in local test networking is still performed via servers, just world file is not being downloaded
well i had a few tests already with 10-15 people and it works well syncing them all but as soon as they then teleport to another place that enables a interaction on them it loses references to some people. and things dont appear to interact as it should
and i tested that with 15 offline clients
ok so I have a pickup you click and sends a network event that plays a random sound, what’s the best way to sync that random index, such that which sound is played lines up for everyone? Reading the docs it seems like variables and events sync at different rates, and events can’t have parameters.
option one - on same pickup use synced var and play sound on variable change. make sure that random cant be the same. option two - child object with manual sync that recieves event from main pickup's use, sets variable, requests serialization and then plays sound on deserialization(+locally).
I used option two that @tulip sphinx sent above and that worked well for me
Having someone on the other side the world help test your world might also be nice to test for networking race conditions you never considered before
Hello everyone, sorry to disturb but I was wondering if there is any way to make the VRCinstantiated objects synchronized?
sure, just keep synced stuff outside of instances themselves
Short answer: no, use object pooling instead
Long answer: it depends on how many objects you need, and what kind, the larger to scale, the more complex your system will need to be, only do this if you are advanced in udon and vrchat networking
Many thanks for the answers!
Hi guys, another question :((
I’m trying to make an among us-like game where roles are divided imposter/crew
I wanna pick a random player to be an imposter and have the ui “you’re an imposter” while other people get the ui “you’re a crew”
However I can’t get it how to show different screens using the network system in vrc
Any ideas how to start this??
Thanks always
Not a pro by any means but I'd probably set it up such that
-Instance master decides what team teach player is on
-Sync an array for each team
-SendCustomNetworkEvent({Target all}, {name of ShowUiFunction})
-ShowUiFunction called on every player, this check which array they are in, and then runs an animation to show their respective screen.
Make sure the SowUIFunction is public or else it won't get called
This does require telling the user, on the backend, who the imposter is which isn't good for preventing cheaters, however you'd have to be hacking to see that data but by that point the lobby's probably already too far gone
Yah, only the information of who is the imposter needs to be networked. Stuff like UI logic should be handled locally. If localplayer is imposter then render imposter UI, else render crew UI
Regardless of the exact method to do it, the overall thing you need to do is sync an int or array of ints representing the player IDs of who is an imposter. Then when you show the UI, you compare the local players ID to the synced IDs to check if the local player is an imposter, and show different things if they are
so now that the Network ID utility is broken for the past like 3 SDK versions, how does anyone make quest worlds anymore? Do quest creators just stick with some specific SDK version, or is there a third party tool that works around it?
how is it broken?
i havent had any issues with my quest worlds recently
also i got a question #udon-general message
you can't import network ids from one scene to another anymore, it just spams the console with errors. https://feedback.vrchat.com/sdk-bug-reports/p/network-id-utility-fails-to-import-with-nullreferenceexception
oh, why do you import them?
do you use different scenes for windows and android?
of course
I guess everyone does
try using EasyQuestSwitch on a scene that has hundreds and hundreds of objects. Ah yes let me just mark every single one individually by hand to have its material replaced with the quest shader
tis crazy how theres still no mat replacer
yeahhh darn
I use this, although apparently theres a new version now https://github.com/kurotu/MaterialReplacer
but it requires it being a separate scene
i tried that one, was pain
ended up just manualy placing replacrable stuff in diff folder then copying it to pc/quest folders via explorer when switchin. prob should work on one.
Guys, can you please help me figure out how to make inventory by type? that is, taking some object in your hands, putting it to your chest, releasing it, it disappears into the inventory, while the task is being completed, then how else do you need to find several objects to open access to completing the task in the dialog.
I kind of tried to do it like in that video https://youtu.be/hsnBrLQizDo?si=dVWhwDoqXixmJ0Yb, only I tied the box collider to my chest, but the object does not perform the action because it is not in the script itself, it will not work separately.
I want to find out how it can be done in the form of a name so that it is executed separately, or in the line of the object where it needs to be placed in the script.
I need answers, although I am ready to get negative ones, that this script with inventory cannot be done. And so, I don't want to wait a long time without an answer to this at all.
Here's a video on how to make a door that requires multiple pickups to unlock. This can be coins, or something completely different like keys, pictures, etc..
In this tutorial, I make a door that requires 3 coins to open
This tutorial also covers how to make a door open using an 'animator, play' node; something I haven't covered before. I also ...
to start, you want to use name of collider with 'contains' node to check if its a proper item and use some naming scheme for them ie ItemVodka ItemBread etc
then it will work with any object anywhere just based on its name
to store an item you ofc can use an array but actually i guess an easy way is to reparent item transform to your inventory so its literally ends up in it and when checking for quest conditions you just search in your inventory object.
Thank you, if something doesn't work out for me, I will definitely ask for help again, if you don't mind.
Can I get more details on how to do this? if it is possible to show it by the picture, it is desirable 😅
@finite folio dm me
You can also sort items into layers and either have the collider only collide with those items or check what layer the collision object belongs to and go from there
anyone knows what the EOS update thing is in the Log for worlds?
If I have a pickup with object sync (continuous sync) and an udon script with continuous script on that same gameobject
can it have a sub-gameobject with an udon script that is manual sync? or must the sub-objects be continuous sync too?
Can I use RequestSerialization in a continuous sync'd script?
Does OnDeserialization ever fire in a continuous sync'd script?
Each object syncs independently, they don't inherit sync type from their parents
Continuous sync is already repeatedly syncing so request serialization is unnecessary and does nothing
Ondeserialization fires when you receive data from a remote user, same as on manual sync except that it happens more often
@obsidian cedar with your networkcaller thing if i have lets say 40 people in a world and i target all 40 people would that mean it takes roughly 13 seconds in total to send to all or is the Limit you have hardcoded to .33 only if its called multiple times?
or would it be limited per network caller?
No it transfers to all at once
so if you send an event to everyone it'll be "instant" if no event was sent for 0.33s or max 0.33s
Ofc you have to note the latency etc.. so it will SEND to all at once but based on each person's latency it will be received at different times
And also NOTe, due to VRChat limitations you can't just send something to just 1 player, it will always send to everyone regardless of anything. But what I do in NetCaller is on the receiving side I check some target info bytes to check who the event is for and ignore it if it's not for the player
i assume if i use the SyncTarget VrcPlayer API then it only sends to that person correct @obsidian cedar ?
Again, it will traget that person -> Only that person will process that even but due to limitations in VRC Udon Networking, the Data will be sent to everyone in the instance. but everyone else will skip over the event
ahh gotcha i just missunderstood what u ment by it thanks.
Would a networking expert be able to look over my code if possible? I am having an issue where OnDeserialization is being called constantly and I am really confused as to why
is the behavior continuous sync?
see the last line of #udon-networking message
sdfjaksjhdfkjsldfjkhsaf
it was because of this
thank you lol
I was struggling with this for longer than I want to admit
but thats the way of code I suppose
I once spent an hour or so trying to debug a problem caused by if (gameObject = void)
I have a VRC Pickable up that I want to play an audio clip thats synced with everybody else. The issue I am encountering is the fact the script has to be Continuous and keeps calling OnDeserialization. Is there a way prevent it from being called multiple times on a VRC pickable up.
a. you dont even run Ondeserialization event (and you sohuldnt, for continuous sync)
b. your local code both plays stuff locally and calls network event that performs same stuff again. network events unlike ondeserialization fire for owner as well
c. at least say what behaviour you expect/get
I changed up the code to a network event.
But biggest issue for this is the value dosen't sync before the event is fired.
overall just move everything to a child object with manual sync, both easier do deal with and less network data. onpickupusedown transform.getchild(0).getcomponent....SendCustomEvent...
but will that desync the object position or the child position?
im pretty sure pickupusedown is local
It is
.
cant you just do it all in child script?
ie set owner etc
pickup can just send local custom event
Got it
probably doesnt matter but seems more streamlined to me
Lemme check if what your saying works
You can probably use a FieldChangeCallback on a networked value to do what you're looking for
something like
[UdonSynced] private int _vl;
public int V1
{
get { return _v1; }
set
{
_v1 = value;
PlaySound(value);
}
}```
and what if random is the same
that should have the same indexed sound play for both the owner and remote clients
This will also cause the sound to play for late joiners when they first join the instance, though
Oh, I see what you mean now by random; good point
Looking the code over I don't see why you want/need a sync'd property at all. If you want one of an array of sounds to play just define PlayVoiceLine1 ... PlayVoiceLineX methods. Whomever picks up the object generates a random number and calls the SendCustomNetworkEvent that is appropriate. Nothing to sync, everybody plays the same sound and new players are not affected.
that scales terribly; best option is using a manual sync and putting the event into pre/deserialization
Writing a method for each audio would be god awful. Since it will be reused multiple times. It is really easy to just sync 1 variable and have it play instead of writing multiple methods and randomly generating from there
I was using a manual sync. But when I found out you couldn't use manual sync with a vrc object sync it screwed me up.
yah, have to make it a child
in general having any synced behaviors on an object VRC Object Sync seems like a bad idea because VRC Object Sync seems to shut down all syncing on the entire object if it hasn't moved in awhile
Seriously it wouldn't be bad at all much less awful. Do what makes you happy.
Well you would need a script for each x amount of audios you want
I am getting used to these being the days when people tell me how stuff works rather than asking. The network event is a method-based not class based. It would take one script that would handle all the audio behaviors as far as I can tell. But then I already do this so maybe I'm mistaken and it isn't actually working.
anyone else had issues with the rejoin function for a world? i have observed that if you rejoin a world immediately it can result in some objects being null. which i find rather strange. but if you do not immediately rejoin and you choose to go back home first and then rejoin then it will work as normal
oh. i found out why. i cannot rely on ID's assigned to player that joins a world.
seems like i found a big bug lol. if two people join at the very same time both people get assigned the exact same ID PlayerID
You sure it's not just something wrong with your script logic?
yep.
i just looked through my logs. and somehow it ran OnPlayerJoined 3 times even through only two players exist. and also the logic only runs when your master.
do networked variables need to be public
is it possible in a manual sync'd object for RequestSerialization/OnDeserialization to misfire on an object that is potentially rapidly changing owners?
It is an illusion. The player id is unique per user, assigned when a player joins and simply incremented by one each time a new player joins. And realize that OnPlayerJoined is called by every player so each player is notified each time. Trust us, it works.
doesnt matter. it still happens
there are duplicate collisions on the ID which causes two masters to people to be the same
So I have an object with ObjectSync and at this time PlayerPickup.
The object which is in the scene at start, is synced between players in the world, however I want to take this behavior a step further. I want to create new instances of the object that are also synced between players. However, objects that are instanciated are not synced and are local. So what must I add to the code to ensure that objects that are created are networked synced?
You need to use an object pool, using objects already there. You can either use the official Vrc objectpool or make your own pool script
Can you provide some examples of what you're trying to do and how it breaks?
right so. i discovered it when me and a friend of mine goes into the world as close as possible . like on the dot. and when it happens it for some reason gives one of us the master which is correct and it sends and receives all the correct data. but for some reason it only sets the owner to one of us
What does this mean exactly?
Let's take an example from the world, "Trash Compactor" where as, there is a large cannon that shoots trash when a trigger event is called. An object is then randomly thrown out of the cannon onto the arena below.
When you are referring to an object pool, are you saying that all the trash is not being instantiated but there are a large pool, like traffic stuck on the road, above the arena already there on world start waiting to shoot out when the trigger event is called?
yes
it grabs first free item, probly even has pools for pianos, pool for tyres etc since its easier and shoots one of them
its not like its stuck tho, its disabled and doesnt do any networking when so
but ye it already exists in the scene and when projectile dies goes back to being disabled to be reused later
This is going to add a bit more complexity to what I had already in mind.
If not already to what I was wanting to test. (It's been a while since working in unity) But an idea to test was to give each instance an ID with a range, call all ID's with a range and type (in this case a ball) and then add a component (the network sync) on the active state (or awake) and see if that can trick it into working.
But I don't know if someone has done that already or not.
Yeah in runtime. A script that adds the networkSync component to an object after the "game" had started, won't do a thing to add networking is what you are saying.
Well shucks.
anything networked should have an unique network id on upload
if all you need is vrc sync you can reuse them, i have a world with a pool of 150 empties (default vrc sync also quite heavy on bandwidth but eh) that can be any form or shape.
then you throw out what you dont need and can make new ones (in fact reusing same pool objects)
but its not the easiest stuff
Wow... Is it a bug or intended behavior that instantiated objects can't be synced?
Because if that is the only way to do it, seems as that is the only way to do it then.
again. anything that should send the data across network should have network id, assigned when building the world. its intended. if you need smth simpler/less data heavy/manualy synced than vrc sync (like, idk, small minecraft zone) you can outsource it so you actually destroy/instantiate stuff locally based on a single script containing synced arrays of block data etc. but thats not viable for continuous sync of large amount of data since theres no selective sync.
So here is a question, how do you keep up with 100+ objects in your project? If you have to create a pool, where as in an instance one object being changed affects all instances to that object, which is ideal for testing. Now you must change 100+ objects, MANUALLY. I mean, am I missing the logic here in how inefficiant this all is?
Did VRC at least create a tool or something to make this all easier?
wha
' a pool, where as in an instance one object being changed affects all instances to that object'
?
Every instance of an object is a clone, an exact copy.
A pool of 100 objects are that which are independent of another.
Networking doesn't exist with instanced objects (because VRC either is preventing this purposly, or they don't know how to network their game)
A pool must be created of objects in order to invoke networking capibilities. How do you then keep up with 100 objects when you wish to change the behavior of all of them?
they use same script, why should i change anything on them. otherwise if i realise i need say capsule collider as well as cube i fix first instance, delete others, hold ctrl+d. but thats rare
Don't you mean first object?
well ye
Very inconvenient.
you can script it, just easier to not to.
Can you not just have a prefab and update the prefab?
ye good idea as well
Myself, I have a custom pool script I made that I just hit a button and it generates the pool objects for me and assigns a few certain variables that the prefab can't hold.
Hmm.
@lapis lodge you can technically get networked instantiated objects, but it’s true that you can’t actually sync changes to the instantiated object itself, so all the networking data would need to be handled by another “item manager” and the more you have to sync on those, the more you’re bloating its manager.
Make an item networking manager that has an array of all your object types. When a player spawns an item, they just update their “active inventory” with the index of the item they spawned so others know to spawn it too, but then you have to do the same for that object’s position, you need custom handling for applying networking to objects that are picked up, thrown, and despawning. Etc etc. it’s a lot of manual implementation to make this work 👌
You’re basically completely rebuilding item interactions alongside it, but it is possible, and it does look very pretty if you get it working, but it’s a lot of work you’re giving yourself in the end
This world uses this system for all of their items spawning, because there are a lot of item types, and they wouldn’t want to pool all of those for the player count or it would probably bog the game down
Aye, and that is a huge benefit of instanced objects.
What I'm doing in my item system, is my pool is a list of Item objects, and each item instantiates the visuals along with a descriptor of the item that stores the item data, then I only really need sync what the item type is and the item class that each object is will update the visuals and effects
It is certainly rough not having something like an InstanciateNetworked, but we do what we need to within the limits we have.
Like, the amount of destruction I would give to have structs
yeah, a more advanced pool where it manages a collection of generic synced objects and then instantiates additional things under each object is really handy for large-scale worlds with many items
I set up a pool with over 300 "template" objects and gave them each unique names, icons, and IDs. Then there were 150 generic pool objects, so at any one time you could have 50 apples, 50 swords, 50 shields, or any other combination
such a system is also a great foundation for building more complex interactions involving props, because you have more context on what something is supposed to be and you can distill the entire existence of the prop down to just data. Because of that, I also made stackable props, inventories, and save system. It's a lot of work but it's very rewarding to have such a system because it can become the basis behind many other features
Similar, I have 128 item holders and a number of descriptors, the holders handle any of the networking stuff, the descriptors have the data. Its for a lethal company like world so there are multiple behaviors for items, like flashlights, radio, generic scrap, noisy scrap, items that do damage etc.
@frozen igloo i found that i am encountering Network Race conditions. is there a simple way to avoid this issue? if lets say 10 people join at the same it gives the wrong things to wrong people.
I have the instance master distribute player owned objects in the OnPlayerJoined event, but I don't know your use case. Like, why are players attempting to take ownership of things on join? Can you defer this action to an event sent by the instance master after assigning an ID? Or maybe use the player ID?
If you're doing a thing where it automatically hands out an object to each person that joins, yes that's a pretty complex project that requires various safeguards against race conditions. There are prefabs to do that such as cyan player pool, but also in the persistence beta, it's now a built in feature with playerobjects
yea not in the beta yet
I'd highly recommend it unless you're putting on an event this weekend
thing is. only the Master hands assigns what objected is owned by who. and considering there is only ever one master how could it actually even end up in a race condition. considering it only runs it once per time someone joins.
Using the master to assign it is only one method of resolving those race conditions. But you need to make sure that your code is properly handling it. If you post your code I could review it
i assume the other would be Request ownership transfer?
eh, I'd not use request transfer for this case, it's not reliable enough
I was thinking more like determining owner of each object based on inherent factors that don't require additional networking like playerID
that's a more oldschool technique though, when networking in general wasn't even reliable enough to have master handle it. But it makes up for the clunkiness by being extremely reliable
but even cyan player pool is starting to look oldschool compared to playerobjects
There's really not much of a reason to build your own player pool at this point. If you desperately need something now before persistence goes out, use cyan player pool. Otherwise, use persistence playerobjects
hmm.
I've been thinking about race conditions too for an upcoming project 💖
There's going to be a big rush from people to claim ownership of certain objects on a list at the same time
Are there other terms or ideas I should be researching for handling this?
Whats a good way to check if a script variable has been synced
You can listen to the OnVariable Change events, and log it on the console when that happens
thats smart
Is the code for syncing object positions optimized? Like even though it's continuous, if there's an item sitting still, it's not generating network traffic right?
Im pretty sure vrc object sync does have a sleep state, the debug menu shows something like that if i remember correctly
Have you had issues with objects losing reference upon entering a world? For the local user that is
Like to other udon behaviors
With VRCObjectSync, yes the sync goes to sleep if the object isn't moving. You have to be aware of that if you attach another script to the same object, since the sleep mode will apply to it as well.
I have two objects, need one object to teleport to another object's location where that object is network synced. IE a pinball moves to the pinball spawner.
This is what I have, but I feel I am doing something wrong here. Can anyone help so that I may learn how to get this to work?
Anyone around?
why are you using a user input to do it and why are you doing it every frame?
It's not every frame, it's only on pressing down the key.
Exactly, to check for input, it must be in the update to check for the event.
I tried to rework the code a bit, but still giving issues.
Am I using "teleportTo" correctly?
Yeah that's the direction I was going to say, that line before was unnecessary and causing problems
as for the teleportto, that's simply not a function on gameobject class. To teleport a gameobject, you would want to get it's transform then call setpositionandrotation
that said, things are different if the pinball has objectsync. Does it?
Yes, yes it does. as this be a game with multiple players to each, being able to knock the ball into the other players "goal" or what ever it is called in pinball.
ok then if it's synced you would need to first take ownership of it, and then call TeleportTo. But you can only call TeleportTo on the VRCObjectSync, not the transform or gameobject. TeleportTo is basically the same as setpositionandrotation except it also tells remote users about the teleport as well, which makes it actually teleport instead of just lerp into place.
additionally, regardless of what you're doing with this specific code, it looks like you don't have intellisense hooked up and that makes coding a lot more difficult. You should ensure that you have it set up properly so that it will be able to recognize what functions exist, show you a list of options, auto-correct capitalization, and show you exactly what's wrong when it's a compile error
the first thing to do would be to go to file > preferences > external tools and ensure that something valid has been set as your external script editor. Looks like some form of visual studio you have, so make sure that's plugged in. Then, open the scripts by double clicking in unity, not through the windows explorer
I think something broke.
I did what you said, and it gave me some sort of error and opened up a website with this migration report.
close visual studio entirely
make sure that it's selected as the editor in unity
double click a script in unity
It be downloading something now... I don't know.
XD
This is why I like to just stick to the 3d modeling lol, so much more simple.
You should probably install Visual Studio Community through Unity Hub if you didn't originally to make sure it has everything needed for Unity projects
hmm has anyone encountered issues where players dont get initialized?
Not sure what all this is about.
Does it matter what version of visual studio you're using? I know Unity likes to have a certain version installed depending on your version of Unity
That's a good question, I don't know.. But it is acting as if perhaps the case?
That is what I am using.
I do have a 2019 version of VS as well. Should I try to open in that?
you have to spend more time configuring stuff for code iirc
Well I don't think it isn't an unity package issue, I think it is a VRC package issue.
Just about everything on that "Solution Explorer" states VRC
I don't know what is going on anymore but I think my project just broke.
How do I fix this?
Anyone know why the SENDCUSTOMNETWORKEVENT
isnt working for me in this instance.. if i connect interact to the set active it works fine but the send customnetwork even does not work at all
Is the behaviour Synchronization mode set to something other than None?
Yeah set it to manual
do i still need the custom network script?
Yeah, None just means that the object isn't networked so network events or variable serialization events won't fire for other players
if i can trouble you, whats the difference between none, manual and continuous ?
Continuous will automatically fire synced variable serialization events on a fixed interval, Manual has to be triggered manually using UdonBehaviour > RequestSerialization
so manual is the best one to go with in this instance then?
Yeah Continuous is mostly used with pickups that use VRCObjectSync, Manual is what most things use nowadays
ahhh i get ya
Especially if you're not actually syncing any variables
thank u! i appreciate the insight
ok another issue with this
|
my ranom array seems to be not syncing with players
what it does is sets a random object in a array to active. but it seems to be grabbing differnt cards for people in the instance
Yep since you're telling every client to run the logic locally they're going to generate a different random value on their client
T^T
You'd be better off syncing a bool array to represent the active state of each object and have the client that triggers Interact set a random object and the corresponding bool state in the array then RequestSerialization, then in the OnDeserialization event clients can iterate through that bool array and apply it to the gameobjects so everyone has the same state
That will also make sure it syncs for late joiners
(ActiveCards and Cards should have been marked as Public)
It's missing the ActiveCards node hooked up to Boolean[] Set's instance
Put your card objects in Cards and set ActiveCards to be the same size as the Cards array and leave the array values at false
Unless you've got some cards enabled by default in which case set the corresponding array values to true
Oh I forgot to add SetOwner on the gameobject
Gotta do that before modifying ActiveCards or it won't apply the changes
willl this auto sync withou the custom event trigger?
also set owner node on the gameobject? in the graph?
for all on just one of them
Yeah when you call RequestSerialization all players except the person who called RequestSerialization will fire the OnDeserialization event with the updated synced variables
ahhhhh
Also anyone who joins the instance will fire OnDeserialization with the latest synced variable state
Yeah that looks fine
man Udon graph got me like
i wish i could dragg all 48 card objects in the array to the inspector in one go.
i have to do em on by one
ok time to set
test
works in unity.. now to try in vrc with ppl
btw @strange gyro thank u a bunch id be slamming my head if it wasnt for you
fyi reason for this is a custom board game idea i wanted to put in vrc XD
everything is working BUT the cards till you helped me with that so cheers!
I guess the only thing you'd want to improve after this is the random card selection
Since you'll eventually have to click spawn multiple times to pick a card that isn't already active
well you should only want one card.. im having it so the SPWN CARD button goers away when clicked aswell.. if they want and new game the reset button will set everything to unactive
if that makes sense
Ah fair enough
yee th reset bu8ttons flips them all up and resets the cards and all that jaz 🙂
ok weird one
it Kinda works?
Oh i know what its doing
id how to explain but the rest button is like not working as intended for the cards
You'd have to reset the state of ActiveCards as well and RequestSerialization
even if i click reset it toggles off all the the game ojects but if somone elese clicks spawn cards it has multilple commin up but for themn only one does
What does the reset button logic look like?
....veryy silly setip ahah
dont jusge me i did it myself
im embarresed by my graph
Ons and offs are for the fl;ip piceses and cards and the buttons are set the spawn cards button to come back after its been clikced already
... COULD i just use your other script? we did
and remove the random array?
Hmm this makes it a little trickier to manage the sync state because you disable the spawn button
The card states should probably be in their own udon behaviour
And the spawn button changes that instead
Then you could put reset logic in that other udon behaviour
Basically a game manager behaviour
i only do it so people do accidently click it and get a new card and go " OH MY CARD CHANGED"
we can disregard the button despawner as long as the spawner will one have one spawned at a time
I guess you could turn off the collider and mesh renderer instead on the spawn button to hide it and prevent it from being clickable
big brain move
So long as the game object and udon behaviour is active so OnDeserialization can fire on changes
we can not worrya bout the button despawning and just make sure the reset button works in this instance
wouldnt your script for the cards work?
just remove the random array?
like this ?
This is the Spawn button's script, then on your Reset button script you'd do Interact > SendCustomEvent with ResetCards as the eventName and a reference to the spawn button behaviour as the instance
also any chance you can send me this graph so i dont fuck it up?
right >.> ok i think i get it the reset button grah callthe the graph in the spawn button right?
Yep it'll call ResetCards in the spawn button's behaviour which resets the ActiveCards array to an empty one and syncs that to everyone
Then OnDeserialization in the spawn button will update the card visuals so they're all hidden using the reset active card states
with the sapwncards would the active cards need to be active? since i wan them to make a random card active?
no
no i wouldnt
Nah they would be false by default since they represent which cards are currently active which should be none
You probably don't even need it to be an array of booleans now that I know you only intended one card to be active
Just the array index of whatever the active card is would be enough if it's only meant to be a single active card
Do they share the same card objects?
nah each players representive cards 24 each side.. so i have the script on 2 buttons calling 24 cards
i can make it one button if the complicates thjngs
Nah that's fine
Your reset button just needs to call SendCustomEvent for both spawn buttons
how to iu make it 2 objects then?
Probably the simplest since it's only for two players
UdonBehaviour arrays are broken in graph so you'd have to use Component arrays instead if you want to store them as an array
AWSOME
now the reset button needs to reset the flips
i shouild bne able to do that one
would this work?
the tiles are 2 difrfrent objects one toggles off and the other on
Maybe but you'd only really want the person who clicked the reset button to fire ResetCards on the spawn buttons since they're going to sync to everyone anyway
Otherwise everyone is going to fight for control over the spawn buttons to change the sync state and fire it off to everyone
Gets kinda messy
Also your flip states probably won't sync for late joiners
thats fine for now
people used to say not to network your game with networked methods, only to used fieldchangecallbacks on udonsynced variables, because people could somehow force-run the networked methods... was that patched out by the update VRC made that made worlds more secure recently?
A modified client could still do it but they're so rare nowadays that it's probably never gonna be an issue for the average world
At that point they'd be able to manipulate synced variable state as well
current advice has moved away from network events but it's not entirely because of security. Standard synced variables are also susceptible to modified clients but that's not because of some security hole, it's because they're designed to allow anybody to sync with them.
That said, there are two key takeaways:
- Syncing through synced variables is still recommended simply because it's more robust. When you rely on them for an entire project worth of syncing, network events tend to get pretty fragile and break a lot of rules
- Persistence adds PlayerObjects, and unlike normal objects, PlayerObjects are not allowed to transfer ownership, and this is enforced on the server side. You could use them for the purpose of security to ensure you aren't getting anything messed with. That said, I don't think this method is going to be a "recommended best practice" any time soon, rather it's a technique you can use if you're in a situation where security is a high priority.
just to be sure I understand, anybody is able to pull & read the "player object data" of another player, correct?
read yes, write no
yeah
cool
so the "don't use networked methods at all because they can be hacked" is a lie, and a hacker could just manually call udonsynced fieldchangecallbacks in the same way, so it doesn't really matter?
nothing is an ultimatum, but generally yeah
I do my best to build unhackable code but I don't want to give bad advice
Telling someone not to use networked methods just because is bad advice and now I will stop! xD
@broken rampart I apologize fren ;_;
ooo alr
It's likely that the advice you mentioned to move away from synced variables was right after manual sync. Back when we only had continuous sync, it was pretty flimsy and so networked events were a good method to run all your networking on. Then manual sync released, and it's far more capable than either continuous or network events. So there's probably some sentiment along the lines of "network events are trash now, let's use manual sync" - that, I would generally agree with. But I would not agree with "never use network events because they can be hacked" since that's a bit of a misnomer
Network events are mainly considered useless because you can't pass arguments along with them, otherwise they'd be amazing
Network events are the only form of networking that you can send on an object you don't own. As a result, they have their uses. They're also useful for quick and dirty implementations of something that doesn't have state. But as the networking backbone for a large system? Yeah, not recommended. They're just a bit too wasteful and slow for that
exactly this, frenetic didn't want to transfer ownership and I thought methods were hackable and needed to not be used
I probably had him overhaul his sytem in a way he really didn't need to do e.e
I mean they are, but it depends entirely on how much you care about security
If this is a system where security is absolutely critical, move to the persistence beta and use synced variables on a playerobject. If you're just making something to have fun, then don't overthink it. Don't try to follow crazy advice that doesn't apply to your own situation. Just use whatever you feel comfortable with
We're planning a bigger world with persistence and such- does it go against ToS to auto moderate a user, that has been banned by us by permanently setting their persistence data to not gain levels and such? They can still walk around but will always remain lvl 1 and deal no damage and are not allowed to store items in their inventory- we're mostly worried about a client cheating unlimited items into the world and handing it out to others 💀
They'll be able to appeal on our discord as well in case they have been banned for any reason. I'm pretty sure that this will most likely only affect client users that have been caught* cheating.
yes
resetting world state (ie persistance) should bring them to nothing ever happened
You're totally fine to have automated cheat detection which resets progress as a punishment. Where you'll run into trouble is trying to add that user to some list which keeps them punished forever across all instances. I'd recommend focusing more on group moderation for that purpose.
Hmm I see- let's hope there won't be that many casualties 😅 what does the udon code signing actually do?
This helps ensure only authentic (unmodified) versions of your world can be loaded into VRChat.
I'm not sure what a modified version is suppose to be to begin with 👀
yeah that's an exploit that allowed people to modify the world to add malicious things, even if they didn't modify the client. That's one more hole that's been patched so it'll be harder for them, but it's still a good idea to not trust the client
Ohh that's what it means- I'm glad that its patched 
well time to figure out how to trust the client and that it won't try to spawn 999 items :D
Uh, I have to take issue with avoiding Network events. There are almost a set of questions one can ask themselves to determine how best to network data. This ranges from "no networking" if local only is the goal, to sync'd variables if you want late joiners to get the values. There are other valid options as well and a few we are stuck with due to the lack of parameters on network events.
If they supported arguments and the ability to send the event to a specific target I'd only ever use synced variables for storing late joiner state
Even that wouldn't be necessary since the master or object owner could send the state to a late joiner when they join
Network events have the potential to be the most flexible way to sync data between clients
It's just held back by poor implementation
and that is one of the reasons it wasn't implemented years ago. Having the synced state be explicit variables allows the server to provide the current state to late joiners without the owner re-sending anything. That represents a pretty big amount of savings, which would be nice if we kept
Network events are fundamentally a Photon Remote Procedure Call right? They have a lot of uses but shouldn't be the only mechanism available.
I use SendCustomNetworkEvent in two general cases. One is any time I need to have all the players play a one-shot sound. The other is on my Click Buttons which flash when pressed. Neither of these needs to be sync'd with players not already present.
people have just implemented their own network event systems, in any remotely involved world the author is going to need to network something in response to players joining
A couple times I tried network events for one-shot audio and animations. But ended up needing to say like play animation 3, sound 7. A separate method per combination would've been annoying to manage.
At this point it's safe to add because people already have a strong basis on manual sync. But it would have been a really messy environment if events with parameters arrived before manual sync, and they became the "standard" method
I think they'd still become the defacto of syncing even if introduced now. Setting variables and waiting for serialization events that are disjointed from the event that caused the serialization is a pretty nebulous concept to grasp compared to sending a user named event along with the context data and handling that same event on the other side with the same event name and context data
That's why newbies to Udon still use SendCustomNetworkEvent without knowing the drawbacks of it
It's just more intutive by nature
Variable change events could kind of help to mitigate that if it supported data structures, you set the struct variable with your values and do stuff on the variable change event
At least that event can have a named association
I believe a lot of the issues could be solved if there was a networkevent that accepted a DataToken as a parameter. It would open the channel for most things.
Let’s pray this feature somehow arrives with udon 2 if that’s not already confirmed 😛
i just hope Udon 2.0 will actually have parameters in networked methods. since it litterly makes zero sense. not to have it and it only makes any world creation alot harder. if udon is needed. also the extreme lack of documentation. and no real proper way to test worlds without needing alot of people to partake.
and also reduce the inconsistency that udon has when people load in worlds.
I agree, some networking bugs can be pretty nasty to fix, especially if they only show up with 8 or more clients in the instance
Having to wait 3 minutes on each build and test with multiple clients slows down workflow significantly
i have inconsistency with just 2 people. its 50/50 if it does as it should. but i noticed it happens alot more from a Cold Boot of a instance after a 10min or so. after that it happens less. but then if one more person joins so 3 people the error comes back.
and its specificly some things that ends up being null even through they are not.
hi guys, I had a question, this is something I could easily do with something like cyan trigger, but im trying to make a toggle with UI, and I was curious on how I could make it synced: does anyone have an easy way to do this?
add component - global toggle (theres other toggles as well, its u# scripts examples), populate it with objects to toggle. Use Interact as name of custom event you use in the button.
ill try that out now, thanks!
now do I add this to my toggle object, or where can I put this?
\
anywhere, it should have editable list
anywhere, you reference script in your button
thank you!
Have you noticed anyone else using Udon with anywhere near the sync issues you seem to be having? Do you suspect nobody is doing the sophisticated stuff you are doing or might there be something else going on? Perhaps you could take a short survey of people with code that works half the time or that routinely fails after 10 minutes. You don't have to answer me so much as ask yourself, what could be up if nobody else reports such things as surprise null values?
i have no idea lol. But i do know there are creators who have made crazy big maps and had to work on it for a very long time to get things to work. to get around every issue they found. and its more or less because i am vocal about these issues and findings. And its more or less me observing that i run into issues that are specificly udon related. and there is little to no documentation of these problems or if its a known issue etc.
There are a lot of creators and Udon developers on this channel. We all know some of them. I wouldn't attribute problems to the size of the map. I've worked on projects that have reduced 1000 lines of code to 100 lines of code. Reusing working and well-tested solutions is superior to one-up poorly tested solutions. If you spend a month digging a hole your hole is not better than the one someone dug in a day.
You write there is little to no documentation of these problems but have yet to identify a problem. You describe something you see but you haven't supplied any code. Lots of people do supply code and you would be surprised how many issues can be solved this way.
Udon has issues but it does not suck. It doesn't randomly null references that I am aware of and my world is used every day. Other world builders have dozens of instances with a combined count of hundreds of users. All of us here (I assume) use VRC on a daily basis and we aren't noticing random crashes in the worlds. When mine encounter an issue I can trace it back to the code that caused it and typically I overlooked some combination of events and handle it. This is how all software works, BTW.
try posting a class that causes a sync issue for you and possibly 90% of your issues will disappear.
That may be true for basic use cases, but I can very confidently say that when you think of things from the view-model architecture perspective, a lot of large networking problems suddenly become very very simple, and synced variables are the best way to do that.
depends on what u mean? Methods with parameters would be the ideal way to do everything and more likely to be the better solution as its also normal everywhere else
Would love even a single byte that I could send with an event so I can stop doing trash code like:
public void OnDelayedEventDisplayReceipt()
{
SendCustomNetworkEvent(NetworkEventTarget.All, nameof(OnEventDisplayReceipt));
if (UnityEngine.Random.Range(0.0f, 1.0f) < 0.03f)
{
// rare line
int line = UnityEngine.Random.Range(0, _transactionRare.Length);
SendCustomNetworkEvent(NetworkEventTarget.All, $"OnEventTransactionRareVoice{line}");
}
else
{
// common line
int line = UnityEngine.Random.Range(0, _transactionPositive.Length);
SendCustomNetworkEvent(NetworkEventTarget.All, $"OnEventTransactionVoice{line}");
}
}
public void OnEventTransactionRareVoice0() { _wallVoice.PlayOneShot(_transactionRare[0]); }
public void OnEventTransactionRareVoice1() { _wallVoice.PlayOneShot(_transactionRare[1]); }
public void OnEventTransactionRareVoice2() { _wallVoice.PlayOneShot(_transactionRare[2]); }
public void OnEventTransactionRareVoice3() { _wallVoice.PlayOneShot(_transactionRare[3]); }
public void OnEventTransactionRareVoice4() { _wallVoice.PlayOneShot(_transactionRare[4]); }
public void OnEventTransactionVoice0() { _wallVoice.PlayOneShot(_transactionPositive[0]); }
public void OnEventTransactionVoice1() { _wallVoice.PlayOneShot(_transactionPositive[1]); }
public void OnEventTransactionVoice2() { _wallVoice.PlayOneShot(_transactionPositive[2]); }
public void OnEventTransactionVoice3() { _wallVoice.PlayOneShot(_transactionPositive[3]); }
public void OnEventTransactionVoice4() { _wallVoice.PlayOneShot(_transactionPositive[4]); }
public void OnEventTransactionVoice5() { _wallVoice.PlayOneShot(_transactionPositive[5]); }
public void OnEventTransactionVoice6() { _wallVoice.PlayOneShot(_transactionPositive[6]); }
public void OnEventTransactionVoice7() { _wallVoice.PlayOneShot(_transactionPositive[7]); }
public void OnEventTransactionVoice8() { _wallVoice.PlayOneShot(_transactionPositive[8]); }
public void OnEventTransactionVoice9() { _wallVoice.PlayOneShot(_transactionPositive[9]); }
Unless someone has a good way to play the same sound across all clients that doesn't involve dancing around sync timings or packing data into a single synced var
Nah, only thing I'd do to make that feel less painful to write out would be putting the logic in a common method:
private void PlayRareVoice(int index) => _wallVoice.PlayOneShot(_transactionRare[index]);
public void OnEventTransactionRareVoice0() => PlayRareVoice(0);
public void OnEventTransactionRareVoice1() => PlayRareVoice(1);
public void OnEventTransactionRareVoice2() => PlayRareVoice(2);
public void OnEventTransactionRareVoice3() => PlayRareVoice(3);
public void OnEventTransactionRareVoice4() => PlayRareVoice(4);
Yeah that's cleaner, but still painful
People's measure of pain these days is interesting...
is it ment to play the same sound for everyone? or random for everyone?
[SerializeField]
private AudioSource audioSource;
[SerializeField]
private AudioClip[] audioClips;
[SerializeField]
[UdonSynced, FieldChangeCallback(nameof(SyncLine))]
private int line;
public void OnDelayedEventDisplayReceipt()
{
if(!Networking.LocalPlayer.IsOwner(gameObject)) return;
// Rare
if (Random.Range(0.0f, 1.0f) < 0.03f)
{
SyncLine = Random.Range(0, 4); // lets say that the first 0 to 4 audio clips are rare.
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All,nameof(SyncLine));
RequestSerialization();
return; // Exits the method prevents the need to have an if else statement afterwards.
}
// Common
SyncLine = Random.Range(5, audioClips.Length);
// since random.range is inclusive it starts from 5 and up to the length of the audioclips array.
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All,nameof(SyncLine));
RequestSerialization();
}
public int SyncLine
{
set
{
line = value;
OnEventTransactionPlayVoice();
}
get => line;
}
private void OnEventTransactionPlayVoice()
{
Debug.Log(line);
audioSource.PlayOneShot(audioClips[line]);
// plays an audioclip based on what line has be synced. can be common or rare.
}
