Consider refactoring InputManager, MixedRealityCameraParent, Cursor to reduce dependencies
See original GitHub issueCurrently scenes that have any of InputManager, MixedRealityCameraParent or a Cursor all have hard dependencies on the others.
If this is an absolute requirement, then the documentation should reflect this. Otherwise, this dependency chain along with Unity’s uncertain load and unload order creates extra complexity around scene load and unload as well as enabling and disabling objects, or having scenes that might not require one of the components.
MixedRealityCameraParent without an InputManager throws:
NullReferenceException: Object reference not set to an instance of an object
HoloToolkit.Unity.InputModule.SetGlobalListener.OnEnable () (at
Assets/HoloToolkit/Input/Scripts/Utilities/SetGlobalListener.cs:16)
InputManager without a cursor throws:
Couldn't find cursor for "InputManager.SimpleSinglePointerSelector". UnityEngine.Debug:LogErrorFormat(Object, String, Object[])
HoloToolkit.Unity.InputModule.SimpleSinglePointerSelector:FindCursorIfNeeded() (at Assets/HoloToolkit/Input/Scripts/Focus/SimpleSinglePointerSelector.cs:135)
HoloToolkit.Unity.InputModule.SimpleSinglePointerSelector:Start() (at Assets/HoloToolkit/Input/Scripts/Focus/SimpleSinglePointerSelector.cs:51)
DefaultCursor (I assume the other versions as well) without an InputManager throws:
NullReferenceException: Object reference not set to an instance of an object
HoloToolkit.Unity.InputModule.Cursor.RegisterManagers () (at Assets/HoloToolkit/Input/Scripts/Cursor/Cursor.cs:183)
HoloToolkit.Unity.InputModule.Cursor.Start () (at assets/HoloToolkit/Input/Scripts/Cursor/Cursor.cs:136)
NullReferenceException: Object reference not set to an instance of an object
HoloToolkit.Unity.InputModule.Cursor.UpdateCursorTransform () (at Assets/HoloToolkit/Input/Scripts/Cursor/Cursor.cs:289)
HoloToolkit.Unity.InputModule.Cursor.Update () (at Assets/HoloToolkit/Input/Scripts/Cursor/Cursor.cs:143)
I’m not sure of all the interconnections and implications for how to refactor these, but for example, the MixedRealityCameraParent’s SetGlobalListener OnEnable method requires an InputManager or it will throw a nullreference exception. Wrapping this in an if statement to check for null would remove the error but at the risk of the MixedRealityCameraParent never being added to the InputManager’s GlobalListener if an InputManager is later added to the scene.
In this case, you could have the InputManager check for the existence of a MixedRealityCameraParent in the scene and then add it if it has not already been added to the GlobalListener array.
Issue Analytics
- State:
- Created 6 years ago
- Reactions:2
- Comments:15 (15 by maintainers)
Top GitHub Comments
This looks perfect! But my question is, where did the
name
field come from that is used in yourDebug.LogError
message? And how did it get set to the string"MixedRealityCameraParent"
?Precisely. That would be ideal. But without doing a stack walk I don’t think that’s possible. Especially with a property. One of the reasons I was suggesting the IfInstance method above was to provide more information about the caller or the request. But again that might be overkill.
I believe @keveleigh may be proposing we add a
name
(orrequester
?) field to SetGlobalListner? If so that could help with the prefab issue because that field could be set as part of the MixedRealityCameraParent prefab. But that doesn’t help with the other two mentioned in this issue and I agree it would be much nicer to solve this in Singleton itself. I just don’t see a way to solve it through the .Instance property alone.It may be worth discussing at this point that what we’re really trying to solve for with the Singleton class is effectively Inversion of Control (or IoC). And here’s a great MSDN Article that compares IoC Containers and Singletons.
It’s probably overkill, but one possible solution would be to actually use an IoC Container. If we did, the Singleton base class would simply call
Container.Register
when it’s activated. As with other IoC systems, the Container would then be responsible for making sure there is only once instance (or named instance, etc.)Even if we didn’t opt for a full IoC container, we could still opt for using some of the patterns. For example, instead of a .Instance property we could opt for a .GetInstance method. This would allow .GetInstance to thrown an exception when the service is missing, and another method .GetInstanceOrDefault would work like the .Instance property does today. If these were methods instead of properties, we could also have optional string parameter(s) that describe the caller and / or use case. That information could then be propagated into any log or exception messages.
Anyway, just thinking out loud here again.
is totally possible!
leads to
My preference would be to find a way to do this in
Singleton
, though. This would be a very commonly reused bit of code, which is why we added the log inSingleton
when more than one instance was found. I’m not sure the best way to get the GameObject name in there though.Of course, if we’re going through and refactoring anyway, like this Issue asks, perhaps it wouldn’t be too bad to follow this pattern everywhere.