UdonSharp
UdonSharp copied to clipboard
When using SetOwner from not owner player, strange problem happen
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:
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 :
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 :
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;
}