Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feature/respawning #782

Draft
wants to merge 6 commits into
base: dev
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Assets/Scripts/Augment/GunController.cs
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,12 @@ public void Initialize()
localGunZOffset = transform.localPosition.z;
}

public void Reset()
{
stats.Ammo = stats.MagazineSize;
isFiring = false;
}

private void OnDestroy()
{
if (!barrelAnimator)
Expand Down
36 changes: 31 additions & 5 deletions Assets/Scripts/Control&Input/OrbitCamera.cs
Original file line number Diff line number Diff line change
Expand Up @@ -19,11 +19,14 @@ public class OrbitCamera : MonoBehaviour
private Transform cameraTransform;
private new Camera camera;

private LayerMask previousCullingMask;

public Camera Camera
{
set
{
camera = value;
previousCullingMask = camera.cullingMask;
camera.cullingMask = cullingMask | (1 << (12 + player.LayerIndex));
cameraTransform = value.transform;
}
Expand All @@ -39,6 +42,8 @@ public Camera Camera
private int targetIndex = 0;
private PlayerManager player;

private Coroutine trackingRoutine;

private void Start()
{
player = GetComponent<PlayerManager>();
Expand All @@ -62,17 +67,28 @@ public void Activate()
if (!MatchController.Singleton.IsRoundInProgress)
return;
otherPlayers = MatchController.Singleton.Players.Where(p => p != GetComponent<PlayerManager>()).ToArray();
StartCoroutine(WaitAndStopTrackingRagdoll());
trackingRoutine = StartCoroutine(WaitAndStopTrackingRagdoll());
}

public void Deactivate()
{
StopTracking();
StopCoroutine(trackingRoutine);
camera.cullingMask = previousCullingMask;
}

private IEnumerator WaitAndStopTrackingRagdoll()
{
yield return new WaitForSeconds(3f);
player.HUDController.DisplaySpectateHint();
InputManager.onSelect += SwitchTarget;
InputManager.onFirePerformed += SwitchTarget;
// TODO remove
InputManager.onZoomPerformed += Respawn;

yield return new WaitForSeconds(3f);
player.HUDController.DisplaySpectateHint();

yield return new WaitForSeconds(3f);
var isStillOnPlayer = target == player.AiAimSpot;
var isStillOnPlayer = isTracking && target == player.AiAimSpot;
if (isStillOnPlayer)
{
StopTracking();
Expand All @@ -81,6 +97,12 @@ private IEnumerator WaitAndStopTrackingRagdoll()
}
}

// TODO remove
private void Respawn(InputAction.CallbackContext ctx)
{
player.Respawn(FindObjectOfType<PlayerFactory>().GetRandomSpawnpoints().First());
}

private void SwitchTarget(InputAction.CallbackContext ctx)
{
if (!MatchController.Singleton.IsRoundInProgress)
Expand All @@ -97,7 +119,7 @@ private void SwitchTarget(InputAction.CallbackContext ctx)

private void StartTracking(PlayerManager nextTarget)
{
if (!cameraTransform || !InputManager || !MatchController.Singleton.IsRoundInProgress)
if (!cameraTransform || !InputManager)
return;
isTracking = true;
camera.enabled = true;
Expand All @@ -110,6 +132,10 @@ private void StopTracking()
{
if (!camera)
return;
InputManager.onSelect -= SwitchTarget;
InputManager.onFirePerformed -= SwitchTarget;
// TODO remove
InputManager.onZoomPerformed -= Respawn;
isTracking = false;
camera.enabled = false;
ResetCamera();
Expand Down
224 changes: 14 additions & 210 deletions Assets/Scripts/Control&Input/Peer2PeerTransport.cs
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,14 @@ public struct PlayerDetails
public string body;
public string barrel;
public string extension;

public string PlayerNameWithIndex()
{
var mySteamID = steamID;
if (Peer2PeerTransport.PlayerDetails.Count(p => p.steamID == mySteamID) > 1)
return $"{name} {localInputID + 1}";
return name;
}
}

public struct PlayerConnectedMessage : NetworkMessage
Expand Down Expand Up @@ -135,8 +143,6 @@ public class Peer2PeerTransport : NetworkManager
private const int AIFPSPlayerPrefabIndex = 2;
private const int TrainingPlayerPrefabIndex = 4;

private const int NetworkPlayerLayer = 3;

private PlayerFactory playerFactory;
private static Transform[] spawnPoints;
private static Stack<Transform> spawnPointStack;
Expand Down Expand Up @@ -701,8 +707,8 @@ private IEnumerator SendSpawnRequestsAfterSceneLoad(string originalSceneName)

#endregion

#region Spawn FPS players

#region Spawn players

private void SpawnPlayer(NetworkConnectionToClient connection, SpawnPlayerMessage message, int prefabIndexOffset = 0)
{
Expand Down Expand Up @@ -754,161 +760,22 @@ private void OnSpawnFPSPlayer(NetworkConnectionToClient connection, SpawnPlayerM

private void InitializeFPSPlayer(InitializePlayerMessage message)
{
StartCoroutine(WaitAndInitializeFPSPlayer(message));
}

// TODO move this somewhere else?
public static string PlayerNameWithIndex(PlayerDetails playerDetails)
{
var playerName = playerDetails.name;
if (players.Values.Count(p => p.steamID == playerDetails.steamID) > 1)
playerName = $"{playerName} {playerDetails.localInputID + 1}";
return playerName;
}

private void UpdateIdentityFromDetails(PlayerIdentity identity, PlayerDetails playerDetails)
{
identity.UpdateFromDetails(playerDetails, PlayerNameWithIndex(playerDetails));
}

private IEnumerator WaitAndInitializeFPSPlayer(InitializePlayerMessage message)
{
// Wait until player object is spawned
PlayerManager player = null;
while (player == null)
{
player = FindObjectsOfType<PlayerManager>()
.FirstOrDefault(p => p.id == message.id);
yield return null;
}

if (!player)
{
Debug.LogError($"Could not find player object for id {message.id}");
yield break;
}

if (!players.TryGetValue(message.id, out var playerDetails))
{
Debug.LogError($"Could not find player details for id {message.id}");
yield break;
}

var playerManager = player.GetComponent<PlayerManager>();

player.transform.position = message.position;
player.transform.rotation = message.rotation;

var cameraOffset = player.transform.Find("CameraOffset");
playerManager.GetComponent<AmmoBoxCollector>().enabled = true;

if (playerDetails.type is PlayerType.Local)
{
Debug.Log($"Spawning local player {playerDetails.id}");
var input = PlayerInputManagerController.Singleton.LocalPlayerInputs[playerDetails.localInputID];

// Reset camera transform (it may have been kerfluffled by the spectator cam thingy)
input.transform.localPosition = Vector3.zero;
input.transform.localRotation = Quaternion.identity;
input.PlayerCamera.transform.localRotation = Quaternion.identity;
input.PlayerCamera.transform.localPosition = Vector3.zero;

// Make playerInput child of player it's attached to
input.transform.parent = player.transform;
// Set received playerInput (and most importantly its camera) at an offset from player's position
input.transform.localPosition = cameraOffset.localPosition;
input.transform.rotation = player.transform.rotation;

// Enable Camera
input.PlayerCamera.enabled = true;
input.PlayerCamera.orthographic = false;

playerManager.HUDController.gameObject.SetActive(true);
var movement = player.GetComponent<PlayerMovement>();

// The identity sits on the input in this case, so edit that
var identity = input.GetComponent<PlayerIdentity>();
UpdateIdentityFromDetails(identity, playerDetails);

// Update player's movement script with which playerInput it should attach listeners to
playerManager.SetPlayerInput(input);
var gunHolder = input.transform.GetChild(0);
playerManager.SetGun(gunHolder);

// Set unique layer for player
playerManager.SetLayer(input.playerInput.playerIndex);
movement.SetInitialRotation(message.rotation.eulerAngles.y * Mathf.Deg2Rad);

if (GunFactory.TryGetGunAchievement(playerManager.identity.Body, playerManager.identity.Barrel,
playerManager.identity.Extension, out var achievement))
SteamManager.Singleton.UnlockAchievement(achievement);
}
else if (playerDetails.type is PlayerType.AI && NetworkServer.active)
{
Debug.Log($"Spawning AI player {playerDetails.id}");
AIManager manager = player.GetComponent<AIManager>();
manager.SetLayer(NetworkPlayerLayer);
UpdateIdentityFromDetails(playerManager.identity, playerDetails);
manager.SetIdentity(playerManager.identity);
manager.GetComponent<AIMovement>().SetInitialRotation(message.rotation.eulerAngles.y * Mathf.Deg2Rad);
}
else
{
Debug.Log($"Spawning network player {playerDetails.id}");

UpdateIdentityFromDetails(playerManager.identity, playerDetails);

// TODO do some other version of disabling HUD completely
Destroy(playerManager.HUDController);

// Disable physics
playerManager.GetComponent<Rigidbody>().isKinematic = true;

// Create display gun structure
var gunHolderParent = new GameObject("DisplayGunParent").transform;
gunHolderParent.parent = player.transform;
gunHolderParent.position = cameraOffset.position;
gunHolderParent.rotation = player.transform.rotation;
var gunHolder = new GameObject("DisplayGunHolder").transform;
gunHolder.parent = gunHolderParent.transform;
gunHolder.localPosition = Vector3.zero;
gunHolder.localRotation = Quaternion.identity;
playerManager.SetLayer(NetworkPlayerLayer);
// Can't initialize quite like the AIs because of where the GunController network behaviour is located :(
playerManager.SetGun(gunHolder);
}

playerManager.ApplyIdentity();

// This ensures that behaviours on the gun have identities.
// SHOULD be safe to initialize them here as this is at roughly the same point on all clients
player.GetComponent<NetworkIdentity>().InitializeNetworkBehaviours();

if (MatchController.Singleton)
{
MatchController.Singleton.RegisterPlayer(playerManager);
}

playerInstances[player.id] = player;
StartCoroutine(WaitAndInitializePlayer(message, false));
}

#endregion

#region Bidding spawning

private void OnSpawnBiddingPlayer(NetworkConnectionToClient connection, SpawnPlayerMessage message)
{
SpawnPlayer(connection, message, BiddingPlayerPrefabIndexOffset);
}

private void InitializeBiddingPlayer(InitializePlayerMessage message)
{
StartCoroutine(WaitAndInitializeBiddingPlayer(message));
StartCoroutine(WaitAndInitializePlayer(message, true));
}

private IEnumerator WaitAndInitializeBiddingPlayer(InitializePlayerMessage message)
private IEnumerator WaitAndInitializePlayer(InitializePlayerMessage message, bool isBidding = false)
{
// Wait until players must've been spawned
// Wait until player object is spawned
PlayerManager player = null;
while (player == null)
{
Expand All @@ -929,70 +796,7 @@ private IEnumerator WaitAndInitializeBiddingPlayer(InitializePlayerMessage messa
yield break;
}

var playerManager = player.GetComponent<PlayerManager>();

player.transform.position = message.position;
player.transform.rotation = message.rotation;

var cameraOffset = player.transform.Find("CameraOffset");
playerManager.GetComponent<AmmoBoxCollector>().enabled = true;

if (playerDetails.type is PlayerType.Local)
{
Debug.Log($"Spawning local player {playerDetails.id}");
var input = PlayerInputManagerController.Singleton.LocalPlayerInputs[playerDetails.localInputID];

// Reset camera transform (ensuring we don't mess up in weapon building)
input.transform.localPosition = Vector3.zero;
input.transform.localRotation = Quaternion.identity;
input.PlayerCamera.transform.localRotation = Quaternion.identity;
input.PlayerCamera.transform.localPosition = Vector3.zero;

// Make playerInput child of player it's attached to
input.transform.parent = player.transform;
// Set received playerInput (and most importantly its camera) at an offset from player's position
input.transform.localPosition = cameraOffset.localPosition;
input.transform.rotation = player.transform.rotation;

// Disable Camera
input.PlayerCamera.enabled = false;

// Update player's movement script with which playerInput it should attach listeners to
playerManager.SetPlayerInput(input);
player.GetComponent<HealthController>().enabled = false;

// The identity sits on the input in this case, so edit that
var identity = input.GetComponent<PlayerIdentity>();
UpdateIdentityFromDetails(identity, playerDetails);
}
else if (playerDetails.type is PlayerType.AI && NetworkServer.active)
{
Debug.Log($"Spawning AI player {playerDetails.id}");
AIManager manager = player.GetComponent<AIManager>();
manager.SetLayer(NetworkPlayerLayer);
UpdateIdentityFromDetails(playerManager.identity, playerDetails);
manager.SetIdentity(manager.identity);
}
else
{
Debug.Log($"Spawning network player {playerDetails.id}");

UpdateIdentityFromDetails(playerManager.identity, playerDetails);

// Disable physics
playerManager.GetComponent<Rigidbody>().isKinematic = true;
}

playerManager.ApplyIdentity();

// This ensures that behaviours on the gun have identities.
// SHOULD be safe to initialize them here as this is at roughly the same point on all clients
player.GetComponent<NetworkIdentity>().InitializeNetworkBehaviours();

if (MatchController.Singleton)
{
MatchController.Singleton.RegisterPlayer(playerManager);
}
PlayerFactory.InitializePlayer(message, player, playerDetails, isBidding);

playerInstances[player.id] = player;
}
Expand Down
7 changes: 5 additions & 2 deletions Assets/Scripts/Gamestate/AIManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -249,7 +249,8 @@ private void FindPlayers()
agent.stoppingDistance = ShootingTarget ? shootingStoppingDistance : itemStoppingDistance;
try
{
agent.SetDestination(DestinationTarget.position);
if (agent.enabled)
agent.SetDestination(DestinationTarget.position);
}
catch
{
Expand Down Expand Up @@ -287,7 +288,9 @@ IEnumerator AnimateJumpCurve(float duration)
normalizedTime += Time.deltaTime / duration;
yield return null;
}
agent.CompleteOffMeshLink();
// TODO why is the agent sometimes not enabled here?
if (agent.enabled)
agent.CompleteOffMeshLink();
onLinkEnd?.Invoke();
}

Expand Down
Loading