Skip to content

Commit 43906be

Browse files
update
Adding AttachableBehaviour and ObjectController.
1 parent 169a1ae commit 43906be

File tree

4 files changed

+269
-0
lines changed

4 files changed

+269
-0
lines changed
Lines changed: 146 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,146 @@
1+
using System;
2+
using UnityEngine;
3+
4+
namespace Unity.Netcode.Components
5+
{
6+
/// <summary>
7+
/// Handles parenting the <see cref="GameObject"/> that is a child under a root network prefab
8+
/// without having to use the same <see cref="NetworkObject"/> parenting rules.
9+
/// </summary>
10+
public class AttachableBehaviour : NetworkBehaviour
11+
{
12+
/// <summary>
13+
/// Invoked just prior to the parent being applied.
14+
/// </summary>
15+
/// <remarks>
16+
/// The <see cref="NetworkBehaviour"/> parameter passed into a susbcriber callback will be either null or a valid. <br />
17+
/// When null, the parent is being unapplied/removed from the <see cref="GameObject"/> this <see cref="AttachableBehaviour"/> instance is attached to.
18+
/// </remarks>
19+
public event Action<NetworkBehaviour> ParentIsBeingApplied;
20+
21+
private NetworkVariable<NetworkBehaviourReference> m_AppliedParent = new NetworkVariable<NetworkBehaviourReference>(new NetworkBehaviourReference(null));
22+
private GameObject m_DefaultParent;
23+
private Vector3 m_OriginalLocalPosition;
24+
private Quaternion m_OriginalLocalRotation;
25+
26+
/// <summary>
27+
/// Will be true when this <see href="AttachableBehaviour"/> instance has a parent applied to it.<br />
28+
/// Will be false when this <see href="AttachableBehaviour"/> instance does not have a parent applied to it.<br />
29+
/// </summary>
30+
public bool ParentIsApplied { get; private set; }
31+
32+
/// <inheritdoc/>
33+
protected virtual void Awake()
34+
{
35+
m_DefaultParent = transform.parent == null ? gameObject : transform.parent.gameObject;
36+
m_OriginalLocalPosition = transform.localPosition;
37+
m_OriginalLocalRotation = transform.localRotation;
38+
}
39+
40+
/// <inheritdoc/>
41+
protected override void OnNetworkPostSpawn()
42+
{
43+
base.OnNetworkPostSpawn();
44+
if (HasAuthority)
45+
{
46+
m_AppliedParent.Value = new NetworkBehaviourReference(null);
47+
}
48+
UpdateParent();
49+
m_AppliedParent.OnValueChanged += OnAppliedParentChanged;
50+
}
51+
52+
/// <inheritdoc/>
53+
public override void OnNetworkDespawn()
54+
{
55+
ResetToDefault();
56+
base.OnNetworkDespawn();
57+
}
58+
59+
private void OnAppliedParentChanged(NetworkBehaviourReference previous, NetworkBehaviourReference current)
60+
{
61+
UpdateParent();
62+
}
63+
64+
private void UpdateParent()
65+
{
66+
var parent = (NetworkBehaviour)null;
67+
if (m_AppliedParent.Value.TryGet(out parent))
68+
{
69+
ParentIsApplied = true;
70+
transform.SetParent(parent.gameObject.transform, false);
71+
}
72+
else
73+
{
74+
ParentIsApplied = false;
75+
ResetToDefault();
76+
}
77+
78+
OnParentUpdated(parent);
79+
}
80+
81+
private void ResetToDefault()
82+
{
83+
if (m_DefaultParent != null)
84+
{
85+
transform.SetParent(m_DefaultParent.transform, false);
86+
}
87+
transform.localPosition = m_OriginalLocalPosition;
88+
transform.localRotation = m_OriginalLocalRotation;
89+
}
90+
91+
/// <summary>
92+
/// Invoked after the parent has been applied.<br />
93+
/// </summary>
94+
/// <remarks>
95+
/// The <param name="parent"/> can be either null or a valid <see cref="NetworkBehaviour"/>. <br />
96+
/// When null, the parent is being unapplied/removed from the <see cref="GameObject"/> this <see cref="AttachableBehaviour"/> instance is attached to.
97+
/// </remarks>
98+
/// <param name="parent">The <see cref="NetworkBehaviour"/> that is applied or null if it is no longer applied.</param>
99+
protected virtual void OnParentUpdated(NetworkBehaviour parent)
100+
{
101+
102+
}
103+
104+
/// <summary>
105+
/// Invoked just prior to the parent being applied. <br />
106+
/// This is a good time to handle disabling or enabling <see cref="Object"/>s using an <see cref="ObjectController"/>.
107+
/// </summary>
108+
/// <remarks>
109+
/// The <param name="parent"/> can be either null or a valid <see cref="NetworkBehaviour"/>. <br />
110+
/// When null, the parent is being unapplied/removed from the <see cref="GameObject"/> this <see cref="AttachableBehaviour"/> instance is attached to.
111+
/// </remarks>
112+
/// <param name="parent">The <see cref="NetworkBehaviour"/> that is applied or null if it is no longer applied.</param>
113+
protected virtual void OnParentBeingApplied(NetworkBehaviour parent)
114+
{
115+
116+
}
117+
118+
/// <summary>
119+
/// Applies a parent to a nested <see cref="NetworkBehaviour"/> and all <see cref="GameObject"/> children
120+
/// of the nested <see cref="NetworkBehaviour"/>.
121+
/// </summary>
122+
/// <param name="parent">The <see cref="NetworkBehaviour"/> to be applied or null to reparent under its original <see cref="GameObject"/> when spawned.</param>
123+
public void ApplyParent(NetworkBehaviour parent)
124+
{
125+
if (!IsSpawned)
126+
{
127+
Debug.LogError($"[{name}][Not Spawned] Can only have a parent applied when it is spawned!");
128+
return;
129+
}
130+
131+
if (!HasAuthority)
132+
{
133+
Debug.LogError($"[{name}][Not Authority] Client-{NetworkManager.LocalClientId} is not the authority!");
134+
return;
135+
}
136+
// Notify any subscriptions
137+
ParentIsBeingApplied?.Invoke(parent);
138+
139+
// Invoke for any overrides
140+
OnParentBeingApplied(parent);
141+
142+
// Once everything has been notified that we are applying a parent...apply the parent.
143+
m_AppliedParent.Value = new NetworkBehaviourReference(parent);
144+
}
145+
}
146+
}

com.unity.netcode.gameobjects/Runtime/Components/Helpers/AttachableBehaviour.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
using System.Collections.Generic;
2+
using System.Reflection;
3+
using UnityEngine;
4+
using Object = UnityEngine.Object;
5+
6+
namespace Unity.Netcode.Components
7+
{
8+
/// <summary>
9+
/// Handles enabling or disabling commonly used components, behaviours, RenderMeshes, etc.<br />
10+
/// Anything that derives from <see cref="Object"/> and has an enabled property can be added
11+
/// to the list of objects.<br />
12+
/// This also synchronizes the enabling or disabling of the objects with connected and late
13+
/// joining clients.
14+
/// </summary>
15+
public class ObjectController : NetworkBehaviour
16+
{
17+
/// <summary>
18+
/// Determines whether the selected <see cref="Object"/>s will start out enabled or disabled.
19+
/// </summary>
20+
public bool InitialState;
21+
22+
/// <summary>
23+
/// The list of <see cref="Object"/>s to be enabled and disabled.
24+
/// </summary>
25+
public List<Object> Objects;
26+
27+
private Dictionary<Object, PropertyInfo> m_ValidObjects = new Dictionary<Object, PropertyInfo>();
28+
private NetworkVariable<bool> m_IsEnabled = new NetworkVariable<bool>();
29+
30+
/// <inheritdoc/>
31+
protected virtual void Awake()
32+
{
33+
var emptyEntries = 0;
34+
foreach (var someObject in Objects)
35+
{
36+
if (someObject == null)
37+
{
38+
emptyEntries++;
39+
continue;
40+
}
41+
var propertyInfo = someObject.GetType().GetProperty("enabled", BindingFlags.Instance | BindingFlags.Public);
42+
if (propertyInfo != null && propertyInfo.PropertyType == typeof(bool))
43+
{
44+
m_ValidObjects.Add(someObject, propertyInfo);
45+
}
46+
else
47+
{
48+
Debug.LogWarning($"{name} does not contain a public enable property! (Ignoring)");
49+
}
50+
}
51+
if (emptyEntries > 0)
52+
{
53+
Debug.LogWarning($"{name} has {emptyEntries} emtpy(null) entries in the Objects list!");
54+
}
55+
else
56+
{
57+
Debug.Log($"{name} has {m_ValidObjects.Count} valid object entries.");
58+
}
59+
}
60+
61+
/// <inheritdoc/>
62+
public override void OnNetworkSpawn()
63+
{
64+
if (HasAuthority)
65+
{
66+
m_IsEnabled.Value = InitialState;
67+
}
68+
base.OnNetworkSpawn();
69+
}
70+
71+
/// <inheritdoc/>
72+
protected override void OnNetworkPostSpawn()
73+
{
74+
m_IsEnabled.OnValueChanged += OnEnabledChanged;
75+
ApplyEnabled(m_IsEnabled.Value);
76+
base.OnNetworkPostSpawn();
77+
}
78+
79+
/// <inheritdoc/>
80+
public override void OnNetworkDespawn()
81+
{
82+
m_IsEnabled.OnValueChanged -= OnEnabledChanged;
83+
base.OnNetworkDespawn();
84+
}
85+
86+
private void OnEnabledChanged(bool previous, bool current)
87+
{
88+
ApplyEnabled(current);
89+
}
90+
91+
private void ApplyEnabled(bool enabled)
92+
{
93+
foreach (var entry in m_ValidObjects)
94+
{
95+
entry.Value.SetValue(entry.Key, enabled);
96+
}
97+
}
98+
99+
/// <summary>
100+
/// Invoke on the authority side to enable or disable the <see cref="Objects"/>.
101+
/// </summary>
102+
/// <param name="isEnabled">true = enabled | false = disabled</param>
103+
public void SetEnabled(bool isEnabled)
104+
{
105+
if (!IsSpawned)
106+
{
107+
Debug.Log($"[{name}] Must be spawned to use {nameof(SetEnabled)}!");
108+
return;
109+
}
110+
111+
if (!HasAuthority)
112+
{
113+
Debug.Log($"[Client-{NetworkManager.LocalClientId}] Attempting to invoke {nameof(SetEnabled)} without authority!");
114+
return;
115+
}
116+
m_IsEnabled.Value = isEnabled;
117+
}
118+
}
119+
}

com.unity.netcode.gameobjects/Runtime/Components/Helpers/ObjectController.cs.meta

Lines changed: 2 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

0 commit comments

Comments
 (0)