vrchat-community / UdonSharp

A compiler for compiling C# to Udon assembly
https://udonsharp.docs.vrchat.com
MIT License
463 stars 50 forks source link

When using SetOwner from not owner player, strange problem happen #56

Open arumogina opened 1 year ago

arumogina commented 1 year ago

I will write the code and the result of it.

U# version : 1.1

pattern1 this is correct pattern.

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class GameMastar : UdonSharpBehaviour{

    [SerializeField] GameReady game_ready;
    [SerializeField] EachLocalDataForSyncList eld_list;

    [SerializeField] FootSoundList foot_sound_list;

    public void Phase1Ready(){

        GeneralMethods.OutLog("Phase1Ready");
        if(!Networking.IsMaster) {
            GeneralMethods.OutLog("Not Master");
            return;        
        }
        VRCPlayerApi[] players = GeneralMethods.GetPlayers();
        game_ready.SetFootSound(players); 
        game_ready.SetEachLocalDataForSync(players);
        WaitReadyEachLocalDataForSync();
    }

    public void WaitReadyEachLocalDataForSync(){
        GeneralMethods.OutLog(nameof(WaitReadyEachLocalDataForSync));
        if(game_ready.ConfirmEachLocalDataFoySyncOwner()){
            Phase2Ready();
        }else{
            SendCustomEventDelayedSeconds(nameof(WaitReadyEachLocalDataForSync),2.0f, EventTiming.Update);
        }

    }

    public void Phase2Ready(){
        GeneralMethods.OutLog("Phase2Ready");
        FootSound[] kk =  (FootSound[])foot_sound_list.GetList();
        GeneralMethods.OutLog("FootSound player_id :" + kk[0].GetTargetPlayerId().ToString());
        GeneralMethods.OutLog("FootSound player_id :" + kk[1].GetTargetPlayerId().ToString());
    }

//ユーザーごとのローカルデータ共有用のクラス

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class EachLocalDataForSync : BaseUserData
{
    [UdonSynced,HideInInspector] public int[] auto_skill_id = {-1,-1,-1};
    [UdonSynced,HideInInspector] public int manual_skill_id = -1;

    protected override void WhenTargetPlayerIdSeted(){
        base.WhenTargetPlayerIdSeted();
        if(Networking.IsOwner(Networking.LocalPlayer,gameObject)){
            ChangeOwnerToTargetPlayer();
        }

    }
}

result: R0

pattern2

//same as pattern1
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class GameMastar : UdonSharpBehaviour{

    [SerializeField] GameReady game_ready;
    [SerializeField] EachLocalDataForSyncList eld_list;

    [SerializeField] FootSoundList foot_sound_list;

    public void Phase1Ready(){

        GeneralMethods.OutLog("Phase1Ready");
        if(!Networking.IsMaster) {
            GeneralMethods.OutLog("Not Master");
            return;        
        }
        VRCPlayerApi[] players = GeneralMethods.GetPlayers();
        game_ready.SetFootSound(players); 
        game_ready.SetEachLocalDataForSync(players);
        WaitReadyEachLocalDataForSync();
    }

    public void WaitReadyEachLocalDataForSync(){
        GeneralMethods.OutLog(nameof(WaitReadyEachLocalDataForSync));
        if(game_ready.ConfirmEachLocalDataFoySyncOwner()){
            Phase2Ready();
        }else{
            SendCustomEventDelayedSeconds(nameof(WaitReadyEachLocalDataForSync),2.0f, EventTiming.Update);
        }

    }

    public void Phase2Ready(){
        GeneralMethods.OutLog("Phase2Ready");
        FootSound[] kk =  (FootSound[])foot_sound_list.GetList();
        GeneralMethods.OutLog("FootSound player_id :" + kk[0].GetTargetPlayerId().ToString());
        GeneralMethods.OutLog("FootSound player_id :" + kk[1].GetTargetPlayerId().ToString());
    }
[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class EachLocalDataForSync : BaseUserData
{
    [UdonSynced,HideInInspector] public int[] auto_skill_id = {-1,-1,-1};
    [UdonSynced,HideInInspector] public int manual_skill_id = -1;

    protected override void WhenTargetPlayerIdSeted(){
        base.WhenTargetPlayerIdSeted();  
        if(Networking.LocalPlayer.playerId == target_player_id){
            ChangeOwnerToTargetPlayer();
        }

    }
}

result : R1

FootSound player_id Should not have 0, should have 2.

pattern3


[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class GameMastar : UdonSharpBehaviour{

    [SerializeField] GameReady game_ready;
    [SerializeField] EachLocalDataForSyncList eld_list;

    [SerializeField] FootSoundList foot_sound_list;

    public void Phase1Ready(){

        GeneralMethods.OutLog("Phase1Ready");
        if(!Networking.IsMaster) {
            GeneralMethods.OutLog("Not Master");
            return;        
        }
        VRCPlayerApi[] players = GeneralMethods.GetPlayers();
        game_ready.SetFootSound(players);        
        game_ready.SetEachLocalDataForSync(players);
        WaitReadyEachLocalDataForSync();
    }

    public void WaitReadyEachLocalDataForSync(){
        GeneralMethods.OutLog(nameof(WaitReadyEachLocalDataForSync));
        FootSound[] kk =  (FootSound[])foot_sound_list.GetList();
        GeneralMethods.OutLog("FootSound player_id :" + kk[0].GetTargetPlayerId().ToString());
        GeneralMethods.OutLog("FootSound player_id :" + kk[1].GetTargetPlayerId().ToString());
        if(game_ready.ConfirmEachLocalDataFoySyncOwner()){
            Phase2Ready();
        }else{
            SendCustomEventDelayedSeconds(nameof(WaitReadyEachLocalDataForSync),2.0f, EventTiming.Update);
        }

    }

    public void Phase2Ready(){
        GeneralMethods.OutLog("Phase2Ready");
        FootSound[] kk =  (FootSound[])foot_sound_list.GetList();
        GeneralMethods.OutLog("FootSound player_id :" + kk[0].GetTargetPlayerId().ToString());
        GeneralMethods.OutLog("FootSound player_id :" + kk[1].GetTargetPlayerId().ToString());
    }
same as pattern2

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class EachLocalDataForSync : BaseUserData
{
    [UdonSynced,HideInInspector] public int[] auto_skill_id = {-1,-1,-1};
    [UdonSynced,HideInInspector] public int manual_skill_id = -1;

    protected override void WhenTargetPlayerIdSeted(){
        base.WhenTargetPlayerIdSeted();  
        if(Networking.LocalPlayer.playerId == target_player_id){
            ChangeOwnerToTargetPlayer();
        }

    }
}

result : R2

If access to player_id value before Phase2Ready, player_id become correct value.

++++OtherCode

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

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class BaseUserData : UdonSharpBehaviour
{
    [UdonSynced,FieldChangeCallback(nameof(SyncedTargetPlayerId))] protected int target_player_id = -1;        
    protected VRCPlayerApi target_player = null;

    public bool IsUsed(){
        if(target_player_id != -1 && Utilities.IsValid(target_player)) return true;
        return false;
    }

    public bool IsTargetPlayerBeOwner(){
        if(target_player == null) return true;
        if(Networking.IsOwner(target_player,gameObject)) return true;
        return false;
    }

    public int GetTargetPlayerId(){
        return target_player_id;
    }
    int SyncedTargetPlayerId{
        get => target_player_id;
        set { 
            target_player_id = value;
            if(target_player_id != -1){
                WhenTargetPlayerIdSeted();
            }
        }
    }

    protected virtual void WhenTargetPlayerIdSeted(){
        target_player = VRCPlayerApi.GetPlayerById(target_player_id);
    }

    public void ChangeOwnerToTargetPlayer(){
        if(target_player == null) return;
        Networking.SetOwner(target_player,gameObject);
    }

    public void SetPlayer(int player_id){
        if(!Networking.IsOwner(Networking.LocalPlayer,gameObject)){
            GeneralMethods.OutLog("BaseUserData.SetPlayer : not owner");
            return;
        }
        SetProgramVariable("target_player_id",player_id);
        RequestSerialization();
    }

    public void SyncReset(){      
        if(!IsUsed()) return;
        SendCustomNetworkEvent(NetworkEventTarget.All,nameof(Reset));
        Networking.SetOwner(GeneralMethods.GetMaster(),gameObject);
    }

    public virtual void Reset(){
        target_player_id = -1;
        target_player = null;
    }               

    public override void OnPlayerLeft(VRCPlayerApi player){
        if(Networking.IsOwner(Networking.LocalPlayer,gameObject)){
            if(player.playerId == target_player_id){
                SyncReset();
            }
        }
    }

    public override void OnPlayerJoined(VRCPlayerApi player){
        if(Networking.IsOwner(Networking.LocalPlayer,gameObject)){
            RequestSerialization();
        }        
    }

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

[UdonBehaviourSyncMode(BehaviourSyncMode.Manual)]
public class FootSound : BaseUserData
{
    [SerializeField] AudioSource run_sound;
    [SerializeField] AudioSource walk_sound;
    private bool is_walk_sound_playing = false;
    private bool is_run_sound_playing = false;    
    void LateUpdate(){
        if(Utilities.IsValid(target_player)){
            transform.position = target_player.GetPosition();            
            float spd = target_player.GetVelocity().magnitude;
            spd = Mathf.Round(spd);
            float walk_spd = target_player.GetWalkSpeed();
            float run_spd = target_player.GetRunSpeed();
            if(target_player.IsPlayerGrounded()){
                if(spd < walk_spd){
                    if(is_walk_sound_playing) StopWalkSound();
                    if(is_run_sound_playing) StopRunSound();
                }else if(walk_spd <= spd && spd < run_spd){
                    if(!is_walk_sound_playing) PlayWalkSound();
                    if(is_run_sound_playing) StopRunSound();
                }else if(run_spd <= spd){
                    if(is_walk_sound_playing) StopWalkSound();
                    if(!is_run_sound_playing) PlayRunSound();
                }
            }else{
                if(is_walk_sound_playing) StopWalkSound();
                if(is_run_sound_playing) StopRunSound();
            }
        }        
    }

    private void PlayRunSound(){
        run_sound.Play();
        is_run_sound_playing = true;
    }

    private void StopRunSound(){
        run_sound.Stop();
        is_run_sound_playing = false;
    }

    private void PlayWalkSound(){
        walk_sound.Play();
        is_walk_sound_playing = true;
    }

    private void StopWalkSound(){
        walk_sound.Stop();
        is_walk_sound_playing = false;
    }

    public override bool OnOwnershipRequest(VRCPlayerApi requestingPlayer, VRCPlayerApi requestedOwner){
        return false;
    }
}
GameReady

    public bool ConfirmEachLocalDataFoySyncOwner(){
        EachLocalDataForSync[] elds =  (EachLocalDataForSync[])eld_list.GetList();
        foreach(var eld in elds){               
            if(!eld.IsTargetPlayerBeOwner()) return false;
        }
        return true;
    }