Skip to content
This repository was archived by the owner on Oct 20, 2021. It is now read-only.

Commit e9cfb62

Browse files
authored
Adding callbacks for losing player (#181)
* ensuring that player entity gets respawned, if deleted due to heartbeating * updating imports * PR feedback
1 parent e9de9ae commit e9cfb62

File tree

5 files changed

+99
-66
lines changed

5 files changed

+99
-66
lines changed

workers/unity/Assets/Fps/Scripts/GameLogic/StateMachine/Default/DefaultPlayState.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,18 +9,28 @@ public DefaultPlayState(UIManager manager, ConnectionStateMachine owner) : base(
99
public override void StartState()
1010
{
1111
Blackboard.ClientConnector.Worker.OnDisconnect += WorkerOnDisconnect;
12+
Blackboard.ClientConnector.OnLostPlayerEntity += LostPlayerEntity;
1213
Manager.InGameManager.Timer.SetActive(false);
1314
Manager.ShowGameView();
1415
}
1516

1617
public override void ExitState()
1718
{
1819
Blackboard.ClientConnector.Worker.OnDisconnect -= WorkerOnDisconnect;
20+
Blackboard.ClientConnector.OnLostPlayerEntity -= LostPlayerEntity;
1921
}
2022

2123
private void WorkerOnDisconnect(string reason)
2224
{
2325
Owner.SetState(new DisconnectedState(Manager, Owner));
2426
}
27+
28+
private void LostPlayerEntity()
29+
{
30+
Manager.ShowFrontEnd();
31+
ScreenManager.SwitchToDefaultScreen();
32+
Animator.SetTrigger("Disconnected");
33+
Owner.SetState(new DisconnectedState(Manager, Owner));
34+
}
2535
}
2636
}

workers/unity/Assets/Fps/Scripts/GameLogic/StateMachine/Default/DisconnectedState.cs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
using UnityEngine;
2+
13
namespace Fps
24
{
35
public class DisconnectedState : DefaultState
@@ -8,6 +10,7 @@ public DisconnectedState(UIManager manager, ConnectionStateMachine owner) : base
810

911
public override void StartState()
1012
{
13+
Object.Destroy(Blackboard.ClientConnector.gameObject);
1114
Blackboard.ClientConnector = null;
1215
ScreenManager.DefaultConnectButton.enabled = true;
1316
ScreenManager.DefaultConnectButton.onClick.AddListener(Connect);

workers/unity/Assets/Fps/Scripts/SetupLogic/AdvancedEntityPipeline.cs

Lines changed: 72 additions & 62 deletions
Original file line numberDiff line numberDiff line change
@@ -6,94 +6,104 @@
66
using Improbable.Gdk.Movement;
77
using Improbable.Gdk.StandardTypes;
88
using Improbable.Gdk.Subscriptions;
9-
using Unity.Entities;
109
using UnityEngine;
1110
using Object = UnityEngine.Object;
1211

13-
public class AdvancedEntityPipeline : IEntityGameObjectCreator
12+
namespace Fps
1413
{
15-
private const string GameobjectNameFormat = "{0}(SpatialOS {1}, Worker: {2})";
16-
private const string WorkerAttributeFormat = "workerId:{0}";
17-
private const string PlayerMetadata = "Player";
14+
public class AdvancedEntityPipeline : IEntityGameObjectCreator
15+
{
16+
private const string GameobjectNameFormat = "{0}(SpatialOS {1}, Worker: {2})";
17+
private const string WorkerAttributeFormat = "workerId:{0}";
18+
private const string PlayerMetadata = "Player";
1819

19-
private readonly GameObject cachedAuthPlayer;
20-
private readonly GameObject cachedNonAuthPlayer;
20+
private readonly GameObject cachedAuthPlayer;
21+
private readonly GameObject cachedNonAuthPlayer;
2122

22-
private readonly IEntityGameObjectCreator fallback;
23-
private readonly string workerIdAttribute;
24-
private readonly Worker worker;
23+
private readonly IEntityGameObjectCreator fallback;
24+
private readonly string workerIdAttribute;
25+
private readonly Worker worker;
2526

26-
private readonly Dictionary<EntityId, GameObject> gameObjectsCreated = new Dictionary<EntityId, GameObject>();
27+
private readonly Dictionary<EntityId, GameObject> gameObjectsCreated = new Dictionary<EntityId, GameObject>();
2728

28-
private readonly Type[] componentsToAdd =
29-
{
30-
typeof(Transform),
31-
typeof(Rigidbody)
32-
};
29+
public event Action OnRemovedAuthoritativePlayer;
3330

34-
public AdvancedEntityPipeline(Worker worker, string authPlayer, string nonAuthPlayer,
35-
IEntityGameObjectCreator fallback)
36-
{
37-
this.worker = worker;
38-
this.fallback = fallback;
39-
workerIdAttribute = string.Format(WorkerAttributeFormat, worker.WorkerId);
40-
cachedAuthPlayer = Resources.Load<GameObject>(authPlayer);
41-
cachedNonAuthPlayer = Resources.Load<GameObject>(nonAuthPlayer);
42-
}
31+
private readonly Type[] componentsToAdd =
32+
{
33+
typeof(Transform),
34+
typeof(Rigidbody)
35+
};
4336

44-
public void OnEntityCreated(SpatialOSEntity entity, EntityGameObjectLinker linker)
45-
{
46-
if (!entity.HasComponent<Metadata.Component>())
37+
public AdvancedEntityPipeline(Worker worker, string authPlayer, string nonAuthPlayer,
38+
IEntityGameObjectCreator fallback)
4739
{
48-
return;
40+
this.worker = worker;
41+
this.fallback = fallback;
42+
workerIdAttribute = EntityTemplate.GetWorkerAccessAttribute(worker.WorkerId);
43+
cachedAuthPlayer = Resources.Load<GameObject>(authPlayer);
44+
cachedNonAuthPlayer = Resources.Load<GameObject>(nonAuthPlayer);
4945
}
5046

51-
var prefabName = entity.GetComponent<Metadata.Component>().EntityType;
52-
if (prefabName.Equals(PlayerMetadata))
47+
public void OnEntityCreated(SpatialOSEntity entity, EntityGameObjectLinker linker)
5348
{
54-
var clientMovement = entity.GetComponent<ClientMovement.Component>();
55-
if (entity.GetComponent<EntityAcl.Component>().ComponentWriteAcl
56-
.TryGetValue(clientMovement.ComponentId, out var clientMovementWrite))
49+
if (!entity.HasComponent<Metadata.Component>())
5750
{
58-
var authority = false;
59-
foreach (var attributeSet in clientMovementWrite.AttributeSet)
51+
return;
52+
}
53+
54+
var prefabName = entity.GetComponent<Metadata.Component>().EntityType;
55+
if (prefabName.Equals(PlayerMetadata))
56+
{
57+
var clientMovement = entity.GetComponent<ClientMovement.Component>();
58+
if (entity.GetComponent<EntityAcl.Component>().ComponentWriteAcl
59+
.TryGetValue(clientMovement.ComponentId, out var clientMovementWrite))
6060
{
61-
if (attributeSet.Attribute.Contains(workerIdAttribute))
61+
var authority = false;
62+
foreach (var attributeSet in clientMovementWrite.AttributeSet)
6263
{
63-
authority = true;
64+
if (attributeSet.Attribute.Contains(workerIdAttribute))
65+
{
66+
authority = true;
67+
}
6468
}
65-
}
6669

67-
var serverPosition = entity.GetComponent<ServerMovement.Component>();
68-
var position = serverPosition.Latest.Position.ToVector3() + worker.Origin;
70+
var serverPosition = entity.GetComponent<ServerMovement.Component>();
71+
var position = serverPosition.Latest.Position.ToVector3() + worker.Origin;
6972

70-
var prefab = authority ? cachedAuthPlayer : cachedNonAuthPlayer;
71-
var gameObject = Object.Instantiate(prefab, position, Quaternion.identity);
73+
var prefab = authority ? cachedAuthPlayer : cachedNonAuthPlayer;
74+
var gameObject = Object.Instantiate(prefab, position, Quaternion.identity);
7275

73-
gameObjectsCreated.Add(entity.SpatialOSEntityId, gameObject);
74-
gameObject.name = GetGameObjectName(prefab, entity, worker);
75-
linker.LinkGameObjectToSpatialOSEntity(entity.SpatialOSEntityId, gameObject, componentsToAdd);
76-
return;
76+
gameObjectsCreated.Add(entity.SpatialOSEntityId, gameObject);
77+
gameObject.name = GetGameObjectName(prefab, entity, worker);
78+
linker.LinkGameObjectToSpatialOSEntity(entity.SpatialOSEntityId, gameObject, componentsToAdd);
79+
return;
80+
}
7781
}
78-
}
7982

80-
fallback.OnEntityCreated(entity, linker);
81-
}
82-
83-
private static string GetGameObjectName(GameObject prefab, SpatialOSEntity entity, Worker worker)
84-
{
85-
return string.Format(GameobjectNameFormat, prefab.name, entity.SpatialOSEntityId, worker.WorkerType);
86-
}
83+
fallback.OnEntityCreated(entity, linker);
84+
}
8785

88-
public void OnEntityRemoved(EntityId entityId)
89-
{
90-
if (!gameObjectsCreated.TryGetValue(entityId, out var go))
86+
private static string GetGameObjectName(GameObject prefab, SpatialOSEntity entity, Worker worker)
9187
{
92-
fallback.OnEntityRemoved(entityId);
93-
return;
88+
return string.Format(GameobjectNameFormat, prefab.name, entity.SpatialOSEntityId, worker.WorkerType);
9489
}
9590

96-
gameObjectsCreated.Remove(entityId);
97-
Object.Destroy(go);
91+
public void OnEntityRemoved(EntityId entityId)
92+
{
93+
if (!gameObjectsCreated.TryGetValue(entityId, out var go))
94+
{
95+
fallback.OnEntityRemoved(entityId);
96+
return;
97+
}
98+
99+
// Trigger a callback when authoritative player gets removed
100+
if (go.GetComponent<FpsDriver>() != null)
101+
{
102+
OnRemovedAuthoritativePlayer?.Invoke();
103+
}
104+
105+
gameObjectsCreated.Remove(entityId);
106+
Object.Destroy(go);
107+
}
98108
}
99109
}

workers/unity/Assets/Fps/Scripts/SetupLogic/ClientWorkerConnector.cs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,8 @@ public class ClientWorkerConnector : WorkerConnectorBase
2121

2222
protected bool UseSessionFlow => !string.IsNullOrEmpty(deployment);
2323

24+
public event Action OnLostPlayerEntity;
25+
2426
public async void Connect(string deployment = "")
2527
{
2628
this.deployment = deployment.Trim();
@@ -95,11 +97,12 @@ protected override void HandleWorkerConnectionEstablished()
9597

9698
var fallback = new GameObjectCreatorFromMetadata(Worker.WorkerType, Worker.Origin, Worker.LogDispatcher);
9799

100+
var entityPipeline = new AdvancedEntityPipeline(Worker, GetAuthPlayerPrefabPath(),
101+
GetNonAuthPlayerPrefabPath(), fallback);
102+
entityPipeline.OnRemovedAuthoritativePlayer += RemovingAuthoritativePlayer;
103+
98104
// Set the Worker gameObject to the ClientWorker so it can access PlayerCreater reader/writers
99-
GameObjectCreationHelper.EnableStandardGameObjectCreation(
100-
world,
101-
new AdvancedEntityPipeline(Worker, GetAuthPlayerPrefabPath(), GetNonAuthPlayerPrefabPath(), fallback),
102-
gameObject);
105+
GameObjectCreationHelper.EnableStandardGameObjectCreation(world, entityPipeline, gameObject);
103106

104107
if (UseSessionFlow)
105108
{
@@ -109,6 +112,12 @@ protected override void HandleWorkerConnectionEstablished()
109112
base.HandleWorkerConnectionEstablished();
110113
}
111114

115+
private void RemovingAuthoritativePlayer()
116+
{
117+
Debug.LogError($"Player entity got removed while still being connected. Disconnecting...");
118+
OnLostPlayerEntity?.Invoke();
119+
}
120+
112121
protected override void HandleWorkerConnectionFailure(string errorMessage)
113122
{
114123
Debug.LogError($"Connection failed: {errorMessage}");

workers/unity/Assets/Fps/Scripts/SetupLogic/OneTimeInitialisation.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ private static void Init()
2323

2424
// Setup template to use for player on connecting client
2525
PlayerLifecycleConfig.CreatePlayerEntityTemplate = FpsEntityTemplates.Player;
26+
PlayerLifecycleConfig.MaxNumFailedPlayerHeartbeats = 5;
2627
}
2728
}
2829
}

0 commit comments

Comments
 (0)