top of page

未発表パーティゲーム BasicSpawner.cs

  • msandfrey3
  • Aug 12, 2024
  • 3 min read
using System.Collections.Generic;
using PartyGame.Character.Player;
using PartyGame.Multiplayer.Inputs;
using UnityEngine;
using UnityEngine.InputSystem;
using Fusion;
namespace PartyGame.Multiplayer
{
    public class PlayerSpawner : NetworkBehaviour, IPlayerJoined, IPlayerLeft
    {
        [SerializeField] private Transform[] _spawnPoints;
        [SerializeField] private NetworkPrefabRef _playerPrefab;
        [SerializeField] private NetworkPrefabRef _playerPrefab2;
        [SerializeField] private NetworkPrefabRef _playerPrefab3;
        [SerializeField] private NetworkPrefabRef _playerPrefab4;
        [SerializeField] private NetworkInputManager _inputManager;
        [SerializeField] private Character.Player.Players _netPlayers;
        [Networked(OnChanged = nameof(OnSpawnedCharsChanged))]
        [Capacity(4)]//set to 4 because of max 4 players
        private NetworkDictionary<NetworkObject, PlayerRef> _spawnedChars => default;
        [Networked(OnChanged = nameof(OnSpawnedCharsChanged))]
        [Capacity(4)]//set to 4 because of max 4 players
        private NetworkLinkedList<NetworkObject> _spawnedList => default;
        private PlayerRef _localRef;
        private NetworkPrefabRef _prefabToSpawn;
        private List<Gamepad> _connectedPads = new List<Gamepad>();
        public override void Render()
        {
            // Cheat code to force more players to get added to the scene
            if (Input.GetKeyDown(KeyCode.A))
            {
                if (Runner.IsSinglePlayer)
                {
                    RPCLocalPlayerJoined(_localRef);
                    SetupPlayerObject(_localRef);
                }
            }
        }
        public override void Spawned()
        {
            _localRef = Runner.LocalPlayer;
            if (GetPlayerCount() > Runner.SessionInfo.MaxPlayers)
            {
                Debug.Log("Too many players. No spawn.");
                return;
            }
            //setup for main network player 
            if (Object.HasStateAuthority)
            {
                foreach (PlayerRef pRef in Runner.ActivePlayers)
                {
                    NetworkPlayerJoined(pRef);
                    SetupPlayerObject(pRef);
                }
            }
            else
            {
                SetupPlayerObject(_localRef);
            }
            if (Runner.IsSinglePlayer)
            {
                //local setup
                //if move this above network player setup limits players, and extras that join just watch
                int x = _inputManager.GetUnassignedGamepadCount();
                for (int i = 0; i < x; i++)
                {
                    RPCLocalPlayerJoined(_localRef);
                    SetupPlayerObject(_localRef);
                }
            }
            //listen to when devices are added to add more players
            InputSystem.onDeviceChange += OnDeviceChange;
        }
        private void OnDeviceChange(InputDevice device, InputDeviceChange change)
        {
            if (change == InputDeviceChange.Added)
            {
                if (device is Gamepad)
                {
                    Gamepad pad = (Gamepad)device;
                    if (_inputManager.ConnectedPads.Contains(pad))
                    {
                        return;
                    }
                    //unplugging and then replugging causes both added and reconnected to trigger
                    //this makes another player ready to party but it has no controller to pilot it
                    _inputManager.AddGamepad(pad);
                    bool success = _inputManager.TryAssignController(pad);
                    //dont spawn online right now
                    if (!success && Runner.IsSinglePlayer)
                    {
                        RPCLocalPlayerJoined(_localRef);
                        SetupPlayerObject(_localRef);
                    }
                }
            }
        }
        //the host calls this when a player is spawned
        public void PlayerJoined(PlayerRef player)
        {
            if (!HasStateAuthority) return;
            if (Runner.GetPlayerObject(player) != null) return;
            NetworkPlayerJoined(player);
        }
        public void NetworkPlayerJoined(PlayerRef player)//for network players and host/main client
        {
            SetPrefabToSpawn();
            NetworkObject networkPlayer = SpawnNewPlayer(player);
            if (networkPlayer == null)
            {
                Debug.LogError("The network player could not be spawned.");
                return;
            }
            // Set Player Object to facilitate access across systems.
            Runner.SetPlayerObject(player, networkPlayer);
            TrackPlayer(networkPlayer, player);
        }
        /// <summary>
        /// This will only be called when disconnected from the server. 
        /// If a controller disconnects the player will still be shown.
        /// If we want to allow added local players to drop out we will need
        /// specific code for that.
        /// </summary>
        /// <param name="player"></param>
        public void PlayerLeft(PlayerRef player)
        {
            if (!HasStateAuthority)
            {
                return;
            }
            if (!_spawnedChars.ContainsValue(player))
            {
                return;
            }
            //use ref to find all the objects to remove
            List<NetworkObject> objectsToRemove = new List<NetworkObject>();
            foreach (KeyValuePair<NetworkObject, PlayerRef> netObj in _spawnedChars)
            {
                if (netObj.Value == player)
                {
                    objectsToRemove.Add(netObj.Key);
                }
            }
            foreach (NetworkObject netObj in objectsToRemove)
            {
                _spawnedChars.Remove(netObj);
                PlayerController playerController = netObj.GetComponent<PlayerController>();
                _netPlayers.RemovePlayer(playerController);
                PlayerInputHandler playerInputHandler = netObj.GetComponent<PlayerInputHandler>();
                _inputManager.RemovePlayer(playerInputHandler);
                Runner.Despawn(netObj);
            }
        }
        /// <summary>
        /// This is used to spawn in additional local players.
        /// It will only spawn a new player if the player count 
        /// is under the max amount of players allowed.
        /// </summary>
        /// <returns></returns>
        [Rpc(sources: RpcSources.All, targets: RpcTargets.StateAuthority)]
        public void RPCLocalPlayerJoined(PlayerRef player)
        {
            SetPrefabToSpawn();
            NetworkObject localPlayer = SpawnNewPlayer(player);
            if (localPlayer == null)
            {
                Debug.Log("I spawn a nobody, you waste-a your time.");
                return;
            }
            TrackPlayer(localPlayer, _localRef);
        }
        private void SetupPlayerObject(PlayerRef player)
        {
            foreach (KeyValuePair<NetworkObject, PlayerRef> netObjPlayerPair in _spawnedChars)
            {
                if (netObjPlayerPair.Value == player)
                {
                    NetworkObject networkPlayerObject = netObjPlayerPair.Key;
                    if (networkPlayerObject == null) continue;
                    if (_localRef == networkPlayerObject.InputAuthority)
                    {
                        Setup(networkPlayerObject);
                        PlayerInputHandler playerInputHandler = networkPlayerObject.GetComponent<PlayerInputHandler>();
                        _inputManager.RegisterNewLocalPlayer(playerInputHandler);
                    }
                }
            }
        }
        private void Setup(NetworkObject networkPlayerObject)
        {
            int localID = GetPlayerCount();
            PlayerController playerController = networkPlayerObject.GetComponent<PlayerController>();
            if (playerController.IsActiveInGame)
            {
                return;
            }
            playerController.LocalID = localID;
            playerController.RPCEnableControls();
            //this could probably be simplified, unless we will only spawn a single prefab type TODO
            int playerNumber = localID;
            networkPlayerObject.name += playerNumber.ToString();
            string actionPrefix = "Player" + playerNumber.ToString() + ".";
            string actionMap = (actionPrefix + "GameActionMap");
            PlayerInputHandler playerInputHandler = networkPlayerObject.GetComponent<PlayerInputHandler>();
            playerInputHandler.PlayerInputListener.SetGameActionMap(actionPrefix, actionMap);
        }
        private NetworkObject SpawnNewPlayer(PlayerRef player)
        {
            Vector3 spawnPosition = _spawnPoints[GetSpawnIndex()].position;
            return Runner.Spawn(_prefabToSpawn,
                spawnPosition,
                Quaternion.identity,
                player);
        }
        private void TrackPlayer(NetworkObject networkObject, PlayerRef player)
        {
            if (!_spawnedChars.ContainsKey(networkObject))
            {
                _spawnedChars.Add(networkObject, player);
                int index = GetSpawnIndex();
                if (index >= _spawnedList.Count)
                {
                    _spawnedList.Add(networkObject);
                }
                else
                {
                    _spawnedList.Set(GetSpawnIndex(), networkObject);
                }
            }
            //track with players
            PlayerController playerController = networkObject.GetComponent<PlayerController>();
            _netPlayers.AddNewPlayer(playerController);
        }
        private int GetSpawnIndex()
        {
            int i = 0;
            foreach (NetworkObject no in _spawnedList)
            {
                if (no == null) return i;
                i++;
            }
            return i;
        }
        protected static void OnSpawnedCharsChanged(Changed<BasicSpawner> changed)
        {
            changed.Behaviour.SetPrefabToSpawn();
        }
        private void SetPrefabToSpawn()
        {
            //create a list/array of these prefabs
            int index = GetSpawnIndex();
            switch (index)
            {
                case 0:
                    _prefabToSpawn = _playerPrefab;
                    break;
                case 1:
                    _prefabToSpawn = _playerPrefab2;
                    break;
                case 2:
                    _prefabToSpawn = _playerPrefab3;
                    break;
                case 3:
                    _prefabToSpawn = _playerPrefab4;
                    break;
                default:
                    break;
            }
        }
        private int GetPlayerCount()
        {
            return _spawnedChars.Count;
        }
        private int GetLocalPlayerCount()
        {
            int count = 0;
            foreach (KeyValuePair<NetworkObject, PlayerRef> character in _spawnedChars)
            {
                if(character.Value == _localRef)
                {
                    count++;
                }
            }
            return count;
        }
    }
}

Recent Posts

See All

Comments


© 2024 by Matthew Sandfrey. Proudly created with Wix.com

bottom of page