1+ using System ;
12using System . Collections . Generic ;
23using System . Reflection ;
34using UnityEngine ;
45using Object = UnityEngine . Object ;
56
67namespace Unity . Netcode . Components
78{
9+ /// <summary>
10+ /// This is a serializable contianer class for <see cref="ComponentController"/> entries.
11+ /// </summary>
12+ [ Serializable ]
13+ public class ComponentControllerEntry
14+ {
15+ /// <summary>
16+ /// When true, this component's enabled state will be the inverse of
17+ /// the value passed into <see cref="ComponentController.SetEnabled(bool)"/>.
18+ /// </summary>
19+ public bool InvertEnabled ;
20+
21+ /// <summary>
22+ /// The component to control.
23+ /// </summary>
24+ /// <remarks>
25+ /// You can assign an entire <see cref="GameObject"/> to this property which will
26+ /// add all components attached to the <see cref="GameObject"/>. The <see cref="StartEnabled"/>
27+ /// and <see cref="InvertEnabled"/> properties will be applied to all components found on the <see cref="GameObject"/>.
28+ /// </remarks>
29+ public Object Component ;
30+
31+ internal PropertyInfo PropertyInfo ;
32+ }
33+
834 /// <summary>
935 /// Handles enabling or disabling commonly used components, behaviours, RenderMeshes, etc.<br />
1036 /// Anything that derives from <see cref="Component"/> and has an enabled property can be added
@@ -20,16 +46,21 @@ public class ComponentController : NetworkBehaviour
2046 /// <summary>
2147 /// Determines whether the selected <see cref="Components"/>s will start enabled or disabled when spawned.
2248 /// </summary>
23- [ Tooltip ( "The initial state of the components when spawned ." ) ]
24- public bool InitialState = true ;
49+ [ Tooltip ( "The initial state of the component controllers enabled status when instnatiated ." ) ]
50+ public bool StartEnabled = true ;
2551
2652 /// <summary>
2753 /// The list of <see cref="Components"/>s to be enabled and disabled.
2854 /// </summary>
2955 [ Tooltip ( "The list of components to control. You can drag and drop an entire GameObject on this to include all components." ) ]
30- public List < Object > Components ;
56+ public List < ComponentControllerEntry > Components ;
3157
32- private Dictionary < Component , PropertyInfo > m_ValidComponents = new Dictionary < Component , PropertyInfo > ( ) ;
58+ /// <summary>
59+ /// Returns the current enabled state of the <see cref="ComponentController"/>.
60+ /// </summary>
61+ public bool EnabledState => m_IsEnabled . Value ;
62+
63+ private List < ComponentControllerEntry > m_ValidComponents = new List < ComponentControllerEntry > ( ) ;
3364 private NetworkVariable < bool > m_IsEnabled = new NetworkVariable < bool > ( ) ;
3465
3566#if UNITY_EDITOR
@@ -44,39 +75,45 @@ protected virtual void OnValidate()
4475 return ;
4576 }
4677
47- var gameObjectsToScan = new List < GameObject > ( ) ;
78+ var gameObjectsToScan = new List < ComponentControllerEntry > ( ) ;
4879 for ( int i = Components . Count - 1 ; i >= 0 ; i -- )
4980 {
5081 if ( Components [ i ] == null )
5182 {
5283 continue ;
5384 }
54- var componentType = Components [ i ] . GetType ( ) ;
85+
86+ if ( Components [ i ] . Component == null )
87+ {
88+ continue ;
89+ }
90+ var componentType = Components [ i ] . Component . GetType ( ) ;
5591 if ( componentType == typeof ( GameObject ) )
5692 {
57- gameObjectsToScan . Add ( Components [ i ] as GameObject ) ;
93+ gameObjectsToScan . Add ( Components [ i ] ) ;
5894 Components . RemoveAt ( i ) ;
5995 continue ;
6096 }
6197
6298 if ( componentType . IsSubclassOf ( typeof ( NetworkBehaviour ) ) )
6399 {
64- Debug . LogWarning ( $ "Removing { Components [ i ] . name } since { nameof ( NetworkBehaviour ) } s are not allowed to be controlled by this component.") ;
100+ Debug . LogWarning ( $ "Removing { Components [ i ] . Component . name } since { nameof ( NetworkBehaviour ) } s are not allowed to be controlled by this component.") ;
65101 Components . RemoveAt ( i ) ;
66102 continue ;
67103 }
68104
69- var propertyInfo = Components [ i ] . GetType ( ) . GetProperty ( "enabled" , BindingFlags . Instance | BindingFlags . Public ) ;
105+ var propertyInfo = Components [ i ] . Component . GetType ( ) . GetProperty ( "enabled" , BindingFlags . Instance | BindingFlags . Public ) ;
70106 if ( propertyInfo == null && propertyInfo . PropertyType != typeof ( bool ) )
71107 {
72- Debug . LogWarning ( $ "{ Components [ i ] . name } does not contain a public enabled property! (Removing)") ;
108+ Debug . LogWarning ( $ "{ Components [ i ] . Component . name } does not contain a public enabled property! (Removing)") ;
73109 Components . RemoveAt ( i ) ;
74110 }
75111 }
76112
77113 foreach ( var entry in gameObjectsToScan )
78114 {
79- var components = entry . GetComponents < Component > ( ) ;
115+ var asGameObject = entry . Component as GameObject ;
116+ var components = asGameObject . GetComponents < Component > ( ) ;
80117 foreach ( var component in components )
81118 {
82119 // Ignore any NetworkBehaviour derived components
@@ -88,7 +125,12 @@ protected virtual void OnValidate()
88125 var propertyInfo = component . GetType ( ) . GetProperty ( "enabled" , BindingFlags . Instance | BindingFlags . Public ) ;
89126 if ( propertyInfo != null && propertyInfo . PropertyType == typeof ( bool ) )
90127 {
91- Components . Add ( component ) ;
128+ var componentEntry = new ComponentControllerEntry ( )
129+ {
130+ Component = component ,
131+ PropertyInfo = propertyInfo ,
132+ } ;
133+ Components . Add ( componentEntry ) ;
92134 }
93135 }
94136 }
@@ -97,23 +139,24 @@ protected virtual void OnValidate()
97139#endif
98140
99141 /// <summary>
100- /// Also checks to assure all <see cref="Component"/> entries are valid and creates a final table of
101- /// <see cref="Component "/>s paired to their <see cref="PropertyInfo"/> .
142+ /// This checks to make sure that all <see cref="Component"/> entries are valid and will create a final
143+ /// <see cref="ComponentControllerEntry "/> list of valid entries .
102144 /// </summary>
103145 protected virtual void Awake ( )
104146 {
105147 var emptyEntries = 0 ;
106- foreach ( var someObject in Components )
148+ foreach ( var entry in Components )
107149 {
108- if ( someObject == null )
150+ if ( entry == null )
109151 {
110152 emptyEntries ++ ;
111153 continue ;
112154 }
113- var propertyInfo = someObject . GetType ( ) . GetProperty ( "enabled" , BindingFlags . Instance | BindingFlags . Public ) ;
155+ var propertyInfo = entry . Component . GetType ( ) . GetProperty ( "enabled" , BindingFlags . Instance | BindingFlags . Public ) ;
114156 if ( propertyInfo != null && propertyInfo . PropertyType == typeof ( bool ) )
115157 {
116- m_ValidComponents . Add ( someObject as Component , propertyInfo ) ;
158+ entry . PropertyInfo = propertyInfo ;
159+ m_ValidComponents . Add ( entry ) ;
117160 }
118161 else
119162 {
@@ -128,14 +171,17 @@ protected virtual void Awake()
128171 {
129172 Debug . Log ( $ "{ name } has { m_ValidComponents . Count } valid { nameof ( Component ) } entries.") ;
130173 }
174+
175+ // Apply the initial state of all components this instance is controlling.
176+ InitializeComponents ( ) ;
131177 }
132178
133179 /// <inheritdoc/>
134180 public override void OnNetworkSpawn ( )
135181 {
136182 if ( HasAuthority )
137183 {
138- m_IsEnabled . Value = InitialState ;
184+ m_IsEnabled . Value = StartEnabled ;
139185 }
140186 base . OnNetworkSpawn ( ) ;
141187 }
@@ -165,17 +211,44 @@ private void OnEnabledChanged(bool previous, bool current)
165211 ApplyEnabled ( current ) ;
166212 }
167213
214+ /// <summary>
215+ /// Initializes each component entry to its initial state.
216+ /// </summary>
217+ private void InitializeComponents ( )
218+ {
219+ foreach ( var entry in m_ValidComponents )
220+ {
221+ // If invert enabled is true, then use the inverted value passed in.
222+ // Otherwise, directly apply the value passed in.
223+ var isEnabled = entry . InvertEnabled ? ! StartEnabled : StartEnabled ;
224+ entry . PropertyInfo . SetValue ( entry . Component , isEnabled ) ;
225+ }
226+ }
227+
228+ /// <summary>
229+ /// Applies states changes to all components being controlled by this instance.
230+ /// </summary>
231+ /// <param name="enabled">the state update to apply</param>
168232 private void ApplyEnabled ( bool enabled )
169233 {
170234 foreach ( var entry in m_ValidComponents )
171235 {
172- entry . Value . SetValue ( entry . Key , enabled ) ;
236+ // If invert enabled is true, then use the inverted value passed in.
237+ // Otherwise, directly apply the value passed in.
238+ var isEnabled = entry . InvertEnabled ? ! enabled : enabled ;
239+ entry . PropertyInfo . SetValue ( entry . Component , isEnabled ) ;
173240 }
174241 }
175242
176243 /// <summary>
177- /// Invoke on the authority side to enable or disable the <see cref="Object"/>s .
244+ /// Invoke on the authority side to enable or disable components assigned to this instance .
178245 /// </summary>
246+ /// <remarks>
247+ /// If any component entry has the <see cref="ComponentControllerEntry.InvertEnabled"/> set to true,
248+ /// then the inverse of the isEnabled property passed in will be used. If the component entry has the
249+ /// <see cref="ComponentControllerEntry.InvertEnabled"/> set to false (default), then the value of the
250+ /// isEnabled property will be applied.
251+ /// </remarks>
179252 /// <param name="isEnabled">true = enabled | false = disabled</param>
180253 public void SetEnabled ( bool isEnabled )
181254 {
0 commit comments