On Remote Player UltimateCharacterLocomotion is Disable


New member

I made this script, it is a modification of SpawnManagerBase.cs and it is working, but in the client the UltimateCharacterLocomotion character is disabled, if I manually enable it in the unity editor it works very well but I don't know why this problem happens

using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using Photon.Pun;
using Photon.Realtime;
using ExitGames.Client.Photon;
using Opsive.Shared.Events;
using Opsive.Shared.Game;
using Opsive.UltimateCharacterController;
using Opsive.UltimateCharacterController.Character;
using Opsive.UltimateCharacterController.Game;

public class SpawnMultiPlayer : MonoBehaviourPunCallbacks, IOnEventCallback
    [SerializeField] private GameObject PrefabCharacterController;

    private SendOptions m_ReliableSendOption;
    private RaiseEventOptions m_RaiseEventOptions;

    private const byte CREATE_IN_MASTER = 0;
    private const byte CREATE_IN_GUEST = 10;

    private PhotonView[] m_Players;
    private int m_PlayerCount;
    private Dictionary<int, int> m_ActorNumberByPhotonViewIndex;

    private void Start(){
            m_ReliableSendOption = new SendOptions { Reliability = true };
            m_RaiseEventOptions = new RaiseEventOptions();
            m_RaiseEventOptions.CachingOption = EventCaching.DoNotCache;
            m_RaiseEventOptions.Receivers = ReceiverGroup.Others;

            foreach (Player player in PhotonNetwork.PlayerList){
                SpawnPlayer(newPlayer: player);

    public void SpawnPlayer(Player newPlayer){
        // Instantiate the player and let the PhotonNetwork know of the new character.
        var player = GameObject.Instantiate(PrefabCharacterController, transform.position, transform.rotation);
        var photonView = player.GetComponent<PhotonView>();
        photonView.ViewID = PhotonNetwork.AllocateViewID(newPlayer.ActorNumber);
        if (photonView.ViewID > 0) {

            // The character has been created. All other clients need to instantiate the character as well.
            var data = new object[]{
                player.transform.position, player.transform.rotation, photonView.ViewID, newPlayer.ActorNumber

            m_RaiseEventOptions.TargetActors = null;
            PhotonNetwork.RaiseEvent(CREATE_IN_MASTER, data, m_RaiseEventOptions, m_ReliableSendOption);
        } else {
            Debug.LogError("Failed to allocate a ViewId.");

    /// <summary>
    /// A event from Photon has been sent.
    /// </summary>
    /// <param name="photonEvent">The Photon event.</param>
    public void OnEvent(EventData photonEvent){
        if (photonEvent.Code == CREATE_IN_MASTER) {
            // The Master Client has instantiated a character. Create that character on the local client as well.
            var data = (object[])photonEvent.CustomData;
            for (int i = 0; i < data.Length / 4; ++i) {
                var viewID = (int)data[i * 4 + 2];
                if (PhotonNetwork.GetPhotonView(viewID) != null) {

                var player = PhotonNetwork.CurrentRoom.GetPlayer((int)data[i * 4 + 3]);
                var character = Instantiate(PrefabCharacterController, (Vector3)data[i * 4], (Quaternion)data[i * 4 + 1]);
                var photonView = character.GetCachedComponent<PhotonView>();
                photonView.ViewID = viewID;
                // As of PUN 2.19, when the ViewID is set the Owner is not set. Set the owner to null and then to the player so the owner will correctly be assigned.

                // If the instantiated character is a local player then the Master Client is waiting for it to be created on the client. Notify the Master Client
                // that the character has been created so it can be activated.
                if (photonView.IsMine) {
                    m_RaiseEventOptions.TargetActors = new int[] { PhotonNetwork.MasterClient.ActorNumber };
                    PhotonNetwork.RaiseEvent(CREATE_IN_GUEST, photonView.Owner.ActorNumber, m_RaiseEventOptions, m_ReliableSendOption);
                } else {
                    // Call start manually before any events are received. This ensures the remote character has been initialized.
                    var characterLocomotion = character.GetCachedComponent<Opsive.UltimateCharacterController.Character.UltimateCharacterLocomotion>();

        } else if (photonEvent.Code == CREATE_IN_GUEST) {
            // The remote player has instantiated the character. It can now be enabled (on the Master Client).
            var ownerActor = (int)photonEvent.CustomData;
            for (int i = 0; i < m_PlayerCount; ++i) {
                if (m_Players[i].Owner.ActorNumber == ownerActor) {

    private void AddPhotonView(PhotonView photonView) {
        if (m_PlayerCount == m_Players.Length) {
            System.Array.Resize(ref m_Players, m_PlayerCount + 1);
        m_Players[m_PlayerCount] = photonView;
        m_ActorNumberByPhotonViewIndex.Add(photonView.OwnerActorNr, m_PlayerCount);


Staff member
For something like this I would need to debug it line by line to determine exactly what it is doing but it looks like that class is reimplementing a lot of what the spawn manager base does. You should instead subclass the SpawnManagerBase and override the GetCharacterPrefab method.