Mixedrealitytoolkit-unity: [Plan of Record] Improve MRTK ease of use: system facades, registrar interface, config ux

Created on 28 Feb 2019  Â·  113Comments  Â·  Source: microsoft/MixedRealityToolkit-Unity

Plan of Record: Support Service Specific Scene Presence

Microsoft Mixed Reality Toolkit v2

This document describes a design change for the Microsoft Mixed Reality Toolkit v2 concerning how developer customers can choose the MRTK and its services.

The Issue: Usability

The MRTK team has received feedback from multiple sources that the current, single object presence in the application scene is difficult to use with regards to feature discovery and modularization. Multiple customers, both internal and external, have requested an alternative to beta 2’s MixedRealityToolkit object in the form of system specific locator components (ex: MixedRealityInputLocator) that can be additively included.

One piece of feedback, heard from multiple sources, points out the promise of additive vs. subtractive consumption of MRTK. The comments largely center around two themes:

  1. It is not easy, at a glance, to see if a scene is using a specific MRTK service. Many developers from whom we heard desire an individual service presence in the scene hierarchy.
  2. The root Mixed Reality Toolkit configuration profile makes it appear that all services are present in the application, even when disabled. There is a strong desire for scoping the profile inspector to show only installed _and_ active services.

Solution: Enable Support for Individual Services to have Scene Presence

The solution defines the following changes:

  1. Provide service registration interfaces to enable customers to create a custom service locator and/or fully stand-alone service components
  2. Provide support for exposing active services and their configuration settings in the scene hierarchy _at edit time_ via service facades
  3. Enable customers to create hybrid application architectures, if desired, that use any number of service locators in conjunction with any number of stand-alone services
  4. Create a light-weight service registry that maps service interfaces with the concrete type that manages service registration
  5. An updated scene hierarchy to contain the service registry, service facades, etc
  6. Modified MRTK project configuration flow to provide enhanced flexibility for customers when setting up their projects

Please see the Solution Details section of this document for information the described changes.

Goals

  1. Respond to direct customer feedback
  2. Provide customers with a choice of how they consume MRTK services
  3. Minimize required client code changes
  4. Preserve as much of the MRTK service locator functionality as possible (anticipating 90% or greater equivalence)

Non-Goals

  1. Removal of the service locator pattern
  2. Require developers to change how they wish to work

Solution Details

Service Registration Interfaces

To enable developers to create custom service locators and/or extend an existing service locator to add support for MRTK services, a set of interfaces will be created to support the registration and retrieval of service instances.

It is anticipated that there will either be one or three interfaces that will be created. The following sections describe the pros and cons of each implementation.

Single Registrar Interface

In the single interface approach, the MRTK will define IMixedRealityServiceRegistrar. This interface would define explicit methods for supporting objects implementing the following service types (listed by interface):

  • IMixedRealityService
  • IMixedRealityExtensionService
  • IMixedRealityDataProvider

Each method (Register, Unregister, Get, CheckRegistration) will have a version that is type safe to the listed interfaces.

| Pros | Cons |
| ---- | ---- |
| Only one interface to implement | Implementors may be required to implement stub methods |
| Can provide a single base class supporting all service types | |

Multiple Registrar Interfaces

In the multiple interface design, each type of service would have a corresponding registrar interface:

  • IMixedRealityServiceRegistrar
  • IMixedRealityExtensionServiceRegistrar
  • IMixedRealityDataProviderRegistrar

This approach would allow customers to support _only_ the specific types of services necessary to build their component.

| Pros | Cons |
| ---- | ---- |
| Developers are free to implement only the required service type support | Potentially mutltiple interfaces to implement |
| Develipers do not have to implement stub methods | Cannot consume individual interface base class implementations (C# limitations)

Base Class Implementations

As with much of the MRTK, base classes will be provided to provide robust, reusable implementations of the registrar interface(s).

Providing the Registrar Instance to Services

When the registrar instantiates a service instance, it will provide itself as a constructor argument. The following example shows the parameter to be added to each service constructor.

``` C#
public ServiceClass(IMixedRealityRegistrar registrar, ...);

A similar pattern will occur for data providers.

When a service requests registration of a data provider, it calls RegisterDataProvider, handing a reference to itself.

``` C#
registrar.RegisterDataProvider<IMixedRealitySpatialObserver, IMixedRealitySpatialAwarenessSystem>(IMixedRealitySpatialAwarenessSystem system, Type observerType, ...);

The data provider's constructor is passed the provided reference in its constructor.

``` C#
public SpatialObserver(IMixedRealitySpatialAwarenessSystem system, ...);

## Service Facades

Service facades are an editor only monobehavior that exists in the application scene to give customers and easy, at-a-glance representation of the active services in the scene. When selected, the facade will display the service specific profile inspector and allow for easy configuration.

Backing these facades will be added to the scene and backed by the MRTK service locator. Developers not wishing these facades to be in their scene will be able to disable them in the MixedRealityToolkitConfiguration profile.

## Hybrid Application Architecture

Hybrid applications architecture is a term intended to describe an application which utilizes any number of service locators and/or stand-alone service implementations.

To support hybrid architectures, MRTK will add a [light-weight service registry](#service-registry) that enables client code easy access to concrete service implementations.

## Service Registry

The service registry in MRTK is an optional component that client code can use to acquire an instance of a desired service.

The registry can be thought of as a table that maps service interfaces to the object that manages the concrete implementation(s) .

The following table illustrates an example registry:

| Registrar | Interface |
| ---- | ---- |
| MixedRealityToolkitServiceLocator | IBoundarySystem |
| CustomServiceLocator | ISpatialAwarenessSystem |
| StandaloneInputSystem | IInputSystem |


The component managing the service registry can be attached to client script(s) or developers can choose to bypass the registry and hard-code references to the object managing service registration. 

For example:

``` C#
IServiceInterface service = MixedRealityToolkit.Instance.GetService<IServiceInterface>();

Scene Hierarchy

To help keep the scene hierarchy uncluttered, the default MRTK configuration process will create a Mixed Reality Toolkit parent object. This object will be the parent for the service locator and any enabled facades.

It is recommended that this object be the parent of objects created by registered services (ex: spatial awareness mesh objects).

The following image illustrates the default hierarchy when the MRTK service locator is used with the input and spatial awareness system facades enabled.

Hierarchy With Facades

Project Configuration UX

To make it easy and intuitive for customers to configure MRTK to suit their application's requirements, the Mixed Reality Toolkit menu's Configure item will display a selection dialog similar to the following illustration.

Configuration Dialog

3 - Working BREAKING CHANGE Feature Request

Most helpful comment

Just want to give a little extra context. This feedback is coming directly from partners building production HoloLens applications with MRTK.

In fact many Microsoft employees close to MRTK worked directly with them to educate and guide them. The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive. The feedback isn’t around POCO and decoupling services from MonoBehaviors.

We’re in beta, we’ve received legitimate feedback, we shouldn’t brush it off, we should figure out how to make MRTK work better. Education/documentation is only part of the solution.

All 113 comments

How do we know this docx doesn't contain a malware macro ;)

But seriously, could we get these in a better format that's readable from a browser window?

I can reformat to .md but it will take time

GitHub does not appear to support attaching .md files.... Sorry about the length of this comment.

Proposal: Support Individual Service Locators

Microsoft Mixed Reality Toolkit v2

This document describes a design change proposal for the Microsoft Mixed Reality Toolkit v2 concerning how developer customers consume the MRTK and its system services.

The Issue: Usability

The MRTK team has received feedback from multiple sources that the current, single object presence in the application scene is difficult to use with regards to feature discovery and modularization. Multiple customers, both internal and external, have requested an alternative to beta 2’s MixedRealityToolkit object in the form of system specific locator components (ex: MixedRealityInputLocator) that can be additively included.

One piece of feedback, heard from multiple sources, points out the promise of additive vs. subtractive consumption of MRTK. The comments largely center around two themes:

  1. It is not possible, at a glance, to see if a scene is using a specific MRTK system. Many developers from whom we heard desire an individual system presence in the scene hierarchy.
  2. The root Mixed Reality Toolkit configuration profile makes it appear that all systems are present in the application, even when disabled. There is a strong desire for scoping the profile inspector to show only installed _and_ active systems.

Proposed Solution

The proposed solution will provide support for both a single, global service locator component (MixedRealityToolkit) and for individual service locator components out of the box in MRTK.

This proposal will also enable developer customers to provide their own service locator implementations that can support custom functionality and/or support for a customized collection of pre-existing services.

Core Scene Component Refactor and Creation of System Serivce Locator Components

The proposal is to create a set of interfaces and base classes that that the MixedRealityToolkit object and other service locator objects can be built upon.

The MRTK would then provide additional service locators for:

• Camera
• Boundary
• Diagnostics
• Input
• Locomotion (aka Teleportation)
• Spatial Awareness

Configuration Profile UI Changes

As part of this work, the configuration profile inspectors will be updated to reduce the complexity and to enable “one stop” modification of settings.

This proposal does not mandate merging related profiles, nor does it eliminate profile specific inspectors.

Data Provider Registration

As of beta 2, all data providers are registered in the Additional Service Providers profile.

With this proposal, all data providers will be registered in the profile of the relevant system and loaded / managed by the user's selected service locator, which is potentially the service itself. The additional providers profile will be reserved for extension systems and services.

For example, the Windows Mixed Reality Device Manager and Open VR Device Manager components will be registered as data providers with the Input System locator.

Details

The following sections describe architectural details for this proposal. As the proposal is implemented, some details may change.

IMixedRealityServiceLocator

The IMixedRealityServiceLocator interface will define the core requirements for all service locator implementations.

Note: It is under consideration as to whether or not this interface will be subdivided by service type to allow some locator implementations to be simpler and to reduce the number of required methods.

Each locator is responsible for loading supported services. The global locator will continue to support loading all currently defined as well as customer created systems and services (implementing IMixedRealityService). The following APIs are the minimum set that will be required.

``` C#
///


/// Registers a service with the service locator.
///

/// The interface type of the service to be registered (ex: IMixedRealityBoundarySystem.
/// Instance of the service class.
/// True if the service was successfully registered, false otherwise.
bool RegisterService(
IMixedRealityService serviceInstance) where T : IMixedRealityService;
///
/// Registers a service with the service locator.
///

/// The interface type of the service to be registered (ex: IMixedRealityBoundarySystem).
/// The concrete type to instantiate.
/// The platform(s) on which the service is supported.
/// Optional arguments used when instantiating the concrete type.
/// True if the service was successfully registered, false otherwise.
bool RegisterService(
Type concreteType,
SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1),
params object[] args = null) where T : IMixedRealityService;
///
/// Unregisters a service from the service locator.
///

/// The name of the service to unregister.
/// True if the service was successfully unregistered, false otherwise.
bool UnregisterService(string name);
///
/// Unregisters a service from the service locator.
///

/// The interface type of the service to be unregistered (ex: IMixedRealityBoundarySystem).
/// The name of the service to unregister.
/// True if the service was successfully unregistered, false otherwise.
/// If the name argument is not specified, the first instance will be unregistered
bool UnregisterService(
string name = null) where T : IMixedRealityService;
///
/// Unregisters a service from the service locator.
///

/// The specific service instance to unregister.
/// True if the service was successfully unregistered, false otherwise.
bool UnregisterService(IMixedRealityService serviceInstance);
///
/// Unregisters all services from the service locator.
///

void UnregisterServices();
///
/// Unregisters all services from the service locator.
///

/// The interface type of the services to be unregistered (ex: IMixedRealityBoundarySystem).
void UnregisterServices() where T : IMixedRealityService;
///
/// Checks to see if a service has been registered with the service locator.
///

/// The name of the service.
/// True if the service is registered, false otherwise.
bool IsRegistered(string name);
///
/// Checks to see if a service has been registered with the service locator.
///

/// The interface type of the service (ex: IMixedRealityBoundarySystem).
/// The name of the service.
/// True if the service is registered, false otherwise.
bool IsRegistered(string name == null) where T : IMixedRealityService;
///
/// Gets the instance of the registered service.
///

/// The name of the service.
/// The registered service instance, as IMixedRealityService.
IMixedRealityService GetService(string name);
///
/// Gets the instance of the registered service.
///

/// The interface type of the service (ex: IMixedRealityBoundarySystem).
/// The name of the service.
/// The registered service instance as the requested type.
T GetService(string name) where T : IMixedRealityService;
///
/// Gets the collection of the registered service instances matching the requested type.
///

/// Read-only collection of the service instances, as IMixedRealityService.
IReadOnlyList GetServices();
///
/// Gets the collection of the registered service instances matching the requested type.
///

/// The interface type of the service (ex: IMixedRealityBoundarySystem).
/// Read-only collection of the service instances, as type requested type.
IReadOnlyList GetServices() where T : IMixedRealityService;

## IMixedRealityExtensionServicelocator

The IMixedRealityServicelocator can manage any service that implements IMixedRealityService and the IMixedRealityExtensionService is defined as extending this interface.

The IMixedRealityExtensionServicelocator interface is an optional interface that provides methods that can be implemented to limit management to implementations of IMixedRealityExtensionService.

``` C#
/// <summary>
/// Registers an extension service with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be registered.
/// <param name="serviceInstance">Instance of the service class.</param>
/// <returns>True if the service was successfully registered, false otherwise.</returns>
bool RegisterExtensionService<T>(
    IMixedRealityExtensionService serviceInstance) where T : IMixedRealityExtensionService;
/// <summary>
/// Registers an extension service with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be registered.
/// <returns>True if the service was successfully registered, false otherwise.</returns>
bool RegisterExtensionService<T>(
    Type concreteType, 
    SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1),     
    params object[] args = null) where T : IMixedRealityExtensionService;
/// <summary>
/// Unregisters an extension service from the service locator.
/// </summary>
/// <param name="name">The name of the service to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
bool UnregisterExtensionService(string name);
/// <summary>
/// Unregisters a service from the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service to be unregistered.
/// <param name="name">The name of the service to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
/// <remarks>If the name argument is not specified, the first instance will be unregistered</remarks>
bool UnregisterExtensionService<T>(string name == null) where T : IMixedRealityExtensionService;
/// <summary>
/// Unregisters an extension service from the service locator.
/// </summary>
/// <param name="service">The specific service instance to unregister.</param>
/// <returns>True if the service was successfully unregistered, false otherwise.</returns>
bool UnregisterExtensionService(IMixedRealityExtensionService serviceInstance);        
/// <summary>
/// Unregisters all extension services from the service locator.
/// </summary>
bool UnregisterExtensionServices();
/// <summary>
/// Unregisters all extension services from the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the services to be unregistered.
bool UnregisterExtensionServices<T>() where T: IMixedRealityExtensionService;
/// <summary>
/// Checks to see if an extension service has been registered with the service locator.
/// </summary>
/// <param name="name">The name of the service.</param>
/// <returns>True if the service is registered, false otherwise.</returns>
bool IsExtensionServiceRegistered(string name);
/// <summary>
/// Checks to see if an extension service has been registered with the service locator.
/// </summary>
/// <typeparam name="T">The interface type of the service.
/// <param name="name">The name of the service.</param>
/// <returns>True if the service is registered, false otherwise.</returns>
bool IsExtensionServiceRegistered<T>(string name == null) where T : IMixedRealityExtensionService;
/// <summary>
/// Gets the instance of the registered extension service.
/// </summary>
/// <param name="name">The name of the service.</param>
/// <returns>The registered service instance, as IMixedRealityExtensionService.</returns>
IMixedRealityExtensionService GetExtensionService(string name);
/// <summary>
/// Gets the instance of the registered extension service.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <param name="name">The name of the service.</param>
/// <returns>The registered service instance as the requested type.</returns>
T GetExtensionService<T>(string name) where T : IMixedRealityExtensionService;
/// <summary>
/// Gets the collection of the registered extension service instances matching the requested type.
/// </summary>
/// <returns>Read-only collection of the service instances, as IMixedRealityService.</returns>
IReadOnlyList<IMixedRealityExtensionService> GetExtensionServices();
/// <summary>
/// Gets the collection of the registered extension service instances matching the requested type.
/// </summary>
/// <typeparam name="T">The interface type of the service (ex: IMixedRealityBoundarySystem).
/// <returns>Read-only collection of the service instances, as tye requested type.</returns>
IReadOnlyList<T> GetExtensionServices<T>() where T: IMixedRealityExtensionService;

IMixedRealityDataProviderlocator

As with extension services, the IMixedRealityServicelocator can also manage data providers that implement the IMixedRealityDataProvider interface. Similarly, the IMixedRealityExtensionServicelocator supports management of IMixedRealityDataProvider implementations.

The IMixedRealityDataProviderlocator interface is an optional interface that provides methods that can be implemented to limit management to implementations of IMixedRealityDataProvider.

``` C#
///


/// Registers a data provider with the data provider locator.
///

/// The interface type of the data provider to be registered.
/// Instance of the data provider class.
/// True if the data provider was successfully registered, false otherwise.
bool RegisterDataProvider(
IMixedRealityDataProvider dataProviderInstance) where T : IMixedRealityDataProvider;
///
/// Registers a data provider with the data provider locator.
///

/// The interface type of the data provider to be registered.
/// True if the data provider was successfully registered, false otherwise.
bool RegisterDataProvider(
Type concreteType,
SupportedPlatforms supportedPlatforms = (SupportedPlatforms)(-1),
params object[] args = null) where T : IMixedRealityDataProvider;
///
/// Unregisters a data provider from the data provider locator.
///

/// The name of the data provider to unregister.
/// True if the data provider was successfully unregistered, false otherwise.
bool UnregisterDataProvider(string name);
///
/// Unregisters a data provider from the data provider locator.
///

/// The interface type of the data provider to be unregistered.
/// The name of the data provider to unregister.
/// True if the data provider was successfully unregistered, false otherwise.
/// If the name argument is not specified, the first instance will be unregistered
bool UnregisterDataProvider(string name == null) where T : IMixedRealityDataProvider;
///
/// Unregisters a data provider from the service locator.
///

/// The specific data provider instance to unregister.
/// True if the data provider was successfully unregistered, false otherwise.
bool UnregisterDataProviderService(IMixedRealityDataProvider dataProviderInstance);
///
/// Unregisters all data providers from the data provider locator.
///

bool UnregisterDataProviders();
///
/// Unregisters all data providers from the data provider locator.
///

/// The interface type of the data providers to be unregistered.
bool UnregisterDataProviders() where T: IMixedRealityDataProvider;
///
/// Checks to see if a data provider has been registered with the service locator.
///

/// The name of the data provider.
/// True if the data provider is registered, false otherwise.
bool IsDataProviderRegistered(string name);
///
/// Checks to see if a data provider has been registered with the service locator.
///

/// The interface type of the data provider.
/// The name of the data provider.
/// True if the data provider is registered, false otherwise.
bool IsDataProviderRegistered(string name == null) where T : IMixedRealityDataProvider;
///
/// Gets the instance of the registered data provider.
///

/// The name of the data provider.
/// The registered data provider instance, as IMixedRealityDataProvider.
IMixedRealityDataProvider GetDataProvider(string name);
///
/// Gets the instance of the registered data provider.
///

/// The interface type of the data provider.
/// The name of the data provider.
/// The registered data provider instance as the requested type.
T GetDataProvider(string name) where T : IMixedRealityDataProvider;
///
/// Gets the collection of the registered data provider instances matching the requested type.
/// /// Read-only collection of the data provider instances, as IMixedRealitydata provider.
IReadOnlyList GetDataProviders();
///
/// Gets the collection of the registered data provider instances matching the requested type.
///

/// The interface type of the data provider.
/// Read-only collection of the data provider instances, as tye requested type.
IReadOnlyList GetDataProviders() where T: IMixedRealityDataProvider;

## MixedRealityServicelocatorBase

The MixedRealityServicelocatorBase class will provide a default implementation of the IMixedRealityServicelocator interface and will be leveraged by MixedRealityExtensionServicelocatorBase and MixedRealityDataProviderlocatorBase.

Custom service locator implementations are encouraged to inherit from MixedRealityServicelocatorBase and customize behaviors as needed to avoid the need to implement duplicate code.

## MixedRealityExtensionServicelocatorBase

The MixedRealityExtensionServicelocatorBase class will use MixedRealityServicelocatorBase to handle core service management functionality and add a layer of type checking to ensure that all managed services implement IMixedRealityExtensionService.

## MixedRealityDataProviderlocatorBase

The MixedRealityDataProviderlocatorBase class will use MixedRealityServiceExtensionlocatorBase to handle core service management functionality and add a layer of type checking to ensure that all managed services implement IMixedRealityDataProvider.

## MixedRealityToolkit Class Refactor
As part of the interface and base class definition and implementation process, the MixedRealityToolkit class will be refactored with common and reusable code moving into the base class.

## System locators

locators for each of the systems listed previously will be created leveraging the base classes and interfaces. Not all system locators will require all features (ex: the Spatial Awareness system does not use a profile) and each will implement the minimum set of interfaces necessary.

## System Implementation Changes

As the systems will no longer be able to expect the concrete MixedRealityToolkit class to be managing them, the current system implementations will need to be updated. These changes will involve requesting data from the locator via interface contracts.

### Data Providers

With this proposal, each system will bear the responsibility for Unloading and managing registered data providers. The system implementations will call into the system locator to Unload, Unregister and request data about the registered data providers.

### Scene Presence

To better support a wide variety of developers and applications, while maintaining the goal if MRTK being minimally intrusive in the scene hierarchy, the scene presence will be modified to add a Mixed Reality Toolkit top level GameObject which will contain the MRTK’s system locator(s).

The following images illustrate the single, global locator and individual component locator options.

For customers wishing to use the current, global system locator, the hierarchy now nests the MixedRealityToolkit object in a parent of the same name (exact name TBD).

![Single, Global locator](https://raw.githubusercontent.com/Microsoft/MixedRealityToolkit-Unity/wikiFiles/ProposalFiles/3545/singlemanager.png)

Customers that prefer to explicitly add individual system locators will see each added under the MixedRealityToolkit parent object.

![Individual locators](https://raw.githubusercontent.com/Microsoft/MixedRealityToolkit-Unity/wikiFiles/ProposalFiles/3545/individualmanagers.png)

Each of the previous illustrations show the hierarchy that will appear when using the Mixed Reality Toolkit > Configure menu. Customers are free to manually modify / build the MRTK presence in their scene(s) manually if desired.

For reference, the scene hierarchy in beta 2 is shown in the following illustration.

![MRTK v2 Beta 2 locator](https://raw.githubusercontent.com/Microsoft/MixedRealityToolkit-Unity/wikiFiles/ProposalFiles/3545/beta2manager.png)

While the above is arguably somewhat cleaner, collapsing the new MixedRealityToolkit parent object presents a similar appearance. Additionally, adding a parent object allows for better containment of scene components added and managed by MRTK, for example spatial mesh objects.

## Configuration Menu

The Mixed Reality Toolkit menu’s Configure item will be expanded to support configuring for the global system locator or individual component locators. The following image illustrates early thinking of the configuration UI.

![Configuration Dialog Concept](https://raw.githubusercontent.com/Microsoft/MixedRealityToolkit-Unity/wikiFiles/ProposalFiles/3545/configdialog.png)

## Configuration Profiles

Existing system configuration profiles will continue to be used by the systems regardless of the chosen locator. It is expected that some minor modifications to the user interface / navigation may be required to best provide a delightful customer experience.

# Examples

The following sections describe examples of how locators and services will be discovered and referenced in code.

•   locator Access in Services
•   Service Discovery in Application Code
•   Data Provider Access in Application Code

## locator Access in Services

When a locator loads a service, the constructor will be passed an instance of IMixedRealityServicelocator to provide access to an equivalent of beta 2’s MixedRealityToolkit.Instance property.

## Data Provider Management

Through the IMixedRealityServicelocator instance, services will be able to request data provider management (register, unregister, etc.).
Service Discovery in Application Code

There are two proposals for providing service access to application code to replace beta 2’s direct MixedRealityToolkit calls. For example (ex: MixedRealityToolkit.Instance.InputSystem).

### Proposal 1: GetServicelocator<T>()

One possible solution is to provide a script that is attached to the MixedRealityToolkit parent object that iterates through the scene and builds a table of locator objects and which services the manage. This table would be created by locators registering themselves at startup. Application code would then request the appropriate locator for their service(s) of interest.

### Proposal 2: Script Registration of Service locator

Another proposed solution involves customers dragging the instance of the locator to a script in the inspector. 

The MixedRealityToolkit would provide a generic solution that can be used or extended by customer projects. This solution would provide a mapping of service interface to locator instance. For example:

| Service Interface | Service locator |
| ----------------- | --------------- |
|IMixedRealityBoundarySystem | MixedRealityBoundarySystemlocator |
|IMixedRealityInputSystem | ContosoInputSystemlocator |
|IMixedRealitySpatialAwarenessSystem | MixedRealityToolkit |
|IMixedRealityTeleportSystem | MixedRealityToolkit |

### Data Provider Access in Application Code

Access to data provider instances should be provided by the service which consumes the provider. This allows most application code to avoid needing knowledge of the locator and allows services to control when data providers are registered and unregistered.

The current (beta 2) Spatial Awareness system implementation demonstrates this pattern:

``` C#
/// <summary>
/// Gets the collection of registered <see cref="IMixedRealitySpatialAwarenessObserver"/> data providers.
/// </summary>
/// <returns>
/// Read only copy of the list of registered observers.
/// </returns>
IReadOnlyList<IMixedRealitySpatialAwarenessObserver> GetObservers();
/// <summary>
/// Get the collection of registered observers of the specified type.
/// </summary>
/// <typeparam name="T">The desired spatial awareness observer type (ex: <see cref="IMixedRealitySpatialAwarenessMeshObserver"/>)</typeparam>
/// <returns>
/// Readonly copy of the list of registered observers that implement the specified type.
/// </returns>
IReadOnlyList<T> GetObservers<T>() where T : IMixedRealitySpatialAwarenessObserver;
/// <summary>
/// Get the <see cref="IMixedRealitySpatialAwarenessObserver"/> that is registered under the specified name.
/// </summary>
/// <param name="name">The friendly name of the observer.</param>
/// <returns>
/// The requested observer, or null if one cannot be found.
/// </returns>
/// <remarks>
/// If more than one observer is registered under the specified name, the first will be returned.
/// </remarks>
IMixedRealitySpatialAwarenessObserver GetObserver(string name);
/// <summary>
/// Get the observer that is registered under the specified name matching the specified type.
/// </summary>
/// <typeparam name="T">The desired spatial awareness observer type (ex: <see cref="IMixedRealitySpatialAwarenessMeshObserver"/>)</typeparam>
/// <param name="name">The friendly name of the observer.</param>
/// <returns>
/// The requested observer, or null if one cannot be found.
/// </returns>
/// <remarks>
/// If more than one observer is registered under the specified name, the first will be returned.
/// </remarks>
T GetObserver<T>(string name) where T : IMixedRealitySpatialAwarenessObserver;

After calling one of the GetObserver methods, applications are able to modify properties and control the activity of the spatial awareness observers.

@davidkline-ms I am always causious when un-known text is used as identifiers for object recognition. Using the Friendly Name as an index into a list of objects can cause errors due to name collisions.

I would like to see if the usage of Namespaces can be impemented in the when registering and un-regestering services by name or type. This would allow for multiple implementations of a service to be alive but unique. For example having multiple controllers available to be used at the same time.

Scenario: When a student is running an application in WHMD or HoloLens an instructor may want to show the Student where to click or point them in a direction to assit in thier learning. The students could be using the Motion Controllers and the Instructor could be using an XBox One controller. Different Cursors and interaction can be defined for visuals.

i.e
bool RegisterService(string "name", string "nameSpace)
bool Un-RegisterService(string "name", string "nameSpace)

bool RegisterService\ bool Un-RegisterService\

bool RegisterService bool Un-RegisterService\

@hridpath, thanks for the feedback!

I think everyone is overthinking a lot of this stuff, and there's a focus on "Scene" objects, when the fact of the matter is, none of this stuff exists in the scene.

We're working with POCO objects. Classes and structures that should (in theory) be independent from Unity as much as possible. (Let's not even talk about how adding additional GameObjects that don't really do much of anything, could impact performance).

I think taking a bigger focus on educating people how to understand and use the system would help.

Yes, this new way of doing things is _very_ different to traditional unity developers, but I think it's counterproductive to give into the pressure of such feedback without attempting to educate people.

A bit nitpicky here with the terminology, but didn't we agree (months and months ago) that the term manager implied a single instance of something (and we ended up with system). Adding manager to the end of anything with System seems redundant, less descriptive, and more confusing.

Just want to give a little extra context. This feedback is coming directly from partners building production HoloLens applications with MRTK.

In fact many Microsoft employees close to MRTK worked directly with them to educate and guide them. The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive. The feedback isn’t around POCO and decoupling services from MonoBehaviors.

We’re in beta, we’ve received legitimate feedback, we shouldn’t brush it off, we should figure out how to make MRTK work better. Education/documentation is only part of the solution.

I'm a huge fan of the increased scene presence. This will help me teach the folks I work with about how MRTK works.

Big fan of this proposal. Directly addresses some of the loudest criticism / chatter I've been hearing from folks using the toolkit. I've been an advocate of the existing approach for a while but there's no shame in accepting that it didn't get the traction we'd hoped for. Like @radicalad says, we're in beta - now's the time.

@StephenHodgson agreed that educating people should be our goal - and the best way to teach someone about a new system is to present in familiar terms. Increased scene presence for services is a win regardless of (frankly minimal) perf costs. Nobody likes to be told their ignorance is the reason something is hard to use, and who can blame them?

@davidkline-ms This is just nitpicking but I do find the names hard to look at. I feel like there's got to be a better suffix than Manager - ServiceExecutor? ServiceLocator? ServiceHandler?

@davidkline-ms This is just nitpicking but I do find the names hard to look at. I feel like there's got to be a better suffix than Manager - ServiceExecutor? ServiceLocator? ServiceHandler?

While I can see that, the intent of these interfaces _is_ to manage (load, unload, enumerate, etc) services. I'll give the interface names / service controllers (would that work?) some thought and get consensus from others before submitting any code. Hopefully the proposal's use of "manager" doesn't distract from the goal.

Also, please note that the proposal does not include removing the current approach, just augmenting it with the ability to add a system specific scene presence as well as the ability for others to easily add support for MRTK systems in their own components.

@davidkline-ms Agreed, the names are not a dealbreaker.

The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive.

Could we elaborate on this? There isn't much substantial objective criteria here to formulate an appropriate response.

Nobody likes to be told their ignorance is the reason something is hard to use, and who can blame them?

đź’Ż% agree, and that wasn't exactly what I was trying to say, just that I think we should give people time to get familiar with it before deciding to fundamentally change the way it all works.

It'll be interesting to see how much workflows will continue change once Unity finishes up with ECS and DOTS. Traditional Unity development pipelines are going to be fundamentally changing a lot here in the near future.

Overall I think this is a step backwards, not forwards.

before deciding to fundamentally change the way it all works.

The existing MixedRealityToolkit object will remain an option. This is about providing options based on customer feedback.

The general feedback has been services and profiles are confusing, the system feels heavy and the MRTK Singleton is very aggressive.

Could we elaborate on this? There isn't much substantial objective criteria here to formulate an appropriate response.

I can very much elaborate on this one. We have an unwieldy and over-engineered set of nested profiles and a frustratingly restrictive architecture. Which basically leads to the inability for anyone to incorporate MRTK in an existing project. If I used it in a new project I would quickly run into an inflexible set of requirements that kill iteration times. In general quality in products is a function of evolutionary or iteration time steps. Ideally everything should be easily extensible and able to function as a standalone service in whatever structure a developer wants to incorporate it. Case study, use the toolkit with others at a game jam or hackathon and observe.

đź’Ż% agree, and that wasn't exactly what I was trying to say, just that I think we should give people time to get familiar with it before deciding to fundamentally change the way it all works.
It'll be interesting to see how much workflows will continue change once Unity finishes up with ECS and DOTS. Traditional Unity development pipelines are going to be fundamentally changing a lot here in the near future.
Overall I think this is a step backwards, not forwards.

I couldn't disagree more. The phrase "give people time to get familiar" is an indicator that it's not intuitive. It's like a level designer saying that someone is "playing it wrong" only because they designed it for their golden path. Regardless of Unity's structural changes and features, if you rely on what their "new" infrastructures are you will always be on some shaky ground until they are proven and solidified. The step to having more namespaces than the library of congress and one ring to rule them all was a larger step backwards IMO.

thanks,
-pat

@StephenHodgson If your predictions about Unity's workflow are true then maybe this is just a case of a system being slightly ahead of its time. In which case it would be best to wait for Unity to boil the frog a bit longer and revisit the issue when devs are more receptive. You can't surf a wave that's still underwater.

Option 2 adds a layer of complexity to satisfy design views of developers but doesn't degrade the overall functioning of the project.

Agreed, that's my biggest fear with this proposal.

The phrase "give people time to get familiar" is an indicator that it's not intuitive. It's like a level designer saying that someone is "playing it wrong" only because they designed it for their golden path.

Ouch, yup. You're absolutely right 🤣

One thing that I'd like to note with the service locator object, it that it's really just a manifest for all of the services that are running. It doesn't really do much of anything else, besides doing some scene setup with the event system, and camera.

I'm curious to know how this impacts everyone's thoughts on why it feels heavy handed and unweildy. The biggest problem it was trying to solve was ensuring that the object lifetimes were handled appropriately and MonoBehaviour events forwarded.

Ideally everything should be easily extensible and able to function as a standalone service in whatever structure a developer wants to incorporate it

The first part I believe to already be true, but if you could elaborate on the other structures?

Case study, use the toolkit with others at a game jam or hackathon and observe.

I wish I could have attended some, it would have been very interesting to see and learn from.

The mrtk was supposed to handle 90% of the needs, while letting the developer get that last 10%

For example:
You only have 48 hours, and you'd like to create an app that does x feature.

  1. Import the mrtk.
  2. Press configure
    > By this point everything should just work out of the box. No additional setup needed.
  3. Devs register their own custom service in the additional service provider profile, and iterate on that.
  4. Devs setup their scene and UI (can be done in parallel with 3)

Is there something above I missed?

I would like to see if the usage of Namespaces can be impemented in the when registering and un-regestering services by name or type. This would allow for multiple implementations of a service to be alive but unique.

Love this idea @hridpath

The TL;DR I'm for this proposal and anything that makes our "mangers" system more Unity-like and scene accessible.

I đź’Ż% agree for the need of system presence in the scene hierarchy. One of the reasons I believe Unity has become successful, especially among people new to game/3D development, is the accessibility of inspecting your app's state at runtime via the scene view. As it stands currently I can't really tell what state my systems are in and/or which ones are enabled without stepping though a debugger or plunging though profiles.

I also agree with @Railboy about

present in familiar terms.

A value I take into consideration when building new features in Unity is "_does something akin to this featue already exist, and how can I make my feature behave as similar as possible to the way it's currently done?_" When doing this you provided your users with familiarity and reduce friction when stepping into your new feature. The real win is when users can be productive right out of the gate because they have used a similar feature before.

Unity has become successful [because of] the accessibility of inspecting your app's state at runtime via the scene view. As it stands currently I can't really tell what state my systems are in and/or which ones are enabled without stepping though a debugger or plunging though profiles.

^ This

Having a visual representation of the currently running systems is good feedback, but I'm not entirely convinced that we should use the scene as a representation of said information. The scene is only for UX/UI. It's a single layer of the application that should be reactive to the business level app logic.

What about if we had another way to represent them without putting them in the scene? These services/managers don't exist in the scene in any way, nor should they (they're purely c#). I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

Let's call it the service graph

TL;DR the whole point of the re-architecture was to get away from the dependency of the MonoBehavour and the scene

These “Components” are intended to be attached to GameObjects which live in the project’s various scenes. However, this has the unfortunate side effect of making traditional patterns like MVC or MVVM impossible to use in the Unity development environment, out of the box. Instead, many developers closely couple application logic with the UI / UX logic — a practice frowned upon by many professional software engineers.

I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

That's missing the point. I'm a Unity dev, and I have an incredibly powerful debugging tool that's constantly maintained and improved by one of the most accomplished game engine development teams in the world. Let me use that tool. Don't make me go without. Don't make me use Visual Studio. Don't make me use a home brewed version of that tool that only exists in MRTK.

TL;DR the whole point of the re-architecture was to get away from the dependency of the MonoBehavour and the scene

I read that article when it came out. It felt like petting the cat backwards at the time, but I gave it a chance. I taught it to other people. I enforced it in code reviews. I wrote my own code to be in line with it.

I now believe we've pushed that philosophy too far. We have been "very aggressive" in pursuing it, as Addison said. Feedback from numerous projects has been clear. That principle cannot be our only guiding light.

A "service graph inspector" is an interesting idea. But, I agree with @Ecnassianer why should we reinvent something that is already robust and used by many? Purely C# managers/systems don't really fit into Unity's data driven design, but I do agree they should be separate from your normal app layer/state.

In the past I've done this by keeping managers in a separate scene. This is also Unity's general guidance at the bottom of this page.

What about if we had another way to represent them without putting them in the scene? These services/managers don't exist in the scene in any way, nor should they (they're purely c#). I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

Then your challenge is persuade us that the best response to feedback that the system is unfamiliar and unintuitive is to _avoid_ leveraging a familiar, intuitive system that already exists. And that we ought to then _duplicate_ parts of the existing system. And that this extra work and redundancy is necessary because representing pure C# objects as scene objects violates some kind of unstated aesthetic principle.

Not saying it's impossible but that's a tough sell.

Now last question @davidkline-ms , in judging this proposal do we push back the RC for the MRTK until this is ratified and implemented (along with other likely breaking changes needed to stabilise it) or are we planning this for a RC 1.1?

The RC timing includes time much of this work. It is something the team has been discussing options on for some time.

We are definitely planning additional release candidates before we v2.final to ensure quality, stability, customer feedback and educational materials..

The mrtk was supposed to handle 90% of the needs, while letting the developer get that last 10%

It does this very well for simple green field projects. What the team has learned in the past several months is that it is difficult to adapt MRTK to existing projects.

The intent here is to expand the usability and flexibility of MRTK to accommodate a wide range of projects and development styles.

Not saying it's impossible but that's a tough sell.

Indeed. Part of the problem was that it wasn't finished, nor ready for adoption, and undocumented. I know there was the pressure to have something for the HL2 launch, but I think maybe it was too much too fast.

I understand that it's a _completely_ new way of developing and it does take some time to adjust to. I too am a Unity developer, been using it for 15 years, and I've had some very frustrating and painful learning curves along the way. The pattern is essentially a culmination of all the things I've learned along the way, and an attempt to address those pitfalls I think the engine has.

Let me pose a few questions. Consider a "drag and drop" approach where the user just takes a prefab and puts it in the scene:

  • What if that service doesn't exist?
  • What if that service isn't fully initialized yet?
  • What if that service has to do very specific steps before adding content that uses it to the scene?
  • What if that service needs to spawn a specific prefab for a specific platform?

There are more scenarios that that maybe I didn't think about?


Here's a reply from other MVPs that were a thoughtful responses:
(I'm unable to reply to the email thread because of technical difficulties)

James:

I basically loathe the way people write Unity code. Coming from C# line-of-business development, it’s clearly a disaster. A lot of it is because of the heavy dependence on MonoBehaviour classes, which aren’t even spelled correctly, which are slow as molasses and screws up the whole object life cycle – but mostly it’s because Unity coders are horrible at writing reusable, resilient code. Unity has lots of built-in hooks to make everything accessible and it’s the wild west where all code has public accessors and anything can call anything at anytime. It’s a set of coding practices that invites abuse (actually, probably even requires it) and makes “clean code” principles almost impossible. Not to mention the horror of using coroutines instead of a nice async await pattern and calling it “threaded”. Or the prevalence of Singleton patterns that aren’t even implemented correctly. And a lot of these poor practices are ultimately built around all of these “Manager” classes that are faux singletons and accessible from anybody anywhere.

In C#, we have the notion of a service locator, which is an implementation of IoC that works well in Unity and happens to be the foundation of the new MRTK.

If you are used to having managers that you can drop into a scene in order to provide HoloLens functionality, then you may not like it as much.

But if you come from the C# app dev world and didn’t start in Unity thrown things at the wall and see what compiles and don’t worry about maintainability, then seeing traditional design patterns should come as a relief.

Dwight:

Coming from the same point of view as James, it appears in my experience that Managers are easier to use if you are a newbie to development. When teaching how to just build a MR application, there is demo code, POC/Pilot code – this is how you get it done type code, and then there is Reusable, patterns, production – secure, performant ready code. I find the later longer to develop, longer to explain, and basically for experienced developers who understand more than the game loop.

Being on a couple of projects similar to what James has expressed, I can attest to code in Unity almost infers or better yet implies Demo/POC code patterns because it’s quick, fast, compilable and easy to use, and the original MRTK was built with this in mind in my opinion. We were all learning it and it got us past Demo Code. Heck I would even say the HL was a demo product, where as HL v2 would be the true production, reliable, secure, performant product. So we must promote our learnings to production ready code now.

When explaining MR development to new developers, the steps were plop a manager in your scene, set some properties (without fully understanding them) and then watch everything work.

At the end of the day the pattern is meant to be production ready.

I'm open to making a window that looks very similar to the scene window, with a hierarchy that shows the relationships between services, and their data models.

While this is a cool idea, it would present another learning curve and an additional custom window that they are required to use.

this has the unfortunate side effect of making traditional patterns like MVC or MVVM impossible to use in the Unity development environment

It is the choice of the developer which patterns to use in a project. MRTK should be flexible and not limit a developer's choice of pattern.

Let's wind this back a little and ask the question :

what is it we are solving and what are we actually asking for?

As I'm seeing a lot of mixed metaphors used in this discussion.

From what I can see, we need:

Something which is highly performant at runtime, carving the best performance or of Unity and the .NET runtime (currently the existing architecture does this in spades ( Something I can easily inspect at design time and use familiar tools to debug / build with (which sadly the existing architecture hides due to it's focus on delivery)

Now we have to balance this with development vs runtime. In the lifetime of the project, it's going to get RUN a lot more than it's getting developed (although granted I know a lot of developers woud argue against this, but in that case you would need to ask why that is the case as it's not profitable)

So it becomes a means test against what can be introduced to assist in the design / develop cycle that doesn't impinge on the performance we've gained in the architecture.

This can be achieve by either:

  • Option 2 as above, enabling extension in the editor at design time
  • Having more "design time" features that can be easily disabled at build
  • A scene graph / design output that can easily be hooked in to the pipeline to enable quicker access to the critical things we need during the design/build cycle.

There can't be a one size fits all (although option two in my list) does come close. as any design requirements should no (and should never) impact or reduce the performance of a build solution (this one one of those core reasons we went with a new architecture to solve the problems introduced by the legacy behaviour of previous Unity developments, USING unity's own advice).

So can we simply FIRST break this down to a requirements discussion before jumping headlong in to the discussion around a solution. As I've not seen enough detail on what has been asked first.

Although David's proposal does look sound from the outside, we need to understand the drivers behind that solution so we can all agree on a final approach. WHAT do we need, vs what sounds like a good idea (which has hurt us a lot in the past).

To put in to frame David's point

It is the choice of the developer which patterns to use in a project. MRTK should be flexible and not limit a developer's choice of pattern.

But that choice should not impede the ultimate goal of the solution, the delivery of a perfomant and easy to use end solution. Not to say the developers story is any less important, but it is a impactful choice and requires a developers answer on top of an architecture that works in the long run.

Wouldn't shattering the service locator would essentially do the same thing?

This is not a shattering. The existing component will remain and behave the same way though some method names / signatures will likely change (ex: the name + namespace suggestion).

This is an additive change to enable developers who wish to have service specific scene objects and those who choose to add service support to existing objects.

@StephenHodgson has pointed out one thing, which makes sense.

It simple seems to be the ask to to make a DEVELOPER's life easier by adding another layer, which is fine. So long as in adding that we are not detracting away all the hard work to make the FINAL solution as fast as it can be

In the same way, Unity has now bent to C# as the best development solution but using IL2CPP to craft the final solution, MRTK is our current answer (in code form) for IL2CPP

So long as in adding that we are not detracting away all the hard work to make the FINAL solution as fast as it can be

There is no disagreement here. Developers will choose the strategy they wish to use based on ease of consumption and performance. Every project is different and requirements will vary.

The team has spent many many long hours profiling and tuning in the past several months and is very focused on performance.

@StephenHodgson @SimonDarksideJ As David mentioned, we have been intensively using MRTK vNext for various projects for the past several months, with both internal and external partners. I believe no one has used MRTK vNext this level in the product so far. The feedback and refactoring effort is coming as common voice from various teams and partners we've been working with who are also part of the external community. Just wanted to let you know this was not rushed conclusion or request from a few internal engineers. Definitely, the goal is to make MRTK vNext easy to use and best toolkit for MR development.

Personally, I just want a layered approach that lets me use as much or little as I want, and I'm fine with POCO being a layer. I don't want to have to use IMixedRealityExtensionServiceManager, or a super singleton with everything on it. I want it to be easy to consume just the input system (for example) and configure it (e.g. I can use just the input system related profiles independently, and there is no special initialization code from MixedRealityToolkit that I need to duplicate). If others want to use a higher level super-component that brings in everything and ties it all together to simplify their green field project, I have no opposition to that, I just want the ability to easily consume one MRTK component at a time in my existing app, and not bring in a bunch of stuff that I'm not ready to use.

I want it to be easy to consume just the input system (for example) and configure it (e.g. I can use just the input system related profiles independently, and there is no special initialization code from MixedRealityToolkit that I need to duplicate)

I'd argue that it's already possible to do this with any/all services. The service locator is just a way to manage the instances that are created.

For example, you could in theory, create a new instance of any service in any script.
Then manually call any of the public methods on them.

```C#
using Microsoft.MixedReality.Toolkit.Core.Interfaces.InputSystem;
using Microsoft.MixedReality.Toolkit.Services.InputSystem;
using UnityEngine;

public class ExampleIndependentService : MonoBehaviour
{
private IMixedRealityInputSystem InputSystem;

private void Awake()
{
    InputSystem = new MixedRealityInputSystem();
    InputSystem.Initialize();
}

private void OnEnable()
{
    InputSystem.Enable();
}

private void Update()
{
    InputSystem.Update();
}

private void OnDisable()
{
    InputSystem.Disable();
}

private void OnDestroy()
{
    InputSystem.Dispose();
}

}
```

For example, you could in theory, create a new instance of any service in any script.
Then manually call any of the public methods on them.

This sounds very much like what this proposal is looking to accomplish. The difference is that this is looking to provide scripts that automatically do the public method calls, etc, for each individual system, instead of pushing that work onto the developer.
The bulk of this proposal is about defining what that layer looks like, and proposing how systems can interact with that layer when there are more options than MixedRealityToolkit.Instance.

This sounds very much like what this proposal is looking to accomplish

Sounds like an anti-pattern. There's nothing there in the proposal that you couldn't already do, not to mention you'll lose the performance benefits, as well as organization, and ease of use from a programming perspective.

Currently, all systems make a direct call into MixedRealityToolkit.Instance to acquire profiles and load/unload/acquire data providers. Based on that, I believe the example above will not work as written.

This proposal is attempting to preserve centralization of service registration, etc and to keep the simple service implementation pattern that we currently have.

I don't want to have to use IMixedRealityExtensionServiceManager, or a super singleton with everything on it.

@ryantrem, do you see an issue with having a feature specific manager (ex: InputSytemManager)? Is there a desire for systems to manage their own data providers, for example?

ease of use from a programming perspective.

We have been hearing quite the opposite, that MRTK is not easy to use. The proposal aims to simplify usage while maintaining existing functionality for customers who wish to use current behavior.

Is there a desire for systems to manage their own data providers, for example?

That was part of the changes I was trying to get in wayyy back when.

Sounds like an anti-pattern. There's nothing there in the proposal that you couldn't already do

@StephenHodgson You seem to be forgetting that a) this is a lot of work, and b) a precondition of doing that work is more-or-less complete knowledge of the system.

Unless your input is meant to help us modify this proposal to better address the negative feedback we've gathered then I'm not sure how it helps us. We're trying to steer the conversation back to the real flesh-and-blood chorus of users offering this feedback. But you seem uninterested those developers, or maybe distrustful of their authenticity / credentials, and you keep steering it right back towards aesthetic principles.

I'm not saying that discussion is uninteresting. It's just not terribly useful. Maybe you can move it into a broader issue discussion?

But you seem uninterested those developers, or maybe distrustful of their authenticity / credentials, and you keep steering it right back towards aesthetic principles.

I'm sorry if it comes across this way. Not my intention at all. Part of any discussion or proposal like this is to consider many different perspectives of all parties involved.

Profiles are great for configuring things, but the initial configurations often don't match everyone's use case.

Improving the visibility to end users is worth substantial costs if we want our users to adopt this workflow.

It would be entirely reasonable to have the scene objects display inspectors that aid discoverability.

[Mixed Reality Toolkit Root Object]
--[Input System Representation]
----"This component exists to improve discovery and only forwards events. If you wish to change the behaviors of the Input system - [Button to Profile Configuration] or adjust [Name of a few related classes] or look into [Related Interface]"
--[Teleport System Representation]
etc.

As a developer, getting a breadcrumb like this would be hugely helpful and would help alleviate many of the common profile-related problems I encountered and other developers relying heavily on the profile system.
We can even have the component objects on each of the 'Hey this represents a system running in the background' objects be largely just documentation and inspector controls that guide developers to where they actually want to look to adjust functionality.

It's a far simpler solution than building an entire other system like the Inspector and expending resources to teach it.

getting a breadcrumb like this would be hugely helpful and would help alleviate many of the common profile-related problems I encountered and other developers relying heavily on the profile system.

Best bit of feedback I've heard. I agree, this could definitely be better. Exposing a field on each inspector with the associated service would be very helpful I think, but I'm still not sold about tying it into the scene hierarchy.

Not trying to detract from the conversation, but I felt like it was beneficial to share more feedback.

Tamas:

This is a really interesting discussion, one I have given a lot of thought in the last 2-2.5 years of using Unity. Just as James (and then many others) said, the world of many Unity apps/code is horrid to someone who comes from an enterprise world – me included. Again, just as James said – the Unity run lifecycle makes it very easy to jump in, but just as easy to write unmaintainable messes. I will admit that most of my projects starting out in Unity followed the “bigger the project, bigger the spaghetti” motto.

It took me until now-ish, to see how probably best to implement “our” best practices while not going completely head-to-head against the Unity ways of doing things. I’m currently working on a project/framework that encompasses my ideas, and I’ll be excited to show that to this community when it gets to a demoable and feels-complete state. These are the areas where I see place for improvement:

  • Scenes depend on many things (usually sadly “managers”), this hinders scene- and concern-separation efforts
  • Eventing is either Unity or C# but the two don’t mix well, and also the UI support for it is bad
  • Keeping track of things, components, dependencies is hard & requires tie-ins to the “bad” Unity lifecycle patterns
  • As soon as you do something in an enterprise-y way, Unity UI often stops being helpful (e.g. it’s not easy to keep private things private)
  • All the above makes it very hard to test and experiment on new things in an isolated way… often you can’t just create an empty scene for a new feature because it’ll depend on many things. I want this limitation to go away.

And these are the tools I’m planning to use to solve (or at least improve on) the above:

  • ScriptableObjects are awesome. Minimal tie-in to the Unity lifecycle, can be saved/seen/used project-wise
  • Custom predictable loops, abstract away the not-so-nice parts of the lifecycle (this btw can also have performance improving effects https://blogs.unity3d.com/2015/12/23/1k-update-calls/ )
  • Write tons of custom UI elements (inspectors, windows etc…) – make it as easy, or even easier to work with the custom things as it is with the built-in ones
  • Encourage concern/context separation with scenes – just as in Xaml we’d have App -> Frame -> Page -> etc… we can have Scenes that have the same responsibilities and act similarly
  • Use the newer versions of unity to embrace nameof(), async/await, pattern matching and similar nice features of C# that can help avoid ugly patterns in Unity

Well said, and I think this really hits home all the points we were trying to cover with the new architecture.

Thanks all, for the lively and illuminating discussion so far!

We will definitely update MRTK (regardless of the ultimate decision on this specific proposal) per @hridpath (name + namespace) as we currently have a far too easy opportunity for accidentally registering two services with exactly the same type and name.

The team is committed to reviewing all of the feedback received so far and applying ourselves to addressing / resolving to (hopefully) a good solution for all.

Can we also spend a bit of time on a couple of smaller pieces of the proposal that I have not heard feedback on yet...

  1. Proposed configuration dialog layout / options (please ignore, for now, the option on manager selection) specifically:
    a. Does it feel intuitive
    b. Does it help reinforce the additive qualities of MRTK

  2. Proposed MRTK parent object in the scene hierarchy.
    Note: One of the goals for this is to provide an easily collapsible node that would contain any objects created and added by MRTK, to allow developers to focus on the scene objects of most interest to them (at design and runtime).

Thanks for the continued, open feedback. It is beyond valuable.

Quick note: I'll be sure to post an FYI whenever the proposal contents change. It will be updated inline.

Thanks!

It would be entirely reasonable to have the scene objects display inspectors that aid discoverability.
[Mixed Reality Toolkit Root Object]
--[Input System Representation]
----"This component exists to improve discovery and only forwards events. If you wish to change the behaviors of the Input system - [Button to Profile Configuration] or adjust [Name of a few related classes] or look into [Related Interface]"
--[Teleport System Representation]
etc.

This is REALLY close to the intent of this proposal! The individual "managers" would provide access to the profiles.

Let's chat early next week and see how it lines up.

@StephenHodgson it doesn't seem like the example you gave above would work. As @davidkline-ms pointed out, the MixedRealityInputSystem has a bunch of accesses to MixedRealityToolkit.Instance (e.g. for the input system profile and the focus provider). I'd want to be able to have them as serialized fields on the standalone MonoBehaviour from your example, and pass these dependencies into the MixedRealityInputSystem. This is all I really mean when I'm asking for a more layered approach that allows me to use individual components and not need to use the whole MixedRealityToolKit mega component.

I really don't want to fork this discussion even more, but I keep seeing references to improved performance with the current approach. As far as I can tell, this is referring to having 1 MixedRealityToolKit component instead of ~6 individual MRTK related standalone system components within a scene that will typically have many hundreds of components.

it doesn't seem like the example you gave above would work.

Well I was giving a _very_ basic example, but I disagree, it could, in theory be done. Not with the current MixedRealityInputSystem implementation because, yes you're right there's calls to the service locator; but that's why we provided an interface for people to implement their own versions of said system/service. The default implementations of the services were implemented to work with the current architectural patterns.

But you're right, simply wrapping them wouldn't work.

Here's a really easy way to make services "additive" instead of "subtractive":

        [MenuItem("CONTEXT/BaseMixedRealityProfile/Create Copy from Profile Values", false, 0)]
        protected static async void CreateCopyProfileValues()
        {
            profileToCopy = profile;
            ScriptableObject newProfile = CreateInstance(profile.GetType().ToString());
            profile = newProfile.CreateAsset("Assets/MixedRealityToolkit.Generated/CustomProfiles") as BaseMixedRealityProfile;
            Debug.Assert(profile != null);

            await new WaitUntil(() => profileToCopy != profile);

            Selection.activeObject = null;
            PasteProfileValues();
            Selection.activeObject = profile;

            if (!profileToCopy.IsCustomProfile)
            {
                // For now we only replace it if it's the master configuration profile.
                // Sub-profiles are easy to update in the master configuration inspector.
                if (MixedRealityToolkit.Instance.ActiveProfile.GetType() == profile.GetType())
                {
                    MixedRealityToolkit.Instance.ActiveProfile = profile as MixedRealityToolkitConfigurationProfile;
                    MixedRealityToolkit.Instance.ActiveProfile.IsBoundarySystemEnabled = false;
                    MixedRealityToolkit.Instance.ActiveProfile.IsCameraProfileEnabled = false;
                    MixedRealityToolkit.Instance.ActiveProfile.IsDiagnosticsSystemEnabled = false;
                    MixedRealityToolkit.Instance.ActiveProfile.IsInputSystemEnabled = false;
                    MixedRealityToolkit.Instance.ActiveProfile.IsSpatialAwarenessSystemEnabled = false;
                    MixedRealityToolkit.Instance.ActiveProfile.IsTeleportSystemEnabled = false;

                }
            }
        }

Nice example, @jamesashley1. This will definitely help some customers.

When it comes to additive vs subtractive, one thing to note is that creating a new profile has everything disabled by default, where as copying a profile just makes a copy of whatever is enabled at the time.

FYI: Added Goals and Non-Goals sections to the existing issue description.

The proposal is in the process of being updated to replace "Manager" with "Locator". An FYI will be posted when that is completed.

FYI: Proposal updated to replace Manager with Locator. Please note some captialization issues may be present as the update was a quick Find|Replace. :)

We shouldn't need to change the base SDK to support that mode.

It is important to note that the proposal does not include removing any current components (i.e. MixedsRealityToolkit object). It formalizes a design that has been under discussion for some time now (providing support for custom service locator implementations) while adding individual locators for systems.

Any feedback from folks on the following?

  • MRTK parent in the hierarchy (default configuration, not required)
  • New configuration dialog

Thanks!

while adding individual locators for systems.

Why are we adding additional service locators? Wouldn't that add more complexity to the architecture, when the service locator is supposed to be the only one to begin with? (think of it as an application container)

This pattern uses a central registry known as the "service locator", which on request returns the information necessary to perform a certain task.

The application, not the component, should be the singleton. The application then makes an instance of the component available for any application-specific code to use.

Call it a locator, call it a Singleton, whatever you want. We're defining the functionality. This proposal aims to make standalone services locatable and accessible to a developer in a way that they choose and may be more familiar to them.
The point is defining and building specific MonoBehaviours that can configure and run individual services. Think of it as the MixedRealityToolkit class, but specifically for the InputSystem, the BoundarySystem, etc.
This way, a developer has the option of configuring their scene with individual GameObjects / MonoBehaviours, instead of just the one MRTK Service Locator. It's an added option, and the current method of having one single MRTK singleton to manage every service will still be an option.

Also I noticed that this proposal covers moving the data provider registry to the service, which I totally support doing, but this is already defined in another task/proposal.

Also I noticed that this proposal covers moving the data provider registry to the service, which I totally support doing, but this is already defined in another task/proposal.

That was added to the proposal for completeness. Thx!

Why are we adding additional service locators?

The intent is that service implementers would not have to implement support for loading and managing their data providers. It also creates a common object that can be used to quickly and easily change the specific system implementation.

That said, there is nothing preventing a service from implementing these interfaces (or not, if it doesn't need to load any additional services).

Following the pattern that has been established with service and system interfaces, the locator interfaces are defined as a contract that can be relied upon without need for knowledge of the specific implementation.

The point is defining and building specific MonoBehaviours that can configure and run individual services

The whole purpose of MRTK v2 architecture was to break the tyranny of the MonoBehaviour. Even Unity is working towards this end goal with ECS and DOTS (just to name a few).

  • Do we really want to continue teaching frowned upon practices to developers?
  • Do we want to introduce anti-patterns that undermine the recommended way we should be teaching them?

Think of it as the MixedRealityToolkit class, but specifically for the InputSystem, the BoundarySystem, etc.

Actually we should be thinking in terms of Interfaces and Contracts, which already support creating _implementations_ based on needs (see my concrete example above). Classes are _implementations_ of the contracts we setup. They can be implemented however the developer wants. If they wanna bind it to a monobehaviour _they already can_.

This proposal aims to make standalone services locatable and accessible to a developer in a way that they choose and may be more familiar to them.

The point is defining and building specific MonoBehaviours that can configure and run individual services.

What's so hard about calling MixedRealityToolkit.InputSystem from any script? Calling gameObject.GetComponent<InputSystem>() is arguably more expensive and falls back into the traps of race conditions and binding the application logic to the UI/UX presentation layer.

Arguably we started getting feedback before the whole thing was completed, without a solid SDK for people to utilize, and proper documentation. While yes, that early feedback is valuable, we also need to think about the root cause of the problem, and not treat the symptoms by simply covering it up with a fake layer of fluff (i.e. the GameObject references to things that shouldn't live in the presentation layer). This proposal sounds like someone got some feedback, then they came up with a solution for it, and proceeded to work their way backwards to the problem.

I understand it's a completely different workflow and that it's not immediately familiar to traditional Unity developers.

It's a culture shock, and I agree, maybe we should have had better teaching materials, and a solid SDK. It's like throwing someone from the 15th century into the modern era grocery store and asking them to pick up dinner. They have no clue where to begin! They're used to having to farm, and kill the cow, and butcher it all on their own. We shouldn't knock down the grocery store and plow a field for them just to help them adapt, but we should educate and ease them into the process of shopping, step by step.

One excellent solution to this was brought up by a someone for an article I plan on doing here in the future (that will hopefully make its way into documentation):

  • Have an example of the old version, and step by step, modernize it with the new architecture.
  • Show where the old things live, and where the new things live, and how they relate to each other in both applications with a diagram of the related parts.
  • It should be a journey of discovery and learning, pausing along the way to teach important lessons and clearly state the advantages of each decision.

We're not trying to uphold some "aesthetic principle", but instead an objective, concrete, testable architecture that will unlock the potential of creators to quickly create enterprise level applications.

Actually we should be thinking in terms of Interfaces

That is a large part of this proposal. The one place where MRTK does not have interfaces is the service locator.

From the way the discussions are going, I think we can agree this isn't something that should be a part of the foundation.
More likely this should be another extension for those wanting to only take parts of the MRTK and utilities to make that happen.

The discussion here, and threads I have received in email paints a different picture. Even if service specific locators are shipped as an extension, well known interfaces are necessary to enable consistent and reliable contracts for customer code to utilize.

to be used by those few who need only parts of the MRTK.

The purpose of modularizing MRTK is to enable developers to use only the portions of interest. In fact, the vast majority of the feedback we receive is related to use a subset of the feature set.

I agree we should support other patterns, but the foundation is a core to service the many and not the few.

That is what this proposal is about. Empowering as many developers as possible.

For the normal operation of the toolkit, the service locator doesn't have interfaces as it is never meant to be replaced like all the other components

đź’ŻThis couldn't be stated better. There's no reason to replace the service locator, and this one is specific to Unity. Now, if this was Unreal, or Monogame, then they'd likely have a different requirement for their respective engines. This repository is focused on Unity specifically. Let's not forget that.

The purpose of modularizing MRTK is to enable developers to use only the portions of interest.

They could already do that.

  • Each service can be individually enabled/disabled in the main configuration profile with the application container (aka: the service locator).
  • Each service could be ran individually by itself in its own sandbox so long as specific methods are driven by _something_ whether or not it's the service locator or monobehaviour game loop messages (But then you'd lose the complex system that emerges from the service locator).

That is what this proposal is about. Empowering as many developers as possible.

That should be the goal of the entire toolkit. Stating that it's what the proposal is about doesn't actually justify anything. It's a politically charged message that attempts to detract attention from the real discussion.

Each service could be ran individually by itself in its own sandbox so long as specific methods are driven by _something_ whether or not it's the service locator or monobehaviour game loop messages

That is this proposal. We will provide this ability without forcing our customers to have to write it.

I've taken a step back and reviewed your proposal @davidkline-ms and believe it is the best path to support the priorities you mentioned above. It appears the Service Locator pattern is simply not conducive to the way that these partners are building solutions and it's hampering the adoption of the MRTK.

To that end I've created a proposal to take this proposal to it's ultimate conclusion and cut out the service locator pattern from the MRTK as it doesn't fit with the way developers need to work.
https://github.com/Microsoft/MixedRealityToolkit-Unity/issues/3568

@davidkline-ms I still think that more detail is needed in this proposal around configuration menu usage when reconfiguring a project. I can imagine the following scenarios, and I think we should have a clear ux understanding of what will be possible/what users should avoid:

1) Developer has a global system manager and wants to convert a project to use a few individual system managers.
2) Developer has a few individual system managers and chooses to move to the global system manager
3) Developer has a few individual system managers and wants to add more individual system managers
4) Developer has a few individual system managers and would like to remove unused system managers

Do we know what will happen to a scene in going through these steps (i.e. What serialized fields do we expect to break in a scene)?
What is our undo story if you remove system managers through this ui (Is it at all possible to revert a reconfiguration)?
Are there any ui visual affordances that should be added so that users know they will be performing breaking changes (assuming a reconfiguration introduces breaking changes)?

nit: it looks like some of the provided images have also 404'd. Is it possible to get these fixed?

nit: Why is locator all lowercase in the interface/class names when its a new word?

Your point @chrisfromwork is why I'm most concerned about having a multitude of choice such as this in a single framework. Ultimately for any project you should have a single path and stick to it for the lifecycle of your project. There should never need to be a change, else it is likely to mess up your project completely.

Simply put as per David's proposal, the choice is only ever at the beginning and once chosen, you should not change.

My point is that if the project is giving advice for how to develop solutions, then there should only be one path. Choice in open source is to chose a different framework that works in a particular pattern.

That choice for MRTK, seems to lead to the Single GameObject pattern, leveraging the service approach built within the MRTK V2 but applying it in a way akin to the HoloToolkit that the enterprise developers are familiar with.

Offering such a drastic choice in the framework will only lead to misery. It would be like either mixing ECS and traditional unity development in a single project, or using both async and non async for the same work. The two methods are incompatible and miles apart.

nit: it looks like some of the provided images have also 404'd. Is it possible to get these fixed?

Fixed

nit: Why is locator all lowercase in the interface/class names when its a new word?

search replace mistake

There should never need to be a change, else it is likely to mess up your project completely.

I think that new releases of the MRTK will eventually lead all projects to require some amount of refactoring. I also feel like porting existing projects to the MRTK will always have the potential for encountering configuration related breaks based on MRTK system service behaviors/forced scene changes. In this individual services based architecture, hopefully all reconfigurations are additive, resulting in new behavior and no pre-existing logic breaks. But I could also imagine scenarios where an extension service is provided through this menu and may need to be removed (Enterprises may decide that an extension doesn't meet their quality/security bar after some prototyping/internal assessment). We should have the foresight to assess what support we can provide for these scenarios, even if we choose to do nothing. We should also try and understand whether its possible to undo any of these configuration changes. It may be that someone already assessed what was possible when setting up the configuration tool before? It may also be felt that source control (git commit histories) should be the only mechanism for undoing things?

In regards to this proposal, I feel that the fallout of reconfiguring a scene to use the MRTK/different systems is not well documented. It may be well understood by contributors, but I'd like the proposal to capture these potential pain points so we understand what we are asking of end developers. And I think we should have explicit call outs in documentation stating what may happen when going through configuration. And guidance for trying to make the process easier.

I think that new releases of the MRTK will eventually lead all projects to require some amount of refactoring

That is certainly true where projects adopt the new service locator pattern. Like ECS it's a fundamental change in how you build a unity project, for the better.

This document Stephen published did go over a lot of detail for how the Service locator pattern should work, attributing to MVVM standards for readability
https://docs.google.com/document/d/1B0BXCQq-Dn_xSmTUbHdWQ6aAx5K9IHmxq_E-OvV1AYc/edit?usp=sharing

In regards to configuration management, that's what the profiles are for, changes must be backwards compatible going forward, similarly, each service needs to be aware of it's dependencies and it's role in a project. However, this was core to the new approach to ensure that no one system is the MRTK, it's a sum of parts. SO that if you either want to replace or simply drop a system, the rest of the framework will carry on regardless without error.

the MRTK/different systems is not well documented

This is sadly true and both Stephen and I have to take a larger responsibility for that. As the original creators of this pattern for the MRTK, we did a fair amount of demo sessions and overviews with multiple teams, but we had little time to culminate proper documentation or guidance in the correct use and adoption of the framework. There were many reasons for this, mostly due to spending too much time building and not documenting as we go (although the code is highly documented in what it does, just now how to use)

I had started some documentation content in the documentation folder of this repo, however it became largely overlooked. Not because of anyone's fault, it just didn't make the front page. I also did a quickstart video and posted it, but didn't repeat that enough for the wider audience to appreciate (plus didn't have the time to dedicate to fully launch the channel due to working on the MRTK). More videos were planned but the project was in too much flux between beta's, which meant a lot of content would need to be repeatedly re-shot.

Now that the 2nd Beta is out and the framework is bedding in, I should have more time for more dedicated content to show people how to use it. Depending on which way this Proposal goes.

reopening since I closed this on accident when commenting

Great thread!

I'm currently going through the process of migrating a couple projects from HTK to MRTK. It is definitely confusing at first. The main frustration I am hitting right now is jumping between profiles as mentioned by others. I can easily go between a level or two deep into profiles by using 2 inspector windows and locking one but beyond two levels its very difficult to jump between things in the scene. The breadcrumb idea could solve that to some extent. I do miss the ease of having game objects in the scene to search for and click on. @StephenHodgson Do you know how is Unity handling viewing/editing what is in the scene in ECS?

I like the idea of moving away from Monobehavior due to ECS and DOTS, but would this scriptableObject setup be easily translated to ECS any easier than Monobehavior? @StephenHodgson Is there a clear path from scriptableObject to ECS? That would be the main reason in my mind for finding a way to make this current setup work.

I haven't used the toolkit enough to comment on how easy it will be to configure and extend. It seems like you could enable/disable whatever you need at first glance. So I can't speak to that goal of this proposal.

I don't like the idea of two different configurations but perhaps I am missing a key part of this proposal because I am a bit unclear on a few things:

  1. Are we getting rid of scriptableObjects profiles or not?

I see this:

The feedback isn’t around POCO and decoupling services from MonoBehaviors.

But also this:

We have an unwieldy and over-engineered set of nested profiles and a frustratingly restrictive architecture.

Are we just swapping top level profiles with GameObjects and keeping low level profiles? Or how are we adding game objects without removing profiles?

  1. Why do we need multiple locators? That seems like a messy solution to fixing the issue of wanting components to be standalone. Could we instead have the ability to define the interface being used as a property on the gameObject and if it is not there then look in the central locator?

  2. Why are we using strings to Register/GetServices? Wouldn't it be more optimized to store interface implementation by their type and then just call GetService(type)? That would also nix the need to pass namespace.

I'm sure I'm missing some things so I apologize if these thoughts/questions aren't helpful. I'll be sure to add more as I progress further and hit any bottlenecks.

I'm so glad you joined the conversation Mark, and these are all great thoughts and questions you've brought up.

I do miss the ease of having game objects in the scene to search for and click on.

I think people forget that you can navigate profiles (aka ScriptableObjects) in the project window with the same ease as the scene hierarchy (In fact I don't see this being any different).

Do you know how is Unity handling viewing/editing what is in the scene in ECS?

They've got specialized components that go on the GameObject to do fast lookups (similar to what we do with the interface handlers, but way more involved).

Is there a clear path from scriptableObject to ECS?

I'm pretty sure Unity is already defining this with their "data driven" approach, so yes the scriptable objects fit that criteria. As for the exact path? I'm not quite too sure about. Maybe some inside knowledge from Aras PranckeviÄŤius would help? Unity is really big with scriptable objects atm and I don't see that going away anytime soon. Essentially they're containers that help split the data from the core application logic.

Why are we using strings to Register/GetServices? Wouldn't it be more optimized to store interface implementation by their type and then just call GetService(type)? That would also nix the need to pass namespace.

In my fork, I actually only made it so you can only register by type, and got rid of the name altogether. (it was just a helper to find a unique instance anyway).

restrictive architecture

  • Could we better explain how it can be restrictive and in what ways would it feel more open?

nested profiles

Yeah this can def be much better, but I also don't think throwing them all into a massive inspector window helps much either.

Those were quotes from the thread. I was confused by some chatter saying profiles aren't being debated and others saying they are the problem.

Thanks for the feedback, @markgrossnickle! I called out your numbered questions and added some comments. Hope they help clarify things.

Are we getting rid of scriptableObjects profiles or not?

That is not the intent. Scriptable objects and profiles will still remain.

Why do we need multiple locators?

This was proposed to allow developer customers an easy way to swap service implementations (like they can with the current MixedRealityToolkit component without needing to reconfigure their profile settings. The multiple locators would exist as an option for developers who wish to have the service swapping capability yet see individual objects in the scene,

Why are we using strings to Register/GetServices? Wouldn't it be more optimized to store interface implementation by their type and then just call GetService(type)? That would also nix the need to pass namespace.

Strings were in the original class definition and allow developer customers to add a friendly name to an instance (mostly for the Additional Service Providers profile). Using Type objects is definitely a good suggestion and one we should consider standardizing around.

That brings up a good question: do we need service friendly names at all?

@davidkline-ms Thanks for the clarification!
If Profiles are not out, how will the in-scene gameObject representation of the profiles work? I thought the locator code shown above was going onto the profile ScriptableObjects? Where does the monobehavior locator code come into play and how does that easily tie into the profile code?

Understanding how the gameObjects will work with profiles may clear up multiple locators for me too. Keeping profiles but giving the ability to customize without reconfiguring profiles is a bit confusing.

I'd vote no on friendly names as they can be error prone and are slow for comparison (depending on implementation).

Great discussion! Might be getting a bit lengthy and needs separating into a few separate topics. However, my two cents. Like many here, I came into Unity from a non-Unity developer background. So I often like to do things the "non-Unity" way. However, that doesn't really meet the requirements of our target audience.

For the most part, heavy use of interfaces and dependency injection allow for most of the logic to be outside of Unity. While also allowing implementation inside of Unity for those that want to do it that way.

For example having an interface and base class inside of a non-Unity MRTK core, but still allowing an implementation inside of Unity.

interface IMyInterface {
string Name { get; }
void DoStuff();
}

class MyBaseClass : IMyInterface {
string _name;
string Name => _name;

void DoStuff() {
//Do some stuff
}
}

And in Unity, you can implement this with encapsulation of the base class:

class MyUnityClass : MonoBehaviour, IMyInterface
{
MyBaseClass baseClass = new MyBaseClass();
string Name => baseClass.Name;

void DoStuff() {
baseClass.DoStuff();
}
}

And of course, it allows purely Unity side implementation, which will be passed back down into the non-Unity "managers/systems" via dependency injection.

This is similar to Stephens example, but having the encapsulating class also implement the interface to ensure it doesn't miss any functionality.

Just chiming in to @markgrossnickle & @michael-house 's feedback, thanks for jumping in on the debate.

Are we getting rid of scriptableObjects profiles or not?

Scriptable objects are core to the service approach as they are the main configuration / data model for each service, as they provide a single instance of the runtime of the service that can be observed. It means we have standard classes to describe the data used in a service and manage it at runtime (where the service actively cooperates with its data)

Why are we using strings to Register/GetServices?

This was an enabler for developers to reuse the service locator for their own projects. Core services do not use name, only type because invariably there should only be one instance of a service.
But in a consumer project, the string name was added to allow a developer to register multiples of the same class and be able to identify a specific on by name. This was optional of course.

Meaning you could either:

  • Update all enemies of type IBigBadassEnemy
  • Destroy a specific enemy by name because the player took offence to them.

Why do we need multiple locators?

This is one point of contention I have with the proposal, and hence why I proposed the MRTK itself drop the locator pattern. Following standard architecture, there should only ever be ONE locator service within a project, a single place to find, register and recover the state of a service at any point in time.
Multiple locators breaks the base pattern of the locator / DI pattern. As you are either:

  • Looking for a service to work with
  • You already know the service you want to work with (which doesn't need locating)

Either you know or you don't and if you don't you wouldn't know which of the multitude of locators to ask the question of, unless you are going to have a locator of locators, which is just silly.

If as this proposal suggests, a service should be standalone linked to a GameObject, then you already have a located instance of that service in the scene and you would fall back to the traditional methods for selecting that service, as has been done in the HTK and Unity projects going back years. A "locator" would not improve this situation.

It's like saying in a single town you need multiple phone directories, one for each zip code. But if you don't know which zip code the number you want is in, then you would have to fall back to asking each and every one (e.g. GameObject.FindObjectofType), or have a separate master phone directories to know roughly which zip the number could be in (which ultimately is flawed as people move how and take their number with them)

but I am but one voice in the wilderness. But my simple point is you fall back to the Unity pattern (which is what has been asked for) or you use the locator, there is no middle ground without even more complex architecture. Plus what would be using these new locators?

And thanks for your Feedback @michael-house , that code pattern is exactly what we followed for the Service locator / DI style pattern used currently in the MRTK. Applying standards based approaches in a Unity way, allowing us to avoid the overuse of MonoBehaviours and turn the majority of services in to pure C#, which has a huge performance boost in a Unity project, in excess of 80% improvement

The shiproom call cleared up some things for me.

Agree all services should be able to be able to drag-and-drop and that the framework should be additive. I understand now the gameObjects are facades and I think that is a great solution for typical unity devs. Perhaps it could be toggled off for those who dislike the added gameObjects in the scene but overall I think most people will want it at first.

The only pushback I have is I want to avoid having to know which service components are registered to and I want to avoid coupling between services. Perhaps we can still do that with this proposal but I'm wondering if we can achieve everything above without the added complexity by automating the inclusion of a light weight locator in the scene whenever a service is added to the scene.

That could be annoying to some but if we change the locator to be light weight and additive I wouldn't think anyone would have a serious complaint. The locator at that point would have no hard coded values and just get/register interfaces and display a list of the added services in the inspector.

I feel the annoyance of that light weight locator being added to scenes automatically would be a lesser evil than the complexity added of multiple locators. But again, that's just my two cents and I realize I'm still new to this framework and am not privy to all of the feedback.

Great thread, I'll try to stop making it longer now that I understand it and said my piece. Cheers for the discussion!

This is one point of contention I have with the proposal, and hence why I proposed the MRTK itself drop the locator pattern. Following standard architecture, there should only ever be ONE locator service within a project, a single place to find, register and recover the state of a service at any point in time.

Agreed. The point of the locator is to act as an application container and keep everything in sync with each other. The conductor in the orchestra as it were. It also serves as your phone book to know how to call up your friends when you need to tag team a problem.

I understand the desire and feedback that other consumers of the toolkit have their own "service locator" type of application registry, but I still don't understand why they can't create their own implementations of services based on their service locator?

They are not going to be able to consume the services created _specifically_ for the toolkit. They will need to create implementations of those services that fit their requirements, and we enabled that with the contracts/interfaces. That's precisely what we meant when we described the architecture as being open. You take the service contracts and implement them to your specific needs. It's like saying that you want to take services written specifically in Unity and put them in Unreal. It's not going to work out of the box. There's dependencies in the implementation that require you to be dependant on certain things.

I don't think we should sacrifice the architecture to achieve something that's already possible to do.

Thanks for the well stated feedback, @markgrossnickle! The team will look into what it would take to have a light-weight locator (has been recently called a registry in internal conversations).

I believe we have a good feel for the various opinions as captured in this thread (and in email / direct communications). The proposal will be updated in the near future to reflect this feedback.

@davidkline-ms a few thoughts:

Proposal pros:

  • Devs are used to the traditional workflow of having objects/components/prefabs in the scene, and also this is how features are generally distributed on the Unity Asset Store
  • Devs like having control over their scenes, and what's included / what's not
  • This proposal provides a bridge and more palatable learning curve for HTK devs getting into MRTK 2. As devs get used to MRTK V2, they can start to appreciate the benefits of the new pattern and move in that direction.
  • Existing MRTK 2 pattern remains intact? Or at least all the effort devs have put into getting used to MRTK 2 will not be broken or changed with this proposal?

Proposal cons:

  • Good devs have intentions of trying to write apps in the most performant away they're aware of. It's unclear from the conversations above if your proposal will result in less performant code - but that's my interpretation of Simon's concerns and some other comments. Although devs might get some coding culture shock with the MRTK V2 being so different, we'd be also be sad if the compromise was less performant code/methods.

Question/proposal:
Is there a way we can use something similar to your selection UI/UX to just enable/disable features in the current MRTK profiles? Basically a UX to toggle stuff we already have in MRTK 2. And as others have suggested - we can also include an option to display facade gameobjects in the scene, representative of the MRTK features that are enabled. For example, a spatial awareness object in the scene. It would be optional, and purely to help devs get over MRTK 2 culture shock. It would be nice if those gameobjects had the ability to point to settings that devs can modify - for example being able to tweak spatial mapping settings during runtime - but unsure if that would introduce monobehaviours and break patterns. Just a few thoughts/ideas - not sure if they are founded or realistic.

Is there a way we can use something similar to your selection UI/UX to just enable/disable features in the current MRTK profiles

This was my alternate proposal some time back (which I sadly deleted for reasons unknown). Simply stating, that in order to give developers more access to the services in the scene, we can have SDK components that provide an editor shim that does not impact the overall operation of the framework.

I've asked this proposal to be split in to two, because there are two different requirements here, each requiring different solutions but as yet I've not had a response to that request.

Catching up on this thread. Sorry that my post is a bit tangential to the architectural disucssion. I think the proposed architecture is definitely the right direction we want to see MRTK move in based on feedback we have given. I'll work on some more actionable feedback on the architecture proposal :)

I think a design principle the MRTK should have is: "How can we create components that could easily be adopted by Unity".

A lot of what me and my team want out of MRTK are systems and abstraction that Unity doesn't currently provide, but should perhaps at one point. What I we want out of MRTK is:

  • A system that handles turning system input into Unity events
  • A system that abstracts spatial data
  • Platform abstraction
  • MRTK to work on top of Unity UI system, and enhance them to have functionality more like shell

I'd also like to address some misconceptions I've seen in this thread:
Some thoughts and a couple misconceptions I would like to point out that have been brought up:
Unity is abandoning MonoBehaviours
This just simply isn't true, it is not a deprecated feature. Yes they have ECS/DOTS, most existing codebases are not going to swap entirely from a GameObject MonoBehavior system to an ECS/DOTS system. I believe it is more likely that most Unity projects will have a hybrid of existing GameObject/Prefab model today with using the ECS for high performance work (but not all work..).

Additionally, if you look at any of the ECS samples, they use GameObjects and prefabs to layout elements in the scene and then at runtime convert the GameObjects into entites, which is a much better workflow.

Enterprise C# developers don't like Unity/think it's current behavior is bad. Everything is accessible by everything

I suppose at this point I am an enterprise C# developer, and I love working in Unity for a lot of the reasons mentioned above. We have in our codebase definitely had issues with over coupling system, but I believe asmdef's and architectural guidelines help solve that. Complaints I have heard from people who do not like Unity due to it's component nature usually just come from a world where everything is just raw code. I think it's just a matter of doing things differently. If MRTK is building an SDK for Unity, it should be Unity centric. I have found the most success in doing things the Unity way rather than fighting against it. If there is feedback about how they are doing things I think it is better to work with the Unity team to best identify patterns/issue areas.

MRTK should be handling 90% and the developers 10%
I find this absurd. It must be a very simple project if that is the case. MRTK has its purposes as
I listed above. It should be extending Unity to make it simpler to write code in the engine.

Thanks for your feedback @blgrossMS
On one point though

Unity is abandoning MonoBehaviours, This just simply isn't true, it is not a deprecated feature.

We're not saying Unity are deprecating MonoBehaviours. Just that MonoBehaviours are the children of evil powers and should be avoided if you can :D
ECS, Like XRTK's service structure are a way to move past MB's for the majority of operations that are not UI based.

MRTK should be handling 90% and the developers 10%
Agreed, this is a bit lofty, but that was the aim. We are far from it currently, mainly due to the lack of a Mature SDK. But the intent is to have the majority of the tools available that are used in the majority of projects ready off the shelf to reduce the needs for custom code. It's always the dream, but we're closer to 50/50 (or 40/60 tbh) currently.

Just a few additions

most existing codebases are not going to swap entirely from a GameObject MonoBehavior system to an ECS/DOTS system

Yup, and I think the MRTK is that middle stepping stone to get there. It helps ease developers into the workflow and thinking that they'll need for future projects that utilize them.

It should be extending Unity to make it simpler to write code in the engine.

Agreed, but what about those developers that aren't writing code? You'd be abandoning those creators that just want to focus on getting content made.

If MRTK is building an SDK for Unity, it should be Unity centric.

Agreed, and all presentation layer GameObjects would be. Infact, many people are forgetting that the entire event system is based on and extends the built-in features already.

The only thing the MRTK does is make that clear distinctions between Presentation layer and Core application layer. The SDK should entirely based on MonoBehaviors with interface event handlers.

Quick note: This proposal has been refined and will be updated shortly.

Thank you to everyone who provided feedback (here, on email, in a call, in person).

The following is the plan of record.

Plan of Record: Support Service Specific Scene Presence

Microsoft Mixed Reality Toolkit v2

This document describes a design change for the Microsoft Mixed Reality Toolkit v2 concerning how developer customers can choose the MRTK and its services.

The Issue: Usability

The MRTK team has received feedback from multiple sources that the current, single object presence in the application scene is difficult to use with regards to feature discovery and modularization. Multiple customers, both internal and external, have requested an alternative to beta 2’s MixedRealityToolkit object in the form of system specific locator components (ex: MixedRealityInputLocator) that can be additively included.

One piece of feedback, heard from multiple sources, points out the promise of additive vs. subtractive consumption of MRTK. The comments largely center around two themes:

  1. It is not easy, at a glance, to see if a scene is using a specific MRTK service. Many developers from whom we heard desire an individual service presence in the scene hierarchy.
  2. The root Mixed Reality Toolkit configuration profile makes it appear that all services are present in the application, even when disabled. There is a strong desire for scoping the profile inspector to show only installed _and_ active services.

Solution: Enable Support for Individual Services to have Scene Presence

The solution defines the following changes:

  1. Provide service registration interfaces to enable customers to create a custom service locator and/or fully stand-alone service components
  2. Provide support for exposing active services and their configuration settings in the scene hierarchy _at edit time_ via service facades
  3. Enable customers to create hybrid application architectures, if desired, that use any number of service locators in conjunction with any number of stand-alone services
  4. Create a light-weight service registry that maps service interfaces with the concrete type that manages service registration
  5. An updated scene hierarchy to contain the service registry, service facades, etc
  6. Modified MRTK project configuration flow to provide enhanced flexibility for customers when setting up their projects

Please see the Solution Details section of this document for information the described changes.

Goals

  1. Respond to direct customer feedback
  2. Provide customers with a choice of how they consume MRTK services
  3. Minimize required client code changes
  4. Preserve as much of the MRTK service locator functionality as possible (anticipating 90% or greater equivalence)

Non-Goals

  1. Removal of the service locator pattern
  2. Require developers to change how they wish to work

Solution Details

Service Registration Interfaces

To enable developers to create custom service locators and/or extend an existing service locator to add support for MRTK services, a set of interfaces will be created to support the registration and retrieval of service instances.

It is anticipated that there will either be one or three interfaces that will be created. The following sections describe the pros and cons of each implementation.

Single Registrar Interface

In the single interface approach, the MRTK will define IMixedRealityServiceRegistrar. This interface would define explicit methods for supporting objects implementing the following service types (listed by interface):

  • IMixedRealityService
  • IMixedRealityExtensionService
  • IMixedRealityDataProvider

Each method (Register, Unregister, Get, CheckRegistration) will have a version that is type safe to the listed interfaces.

| Pros | Cons |
| ---- | ---- |
| Only one interface to implement | Implementors may be required to implement stub methods |
| Can provide a single base class supporting all service types | |

Multiple Registrar Interfaces

In the multiple interface design, each type of service would have a corresponding registrar interface:

  • IMixedRealityServiceRegistrar
  • IMixedRealityExtensionServiceRegistrar
  • IMixedRealityDataProviderRegistrar

This approach would allow customers to support _only_ the specific types of services necessary to build their component.

| Pros | Cons |
| ---- | ---- |
| Developers are free to implement only the required service type support | Potentially mutltiple interfaces to implement |
| Develipers do not have to implement stub methods | Cannot consume individual interface base class implementations (C# limitations)

Base Class Implementations

As with much of the MRTK, base classes will be provided to provide robust, reusable implementations of the registrar interface(s).

Providing the Registrar Instance to Services

When the registrar instantiates a service instance, it will provide itself as a constructor argument. The following example shows the parameter to be added to each service constructor.

``` C#
public ServiceClass(IMixedRealityRegistrar registrar, ...);

A similar pattern will occur for data providers.

When a service requests registration of a data provider, it calls RegisterDataProvider, handing a reference to itself.

``` C#
registrar.RegisterDataProvider<IMixedRealitySpatialObserver, IMixedRealitySpatialAwarenessSystem>(IMixedRealitySpatialAwarenessSystem system, Type observerType, ...);

The data provider's constructor is passed the provided reference in its constructor.

``` C#
public SpatialObserver(IMixedRealitySpatialAwarenessSystem system, ...);

## Service Facades

Service facades are an editor only monobehavior that exists in the application scene to give customers and easy, at-a-glance representation of the active services in the scene. When selected, the facade will display the service specific profile inspector and allow for easy configuration.

Backing these facades will be added to the scene and backed by the MRTK service locator. Developers not wishing these facades to be in their scene will be able to disable them in the MixedRealityToolkitConfiguration profile.

## Hybrid Application Architecture

Hybrid applications architecture is a term intended to describe an application which utilizes any number of service locators and/or stand-alone service implementations.

To support hybrid architectures, MRTK will add a [light-weight service registry](#service-registry) that enables client code easy access to concrete service implementations.

## Service Registry

The service registry in MRTK is an optional component that client code can use to acquire an instance of a desired service.

The registry can be thought of as a table that maps service interfaces to the object that manages the concrete implementation(s) .

The following table illustrates an example registry:

| Registrar | Interface |
| ---- | ---- |
| MixedRealityToolkitServiceLocator | IBoundarySystem |
| CustomServiceLocator | ISpatialAwarenessSystem |
| StandaloneInputSystem | IInputSystem |


The component managing the service registry can be attached to client script(s) or developers can choose to bypass the registry and hard-code references to the object managing service registration. 

For example:

``` C#
IServiceInterface service = MixedRealityToolkit.Instance.GetService<IServiceInterface>();

Scene Hierarchy

To help keep the scene hierarchy uncluttered, the default MRTK configuration process will create a Mixed Reality Toolkit parent object. This object will be the parent for the service locator and any enabled facades.

It is recommended that this object be the parent of objects created by registered services (ex: spatial awareness mesh objects).

The following image illustrates the default hierarchy when the MRTK service locator is used with the input and spatial awareness system facades enabled.

Hierarchy With Facades

Project Configuration UX

To make it easy and intuitive for customers to configure MRTK to suit their application's requirements, the Mixed Reality Toolkit menu's Configure item will display a selection dialog similar to the following illustration.

Configuration Dialog

Ok, Sorry, but the proposal does not meet and far exceeds the "goal" of this request.

It simply states this proposal is to "Plan of Record: Support Service Specific Scene Presence"

However, this "proposal" still does to many things and in order to be successful should still be broken in to multiple parts.

It still contains two fundamental changes in the way MRTK operates:

  1. To enhance the scene management for developers to gain a better understanding of what is running in the scene (which is honest feedback and something the SDK should provide without changing the architecture)
  2. An improved ability to navigate configuration as key elements are too deep in the configuration hierarchy (which again is great feedback and likely will either need extensions to the configuration profiles or amendments to ease navigation, which still wouldn't need changes to the foundation, except maybe some editor inspector enhancements)
  3. Fundamentally changing and extending how services register their presence and enable standalone services to operate. This according to the proposal will enhance the foundation to support this workflow.

WE seriously cannot have a SINGLE task and expect it to fully detail the outcomes for each of these proposals. Seems we are beyond debate now and should just push ahead, so please setup three independent "Tasks" outlining each of the requirements and the proposal delivery mechanism for each. This "Request" is simply too large for any one change.

This plan will definitely be implemented in a series of smaller, focused PRs.

That sounds complicated. Will there be a default mode where I can just drag things into the scene and start using them? Or am I going to have to understand the details of this service registration architecture?

At this time, the default mode will be to use the configuration UX to select your desired services (they will appear as facades in the hierarchy). You will also be able to add/remove facades by enabling/disabling services in the MixedRealityToolkit component.

Drag/drop of individual features could be done. That would likely involve wrapping the desired service.

We can chat more on this if you would like.

Thanks for the explanation, David. I'm new to MRTK vNext. Sounds like I need to jump in to try it out and see how it goes!

Simply put @ForrestTrepte , today, you simply download the project, configure your scene and hit Run and everything should work.
Then it's a process of tailoring the MRTK to meet your projects needs. No need to learn the Locator architecture unless you want to build your own services.

Aim was a low barrier to entry as possible, but as @davidkline-ms points out, we do need to evolve the developer story to make it easier to transform the MRTK to meet your needs and understand what you're building.

If you haven't already, I recommend watching this short 10 minute video if you are just getting started -
https://www.youtube.com/watch?v=-ODnfcv5Rzg

In the end, these should be developer "add-ons" that don't impact the runtime performance boot the architecture gives you at run-time.

Will there be a default mode where I can just drag things into the scene and start using them?

@ForrestTrepte At the moment, you just have to import and press a single button to have everything "Just work". As for the UX/UI drag and drop stuff that's the primary goal of the SDK (that's not quite complete?). If you plan to implement your own UI/UX stuff then it'll be just implementing the appropriate interface handlers in your components.

Or am I going to have to understand the details of this service registration architecture?

Only if you want to implement your own systems/services which inherently _don't have scene representations_ because they're pure c# objects so no "drag and drop" there.

@ForrestTrepte, please feel free to reach out if you have any questions.

@davidkline-ms I assume you mean reach out on Teams or discuss in this proposal or comments on the guides, rather than in-person talking? Else how does the rest of the community also learn.

The plan outlined here is a step in the right direction. To see why this is a step in the right direction, and where it leads, I think it's helpful to have a shared understanding of the evolution of architectural constructs supporting dependency management, as that should clearly illustrate the path ahead for MRTK to fully resolve the issues potential MRTK consumers are facing. Here are the stages dependency management has moved through, in a nutshell:

  1. Global variables - an easy solution for components to get their hands on other components they depend on. A singleton is a type of global variable. The following problems with this construct became apparent:
  2. Tight coupling - dependencies are always resolved to specific concrete types.
  3. Lifetime management - component lifetimes are all scoped to the application.
  4. Order of initialization - manually resolving the correct initialization order based on dependencies in code is cumbersome.
  5. Hidden dependencies - you have to look at every line of code to fully discover all dependencies across components.
  6. Testability - it's hard to test code that has hard dependencies concrete types through globals.

  7. Service providers - introduced to address testability and hidden dependencies problems, with the basic contract including something along the lines of void RegisterService(Type serviceType, object serviceInstance) and object GetService(Type serviceType). In this model, the service provider instance is accessible to the components (perhaps as a constructor parameter), and the components use it to resolve their dependencies. Taken a step further, service providers allow service types to be registered instead of instances, e.g. void RegisterService(Type serviceType). This makes progress at also addressing lifetime management and order of initialization problems, but leaves the following problems:

  8. Dependencies are less hidden, but they are still not apparent from the contract of a component.
  9. Consumers of a component cannot use the component without also using the dependency management system (the service provider), as the "system" leaks into the "components" with this approach.

  10. Inversion of control - introduced to further address hidden dependencies problems, as well as fully decoupling components from the dependency management system. The defining characteristic here is that instead of components querying the service provider, they simply declare their dependencies, typically as constructor arguments, and instead of registering instances or raw types with the service provider, a factory function is registered. This typically looks something like: void RegisterService<TService>(Func<IServiceResolver, TService> serviceFactory), with usage looking something like this: serviceProvider.RegisterService<IFoo>(serviceResolver => new Foo(serviceResolver.Resolve<IBar>())). Now Foo is just a type that depends directly on an IBar. This solves the problem of components having knowledge of the dependency management system, and works with most programming languages, but leaves the following problems:

  11. Defining factory functions can be cumbersome, especially when the dependency graph is complex.
  12. Registering services declaratively is hard, since this is a very imperative approach typically requiring code.

  13. Dependency injection - at least in the .NET world, typically a defining characteristic of dependency injection is using reflection to automate the challenges of factory function based inversion of control. Dependencies are automatically discovered via reflection, and the underlying factory function can be programmatically generated. We're back to being able to simply do something like dependencyInjector.Register<Foo>() while at the same time being free to do new Foo(new Bar()). Now we finally have a flexible, easy to use dependency management system that is decoupled from the components being composed by the dependency management system. Components are easy to test, order of initialization/deinitialization is handled, and dependencies are discoverable at a glance.

Today, MRTK uses a combination of 1 and 2 (globals and service providers). @davidkline-ms's proposal makes a little progress in that it reduces the use of globals, and lets consumers define their own service provider implementation as an adapter to their existing dependency management system. I'd very much like to see MRTK move on to 3 or 4 (inversion of control/dependency injection), with the following caveat:

Dependency management is not a problem specific to mixed reality applications. As such, MRTK should not be trying to define a dependency management system (e.g. a service provider). MRTK should provide plain classes with dependencies passed in as constructor arguments. If we want a layer on top of that that provides the dependency management to simplify consumption, that's fine, but it should be an optional layer on top, and should just use an existing dependency injection solution. This is a solved problem, and the solutions out there (like autofac) solve this problem better than MRTK will, as it is the sole purpose of these libraries.

I assume you mean reach out on Teams or …

Any discussion, internal or otherwise will have the result posted on Teams / Slack / GitHub / etc. for all to see. This is part of the transparency philosophy the project is using for proposals, like this one.

Thanks!

This is a solved problem

If that were true, I don't think we'd be having this conversation.

As such, MRTK should not be trying to define a dependency management system

So do you agree that https://github.com/Microsoft/MixedRealityToolkit-Unity/issues/3568 is a better proposal to achieve this desired goal?

Closing as the infrastructure work is complete. Prefabs for standalone service usage are to be added in an experimental namespace in the SDK.

Configuration UX will be addressed via a separate set of work.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

amfdeluca picture amfdeluca  Â·  3Comments

nuernber picture nuernber  Â·  3Comments

provencher picture provencher  Â·  3Comments

reillydonovan picture reillydonovan  Â·  3Comments

dustin2711 picture dustin2711  Â·  3Comments