#udon-networking
1 messages · Page 34 of 1
programming-wise, ints are usually 32 bits long, and it does not resize dynamically, it takes up that much space regardless of value stored
shorts or bytes would take up less space than an integer, but in turn have a smaller range of values
In .NET "int" is just a shorthand for System.Int32 which is indeed always 32 bits i.e. 4 bytes.
I have a udon project built around having 1 unsynced udon script on each client that reads the local player's inputs and applies changes to them, then goes through and checks every player's information and applies effects to match. Basicly All the syncing should be done through the players themselves.
My problem is this script seems to do nothing if its Synchronization Method is set to None. Am I missing something basic here?
Sync mode none is currently broken on live. It's fixed in the beta
Oh that sounds hopeful. So is the logic sound? Having a local script that reads inputs can changes player velocity for example, then locally applies effects on each player based on their velocity
yes, as long as you're only planning to do anything to the local player
Oh i was hoping vrchat did something to sync the player data. So things like player velocity when changed locally would later get shared and synced up with the other clients
if player A says "I want player B to move" then no, you can't just do playerapiB.setvelocity
you'll have to sync a variable or send a network event, which would in turn be received by player B and they would interpret it by setting their velocity
Yeah that's what I was trying to figure out thanks
So I "think" im taking the right approach here so I want to be sure.
With simple things like switches that trigger behaviour that requires syncing, that's not something you need to constantly switch ownership for right? I assume that would just add networking delay for no benefit even though the if the owner doesn't trigger it there might be a delay for the user who did trigger it to see the action take effect
eh, it's up to you
if it's manual, then taking ownership, setting the variable, and requesting serialization shouldn't have much delay
On the contrary, if you don't transfer ownership, that means you would have to use network events. Network events have a higher latency than manual sync so it might actually be longer for everyone with that method
I was gonna say, having a non-owner make a Network Event request to the owner to have the variable change takes nearly a second for that entire process
So I assume ownership transfers are actually quicker?
Seems weird and convoluted
Yeah, the variable in question is manual
Thanks as always, ill try adding an ownership transfer and see how that goes
Question on networking logic here, if I have multiple instances of a card game going, I am wondering if somebody were to click "reset" button on two or more games, they'll become the owner of both game's parent object with my game controller logic.
If they hit reset, a local(non-network) event will fire to reset the game because I only found TMPro to do so OnClick().
Could this potentially affect both game instances since they're both owned by the same client? How could I isolate them if I can't provide some sort of GameID or parameter in the event?
Here is what my method looks like, and is called by a local event from TMPro.
when using manual sync, OnDeserialization is called for the new joined player and a random player already in room?
when a late joiner enters the game, the OnDeserialization will fire for every game object with the latest data for them
to learn more about udon networking: https://docs.vrchat.com/docs/udon-networking
yes, and a random player already in room!
i mean, anyone else have this problem? maybe it's a bug.
how many players are we talking about?
player ABC are in room, when player D joined, OnDeserialization is called on D, and one of ABC
you can use the Interact event node instead and make a button, it will allow you to target a card game instance based on the game ID you will set via a variable
okay, OnDeserialization is fired for both the later joiners and the non-owners already in room.
it may be caused by another user that updates some udon behaviour and then requests when a player joins
Requesting serialization only updates the udon behaviour that requests it tho, right?
it will sync the synced variables on the behaviour you call it, yes, if you marked the sync method to be manual
Makes sense
@azure crane @fiery grove correct me if I'm wrong, but that method request the serialization of all other clients. Only the owner can call it and it notifies everyone else to get the right value, right?
the method can only be used by the game object's owner.
the other players will then receive the updated synced variables, they will also trigger the OnDeserialization event, if implemented
Thanks, looks like my understanding is correct then. Maybe I misread the question.
What is the best way to create a script that only the first user to create/enter an instance executes?
Spawn didn't work for me and Start seems to execute before networking states are established which prevents me from checking instance ownership for late joiners in order to stop unwanted script execution
...nevermind! Seems like just checking for object ownership instead of instance ownership worked.
Maybe like combination of OnPlayerJoined + isMaster could be?
Yeah but master changes when the old one leaves and it would fire when new people join
There's a is network ready event I believe, but I'm not sure what it does
Either way just checking for master once should be enough
But you need to consider what happens to late joiners as well
The network ready event is pretty much a relic of the trigger stuff I think. At least it was explained to me that Udon starts, only after the network has readied
start is effectively onnetworkready. It's an internal function. But "ready" just means connected to the network, so in udon you won't have received all sync until a bit later
if you use OnPlayerJoined, and check whether or not the joining player is master, it should fire at most once.
because when the original master leaves, another player who is present becomes master.
thus, a joining player may only be instance master if there were no players in the instance before they joined [in which case the instance is new, as there is nobody to recieve sync from anyways]
I see 
granted, this is what should be the case. if for some reason OnPlayerJoined is fired locally before the local player knows they're not master, this method won't work. so better test
Do we know if they plan to add syncing to any of the new types they're exposing to Udon in the current Open Beta?
Is there any issue with Udon's networking currently? My object assigner that I made won't sync objects to the players it's assigned to currently. Even tried uploading the default test version of the World Jam one and nothing follows the players in world.
there are no known big syncing issues, except for sync mode None being broken on the live client
can you elaborate your situation with some details?
I'm using the object pooling to assign a simple sphere to players currently. The spheres and such however do not sync to the players position. At first I thought I messed something up but not even the example version in the World Jam works.
how are you syncing their positions? have you added the object sync component?
Oh does it need an object sync now? Before it didn't. I can try that though.
object pools only sync whether an object is enabled, nothing else
Huh. Well damn. That resolved my issue. Thank you very much. LOL. I had been spending like, 5 hours trying to figure out what I messed up on. The example version didn't have an object sync either since it wasn't suppose to be a pickup. Thank you for that. Thank you very much.
glad it worked! 
I'm like day 2 learning udon and vrc networking and such. I could use some code review on a pretty simple vending glow stick vending machine. Here is the udonbehavior I have attached to each of the buttons on the machine:
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.SDK3.Components;
public class glowstickbutton : UdonSharpBehaviour
{
public VRCObjectPool pool;
public Transform spawnPos;
public override void Interact()
{
Networking.SetOwner(Networking.LocalPlayer, pool.gameObject);
var stick = pool.TryToSpawn();
if (stick == null)
{
return;
}
Networking.SetOwner(Networking.LocalPlayer, stick);
stick.gameObject.transform.SetPositionAndRotation(spawnPos.position, spawnPos.rotation);
}
}
This works fine for one player for sure. But I have a suspicion that this is subject to races with SetOwner and whatnot when multiple people are mashing the buttons at the same time. Would it be smarter to send an event to the master and have the master spawn glowsticks on behalf of the button presser?
You can or you can deny requests until the local behavior finishes its routines
I guess master method requires less moving parts because I would have to have an additional udonbehavior on the object pool that is aware of the state of all the local routines and receives the ownership transfer requests, right?
I think the owner of the object pool is the owner of the objects starting off. You could transfer the ownership of objects but the owner of the pool can always take it back with the return method.
@drifting flame
It is unknown if it'll be subject to onownership request though if you want to deny it. Would be an interesting test
@crisp bone do you know if Networking.SetOwner blocks until the ownership requests are resolved? Debating whether I can just
if (!player.IsOwner(gameObject))
{
Networking.SetOwner(player, gameObject);
}
if (!player.IsOwner(gameObject))
{
return;
}
how do we get networked toggles to work cross platform?
right now, only quest useres can effect toggles for quest users and vice versa for PC
youre hierarchies mights be different between the platforms
I have been wondering this myself, hope someone has an answer. My intuition tells me it blocks, so you first script might be fine. I've seen examples of people doing set owner right before syncing manual vars too. I personally just let the master handle most things, because it was easier to reason about what's going on when I started out.
SetOwner doesn't block AFAIK, it assumes it will be successful until it gets a response back. When a non-owner changes variables of a script you can simply change ownership and immediately set the variable (with continuous sync however there might be a little more delay, havent tried)
"Blocking" is a very specific term related to multithreading. Udon is not multithreaded so everything will execute instantly.
Good point
No multithreading is a good callout. I was sorta assuming there would be some asynchronous i/o going on with the network calls and what not. And that’s where the question came from. Thanks for the info!
no, blocking is not specific to multithreading but can be used in. when I/O is involved and you wait for networking, you can block on a single thread too
I mean, yeah, you can block the main thread but uhh that's not a good idea
depends on the application, in udon, you would choose death 
but for normal cmd programs waiting for user input or network replies, it's very fine
If you are creating an application which is doing nothing else, then sure. But unity has to render frames
even then, it's still not a good practice to block main thread on an application that is doing nothing because windows will consider it unresponsive and prompt the user to close or wait
Technically speaking Udon supports running code on the DSP thread with OnAudioFilterRead. This is executed separately from main thread but it’s a bit tricky to get it working correctly. I don’t recommend using it other than audio processing though, because blocking this thread will block audio you hear
That's interesting. What happens when the response denies? So we use a pool, we SetOwner to us and immediately TryToSpawn. Will it queue up the spawn until the it gets a response and then decides whether to use it or not?
Maybe a bit off topic, but can you find the source code for that in the vrchat application?
is anyone going to make a vrchat wii sports swordfighting
Anything Realtime-PvP is kind of meh, due to the high latency in VRChat.
Its gotten slightly better with regions and having manual sync which has higher priority, but I think its still around 200ms on average which is quite a lot.
If we had access to the latency / connection quality to a player, we could doing... something similar to rollback netcode, maybe? game would have to be designed around it.
it was a duplicated scene
Hello
even though your ping is below 10ms, still you got netIK delay which is at least 500ms I’ve tested before..
It is pretty cray. This was a test I did to test sending a keypress from my laptop in my VRC instance, to a server on the other side of the USA, then create a video frame with data that changes something visually, then I hear the keypress. It really is as bad as you are noticing, @mental mountain
(This tests the difference between ping and IK, and I'm not cheating with ping)
BTW - Udon to Photon server is also usually much much faster than IK/audio sync too, though I haven't done detailed profiling wit hit.
When I tested of sync problem making some mmd world, ping 50ms, udon sync was 130ms < send custom network event was 550ms == netIK==voice(as i know they work together) < continuous sync 700ms.
is using LateUpdate instead of FixedUpdate a good idea for sending custom network events more accurrately?
That really won't change anything
ok
Is there a way to network an animator? I made these elevators and I got them working pretty good. The udon graphs that fire off the triggers are networked but everything in the state machine is not networked. I'm still pretty green at this. I thought about just object syncing the individual elements but it feels like that would collide with the animator. If there's a good resource i'd love to read up
I know when making avatars, there are some extra scripts to sync things, but I don't think that's necessary when making worlds.
In udon, you could use SendCustomNetworkEvent to call an event called "StartElevator" where you use SetTrigger on the Animator.
This way, all clients will execute "StartElevator" and trigger the animation.
ok. I found it strange because for my automatic doors, I'm just using sendcustomevent and its synced for everybody.
I think what im going to do is condense all my animations in to a single up or down animation and use any state transistions with udon scripts calling that and see what happens. When I realize how these elevators work, there only needs to be two animations in total to do everything
Animators aren't synced, everyone has their own instance of it. So your door must be using something other than animators to do that.
ok thats what i figured. I'm gonna try this method since it directly calls one animation via the animator and see what happens
Is there a way to buffer an event like on SDK2 so that new players will see the current state?
I'm guessing I need to set a variable that fires off on entry
I just wanna say I absolutely love udon's networking, it's so easy to set up really good networking!
jeeze, you're making me nervous. I legit can't tell if that's sarcasm or not
I guess ever since the udon network update that's significantly less likely to be sarcasm, but still 😁
Animator can be synced by network I saw my friend implemented it, I’m not sure but you can control parameters inside animator layer by udon sharp, so maybe you can use this?
If it's just a simple looping animation or triggering states what I've been doing is putting an event keyframe at the end of the animation that does a SendCustomEvent (String) to call a method which then (for owner only) updates the animator for everyone via network event.
So it's synced to the owner to either rebind and restart the loop or switch everyone to the same state.
kinda new to networking, trying to figure out the best way I can grab a players name who interacts with a object and put it in a text for all the other players? The closest I have gotten is it the main person can see it but it is blank for others
So what I tried didn't work. This was the next thing I was planning on doing. If I use SendCustomEvent (String) will it call a defined udon event?
Yes you would set that string as the name of the method in the udon script assuming you're using UdonSharp.
And then in that method you would check for owner and call the update/sync method as a custom network event to all.
I assume it can still be done with graph I'm just not very familiar with that myself. I recall there being a node for custom network events, you might be able to have the animation event keyframe call that directly.
its easy to define customs in graph. I just need to test to make sure it works
I'm not sure how it looks like in graphs, just U#. You'll have two objects: one button and one display.
1. The button has an Interact(...) event listener that calls a function on the display (e.g. ChangeDisplay(...)) and passes the VRCPlayerApi.
2. That function on the display needs to call Networking.SetOwner(...) so that the display is owned by the player who pressed the button. When synchronizing, data flows from the owner to other people.
3. After that you need prepare your synchronized variables: I'd suggest using the int type via VRCPlayerApi.GetPlayerId(...) and not a string since that is lighter on data.
3b. Alternatively you can put the code that prepares the synced variables in the event OnPreSerialization() which gets called on RequestSerialization() before sending data over the network.
4. After setting your synced variable(s), you want to call RequestSerialization() to send this data over the network.
5. This will trigger the OnDeserialization() event on all other players in the world which you can use convert the player id back to a string and display it.
X. Put the behaviour sync mode to manual and use the non-interpolated [UdonSynced]
At least that's how I would do it, not sure if it's the way of doing it 🤷♀️
you can use OnOwnershipTransferred(VRCPlayerApi player) and by Interact() - fire event to take ownership of the text panel, to make it easier. and then you can change .text of text panel to player's .displayName 
Why can remote players trigger a network event that has no network event call in the world? There is no sanity check for that?
If you specifically don't want an event to be callable by a network event, you can add an underscore to the beginning
So does OnOwnershipTransferred run for the last owner or current?
i think, for everyone? you can test, if you have an alter account and GotoUdon to run "local" test with multiple accs, but need to manualy fix some errors due to updated sdk
So does ownership transfer happen when setOwner is run?
dont know much, i think that will fire after setowner called and new owner applied
ownership transfer happens sometime after setowner is called and the old owner hasn't rejected the ownership transfer
how would a reject happen?
basically doing a onInteract that set's that person as the new owner of text
ah ok cool
yup, and if ownershiptransfered fire for everyone (i think), it returns new owner vrcplayerapi where you can grap displayName from
oh ok wait
so if I do set owner should I set the owner to the current object (gameObject) or the text object?
I have it set currently to set it as the text object
it should be on the object you want to transfer ownership of
whatever you want, but that object should have udonbehaviour with ownrtransfrd
and ownership is only relevant to synced objects (a.k.a objects with udon behaviour or an objectsync component)
like if I wanted to sync the text, it would be the text object
so I should add object sync to the text then
you can have empty with udonbehav, with reference to text component on another object, etc
and assign owner to that empty
or on object with text udonvehav
objectsync just syncs the position, rotation and scale
gotcha empty udonbehav
so if I do on interact SetOwner of local player to the text object like this
and I reference the text object in script which is RacerName
and the text have this
gotchaaa
no
no?
what you want is to do setOwner on the udonbehaviour itself. and that udonbehaviour then does on ownership transfer: set text to displayname of new owner
gotcha so this and then when the ownership is transferred I just set the text got it ty!
yep. because the text panel cares not who owns it. it just displays a preset text to whoever looks at it
so then out of curiosity
when doing player.displayerName; that just deals with the new owner right?
on ownership transferred does not pass you the new owner. but since it fires after ownership was transferred, you can just getOwner on the gameobject the udon behaviour is on to get the VRCPlayerApi of the new owner
should be
another way if i wrote everything right ```CSharp
public string PlayerNameProperty
{
get => playerName;
set
{
playerName = value;
ChangeText();
}
}
[UdonSynced] [FieldChangeCallback(nameof(PlayerNameProperty))] public string playerName;
public Text UIText;
public void SetOwner()
{
Networking.SetOwner(Networking.LocalPlayer, gameObject);
playerName = Networking.LocalPlayer.displayName;
RequestSerialization();
}
private void ChangeText() => UIText.text = PlayerNameProperty;
should be `[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]` and on ui button you call SetOwner function 
so this should work no?
it doesn't run on ownership transferred for myself? not sure about others
do I have to do a delay or do the variable change locally?
well depents on what you want to happen, i assume this is a manual sync udon behaviour
yeah it is
well basically I want to make it so someone clicks on it, it grabs their name and sets the name to a text
so OnOwnershipTransfered, is a bit of a weird event, i think it only fires for a certain people not everyone
it works fine if I move the
Namestring = Networking.GetOwner(gameObject).displayName;
Nametext.text = Namestring;
into OnInteract
but wasn't working for me when it was under OnOwnershipTransfered
Also if you are already the owner of the object because you loaded into the world first, i dont think OnOwnershipTransfered triggers
ohhh darn
how could I make it work for me then if that were to happen?
besides getting someone else to click it first then I click it again
I mean I could do like check if they are owner already and if they are run what's inside OnOwnershipTransferred right?
I think if you do GetOwner inside OnOwnershipTransfered you probly get the same player as the in the playerapi paramater as its already transafered
but not 100% sure on that i rare work with OnOwnershipTransfered events myzelf
what i would recommend it is adding synched variable of type string, like currentOwner
then in OnInteract(),
if your not the owner, claim it and set currentOwner = Networking.localPlayer.ToString() then request serialisation and then directly call OnDeserialisation()
Then implement OnDeserialisation() like set Nametext.Text = currentOwner
well that way it wont properly sync, you got to call requestSerialisation() after you change the variable
if in your example NameString is a sycnhed udon variable, then you need to call RequestSerialisation() after you change it, and you change it after you claimed ownership
i think you should move away from the OnOwnershipTransfered
RequestSerialisation only works if you are the owner (or if you ran SetOwner to Networking.LocalPlayer)
so like in this pic for example
I could put it with the if networking.isOwner
bc it changes it and it's the owner
yes i think so
and then for On Deserialization
So OnDeserialisaiton() get called when a synched variable was send to other clients
So thats where you use the value of the synched variable and assign it where you want it, so in your case
Nametext.text = Namestring (assuming Namestring is a synched variabe)
yep it is cool so I got that already
also
would the OnOwnershipTransferred have a issue if I don't use request serialisation?
bc for example
actually
nvm
@lean silo here is how I would do it, syntax might not be 100% since I wrote it in a notepad lol
public class ChangeTextViaSync : ... {
// The currently displayed playerId
[UdonSynced]
public int playerId;
public string textFormat = "My name is {0}";
public void ChangeText() {
var me = Networking.LocalPlayer;
if (playerId == me.playerId) {
// No need to sync playerId since it's already set to us.
return;
}
// Change owner to self
Networking.SetOwner(me, gameObject);
// Set data and sync
playerId = me.playerId;
RequestSerialization();
// Update text for new owner
UpdateText();
}
public override void OnDeserialisation() {
// Update text for late joiners and when ChangeText() is called.
UpdateText();
}
private void UpdateText() {
var player = VRCPlayerApi.GetPlayerById(playerId);
if (!Utilities.IsValid(player)) {
// Handle unknown player
return;
}
var text = String.Format(textFormat, player.displayName);
// Do things with text here, like setting an UI.
}
}
notepad, the ide of champions
personally i use google docs, but hey, notepad works if you have no connection
I feel like you could write better in discord itself because you can get syntax highlighting
Hey if someone can help point me in the correct direction/methods I need to use for this networking issue. I have candles and a candalabra. All the gameobjects have a VRC Object Sync component. So all players can move them. The canadalabra has a hitbox trigger on each candlestick, and if a user lets go of a candle in the candle stick, the candle teleports to the correct location and becomes a child of the candalabra (inserting the candle into the slot).
In single player it worked great. When the world went live, it had networking issues wherein the new players didn't have the candle childed.
Is there an event/method in Udon that would allow me to pass a transform to all players to specify it as a gameobject's parent? I'm building this with U# if that makes any difference. Thanks a lot for any advice!
that doesnt sound good because network is dependent on the scene hierachy. By parenting the transformation you are changing the network hierachy, causing desyncs
it might be better to just not change the parenting and do the transformation manually
You mean just update the position + rotation every frame without childing the object?
yeah
but im not an expert on networking so I can't say if its possible to do parenting. But in VRChat you get desyncs if you upload a world with different hierarchy from the previous version.
a world stays in sync with it's previous version as long as it has the same scene hierarchy, so preserving the hierarchy is super important.
Hmm
So that leads me to my other question, in Udon is it possible to pass parameters to networking events?
you are not using udonsharp arent you?
I am.
If I want the candle attached to a particular candlestick, I want to be able to specify that candlestick's transform in an event to inform all players it's attached.
Unless there's a better method of doing that.
from what I feel, i think it is necessary to assign each candle an ID, and during the attaching, pass the ID to everyone
I can do that.
Udon events allow passing an ID?
This is my first VRC map, so while I have a lot of fullstack developer experience, I don't know what can/can't be done with VRC.
that doesnt seem possible, but i can expect you can add a "int ParentID" and initialize it to -1 when there's no parent
and when its parented, change that ParentID and call RequestSerialization
so in the FixedUpdate loop, if the ParentID is not -1, change the transformation.
Mmm yeah that'd work.
yeah sadly i feel this is the only way to do it since networking is dependent on hierachy
I'll download the udon networking package to see what samples they provide.
- Have a UdonSynced int ParentID, initialized to -1. Use Manual Sync for the fastest update.
- When a player move the candle, set the candle's owner to that player.
- When that player attaches to a slot, change ParentID to that slot and call RequestSerialization() to sync variables. This causes all other players' candle's ParentID to get synced.
- Update the transformation in the update loop based on the ParentID.
if this helps, this is pretty much what you need to do to get this to work!
That is exactly what I needed to hear! 😄
Could also do an area trigger over the candelabra holder areas, and when detecting on drop of a candle, toggle off the pickup and toggle on a stationary one already fitted to that slot ?
I considered that! I also want players to be able to then remove/move the candles from the slot afterwards and I figured that's where it would start getting buggy.
(ops actually i think you'll need continuous sync since there's also position syncing)
I may be able to do a hybrid of your two methods, keeping the candles synchronized using k0sm0s' method but showing/hiding the visuals using Fooma's.
That would mean when a player is wooshing the candalabra around, the non-interactable candles would move with it flawlessly while there will still be a real invisible one tracked underneath it the player can interact with.
Ok now I'm excited for work to be done with so I can try all this...
https://buildsoft.booth.pm/items/3159749 check out this grid snap system, it sounds a lot like what you want to do
[説明] CAD、そんな感じ 現在は点グリッド・線グリッドをサポート グリッドを高速で振るとオブジェクトが離れますが、仕様です。 [導入方法] UdonSharp の最新版が import されているプロジェクトに導入してください。 https://github.com/MerlinVR/UdonSharp/releases [利用規約] 改造OK VRChat での利用OK 改造・無改造にかかわらず、無償での再配布OK。 改造・無改造にかかわらず、有償での再配布はNG。 ただし、他の創作物の一部として同封する場合に限り、クレジットを表記した上で有償での再配布を認めます。
Ooh that might save me some trouble. I hope the grid itself can be attached to a pickup.
you could have invisible candles already in place and enable them based on a synced array
one index/element for each candle
getting close to the slot will then snap
Dipping my pinkie into some territory I thought I had mastered before, but am having strange issues so here I am. xD
I'm trying to figure out what the best method is for detecting on a specific udon script that it's owner has left the world. OnOwnershipTransferred was how I thought it worked, but I'm having some strange issues with it.
Can I send a serialization request to another Udon script from one that is set to a Sync Method of None and have it go out to all players? (Ie; push button, tell other script it needs to sync for all players) Or does it need at least Manual sync so the serialization request goes out to all players rather than just the local?
The serialization "request" is not a networked request. It simply sets a flag for the underlying networking manager to know when to serialize the data and send it to other players. So to answer your question: Yes you can.
Cool, I thought it'd work something like that but just wanted to make sure.
[UdonSynced] [SerializeField] int PlayerID; //not syncing?
why does this return different values on my two clients?
public override void Interact()
{
PlayerID = Networking.LocalPlayer.playerId;
// Hair.SetActive(false);
// LocalHair.SetActive(true);
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "SetTransformVars");
}
public void SetTransformVars()
{
Debug.LogError(PlayerID);
Player = VRCPlayerApi.GetPlayerById(PlayerID);
Go = true;
// }
void Update()
// {
// if (Go == true)
// {
// Hips.position = //Player.GetBonePosition(HumanBodyBones.Hips);
is this manual sync?
i really would just switch it over to manual sync and do that
if i set it to manual, i have to do RequestSerialization(); before the debug line?
your code is a bit of a mystery to me
with manual sync, you need to be owner of the behaviour you want to sync, then request, and you can do everything inside OnDeserilization instead of a custom networked event
right now, you won't even know if continuous will sync before the event arrives
good luck
perfect, got it working first try, not something i say aften lol
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
public class TakeOver : UdonSharpBehaviour
{
[SerializeField] Transform Hips;
[SerializeField] bool Go;
[UdonSynced] [SerializeField] int PlayerID;
[SerializeField] VRCPlayerApi Player;
public override void Interact() //interact with object
{
Networking.SetOwner(Networking.LocalPlayer, this.gameObject);
PlayerID = Networking.LocalPlayer.playerId; //get player ID who selected button
RequestSerialization();
Player = Networking.LocalPlayer; //get player who selected button FOR LOCAL PLAYER
Go = true; //start update loop FOR LOCAL PLAYER
}
public override void OnDeserialization()
{
Debug.LogError(PlayerID);
Player = VRCPlayerApi.GetPlayerById(PlayerID); //get player who selected button FOR ALL PLAYERS (except local?)
Go = true; //start update loop FOR ALL PLAYERS (except local?)
}
void Update()
{
if (Go == true)
{
Hips.position = Player.GetBonePosition(HumanBodyBones.Hips); //set position of object every update tick
}
}
}
``` here the code if your intrested at all lol
just wondering, if you try to claim ownership of an object under heavy network stress, will it evently transfer or is there a chance the attempt will fail?
it will eventually transfer
if only one player is trying to take it you can be pretty confident that it'll go through even under the heaviest situation. But if multiple people try to take it, there's no guarantee what order things will happen so they may get mixed up
it should still eventually stabilize but hard to say what variables will get through to other players
ok thats good to know, i didnt know if i had to do a retry or not
it's pretty safe to assume that given enough time to deal with latency, everyone will agree on who the owner is
but it is not safe to assume that messages arrive in the correct order
so it can be good to retry synced variables
I need help with teleportation. I'm trying to teleport users to a specified location with whitelist. IS anything wrong in this code
Hefner is the gameobject, Players is the array with whitelisted players that are allowed to use the teleport function and selectedPlayer is a VRCPlayerApi of the player that should be teleported
you cannot teleport remote players, that means, only a local player can teleport itself
but how does worlds do it with private rooms. I've been to private rooms where if you click a player in the player list they get teleported to the private room
Instead of directly teleporting someone, you can tell the selected player "hey, teleport here".
So you would send that message to the client, who then teleports itself locally.
Can you guide me in the right direction on how to implement that in code? I'm not really sure how I send that msg
I've got this right now, am I doing something wrong?
I can teleport myself but I can not teleport other players
so you want to teleport a specific player, but only if they are on a whitelist ?
or you only want to teleport a selected player if the person initiating the teleport is on a whitelist ?
I want to teleport a specific player but only a whitelisted player can use the teleport function
second one you wrote
how is selected player set ?
selectedPlayer is an playerAPI that gets set from a playerlist
got another question, on the OnPlayerLeft event, the player returned, is it possible checking its display name could result in an error? I have an instance which im trying to narrow down where the code crashed during when a player left it broke on VRCSDKBaseVRCPlayerApi.__get_displayName__SystemString, and im curious if that could be a breaking point
sync the playerid, hmmm. Alright. I'll google some to see how I do that
[UdonSynced]
public int _playerIdToTeleport = -1;
override void OnDeserialization(){
if(Networking:Localplayer.playerId == _playerIdToTeleport)
_Teleport();
}
oh also, i am not sure, but i think if you put an underscore in front of your method it cant be called over the network
ooooooooooh
so looking at my debugger, i can say for a fact it broke calling player.displayName from the OnPlayerLeft(VRCPlayerApi player) event, im wondering if this is a bug
@strange oriole thank you for all the help but it still doesn't work 😦 Feelsbad
I still can only teleport myself
public override void OnDeserialization()
{
if (Networking.LocalPlayer.playerId == playerIdToTeleport)
{
Teleport();
}
}
public void Teleport()
{
foreach (string _str in Players)
{
if (Networking.LocalPlayer.displayName == _str)
{
playerIdToTeleport = selectedPlayer.playerId;
SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "Teleportation");
}
}
}
public void Teleportation()
{
if(Networking.LocalPlayer.playerId == playerIdToTeleport) {
Networking.LocalPlayer.TeleportTo(Hefner.transform.position, Hefner.transform.rotation);
}
}
That's what I got. I can still only teleport myself :/
not sure if it helps your conversation, but what i've come to find is you can only really teleport yourself. So you have to set up who needs to teleport, tell them to teleport, then locally to them call the teleport method on themselves
I'm pretty sure that's what I'm doing with that code
I send an event to the entire lobby and if their playerid matches the one I want to teleport it calls: Networking.LocalPlayer.TeleportTo(Hefner.transform.position, Hefner.transform.rotation);
Have you looked up how OnDeserialization works when you have manual sync on an Udon object? You don't want to send an event anymore, only the playerid. Then request the serialization so everybody receives the new value. When you receive the new value, only then do you actually execute the teleportation. That's how Thryrallo's code is supposed to be used.
ngl, I'm super drunk rn but I'll save this. Thank you haha
I noticed that to be the case as well. I don't remember how I dealt with it though, except switching up my approach.
oh somthing else, never call teleport from on deserialize. Set up a timed event to call it after. Dunno what it is but if you call teleport during on desterilize it mucks up teleport
right now the way im dealing with it is only treating that player as a memory reference and comparing it to a player list i create myself to verify if its the same object
although i dont know if it will work 100% of the time, as it might get a cass of null == null
Yeah, that might be an issue. I used ownership to detect when a specific player joins or leaves. The owned objects holds data about the player, like my own identifier, which I can continue to use without it disappearing like in OnPlayerLeft.
No idea if there is a better way.
Hey k0sm0s just wanna inform ya that I followed your advice here and it worked! My objects are now all fully synched properly. 🙂
im hella drunk
In OnDeserialization call "Teleportation" not "Teleport". If you use manual sync, dont forget to call RequestDeserialization
Do not call TeleportTo from OnDeserialization. It messes it up. You need to defer Teleports to the next Update call.
not really must be the next Update call, as mentioned before, sending a delayed event is fine and will teleport without needing Update, since Update can have an overhead
I said it should be deferred to the next update call. Doing "SendCustomEventDelayed" will simply call it during the Update phase.
I didnt say to put it into Update :P
Thank you all for the help! I'll take a look at in a few and see if I can figure it out. Such a nice community in here tbh. Thank u thank uuuu 😄
i just wanted to make sure nobody misunderstands it, it was not directed to you but to people who read Update and then try to do things that way 
Yeah I wanted to include that originally but too lazy
Hey I was just wondering if there's any tools to facilitate debugging network issues? Something that allows me to check who currently has ownership or the state of a variable on each client?
So I changed my event to this but now the event is not fireing. Did I misunderstand something?
is Teleportation a custom method/event? if so, please show us the code
if not, make a method and call it _Teleportation and perform your action in that (note the underscore prevents remote clients to send networked events to that method)
you can also use nameof() on udon methods to generate strings of them, prevents typos
I'm pretty sure I must have it without _ or else I can not use it in
you can, but you cannot do a networked custom event
oh, alright
wait, so that event isn't networked? so I can't use that event to teleport somebody with (the delayed event)
no, there is a different function with a networked word in the name
who is calling this? the remote player?
is this in Deserialization?
should add logs
check if the function is called
who is the user and what ids they have and need to have
Okay so, a whitelisted user, can select players from a playerlist. When a player is selected it saves their playerid in a synced variable. Then it calls Teleport when the whitelisted user presses a teleport button
and teleport sends the event with Teleportation
I had the same code yesterday but used the networked event instead and I could only teleport myself. I could not teleport other users
let the selection set the id,
the button requests serialisation,
users check in OnDeserialization if the id matches, then issue the delayed teleport
ensure the user clicking the button owns the gameobject with the udon behaviour or sets the ownership otherwise
so basically all I have to do is add: RequestSerialization(); in my teleport function?
and move the send customevent to the desrializaiton
@warped ore
Teleports a player by name. I tested it and you don't seem to need to offset teleportation by a frame.
Ehm, it teleports them into a wall
it works but, yeah 😂
nah
I teleport to a gameobject I have
I can teleport to the game object with my keypad
but when i teleport someone they fly into a wall
It's funny as hell but not really what I'm looking for hahaha
ah, that might be that issue Helper was talking about then
Maybe this is why you need to delay it
Thank youuuuuu
👍
I just had a weird bug that my friend that I teleported got teleported twice. It might've been cause someone else joined right after they were teleported. I'll have to do some testing on it
yes, this happens cause OnDeserialization get's called when a player joines
gimme a sec ill fix it
@warped ore here you go, a beautiful bit flag to fix it
yeah, I thought that was the issue. Should the "lastTargetPlayerId = targetPlayerId" really be outside of the IF statement in the onDeserialization()
yes
oooh, now I see
(it might actually be okay inside, but i havent tested that)
I was just gonna put it inside and everytime it when inside the IF statment it just reset the playerid to -1 and use the check Utilities.IsValid(VRCPlayerApi.GetPlayerById(playerIdToTeleport))
yeah, i guess resetting it to -1 would work too. Would be a little more network usage, but negligible
If using bitflags is better I'll just use the code u sent. I've never read about bitflags tho. Might read a bit about them now
Turn on GUI debug then right-shift tilde 8
What is Debugging? Debugging is how you learn about what's going on under the hood in the VRChat client and your world. It's a key skill to develop for programming in general, and for building your worlds. VRChat Logs When you use the VRChat client, it saves logs about things that happen like worlds...
Oh damn cool I'll try that tonight. Also, I test my code using CyanEmu and I never succesfully connected a VisualStudio debugger to UdonSharp code. Is there a way to get that working or is that not feasible?
For now I'm managing using Debug.Log but if I can get a breakpoint working that'd be rad.
There is this but I haven’t really played with it yet …
Ah girl you're amazing. Thank you so much! 😄
Another day at work just fantasizing about getting home and working on VRC stuff again~~~
Hewo, there is a way to get the player API (local) when you click on a button sending the "interact" event in udon ?
I Was trying to use "Get LocalPlayer" for edit the Voice Gain/Distance, but looks like the udon component crash when the event interact trigger the udon script
Interact is always local, so you can safely assume and get local player. But setting the local player's voice settings won't do anything because voice settings are not synced. Instead, you need to sync variables or events in order to tell other people that they should set your voice
Hmm... Okay i see, i'll put some times on it so ^^"
I have some boulders that i want to be destructible if the player that enters their trigger at a certain speed
I want it to either be clientside so each player needs to break their own, or synced where the boulder breaks if anyone touches it, but right now it just desyncs and the boulder breaks for the first to hit it but noone else
So i've done some testing, and it seems that Onplayertriggerenter only triggers twice, then doesnt reset
text sets for one player, is ignored by the other
does setowner disable the script for local players entering a trigger?
can you put a bigger screenshot of the entire udongraph?
it kindof works now
it just runs a network synced bool and im not bothering with clientside anymore
ah good for you, but that screenshot's still tiny haha..
so wanted to verify something. Does the owner of the object need to call RequestSerialization() on a manual object the same frame as the object changed? I saw there was a recommendation that you change the value in PreSerialization but ive been able to change a value and then request serialization with no issue, tho as of late im seeing a weird error when I RequestSerilization some frames later when the network isnt clogged:
ERROR: [Behaviour] Caught ArgumentNullException: Value cannot be null
does not matter when you call it, all RequestSerialization does is requesting the network system to send the data to the remote players, you can request the serialisation and then still change values, they also may be sent, as the network sending does not happen instantly nor will it prevent changes
your error often refers to a method/function being used incorrectly, is that the full error?
It does not request anything. It sets a flag. The network handler has an internal timing for when it serialize the data. If the flag is not set it will simply skip serialization. So when you call RequestSerialization all it does, is set a flag to tell the network handle to serialize the data the next time it does. So yeah you can in fact change the value in-between calling it and the serialization actually happening.
by setting the flag, the user is requesting the data to be serialised, you are pedantic here imo, i don't think we must explain every intrinsic to people new to networking, abstractions are helpful
Well the problem is that "request" especially, in the world of apis is usually an active act where data is being sent somewhere. While this is a request, it's a rather passive one. So the potential for confusion is quite high there.
i agree with you
ya i understood it sets a flag, which is why i was curious if i set the data a long time ago, then request searlization to flag the next time to serlize the data, if that old change doesnt get pulled. My suspesion is they have a way to check when data is changed to optimize how much data gets synced
when i switched my code to requesting serliazation the same frame as when the data was changed, that error went away. I dont think it was that it requires the same frame for the data to be set, but i think the data it pulls has to be resently changed data
since the only way to use the method is call RequestSerlization()
also should add, by changing my code to request serlization within the same frame of the code change, all my code started working as intended
as a reminder, this wasnt an issue of changing the data after calling RequestSerialization, this was an issue of changing the data long before calling it
like potentially 0.6 seconds before
requestserialization should send all data no matter what
when you changed the data a long time ago, are you sure you were even the owner?
yes, i have a system where i have my own player list that keeps track of what i call player callers. Each player caller is assigned a player where they are set to own said caller. I also have a queue of commands in a string (local only) to each player, that on a timer ever 0.2 seconds checks if the network is not clogged, and if its not, it interprets the next line in the queue. These are all intended to be actions that effect the network, one of them being RequestSerilization. When i was doing changes to certain synced values, i was changing them, then adding to the queue a command which when it ran through the system called RequestSerialization. In essence, depending on how bogged the network was, could take anywhere from milliseconds (when the timer gets called) to seconds (if the networked is bogged down and the timer tried several times). When i changed it to instead of going through this queue to call RequestSerialization to just calling it the same frame, everything started to work and properlly sync the data. I will note this method i used use to work in the past,
unfortunatly, ive been changing the code over the week a lot to try and optimize features on it since i need it done by tomarrow, so its not in the same state as it was before. When i get the changes working ill try to set it up to the way it was before and see if it was a fluke where i missed somthing, or indeed a problem assosiated with the timing when to seralize
oh also, wanted to ask, So if i set a value, requestSerailization, then call a networked event, is there a possibility that the event will fire off before the values are synced? so far all the code ive written, even when the system is super bogged down, the items in a manual synced object always seem to sync the values before the event triggers, which seems pretty fantastic
Manual sync in a good situation will have lower latency than networking events, yes. However if the network is clogged (as in, you are sending a lot of outgoing data) there is the potential for manual sync to be delayed, and it would arrive after a network event sent at the same time
hmm..gonna have to note that and try to think of a better way to do networked method calls with parameters in the future
yeah, just do stuff in OnDeserialization
I had a huge issue with that, OnDeseralization seemed to fire off when people joined, causing values I thought should be one thing end up flipping to another. So if i set a value intended as a method, the logic would fire off a second time. Maybe i can find a better way to do it but i tried my best not to use the method
oh, one last thing. My code for my player list worked great up till resently. I posted bout it but seemed the information tied to the returned player in OnPlayerLeft can be flawed. Had a debug log error out an udon script because calling that player was miss referenced. Know anything bout that bug?
yeah, you can't ever rely on OnDeserialization happening just once. It is not a message system, it does not guarantee that
if you want to guarantee unique messages, you can simply add another variable like a timestamp and then if the timestamp hasn't changed since the last OnDeserialization, you know it's not unique
true could do that
but gotta figure a way around the OnPlayerLeft bug before i work twords that optimization
don't know about that, but at the same time OnPlayerLeft implicitly tells you that player left so can't you just manually invalidate them, remove them from your array, whatever?
if the returned value is null, how do i know who left?
ooo you mean go through my list and verify who isnt valid anymore
ya, that could work
no, you can do comparisons in onplayerleft
go through your array and check if it matches the player that left
i was doing that, and i dont get a match
hm, I've been doing that since before getplayers was a thing and it worked
this is with each of my object containing a VRCPlayerAPI of said player, and doing a player == player comparison
thats what boggled me
it was working before, so i was wondering if somthing changed that broke the reference
do you do a .Equals or a ==?
ill also need to triple check i dont have anything unsetting my player
there is an obscure bug that if you never reference a player (eg upon join), they may have a bad player id when the player leaves
seems that bug does extend to their display name, i tagged that onto the canny that i saw related to that bug
btw, i just found that indeed my code was unsetting my reference to the player before onPlayerLeft event fired off. I now have it set it up it wont do that
What's UDON?
What’s this Udon thing anyways? VRChat Udon is a programming language built completely in-house by the VRChat Development Team. It is designed to be secure, performant, and easy to use via the VRChat Udon Node Graph, a built-in visual programming interface that uses nodes and wires (we call them “no...
More like C# in a Bolt format. Even more like C# if using UdonSharp. But unity supports various languages so it doesnt matter as long as you convert it to Udon.
Ayyy, I'm back with another question. So I got this spinner from a drinking game but sometimes it decides to either stop spinning at all or land at the same location every spin. Is there something wrong inside of this code? I'm not really sure what it could be.
SyncSpeen is sent by/to owner but no where do you actually set an owner. I guess technically the instance master is the owner but if you are looking for dependable then the person interacting should be the owner.
Interact should probably call Speen, and not SyncSpeen
also if manual synced you need to call request serialization
no owner setting needed since the synced var is set by the owner via network event
Been trying to find some clarification in the docs with no luck, but I assume using _Underscore() method names to block malicious network event calls is only necessary for public methods? Or do they somehow have access to private ones too?
I've seen people using them for variable names too which is also throwing me off, just trying to figure out what all I need to actually worry about renaming.
Udon doesn't have a concept of public and private functions. UdonSharp compiles private functions by not even exposing the name anywhere, it's just a jump address that only the compiler knows
and putting an underscore in front of a private variable is just common code styling, it doesn't do anything functionally
Ok awesome, yea forgot to clarify I'm using U#, will just rename my public methods then. Thanks!
Thanks yea I saw that but it didn't specify private/public and I hadn't thought of the graph/# distinction. Makes sense now.
to clarify: making it a private function is still valid. And an underscore is not necessary in that case
ah, okay, i missed that distinction (in the question)
it's even safer than underscore because modded clients can't even call it on their own machine, let alone others
always use underscore if you attend the event to be local only at all times
You can also now use the Networked Mode "None" as it will make the object completely invisible to the network handler. (That is as long as all the bugs have been fixed...)
simple button that spawns from pool. For some reason only instance owner can spawn. Is vrchat checking owner by default?
Only the owner of the object can spawn from the pool, so you need to transfer ownership before trying to spawn
Thank you ❤️
How can I make an object sync their position over the network. I have the VRC Object Sync script on it. But when I spawn it. it just kinda freezes position on the NON master clients: (Master Client on right) I want it to fall. It has Rigidbody and I spawn the cube using VRCInstantiate
instantiate isnt synced, use object pool instead
:I let's not talk about my stoopidity 🙃
Wait so do I still need to call it from a SendCustomNetworkEvent for it to spawn on EVERY client though 👀
Your trying to do something similar to me it seems. I'm trying to get an object from the pool to spawn on every player that joins, and in my case stay attached to them then return when they leave the game
I can get it to spawn on join and go to their hip bone, but no luck making it follow them.
Yes I want something like that. So I want an object to "spawn" (Grabbed from the pool) than it goes from point a to b after x amount of time
What's your object actually going to do while tethered to the player? Is it something only they need or needs to talk to other instances of itself on other players?
i need the udonsharp form merlin fr the 2019. i think its 2021.3 or something
Make sure you are using the latest VRCSDK
If you are upgrading from Unity 2018, follow the upgrade instructions https://docs.vrchat.com/v2021.3.2/docs/migrating-from-2018-lts-to-2019-lts pay specia...
that is the current version
you do not need or want an older version unless using an outdated sdk in which case your on your own
im having an error where it says its missing ascript of vrc. its cs0234 and cs0236 and i put the newest vrcsdk3 in FIRST
also thats for the 2018. im using 2019 and there is a 404 error when i click on the upgrading
no its current. Dont pay attention to the 2018 bs. readme needs update
not that it matters but here is the migration doc https://docs.vrchat.com/docs/migrating-from-2018-lts-to-2019-lts
Migrating your project from Unity 2018 to 2019 LTS isn't as difficult as you might think! Here's a guide providing each step in detail.
Ok but im still getting the cs error even for my world now with that version
Show your errors
hint / question : Which window is the owner of the cube if the cube is a pickup ?
I will be honest XR I can't remember anymore 👀
I kinda stopped making VRChat worlds imma just focus on actual game development and bot development. My brain is too smoll for VRChat worlds
Can someone join me right now so I can test object sync if its working for late joiners?
One way to test it yourself is to enable 'Go' on load & start multiple test clients via Unity
All my clients loaded at the same time
So does not really help
unless there is a way to intentionally block one from joining until im ready, regardless it does not work
if anyone knows how vrc udon networking works can i get help making the state of an object to sync with late joiners
Disable "skip go button" in settings, thus you can enter the instance late
@vestal radish There's a setting on the far right tab of the VRCSDK control panel that adds a 'Last Build' button or something like that which you can use to hop in on separate clients in the same instance without building them all at the same time.
u replied to me but talk to someone else?
The response was for both of you, so yea.
Matswaps in worlds a thing or no
yup define new_Material GetComponent<MeshRenderer>().material = new_Material;
Just want to double-check; Is this an ideal/optimized use case for a Manual Udon script? Bool value stays largely unchanged, only toggles when object enters detection cube.
this won't sync at all
after you marked your variable as synced, you will have to ensure the object owner (only object owners can request syncing) of the object with the u# graph component will call RequestSerialization after you changed the variable
Cheers, I haven't messed with Manual sync much.
Quick question: Will the OnDeserialization() still being called if it's set to Continues syncing?
yes
Got it. Thanks!
What's the max data send rate for manual sync?
About 18kb/s
are fast paste pvp maps do able on udon or am i going to run into network problems and limits with udon?
you are likely going to run into ping/latency issues instead
vrchat has no networking engineered towards fast pace pvp
nor any special internal routing like some games offer
Got a general networking question; I'm looking at the debug screens in-game and I'm noticing that network hitches is constantly increasing for players who aren't the world owner. Is that normal, or do I need to go bug hunting to find what's causing that?
@sharp tinsel could i dm you to ask you some stuff i saw your ghost world
How to enforce ownership
Should I check If (I'm not owner): Set me as owner
In Update ()
Or in LateUpdate()
Does it matter?
why do you need ownership? what do you want to do?
both suggested ways are not good ones
ya sure.. very surprised you find me lol
It was in your vrchat bio :3
oh, hahah
is get players with tag still broken?
what are you trying to doing?
When is it better to use methods to modify game objects and when is it better to use an animation?
Seems pretty much anything could go either way
If you are safe you can use either one. Animations are updated per frame every frame so when they are not in use you deactivate them. You won't find many tutorials that explain that though. I'm old school, I script almost everything, and just like Animations, if you are lazy with your scripts you can tax your performance as well. So basically it's just "you do you".
if you need a specific situation it would be networking. If something needs tracked for sync you are better off scripting it for now. object sync will in time cover Animations I am sure but for now, those should be scripted.
How can I stop this cyan trigger from teleporting other players along with me? Doesn't seem to be completely local in game (edit: just switched the first tab to VRC_Direct instead of Local player after reading the manual, hopefully that works)
your trigger seems ok to me but no idea what's inside player input said....also maybe remove udon behaviour to make it auto regenerate to fix could be...
(if it VRC_Direct, it will teleport all players.)
I will try that thanks, I didn't think of removing the udon behaviour tbh
it will re-generated anyway if you removed. sometimes....it bug out...
If you need further help, Cyan got official support discord at "JHA3ZQ5mXM" as well.
is there an overlay i can enable somewhere to see the synced variables of an object?
use in-game outputlog function.
(require lanch parms)
I think it is option 3 IIRC.
Apologies if I'm miss-reading your question (or if you've already solved it by now), but isn't this because your not breaking it down when you search? When finding a node, you first find the component type and then you say what with said component. In terms of VideoPlayer.get IsPlaying node, you would first search up 'videoplayer', selected it, and then search up 'get isplaying'. You can't search up 'videoplayer.getisplaying' as a whole in the search, you have to search in two parts
Sorry for the ping then. Just that your image didn't show so I though I better check
try using tab to do a full search instead. It will be slower, but it will give you absolutely everything without having to go inside a directory
Hi. I'm currently trying to create a vehicle switcher for Sacchan's Flight and Vehicles prefab. Locally, things work perfectly fine, but I'm having issues getting the owner of the buttons to change. So far, I've gotten it (mostly) working, however there are some issues.
This graph is applied to all "Toggle" buttons
This graph is in the "Script", which is the sort of main control for the selector. This is the only networking related part. The reason I have it doing the same thing on the request and transfer is because non-owners were having to press the button twice. (I haven't tested if this even works yet, so just pretend the request part doesn't exist for now).
"selectedHeli" is a synced variable, while "tempSelectedHeli" isn't synced
There are many issues with the selector, for example, it will select a seemingly random helicopter on the first ownership change
Are you trying to ensure that you first get ownership before you sync a variable? That's what it looks like to me. Afaik, it's enough to just do SetOwner -> set synced variable for the value to propagate to everyone else. This could vastly simplify the code and you won't have to deal with the issues you are having now.
I tried that before, and it refused to set the owner
This way actually works at the very least
It's just extremely buggy
It seems to select a random helicopter on first ownership transfer
Is selectedHeli manual synced?
Yep
Then you have to do RequestSerialization to propagate it to everyone else.
Ah okay, that will probably solve all of my problems then
Yeah, try doing Interact -> SetOwner -> set selectedHeli -> RequestSerialization, then should already do what you want. Then you call OnDeserialization and execute the actual heli change.
The actual heli change is all local and happens on update, it's just listening for the synced variable which is used to define an entry in an array
Yeah, you can listen to a change of selectedHeli each frame. However, that's what OnDeserialization is created for, it will only trigger if the value actually changes by someone else.
Right but what about late joiners
So you can save yourself some frames.
That works too.
They receive OnDeserialization when they join.
Yeah, best of luck and merry christmas.
Merry Christmas to you too, and thanks for the help
do you have a VRCUIShape on the canvas?
then you don't need to worry about that, because that script will assign the event camera
so when you point at the UI, does the laser show up?
what layer is this on?
put it on default
UI is for internal stuff, not world things
Are you getting any errors in your log?
add some debug logs to see how far the code is getting and what it's doing
add a new node, search for debug
yes
and then add a string const node to plug into the debug log
place these wherever things happen so that you can later look at your log and make sure things happen when you expect them to
like this
that's not necessary, don't worry about it
If a Client wants update a networked value of a program, do I have to transfer ownership first
The client who is updating the synced variable must be the owner of the object, so yes
IS there anyone around that can help me test performance
is there a way for custom events to call methods with arbitrary parameters?
no
there are many alternatives, though. If you give more details about what you're trying to do I could recommend an alternative
I want Clients to be authoritive in adding themselves to a VRCPlayerApi[] which represents the players in the game I am developing
ah, like a "I want to join red team" kinda thing?
Easiest way would be to simply take ownership of an object, change the array, and then sync it as an int array. Realistically, manual sync is fast enough that it might work even if two people click it at the same time, as long as you're not using OnOwnershipRequest
I was hoping to avoid taking ownership of the manager since hypothetically, 22 people could be wanting to join at the exact same time
if that's not acceptable because you expect a large number of players to sign up very quickly, the more robust but complicated option would be to give a unique object to every player
and usually in a game, it's very useful to have a unique object per player for many other reasons anyway
for that, you can use something like this https://github.com/CyanLaser/CyanPlayerObjectPool
I'll probably go with that. Is there a way to properly make a relation between an arbitrary value and a player where programs can access it?
Oh. Wow
even in test mode?
I see. That's handy
Thank you for the advice. My work around would have been the physics host being authoritive in determining who's on what team, but I don't want to network what I don't have to
working with Arrays is also jank since I'm coming from JS which is very high level
I need help setting up some simple actions that look for any player in an instance pressing a keyboard key and triggering an action. I've tried it with Cyantrigger but it seems that using simple if statements for checking 20 different keypresses across everyone in the world fudges frames. I dont know a better way of doing this or how to check this locally and send the event to everyone else...
could you clarify what you mean by "fudging frames"?
I forgot how to do simple networking stuff
is there anyone i could DM my code example for some advice?
Is there a way to make it so OnOwnershipTransferred doesn't call when the master leaves and a new master is chosen?
My method for sort of "bypassing" this right now is this, but I can see this being an issue that will require the master to press the button twice to actually change the variable
Right now, when the master leaves, all the helicopters in my world get set to whichever one the new master last chose, which kicks people out of their helicopters
To detect a master change, you can cache the previous master and then compare it to the new one.
Not sure if what I wrote will actually help you though. Using OnOwnershipTransferred to change the helicopter looks a bit sus to me.
So basically store all the variables and when the master leaves, send it to the new master?
It's only for when a non-owner of a button presses the button
They have to first take ownership of the script so they are able to change the variable
Are you not using OnDeserialization?
Hmm you might have a point actually lol
Idk how it works tbh
There's no good documentation anywhere about how it all works
I was told by someone that it takes time to take ownership of something so I should use OnOwnershipTransferred
Changing a synced variable requires ownership of the behaviour object, does it not?
It does require ownership, however, if you call RequestSerialization after SetOwner, it should arrive properly.
This has worked for me so far.
Even if it's in two different behaviours?
Basically, the OnOwnershipTransferred part happens in the button graph, and the requestserialization happens in the main graph
Ahh, I think I understand now. Sorry, graph is a bit hard to read for me sometimes. It's also a bit different than what I would do.
Yeah I should really just learn U# shouldn't I 🤣
If there's a way I could get around using OnOwnershipTransferred, that'd be awesome
Maybe I could do SetOwner in the main script? Instead of checking for owner in the button script, just send the custom event no matter what, and on the owner check in the main script, SetOwner and then RequestSerialization
Yeah, I'd definitely use OnDeserialization for this. It will be a lot cleaner. Basically as I wrote before, literally Interact -> SetOwner of Sync object to local -> change selectedHeli on Sync object -> RequestSerialization on Sync object
I tried that before but it didn't work due to the multiple graph thing
What did not work?
You need to use OnDeserialization event on the Sync object to catch the change after too.
The thing is, since you are doing it cross graph, you might need to call syncObj.RequestSerialization in the button.
What if I did
Interact>SetProgramVariable>SendCustomNetworkEvent
in the button, and in the main script I did
CustomEvent>Branch(isOwner)>If True do>set syncedVariable to localVariable>RequestSerialization>else(If False)>SetOwner>set syncedVariable to localVariable>RequestSerialization
Because I'm not setting owner of the button, I'm setting owner of the main script anyways
Hmm, you gave me an idea hold on. But I meant something like this:
RequestSerialization doesn't do anything in the button script because the synced variable is in the main script
I'm just trying to change a synced variable in the main script using the buttons, that's all
The "SetProgramVariable" changes a local variable that it uses as a reference for which button was pressed basically
I'm changing the selectedHeli in the main script, which is a synced variable, right?
It first changes a local variable in the main script
The customnetworkevent changes the synced variable into the local variable
And instead of changing a local variable in the main script to then sync it, you can instead change the synced variable directly is what I'm saying.
Not from the button though, because then they'd have to take ownership of each button individually
Hold on, I'll make a better example how I'd do it maybe it will be more clear then. (I could be misunderstanding too).
That's what I tried before and it didn't work
Tell me if it's what you want, everyone else will receive the new variable and you can do whatever you want after the branch.
You can also use this node instead of OnDeserialization:
The OnDeserialization is optional, right?
Yeah it's optional, it's just an event that will be called and you can choose to listen to it.
Alright
Everything before that is basically what I was saying
Except without the ownership checking branch
Which I didn't realize is actually not necessary
Yeah, and this way it's easier to see what's going on since it's more simple.
One thing to know though, OnDeserialization is called when someone receives a change of the variable from the network, so the one who set it locally won't get it called. That's why I suggested the Change node, that one will be called every time the synced variable changes, be it from the Network or locally.
Ah that makes a lot of sense
That might be why it wasn't working for me lol. I always check with CyanEmu if it even works locally before I build and test it to see if it syncs properly
I'm completely new to networking stuff in general so I don't understand a lot of what's going on
But it's starting to make sense now
Yeah, you can only simulate how ownership would look like locally with CyanEmu. I don't think sending data between two clients is possible
It's not I've tried :((
Also, don't worry, Networking can make very little sense for normal humans if you try hard enough, so better keep it simple for yourself.
I understand a lot of the concepts of it, but actually working with it is confusing
I don't understand what a lot of these words and phrases actually mean in networking, can it's hard to find any information about it
So this isn't working lol
Ownership isn't being transferred at all for some reason
Ah
It might be because local testing is weird
This is what it says when I try clicking on it with the other client
This is intended, SetOwner gets ignored if you are already the master.
Everything else will continue working.
No
I'm saying
For the client that wasn't the owner
It wasn't setting the owner
It would say that in the console
I'm testing it with a second account
If you are the master, then you already own the object.
Yes, I know that. I was testing with 2 local clients but they were under the same name
One local client is master (first joined), the other isn't master and doesn't own anything unless otherwise specified
They still have different ids and ownerships states.
What exactly is not working by the way?
Then why does the console say I already own it if it didn't own anything
Master can change helis freely, local user cannot gain ownership of main script and therefore cannot change synced variable
Anytime I clicked on the button with the LOCAL user, not the master, it would give me that warning in the console
It claimed I already had ownership
My guess is it was bugging out since local testing just does that sometimes
If I put the target on all, it'll desync
Because it doesn't update the local variable for everyone else
So it sets it to whatever THEIR local variable is
Oh wait, I just realized it's a networked event, you don't need that.
Ah okay I was about to say
I had it on all before and I had this nightmare occuring
Hm
I have to SetOwner in the button script I just realized
That's why I'm having issues
Or
I need to switch the networkevent for a normal customevent
Because a normal customevent affects the local player
Yeah, that's what I wrote before.
Only the local player needs to take control over the sync and then tell everyone else what they do with it.
Thanks for the help again btw
It's working now hmm might just go ahead and drop this and see how it goes lol
I'm trying to figure out why some networking events are working for some players and not others, purely as a fact find - have there been any known cases of client modifications interfering with in-map udon events?
could be several things. I don't think it would be a modified client unless they're specifically blocking it, which I doubt would happen on accident
Sure, that was the expected answer, thanks Phase.
first things first - make sure everyone is on the same version of the world. If it's been updated recently, get everyone to rejoin. If there is both a quest and PC version, make sure that both versions have the same hierarchy
other thing might be that the scripts have crashed for some people
Ah actually thanks for mentioning that. I have been trying to test networking events through using the in-built Test feature in the API package. Are there any limitations on this? For example, if I am trying to do something by a vrcplayerapi, does it register two test clients as separate players?
yes, local testing with multiple clients is quite reliable and I would highly recommend doing that before dragging in a bunch of people
the only situation that won't work is if you are checking their name, the name will be the same
Excellent, it is good to rule that out.
I shall puzzle on, thanks for your insight man.
I correct in my understanding that OnPlayerCollision and such events fire on all clients including master?
onplayertrigger events, yes
collision events are a bit different and probably not what you want
Probably I testing triggers currently, and somewhere between event and variable sync something not working (silently)
does Synchronization have something to do with trigger/collision detection?
not directly
everyone will observe it happen because the players themselves are synced
but that doesn't mean the event itself is "synced" it's just that everyone observes it as a result of something that is synced
i still cant trigger OnPlayerTrigger on master from client.
what layer is the object on
does this object move?
nope
does it extend all the way to the floor or is it floating?
floating
ah, that would do it
there's a weird thing where remote player colliders are smaller than local colliders
if you were to jump they'd probably see it
how do i destroy object for all players?
Unity.Destroy destroys only local copy...
i thinking about sending Destroy network event and killing object in each instance. Any other way?
Networking destroy won't work. You would need to send some kind of network event or synced variables that can tell other players what you want to do and then they all do unity destroy together
But of course instantiated objects can't sync so some other object would need to coordinate this and have some way of determining which object you want to deatroy
will that work?
Depends, what is destroyonhit?
No I mean where does it come from
Was it instantiated? Can you guarantee that it will always be valid before this point?
from inspector on prefab
What I'm getting at is that you probably want to add another isvalid when they receive the event because it may be valid on the person sending but not the receiver
Or perhaps two people have it valid and send the event at the same time and now it tries to destroy twice
done, thanks for suggestion. hope it works
what about "instantiated objects can't sync"? that sounds very important
Yeah, you cannot put synced variables or objectsync on them
But depending on what you're doing, you can make the actual syncing happen through an object that is not instantiated
tested it... now i get why instantiated object don't sync... they created locally only aren't they?
so if i want to create them everywhere i need to do in on each client separately, but then they will be different object and wont sync
what a pain...
is there a way to instantiate object so it would sync?)
No
^
i starting to think of just creating those objects on scene for each possible player manually....
and there no way to transfer actual data over network other then sync, right?
but they didnt say anything about instantiating working only locally! so i thought maybe they didn't tell us something actually usefull X)
Look for cyan object pool, it assigns a unique object to each player from a pool rather than indtantiating
Found it, it basically does what I was thinking to do)
When someone spawns all available objects from pool, and someone else tries to spawn from empty, their vrchat crashes. am i doing something wrong? pretty sure its not supposed to crash people.
are you doing anything with the object that you get from trytospawn?
I do, but that code from empty test scene with simple cubes that dont have anything. still crashes
I don't see how the code you posted could crash
makes 2 of us
but if you're doing anything with the object you get, make sure that you check isvalid before trying to do anything else
because if the pool is full, trytospawn will return null. Trying to do anything with a null object will crash
it crashes on TryToSpawn, so there is nothing to validate
what's the error you're getting?
i dont have errors, just freeze and crash
yeah, it freezes, and only way to close is to force close the window
that sounds like it's stuck in an infinite loop
also i wasnt able to replicate in cyanemu
could you share a pic of the objectpool with the array expanded?
that the test one
hm I'm not sure how it would cause the problem you're describing, but you shouldn't have that udonbehaviour on continuous
its not the issue
yeah just replicated issue in completly new clean project, i guess its a bug
upload a world and post a canny with the world
i got my main project already uploaded, it happens to any object pool https://vrchat.com/home/world/wrld_323e1d92-b0fc-485b-b394-2d8e05b6565b
you need 2 clients to test it though. it happens only to second person that didnt spawn original pool objects
ok this is test world with 3 cubes. 1 person clicks 3 times and spawns 3 cubes, other person clicks and crushes. if by tommorow there wont be any answer, ill submit bug report to vrchat developers https://vrchat.com/home/launch?worldId=wrld_deb7c7d4-6c5b-419f-a3d5-26725e0f6e7b
ill go celebrate now, happy new year @frozen igloo and thanks for trying to help
if you need a quick alternative though, one solution would be to send a network event to the owner and then have the owner spawn from the pool
thanks for advice, i think there wont be an alternative anytime soon so ill use it instead
❤️
yeah dont want owner to be bombarded with network events though, its for discord events, and host will be owner of everything....
sending a network event to the owner would be better than transferring ownership
really? transferring ownership is that heavy on network?
i mean i want like 20 pools to be manged
I mean it's all pretty cheap tbh
splitting hairs
if it was a single pool, keeping it on one owner would be better. but if you have a bunch of pools, you can distribute them to all the players so technically that might be cheaper. But the majority of the cost is going to come from the objects that are spawned from the pool, not from the pool itself. So it really doesn't matter
So.. my game almost always take very long to initialize sync, but it will work smoothly after the first time load, what could be the potential reason that can delay the manual sync for 1 min?
are you talking about yourself in general or everyone in your world?
Everyone in the world but the room master,
do you have a lot of manual synced objects?
Yes, do they delay the sync even if we don't request sync on it?
two thinga: if a player joins, manual sync is resent on all objects
that's probably the reason...
and if you have a lot to send, you will be "clogged" and which will delay manual sync and slow continuous
🤔 if I set these object inactive when player just joined, will that help?
not really
you shouldn't try to stop it, it's doing exactly what you want
you should instead try to reduce how much data you're sending
well not exactly... caz they are just empty player slot when player joined, it will only be filled later when the game start, by when I need to sync them for assigning roles and stuff.
if you add OnPostSerialization to your manual sync objects, you can then access serializationresult.bytecount and see how expensive it is. If it's around a few thousand that's like a bit but not a ton. over 10 thousand is where it gets heavy. And the limit is 50k
if you're under 1000 bytes and still running into problems then it's not your fault
well....
The only other sync object is the lobby manager, which does have a bit more data but the door will only open when it finished sync, but I can double check its sync byte count
well there's 20 players in total so it's going to be around a few thousand when the game start I guess.
It's just weird that even when there's 20 players, it really doesn't take long to sync,
it's just when a lot new player joins, it greatly delay the sync, like for minutes. And I removed all "OnPlayerJoined" functions still not getting any better. that's where confuses me
well.....

I think it's probably multipliying the sync request... 20 players joining at the same time ended with 20 x requests for 20 player objects and that's about 25,600 byte data to sync.

maybe?
Did set all sync objects into inactive by default when the player loads in, that helps a bit, previously I was setting them into inactive after the initialization functions. Could be much easier if it supports static member.
yeah if they've never been active once they won't sync with late joiners
But it still takes relatively long to do the initial sync, I just couldn't find what is causing it. Only 10 vrc object sync objects left in the scene.
but as soon as they've been active then it doesn't matter if they're active or not, they'll always sync
For the objects with VRC object sync active, will it still sync to late joiners even if on their end these objects are inactive?
I see, I guess it's okay in that case then, caz when player joined the game and going through that initial sync, if it's in-game, it has tons of time to sync, if it's not in-game, well, most of the guns and items will be inactive at that point.
oh there's only 21 manual sync objects in total in my scene. I figured it didn't help to set characters as inactive by default and enable when needed.
I meant I disabled many object sync objects.
gun pickups
I further compressed the byteCount for sync data of my character objects and lobby manager, now the character is at 60, and lobby manager is like 90 or something, not significant improve, but it should still help.
Job/gig Offer: PAID, SFW
- Looking for World Developers
- Assets/3D designers
- Udon programmers
Currently I'm exploring posibilities of what can be done, and looking for people to work with.
PM example of your work (and hourly rate), thank you!
Assets? I can do textures
This isn't really the place for this. would recommend going to 'VRC Traders' discord
Can somebody help me find a militaristic tactical anime female avatar?
id perfer a black outfit
I don't think so. I'm not familiar with it but from a quick search it looks like something you have to bind/send/receive on specific ports, which is quite a bit lower-level than udon networking
Udon networking has two primary components: network events, where you just make a function happen on other clients. And synced variables, where an udonbehaviour has a list of pre-defined variables. The owner will send their values and everyone else will receive those values. Then your code can interpret what to do with them
Not sure if my question belongs here or in the udon-questions-channel:
I am working on a soccer game where players drive around on robots and by click, shoot the ball, if they are close to it.
It seems the synced ball only has proper collisions for the localPlayer, while other players only see an oscillating movement where the ball never hits the walls.
Is there a way to force a higher priority on corretc movement/collisions of a single object, to get it as accurate and fast as possible in the network?
The standard VRCObjectSync seems not to do the trick in my example.
vrcobjectsync is really bad on fast movements, even slow movements, sadly, this was not always the case, but it happened at some point of udon, i am not sure when
it usually looks okay for the owner of the object and the eventual final position should be the same nonetheless
you can do a manual sync approach and see if that works better, but you will have to implement logic such as lerping too
You may check out https://github.com/Xytabich/UNet
Default vrchat networking is yuk
is there a way to get avatar size?
Yes, avatar size is distance between head bone and foot bone
Until you crouch, or lay down, or playspace move. You cant calculate actual avatar height.
You can estimate it, but there is a better way than that.
Well, I mostly need current upper boundary of the head, I thought about using head bone, but head size can vary greatly between avatars, so the position of the bone in the head
why would you continuously calculate it though?
When would you calculate it then?
I suppose its enough to do it at start & when the menu is closed
i have a networking question wondering if anyone can answer. Does anyone know if you set a bytearray sync during on deserialization and call request serialization during a condition that prevents it from spamming, is it possible for that data to not get sent out on a manual sync behavior?
That doesnt guarantee that the avatar has loaded in yet.
okay then attach a sphere with a collider to the head and ontriggerexit recalculate it
I've done some back-and-forths where you receive ondeserialization and then immediately setowner and requestserialization right back. It's always worked great. You didn't mention setowner though, are you doing that?
hmm, ill need to check if the user has set the owner yet. Its on my playermethod scripts which is supposed to verify and take ownership if they dont have it if they are set to own the class
well if you're receiving ondeserialization then you're 100% not the owner
so they should but ya if its not getting set then that would be bad
yes, tho thats not the issue here, lemme explain what im doing
each class is set to a player id and claimed. I have a byte array that has a timestamp, method, and parameter data that is set. Im using this to set a paramater for a player by calling their own parameter set method (which they own). Ondeseralization gets called for that object which everyone sees, and since one of the assosiated parameters is the target player, that player then sets the assosiated data for their own script, then request seralizing for others to pick up on the next on deseralize
but on their own object
yeah, straight forward "hey you, gimme your data"
ya
just make sure to do setowner
i want to avoid spamming it if i dont need to, ondeserlize does have an ownership check
so ill run a quick test to see if they arnt claiming the object yet
ondeserialize, only setowner if your playerID matches the playerID
shouldn't spam anything, should just be one round trip
yes, thats apart of my ownership check
so i verified that when the person was setting the synced data, they did indeed own the object, but ondeseralize did not trigger for everyone else after setting the data and request seralization
did onpostserialization happen for the person who did requestserialization?
that also gives you a serializationresult so you can see if it succeeded and how many bytes it took up
ah, it did and had a false on the result
is this a lot of data?
no, its a byte array with one byte
what other synced variables are on it?
the methodbuffer...wait
so it is giving this error:
caught argument excpetion: argument cant be null
some synced empty arrays might break things
thats...annoying
so, the method buffer is only ment to signal a method call, do i need to fill it with at least one byte of data?
I think you can give it an array with length 0
ah, i think that i can do, ill try that and see what happens
that seemed to work, good to know synced arrays should always default to empty
If a player joins mid-game, while this get run on any variables that get synced from the server? 🙂
yes
Awesome, thanks 🙂
If the first player / main owner leaves, and a new owner is assigned, what happens to the variables of the objects he receives ownership of?
Does he get the new state that the original owner had, or do the variables stay the same as when they had no ownership?
variables will not change without you telling them to
the owner will send the state of the variables, and when it transfers to someone else they will have the same state
however if the owner sets a variable and then leaves before they've sent them, nobody will see it
ah okay. I'm used to not replicating every variable because in theory the clients don't need to know everything about the internals of a round, but in this case its very important that everyone could in theory take over the scripts right?:
And does that mean the game could in theory soft-lock if the owner is running a timer on an important object, but the owner leaves?
yeah definitely
you can build in safeguards where if the owner leaves, it resets the round back to some default state. But it would probably be better (albeit more difficult) to make sure anyone can take over at any time
yep, that makes sense
hmm for my game I suppose the owner leaving causing a reset isn't a huge deal
but I'll try just properly propagating state first
Hi guys, when using Manual instead of Continuous on an UdonBehaviour, how do I trigger the manual sync?
UdonBehaviour.RequestSerialization
Thank you!
what's a good rule of thumb for how many bytes you should limit to a single continous object? like would a byte array of 67 bytes be too much?
I believe it's somewhere around 200 bytes in total. But that does not directly correspond to the length of a byte array. To see how much data you're using precisely, you can use OnPostSerialization's serializationresult
ok, but it sounds like at least ill likly be in a good target zone with 67 length byte array
yeah probably
is this per object or for all objects in scene?
per object
sweetness
had another idea of approach...but i dont know if it would be better. Roughly how many frames do you think pass between packet sends on continuous objects? trying to think if i track input on a per frame bases how much data would i collect before it seralizes it
i assume it would depend on how much traffic is going on, wasnt sure if there was a good average on how offten it seralizes
it's about 5 per second, but can go down to 1-2 per second if the network is clogged
Hey, are there any world-creators interested in making something related for fitness?
I'm with a company called YUR and we're thinking about making some fitness-related content in VRchat
Send me a DM if you're interested, any skill level is fine
i don't think this server is the right place for this type of advertisement
I recommend going to a server for commissions. VRC Traders is pretty good for that kinda thing
I mean it’s technically networking lmao
VRCObjectSync on the main body and wheels, VRC Station controls the wheel colliders for movement and it updates the wheel's pos/rot to the matching collider (making it "roll" and "turn"), anybody know why the wheels are moving at a different rate than the body?
does anyone know how to make a button that enables/disables an object and that object is synced for anyone? also that only the owner of the instance or world can toggle and nobody else? thanks
i have this but idk how to make it work only for the owner of the instance or world
Here's one of my scripts that has toggles two gameobject arrays. the top half is all the networking. if you only want the instance owner to be able to change it, add a 'playerapi.get ismaster' check after the interact
I recommend build a small function that uses sync variable to simulate wheel rolling animation rather than use VRCObjectSync to sync their position/rotations. As it has a relatively high latency and inconsistency, it will make awkward scene like that.
If you keep under the 200 bytes limit on a continous object, whats the liklyhood that there will be data loss if a lot of players are on? Right now i have an object that syncs a lil less then 90bytes, but if a packet is loss that can start causing trouble for what its doing
if you care about every single packet then you shouldn't use continuous
hmm...then how bad would it be if i did the 100 bytes manual, but keep flagging request seralization?
if you do it at the same rate it will have roughly the same cost
you can spam it faster than 5 per second but it will dramatically increase cost
aaah gotcha
so if i make a timer set to go off 5 times per second to call request seralization, then it should be alright
probably
you can keep an eye on it by checking Networking.IsClogged. If you spam requestserialization too much, it will get clogged and then your manual sync will be forcefully delayed. So the trick is if you're doing manual sync in a continuous-like way, you want to adjust the frequency of the requestserialization so that it does not get clogged
hmm, well the issue is the longer i wait, the more data that will stack up
the faster i use it, the less data i need to send
but all that being said, just switching to manual and still doing the same thing that continuous does will probably not solve your problem. Manual does not guarantee that all players receive all packets because if the synced variables get overridden before a player has received them, they will be lost
wait they can be overridden before they get it?
yeah, if their connection is particularly unsteady
it will be cheaper and more reliable to send occasional bursts of data than a frequent stream of data
i see, so i shouldnt go too fast, but in this case i shouldnt go too slow.
i am working in a optimization to help remove data related to the player not changing input, hopefully that will help too
that is indeed the main dilemma of realtime networking
if you want to guarantee that everyone receives a very important message and there might be other important messages coming later, the best way to do that is a network event
network events, unlike synced variables, do guarantee that they are received exactly once
ya, tho thats not gonna work here
if this is input then that's a finite range of values, no?
im basicly trying to make the preview of a game in sync by controlling random and time interval, and syncing the player input
the range of values is an x/y of the joystick, and a button press
that x/y isnt static tho, i could make it static which then that would work better but change the percesion
overall, this is mainly for the preview, so if it desyncs i suppose thats ok, itll reset next game
wait, not sure if static is the right word, its a float not a 0-1
if you want to sync the input that's fine, but you should definitely also sync the results of that input too so that it doesn't drift out of sync
that would end up being too much data tho
are you sure? Manual sync can do a lot
i have a player, 30 eneimes, 10 power ups, with different states
i think overall it was close to 100bytes as well
so i would be pushing that 200 byte limit
manual sync can do 1 kilobyte instantly, 10kb if you wait a few seconds, and the absolute limit is about 60kb per serialization
a few hundred bytes is nothing
hmm
wait, its 100 bytes per frame of result
so the input is 3 bytes a frame
i suppose its more of i could capture where they are that frame
right as you said, result of them XD
I would probably capture a whole second of data and send that as one big blob, to be replayed when it is received
mmm, maybe, ima try just doing the input, keeping that in sync, and see if itll be enough in a stress test. If not ill see about what i can do to show the result too
in the end, i just want it so others can watch you play
yes, in situations where you are simply sharing what happened and you don't need other players to interact with it live, recording and playing back large chunks of data is ideal. That is effectively what video buffering is
imagine figuring out how to caputre the per frame texture of the shader result, and syncing that XD
syncing input is typically used in situations where neither player has authority over the simulation. it's a valid technique but I don't think it's the best here