Пример #1
0
        public bool Clear()
        {
            if (!udonDebug.Assert(Utilities.IsValid(playerList), "playerList invalid", this))
            {
                return(false);
            }

            playerList.DiscardInvalid();

            if (IsActiveAndEnabled())
            {
                if (!udonDebug.Assert(Utilities.IsValid(betterPlayerAudio), "playerAudio invalid", this))
                {
                    return(false);
                }

                if (playerList.players != null)
                {
                    foreach (var affectedPlayer in playerList.players)
                    {
                        betterPlayerAudio.ClearPlayerOverride(this, VRCPlayerApi.GetPlayerById(affectedPlayer));
                    }
                }
                // DeactivateReverb();
            }

            playerList.Clear();
            return(true);
        }
    public bool LocalIsOwner()
    {
        if (ownerPlayerId <= 0)
        {
            return(false);
        }
        var managedPlayer = VRCPlayerApi.GetPlayerById(ownerPlayerId);

        if (Utilities.IsValid(managedPlayer))
        {
            return(managedPlayer.isLocal);
        }

        Debug.LogWarning("Managed player was not cleared before LocalIsOwner was called. Odd!");
        if (ownerPlayerId == 123456)
        {
            Debug.Log("Oh, it's a dummy player! False alarm, carry on.");
        }
        else
        {
            ownerPlayerId = -1;
        }

        return(false);
    }
Пример #3
0
        public void OnEnable()
        {
            Start();

            if (!udonDebug.Assert(playerList, "playerList invalid", this))
            {
                return;
            }

            playerList.DiscardInvalid();
            if (playerList.players == null)
            {
                return;
            }

            foreach (var playerId in playerList.players)
            {
                var playerToAffect = VRCPlayerApi.GetPlayerById(playerId);
                if (!Utilities.IsValid(playerToAffect))
                {
                    continue;
                }

                betterPlayerAudio.OverridePlayerSettings(this, playerToAffect);

                if (playerToAffect.isLocal)
                {
                    // ActivateReverb();
                    Notify(localPlayerAddedListeners, localPlayerAddedEvent);
                }
            }
        }
    public override void OnStationEntered(VRCPlayerApi player)
    {
        if (!SeatInitialized)
        {
            InitializeSeat();
        }                                          //can't do this in start because hudcontrol might not have initialized

        //voice range change to allow talking inside cockpit (after VRC patch 1008)
        if (player != null)
        {
            HUDControl.SeatedPlayers[ThisStationID] = player.playerId;
            if (player.isLocal)
            {
                foreach (int crew in HUDControl.SeatedPlayers)
                {
                    VRCPlayerApi guy = VRCPlayerApi.GetPlayerById(crew);
                    if (guy != null)
                    {
                        SetVoiceInside(guy);
                    }
                }
            }
            else if (EngineControl.Piloting || EngineControl.Passenger)
            {
                SetVoiceInside(player);
            }
        }
    }
Пример #5
0
        public void OnDisable()
        {
            if (!udonDebug.Assert(playerList, "playerList invalid", this))
            {
                return;
            }

            playerList.DiscardInvalid();
            if (playerList.players == null)
            {
                return;
            }

            foreach (var playerId in playerList.players)
            {
                var playerToRemove = VRCPlayerApi.GetPlayerById(playerId);
                if (!Utilities.IsValid(playerToRemove))
                {
                    continue;
                }

                if (!betterPlayerAudio.ClearPlayerOverride(this, playerToRemove))
                {
                    playerList.DiscardInvalid();
                }

                if (playerToRemove.isLocal)
                {
                    // DeactivateReverb();
                    Notify(localPlayerRemovedListeners, localPlayerRemovedEvent);
                }
            }
        }
    public void PlayerExitPlane(VRCPlayerApi player)
    {
        if (!SeatInitialized)
        {
            InitializeSeat();
        }

        HUDControl.SeatedPlayers[ThisStationID] = -1;
        if (player != null)
        {
            SetVoiceOutside(player);
            if (player.isLocal)
            {
                HUDControl.MySeat = -1;
                EngineControl.PassengerExitPlaneLocal();
                //undo voice distances of all players inside the vehicle
                foreach (int crew in HUDControl.SeatedPlayers)
                {
                    VRCPlayerApi guy = VRCPlayerApi.GetPlayerById(crew);
                    if (guy != null)
                    {
                        SetVoiceOutside(guy);
                    }
                }
                if (PassengerOnly != null)
                {
                    PassengerOnly.SetActive(false);
                }
                if (SeatAdjuster != null)
                {
                    SeatAdjuster.SetActive(false);
                }
            }
        }
    }
Пример #7
0
 public void Update()
 {
     if (CurrentActiveStatus)
     {
         if (TrackingUserID != -1)
         {
             var player = VRCPlayerApi.GetPlayerById(TrackingUserID);
             if (player != null)
             {
                 PreviewCameraObject.gameObject.GetComponent <Transform>().position = player.GetPosition();
                 PreviewCameraObject.gameObject.GetComponent <Transform>().rotation = player.GetRotation();
             }
             else if (Networking.IsOwner(this.gameObject))
             {
                 PreviewNext();
             }
         }
     }
     if (UpdateTextTimer != -1)
     {
         if (UpdateTextTimer > 0)
         {
             --UpdateTextTimer;
         }
         else
         {
             var player = VRCPlayerApi.GetPlayerById(TrackingUserID);
             if (player != null)
             {
                 CurrentUserText.text = player.displayName;
             }
         }
     }
 }
Пример #8
0
    public void SetVoteResults(int[] votes, bool isRevealed, int[] scoresVote, int[] playerIds)
    {
        var scoreIndex = 0;

        for (var i = 0; i < animatorsVoteResult.Length; i++)
        {
            var isSubmitted = votes[i] > -1;
            if (isSubmitted)
            {
                var score     = 0;
                var isCorrect = votes[i] < 10;
                if (isCorrect)
                {
                    score = scoresVote[scoreIndex];
                    scoreIndex++;
                }

                var player = VRCPlayerApi.GetPlayerById(playerIds[i]);
                textVoteResult[i].text = player == null ? "ERROR" : player.displayName; // TODO Danger zone!
                animatorsVoteResult[i].SetInteger(Score, score);                        // TODO placeholder score
                animatorsVoteResult[i].SetBool(IsVoteRevealed, isRevealed);
            }

            animatorsVoteResult[i].SetBool(IsVoteSubmitted, isSubmitted);
        }
    }
Пример #9
0
        public void Refresh()
        {
            if (!udonDebug.Assert(Utilities.IsValid(betterPlayerAudio), "betterPlayerAudio invalid", this))
            {
                return;
            }

            if (!udonDebug.Assert(Utilities.IsValid(playerList), "playerList invalid", this))
            {
                return;
            }

            playerList.DiscardInvalid();

            var nonLocalPlayersWithOverrides = betterPlayerAudio.GetNonLocalPlayersWithOverrides();

            foreach (var nonLocalPlayersWithOverride in nonLocalPlayersWithOverrides)
            {
                var vrcPlayerApi = VRCPlayerApi.GetPlayerById(nonLocalPlayersWithOverride);
                if (!playerList.Contains(vrcPlayerApi))
                {
                    betterPlayerAudio.ClearPlayerOverride(this, vrcPlayerApi);
                }
            }

            foreach (var playerListPlayer in playerList.players)
            {
                betterPlayerAudio.OverridePlayerSettings(this, VRCPlayerApi.GetPlayerById(playerListPlayer));
            }
        }
Пример #10
0
 public override void OnStationEntered(VRCPlayerApi player)
 {
     if (!SeatInitialized)
     {
         InitializeSeat();
     }                                          //can't do this in start because hudcontrol might not have initialized
     if (player != null)
     {
         EngineControl.PilotEnterPlaneGlobal(player);
         //voice range change to allow talking inside cockpit (after VRC patch 1008)
         HUDControl.SeatedPlayers[ThisStationID] = player.playerId;
         if (player.isLocal)
         {
             foreach (int crew in HUDControl.SeatedPlayers)
             {//get get a fresh VRCPlayerAPI every time to prevent players who left leaving a broken one behind and causing crashes
                 VRCPlayerApi guy = VRCPlayerApi.GetPlayerById(crew);
                 if (guy != null)
                 {
                     SetVoiceInside(guy);
                 }
             }
         }
         else if (EngineControl.Piloting || EngineControl.Passenger)
         {
             SetVoiceInside(player);
         }
     }
 }
Пример #11
0
        private void UpdateDisplay()
        {
            var player = VRCPlayerApi.GetPlayerById(masterID);

            if (player != null)
            {
                playerDisplay.text = string.Format("{0} : {1}", player.playerId, player.displayName);
            }
        }
Пример #12
0
 public void PreviewNext()
 {
     if (Networking.IsOwner(this.gameObject))
     {
         var          distX      = 0f;
         var          distZ      = 0f;
         VRCPlayerApi player     = null;
         Vector3      playerPos  = new Vector3();
         Vector3      fieldPos   = Sabage.GameField.GetComponent <Transform>().position;
         Vector3      fieldSize  = Sabage.GameField.GetComponent <Transform>().localScale / 2f;
         var          beforeID   = -1;
         var          firstID    = -1;
         var          id         = -1;
         var          trackingID = -1;
         for (int i = 0; i < Sabage.Player_IDs.Length; ++i)
         {
             id = Sabage.Player_IDs[i];
             if (id != -1)
             {
                 player    = VRCPlayerApi.GetPlayerById(id);
                 playerPos = player.GetPosition();
                 distX     = Mathf.Abs(playerPos.x - fieldPos.x);
                 distZ     = Mathf.Abs(playerPos.z - fieldPos.z);
                 if (distX <= fieldSize.x && distZ <= fieldSize.z)
                 {
                     if (firstID == -1)
                     {
                         firstID = player.playerId;
                     }
                     if (beforeID == player.playerId)
                     {
                         trackingID = player.playerId;
                         break;
                     }
                     beforeID = player.playerId;
                 }
             }
         }
         if (trackingID != -1)
         {
             TrackingUserID = trackingID;
         }
         else if (firstID != -1)
         {
             TrackingUserID = firstID;
         }
         else
         {
             TrackingUserID = Networking.LocalPlayer.playerId;
         }
         SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.All, "UpdateText");
     }
     else
     {
         SendCustomNetworkEvent(VRC.Udon.Common.Interfaces.NetworkEventTarget.Owner, "PreviewNext");
     }
 }
    public string GetOwnerName()
    {
        if (ownerPlayerId < 0)
        {
            return(null);
        }
        var player = VRCPlayerApi.GetPlayerById(ownerPlayerId);

        return(Utilities.IsValid(player) ? player.displayName : "!ERROR, TELL FAX!");
    }
Пример #14
0
    private void OnMessageReceived(string message)
    {
        Debug.Log($"<color=green>[THH_ChatMessenger]</color>: Received Message.");

        string PID            = message.Substring(6, 4);
        string messageContent = message.Substring(10);

        VRCPlayerApi sender = VRCPlayerApi.GetPlayerById(int.Parse(PID));

        logger.LogChatMessage(sender, messageContent);
    }
    void HighScoreEvent()
    {
        var player = VRCPlayerApi.GetPlayerById(topPlayer);

        if (player == null)
        {
            return;
        }

        highScoreText  = VRCPlayerApi.GetPlayerById(topPlayer).displayName + " : ";
        highScoreText += topTime.ToString();
    }
Пример #16
0
    private VRCPlayerApi FindGuardian()
    {
        for (int i = Networking.LocalPlayer.playerId - 1; i > 0; i--)
        {
            VRCPlayerApi potentialGuardian = VRCPlayerApi.GetPlayerById(i);
            if (potentialGuardian != null && potentialGuardian != lastLeaver)
            {
                return(potentialGuardian);
            }
        }

        return(null);
    }
Пример #17
0
    // Magical function to get each player their own index in an array (the actual index may change but the player will always have a unique index)
    public int getOwnedOrLowerReleasedIndex()
    {
        int occupiedIndexes = 0;

        for (int index = 0; index < Networking.LocalPlayer.playerId; index++)
        {
            if (VRCPlayerApi.GetPlayerById(index) != null)
            {
                occupiedIndexes++;
            }
        }
        return(occupiedIndexes);
    }
Пример #18
0
    private int CountPlayers(bool checkIsPlaying)
    {
        var count = 0;

        foreach (var p in playerManagers)
        {
            if ((!checkIsPlaying || p.GetIsPlaying()) && Utilities.IsValid(VRCPlayerApi.GetPlayerById(p.GetOwnerPlayerId())))
            {
                count++;
            }
        }

        return(count);
    }
Пример #19
0
        private void OnPlayerLeft(VRCPlayerApi player)
        {
            int          masterID     = CyanEmuPlayerManager.GetMasterID();
            VRCPlayerApi masterPlayer = VRCPlayerApi.GetPlayerById(masterID);

            foreach (CyanEmuSyncedObjectHelper sync in allSyncedObjects_)
            {
                GameObject syncObj = sync.gameObject;
                if (Networking.GetOwner(syncObj)?.playerId == player.playerId)
                {
                    Networking.SetOwner(masterPlayer, syncObj);
                }
            }

            sdkManager_.OnPlayerLeft(player);
        }
Пример #20
0
    VRCPlayerApi FindGuardian(VRCPlayerApi playerWhoLeft)
    {
        // Trying every ID decrementally until a player is found (Janky if a lot of players have joined and left the instance)
        int i = Networking.LocalPlayer.playerId - 1;

        while (i > 0)
        {
            VRCPlayerApi player = VRCPlayerApi.GetPlayerById(i);
            if (player != null)
            {
                return(player);
            }
            i--;
        }
        return(null);
    }
    private void FixedUpdate()
    {
        VRCPlayerApi p = Networking.LocalPlayer;

        PlayerInfoText.text =
            $"DisplayName: {p.displayName}\n" +
            $"PlayerId: {p.playerId}\n" +
            $"Position: {p.GetPosition()}\n" +
            $"CurHitpoint: {p.GetPlayerTag("combat_hp")}\n" +
            $"MaxHitpoint: {p.GetPlayerTag("combat_max_hp")}\n" +
            $"isGrounded: {p.IsPlayerGrounded()}\n" +
            $"isLocal: {p.isLocal}\n" +
            $"isMaster: {p.isMaster}\n" +
            $"PlayerTestTagValue: {p.GetPlayerTag("test")}\n" +
            $"RespawnTimer: {p.GetPlayerTag("combat_respawn_timer")}\n" +
            $"Id1: {(VRCPlayerApi.GetPlayerById(1) == null ? null : VRCPlayerApi.GetPlayerById(1).displayName)}";
    }
Пример #22
0
        /// <summary>
        /// if the mic is still held by the given user let that person no longer be affected by the mic
        /// </summary>
        private void CleanUpOldUser(int oldUser)
        {
            if (oldUser == NoUser)
            {
                return;
            }

            var currentMicUser = VRCPlayerApi.GetPlayerById(oldUser);

            if (Utilities.IsValid(currentMicUser))
            {
                if (Utilities.IsValid(betterPlayerAudioOverride))
                {
                    betterPlayerAudioOverride.RemovePlayer(currentMicUser);
                }
            }
        }
Пример #23
0
    public override void OnDrop()
    {
        _isPickup = false;

        // Get master user and set owner to master
        for (var i = 0; i < 64; ++i)
        {
            var master = VRCPlayerApi.GetPlayerById(i);
            if (master != null)
            {
                Networking.SetOwner(master, this.gameObject);
                break;
            }
        }

        clearGunStatusText();
    }
Пример #24
0
        /// <summary>
        /// let the given user be affected by the mic
        /// </summary>
        private void NewUserStartUsingMic(int newUser)
        {
            if (newUser == NoUser)
            {
                return;
            }

            var newMicUser = VRCPlayerApi.GetPlayerById(newUser);

            if (!Utilities.IsValid(newMicUser))
            {
                return;
            }

            if (Utilities.IsValid(betterPlayerAudioOverride))
            {
                betterPlayerAudioOverride.AddPlayer(newMicUser);
            }
        }
Пример #25
0
        private bool TestGettingPlayerInfo()
        {
            Debug.Log("TestGettingPlayerInfo");

            Debug.Log("GetPlayerById(-1)");
            VRCPlayerApi player = VRCPlayerApi.GetPlayerById(-1);

            if (player != null)
            {
                Debug.LogError("Player -1 is not null?");
                return(false);
            }

            Debug.Log("GetPlayerById(1)");
            player = VRCPlayerApi.GetPlayerById(1);
            if (player == null)
            {
                Debug.LogError("Player 1 is null");
                return(false);
            }

            Debug.Log("GetPlayerId(_localPlayer)");
            int id = VRCPlayerApi.GetPlayerId(_localPlayer);

            if (id != _localPlayer.playerId)
            {
                Debug.LogError("GetPlayerId returned the wrong value for the local player");
                return(false);
            }

            Debug.Log("GetPlayerId(null)");
            id = VRCPlayerApi.GetPlayerId(null);
            if (id != -1)
            {
                Debug.LogError("GetPlayerId returned the wrong value for the local player");
                return(false);
            }

            return(true);
        }
    public void OnRoundChanged(int seed, int round)
    {
        playerUI.MakeAllPromptsNeutral();
        localHasVoted = gameManager.GetMyPlayerManagerId() < 0 ? true : false; // players who don't have an id should not vote

        if (round < 0)
        {
            UpdateInstructions();
            return;
        }
        if (Networking.IsMaster)
        {
            AskOwnerClearLines();
        }

        if (!Utilities.IsValid(VRCPlayerApi.GetPlayerById(ownerPlayerId)))
        {
            ownerPlayerId = -1;
        }
        if (ownerPlayerId < 0)
        {
            isPlaying = false;
            playerUI.SetPromptsVisible(false);
            UpdateInstructions();
            return;
        }

        playerUI.SetPromptsVisible(true);
        isPlaying = true;

        ResetVotes();
        correctIndex = GetCorrectIndex(seed, round);
        if (LocalIsOwner())
        {
            playerUI.SetPromptCorrect(correctIndex);
        }

        UpdateInstructions();
    }
Пример #27
0
    private void DebugState(int secondsSinceLastMatching)
    {
        // skip update if debug text is off
        if (!DebugLogText.gameObject.activeInHierarchy)
        {
            return;
        }

        if ((debugStateCooldown -= Time.deltaTime) > 0)
        {
            return;
        }
        debugStateCooldown = 1f;

        var master = Networking.GetOwner(gameObject);

        int seconds   = MatchingDurationSeconds - secondsSinceLastMatching;
        int minutes   = seconds / 60;
        var countdown = lastSeenState0 == "" ?
                        $"Waiting for instance master ({(master == null ? "unknown" : master.displayName)}) to start" :
                        $"Next matching in {minutes:00}:{seconds:00}";

        DebugStateText.text = $"{System.DateTime.Now} localPid={Networking.LocalPlayer.playerId} master?={Networking.IsMaster}\n" +
                              $"countdown: {countdown}\n" +
                              $"timeSinceLastSeenMatching={secondsSinceLastMatching}\n" +
                              $"lastSeenServerTimeMillis={lastSeenMatchingServerTimeMillis} millisSinceNow={Networking.GetServerTimeInMilliseconds() - lastSeenMatchingServerTimeMillis}\n" +
                              $"lastSeenMatchCount={lastSeenMatchCount} lastSeenMatching={join(lastSeenMatching)}\n";

        if (!MatchingTracker.started)
        {
            return;
        }

        VRCPlayerApi[] players = new VRCPlayerApi[80];
        var            global  = MatchingTracker.ReadGlobalMatchingState(players);

        int[] playerIdsbyGlobalOrdinal = new int[players.Length];
        int   eligibleCount            = 0;

        for (int i = 0; i < players.Length; i++)
        {
            if (players[i] != null)
            {
                playerIdsbyGlobalOrdinal[i] = players[i].playerId;
                eligibleCount++;
            }
        }

        if (eligibleCount < 2)
        {
            FullStateDisplay.text = "not enough initialized/matchable players for a matching yet.";
        }

        var matchingObject = CalculateMatching(playerIdsbyGlobalOrdinal, global, 80);

        int[] playerIdsByMatchingOrdinal = (int[])matchingObject[0];
        int[] matching   = (int[])matchingObject[1];
        int   matchCount = (int)matchingObject[2];

        bool[] originalUgraph = (bool[])matchingObject[3];
        var    s = $"current potential matching:\n";

        s += $"playerIdsByMatchingOrdinal={join(playerIdsByMatchingOrdinal)}\n";
        s += $"matchCount={matchCount}\n";
        s += $"matching={join(matching)}\n";
        s += $"originalUgraph:\n\n";
        string[] names = new string[80];

        for (int i = 0; i < eligibleCount; i++)
        {
            var id     = playerIdsByMatchingOrdinal[i];
            var player = VRCPlayerApi.GetPlayerById(id);
            // should always be non null
            if (player != null)
            {
                names[i] = player.displayName.PadRight(15).Substring(0, 15);
                s       += $"{player.displayName.PadLeft(15).Substring(0, 15)} ";
            }
            else
            {
                names[i] = "                "; // 16 spaces
                s       += "                "; // 16 spaces
            }

            for (int j = 0; j < i; j++)
            {
                s += " ";
            }

            for (int j = i + 1; j < eligibleCount; j++)
            {
                s += originalUgraph[i * eligibleCount + j] ? "O" : ".";
            }
            s += "\n";
        }
        for (int i = 0; i < 15; i++)
        {
            s += "\n                "; // 16 spaces
            for (int j = 0; j < eligibleCount; j++)
            {
                s += names[j][i];
            }
        }

        FullStateDisplay.text = s;
    }
Пример #28
0
 public static VRCPlayerApi GetVRCPlayerApiByID(int ID) =>
 VRCPlayerApi.GetPlayerById(ID);
Пример #29
0
        /// <summary>
        /// Recieve a new set of data from the manager that can be displayed to viewers.
        /// </summary>
        public void UpdateMainMenuView(
            bool newIsTeams,
            bool isTeam2Playing,
            int gameMode,
            bool isKorean4Ball,
            int timerMode,
            int player1ID,
            int player2ID,
            int player3ID,
            int player4ID
            )
        {
            Debug.Log($"Got a new menu update: teams {newIsTeams} team 2's turn {isTeam2Playing} game mode {gameMode} timer mode {timerMode} player 1 {player1ID} player 2 {player2ID} player 3 {player3ID} player 4 {player4ID}");

            if (newIsTeams)
            {
                teamsTxt.text = "Teams: YES";
                isTeams       = true;
            }
            else
            {
                teamsTxt.text = "Teams: NO";
                isTeams       = false;
            }

            currentGameMode = gameMode;

            switch (gameMode)
            {
            case 0:
                gameModeTxt.text = "American 8-Ball";

                break;

            case 1:
                gameModeTxt.text = "American 9-Ball";

                break;

            case 2:
                if (isKorean4Ball)
                {
                    gameModeTxt.text = "Korean 4-Ball";
                }
                else
                {
                    gameModeTxt.text = "Japanese 4-Ball";
                }

                break;
            }

            switch (timerMode)
            {
            case 0:
                timer.text = "No Limit";
                break;

            case 1:
                timer.text = "10s Limit";
                break;

            case 2:
                timer.text = "15s Limit";
                break;

            case 3:
                timer.text = "30s Limit";
                break;

            case 4:
                timer.text = "60s Limit";
                break;
            }

            leaveButton.SetActive(false);
            player1Button.SetActive(false);
            player2Button.SetActive(false);
            player3Button.SetActive(false);
            player4Button.SetActive(false);

            bool found = false;

            if (player1ID > 0)
            {
                found = HandlePlayerState(player1MenuText, player1ScoreText, VRCPlayerApi.GetPlayerById(player1ID));
            }
            else
            {
                player1MenuText.text  = "";
                player1ScoreText.text = "";
            }

            if (player2ID > 0)
            {
                found = HandlePlayerState(player2MenuText, player2ScoreText, VRCPlayerApi.GetPlayerById(player2ID));
            }
            else
            {
                player2MenuText.text  = "";
                player2ScoreText.text = "";
            }

            if (player3ID > 0)
            {
                found = HandlePlayerState(player3MenuText, player3ScoreText, VRCPlayerApi.GetPlayerById(player3ID));
            }
            else
            {
                player3MenuText.text  = "";
                player3ScoreText.text = "";
            }

            if (player4ID > 0)
            {
                found = HandlePlayerState(player4MenuText, player4ScoreText, VRCPlayerApi.GetPlayerById(player4ID));
            }
            else
            {
                player4MenuText.text  = "";
                player4ScoreText.text = "";
            }

            if (!found)
            {
                player1Button.SetActive(true);
                player2Button.SetActive(true);

                if (newIsTeams)
                {
                    player3Button.SetActive(true);
                    player4Button.SetActive(true);
                }
            }
        }
Пример #30
0
 public void OnOwnershipTransferred(int ownerID)
 {
     udonBehaviour_.RunEvent("_onOwnershipTransferred", ("Player", VRCPlayerApi.GetPlayerById(ownerID)));
 }