Advertisement
Guest User

sedf

a guest
Oct 18th, 2021
72
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 13.85 KB | None | 0 0
  1. public enum SpawnMode
  2.  
  3. {
  4.  
  5. FixedLocation, // Always spawns the character in a fixed location.
  6.  
  7. SpawnPoint // Uses the Spawn Point system.
  8.  
  9. }
  10.  
  11.  
  12.  
  13. [Tooltip("Specifies the location that the character should spawn.")] [SerializeField]
  14.  
  15. protected SpawnMode m_Mode;
  16.  
  17.  
  18.  
  19. [Tooltip("The position the character should spawn if the SpawnMode is set to FixedLocation.")] [SerializeField]
  20.  
  21. protected Transform m_SpawnLocation;
  22.  
  23.  
  24.  
  25. [Tooltip("The offset to apply to the spawn position multiplied by the number of characters within the room.")]
  26.  
  27. [SerializeField]
  28.  
  29. protected Vector3 m_SpawnLocationOffset = new Vector3(2, 0, 0);
  30.  
  31.  
  32.  
  33. [Tooltip(
  34.  
  35. "The grouping index to use when spawning to a spawn point. A value of -1 will ignore the grouping value.")]
  36.  
  37. [SerializeField]
  38.  
  39. protected int m_SpawnPointGrouping = -1;
  40.  
  41.  
  42.  
  43. [Tooltip("The amount of time it takes until an inactive player is removed from the room.")] [SerializeField]
  44.  
  45. protected float m_InactiveTimeout = 60;
  46.  
  47.  
  48.  
  49. public SpawnMode Mode
  50.  
  51. {
  52.  
  53. get { return m_Mode; }
  54.  
  55. set { m_Mode = value; }
  56.  
  57. }
  58.  
  59.  
  60.  
  61. public Transform SpawnLocation
  62.  
  63. {
  64.  
  65. get { return m_SpawnLocation; }
  66.  
  67. set { m_SpawnLocation = value; }
  68.  
  69. }
  70.  
  71.  
  72.  
  73. public Vector3 SpawnLocationOffset
  74.  
  75. {
  76.  
  77. get { return m_SpawnLocationOffset; }
  78.  
  79. set { m_SpawnLocationOffset = value; }
  80.  
  81. }
  82.  
  83.  
  84.  
  85. public int SpawnPointGrouping
  86.  
  87. {
  88.  
  89. get { return m_SpawnPointGrouping; }
  90.  
  91. set { m_SpawnPointGrouping = value; }
  92.  
  93. }
  94.  
  95.  
  96.  
  97. private PhotonView[] m_Players;
  98.  
  99. private PhotonView myView;
  100.  
  101.  
  102.  
  103. private int m_PlayerCount;
  104.  
  105.  
  106.  
  107. private SendOptions m_ReliableSendOption;
  108.  
  109. private RaiseEventOptions m_RaiseEventOptions;
  110.  
  111. private Dictionary<int, int> m_ActorNumberByPhotonViewIndex;
  112.  
  113. private Dictionary<Player, InactivePlayer> m_InactivePlayers;
  114.  
  115.  
  116.  
  117. /// <summary>
  118.  
  119. /// Stores the data about the player that became inactive.
  120.  
  121. /// </summary>
  122.  
  123. private struct InactivePlayer
  124.  
  125. {
  126.  
  127. public int PlayerIndex;
  128.  
  129. public Vector3 Position;
  130.  
  131. public Quaternion Rotation;
  132.  
  133. public ScheduledEventBase RemoveEvent;
  134.  
  135.  
  136.  
  137. /// <summary>
  138.  
  139. /// Constructor for the InactivePlayer struct.
  140.  
  141. /// </summary>
  142.  
  143. /// <param name="index">The index within the Player array.</param>
  144.  
  145. /// <param name="position">The last position of the player.</param>
  146.  
  147. /// <param name="rotation">The last rotation of the player.</param>
  148.  
  149. /// <param name="removeEvent">The event that will remove the player from the room.</param>
  150.  
  151. public InactivePlayer(int index, Vector3 position, Quaternion rotation, ScheduledEventBase removeEvent)
  152.  
  153. {
  154.  
  155. PlayerIndex = index;
  156.  
  157. Position = position;
  158.  
  159. Rotation = rotation;
  160.  
  161. RemoveEvent = removeEvent;
  162.  
  163. }
  164.  
  165. }
  166.  
  167.  
  168.  
  169. /// <summary>
  170.  
  171. /// Initialize the default values.
  172.  
  173. /// </summary>
  174.  
  175. private void Start()
  176.  
  177. {
  178.  
  179. var kinematicObjectManager = GameObject.FindObjectOfType<KinematicObjectManager>();
  180.  
  181. m_Players = new PhotonView[kinematicObjectManager.StartCharacterCount];
  182.  
  183. m_ActorNumberByPhotonViewIndex = new Dictionary<int, int>();
  184.  
  185.  
  186.  
  187. // Cache the raise event options.
  188.  
  189. m_ReliableSendOption = new SendOptions {Reliability = true};
  190.  
  191. m_RaiseEventOptions = new RaiseEventOptions();
  192.  
  193. m_RaiseEventOptions.CachingOption = EventCaching.DoNotCache;
  194.  
  195. m_RaiseEventOptions.Receivers = ReceiverGroup.Others;
  196.  
  197.  
  198.  
  199. SpawnPlayer(PhotonNetwork.LocalPlayer);
  200.  
  201. }
  202.  
  203.  
  204.  
  205. /// <summary>
  206.  
  207. /// Spawns the character within the room. A manual spawn method is used to have complete control over the spawn location.
  208.  
  209. /// </summary>
  210.  
  211. /// <param name="newPlayer">The player that entered the room.</param>
  212.  
  213. public void SpawnPlayer(Player newPlayer)
  214.  
  215. {
  216.  
  217. var determineSpawnLocation = true;
  218.  
  219. var spawnPosition = Vector3.zero;
  220.  
  221. var spawnRotation = Quaternion.identity;
  222.  
  223.  
  224.  
  225. InactivePlayer inactivePlayer;
  226.  
  227. if (m_InactivePlayers != null && m_InactivePlayers.TryGetValue(newPlayer, out inactivePlayer))
  228.  
  229. {
  230.  
  231. // The player has rejoined the game. The character does not need to go through the full spawn procedure.
  232.  
  233. Scheduler.Cancel(inactivePlayer.RemoveEvent);
  234.  
  235. m_InactivePlayers.Remove(newPlayer);
  236.  
  237.  
  238.  
  239. // The spawn location is determined by the last disconnected location.
  240.  
  241. spawnPosition = inactivePlayer.Position;
  242.  
  243. spawnRotation = inactivePlayer.Rotation;
  244.  
  245. determineSpawnLocation = false;
  246.  
  247. }
  248.  
  249.  
  250.  
  251. // Spawn the new player based on the spawn mode.
  252.  
  253. if (determineSpawnLocation)
  254.  
  255. {
  256.  
  257. if (m_Mode == SpawnMode.SpawnPoint)
  258.  
  259. {
  260.  
  261. if (!SpawnPointManager.GetPlacement(null, m_SpawnPointGrouping, ref spawnPosition,
  262.  
  263. ref spawnRotation))
  264.  
  265. {
  266.  
  267. Debug.LogWarning(
  268.  
  269. $"Warning: The Spawn Point Manager is unable to determine a spawn location for grouping {m_SpawnPointGrouping}. " +
  270.  
  271. "Consider adding more spawn points.");
  272.  
  273. }
  274.  
  275. }
  276.  
  277. else
  278.  
  279. {
  280.  
  281. if (m_SpawnLocation != null)
  282.  
  283. {
  284.  
  285. spawnPosition = m_SpawnLocation.position;
  286.  
  287. spawnRotation = m_SpawnLocation.rotation;
  288.  
  289. }
  290.  
  291.  
  292.  
  293. spawnPosition += m_PlayerCount * m_SpawnLocationOffset;
  294.  
  295. }
  296.  
  297. }
  298.  
  299.  
  300.  
  301. // Instantiate the player and let the PhotonNetwork know of the new character.
  302.  
  303. var player = GameObject.Instantiate(GetCharacterPrefab(newPlayer), spawnPosition, spawnRotation);
  304.  
  305. var photonView = player.GetComponent<PhotonView>();
  306.  
  307. photonView.ViewID = PhotonNetwork.AllocateViewID(newPlayer.ActorNumber);
  308.  
  309. if (photonView.ViewID > 0)
  310.  
  311. {
  312.  
  313. // As of PUN 2.19, when the ViewID is allocated the Owner is not set. Set the owner to null and then to the player so the owner will correctly be assigned.
  314.  
  315. photonView.TransferOwnership(null);
  316.  
  317. photonView.TransferOwnership(newPlayer);
  318.  
  319.  
  320.  
  321. // The character has been created. All other clients need to instantiate the character as well.
  322.  
  323. var data = new object[]
  324.  
  325. {
  326.  
  327. player.transform.position, player.transform.rotation, photonView.ViewID, newPlayer.ActorNumber
  328.  
  329. };
  330.  
  331. m_RaiseEventOptions.TargetActors = null;
  332.  
  333. PhotonNetwork.RaiseEvent(PhotonEventIDs.PlayerInstantiation, data, m_RaiseEventOptions,
  334.  
  335. m_ReliableSendOption);
  336.  
  337. myView = photonView;
  338.  
  339. AddPhotonView(photonView);
  340.  
  341. EventHandler.ExecuteEvent("OnPlayerEnteredRoom", photonView.Owner, photonView.gameObject);
  342.  
  343. }
  344.  
  345. else
  346.  
  347. {
  348.  
  349. Debug.LogError("Failed to allocate a ViewId.");
  350.  
  351. Destroy(player);
  352.  
  353. }
  354.  
  355. }
  356.  
  357.  
  358.  
  359.  
  360.  
  361. private void SpawnMyPlayer(Player newPlayer)
  362.  
  363. {
  364.  
  365.  
  366.  
  367. if (newPlayer != PhotonNetwork.LocalPlayer)
  368.  
  369. {
  370.  
  371. var data = new object[]
  372.  
  373. {
  374.  
  375. myView.transform.position, myView.transform.rotation, myView.ViewID, newPlayer.ActorNumber
  376.  
  377. };
  378.  
  379.  
  380.  
  381. m_RaiseEventOptions.TargetActors = new int[] {newPlayer.ActorNumber};
  382.  
  383. PhotonNetwork.RaiseEvent(PhotonEventIDs.PlayerInstantiation, data, m_RaiseEventOptions,
  384.  
  385. m_ReliableSendOption);
  386.  
  387. }
  388.  
  389. }
  390.  
  391.  
  392.  
  393.  
  394.  
  395. /// <summary>
  396.  
  397. /// Abstract method that allows for a character to be spawned based on the game logic.
  398.  
  399. /// </summary>
  400.  
  401. /// <param name="newPlayer">The player that entered the room.</param>
  402.  
  403. /// <returns>The character prefab that should spawn.</returns>
  404.  
  405. protected abstract GameObject GetCharacterPrefab(Player newPlayer);
  406.  
  407.  
  408.  
  409. /// <summary>
  410.  
  411. /// Adds the PhotonView to the player list.
  412.  
  413. /// </summary>
  414.  
  415. /// <param name="photonView">The PhotonView that should be added.</param>
  416.  
  417. private void AddPhotonView(PhotonView photonView)
  418.  
  419. {
  420.  
  421. if (m_PlayerCount == m_Players.Length)
  422.  
  423. {
  424.  
  425. System.Array.Resize(ref m_Players, m_PlayerCount + 1);
  426.  
  427. }
  428.  
  429.  
  430.  
  431. m_Players[m_PlayerCount] = photonView;
  432.  
  433. m_ActorNumberByPhotonViewIndex.Add(photonView.OwnerActorNr, m_PlayerCount);
  434.  
  435. m_PlayerCount++;
  436.  
  437. }
  438.  
  439.  
  440.  
  441.  
  442.  
  443.  
  444.  
  445. /// <summary>
  446.  
  447. /// Called when a remote player entered the room. This Player is already added to the playerlist.
  448.  
  449. /// </summary>
  450.  
  451. /// <param name="newPlayer">The player that entered the room.</param>
  452.  
  453. public override void OnPlayerEnteredRoom(Player newPlayer)
  454.  
  455. {
  456.  
  457. base.OnPlayerEnteredRoom(newPlayer);
  458.  
  459.  
  460.  
  461. // SpawnPlayer(newPlayer);
  462.  
  463. SpawnMyPlayer(newPlayer);
  464.  
  465. }
  466.  
  467.  
  468.  
  469. /// <summary>
  470.  
  471. /// Called when a local player leaves the room.
  472.  
  473. /// </summary>
  474.  
  475. public override void OnLeftRoom()
  476.  
  477. {
  478.  
  479. base.OnLeftRoom();
  480.  
  481.  
  482.  
  483. // The local player has left the room. Cleanup like the player has permanently disconnected. If they rejoin at a later time the normal initialization process will run.
  484.  
  485. for (int i = 0; i < m_PlayerCount; ++i)
  486.  
  487. {
  488.  
  489. if (m_Players[i] == null)
  490.  
  491. {
  492.  
  493. continue;
  494.  
  495. }
  496.  
  497.  
  498.  
  499. EventHandler.ExecuteEvent("OnPlayerLeftRoom", m_Players[i].Owner, m_Players[i].gameObject);
  500.  
  501. GameObject.Destroy(m_Players[i].gameObject);
  502.  
  503. }
  504.  
  505.  
  506.  
  507. m_PlayerCount = 0;
  508.  
  509. }
  510.  
  511.  
  512.  
  513. /// <summary>
  514.  
  515. /// Called when a remote player left the room or became inactive. Check otherPlayer.IsInactive.
  516.  
  517. /// </summary>
  518.  
  519. /// <param name="otherPlayer">The player that left the room.</param>
  520.  
  521. public override void OnPlayerLeftRoom(Player otherPlayer)
  522.  
  523. {
  524.  
  525. base.OnPlayerLeftRoom(otherPlayer);
  526.  
  527.  
  528.  
  529. // Notify others that the player has left the room.
  530.  
  531. if (m_ActorNumberByPhotonViewIndex.TryGetValue(otherPlayer.ActorNumber, out int index))
  532.  
  533. {
  534.  
  535. var photonView = m_Players[index];
  536.  
  537. // Inactive players may rejoin. Remember the last location of the inactive player.
  538.  
  539. if (otherPlayer != null && otherPlayer.IsInactive)
  540.  
  541. {
  542.  
  543. if (m_InactivePlayers == null)
  544.  
  545. {
  546.  
  547. m_InactivePlayers = new Dictionary<Player, InactivePlayer>();
  548.  
  549. }
  550.  
  551.  
  552.  
  553. var removeEvent = Scheduler.Schedule<Player>(m_InactiveTimeout,
  554.  
  555. (Player player) => { m_InactivePlayers.Remove(player); }, otherPlayer);
  556.  
  557. m_InactivePlayers.Add(otherPlayer,
  558.  
  559. new InactivePlayer(index, photonView.transform.position, photonView.transform.rotation,
  560.  
  561. removeEvent));
  562.  
  563. }
  564.  
  565.  
  566.  
  567. EventHandler.ExecuteEvent("OnPlayerLeftRoom", otherPlayer, photonView.gameObject);
  568.  
  569. GameObject.Destroy(photonView.gameObject);
  570.  
  571. m_ActorNumberByPhotonViewIndex.Remove(otherPlayer.ActorNumber);
  572.  
  573. for (int j = index; j < m_PlayerCount - 1; ++j)
  574.  
  575. {
  576.  
  577. m_Players[j] = m_Players[j + 1];
  578.  
  579. m_ActorNumberByPhotonViewIndex[m_Players[j + 1].Owner.ActorNumber] = j;
  580.  
  581. }
  582.  
  583.  
  584.  
  585. m_PlayerCount--;
  586.  
  587. }
  588.  
  589. }
  590.  
  591.  
  592.  
  593. /// <summary>
  594.  
  595. /// A event from Photon has been sent.
  596.  
  597. /// </summary>
  598.  
  599. /// <param name="photonEvent">The Photon event.</param>
  600.  
  601. public void OnEvent(EventData photonEvent)
  602.  
  603. {
  604.  
  605. if (photonEvent.Code == PhotonEventIDs.PlayerInstantiation)
  606.  
  607. {
  608.  
  609. // The Master Client has instantiated a character. Create that character on the local client as well.
  610.  
  611. var data = (object[]) photonEvent.CustomData;
  612.  
  613. for (int i = 0; i < data.Length / 4; ++i)
  614.  
  615. {
  616.  
  617. var viewID = (int) data[i * 4 + 2];
  618.  
  619. if (PhotonNetwork.GetPhotonView(viewID) != null)
  620.  
  621. {
  622.  
  623. continue;
  624.  
  625. }
  626.  
  627.  
  628.  
  629. var player = PhotonNetwork.CurrentRoom.GetPlayer((int) data[i * 4 + 3]);
  630.  
  631. var character = Instantiate(GetCharacterPrefab(player), (Vector3) data[i * 4],
  632.  
  633. (Quaternion) data[i * 4 + 1]);
  634.  
  635. var photonView = character.GetCachedComponent<PhotonView>();
  636.  
  637. photonView.ViewID = viewID;
  638.  
  639. // 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.
  640.  
  641. photonView.TransferOwnership(null);
  642.  
  643. photonView.TransferOwnership(player);
  644.  
  645. AddPhotonView(photonView);
  646.  
  647.  
  648.  
  649. // 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
  650.  
  651. // that the character has been created so it can be activated.
  652.  
  653. if (photonView.IsMine)
  654.  
  655. {
  656.  
  657. m_RaiseEventOptions.TargetActors = new int[] {PhotonNetwork.MasterClient.ActorNumber};
  658.  
  659. PhotonNetwork.RaiseEvent(PhotonEventIDs.RemotePlayerInstantiationComplete,
  660.  
  661. photonView.Owner.ActorNumber, m_RaiseEventOptions, m_ReliableSendOption);
  662.  
  663. }
  664.  
  665. else
  666.  
  667. {
  668.  
  669. // Call start manually before any events are received. This ensures the remote character has been initialized.
  670.  
  671. var characterLocomotion =
  672.  
  673. character
  674.  
  675. .GetCachedComponent<
  676.  
  677. UltimateCharacterController.Character.UltimateCharacterLocomotion>();
  678.  
  679. characterLocomotion.Start();
  680.  
  681. }
  682.  
  683.  
  684.  
  685. EventHandler.ExecuteEvent("OnPlayerEnteredRoom", photonView.Owner, photonView.gameObject);
  686.  
  687. }
  688.  
  689. }
  690.  
  691. else if (photonEvent.Code == PhotonEventIDs.RemotePlayerInstantiationComplete)
  692.  
  693. {
  694.  
  695. // The remote player has instantiated the character. It can now be enabled (on the Master Client).
  696.  
  697. var ownerActor = (int) photonEvent.CustomData;
  698.  
  699. for (int i = 0; i < m_PlayerCount; ++i)
  700.  
  701. {
  702.  
  703. if (m_Players[i].Owner.ActorNumber == ownerActor)
  704.  
  705. {
  706.  
  707. m_Players[i].gameObject.SetActive(true);
  708.  
  709. break;
  710.  
  711. }
  712.  
  713. }
  714.  
  715. }
  716.  
  717. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement