.asmdef) system lets you split a project into multiple compiled assemblies instead of one monolithic blob. SET: 3D Edition uses this to make Clean Architecture boundaries physical: if you try to reference a layer you’re not allowed to touch, the compiler refuses to build. You get a hard error at compile time — not a confusing runtime bug discovered two weeks later.
This page explains the seven assemblies planned for the project, the rules they encode, and how the Editor tooling enforces them automatically.
All seven assemblies described here are planned for the pre-production project layout. The folder structure and
.asmdef files are being established as foundational scaffolding before feature implementation begins.Why Assembly Definitions?
Without asmdefs, all scripts inAssets/ compile into a single assembly. Any class can reference any other class and Unity will happily let it happen. Clean Architecture becomes a convention that only survives peer pressure and code reviews.
With asmdefs, the dependency rules are enforced by the C# compiler itself:
- A class in
SET.Domainphysically cannot call intoSET.Application— the assembly reference simply does not exist, so the compiler never finds the type. - A class in
SET.Applicationphysically cannot callUnityEngine.GameObject— same reason. - Violations produce a compiler error, not a runtime exception. You find out immediately, on your own machine, before anything reaches a PR.
The Seven Assemblies
The Critical Rule: Presentation ≠ Infrastructure
SET.Presentation does not reference SET.Infrastructure. At all. No exceptions.
This is the single most important constraint in the assembly graph. It means MonoBehaviours and ViewModels can only call interfaces declared in SET.Application — they never know whether the implementation behind those interfaces is Nakama, a local stub, or a future cloud service.
Infrastructure implementations are bound at runtime by the VContainer composition root that lives in the Bootstrap scene. The Bootstrap scene is the only place in the entire codebase where a concrete infrastructure type is ever named. See Dependency Injection with VContainer for how this wiring works.
Dependency Graph
Solid arrows are compile-time references declared in the.asmdef file. The dashed arrow is a runtime-only binding performed by VContainer — SET.Presentation has zero compile-time knowledge of SET.Infrastructure.
What Lives in Each Assembly
Understanding which interfaces and types belong to which assembly is essential before adding new code. The table below lists the key planned types:Application-Layer Interface Surfaces
The following interfaces are declared inSET.Application and implemented in SET.Infrastructure or SET.Presentation. They represent the public API surface that crosses the assembly boundary at runtime via DI:
IMultiplayerService — Network adapter for Nakama realtime matches:
ConnectAsync(string matchId)— establishes the realtime socket connection to a matchSendClaim(int[] cardIds)— sends a SET claim to the authoritative serverMessages—IObservable<ServerMessage>stream of incoming server messagesDisconnect()— cleanly closes the socket and cleans up state
IInputHandler — Translates platform input into abstract game commands:
CommandStream—IObservable<IGameCommand>stream; downstream consumers never pollEnable()— activates input processing (called when the board becomes interactive)Disable()— suspends input processing during animations or locked states
ILeaderboardService — Leaderboard access via Nakama:
GetTopEntries(int count)— returns the top-N leaderboard entriesSubmitScore(long score)— submits the local player’s score after a match
ILocalSaveService — Persistent offline storage:
SaveAsync<T>(string key, T data)— serialises and writes data to local storageLoadAsync<T>(string key)— reads and deserialises data from local storage
IAudioService — Playback control for the audio system:
PlaySfx(string clipId)— plays a one-shot sound effectPlayMusic(string trackId)— starts looping background musicSetMusicVolume(float volume)— adjusts music volume (0–1)SetSfxVolume(float volume)— adjusts sound effects volume (0–1)
IViewPresenter — High-level screen presentation commands consumed by the Application layer:
ShowBoard()— transitions to and initialises the game board viewUpdateHud(GameStateSnapshot snapshot)— refreshes all HUD elements from the latest snapshotPlaySetAnimation(bool wasValid, int[] cardIds)— triggers the valid or invalid SET animationShowMatchResult(MatchResultData result)— presents the post-match result overlayShowToast(string message)— displays a transient toast notification
What an Asmdef File Looks Like
Each assembly is represented by a single.asmdef JSON file placed at the root of its folder. Here is the planned file for SET.Application:
The
SET.Editor asmdef additionally includes "includePlatforms": ["Editor"] so Unity strips it from any build that targets Android.
Editor Validation
The Editor validator script described here is planned (pre-production). The rule it enforces is active design intent, not yet automated.
SET.Editor will run at build time and scan every .cs file inside _Project/Domain/ and _Project/Application/. It looks for two banned using directives:
BuildFailedException and the build stops with a message identifying the exact file and line. This catches the case where a developer adds a quick Debug.Log to a Domain class and accidentally introduces a Unity dependency — an error that the asmdef itself won’t catch, because UnityEngine types are always available.
What Happens When You Violate a Boundary
If you add a reference that isn’t allowed — say you try to callNakamaMultiplayerService directly from a ViewModel in SET.Presentation — the compiler emits:
SET.Application.
Implementation Checklist
Use this checklist when adding a new assembly or adding code to an existing one:-
.asmdeffile created at the root of the layer folder with the correct"name"field -
"autoReferenced": falseon allSET.*assemblies -
"references"list contains only the assemblies this layer is permitted to depend on (see dependency graph above) - No
using UnityEngine;inSET.DomainorSET.Application - No
using Nakama;inSET.DomainorSET.Application -
SET.Presentationdoes not listSET.Infrastructurein its"references" -
SET.Editorincludes"includePlatforms": ["Editor"]to exclude it from Android builds - New interfaces that cross layer boundaries are declared in
SET.Application, not in the implementing assembly - Test assemblies reference only the assemblies required by the tests they contain
Common Mistakes
Putting Editor-only code in a non-Editor assembly. Anything that usesUnityEditor types (AssetDatabase, EditorGUILayout, etc.) must live in SET.Editor or a dedicated Editor subfolder with its own asmdef. If it ends up in SET.Presentation, the build for Android will fail with a missing type error.
Using a MonoBehaviour in Domain or Application. Even though UnityEngine.MonoBehaviour technically compiles without the full Unity editor, it drags in Unity lifecycle coupling. Pure C# classes in the inner layers should have normal constructors. The moment you find yourself making a Domain class inherit MonoBehaviour, something has gone wrong with the design.
Naming mismatches. The "name" field in a .asmdef must exactly match the string used in another assembly’s "references" array. A typo silently fails to create the reference — Unity won’t warn you; the type just won’t be found.
A Useful Mental Check
Whenever you are about to add a reference to an assembly’s"references" list, ask:
Does this reference point inward (toward Domain) or outward (toward Infrastructure/Presentation)?References must always point inward. If you find yourself needing
SET.Application to reference SET.Infrastructure, you have an abstraction in the wrong place. The interface for that behaviour belongs in SET.Application; only the concrete implementation belongs in SET.Infrastructure.
Related Pages
Clean Architecture Layers
The responsibilities of Domain, Application, Infrastructure, and Presentation explained in depth.
Dependency Injection with VContainer
How the Bootstrap composition root wires Infrastructure implementations to Application interfaces at runtime.
Project Overview
The big-picture system map showing all client and server components.
Engineering Standards & Patterns
The full pattern toolbox, banned anti-patterns, and code review checklists.