Skip to content

t1k:unity:tof:registration

FieldValue
Moduletof
Version2.2.2
Effortlow
Tools

Keywords: asmdef, di, feature integration, gamelifetimescope, link.xml, register, theonefeature, tof, vcontainer

/t1k:unity:tof:registration

Integrating a TheOneFeature module into a Unity consumer project requires updating three files in lockstep. Missing any one produces a silent failure mode (compile OK + runtime null, or IL2CPP strip on device).

FilePurposeFailure if skipped
Assets/Scripts/GameLifetimeScope.csusing + builder.Register<Feature>() call in Configure()DI container has no binding → runtime VContainerException / null injection
Assets/Scripts/Game.asmdefAdd the feature’s .DI assembly to referencesCompile error: namespace not found
Assets/Scripts/link.xml<assembly fullname="..." preserve="all"/>Works in Editor; IL2CPP strips on Android/iOS build → runtime crash on device only
// GameLifetimeScope.cs — top of file
using TheOne.Features.RaceEvent.Core.DI;
using TheOne.Features.PeriodRewardAds.DI;
// inside Configure(IContainerBuilder builder), in the feature-registration region
builder.RegisterRaceEvent();
builder.RegisterPeriodRewardAds();

Game.asmdef — append to the references array (asmdef is strict JSON, no comments allowed):

"TheOne.Features.RaceEvent.Core.DI",
"TheOne.Features.PeriodRewardAds.DI"
link.xml
<assembly fullname="TheOne.Features.RaceEvent" preserve="all"/>
<assembly fullname="TheOne.Features.PeriodRewardAds" preserve="all"/>
<assembly fullname="TheOne.Features.PeriodRewardAds.DI" preserve="all"/>
  • DI namespace: TheOne.Features.<FeatureName>[.Core].DI
  • Registration extension method: builder.Register<FeatureName>() — match the method exported by the DI assembly (browse package source if unsure)
  • link.xml preserves the runtime assembly (no .DI suffix) AND the .DI assembly when a .DI exists separately. When in doubt, preserve both.

Some features pull in UI/leaderboard companion assemblies that need their own preserves but no Register*() call. Examples:

  • PeriodRewardAds → also preserve TheOne.Features.Puzzle.UI.Donate.Period, TheOne.Features.Puzzle.UI.IAA, TheOne.UI.Common.PeriodUI.
  • Leaderboard.Core → also requires TheOne.Features.PlayFab.Core as an asmdef reference even though there’s no direct using (transitive type leak via configs).
  1. Compile in Editor — confirms asmdef edits.
  2. Search for [Inject] on the feature’s services to confirm the Register*() extension actually binds them.
  3. IL2CPP build on a device before declaring done — the only way to catch a missing link.xml entry. Editor and Mono builds will not surface the strip.

Append new builder.Register*() calls inside the existing feature-registration region (after the last Register*() call, before #endregion). Do not reorder existing registrations — VContainer resolves lazily, but registration order matters when one feature’s Configure* lambda references another feature’s binding.

  • asmdef is JSON, not JSON5 — no trailing commas, no comments. Many consumer Game.asmdef files have no trailing newline; preserve that to keep the diff minimal.
  • link.xml order does not matter, but group related preserves together for diff readability.
  • No service-locator fallback. TheOneFeature modules are pure DI — ProjectContext.Instance.Container.Resolve<T>() is forbidden by MainGame governance. All access must be via constructor [Inject].
  • Avoid RegisterX() outside the region. GameLifetimeScope has multiple #region blocks; new TOF registrations belong in the same block as the existing RegisterLocalization() / RegisterDefaultClaimRewardHandler() calls.