#udon-networking

1 messages · Page 17 of 1

sick gull
#

your script is constantly updating the position of the hitbox

scenic sky
#

i thought it would only follow locally?

sick gull
#

Object Sync is needed for pickups.

scenic sky
#

in my mind i just assumed it would only update locally

#

hmm...

sick gull
#

With creator companion, use the quick launcher w/ 2 diff accounts and test ur code out

scenic sky
#

i did it with build and test and see that

#

im just surprised

#

because all this time i thought you needed object sync to do it-

twin portal
scenic sky
#

i see hmm

twin portal
#

you're using the player's networked position to "network" the object instead

scenic sky
#

alright

sick gull
#

Yeah think of players already having ObjectSync on them

#

Since we all need to see when other move etc

scenic sky
#

that makes senseish

twin portal
#

only thing I'm worried abt is starting the following OnEnable; I've noticed in my testing that PlayerObjects get added to the world a little bit before the player is actually in the scene, so it might not be able to find the player's position yet

scenic sky
#

oh..?

twin portal
#

oh and it stores the owner twice in two different variables, but uses only one of them to just print their name to the console....?

sick gull
#

Make your start to the onplayerrestored

twin portal
#

should only have to do that once, and print out player's displayName instead, the result will be the same

#

yea that will be better

scenic sky
#

alright 1 sec

twin portal
#

anything persistence related, you want to wait for OnPlayerRestored just in case

scenic sky
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class FollowPlayer : UdonSharpBehaviour
{
    VRCPlayerApi player;
    public GameObject hitbox;

    public override void OnPlayerRespawn(VRCPlayerApi player)
    {
        hitbox = gameObject;
    }

    public void OnEnable()
    {
        player = Networking.GetOwner(gameObject);
        Debug.Log("Owner = " + player.displayName);
    }

    private void LateUpdate()
    {
        TrackPlayer();
    }

    public void TrackPlayer()
    {
        VRCPlayerApi.TrackingData headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

        hitbox.transform.position = headData.position;
        hitbox.transform.rotation = headData.rotation;
    }

    public override void OnOwnershipTransferred(VRCPlayerApi newOwner)
    {
        player = newOwner;
    }
}
#

oops

#

i did onplayerespawn

#

by accident

#

i dont think its working now

twin portal
#

lmao

#

try respawning and see what happens

scenic sky
#

oh, i took that out before i even tested

#

lol

#

but the issue is i changes start to restored but now the game object doesnt get set

twin portal
#

oh wait a minute

sick gull
#

That's respawn

twin portal
#

this has no persistent data on it

scenic sky
#

yes

#

i was about to say its not meant to be persistent

twin portal
#

I don't actually know if OnPlayerRestored even fires if the object isn't set to be persistent

scenic sky
#

it doesnt seem like it did

sick gull
#

he doesnt have onplayeresroted in his script

#

u dont need persistence

#

example of my footstep script

scenic sky
#

yeah my aim right now is have these cubes act as hitboxes for later when i make thing hit them to do damage

#

trying to make a super basic combat system then build off it

#

since my favorite system iv been using has stopped being updated and has issues

sick gull
#

also when u send ur scripts, after the first 3 `'s put C#

scenic sky
#

honestly, this is like, way out of my league but i think if i take it slow, ask questions and take my time i can get somewhere since you guys are very helpful

scenic sky
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class FollowPlayer : UdonSharpBehaviour
{
    VRCPlayerApi player;
    public GameObject hitbox;
 
    void Start()
    {
        hitbox = gameObject;
    }

    public void OnEnable()
    {
        player = Networking.GetOwner(gameObject);
        Debug.Log("Owner = " + player.displayName);
    }

    private void LateUpdate()
    {
        TrackPlayer();
    }

    public void TrackPlayer()
    {
        VRCPlayerApi.TrackingData headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

        hitbox.transform.position = headData.position;
        hitbox.transform.rotation = headData.rotation;
    }

    public override void OnOwnershipTransferred(VRCPlayerApi newOwner)
    {
        player = newOwner;
    }
}
#

thats cool

#

oh yeah imma remove ownership thingy too

twin portal
#

I think that ownership thing is in there because the creator of that tutorial said they "don't trust VRChat to not screw it up", which I feel is a bad precedent to code around, as ownership of PlayerObjects are pretty rock fuckin' solid in my experiments

scenic sky
#

now... the harder part raycasts and damage detection.. don't suppose you guys have any decent tutorials in mind for that?

sick gull
#

So for that, youll need a collider on your playerobject and have it be a trigger

#

and whenever the right thing triggers it, u can decrement their health or whatever

#

I'd start slow. Make like an object that ticks your health down (you could check out the Example Central Health bar)

twin portal
#

you may not even need raycasts, if your PVP system will have guns or whatnot, just detect the particles hitting the collider

scenic sky
#

would just having it set as a cube and change the box collider to istrigger work?

sick gull
#

yeah it should...

scenic sky
sick gull
#

Cause my footsteps have the ability to read what u step on

twin portal
#

should be isTrigger. or else the player will collide with the box and you'll fly off into the sky lol

scenic sky
#

i dont believe the health state needs to be synced does it?

twin portal
#

not unless you want other players to see it

sick gull
#

Unless you wanna convey it to everyone

scenic sky
#

i dont think it will need to be seen by everyone, for the sake of keeping it simple id prefer to have it handled locally

sick gull
#

yeah then you could just throw an int onto the player object for health

scenic sky
#

would a float or int be better for this situation?

sick gull
#

IDK, depends on what u wanna do

#

If you care about people being at like 12.5 health over 12

#

¯_(ツ)_/¯

scenic sky
#

prob gonna stick to float

sick gull
#

It would be easy to change in the future. regardless of the route u take

scenic sky
#

yeah

#

now the question

#

particles vs raycasts

#

which is more performant, and easier to implement

#

as well as taking latency into consideration

twin portal
#

they'll have both the same latency, networking-wise

#

particles are easier

scenic sky
#

let's start with that then

sick gull
#

I wouldnt worry about it until you get ur health sorted out

#

Again, make an object that ticks your health down when u are colliding w/ it

twin portal
#

if you make hit detection client-sided then latency won't be much of a problem

scenic sky
sick gull
#

I also believe there is a prefab for raycasts

scenic sky
sick gull
#

Yeah... ill look for it while u work on ur stuff

scenic sky
#

oki

sick gull
#

one of these. IDK if the first one is for ur use case BUT i imagine you could pull it apart to make it work.

Having guns and crap fire is a bit more complicated which is why I suggest getting ur other stuff sorted

scenic sky
#

mhm yeah

sick gull
#

IDK the "best" way to do it but I will probably have something figured out in a few weeks when I get to it for my world...

scenic sky
#

just trying to remember how to correctly get a component in a ontriggerenter

#

i thought i was doing it right 😅

sick gull
#

one more tutorial for ya comin right up

#

Well, I am making a bar and I want a "drink" to be a squirt gun that on click will make the collided user tipsy

scenic sky
#

thats cool

sick gull
#

the concept is similar...

#

So on triggerenter over onplayertrigerenter

#

that will give you the thing it collided with, so for your example. You have a lava floor with a collider. When you touch it from your hitbox, you can check
What am I colliding with?
Maybe u will have it go off names or a literal damage script attached to whatever ur touchign which stores all that crap

#

really u can do whatever

twin portal
#

remember if you are using particles it's OnParticleCollision

sick gull
#

Does prison escape use particles?

scenic sky
#

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

public class PlayerHealth : UdonSharpBehaviour
{
    public float playerHealth = 100f;
    public float respawnHealth = 100f;
  
    void Start()
    {
        
    }


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
    }
}

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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;


    public void OnTriggerEnter(Collider other)
    {
        
        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}

this is what i did so far to test but i dont think i did it right

twin portal
#

I think this would work for rigidbodies hitting the collider

#

like a sword or something

scenic sky
#

Ahhh

#

But we want to use particles

sick gull
#

Lowkey I don't see a point in abstracting all this stuff out to seperate scripts

#

I would just tack it into your player object and call it a day

#

Especially if you aren't the "best" coder

#

and what ur doign is calling the collder and checking it has a PlayerHealth Script

#

oh wait

#

I read it wrong

#

you aren't ever calling ur DamageTarget

#

so after u assigned ur targetPlayerHealth in ur OnTriggerEnter, u should call damage target

scenic sky
#

Yeah I forgot that bit

scenic sky
#

Although, I'm not sure how I'd work particle collision into this as damage

#

Since I'd like there to be different damage amounts

sick gull
#

Well when someone shoots a gun, you can call a global network event to instantiate those particles. THey will move in whatever direction.

The particles sent could have a damage script associated to them. So when the particles collide with the hitbox, the hitbox will just grab the damage script and take the values from it

scenic sky
#

Yeah that would work

#

Although I've never worked with firing particles before

sick gull
#

I am not familiar with using them beyond playing them but I am sure we can figure it out

sick gull
# sick gull

For example, my footstep script will play particles globally

scenic sky
scenic sky
sick gull
#

Maybe, I am sure we could also figure it out either through trial and error or pulling apart a public prefab

#

(also I bet Legos may know)

twin portal
#

I know everything

#

Unless I don't

scenic sky
#

xD

scenic sky
#

Big brain

#

So a basic script that will fire a particle globally and damage a player if it hits their hit box

#

Question, if it's like an automatic weapon firing a lot will it screw up the networking?

sick gull
#

Well your gun will need a like ontriggerdown or whatever, that will spawn a particle which will go flying.
Collide with a hitbox and ur hitbox will grab all the damage data it needs

twin portal
#

Particles youve got the right idea, either you look for the name or as Sondly said a script on it (need to filter it somehow, as OnParticleCollision fires for ANY particle that is set to send collision events)

sick gull
#

lowkey to test that out, you could just make a cube that fires every second.

#

and u can walk into the particle and see

scenic sky
#

True

#

Just need to figure out how to fire it and find a particle that will work with it

twin portal
#

the only gun I've made is a sort of sniper rifle, so all I did was configure the particle system not to emit on its own, then used the Emit() function on the particle to emit 1 particle

#

for automatic hmm. You can use Stop() and Play() to turn the system on and off, or put the particle system on a GameObject and toggle it on and off

#

oh and footsteps I think are commonly done by getting the player's velocity, then increasing the volume of the sound based on their speed

#

and maybe also the speed at which the sound plays?

sick gull
#

I don't do that personally but yeah.

scenic sky
#

Interesting

scenic sky
#

okay guys i got a gun now and firing off particles which is great, now i just need it to apply damage, ill show what i have so far


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

public class Gun : UdonSharpBehaviour
{

    public ParticleSystem bullet;

    public override void OnPickupUseDown()
    {
        SendCustomNetworkEvent(NetworkEventTarget.All, "Fire");
    }

    public void Fire()
    {
        bullet.Play();
    }
}

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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;


    public void OnParticleCollision(GameObject other)
    {  
        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class PlayerHealth : UdonSharpBehaviour
{
    public float playerHealth = 100f;
    public float respawnHealth = 100f;


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
    }
}
#

currently, when the particle hits the cube it doesnt apply any damage

#

the detection is working when it hits the cube at least

sick gull
#

thats good

scenic sky
sick gull
#

u still need to add the damagetarget

#

after u log it

scenic sky
#

oh right xd

scenic sky
#

yup it works now

sick gull
#

Now u gotta have some function call when ur health hits 0

scenic sky
#

mhm

#

for now i just made it disable the cube although that will only show locally

sick gull
#

🫡 nice work tho. It isn't too bad once you get the hang of it

#

Yeah, so you could do something like prison escape where you can toggle everyones collider to be visible

#

and technically, you could even change the shade of the material on the collider like prison escape does

#

and that could technically represent health

#

but IK you said earlier it isn't important

scenic sky
#

hmmm i just need to ensure it works now

sick gull
#

Make an alt and dual boot into your vr world to test it out

#

It might be beneifical to have a ui in your world that shows the local players health

scenic sky
#

doing a build and testw ith 2 clients

scenic sky
sick gull
#

You got it boss 🫡

scenic sky
#

there is some unexpected behavior rn

#

uhh ill try to explain

#

unless i figured it out checking rq

sick gull
#

Screw with it. It may be time to work on a UI to debug crap

scenic sky
#

well one thing is, if the player is walking forward while firing it will show it exploding in the player's face for player 2 but appear to be firing normally for player 1 who is firing it

#

i know i need to make a layer to make the cube not collide with the player too

#

since istrigger cant be off it seems

sick gull
#

I imagine the particle spawns for everyone and is colliding with the persons hitbox who is shooting it

sick gull
#

So if you want the user to be able to shoot themselves (low-key kinda funny) , you may need to tune where the particle is relative to the gun

scenic sky
#

as for the layer, how should i make it so the cube doesnt collide with the player but can still be it by particles?

sick gull
#

Is reckon they'd need to be on the same layer

#

I'd*

scenic sky
sick gull
#

Then it's network latency

#

You can scale the hitbox down a bit

#

Also the local player doesn't technically need to have their hitbox active on their end if you don't want them to be able to hurt themselves

scenic sky
sick gull
#

So you could just turn off the collider for the local player

scenic sky
#

how would you approach that?

sick gull
#

Drop your hitbox here again

scenic sky
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class PlayerHealth : UdonSharpBehaviour
{
    public float playerHealth = 100f;
    public float respawnHealth = 100f;


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
        if (playerHealth <= 0)
        {
            gameObject.SetActive(false);
        }
    }
}```
sick gull
#

This isn't the hitbox

scenic sky
#

this is the script attached to the hitbox?

sick gull
#

I need the hitbox script itself

#

Or wait this your hitbox?

#

No it can't be

twin portal
#

where's the collision event(s)

sick gull
#

Cause it doesn't track on the player

scenic sky
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class FollowPlayer : UdonSharpBehaviour
{
    VRCPlayerApi player;
    public GameObject hitbox;
 
    void Start()
    {
        hitbox = gameObject;
    }

    public void OnEnable()
    {
        player = Networking.GetOwner(gameObject);
        Debug.Log("Owner = " + player.displayName);
    }

    private void LateUpdate()
    {
        TrackPlayer();
    }

    public void TrackPlayer()
    {
        VRCPlayerApi.TrackingData headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

        hitbox.transform.position = headData.position;
        hitbox.transform.rotation = headData.rotation;
    }
}
sick gull
#

So after you assign the hitbox in start, you can check the local player, if they are local, find the collider component and disable it

scenic sky
#

alrighty

sick gull
#

How you view code here is everything is ran on everyone's machine (very important on start and update functions)

scenic sky
#

oh..

#
  void Start()
    {
        hitbox = gameObject;
        targetCollider = gameObject.GetComponent<Collider>();

        if (player.isLocal)
        {
            targetCollider.enabled = false;
        }
    }
#

like that?

#

or wait, that may not work because OnEnable is called after start right?

twin portal
#

OnEnable is first I believe

scenic sky
#

oh

#

okay, so i that works and i made a layer for it so it doesnt collide with players

#

now there is some odd behavior

#

so, lets say player 2 is firing at player 1, both players see the impact and after 10 shots (amount needed to reach dead state) the cube turns off, but it only turns off for the shooter.

#

is it tied in with how the damage logic works?


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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;


    public void OnParticleCollision(GameObject other)
    {  
        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            DamageTarget();
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}
sick gull
#

well now its because the users local collider is never triggering for their health since its off

scenic sky
#

that makes sense

sick gull
#

So on the 2nd players POV
The collision code is being ran and its working.
1st player POV will never know they got shot

#

and since the players health isnt synced, they have no way to know they've been hit

scenic sky
#

hmmm

#

okay, what do you think the approach should be here?

sick gull
#

idk lowkey. Legos would know better

scenic sky
#

isnt there a chance that they make take damage twice or multiple times if multiple players see it happen and its synced?

sick gull
#

thasts true yeah

scenic sky
#

ideally, i think for the best experience the shooter should be reporting the damage

sick gull
#

agreed

scenic sky
#

this should make the latency less, annoying?

sick gull
#

I guess when the collision is called, you can check the local player and if it is the local player, modify their health

scenic sky
#

will that still cause the self damage?

sick gull
#

so collision calls would only register for the guy who fired the gun

#

No since the local players collider is always off

scenic sky
#

hmm alright

sick gull
#

so they have no chance of shooting themselves

scenic sky
#

so where do you think i should place the local check?

sick gull
#

But IDK. this is getting into networking game design I am not familiar with just yet

sick gull
#

I agree but I think my brain is just bad at understanding it. I am still a noob.

you could technically call a network event when the collision happens. It would be ran on all players computers to decrement the shot players health

#

Or well, when the damage is called. Not on collision

scenic sky
#

honestly same man my networking understanding is sooo bad rn

#

i have so many wrong things memorized

scenic sky
# sick gull Or well, when the damage is called. Not on collision

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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;


    public void OnParticleCollision(GameObject other)
    {  
        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            DamageTarget();
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}
sick gull
scenic sky
#

in the Damage Target method?

sick gull
#

Actuyally ugh. Maybe we can sync the health instead

scenic sky
#

xd

#

where's lego when we need them lol

sick gull
#

They have a nice prefab in example central

#

I believe he is on vacation

scenic sky
sick gull
#

Yeah

#

It has like a lava thing

#

I'd reckon they may just sync the variable. You could see how it interprets damage

scenic sky
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;

public class DamageOnTouch : UdonSharpBehaviour
{
    // The amount of damage to apply per second
    [SerializeField]
    private float _damagePerSecond = 10f;
    
    // Reference to the HealthBar component
    private HealthBar _healthBar;
    
    public void Start()
    {
        // Get the HealthBar component from the local player
        _healthBar = PersistenceUtilities.GetPlayerObjectComponent<HealthBar>(Networking.LocalPlayer);
    }

    public override void OnPlayerTriggerStay(VRCPlayerApi player)
    {
        // If the player is local, apply damage to the health bar
        if (player.isLocal)
        {
            _healthBar.TakeDamage(_damagePerSecond * Time.deltaTime);
        }
    }
}
#
using UdonSharp;
using UnityEngine;
using UnityEngine.UI;
using VRC.SDKBase;

public class HealthBar : UdonSharpBehaviour
{
    // The health of the player
    [UdonSynced]
    private float health = 100f;
    // The maximum health of the player
    [SerializeField]
    private float _maxHealth = 100f;
    // The offset of the healthbar above the player's head
    [SerializeField]
    private Vector3 _offsetAboaveHead = new Vector3(0, 0.5f, 0);
    // The healthbar slider for visual representation
    [SerializeField]
    private Slider _healthBarSlider;
    
    // The owner of the healthbar
    private VRCPlayerApi _owner;
    
    public void Start()
    {
        _owner = Networking.GetOwner(gameObject);
        _healthBarSlider.minValue = 0;
        _healthBarSlider.maxValue = 1;
        UpdateHealth();
    }

sick gull
#

yeah see, the health is synced

scenic sky
#
 public void Update()
    {
        if (!Utilities.IsValid(_owner))
        {
            return;
        }
        
        if(!Utilities.IsValid(Networking.LocalPlayer))
        {
            return;
        }
        
        // Get the head tracking data of the owner and the local player
        VRCPlayerApi.TrackingData headReference = _owner.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);
        VRCPlayerApi.TrackingData localHeadReference = Networking.LocalPlayer.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);
        
        // Place the healthbar above the head of the owner
        transform.position = headReference.position + _offsetAboaveHead;
        transform.rotation = Quaternion.LookRotation(_owner.isLocal ? Vector3.down :localHeadReference.position - headReference.position, _owner.isLocal ? localHeadReference.rotation * Vector3.forward : Vector3.up);
    }

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

    private void UpdateHealth()
    {
        // Update the healthbar slider
        _healthBarSlider.value = health / _maxHealth;
    }
    
    public void TakeDamage(float damage)
    {
        // Apply damage to the health
        health -= damage;
        // Make sure the health is within the bounds of 0 and the max health
        health = Mathf.Clamp(health, 0, _maxHealth);
        // If the health is 0 or below, die
        if(health <= 0)
        {
            Die();
            return;
        }
        // Request serialization to update the health on all clients
        RequestSerialization();
        UpdateHealth();
    }

    // Respawn the player and reset the health
    private void Die()
    {
        _owner.Respawn();
        health = _maxHealth;
        RequestSerialization();
        UpdateHealth();
    }
}````
#

big script lol

sick gull
#

That may honestly be the thing we need to mess with

#

and see, after everytime the user takes damage, we request serialization which basically syncs your synced crap for everyone else

scenic sky
#

trying to think of how id implement this

#

into my own script xd

sick gull
#

[UdonSynced] on health

#

Request serialization in your playerhealths takedamage AFTER you've modified health

scenic sky
#

so in here?

#

like right under the health being changed

sick gull
#

yeah

scenic sky
#

lets see what happens now

twin portal
#

I'm tryna catch up

scenic sky
#

all good

twin portal
#

so if you disable the local player's collider, they won't be able to respond to themselves taking damage

#

and if they are the owner of this collider, then another player hitting it won't be able to RequestSerialization

sick gull
#

ooh true

scenic sky
#

ah.. yeah i see it not working xd

scenic sky
#

just it being disabled for shooter again

twin portal
#

hard part is there's a lotta ways to do it... these colliders are PlayerObjects right?

scenic sky
#

yes

sick gull
#

alotta ways to tie a knot

scenic sky
#

so taking ownership of them wont work right?

twin portal
#

that's right

scenic sky
#

since its a player object, it cant be owned by someone else

twin portal
#

so instead of the player who hit them attempting to network it, they need to tell the owner to make changes when they register a hit

scenic sky
#

yeah.. but how xd

sick gull
#

With the playerhealth you overwrite when the particle hits

#

(legos knows better)

twin portal
#

you can SendCustomNetworkEvent to just the owner, and have them make the health changes and serialize it

#

with networking you always gotta visualize the relationship between local & remote players, and owner vs. non-owner

#

so, when I, the local player, detect that I hit another player's collider > SendCustomNetworkEvent to the owner and tell them to take damage

scenic sky
twin portal
#

it clicks eventually

scenic sky
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;


    public void OnParticleCollision(GameObject other)
    {  
        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            DamageTarget();
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}

so if im understanding correctly, i should call the damage target method through a network event targetted towards the owner?

twin portal
#

it's good that you already have TakeDamage as its own function, so it should be easy to adapt

#

yep all you should have to change is the DamageTarget call to SendCustomNetworkEvent([the big long thing that targets Owner], nameof(DamageTarget));

scenic sky
#

lets try it

#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;


    public void OnParticleCollision(GameObject other)
    {  
        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}
frozen igloo
#

The biggest problem with using a particle system for favor the shooter will be that everybody sees the particle hit the player, and you don't want everybody sending a message to tell the person to take damage. If you do that, they would take damage multiplied by the number of users in the instance.

It's important to make sure you filter it out so that only the person who shot the particle tells the receiver to take damage, and nobody else. If this is a particle created by the world, then you can modify it so that only the owner of it has SendCollisionMessages enabled.

If this is a particle created by the avatar, you can't manipulate it or identify who it came from, and that's the core problem which prevents you from doing favor the shooter with avatar particles

scenic sky
#

good point, and this isnt for avatars

#

its for a world

frozen igloo
#

yeah, then it's easy

scenic sky
#

how would you filter it?

twin portal
#

oh yeah forgot to consider for everyone seeing the collision

scenic sky
#

he's cooking :3

frozen igloo
#

*she

frozen igloo
#

You can do that either by enabling sendcollisionmessages only on the owner's gun, or by reading the message and checking who the gun belongs to

scenic sky
#

hmm which would be more logical? there will be multiple guns and multiple players firing at different times

frozen igloo
#

whichever is easier for you, both are valid. Though in either case, it would be important to check that the source particle is valid or else you'll get avatar particles which don't have this same filtering

scenic sky
frozen igloo
#

it would be something like

OnParticleCollision(GameObject other)
if (!utilities.isvalid(other)) return;
if (!networking.isowner(other)) return;```
#

the gameobject other doesn't inherently have an owner because it probably doesn't have a networked behavior, but if you ask for the owner of an object like that it will traverse up the hierarchy until it finds a parent that does have an owner. So as long as the particle system is the child of something that you own, it will work

scenic sky
#

okay, so like this?

    public void OnParticleCollision(GameObject other)
    {
        if (!Utilities.IsValid(other)) return;
        if (!Networking.IsOwner(other)) return;

        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");
        }
    }```
#

the particle system is a child of the gun

frozen igloo
#

oh hang on, is this script on the collider of the person being hit, or is it on the particle system of the gun?

scenic sky
#

uhh here lemme send each thing and explain them

frozen igloo
#

When a particle collision happens, both sides get OnParticleCollision. So if this script is on the particle system, then "GameObject other" represents the collider being hit. In that case, we want to check the owner of the particle system not the collider that was hit

scenic sky
#

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

public class Gun : UdonSharpBehaviour
{

    public ParticleSystem bullet;

    public override void OnPickupUseDown()
    {
        SendCustomNetworkEvent(NetworkEventTarget.All, "Fire");
    }

    public void Fire()
    {
        bullet.Play();
    }
}

^^ This script fires the particle system

#

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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;


    public void OnParticleCollision(GameObject other)
    {
        if (!Utilities.IsValid(other)) return;
        if (!Networking.IsOwner(other)) return;

        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}

This one is attached to the actual particle being fired

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

public class PlayerHealth : UdonSharpBehaviour
{
    [UdonSynced] public float playerHealth = 100f;
    public float respawnHealth = 100f;


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
        if (playerHealth <= 0)
        {
            gameObject.SetActive(false);
        }
    }
}

This is attached to the hitbox

frozen igloo
#

if (!Networking.IsOwner(other)) return; this needs to be a reference back to the gun

frozen igloo
#

could just have like public GameObject gun and then if (!Networking.IsOwner(gun)) return;

scenic sky
#

oki lemme do it rq

#

oh we got an issue

#

oh

#

wait

#

im not supposed to reference the Gun script

#

supposed to reference the Gun Game Object

#

my bad

#

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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;
    public GameObject gunRef;




    public void OnParticleCollision(GameObject other)
    {
        if (!Utilities.IsValid(other)) return;
        if (!Networking.IsOwner(gunRef)) return;

        if (other.gameObject.GetComponent<PlayerHealth>())
        {
            targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
            Debug.Log("Collision Detected" + other.name);
            SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");
        }
    }

    public void DamageTarget()
    {
        targetPlayerHealth.TakeDamage(projectileDamage);
    }
}
#

how does that look?

frozen igloo
#

ye

#

I think that should work

scenic sky
#

alright ill give it a shot

frozen igloo
#

I'd replace if (other.gameObject.GetComponent<PlayerHealth>()) { targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();

with

targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
if (Utilities.IsValid(targetPlayerHealth))
        {```
just for code cleanliness though
scenic sky
#

dang, no luck. nothing happened, it collided but no damage applied

frozen igloo
#

oh, actually I see a problem. You're calling the network event on the particle system, which means you lose out on the reference. The targetPlayerHealth isn't synced so when they receive the network event they won't know which playerhealth was supposed to be hit.

You can fix that by moving the DamageTarget function to playerhealth script, and calling the network event on that directly

scenic sky
#

okay, uhh lemme try rq

frozen igloo
#

The tricky part is that without network events with parameters, this won't be able to communicate the amount of damage of the particle system

scenic sky
#

oh..

#

mmm...

frozen igloo
#

But worry about that later, start with getting something to work, even if it's always 1 damage

scenic sky
#

oh okay

frozen igloo
#

add this to PlayerHealth

    {
        targetPlayerHealth.TakeDamage(1);
    }```

Then inside of the particle collision, you'd do `targetPlayerHealth.SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");`
scenic sky
#

okay, lemme try im just piecing it together in my head

#

how does this look?


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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;
    public GameObject gunRef;




    public void OnParticleCollision(GameObject other)
    {
        if (!Utilities.IsValid(other)) return;
        if (!Networking.IsOwner(gunRef)) return;

        targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
        if (Utilities.IsValid(targetPlayerHealth))
        {
            Debug.Log("Collision Detected" + other.name);
            targetPlayerHealth.SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");
        }
    }

}
#

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

public class PlayerHealth : UdonSharpBehaviour
{
    [UdonSynced] public float playerHealth = 100f;
    public float respawnHealth = 100f;


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
        if (playerHealth <= 0)
        {
            gameObject.SetActive(false);
        }
    }

    public void DamageTarget()
    {
        TakeDamage(1);
    }
}
#

just tested it like this but no damage applied

frozen igloo
#

Is PlayerHealth on a PlayerObject?

scenic sky
#

yes

frozen igloo
#

Do you get the Collision Detected log?

#

the follow player script doesn't have the gameobject defined, could that break something with that script?

scenic sky
#

it gets defined at start

#

also

#

ah

#

i found issue

#

i think

#

i didnt assign gun ref

#

okay now ill check for collision

#

yes there is a collision log

#

but player health doesnt go down sadly

#

testing in client sim rn

#

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

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public float projectileDamage = 10;
    public ParticleSystem bullet;
    public GameObject gunRef;




    public void OnParticleCollision(GameObject other)
    {
        if (!Utilities.IsValid(other)) return;
        if (!Networking.IsOwner(gunRef)) return;

        targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
        if (Utilities.IsValid(targetPlayerHealth))
        {
            Debug.Log("Collision Detected" + other.name);
            targetPlayerHealth.SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget");
        }
    }

}
#

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

public class PlayerHealth : UdonSharpBehaviour
{
    [UdonSynced] public float playerHealth = 100f;
    public float respawnHealth = 100f;


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
        if (playerHealth <= 0)
        {
            gameObject.SetActive(false);
        }
    }

    public void DamageTarget()
    {
        TakeDamage(1);
    }
}
#

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

public class FollowPlayer : UdonSharpBehaviour
{
    VRCPlayerApi player;
    public GameObject hitbox;
    private Collider targetCollider;
 
    void Start()
    {
        hitbox = gameObject;
        targetCollider = gameObject.GetComponent<Collider>();

        if (player.isLocal)
        {
            targetCollider.enabled = false;
        }
    }

    public void OnEnable()
    {
        player = Networking.GetOwner(gameObject);
        Debug.Log("Owner = " + player.displayName);
    }

    private void LateUpdate()
    {
        TrackPlayer();
    }

    public void TrackPlayer()
    {
        VRCPlayerApi.TrackingData headData = player.GetTrackingData(VRCPlayerApi.TrackingDataType.Head);

        hitbox.transform.position = headData.position;
        hitbox.transform.rotation = headData.rotation;
    }
}
#

these are all the current versions of the scripts

#

ah

#

i found my issue

#

Sync method was set to none on player health

#

wait...oh man

#

it seems like its.. delayed?

frozen igloo
#

the syncing of playerhealth is definitely not set up right but you shouldn't need that to test basic functionality

scenic sky
#

o-

#

also the delay i thought was there was just unity being weird i think

frozen igloo
#

delay of what?

scenic sky
#

i was watching the health go down in the inspector and it only updated in the inspector when i put my mouse over it

#

ah... shouldnt have tested in client sim

#

because in vrc build and test it doesnt appear to be taking damage

frozen igloo
#

oh yeah, build and test remote clients aren't real, so networking isn't going to work between them

scenic sky
#

oh... boy..

frozen igloo
#

er I mean clientsim

#

build and test clients are real. launch 2 of them

scenic sky
#

but.. oddly enough the "networking" worked in client sim but not build and test

frozen igloo
#

that's because there is only one owner of the objects in clientsim

scenic sky
#

ah

#

okay, so the current issue appears to be no damage is being applied

#

the scripts i sent earlier are still accurate to their current versions

twin portal
#

did you set the sync to Manual or Continuous?

scenic sky
#

Cont

twin portal
#

TakeDamage doesn't RequestSerialization, and you don't have any field change callbacks setup

#

and you don't have the health printing anywhere no?

scenic sky
frozen igloo
#

do you want players to see each other's health? Or do you want people to only see their own health?

sick gull
#

only their own

#

Atleast that was the initial thought

frozen igloo
#

Then there is no need to [udonsynced] the playerhealth or requestserialization or anything

frozen igloo
#

but yeah, get some logging in there, do a respawn on kill, increase the damage, whatever you need to make it more visible when taking damage just to rule out the possibility that you are taking damage but just can't see it

twin portal
#

yea do some loggin' like just Debug.Log the health after the damage is taken

sick gull
#

after its taken, when you are about to call the event etc.

#

just so its easier to trace crap

twin portal
#

half my code ends up being Debug.Logs sometimes

sick gull
#

Its worth it for the sanity

#

or insanity, depends on how you roll 😎

twin portal
#

yea then it doesn't need UdonSynced

scenic sky
#

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

public class PlayerHealth : UdonSharpBehaviour
{
    [UdonSynced] public float playerHealth = 10f;
    public float respawnHealth = 100f;


    public void TakeDamage(float damage)
    {
        playerHealth = playerHealth - damage;
        Debug.Log("Current Health = " + playerHealth);
        if (playerHealth <= 0)
        {
            Networking.LocalPlayer.Respawn();
        }
    }

    public void DamageTarget()
    {
        TakeDamage(1);
    }
}
#

hows that

frozen igloo
#

change TakeDamage(1); to TakeDamage(10); so that it's a one shot kill

sick gull
#

and remove udonsynced on the playerhealth

scenic sky
#

i forgot how to view logs in vrc

frozen igloo
#

rshift, tilde, 3

scenic sky
#

also, it worked it seems

frozen igloo
#

woo

scenic sky
#

yesss progresssssssssssss

#

now that we're good on that part, we need to figure out how to do custom dmg

frozen igloo
#

So, for that you could either build a whole complicated manual event buffer on the particle system script, or you can just have network events with DamageTarget1, DamageTarget2, DamageTarget3, DamageTarget4 etc

frozen igloo
#
    {
        TakeDamage(1);
    }
    public void DamageTarget2()
    {
        TakeDamage(2);
    }
    public void DamageTarget3()
    {
        TakeDamage(3);
    }
    public void DamageTarget4()
    {
        TakeDamage(4);
    }```
sick gull
#

Like DamageTarget2 could deal more damage and you could have your sniper rifles use that one

#

Or a diff gun

scenic sky
#

wouldnt that get messy if you have like 20 guns?

twin portal
#

eh it's only 20 lines

scenic sky
#

true

twin portal
#

and are they all going to do different damage?

sick gull
#

Uh yeah but you should honestly just have a few types of gun damage and just have diff skins and shooting sounds

#

Like I think Ostinyos TTT world has like 3 different skins for each gun type.

scenic sky
#

yeah i think i should just have a select few weapons

frozen igloo
#

Don't have the damage function be tied to the gun type, just do this:

targetPlayerHealth.SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget" + projectileDamage);

#

then you can have the same gun script and just change projectileDamage

#

though projectileDamage should be an int, not a float

scenic sky
#

yeah thats what i would love ^^

twin portal
#

it works p well

sick gull
#

Gigabrain

frozen igloo
#

it's dumb but it works

scenic sky
#

uhh

#

trying to figure it out in the player health part

twin portal
#

if spacing the brackets like that feels like too much space, you can put the function on one line each like this

scenic sky
#

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

public class PlayerHealth : UdonSharpBehaviour
{
    public int playerHealth = 10;
    public int respawnHealth = 100;


    public void TakeDamage(int damage)
    {
        playerHealth = playerHealth - damage;
        Debug.Log("Current Health = " + playerHealth);
        if (playerHealth <= 0)
        {
            Networking.LocalPlayer.Respawn();
        }
    }

    public void DamageTarget(int damage)
    {
        TakeDamage(damage);
    }
}
#
using UdonSharp;
using UnityEngine;
using VRC.SDKBase;
using VRC.Udon;
using VRC.Udon.Common.Interfaces;

public class Projectile : UdonSharpBehaviour
{
    private PlayerHealth targetPlayerHealth;
    public int projectileDamage = 10;
    public ParticleSystem bullet;
    public GameObject gunRef;




    public void OnParticleCollision(GameObject other)
    {
        if (!Utilities.IsValid(other)) return;
        if (!Networking.IsOwner(gunRef)) return;

        targetPlayerHealth = other.gameObject.GetComponent<PlayerHealth>();
        if (Utilities.IsValid(targetPlayerHealth))
        {
            Debug.Log("Collision Detected" + other.name);
            targetPlayerHealth.SendCustomNetworkEvent(NetworkEventTarget.Owner, "DamageTarget" + projectileDamage);
        }
    }

}
#

like this?

twin portal
#

that plus the functions Phased posted, where DamageTarget is

#

what you're doing is essentially making a new function for every possible argument to the original function

#

and all these new functions do, is call the original with the argument

sick gull
#

almost. You need to make DamageTarget -> DamageTarget1 and hardcode the damage value ur gunna deal instead of passing a variable

#

and then dupe that function while changing the number and the damage dealt

frozen igloo
#

yeah that part is correc

frozen igloo
scenic sky
#

Ohhhh

#

I see

twin portal
#

can you tell what your SendCustomNetworkEvent is calling now?

scenic sky
#

Where will those be coded into? The player health?

frozen igloo
#

yes

#

that replaces the single TakeDamage function

scenic sky
twin portal
#

it's gonna smush "DamageTarget" and "10"(projectileDamage), creating "DamageTarget10", and then will call the function DamageTarget10 instead of DamageTarget

scenic sky
#

oh i see

twin portal
#

so for every "projectileDamage" value that you expect, you need a DamageTarget1, DamageTarget2, etc. function, or nothing will happen because the function doesn't exist

#

where the num is projectileDamage

#

then as you can see all the function does is call TakeDamage with the value you want

scenic sky
#

okay so im trying to wrap my head around it

twin portal
#

you're essentially faking doing a function call with parameters, since you can't normally do that with events

scenic sky
#

so how do i change this part to make the number do the projectile damage

#

or am i misunderstanding 😅

twin portal
#

that's what "DamageTarget" + projectileDamage is for

#

the number after "DamageTarget", THAT'S the "input" so to speak

scenic sky
#

okay so, delete damage target and leave the rest like this?

sick gull
#

yez

twin portal
#

you could if you wanted

scenic sky
#

do i change the "DamageTarget" to have 1 in it?

#

for this

twin portal
#

no

sick gull
#

No

scenic sky
#

o

twin portal
#

that's what + projectileDamge does

scenic sky
#

OH

twin portal
#

it will add the number to it

sick gull
#

You are concatinating a string

twin portal
#

aw..

sick gull
#

and just calling that string. its like a psuedo prop or passing a variable

scenic sky
#

okay, so its not actually passing the damage over?

#

or..?

sick gull
#

No, you can't

scenic sky
#

so maybe i should change the name from projectiledamage to damagetype maybe?

sick gull
#

We touched upon it a bit. You can't pass parameters via network events like this

#

Sure

scenic sky
#

since you're basically selecting a type

sick gull
#

You could have classes of damage types

scenic sky
#

oh? could you elaborate?

#

just wanna make sure im understanding correctly lol

sick gull
#

Yeah so your projectiles could be typed OR you can just give the projectiles a damage

#

So say instead of DT1 (DamageTarget), we could have a DT10 which deals 10.

#

It really just depends on how you wanna do it at this point

#

¯_(ツ)_/¯

#

the world is ur oyster

twin portal
#

yeah you're in "do whatever you want that works" territory now

scenic sky
#

if idid DT10

sick gull
#

DT1 can deal whatever damage

#

its just a matter of how you wanna read your code

scenic sky
#

so this is what i have currently

sick gull
#

Yeah that works man

scenic sky
#

how would the second one play into this?

frozen igloo
#

it works but then that means when you put in projectileDamage 4 on the gun, it actually does 50 which is just mildly confusing

sick gull
#

they are the same thing just diff smell

scenic sky
#

whats the other weay of approaching this?

sick gull
#

Yeah so you can either interpret DT1 as deal type one damage
OR deal one damage

twin portal
#

I mean it's down to what you want, what will "projectileDamage" actually represent

frozen igloo
#

I'd personally do DamageTarget50 = TakeDamage(50) so that when you put in projectileDamage 50, it still does 50. And like, you don't need to make DamageTarget43 if you're not gonna have a gun that does specifically 43 damage

twin portal
#

the raw number of damage taken, or the "type" of damage?

scenic sky
#

i would still need to hardcode it regardless right>?

frozen igloo
#

if you ever make a gun that does 75 damage, then you can just make sure you have a DamageTarget75 function

sick gull
#

I think raw damage is probably easier and we just end up abstracting it further

#

With the other method

#

And it'll be easier to read

#

Like say you had 20 types, now your like " damn, what was type 17 again?'

frozen igloo
#

alternatively, you can run a little script that autogenerates 1 through 100 so you never have to think about this again

twin portal
#

yeah I'd go with that

twin portal
# scenic sky

guaranteed this is just gonna confuse you in the future

scenic sky
twin portal
#

just spit out a string to the console that loops 100 times and puts that in the text

frozen igloo
#

go to here https://www.programiz.com/csharp-programming/online-compiler/

and then run this:

// Write, Edit and Run your C# code using C# Online Compiler

using System;

public class HelloWorld
{
    public static void Main(string[] args)
    {
        for (int i = 1; i <= 100; i++){
            Console.WriteLine("    public void DamageTarget" + i + "() { TakeDamage(" + i + ");");
        }
        Console.WriteLine ("Try programiz.pro");
    }
}```
scenic sky
#

oh i see

#

i see what you mean but trying to understand

#

how it would be used

frozen igloo
#

This is just a random website where you can run C# code. You can prototype a quick little script to output what you need, and then take that output and plug it into your script

sick gull
#

with this method, you could theoretically generate a damage (within a small range) when u fire a projectile

twin portal
#

forgot the closing bracket!

// Online C# Editor for free
// Write, Edit and Run your C# code using C# Online Compiler

using System;

public class HelloWorld
{
    public static void Main(string[] args)
    {
        for (int i = 1; i <= 100; i++){
            Console.WriteLine("    public void DamageTarget" + i + "() { TakeDamage(" + i + "); }");
        }
    }
}```
scenic sky
sick gull
#

all good

#

keep at it

twin portal
#

^just run that code on the webbed site, copy the output and slap it into your script

scenic sky
#

oh so it makes it 100 times

twin portal
#

yea

finite sequoia
#

I swear the more I work on networking the less stuff works...

finite sierra
#

maybe you need to rework the logic @finite sequoia

finite sequoia
#

yes that's what I was trying to do for the last 7 hours... 🤣

#

I'm remaking from scratch at this point to un-confuse myself

finite sequoia
#

only one hiccup away from finishing...

#

Everything seems to work on the generic doors.
One thing is weird but only on the "whitelisted user" door

  • when entering a world ID, portal don't update for the owner
  • when entering a world ID, portal do update for everyone else normally
  • when owner rejoins the world, portal updates for the owner

(even tho it works fine on the generic version)

twin portal
#

is the owner also applying the change to themselves?

#

remember they don't get OnDeserialization

finite sequoia
#

yes I'm following the tutorial you sent this morning

#

that structure

#

should I use "SendCustomNetworkedEvent" targeted to "Owner" instead?

twin portal
#

no this should work

#

if the portal string is set

finite sequoia
#

yeah that's why I'm confused since the generic version do work

#

and the OnPlayerRestored do work so it's set way before I input a new link manually

#

it shouldn't fail this late

twin portal
#

what's happening before this Send group

#

you're presumably setting ownership after writing to the synced variable

#

which I don't think will work, you need to be owner first

finite sequoia
finite sequoia
twin portal
#

set ownership right before you write to the ID_current variable, instead of after

#

granted I didn't watch the videos

finite sequoia
#

this part of the lesson

#

Still behaves the same (for the non generic one it was more of a failsafe, since the username whitelist is supposed to set owner already on start)

#

Do you think it's because of the second request when I save the persisted data?

#

would it work to just put the request as a third branch of the block so it's called once?

#

I guess this order would make more sense since the request is after "save" but before "confirm"
(dunno if I even need the block anymore here)

twin portal
#

looks alright to me

finite sequoia
#

acutally yeah, looks like it makes more sense this way

#

wait, no...the whitelist version is always "save" and "network" it doesn't even use these variables anymore

finite sequoia
#

Yeah no I don't see why this don't work...

#

wait, hold on...what did I just do? Why does it work now?

#

I didn't change anything in the menu itself...
Maybe it was something inside the whitelister crashing the menu all along... 🐸

hearty vale
#

I want to make a pickup wish is local for everyone, but a hologram copy appears for remote

This is possible???

frozen igloo
#

you would do that by adding a single pickup to your world, then the VRCPlayerObject script, and then an additional udon script on that object to manage the functionality of the pickup with whatever scripting you want to write.

By putting PlayerObject on it, this one object in editor will be duplicated once per player in client. And the script you put on it will be able to figure out the context of where it's running by comparing the owner of itself to the localplayer. If the localplayer is not the owner, then that means it's a remote playerobject

hearty vale
frozen igloo
#

there is nothing that inherently links together different player objects except for the fact that they are all instantiated from the same template. Once they are spun up and running, they are completely independent and so you can set variables however you like

finite sequoia
#

Something tells me I'm gonna have to redo the whole thing if I ever want my taxis to be sync... 🤣

fallow mountain
#

VRCObjectSync?

finite sequoia
#

that made things worse somehow, things didn't float as much when it was only on the parent

#

To be fair it wouldn't be nearly as bad if it was a propper model and not some cubes thrown around the main object

#

I wonder if it's a case where parent constraints would make more sense than trying to sync all the parts..

#

even tho no parts should be "moving" relative to each others, it's only the parent who drive the whole thing

fallow mountain
#

idk what you doing but why not send network event to tell it where to go, then it will go locally for everyone

finite sequoia
#

That's what it was supposed to do yeah, start the machine-state then it just goes.
But it's an old thing from before I learned about the propper order to send the events yesterday. Hence the "I will need to redo everything" the pic being super obvious was a joke...Because of course I need to if it's this bad xD

#

oh wait, I tried just for the heck of it but it looks like parent contraints do work pretty good compared to the "sync all parts" attempt

#

It just lag behind because don't explode

#

Meh, it's already more acceptable. good enough xD

hearty vale
#

I can do VRC.Udon.Common.Interfaces.NetworkEventTarget.All and .Owner but how can I send an event to everyone EXCEPT the owner?

twin portal
#

send it to All, but then do an ownership check, and skip executing the rest if it's the Owner

fallow mountain
#

Basic question about syncing, if i want to display something correctly, can I not just get GetServerTimeInSeconds every frame?

tulip sphinx
#

display correctly what, animator state? anyway, if were talking optimised and proper way, the amount of update* events and code in them should be minimal, you should always think of ways of NOT doing something every frame first.

fallow mountain
#

say a moving cube, that needs to be the same position for everyone

#

also for late joiner

finite sequoia
fallow mountain
#

what if i dont want any networking, can i not GetServerTimeInSeconds and use it to calculate the position?

twin portal
#

and then what like, mod it by the animation time?

fallow mountain
#

say rotate a clock hand to a correct spot

twin portal
#

oh like not using an animation

#

yeah, you can just translate the servertime into the output display of the clock, essentially?

fallow mountain
#

yeah

twin portal
#

so wether or not you're a late joiner, or been there, you'll be doing the same math

fallow mountain
#

(i havnt learnt animation)

#

yeah so the clock will show the same time

finite sequoia
#

That's quite the roundabout way to do it but I guess if a cycle rounds up exactly to be loopable by minutes it would work

twin portal
#

the server time will be the same for anyone anyway, if I'm thinking it's the right thing

#

an actual animation sync would be neat to make though. it's on my to-do list

tulip sphinx
fallow mountain
#

If I request ownership just before serialization, does it create more lag than say if I requested ownership a few seconds ago?

twin portal
#

changing ownership shouldn't affect performance, you just don't want to request too quickly or the networking will fight itself

strange token
#

Interestingly enough I currently have behavior that is instant when you claim ownership while running it, but if you do that again and are already owner it takes 2-5 seconds to serialize before remote players catch it

#

So I guess for some reason taking ownership forces serialization to happen sooner than if you were already the owner

fallow mountain
#

That is interesting, did you check whether local is owner before requesting ownership?

sick gull
#

^ I always do that

#

Also idk if it matters. I'm not a networking expert but I believe if you are ever running serialization on a script, you should have manual sync mode? (Berate me if I'm wrong)

fallow mountain
#

Yes that is my understanding

strange token
fallow mountain
#

Just wondering if the delay has anything to do with it

strange token
#

Ohh 🤔 I never imagined setting owner when you already are could trigger a delay but I’ll try that and see if it’s any different!

cedar crescent
#

I recall phasedragon mentioning that "it doesn't cause any unnecessary traffic" to call setowner when you're already owner. #udon-networking message

silver hill
#

Alright, so Im having issues with Networking>Getplayerobjects, In editor if I search for what player object 1 is it will be A, but if I publish and go in game and search for player object 1, it will be B, this is seriously messy and is breaking everything, whats going on?

sick gull
#

The order is never the same

silver hill
#

what defines it?

sick gull
#

Idk, I grab playerobjects like this but IK there is a better way

twin portal
#

the order is not guaranteed, so you'll have to account for it

silver hill
#

Is there a way I can define an object as Object 1,2,3,etc?

sick gull
#

idk, I just do it like the screenshot brutha. Never need to care about order

silver hill
#

If only I could read/write code dead

sick gull
#

oh shit ur graph gang

#

yeah my homies don't fw that on hood

#

You would basically

GetPlayerObjects
Loop through them (for each)
Check the name and compare

BUT IK there is a better more clean way

twin portal
#

honestly name is probably the easiest

#

if ClientSim operates the same as PlayerObjects do in-game, they basically keep the same name when it duplicates the object, and just adds a number to it (the one in brackets)

#

so if you have a playerobject named "Cube", and another "Sphere", the function GameObject.name.Contains will be able to differentiate between each (since every player will only have one)

#

as long as the PlayerObjects are not named the same, this method works

silver hill
#

Uhhhhh

#

So... I name object one as "Object one [1]"?

twin portal
#

don't need the brackets

#

the original in my example is "Cube (1)"

#

kinda cut it off a little, it's auto-hidden

silver hill
#

So like this?

#

before>after

twin portal
#

which ones are the PlayerObjects

silver hill
#

Persistence object is what the guns/customisation data etc are inside, the hitbox is... well the hotbox as well as some other stuff that follows their player around

twin portal
#

so

silver hill
#

Those 2 objects have persistence enabled

twin portal
#

you don't necessarily need to change the names

silver hill
#

...

twin portal
#

unless you just want to look for "1" and "2"

silver hill
#

Its an issue because in editor I have to use this device to force the PLAYER PERSISTENCE OBJECT as the target for teleporting the players gun to the player instead of the hitbox

#

In game it works fine but in editor I have to set its value differently for testing

twin portal
#

right I get that

silver hill
#

So can I have a script run oon start that marks each object as 1,2,3 etc?

twin portal
#

no just check the name of the object when you're accessing them via GetPlayerObjects

silver hill
#

Not really sure what you mean, theres no node for getting an objects name

twin portal
#

it's part of GameObject

#

and Contains is part of String

silver hill
#

Right... and how do I use that as part of networking>getplayer objects?

twin portal
#

you need to loop the GameObject[] array that you get out of GetPlayerObjects, and only continue if the name matches

silver hill
#

Ah... thats new to me

twin portal
#

loops are a crucial thing to know about when you're working with arrays; you can create a for loop by holding SHIFT + F, then clicking on the GetPlayerObjects node

silver hill
#

Confusing :L Ok so I got that, not sure how to put it all together

twin portal
silver hill
#

Hmmm

#

I always found programming tutorials are taught by people who arnt really good at speaking at the learners level

#

cupcakes? whah???

twin portal
#

this was like the shortest example that was also not specific to a language

silver hill
#

I see

#

Whats body and exit?

twin portal
#

Body is the part that will be repeated, Exit is the code that will run after the loop is finished

silver hill
#

Makes sense

#

so body is essentially plugged into "For"'s own input invisibly

#

where can I find "For" without having to remember Shift+D

#

Wait was it even Shift D?

#

I forgot already lol

twin portal
#

Shift F but yeah

#

just search "For" and you'll get the For node by itself

#

this quick method of adding it does kinda add a few nodes you don't really need

silver hill
#

Nice

twin portal
#

but it automatically defines the loop to loop for as long as the array is (that's what Get Length is for)

silver hill
#

From that, Im guessing this would be correct?

twin portal
#

that looks alright

silver hill
#

Yey now I can fix the rest of the issues lol

#

If something dont work, hit it harder, if it still dont work... Hit it even harder!, thats my philosophy 😛

twin portal
#

hey, as long as it works

#

but sometimes you're also banging your head through the wall, when there was a door there the whole time

silver hill
#

Yep

#

Now the bruised healing can begin

#

I cant belive VRChat devs didnt just make a integar option in the VRC player object component :L hmmm

#

Maybe down the line

sick gull
#

IDK why it isn't in the same order each time but what happens if you remove one or add a new one? Your scripts will break

#

this is way safer

silver hill
#

Safer... at the cost of having to cycle the code for as long as the list is, I guess its fine a small amount of objects with little need to search, but what if its a massive array and you need to search often...

sick gull
#

There is a way to just grab it

#

I just don't use it. As I said, my method is NOT the best

#

and often you shouldn't loop through them each time

twin portal
#

I'm assuming GetPlayerObjects works similar to some other Unity functions where you get an array of things, that often the order isn't guaranteed by Unity

twin portal
silver hill
#

Yeah, was just a thought

#

Im already using a bunch of arrays, each 100 long, not had to use FOR til this point

twin portal
#

what. what were you doing to go through them

silver hill
#

Theyre just lists, so I have 60 planned guns in my game and 40 gadget items, each gun has a value for damage, weight, range etc

#

So i just been using []get for refering to a stat in a database

twin portal
#

well, if you can work an array without looping it, it's technically more efficient

#

I was worried you were doing array[0] = whatever, array[1] = whatever.... array[100], and just never thinking "surely there is an easier way to do this"

silver hill
#

There is actually a case where I had to make a debug cheat to Unresearch all the guns that I had previously researched just unticking all 100 bools to false using a manual system i made lol

#

I probably invented the FOR before even knowing it even existed :p

#

Wait no thats not the one

#

thats just the debug

#

Where was it...

#

There :p

twin portal
#

a loop that's significantly slower than a real one

#

but it works

sick gull
finite sequoia
#

If you think that's slow you should see mines, I remember one that wait 30 seconds before checking again... 🤣

hybrid kindle
#

is it possible to detect weather a player is on mobile or pc?

twin portal
#

and you don't have to wait for it to actually change, it runs once at the start

hybrid kindle
#

hmm do you think it would be the getjoysticknames one? Ik i can use the anykey for desktop users.

#

or does inputmethod.quest or something like that exist

twin portal
#

it doesn't help that the docs don't have the latest entries of the enum

#

there isn't one quest specific, maybe it's VRCInputMethod.Oculus?

#

there's also QuestHands which I assume is hand tracking

hybrid kindle
#

wouldn't that include rift users though?

twin portal
#

would assume so

hybrid kindle
#

😭 fml

twin portal
#

you can check by doing something like this

#

then run on Quest, and see what it spits out in the logs

#

or just display this in the world somewhere

hybrid kindle
#

ill have to give it a try sometime thank you

twin portal
#

here's all the possible options

hybrid kindle
#

ooohhhh baller thank you

sick gull
#

if by mobile u mean android

#

you can use "Easy Quest Switch" and turn a gameobject on for quest builds. This will signify you are on android vs PC and you can code accordingly off of it

deft bay
#

Ok, this is my set up.

I have stick. If I grab that stick and touch object2(bowl), it would make a sound and make other 55 objects (stations) to appear.

Then, I have second set of sticks. If I touch them together, they would play a sound and then make those 55 objects move in rectangular path one by one (each of 55 objects has script attached to it).
If I touch second set of sticks with each other it would make those 55 objects to move 2x faster and stop at their original position. If I touch these sticks again, all 55 objects will disappear.

Now, if I want to repeat this cycle, I would get the stick from beginning and touch object2(bowl) again it would make those 55 objects appear again which will allow me to repeat this cycle.
I made it work perfectly fine for me.
But whenever I tried to test with second player, he would not see a consequence of me touching those sticks -> he doesn’t see those objects staying/moving or he sees it with glitches.

I added obj sync to each and tried to add some networking addition to code (like stabilization) but it didn’t help.

Does anyone have a suggestion how to make it work? I actually need it to work with up to 55 people in the game.

I know it might be some read, but any help or suggestion would be appreciated!

#

have a stick*

tulip sphinx
fallow mountain
#

You just need to sync the least amount of information, in your situation, it's literally just one integer (touch count) to tell the others (including late joiners) what state the chairs are in

unique osprey
#

I've been making a wave based zombie survival game world,
i'm a game developer / modder, and used my pre-existing c# knowledge and networking knowledge from various mediums like gmod and unity mirror networking,
but i'm having really inconsistent desync issues with my udonsharp networking code.
is there a way to pass in arguments into a method running in SendCustomNetworkEvent? i am having Udonsynced desync issues,
and is there any weird gimmicks to how udonsharp networks stuff?
this whole owner / world master / client setup, is a nightmare for me, and randomly stuff won't set, even when its running on the owner?

#

I feel like there is lacking documentation for the quirks of udonsharp's networking, and its making my knowledge hard to apply / adapt

finite sequoia
finite sierra
# unique osprey I've been making a wave based zombie survival game world, i'm a game developer /...

Udon is sadly pretty poorly made when it comes to documentation. and it lacks aloot of what to do and what not to do etc. you have two ways to Sync things and that is using Continous Sync and Manual. Manual requires the owner of the object to request Serialization and all other people then receive that data that is set on that object. and we have no ways to pass Arguments. and also using SendCustomNetworkEvent is not realiable and is not used to sync things.

#

setting ownership also has a pretty big delay and can cause major issues if to many calls has been done.

#

all your prio knowledge does not apply to UdonSharp or UdonNetworking sadly. and i can confidently say this since i have been not only using unity for a very long time but also been a c# developer, and game developer for a very long but udon made the most simple things complex due to its inherit limits and lack of documentation.

#

and not to mention lack of passing arguments along to sync to other players.

unique osprey
#

this is the doc i've been using, simply relinking the udonsharp doc doesn't help my issues smh.
so you're saying i should go with Manual instead of Continous syncing? and run all my major operations on the owner of the object- and then sync it to clients 2ndarily?
what if a client wants to send data to the owner of the object? what if the ownership of the object changes?? would it change the data to reflect that client's now inaccurate data? thats such a dumb setup

#

in an ideal scenario, i would have everything run on the "server" / master, and make the world master the owner, but then it randomly changes ownership based on contact, and its such a nightmare for me to manage.
would i even be able to apply changes to udonsynced variables then?

finite sierra
#

since Continous sync also has a 200 bytes limit per Serialization.

finite sierra
#

also ownership never changes unless you allow it too.

#

in udon you kinda need every user to have their own object that cannot be stolen. aka Vrc Player Objects.

cedar crescent
#

Master is just whoever owns data that hasn't been explicitly taken ownership of. And the mental model of server, client, or master might be unhelpful. Mostly it's just owner and non-owner. And a player has to take ownership to modify variables

finite sierra
unique osprey
#

imagine an npc is shot with a gun, by a client-
the owner of the npc object would get that data, of the shot vector and its damage 'n such,
and rn in my systems- it would verify the legitimacy of the shot bullet, from the owner's perspective, with the data sent from another client,
and then it would act on that damage, in the npc on the owner, and then sync that with all the clients, for the damage event visually and locally

#

surely there is a way to send this data to the owner in some way?

finite sierra
#

there is two ways. one is to create 100s of methods for each point of damage. which i wouldnt do

#

the second method is whoever shoots. has to have two UdonSynced variables. one that tells who they shot. and the other is the damage they did. sadly doing it this way requires you to check a collection of weapons that are in play and check their stats etc. but even with that you would have to check if its valid as well and so onn

#

and there is no way to send data to a owner. from a non owner. you can only tell them to run a method or do something.

fallow mountain
#

just detect shots locally and if it is hit, SendNetworkCustomEvent to owner to damage the zombie, then you are sending minimal amount of information, they can then calculate what the damage is, based on what they know about your weapon (information you synced to them before)

#

in fact, SendNetworkCustomEvent to everyone, they all render locally the shot

#

i dont actually know but there is already a zombie game, so surely there is some way

finite sierra
obtuse echo
# unique osprey imagine an npc is shot with a gun, by a client- the owner of the npc object woul...

SendCustomNetworkEvent is notoriously slow to send. And no, there are no parameterized version of it. Someone made an asset that mimics the SendCustomNetworkEvent with parameters: https://github.com/Miner28/NetworkedEventCaller
Although I keep suggesting it to people, I've yet to stress test it myself.
I personally usually tend to use synced variables for everything (that asset I linked uses them under the hood btw).

finite sierra
finite sequoia
#

At this point nothing is a solution "good enough to be recommanded" but people still have to make things work somehow... xD

fallow mountain
#

Even without the zombies, if someone fires a gun, they need to send a network event, that is the minimum, so that other people can at least know to play a fire animation and make the gun noise... now imagine the zombies are all run locally, all their damage and dying are local... you don't even need extra networking. There will be desync, but that is I guess a matter of game design to make it not matter so much, which idk the answer. Maybe that can be your strategy.

obtuse echo
#

The ideal way currently is to use PlayerObjects as channels to sync everything (can't be taken ownership from so safe against cheating too). So I'd have a script on the PlayerObject that syncs the damage event with all the required data. Everyone else knows who is doing damage to what and can change visuals appropriately. But that involes a bit of overhead.

obtuse echo
finite sierra
#

when it comes to udon there isn't really anything i would consider smart.

#

like making any fps in udon is not going to be something that is possible. and its not ment for it either. as it is just to slow and we dont have the required networking for it.

obtuse echo
# unique osprey in an ideal scenario, i would have everything run on the "server" / master, and ...

Ownership doesn't change randomly. I think only the VRCObjectSync component can do that when you have physics object that collide (it's a setting you can disable too). It only changes when you call SetOwner or if someone leaves. But then you can consider the new owner to be the "server".

The simplest stupid method to get decent networking is to just take ownership every time you shoot something and then sync the decreased HP. Yes, you will get conflicts if something is being shot at the same time, but it's simple with little overhead.

If you want something more like a "server" concept, then you'd need to have "player owned objects". The new PlayerObjects make it a lot easier, you should use them. Those can then be used to send the damage events to the "server" who then syncs the health of the npc, which is only ever owned by the "server".

unique osprey
finite sierra
fallow mountain
#

I guess you just want the "action" be as deterministic as possible, and can rely on slowly synced data to get very similar or indistinguishable results. Now from observation remote players only sync their movement/aim angle every second or so (if you ever nodded to someone quickly, it won't show up on their end), so your game need to be take into account this fuzzyness... there is no twitch action ever, forget about it, unless your "quick time event" is done locally and you only send the result, so you can still have some element of twitch action, but you just gotta do it locally.

finite sierra
#

Player A Shoots Player B. in this case Player A hits Player B. and Player A request a serialize that then tells everyone else it has updated its data. then Player B puts in those data that comes from Player A and Requests it.

#

then Player A receives the new data on the one they shot.

#

this does mean you have two requests per shot.

#

alternatively is to have fixed data that all people have locally. and then you just need to check what they have. and calculate it based off that

obtuse echo
# finite sierra changing overship every shot is not going not work. to many requests and a serve...

Nah it will work unless you want to have 5+ people shooting the same target, then yeah, but that's where smart game design comes in. That's why it's the simple stupid solution. It will work in a lot of cases. Just not when everyone has to focus a huge boss or something.
Also, you seem to not understand how networking works. It doesn't matter who syncs it, all people are going to get all data anyways. Player owner objects means there will be no ownership transfer which makes sending data a lot cheaper and faster.

finite sierra
#

then you just need to sync what weapon, and what modifiers that person has.

finite sierra
#

and it will fail

#

its not recommended to change owner often.

obtuse echo
finite sequoia
#

wouldn't most player stats be able to be sync beforehand so it's safe to access for calculations and don't need to be sync all the time? Like...sync it on weapon change but that's it, the value stay the same otherwise.

finite sierra
finite sequoia
#

ye

finite sierra
#

so everyone knows what each weapon and modifier does

#

and all you need to do then is just when something is shot. update it based on that

finite sequoia
#

it's the basics of any equippement system. same goes for protective gear (even if it only exist in a menu because avatar shapes differ)

finite sierra
#

mhm. atm having dynamic data is not really possible.

#

it all gotta be fixed.

#

unless you want to go through the hassel of changing owner and then setting the data and then verifying it etc

#

which would ruin any fast phased games.

#

and also heavily limit the amount of people.

#

to possible 8-16 only

finite sequoia
#

to be fair there's quite a few zombie maps on VRc and, as imperfect as they are, they're still fairly playable. Most restrict the players to not be more than a party (which stays wy below the 30 players thresold you mentionned before) so there's ways to work with the limitations rather than against them

#

a map that's 4-12 players should be fine

#

12 is already A LOT of people when you have to shoot stuff...

#

unless it's PvP I mean, but PvE it's a lot

#

But yeah, "fixed" stats you only sync when changing, then use "as is" for calculations. Only need to sync the calculation result
then play the visual "hit animation" which isn't too much of a problem if it's slightly delayed, since it's just flavor/feedback

fallow mountain
#

I wonder if you can even package "firing events" into two-second chucks, so while there is two seconds lag but the shots timing will be consistent internally

finite sequoia
#

could add a multiplier depending on number of shot registered during the delay xD

fallow mountain
#

combined with getservertime... and deterministic "battle" that have the zombie play an animation that is synced, like a synced video player, we can sort of know the exact timing someone made a shot at what time into the animation

#

...maybe too complicated

finite sequoia
#

that seems a bit too much now.. ._.

#

but the "combo" chunk system could be cool for more action oriented map and less horror

fallow mountain
#

yeah combo is a good game design

finite sequoia
#

"go ham or go home" damages xD

fallow mountain
#

to make the events as slow as possible

finite sequoia
#

it's funny to me how people who actually knows what they're doing complain about "when you have more than 30 players" and there I am worlds crashing if there's 3+ in mines... 🤣

#

if you get a party of 4-8 to run without problems you're fiiiine

#

like, really xD

finite sierra
fallow mountain
#

btw the zombie map can have like 100+ zombies at one time

unique osprey
#

the wave based zombie survival world i'm working on,
can handle up to 64 waves, with a total of 128 undead, of type 0 and type 1, if i consider other possible variations, the amount gets cascadingly larger,
but their processed in bulk by the wave manager, so their simply just representations of the data of what undead are where and doing what

#

I was hoping to simulate the undead per client as-is, and then only network position data every now 'n again, their agro status and damage events 'n such,
but im having to rewrite a lot of it anyway

#

the harder thing to network is what undead are spawned where, when a wave starts,
and also what is damaged / repair status,
as they can break walls, doors, windows and such.

finite sierra
#

each zombie should have a ID that is fixed. so a number of 1 to 128 for that is fine.

#

each zombie should have a float or short for health. depending on if you want decimals or not. make sure that its UdonSynced. andn each zombie must have the UdonSyncBeaviour be manual.

#

and each zombie should also have anonther int that is used to check which user its aggroed to at the given moment. again make sure its UdonSynced

#

same goes for the Wave count etc also needs to be UdonSynced. but only needs to be a byte.

#

all in all a zombie only needs 3 or 4 viables that are UdonSynced and should in theory only require 20-28 bytes per serialize.

unique osprey
# finite sierra that isn't so much of an issue luckly. having 128 objects at any given time make...

i made my own system of object caching, and they all exist in a sorta ghost state until in their spawned state,
all their colliders, renderers, operations and children that be cosmetic, are hidden away until spawned, and then hidden again when they are deloaded for the next wave.
they are pulled and put back into the undead cache of the wave handler, with no definition of what one is what- as its irrelevant,
all their data is reset per wave, and there are 64 of each undead type, currently 2, so there are 128

#

even in the unity editor- they hide according to their spawned status

finite sierra
twin portal
#

If she made it herself, then surely it exists, no?

unique osprey
#

just my system involves them never being disabled, meanwhile the other method for object pooling results in them being disabled when not active

finite sierra
unique osprey
#

so i just made my own object pool then? figured, i just looked at what was obvious and made one myself for my use case

finite sierra
#

sounds like it

unique osprey
#

anyway the navmesh agents glitch out if i disable them on load

#

so it was just my solution to it- to keep them enabled but forcibly make my own loading and unloading system, where they are never disabled as objects

#

i would port over my own pathing algorithm from one of my other projects, but the main issue with such an idea is the networking, and i dont wanna mess with trying to rewrite one of my old algorithms to work with this scuffed networking- that i have yet to even sort out for just basic stuff yet

#

having it entirely client-side isn't a good solution forever, but atleast the agents are semi predictable if you put them in the same position and velocity

scenic sky
#

I hope it's alright for me to ask questions about networking and trying to understand how it all works

I remember talking here earlier about shooting someone's hit box and then telling them report the damage you did.

I'm wanting to understand the concept of why and how things need to be done in general and the cases.

I know that's pretty vague or way too general so I'll talk about the thoughts that appear in my mind.

The first thing that appears in my mind is shooting a target.

Let's say this target has 100 health.

Does it need to contain a udon synced variable for its health in order for it to be networked?

If a player shoots this target with their gun, do they need to own that target in order to change its health?

If so, how would you become the owner of it?

If you are shooting particles from a VRC pick up gun you are holding, are you the owner of that gun and the particles fired from it?

Does ownership of particles matter when it comes to interacting with player own objects such as hitboxes and host own objects such as a target?

These are just random thoughts and examples I had in my mind. I'm trying to understand how the networking works.

If anyone has any better examples or is willing to explain it to me with the examples I provided I would appreciate it

Networking has always been a challenging thing for me and I wanna improve my knowledge of it

frozen igloo
# scenic sky I hope it's alright for me to ask questions about networking and trying to under...

The entire concept of ownership simply means the person who has authority over the current state of the synced variables. If something does not have synced variables, then its ownership does not matter.

VRCObjectSync goes through the same architecture, so its position is analogous to

Likewise, if you want to directly change the synced variables but do not currently have ownership, then the first step is to take ownership. After that, you can set variables and requestserialization (if it's manual)

Consider a couple of factors though. What happens if two people try to take ownership and set variables at once? We don't know the future and latency is a thing, so if two people take ownership of the same thing at the same time, they'll fight over it. Perhaps the health is 10, and one person has a gun that does 2 damage while the other person has a gun that does 3 damage.

If the first person shoots it does 10 - 2, take ownership, set new health to 8. Then if there's enough time between that and the second person shooting it, then the second person will do 8 - 3, take ownership, set new health to 5.

However, if they shoot it at the exact same time, then one person will do 10 - 2, and the other person will do 10 - 3. Neither of them knows the other person shot at that point, and so they won't be able to add the damage on top of each other.

That said, that's not the only way of doing that. Instead of taking ownership of the target, you could sync everything through a script on the gun. If one gun says "I shot this target and did 2 damage" and then another gun says "I shot this target and did 3 damage" then it doesn't matter which order they did that in or which order the events are received, everybody can see both of the messages.

This doesn't mean that either way is particularly bad, it just means that they fit different use cases. Consider a simple toggle door - if two people try to open it at the same time, you don't want to open and then immediately close it, right? If both people are trying to open it, then all that matters is that it's open. You don't care that one of those messages was ignored.

Different methods for different use cases.

fallow mountain
#

What is the best way to make one gun say "I did 2 damage"? Do I set a variable "lastHitTarget" = MonsterA and "last hit damage" = 2 and then request serialization and then (immediately?) send networked custom event "ShotFired"?

scenic sky
#

First, thank you taking the time to write that out, it does help me understand especially with edge cases.

I remember in a previous conversation we had the situation I had going was using player object as the hit box which can't be owned by anyone else so I was wondering if you could potentially dive deeper into that concept of how you can shoot someone and have them handle the health changes.

I believe we had a gun script going which has a set amount of damage and we somehow communicated that damage to the owner of the hitbox and had them handle it.

Now i also remember that the health state was handled locally since there was no need to network it for other players

I'm curious of how that concept works

scenic sky
twin portal
#

that's a really interesting way to do weapon damage

scenic sky
fallow mountain
#

Send networked event "Damage1" "Damage2" "Damage3" .....
lol

#

hmm that doesn't look very flexible

twin portal
#

oh that's not what I got from that

fallow mountain
#

what if I for loop counts for "damage" times and fire a number of "do1damage" (im joking)

twin portal
#

I think you'd calculate the boss health by doing "TotalHealth - gun1Damage - gun2Damage... gunNDamage"
each player is networking the damage they deal, do so with Continous sync so it's pretty fast, and so it doesn't matter if player 1's damage or player 2's damage gets there first, AND you don't have to fight over ownership of a variable

cedar crescent
#

Hm continuous can miss updates though, right?

twin portal
#

well that's the point, it doesn't matter if it's missed

#

if local player's gun did 1 damage, then 2, then 3, but network only synced 1 and 3, it's fine, you only need the latest state

cedar crescent
#

yeah but if I take a bunch of shots quickly? Wouldn't some of them possibly get dropped?

twin portal
#

you wouldn't be caring about detecting other players, hit, only your own gun hitting locally

#

it's not the bullets hitting that sync, it's just the damage that player is reporting they've dealt

obtuse echo
twin portal
#

yeah you'd have to expand it for each enemy

cedar crescent
#

yeah I was thinking some kind of most recent shots queue or something would be needed. But I haven't actually done anything action-oriented, so idk what the best solutions are

obtuse echo
#

But yeah, been a while since I tried anything that requires that much information. Not sure myself atm

fallow mountain
#

It is almost we need something other than variables and events, like an event with input nodes to plug in a variable to be sent one-time......

twin portal
#

manual usually ends up being slower

#

most cases manual works best, but there are times where you need things to update quickly, and manual won't cut it

obtuse echo
twin portal
#

continous has the advantage that it will interpolate values inbetween, so the value will seemingly update faster than it's actually getting updates

twin portal
#

yeeah the one for manual I believe is a typo

obtuse echo
#

Manual also mentions doing it quickly

twin portal
#

the same sentence contradicts itself

sick gull
#

There are many issues with the docs :))

twin portal
#

a few weeks ago I submitted a request to edit this very article (as it still has the old Manual sync limit too), but I guess nobody checks them

obtuse echo
twin portal
#

manual definitely has the chance to not be quick at all

#

it purely depends on the package size

#

if you try to sync around the limit (280kb), it can take 30-35 seconds for other players to receive it

#

100kb is around 10 seconds

obtuse echo
# twin portal 100kb is around 10 seconds

I assume that's because of other stuff related to player position, ik stuff etc? If you only sync small amounts of data, relatively speaking, then it should be pretty fast if not instant.

#

Of course, I'm just guessing here. But I heard this said multiple times that the limit isn't just for manual but includes other things too.

twin portal
#

this is true, the limit for manual syncing, 280,496 bytes, is the absolute maximum limit. There's a little bit of overhead. In my experiments a more realistic limit was 280kb that still managed to work

#

so if your world is very full it will push down that limit even more

obtuse echo
strange token
#

Theoretically, if I'm currently having no issues saving/syncing an array of 1764 strings, would combining them and syncing a single string be less easy to work with?

#

Syncing arrays is annoyin because I often need an arbitrary length change, but if that limitation doesn't exist with strings I'd rather just locally parse the synced string into an array as-needed instead

#

I'll be investigating this soon so if you have any worries after reading this, please lmk 🙏

twin portal
#

Only thing I can think of is I think Udon limits how long a single string can be

#

I don't feel like I'm remembering right but I think it's 100k characters

strange token
twin portal
#

You'd have to test I don't think this is documented anywhere

#

Just keep making a string longer until the script crashes

finite sierra
twin portal
#

Ok

finite sierra
#

and has alot of contradicting explanations

fallow mountain
#

Is there documentation for network get server time? And time get UTC time? I want to know if there is any network traffic generated, or if UTC time is from a time server therefore more accurate or something

#

And I wonder which is better for syncing purposes

twin portal
#

docs don't really detail much

tulip sphinx
#

@fallow mountain utc time is your local pc time. but given youre connected to the net, it should be well within 1 second for everyone.

fallow mountain
#

You mean it is just UTC calculated from time zone and local clock? ok that cannot be reliable then, and can be spoofed

outer crater
#

Hello everyone, I need help. I am making my Bachelors Dissertation project in AI using VRChat. I am analyzing a songs emotional content over time using a neural network and mapping that to corresponding character dance animations. I need to connect my VRChat world to a server so that when a user selects a song using the in-world UI, it sends a request, the server processes the song using the trained neural network and sends back a JSON file which can then be used to play the corresponding character animations along with song playback. I have decent experience with Unity, however, have no experience with connecting a world to an external server and I do not know the VRChat (Udon) specifics. If anyone knows how to do that, please give me some hints, refer me to a place where I can get more info, or best of all, get in touch with me. Much appreciated.

lone zealot
# outer crater Hello everyone, I need help. I am making my Bachelors Dissertation project in AI...

Due to VRChat having a very high priority on security and privacy, they limit your ability to send data out of VRChat heavily. You can generally only make requests via a URL that was manually entered (or at least pasted) in by a user directly, or hardcoded into the world at upload. Furthermore VRChat does not allow arbitrary HTTP requests to be made, but specifically only via the VideoDownloader, StringDownloader and ImageDownloader APIs. You can also only make one HTTP request every 5 seconds. No matter what.
All of these restrictions make it very hard to dynamically make requests out of and deliver content back into VRChat.

outer crater
sick gull
#

I mean you can store their movements I guess and have them export it out as a string?

#

or nvm

#

idk what ur trynna do. Good luck tho.
sounds hard

outer crater
#

I only need to send to the server the song that was selected, so it can process it and send back an encoded array something like [0-15:sad, 15-25:neutral, 25-50:excited]

lone zealot
#

But you can also just ask your questions here and I will try to answer them

outer crater
sick gull
#

You can hard code strings on github for each song with the data you need

lone zealot
#

What I would do is host a Webserver which provides an endpoint where one of the URL parameters is the song that was selected.
Then inside the VRC client use the StringDownloader API to make the request to your server.
Your server then processes whatever youre doing and replies with a JSON string, which you can then parse using VRCJson back on the client.

outer crater
#

My brain is going brrr. Thank you so much for the responses, I have hope that this will be possible, my bachelors depends on it 😅. I have to sleep now and will continue figuring it out tmr.

finite sequoia
# outer crater Hello everyone, I need help. I am making my Bachelors Dissertation project in AI...

Like HeplfulHelper said, VRc is very strict on data collection.

What you're trying to do however, only "which song have been selected" is needed, right? Everything else is external and related to the AI, not any players from what I understand?
Maybe you can get away with using OSC to drive the responses (but compute everything externally) and play the song outside of VRchat "for the AI to hear it" but players don't have to know about that little cheat. Send the play request in-world and separately to whatever the AI is actually listening to and...it should be ok?

#

It feel to me the VRchat portion is just flavor in this explaination, and everything could be done externally aside of the call to tell which song needs to start (and the returning OSC commands to drive the virtual-player AI)

tawdry silo
#

Trying to write a comparatively simple rideable vehicle script.
On local side, its smooth, works great.
On remote site, motion is jittery.
I tried a few methods to script interpolating the recieved position for non-owners. I think I am fundamentally misunderstanding something though.

When I try to change the code to smoothly interpolate the position, I somehow always end up breaking the network logic? And then, only the first person to join the instance is able to ride any of the rafts.
But, once that person leaves a raft, suddenly other people can ride that specific one.

#

Wondering if anyone has any ideas on what I am misunderstanding. I'm sure it's something dumb. TLDR, That script is working as expected, but I am having a hard time implementing smoothed motion.

#

Here is an example of me trying to Lerp-N'-Slerp the non-owner motion. The smoothing worked quite well, but now for some reason, the rafts (stations) are locked out for anyone but the instance owner

#

Any help is so appreciated, X_X

fallow mountain
#

I wonder if syncing the movement should just leave it to VRC Object Sync

#

Manual sync is not continuous and probably not suitable for movement syncing

tawdry silo
#

Upon further testing, it seems the motion on the raft itself in the first script (with VRCObjectSync component on the station as well, not sure if thats best practice) is actually pretty smoothed. But, the player model is jittering like crazy

cedar crescent
tawdry silo
#

I'll try that and report back thanks :3
I wonder though - is this being called when the player clicks on the station? Or only once they actually enter the station? Because, in the first script, anyone can join any station as expected. But in the second script, only the instance owner can use the stations at first. For others, they highlight, but dont get put in the station when they click

fallow mountain
#

Once they actually enter

tawdry silo
#

Ok. I wonder why then, though the networking logic isnt really changed between the two scripts (besides non-owners interpolating the synced position), suddenly they can't enter the station.

#

TLDR, First script is working as expected, Raft itself is being smoothly synced (I suppose for no other reason than VRCObjectSync being on the station) - but the player model of the riders, is jittery and choppy when they're driving the raft

fallow mountain
#

is the raft and station the same object?

#

Everything is same object?

tawdry silo
#

Yes. I started with the VRCChair3 prefab, and put this script as well as a VRCObjectSync on the station object.

#

Before, I tried having the station as a child, but then OnStationEntered/Exited wasn't popping.

fallow mountain
#

I think your manual calculation and VRC Object Sync might conflict each other, I would just let it do its thing and not touch the transform at all

#

Yeah OnStationEnter/Exit needs to be on the VRC Station object

#

Just worry about control, and don't worry about syncing at all, leave it to VRC Object Sync

tawdry silo
#

Ok

#

So, do you think, effectively, commenting out / removing the entire "OnDeserialization" block would be in line with that approach?

fallow mountain
#

yeah, and the FixedUpdate

tawdry silo
#

Thank you for your help!
Occams Razor really applied here.
Gosh, I was entering so many layers of convolution, last night I even had an entire "Raft Manager" trying to juggle who owned what. It was such a mess.

Here is the working final script for the rafts now found in my world **Furry Grotto **(At least, before I add more functionality). Hopefully this can help someone in the future. The setup is, this U# script is attached to a station which also has a VRCObjectSync component on it. Not sure if it's relevant but I have the station set to "Immobilize for Vehicle" and the ObjectSync has "collision transfer ownership" off

fallow mountain
#

nice

outer crater
#

Two questions:

  1. When you set up an external server, which hosting service do you use
  2. How does setup in VRChat look like? Do you simply need a script? If yes, can you send me an example script that handles sending and receiving requests.
finite sequoia
#

do you mind if I re-send it in DMs?

#

But yeah VRchat does have documentation about OSC and a list of ressource (aka, known projects and modules the users tend to trust) you can search for it

#

your best bet is to contact said ressources devs and community servers, they're specialists and will have actual answers on what they experimented with and is actually possible or not

outer crater
outer crater
solar nebula
#

i am in need of help getting the networking and object sync playable for a new game world im making. the world has pickupable gameobjects (playing cards) and im finding that the draw mechanic for the cards leaves then un-interactable, unvisible, or simply their transform isnt the same as others. it works perfectly fine with a single person in the world but ya cant really play a board game alone

brisk spade
# outer crater Hello everyone, I need help. I am making my Bachelors Dissertation project in AI...

Are you talking arbitrary songs or a preset list? The later seems like you could pre bake it into the world.

But the former you’re probably better at looking into the YouTube search prefabs and how they work. That’s a more complex setup where everything is actually handled externally, and it has an array of URLs pre baked into the world. The server sends back multiple options, each with a specific url assigned . Since they’re pre baked the URLs themselves aren’t dynamic — you’re instead communicating via url selection.

Alternatively you do a very simple, build the url and present it to the user in a text box to copy from, and then have them paste it into a url entry box. A couple of vket’s have used this approach for cross-world persistence.

Exfiltration of data is possible, though you have to be careful to stay in vrc rules and it can be slow, but by minimizing the data to the absolute minimum needed you can make it work.

Even if they make the music using in-world instruments you could use the copy+paste method to send larger amounts of data.

outer crater
outer crater