@aqian0/dsh-unity 0.0.0-stage → 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (360) hide show
  1. package/CHANGELOG.md +53 -0
  2. package/LICENSE-UNITY-COMPANION.md +122 -0
  3. package/LICENSE.md +31 -0
  4. package/NOTICE.md +90 -0
  5. package/README.md +273 -2
  6. package/cordis.patch.yml +22 -0
  7. package/docs/design.md +297 -0
  8. package/icon.svg +16 -0
  9. package/lib/frontmatter.js +392 -0
  10. package/lib/gating.js +105 -0
  11. package/lib/harness.js +16 -0
  12. package/lib/index.js +171 -0
  13. package/lib/project.js +210 -0
  14. package/lib/registry.js +268 -0
  15. package/lib/requirements.js +214 -0
  16. package/lib/skills.js +191 -0
  17. package/lib/types/frontmatter.d.ts +84 -0
  18. package/lib/types/gating.d.ts +80 -0
  19. package/lib/types/harness.d.ts +152 -0
  20. package/lib/types/index.d.ts +75 -0
  21. package/lib/types/project.d.ts +93 -0
  22. package/lib/types/registry.d.ts +96 -0
  23. package/lib/types/requirements.d.ts +67 -0
  24. package/lib/types/skills.d.ts +54 -0
  25. package/lib/types/watch.d.ts +34 -0
  26. package/lib/watch.js +84 -0
  27. package/locale/en.json +6 -0
  28. package/locale/zh.json +6 -0
  29. package/package.json +70 -4
  30. package/skills/2d-pixel-perfect/SKILL.md +208 -0
  31. package/skills/2d-pixel-perfect/references/api-reference.md +81 -0
  32. package/skills/2d-pixel-perfect/references/camera-setup-builtin.cs +40 -0
  33. package/skills/2d-pixel-perfect/references/camera-setup-urp.cs +49 -0
  34. package/skills/2d-pixel-perfect/references/pipeline-detection.cs +50 -0
  35. package/skills/2d-pixel-perfect/references/sprite-settings.cs +37 -0
  36. package/skills/asset-transformer-toolkit/SECURITY.md +15 -0
  37. package/skills/asset-transformer-toolkit/SKILL.md +39 -0
  38. package/skills/asset-transformer-toolkit/references/create-importer.md +121 -0
  39. package/skills/asset-transformer-toolkit/references/lods.md +61 -0
  40. package/skills/asset-transformer-toolkit/references/rule-api.md +154 -0
  41. package/skills/asset-transformer-toolkit/references/ruleblock-api.md +37 -0
  42. package/skills/asset-transformer-toolkit/references/ruleset-api.md +138 -0
  43. package/skills/asset-transformer-toolkit/references/rulesets-and-actions.md +227 -0
  44. package/skills/audio-setup-mixers/SECURITY.md +16 -0
  45. package/skills/audio-setup-mixers/SKILL.md +127 -0
  46. package/skills/audio-setup-mixers/references/api.md +162 -0
  47. package/skills/build-gtk/SECURITY.md +16 -0
  48. package/skills/build-gtk/SKILL.md +200 -0
  49. package/skills/build-gtk/references/api-reference.md +33 -0
  50. package/skills/build-gtk/references/graph-api-gaps.md +96 -0
  51. package/skills/build-gtk/references/runtime-and-visualization.md +191 -0
  52. package/skills/build-gtk/references/state-machine-api.md +270 -0
  53. package/skills/build-gtk/references/where-the-docs-stop.md +49 -0
  54. package/skills/build-live-game/SKILL.md +159 -0
  55. package/skills/build-live-game/references/achievements.md +757 -0
  56. package/skills/build-live-game/references/apis.md +271 -0
  57. package/skills/build-live-game/references/authentication.md +431 -0
  58. package/skills/build-live-game/references/battlepass.md +904 -0
  59. package/skills/build-live-game/references/blueprints-and-samples.md +75 -0
  60. package/skills/build-live-game/references/cloud-code-cloudbehaviours.md +1111 -0
  61. package/skills/build-live-game/references/cloud-code-modules.md +1276 -0
  62. package/skills/build-live-game/references/cloud-code.md +58 -0
  63. package/skills/build-live-game/references/cloud-save.md +464 -0
  64. package/skills/build-live-game/references/deployment.md +231 -0
  65. package/skills/build-live-game/references/orientation.md +30 -0
  66. package/skills/build-live-game/references/player-account.md +821 -0
  67. package/skills/build-live-game/references/remote-config.md +96 -0
  68. package/skills/build-live-game/references/services-overview.md +76 -0
  69. package/skills/build-live-game/references/tooling.md +375 -0
  70. package/skills/build-live-game/references/ugs-cli.md +86 -0
  71. package/skills/craft-game-floors/SECURITY.md +23 -0
  72. package/skills/craft-game-floors/SKILL.md +134 -0
  73. package/skills/craft-game-floors/references/art-direction.md +85 -0
  74. package/skills/craft-game-floors/references/camera-rigs.md +51 -0
  75. package/skills/craft-game-floors/references/character-motion.md +35 -0
  76. package/skills/craft-game-floors/references/game-audio.md +47 -0
  77. package/skills/craft-game-floors/references/game-feel.md +68 -0
  78. package/skills/craft-game-floors/references/game-shell.md +45 -0
  79. package/skills/craft-game-floors/references/live-floor.md +35 -0
  80. package/skills/craft-game-floors/references/placeholder-assets.md +35 -0
  81. package/skills/craft-game-floors/references/scene-lighting.md +52 -0
  82. package/skills/craft-game-floors/references/toon-shading.md +34 -0
  83. package/skills/craft-game-floors/references/vfx.md +40 -0
  84. package/skills/craft-game-floors/references/visual-scorecard.md +43 -0
  85. package/skills/create-2d-physics/SECURITY.md +16 -0
  86. package/skills/create-2d-physics/SKILL.md +128 -0
  87. package/skills/create-2d-physics/references/2d-physics-core.md +155 -0
  88. package/skills/create-2d-physics/references/legacy-2d-physics.md +45 -0
  89. package/skills/create-tile-palette-or-rule-tiles/SKILL.md +95 -0
  90. package/skills/create-tile-palette-or-rule-tiles/references/hexagonalruletile.md +71 -0
  91. package/skills/create-tile-palette-or-rule-tiles/references/palette-create.md +38 -0
  92. package/skills/create-tile-palette-or-rule-tiles/references/ruletile-createempty.md +37 -0
  93. package/skills/create-tile-palette-or-rule-tiles/references/ruletile-createfromsegment.md +219 -0
  94. package/skills/create-tile-palette-or-rule-tiles/references/ruletile.md +95 -0
  95. package/skills/create-tile-palette-or-rule-tiles/scripts/CreatePaletteTemplate.cs +148 -0
  96. package/skills/create-tile-palette-or-rule-tiles/scripts/ManualWorkflowExample.cs +63 -0
  97. package/skills/create-tile-palette-or-rule-tiles/scripts/RuleTileGenerator.cs +61 -0
  98. package/skills/create-tile-palette-or-rule-tiles/scripts/TilemapRuleTileCreateFromSegment.cs +225 -0
  99. package/skills/fix-3d-physics-collisions/SECURITY.md +17 -0
  100. package/skills/fix-3d-physics-collisions/SKILL.md +139 -0
  101. package/skills/fix-3d-physics-collisions/references/collision-checklist.md +80 -0
  102. package/skills/fix-3d-physics-collisions/references/collision-debugger.md +18 -0
  103. package/skills/fix-3d-physics-collisions/references/console-errors-table.md +9 -0
  104. package/skills/fix-3d-physics-collisions/references/kinematic-trigger-facts.md +18 -0
  105. package/skills/fix-3d-physics-collisions/references/other-symptoms.md +29 -0
  106. package/skills/fix-3d-physics-collisions/references/raycast-checklist.md +8 -0
  107. package/skills/fix-3d-physics-collisions/references/topic-map.md +42 -0
  108. package/skills/fix-3d-physics-collisions/references/trigger-checklist.md +9 -0
  109. package/skills/fix-3d-physics-collisions/scripts/CollisionDebugger.cs +561 -0
  110. package/skills/generate-editor-search-query/SECURITY.md +17 -0
  111. package/skills/generate-editor-search-query/SKILL.md +117 -0
  112. package/skills/generate-editor-search-query/references/open-search-window.md +70 -0
  113. package/skills/generate-editor-search-query/references/query-patterns.md +124 -0
  114. package/skills/implement-in-app-purchases/SKILL.md +82 -0
  115. package/skills/implement-in-app-purchases/references/api-details.md +41 -0
  116. package/skills/implement-in-app-purchases/references/api-notes.md +105 -0
  117. package/skills/implement-in-app-purchases/references/codeless-catalog.md +197 -0
  118. package/skills/implement-in-app-purchases/references/convert-adapty.md +270 -0
  119. package/skills/implement-in-app-purchases/references/convert-essentialkit.md +239 -0
  120. package/skills/implement-in-app-purchases/references/convert-revenuecat.md +277 -0
  121. package/skills/implement-in-app-purchases/references/convert-unipay.md +145 -0
  122. package/skills/implement-in-app-purchases/references/migration-v4-to-v5.md +46 -0
  123. package/skills/implement-in-app-purchases/references/path-add-iap-to-new-project.md +197 -0
  124. package/skills/implement-in-app-purchases/references/path-convert-native-google-billing.md +302 -0
  125. package/skills/implement-in-app-purchases/references/path-convert-native-storekit.md +357 -0
  126. package/skills/implement-in-app-purchases/references/path-implement-iap-d2c.md +253 -0
  127. package/skills/implement-in-app-purchases/references/platform-notes.md +55 -0
  128. package/skills/implement-in-app-purchases/references/pre-check.md +207 -0
  129. package/skills/implement-in-app-purchases/references/topic-map.md +46 -0
  130. package/skills/initialize-ai-navigation/SKILL.md +109 -0
  131. package/skills/initialize-ai-navigation/references/navigation-system.md +793 -0
  132. package/skills/initialize-ai-navigation/references/topic-map.md +66 -0
  133. package/skills/levelplay-unity-integration/SKILL.md +122 -0
  134. package/skills/levelplay-unity-integration/references/adding-more-ad-formats.md +15 -0
  135. package/skills/levelplay-unity-integration/references/banner-api.md +927 -0
  136. package/skills/levelplay-unity-integration/references/best-practices.md +604 -0
  137. package/skills/levelplay-unity-integration/references/dependency-resolution.md +94 -0
  138. package/skills/levelplay-unity-integration/references/examples.md +10 -0
  139. package/skills/levelplay-unity-integration/references/ilrd-api.md +337 -0
  140. package/skills/levelplay-unity-integration/references/initialization-api.md +851 -0
  141. package/skills/levelplay-unity-integration/references/interstitial-api.md +907 -0
  142. package/skills/levelplay-unity-integration/references/ios-setup.md +463 -0
  143. package/skills/levelplay-unity-integration/references/migration-sdk-9.md +666 -0
  144. package/skills/levelplay-unity-integration/references/privacy-settings.md +593 -0
  145. package/skills/levelplay-unity-integration/references/production-release-checklist.md +22 -0
  146. package/skills/levelplay-unity-integration/references/rewarded-api.md +918 -0
  147. package/skills/levelplay-unity-integration/references/step-0-new-or-migration.md +8 -0
  148. package/skills/levelplay-unity-integration/references/step-1-verify-environment.md +4 -0
  149. package/skills/levelplay-unity-integration/references/step-10-testing.md +15 -0
  150. package/skills/levelplay-unity-integration/references/step-2-business-goals.md +12 -0
  151. package/skills/levelplay-unity-integration/references/step-3-install-sdk.md +55 -0
  152. package/skills/levelplay-unity-integration/references/step-4-native-dependencies.md +22 -0
  153. package/skills/levelplay-unity-integration/references/step-5-app-key-and-ad-units.md +18 -0
  154. package/skills/levelplay-unity-integration/references/step-6-5-privacy-and-regulation.md +51 -0
  155. package/skills/levelplay-unity-integration/references/step-6-admob-keys.md +16 -0
  156. package/skills/levelplay-unity-integration/references/step-7-initialize.md +50 -0
  157. package/skills/levelplay-unity-integration/references/step-8-ad-unit-strategy.md +16 -0
  158. package/skills/levelplay-unity-integration/references/step-9-implement-ad-units.md +66 -0
  159. package/skills/levelplay-unity-integration/references/testing-and-validation.md +222 -0
  160. package/skills/levelplay-unity-integration/references/troubleshooting.md +99 -0
  161. package/skills/localize-unity-project/SKILL.md +159 -0
  162. package/skills/localize-unity-project/references/api-notes.md +15 -0
  163. package/skills/localize-unity-project/references/cjk-fonts.md +83 -0
  164. package/skills/localize-unity-project/references/docs-map.md +42 -0
  165. package/skills/localize-unity-project/references/documentation-lookup.md +33 -0
  166. package/skills/localize-unity-project/references/locale-switching.md +17 -0
  167. package/skills/localize-unity-project/references/table-completeness-check.md +47 -0
  168. package/skills/localize-unity-project/references/translating-existing-project.md +47 -0
  169. package/skills/localize-unity-project/references/translation-strategy.md +41 -0
  170. package/skills/localize-unity-project/references/troubleshooting.md +12 -0
  171. package/skills/localize-unity-project/scripts/L10nBatchProcessor.cs +191 -0
  172. package/skills/localize-unity-project/scripts/LocalizedFontAsset.cs +18 -0
  173. package/skills/manage-sprite-atlas/SKILL.md +202 -0
  174. package/skills/manage-sprite-atlas/references/addressables-delivery.md +58 -0
  175. package/skills/manage-sprite-atlas/references/advanced-manual-authoring.md +19 -0
  176. package/skills/manage-sprite-atlas/references/api.md +382 -0
  177. package/skills/manage-sprite-atlas/references/best-practices.md +183 -0
  178. package/skills/manage-sprite-atlas/references/common-errors.md +123 -0
  179. package/skills/manage-sprite-atlas/references/complete-workflow.md +61 -0
  180. package/skills/manage-sprite-atlas/references/custom-packing.md +147 -0
  181. package/skills/manage-sprite-atlas/references/delivery-mechanism.md +30 -0
  182. package/skills/manage-sprite-atlas/references/key-requirements.md +21 -0
  183. package/skills/manage-sprite-atlas/references/manual-authoring.md +39 -0
  184. package/skills/manage-sprite-atlas/references/namespaces.md +15 -0
  185. package/skills/manage-sprite-atlas/references/v2-architecture.md +21 -0
  186. package/skills/manage-sprite-atlas/resources/authoringvsruntime.cs +176 -0
  187. package/skills/manage-sprite-atlas/resources/buildaddressablespostprocess.cs +59 -0
  188. package/skills/manage-sprite-atlas/resources/cacheloadedatlases.cs +145 -0
  189. package/skills/manage-sprite-atlas/resources/cleanupbatchoperations.cs +119 -0
  190. package/skills/manage-sprite-atlas/resources/createandconfiguremasteratlas.cs +57 -0
  191. package/skills/manage-sprite-atlas/resources/custompackersetup.cs +88 -0
  192. package/skills/manage-sprite-atlas/resources/deprecatedmethods.cs +142 -0
  193. package/skills/manage-sprite-atlas/resources/dontmodifywithoutsaving.cs +120 -0
  194. package/skills/manage-sprite-atlas/resources/dontpackinruntimebuilds.cs +190 -0
  195. package/skills/manage-sprite-atlas/resources/dontscriptspriteatlasineditor.cs +114 -0
  196. package/skills/manage-sprite-atlas/resources/editorconfiguration.cs +95 -0
  197. package/skills/manage-sprite-atlas/resources/enablespritepacking.cs +172 -0
  198. package/skills/manage-sprite-atlas/resources/gridspritepacker.cs +50 -0
  199. package/skills/manage-sprite-atlas/resources/handlelatebinding.cs +147 -0
  200. package/skills/manage-sprite-atlas/resources/handlenullcases.cs +141 -0
  201. package/skills/manage-sprite-atlas/resources/migratev1tov2.cs +335 -0
  202. package/skills/manage-sprite-atlas/resources/multipagepacker.cs +80 -0
  203. package/skills/manage-sprite-atlas/resources/optimizetexturesettings.cs +191 -0
  204. package/skills/manage-sprite-atlas/resources/packerdebugging.cs +158 -0
  205. package/skills/manage-sprite-atlas/resources/packtransform.cs +51 -0
  206. package/skills/manage-sprite-atlas/resources/platformnames.cs +127 -0
  207. package/skills/manage-sprite-atlas/resources/queryspritesefficiently.cs +222 -0
  208. package/skills/manage-sprite-atlas/resources/registercallbacks.cs +152 -0
  209. package/skills/manage-sprite-atlas/resources/runtimeatlasloader.cs +15 -0
  210. package/skills/manage-sprite-atlas/resources/runtimespriteaccess.cs +19 -0
  211. package/skills/manage-sprite-atlas/resources/savespriteatlasasset.cs +107 -0
  212. package/skills/manage-sprite-atlas/resources/scriptablepacker.cs +81 -0
  213. package/skills/manage-sprite-atlas/resources/setincludeinbuild.cs +164 -0
  214. package/skills/manage-sprite-atlas/resources/sizeoptimizedpacker.cs +88 -0
  215. package/skills/manage-sprite-atlas/resources/spriteatlaslatebinding.cs +123 -0
  216. package/skills/manage-sprite-atlas/resources/spriteatlasprebuildgenerator.cs +219 -0
  217. package/skills/manage-sprite-atlas/resources/spritedata.cs +35 -0
  218. package/skills/manage-sprite-atlas/resources/spritepack.cs +39 -0
  219. package/skills/manage-sprite-atlas/resources/texturedata.cs +15 -0
  220. package/skills/manage-sprite-atlas/resources/updatebuildscripts.cs +357 -0
  221. package/skills/manage-sprite-atlas/resources/updatesettingsconfiguration.cs +135 -0
  222. package/skills/manage-sprite-atlas/resources/usevariantswisely.cs +179 -0
  223. package/skills/manage-sprite-atlas/resources/variantatlas.cs +39 -0
  224. package/skills/migrate-birp-to-urp/SECURITY.md +16 -0
  225. package/skills/migrate-birp-to-urp/SKILL.md +167 -0
  226. package/skills/migrate-birp-to-urp/references/capturing-the-editor.md +66 -0
  227. package/skills/migrate-birp-to-urp/references/complex-shader-situations.md +272 -0
  228. package/skills/migrate-birp-to-urp/references/conversion-and-rendering-triage.md +113 -0
  229. package/skills/migrate-birp-to-urp/references/custom-shader-triage.md +123 -0
  230. package/skills/migrate-birp-to-urp/references/implementation-patterns.md +529 -0
  231. package/skills/migrate-birp-to-urp/references/migration-workflow.md +265 -0
  232. package/skills/migrate-birp-to-urp/references/parity-validation-and-troubleshooting.md +114 -0
  233. package/skills/migrate-birp-to-urp/references/preflight-and-urp-setup.md +195 -0
  234. package/skills/migrate-birp-to-urp/references/quality-settings-map.md +69 -0
  235. package/skills/new-unity-project/SECURITY.md +26 -0
  236. package/skills/new-unity-project/SKILL.md +171 -0
  237. package/skills/new-unity-project/references/checklist.md +18 -0
  238. package/skills/new-unity-project/references/common-mistakes.md +15 -0
  239. package/skills/new-unity-project/references/skill-setup.md +66 -0
  240. package/skills/new-unity-project/references/step-1-concept.md +13 -0
  241. package/skills/new-unity-project/references/step-2-platforms-and-create.md +31 -0
  242. package/skills/new-unity-project/references/step-3-join-and-reconcile.md +16 -0
  243. package/skills/new-unity-project/references/step-4-source-control.md +9 -0
  244. package/skills/new-unity-project/references/step-5-packages.md +18 -0
  245. package/skills/new-unity-project/references/step-6-identity-and-floors.md +20 -0
  246. package/skills/new-unity-project/references/step-7-visual-baseline.md +75 -0
  247. package/skills/new-unity-project/references/step-8-first-commit.md +21 -0
  248. package/skills/new-unity-project/references/step-9-handoff.md +23 -0
  249. package/skills/optimize-audio/SECURITY.md +16 -0
  250. package/skills/optimize-audio/SKILL.md +120 -0
  251. package/skills/optimize-audio/references/diagnostics.md +42 -0
  252. package/skills/optimize-audio/references/troubleshooting.md +41 -0
  253. package/skills/optimize-audio/resources/audio-import-api.md +149 -0
  254. package/skills/optimize-audio/resources/platform-settings.md +48 -0
  255. package/skills/optimize-text-mesh-pro/SKILL.md +181 -0
  256. package/skills/optimize-text-mesh-pro/references/dynamic-atlas-and-profiling.md +28 -0
  257. package/skills/optimize-text-mesh-pro/references/topic-map.md +36 -0
  258. package/skills/optimize-web/SECURITY.md +16 -0
  259. package/skills/optimize-web/SKILL.md +157 -0
  260. package/skills/optimize-web/references/editor-csharp.md +120 -0
  261. package/skills/optimize-web/references/topic-map.md +49 -0
  262. package/skills/optimize-web/references/troubleshooting.md +45 -0
  263. package/skills/optimize-web/references/understand-request.md +19 -0
  264. package/skills/optimize-web/references/web-assets-quality.md +59 -0
  265. package/skills/optimize-web/references/web-player-settings.md +39 -0
  266. package/skills/optimize-web/references/web-profiling-memory.md +71 -0
  267. package/skills/optimize-web/scripts/WebOptimizer.cs +46 -0
  268. package/skills/optimize-web/scripts/toktx-examples.sh +11 -0
  269. package/skills/setup-multiplayer-services/SKILL.md +36 -0
  270. package/skills/setup-multiplayer-services/references/dgs-entrypoint.md +79 -0
  271. package/skills/setup-multiplayer-services/references/entrypoints.md +213 -0
  272. package/skills/setup-multiplayer-services/references/examples.md +33 -0
  273. package/skills/setup-multiplayer-services/references/implementation-fit.md +30 -0
  274. package/skills/setup-multiplayer-services/references/underlying-services.md +11 -0
  275. package/skills/setup-multiplayer-services/references/workflows-prerequisites.md +17 -0
  276. package/skills/setup-vivox-voice-chat/SECURITY.md +16 -0
  277. package/skills/setup-vivox-voice-chat/SKILL.md +166 -0
  278. package/skills/setup-vivox-voice-chat/references/api-reference-lookup.md +28 -0
  279. package/skills/setup-vivox-voice-chat/references/docs-topic-map.md +13 -0
  280. package/skills/setup-vivox-voice-chat/references/events-and-participants.md +79 -0
  281. package/skills/setup-vivox-voice-chat/references/init-and-login.md +92 -0
  282. package/skills/setup-vivox-voice-chat/references/text-chat.md +93 -0
  283. package/skills/setup-vivox-voice-chat/references/troubleshooting.md +47 -0
  284. package/skills/setup-vivox-voice-chat/references/voice-channels.md +92 -0
  285. package/skills/shader-graph-create-custom-node/SKILL.md +25 -0
  286. package/skills/shader-graph-create-custom-node/resources/all_hints.hlsl +182 -0
  287. package/skills/sprite-editor/SECURITY.md +16 -0
  288. package/skills/sprite-editor/SKILL.md +66 -0
  289. package/skills/sprite-editor/references/api_reference.md +151 -0
  290. package/skills/sprite-editor/references/background.md +112 -0
  291. package/skills/sprite-editor/references/templates.md +72 -0
  292. package/skills/sprite-editor/scripts/AutomaticSliceTexture.cs +40 -0
  293. package/skills/sprite-editor/scripts/GenerateNewSpriteRects.cs +200 -0
  294. package/skills/sprite-editor/scripts/GetTextureSourceImageSize.cs +32 -0
  295. package/skills/sprite-editor/scripts/GetTextureToSlice.cs +55 -0
  296. package/skills/sprite-editor/scripts/GridSliceTexture.cs +40 -0
  297. package/skills/sprite-editor/scripts/IsometricSliceTexture.cs +141 -0
  298. package/skills/sprite-editor/scripts/README.md +134 -0
  299. package/skills/sprite-editor/scripts/SetPivotExample.cs +58 -0
  300. package/skills/sprite-editor/scripts/SpriteToPng.cs +88 -0
  301. package/skills/sprite-segment-3x3grid/SKILL.md +177 -0
  302. package/skills/sprite-segment-3x3grid/references/topic-map.md +37 -0
  303. package/skills/sprite-segment-3x3grid/scripts/SpriteGridAnalysis.cs +119 -0
  304. package/skills/ui/SKILL.md +142 -0
  305. package/skills/ui-imgui/SKILL.md +180 -0
  306. package/skills/ui-imgui/references/gui-elements.md +156 -0
  307. package/skills/ui-imgui/references/templates.md +141 -0
  308. package/skills/ui-ugui/SKILL.md +217 -0
  309. package/skills/ui-ugui/references/layout-and-anchors.md +61 -0
  310. package/skills/ui-ugui/references/scrollview-setup.md +29 -0
  311. package/skills/ui-uitk/SKILL.md +229 -0
  312. package/skills/ui-uitk/references/common-issues.md +74 -0
  313. package/skills/ui-uitk/references/custom-elements.md +241 -0
  314. package/skills/ui-uitk/references/painter2d.md +282 -0
  315. package/skills/ui-uitk/references/pointermanipulator-guide.md +94 -0
  316. package/skills/ui-uitk/references/svg-icons.md +136 -0
  317. package/skills/ui-uitk/references/ui-runtime-binding.md +234 -0
  318. package/skills/ui-uitk/references/uss-guide.md +138 -0
  319. package/skills/unity-cli/CHANGELOG.md +524 -0
  320. package/skills/unity-cli/SECURITY.md +68 -0
  321. package/skills/unity-cli/SKILL.md +160 -0
  322. package/skills/unity-cli/references/auth-license-cloud.md +318 -0
  323. package/skills/unity-cli/references/bootstrap-project.md +177 -0
  324. package/skills/unity-cli/references/build-run-test.md +555 -0
  325. package/skills/unity-cli/references/catalog-plugins.md +86 -0
  326. package/skills/unity-cli/references/ci-recipes.md +76 -0
  327. package/skills/unity-cli/references/cloud-automation.md +819 -0
  328. package/skills/unity-cli/references/cloud-workflows.md +19 -0
  329. package/skills/unity-cli/references/collaboration.md +533 -0
  330. package/skills/unity-cli/references/config-hub.md +239 -0
  331. package/skills/unity-cli/references/diagnostics-maintenance.md +718 -0
  332. package/skills/unity-cli/references/docs-workflow.md +179 -0
  333. package/skills/unity-cli/references/editor-targeting.md +29 -0
  334. package/skills/unity-cli/references/editors-install.md +490 -0
  335. package/skills/unity-cli/references/environment-variables.md +42 -0
  336. package/skills/unity-cli/references/exit-codes.md +47 -0
  337. package/skills/unity-cli/references/global-flags.md +32 -0
  338. package/skills/unity-cli/references/integration-advanced.md +1130 -0
  339. package/skills/unity-cli/references/notes.md +20 -0
  340. package/skills/unity-cli/references/notifications.md +39 -0
  341. package/skills/unity-cli/references/playmode-verification-loop.md +279 -0
  342. package/skills/unity-cli/references/projects-templates.md +997 -0
  343. package/skills/unity-cli/references/scene-editing-preflight.md +25 -0
  344. package/skills/unity-cli/references/setup-and-help.md +54 -0
  345. package/skills/unity-cli/references/version-control.md +612 -0
  346. package/skills/unity-package-management/SKILL.md +169 -0
  347. package/skills/unity-package-management/references/discovering-packages.md +66 -0
  348. package/skills/unity-package-management/references/headless-run.md +31 -0
  349. package/skills/unity-package-management/references/installer-script.md +92 -0
  350. package/skills/unity-package-management/references/select-packages.md +126 -0
  351. package/skills/unity-pipeline/SECURITY.md +17 -0
  352. package/skills/unity-pipeline/SKILL.md +205 -0
  353. package/skills/unity-pipeline/references/csharp-eval.md +23 -0
  354. package/skills/unity-pipeline/references/multiplayer-play-mode.md +103 -0
  355. package/skills/urp-postprocessing/SECURITY.md +16 -0
  356. package/skills/urp-postprocessing/SKILL.md +188 -0
  357. package/skills/urp-postprocessing/references/code-templates.md +150 -0
  358. package/skills/urp-postprocessing/references/effect-reference.md +86 -0
  359. package/skills/validate-urp-render-graph-renderer-feature/SKILL.md +92 -0
  360. package/skills/validate-urp-render-graph-renderer-feature/references/validation-checklist.md +179 -0
@@ -0,0 +1,1276 @@
1
+ # Cloud Code Scripts and Modules Reference
2
+
3
+ Covers **Cloud Code modules** (`.ccmu`, authored natively in the Editor), **legacy modules** (`.ccmr`
4
+ references to a .NET solution built outside Unity) and JavaScript **scripts**. For CloudBehaviours, see the CloudBehaviours reference.
5
+
6
+ > **On Unity 6000.5+, create new C# modules as `.ccmu`.** They are authored inside the Unity project, compile with it, and
7
+ > generate their client bindings at compile time — no separate solution, no `dotnet publish`. `.ccmr` is
8
+ > legacy: on 6000.5+ maintain the ones a project already has and do not create new ones; on an older
9
+ > Editor, new modules use `.ccmr`. On 6000.5+, if you are about to write a
10
+ > `.sln`, a `.csproj` or a `FolderProfile.pubxml`, you are on the wrong path — see
11
+ > [Creating a Cloud Code Module](#creating-a-cloud-code-module-ccmu) instead.
12
+
13
+ > **The signatures, enums and diagnostics below are a convenience snapshot and can lag the package.**
14
+ > Read the [Cloud Code documentation](https://docs.unity.com/en-us/cloud-code/modules/overview.md) for
15
+ > the project's installed `com.unity.services.cloudcode` version before acting, and again whenever a
16
+ > step fails or a symbol does not resolve.
17
+
18
+ ## Table of Contents
19
+
20
+ - [Anti-Hallucination Reference](#anti-hallucination-reference)
21
+ - [ICloudCodeService Methods](#icloudcodeservice-methods)
22
+ - [Module Runtime Constraints](#module-runtime-constraints)
23
+ - [Subscriptions](#subscriptions)
24
+ - [Triggers](#triggers)
25
+ - [Creating a Cloud Code Module (.ccmu)](#creating-a-cloud-code-module-ccmu)
26
+ - [Injected Services](#injected-services-cloudcodeservice)
27
+ - [Registering Services](#registering-services-cloudcloudsetupcs)
28
+ - [Module State and Persistence](#module-state-and-persistence)
29
+ - [Evolving a persisted class](#evolving-a-persisted-class)
30
+ - [Generated Client Bindings](#generated-client-bindings)
31
+ - [Legacy Modules (.ccmr) - Maintenance Only](#legacy-modules-ccmr---maintenance-only)
32
+ - [Code Templates](#code-templates)
33
+ - [Deploying via the Deployment Window](#deploying-via-the-deployment-window)
34
+ - [Running the Local Cloud Code Server](#running-the-local-cloud-code-server)
35
+ - [Error Handling](#error-handling)
36
+ - [Error Messages](#error-messages)
37
+
38
+ ---
39
+
40
+ ## Anti-Hallucination Reference
41
+
42
+ | Correct | Incorrect (do NOT use) |
43
+ |---|---|
44
+ | For a new C# module, author a `.ccmu` in the Editor | Scaffolding a `.sln`/`.csproj`/`.pubxml` for a new module -- that is legacy `.ccmr` |
45
+ | Create a `.ccmu` module with **Create > Services > Cloud Code Module Script** | Hand-writing a new module's `.asmdef` files -- a module without a `.ccmu` never appears in the Deployment window |
46
+ | A `.ccmu` module's name is its **cloud asmdef** `name` | The `.ccmu` filename -- it is only a fallback |
47
+ | `.ccmu` client bindings are generated at **compile time** from `[CloudModuleClient]` | Clicking **Generate Bindings** -- that is the `.ccmr` flow |
48
+ | `[CloudCodeService]` on an injected parameter of a `.ccmu` endpoint | A bare one -- the server still injects it, but it leaks into the generated client binding |
49
+ | `config.AddGameApiClient()` in `ICloudCodeSetup` | `config.Dependencies.AddSingleton(GameApiClient.Create())` -- `Create()` is `[Obsolete]` |
50
+ | The generated client for a `.ccmu` module; `CallModuleEndpointAsync("Module", "Function", args)` for a legacy `.ccmr` module | `CallModuleEndpointAsync` on a `.ccmu` module, or `CallEndpointAsync` for modules |
51
+ | `CallEndpointAsync("scriptName", args)` | `CallEndpointAsync` for modules -- scripts only |
52
+ | `SubscribeToPlayerMessagesAsync()`, or the `(callbacks)` overload | `SubscribeToGeneralMessagesAsync` -- no such method |
53
+ | Pass a `SubscriptionEventCallbacks` to the subscribe call, or attach to `subscription.Callbacks` afterwards | Callbacks as a constructor argument -- there is no such constructor |
54
+ | Non-generic `CallEndpointAsync` returns `Task<string>` | Returns `Task` (void) -- it returns a string |
55
+ | Non-generic `CallModuleEndpointAsync` returns `Task<string>` | Returns `Task` (void) -- it returns a string |
56
+ | `EventConnectionState` enum | `SubscriptionEventConnectionState` |
57
+ | `Error` callback is `Action<string>` | `Action<EventConnectionState>` |
58
+
59
+ ---
60
+
61
+ ## ICloudCodeService Methods
62
+
63
+ ```csharp
64
+ // Call a Cloud Code Script endpoint. Returns the script's return value as string.
65
+ Task<string> CallEndpointAsync(string function, Dictionary<string, object> args = default)
66
+
67
+ // Call a Cloud Code Script endpoint with typed deserialization.
68
+ Task<TResult> CallEndpointAsync<TResult>(string function, Dictionary<string, object> args = default)
69
+
70
+ // Call a Cloud Code Module endpoint. Returns the result as string.
71
+ // module = module name, function = method name.
72
+ // Legacy .ccmr modules only: module = the .ccmr filename without extension.
73
+ // A .ccmu module is called through its generated client, not with this method.
74
+ Task<string> CallModuleEndpointAsync(string module, string function,
75
+ Dictionary<string, object> args = default, CloudCodeScope scope = default)
76
+
77
+ // Call a Cloud Code Module endpoint with typed deserialization.
78
+ Task<TResult> CallModuleEndpointAsync<TResult>(string module, string function,
79
+ Dictionary<string, object> args = default, CloudCodeScope scope = default)
80
+
81
+ // Subscribe to real-time messages sent to the current player. Requires Wire.
82
+ // Either wire callbacks up afterwards on the returned .Callbacks, or pass them in.
83
+ Task<ISubscriptionEvents> SubscribeToPlayerMessagesAsync()
84
+ Task<ISubscriptionEvents> SubscribeToPlayerMessagesAsync(SubscriptionEventCallbacks callbacks)
85
+
86
+ // Subscribe to real-time project-wide messages. Requires Wire. Same two forms.
87
+ Task<ISubscriptionEvents> SubscribeToProjectMessagesAsync()
88
+ Task<ISubscriptionEvents> SubscribeToProjectMessagesAsync(SubscriptionEventCallbacks callbacks)
89
+ ```
90
+
91
+ **CRITICAL:** The first argument to `CallModuleEndpointAsync` is the **module name**, the second is the **function name**. Do NOT confuse the parameter order.
92
+
93
+ ---
94
+
95
+ ## Module Runtime Constraints
96
+
97
+ - **Cold start:** An idle module's worker is eventually shut down, and the next call after that pays a latency spike while it spins back up. The idle window is a service-side setting rather than a documented guarantee, so design the UX to tolerate a slow first call rather than coding to a specific number.
98
+ - **No UnityEngine:** Modules run on standard .NET, not in the player. The `UnityEngine` namespace is NOT
99
+ available. A `.ccmu` cloud assembly is Editor-only and compiled by Unity, so its dependencies must be
100
+ available to the Editor; a `.ccmr` solution can pull NuGet packages directly.
101
+ - **Push messages:** Server-to-client push messages can only be sent from **modules**, not from JavaScript scripts.
102
+ - **.NET version:** modules target .NET 8 on Unity before 6.7 and on the local Cloud Code server; on
103
+ Unity 6.7+ they can target .NET 10. Legacy `.ccmr` solutions support up to .NET 10.
104
+
105
+ ---
106
+
107
+ ## Subscriptions
108
+
109
+ Cloud Code Subscriptions require `com.unity.services.wire`. Subscribe to real-time server-push messages.
110
+
111
+ ### `ISubscriptionEvents`
112
+
113
+ ```csharp
114
+ public interface ISubscriptionEvents
115
+ {
116
+ SubscriptionEventCallbacks Callbacks { get; } // Wire up handlers here
117
+ Task SubscribeAsync(); // Re-subscribe after unsubscribing
118
+ Task UnsubscribeAsync(); // Stop receiving messages
119
+ }
120
+ ```
121
+
122
+ ### `SubscriptionEventCallbacks`
123
+
124
+ There are two forms. **Prefer building the callbacks first and passing them in**, so every handler is
125
+ attached before the subscription goes live:
126
+
127
+ ```csharp
128
+ var callbacks = new SubscriptionEventCallbacks();
129
+ callbacks.MessageReceived += OnMessageReceived; // Action<IMessageReceivedEvent>
130
+ callbacks.MessageBytesReceived += OnBytesReceived; // Action<byte[]>
131
+ callbacks.ConnectionStateChanged += OnStateChanged; // Action<EventConnectionState>
132
+ callbacks.Kicked += OnKicked; // Action
133
+ callbacks.Error += OnError; // Action<string>
134
+
135
+ var subscription = await CloudCodeService.Instance.SubscribeToPlayerMessagesAsync(callbacks);
136
+ ```
137
+
138
+ The parameterless overload is a convenience wrapper that calls the same method with a fresh, empty
139
+ `SubscriptionEventCallbacks`. You then attach handlers to the returned object's `Callbacks` property —
140
+ which means a message arriving between the subscription going live and your `+=` running has no handler to
141
+ reach:
142
+
143
+ ```csharp
144
+ var subscription = await CloudCodeService.Instance.SubscribeToPlayerMessagesAsync();
145
+ subscription.Callbacks.MessageReceived += OnMessageReceived; // anything before this line is missed
146
+ ```
147
+
148
+ Both overloads exist for `SubscribeToProjectMessagesAsync` too.
149
+
150
+ ### `IMessageReceivedEvent` Properties
151
+
152
+ | Property | Type | Description |
153
+ |---|---|---|
154
+ | `MessageType` | `string` | Message type identifier set by the server |
155
+ | `Message` | `string` | Raw message payload (typically JSON) |
156
+ | `Id` | `string` | Unique message ID |
157
+ | `CorrelationId` | `string` | Correlation ID for tracing |
158
+ | `Source` | `string` | Source of the message |
159
+ | `Type` | `string` | CloudEvents type |
160
+ | `SpecVersion` | `string` | CloudEvents spec version |
161
+ | `Time` | `DateTime` | Timestamp |
162
+ | `ProjectId` | `string` | UGS project ID |
163
+ | `EnvironmentId` | `string` | UGS environment ID |
164
+
165
+ ### `EventConnectionState`
166
+
167
+ Namespace: `Unity.Services.CloudCode.Subscriptions`.
168
+
169
+ | State | Value | Meaning |
170
+ |---|---|---|
171
+ | `Unknown` | 0 | Initial state |
172
+ | `Unsubscribed` | 1 | Not connected |
173
+ | `Subscribing` | 2 | Connection in progress |
174
+ | `Subscribed` | 3 | Connected and receiving messages |
175
+ | `Unsynced` | 4 | Temporarily disconnected, will reconnect |
176
+ | `Error` | 5 | Connection error |
177
+
178
+ ---
179
+
180
+ ## Triggers
181
+
182
+ Triggers let Cloud Code endpoints run automatically in response to events from other UGS services, without any client call. Configured in the Unity Dashboard, the Deployment Window (`.tr` files, via `com.unity.services.tooling`), or `unity ugs tr` (see `references/ugs-cli.md`) -- not in client code.
183
+
184
+ Which services emit trigger events, and under what event names, is service-side configuration rather than
185
+ anything in this SDK — it changes independently of the package. Treat the following as illustration and
186
+ confirm the current set in the Dashboard's trigger editor, which lists what is actually available to your
187
+ project:
188
+
189
+ | Emitter | Example trigger events |
190
+ |---|---|
191
+ | Authentication | Player signed in, account deleted |
192
+ | Scheduler | Cron-based or one-shot scheduled events |
193
+ | Leaderboards | Score submitted, leaderboard reset |
194
+ | Cloud Save | Data saved, data deleted |
195
+
196
+ ---
197
+
198
+ ## Creating a Cloud Code Module (`.ccmu`)
199
+
200
+ A Cloud Code module is authored **inside the Unity project**. Its cloud code lives in an Editor-only
201
+ assembly that Unity compiles with the rest of the project, and the client bindings are generated at
202
+ compile time. There is no solution to build, nothing to publish, and no NuGet restore.
203
+
204
+ ### Requirements
205
+
206
+ - Unity **6000.5** or newer.
207
+ - `com.unity.services.cloudcode` **3.0.0** or newer.
208
+ - **Api Compatibility Level set to `.NET Standard 2.1`** in Player Settings. Any other level makes the
209
+ module compile fine and then fail to deploy with "Unsupported API Compatibility Level".
210
+
211
+ ### Create it
212
+
213
+ Right-click a folder under `Assets/` -> **Create > Services > Cloud Code Module Script** and fill in the
214
+ creation window. An agent without computer-use tools asks the user to run this menu step; with them, it
215
+ runs the step itself. The rest of this section describes what the Editor generates for you, so you can
216
+ recognise and check the result. It is not a list of files to write by hand.
217
+
218
+ Always use the menu for a new module, because it writes the module's `.ccmu` asset along with both
219
+ assemblies, and the Deployment window lists only modules that have a `.ccmu`. A module built from
220
+ hand-written asmdefs alone compiles and generates bindings, but never appears in the Deployment window,
221
+ and nothing reports why.
222
+
223
+ If an existing module is missing from the Deployment window, check for its `.ccmu`. When there is none,
224
+ repair the module by adding one rather than rebuilding it, because that keeps every assembly name, GUID
225
+ and script reference:
226
+
227
+ 1. Stop until the user confirms a rollback point, such as a commit in their version control or a backup
228
+ copy of the project.
229
+ 2. Write `<ModuleName>.ccmu` in the folder that holds both assembly folders, following
230
+ [`.ccmu` File Format](#ccmu-file-format).
231
+ 3. Verify: the `.ccmu` imports with zero console errors, and the module is listed in
232
+ **Services > Deployment** under the cloud asmdef's name. If either check fails, restore the rollback
233
+ point and read the console error before trying again.
234
+
235
+ ### Directory Structure
236
+
237
+ The module is a folder named after the module. The `.ccmu` sits at its root, one level **above** both
238
+ assemblies:
239
+
240
+ ```
241
+ Assets/<AnyFolder>/
242
+ MyModule/
243
+ MyModule.ccmu <-- the module asset
244
+ Cloud/
245
+ MyModule.asmdef <-- Editor-only cloud assembly; its name IS the module name
246
+ MyCloudCodeScript.cs <-- [CloudCodeFunction] entry points
247
+ CloudSetup.cs <-- you add this; only if an endpoint injects IGameApiClient
248
+ Client/
249
+ MyModuleClient.asmdef <-- ships in the player; must reference the cloud assembly
250
+ MyCloudCodeScriptClient.cs <-- [CloudModuleClient] partial; bindings generated into it
251
+ ```
252
+
253
+ The module folder can live anywhere under `Assets/`. **No `~` suffix** -- unlike `.ccmr`, the cloud
254
+ assembly is meant to be compiled by Unity, so hiding it from the importer would break the module.
255
+
256
+ This is the layout the Editor creates. Keep it, and in particular **leave the `.ccmu` in the folder it was
257
+ created in**. The Editor treats a folder holding a `.ccmu` as one that already contains a module, so moving
258
+ the file can allow a second module to be created on top of this one. If a project already keeps its `.ccmu`
259
+ somewhere else, leave that alone rather than "fixing" it.
260
+
261
+ ### `.ccmu` File Format
262
+
263
+ Plain JSON, two GUIDs, nothing else. It carries no code, no name and no path -- it exists only to pair the
264
+ two assemblies. The create menu writes it for a new module; write it by hand only to repair an existing
265
+ module that lacks one:
266
+
267
+ ```json
268
+ {
269
+ "cloudAssemblyDefinitionGuid": "<guid from Cloud/MyModule.asmdef.meta>",
270
+ "clientAssemblyDefinitionGuid": "<guid from Client/MyModuleClient.asmdef.meta>"
271
+ }
272
+ ```
273
+
274
+ **Never invent these values.** They are Unity asset GUIDs: Unity mints one per asset on import and stores
275
+ it in that asset's `.meta` file. Copy each one out of the `guid:` line of the matching `.asmdef.meta` --
276
+ the cloud assembly's for `cloudAssemblyDefinitionGuid`, the client assembly's for
277
+ `clientAssemblyDefinitionGuid`:
278
+
279
+ ```yaml
280
+ # Cloud/MyModule.asmdef.meta
281
+ fileFormatVersion: 2
282
+ guid: <this value>
283
+ ```
284
+
285
+ A GUID identifies an asset in one project only, so a value taken from anywhere else -- another project,
286
+ another module, a sample, an example in documentation -- resolves to nothing. Both keys are required; a
287
+ `.ccmu` naming a GUID Unity cannot resolve fails to import and logs an error.
288
+
289
+ Creating the module through the Editor writes the file with the right values already in it.
290
+
291
+ ### Deployed Module Name
292
+
293
+ **The module name is the cloud assembly's `name` field, not the `.ccmu` filename.** That is the name the
294
+ generated bindings pass to `CallModuleEndpointAsync` and the name the module deploys under. The filename
295
+ is used only as a fallback, when the asmdef cannot be read.
296
+
297
+ The creation window keeps the three in sync: module name `MyModule` produces `MyModule.ccmu`,
298
+ `MyModule.asmdef` (cloud) and `MyModuleClient.asmdef` (client). **Leave those names as generated.** Renaming
299
+ a module means renaming the cloud assembly, and that changes the deployed module name and every call site
300
+ along with it.
301
+
302
+ ### Cloud Assembly (`Cloud/MyModule.asmdef`)
303
+
304
+ Editor-only, no engine references, not auto-referenced. It must reference Cloud Code Core and Apis; the
305
+ source generator reference is what emits the client bindings.
306
+
307
+ ```json
308
+ {
309
+ "name": "MyModule",
310
+ "rootNamespace": "",
311
+ "references": [
312
+ "Unity.Services.CloudCode.Apis",
313
+ "Unity.Services.CloudCode.Core",
314
+ "Unity.Services.CloudCode.SourceGenerator"
315
+ ],
316
+ "includePlatforms": [ "Editor" ],
317
+ "excludePlatforms": [],
318
+ "allowUnsafeCode": false,
319
+ "overrideReferences": true,
320
+ "precompiledReferences": [],
321
+ "autoReferenced": false,
322
+ "defineConstraints": [ "UNITY_6000_5_OR_NEWER" ],
323
+ "versionDefines": [],
324
+ "noEngineReferences": true
325
+ }
326
+ ```
327
+
328
+ `includePlatforms: ["Editor"]`, `noEngineReferences: true` and `autoReferenced: false` all matter: they keep
329
+ server-only code out of player builds, out of every other assembly's global scope, and away from
330
+ `UnityEngine` types that do not exist on the Cloud Code host.
331
+
332
+ **Nothing validates them at import or deploy time, though.** Get one wrong and the module still imports,
333
+ still compiles, and still deploys — it is simply wrong in ways you find out later. The checks that do exist:
334
+
335
+ | When | What is checked | How it surfaces |
336
+ | :-- | :-- | :-- |
337
+ | `.ccmu` import | only that both asmdef GUIDs resolve | console error, asset fails to import |
338
+ | **Create > Services > Cloud Code Module Script** into an existing module's `Cloud/` folder | Editor-only, no engine references, not auto-referenced, references Core + Apis | modal dialog: *"This Cloud Code module's server Assembly Definition (.asmdef) is missing or misconfigured..."*, and the script is not created |
339
+ | Deploy | nothing about the asmdef flags; the only structural check is that two modules do not share a cloud assembly | per-item error status on each offending module in the Deployment window, logged as *"Assembly Failure -- Multiple CCMs reference the same assembly definition"* |
340
+
341
+ So the asmdef flags are effectively enforced only when you add a script through the menu. A hand-edited
342
+ module is on the honour system — worth checking by eye, because nothing else will. (Deploy
343
+ does make other checks unrelated to the asmdef — Api Compatibility Level and whether the project compiles —
344
+ covered under [Deploying via the Deployment Window](#deploying-via-the-deployment-window).)
345
+
346
+ ### Client Assembly (`Client/MyModuleClient.asmdef`)
347
+
348
+ This is the assembly that ships in your game. It **must reference the cloud assembly**, which looks wrong at
349
+ first glance: the cloud assembly is Editor-only, so how can a runtime assembly that gets compiled into a
350
+ player depend on it?
351
+
352
+ - **In the Editor**, the reference is what lets the source generator see the cloud class and read its
353
+ `[CloudCodeFunction]` methods, and what makes `[CloudModuleClient(typeof(MyCloudCodeScript))]` resolve.
354
+ Without it there is nothing to generate bindings from.
355
+ - **In a player build**, the Editor-only cloud assembly is not linked — so the generator emits an **empty
356
+ stub type** for each bound cloud class, purely so the `typeof(...)` in the attribute still resolves. The
357
+ stub carries no members.
358
+
359
+ The upshot: your server code never ships to players. What ships is the generated bindings plus an empty
360
+ shell of the cloud class name. You do not write or manage the stubs; they exist only in non-Editor
361
+ compilation.
362
+
363
+ The asmdef itself is an ordinary runtime one — no `includePlatforms`, engine references allowed:
364
+
365
+ ```json
366
+ {
367
+ "name": "MyModuleClient",
368
+ "rootNamespace": "",
369
+ "references": [
370
+ "MyModule",
371
+ "Unity.Services.CloudCode",
372
+ "Unity.Services.CloudCode.SourceGenerator"
373
+ ],
374
+ "includePlatforms": [],
375
+ "excludePlatforms": [],
376
+ "autoReferenced": true,
377
+ "defineConstraints": [],
378
+ "versionDefines": [],
379
+ "noEngineReferences": false
380
+ }
381
+ ```
382
+
383
+ ### Cloud Script (`Cloud/MyCloudCodeScript.cs`)
384
+
385
+ A plain class — no `.csproj`, no publish profile.
386
+
387
+ ```csharp
388
+ using System.Threading.Tasks;
389
+ using Unity.Services.CloudCode.Core;
390
+
391
+ namespace MyModule.Cloud
392
+ {
393
+ // The scope determines how state is persisted. See Module State and Persistence below.
394
+ [StateScope(Scope.Player)]
395
+ public class MyCloudCodeScript
396
+ {
397
+ [CloudCodeFunction(nameof(SayHello))]
398
+ public string SayHello(string name) => $"Hello, {name}!";
399
+
400
+ [CloudCodeFunction(nameof(GetScoreAsync))]
401
+ public async Task<int> GetScoreAsync() => await Task.FromResult(1);
402
+ }
403
+ }
404
+ ```
405
+
406
+ The generated namespaces derive from the **cloud** assembly name: `<CloudAsmName>.Cloud` for cloud scripts
407
+ and `<CloudAsmName>.Client` for client scripts.
408
+
409
+ ### Injected Services (`[CloudCodeService]`)
410
+
411
+ A module gets its services in one of two ways — constructor injection and marked method parameters. Both
412
+ are supported and both generate correct client bindings; the one exception is `IExecutionContext`, which
413
+ must always be a method parameter (see below).
414
+
415
+ **Constructor injection.** The class takes its services in a constructor; the runtime resolves them from the
416
+ DI container. The class must have **exactly one public constructor**, or instantiation fails with
417
+ `Invalid constructor: type X must have exactly one public constructor`. Constructor parameters are not
418
+ endpoint parameters, so they never reach the generated client:
419
+
420
+ ```csharp
421
+ public class Rewards
422
+ {
423
+ readonly IGameApiClient _client;
424
+ public Rewards(IGameApiClient client) => _client = client;
425
+
426
+ [CloudCodeFunction(nameof(Grant))]
427
+ public Task<int> Grant(string rewardId) { ... } // client sees: Grant(string rewardId)
428
+ }
429
+ ```
430
+
431
+ **Method-parameter injection.** The service is a parameter on the endpoint itself. Here — and *only* here —
432
+ it must carry `[CloudCodeService]`:
433
+
434
+ ```csharp
435
+ [CloudCodeFunction(nameof(Grant))]
436
+ public Task<int> Grant([CloudCodeService] IGameApiClient client, string rewardId) { ... }
437
+ ```
438
+
439
+ The attribute tells the generator "this is injected, not caller data". It has no bearing on constructor
440
+ parameters.
441
+
442
+ **Mark every injected parameter.** An unmarked parameter is treated as caller data: it lands in the
443
+ generated client as an argument the caller has to supply, and is sent in the request payload. That is
444
+ almost never what you want for a service — `IExecutionContext` in particular is a server-side interface
445
+ the client cannot construct, so the generated client is unusable. No diagnostic fires; an unexplained
446
+ error inside a generated `.g.cs` is the signal.
447
+
448
+ **`IExecutionContext` must be a `[CloudCodeService]` method parameter** — a constructor asking for it
449
+ fails. Other services are fine in the constructor, and that is the tidier form when every endpoint uses
450
+ them. Keep per-invocation values out of the constructor: the instance is cached per scope, so whatever it
451
+ captures outlives a single call.
452
+
453
+ The runtime provides these without any registration:
454
+
455
+ | Service | Gives you |
456
+ | :-- | :-- |
457
+ | `IExecutionContext` | player ID, project ID, environment, service token, session |
458
+ | `ILogger<T>` | logging |
459
+ | `ITimerService` | register and cancel server-owned timers that call back into the module |
460
+ | `IPushClient` | send push messages to a player or the whole project |
461
+
462
+ Anything else — `IGameApiClient` above all — must be registered in `CloudSetup.cs` (below) before it can be
463
+ injected. Private helper methods are ordinary C# and need no attribute; only `[CloudCodeFunction]`
464
+ endpoints do.
465
+
466
+ ### Registering Services (`Cloud/CloudSetup.cs`)
467
+
468
+ A class implementing `ICloudCodeSetup` registers what `[CloudCodeService]` can inject. Required once per
469
+ module if any endpoint injects `IGameApiClient`; omit the file entirely if none do.
470
+
471
+ ```csharp
472
+ using Unity.Services.CloudCode.Apis.Extensions;
473
+ using Unity.Services.CloudCode.Core;
474
+
475
+ namespace MyModule.Cloud
476
+ {
477
+ public class CloudSetup : ICloudCodeSetup
478
+ {
479
+ public void Setup(ICloudCodeConfig config)
480
+ {
481
+ config.AddGameApiClient();
482
+ }
483
+ }
484
+ }
485
+ ```
486
+
487
+ Use the `config.AddGameApiClient()` extension. The older
488
+ `config.Dependencies.AddSingleton(GameApiClient.Create())` still appears in legacy `.ccmr` modules, but
489
+ `GameApiClient.Create()` is `[Obsolete]` — its own message directs you to `AddGameApiClient()`.
490
+
491
+ ### Client Script (`Client/MyCloudCodeScriptClient.cs`)
492
+
493
+ An empty `partial` class carrying `[CloudModuleClient(typeof(CloudClass))]`. The source generator fills in
494
+ the other half at compile time. Do not add members here -- they will collide with the generated partial.
495
+
496
+ ```csharp
497
+ using Unity.Services.CloudCode;
498
+
499
+ namespace MyModule.Client
500
+ {
501
+ [CloudModuleClient(typeof(global::MyModule.Cloud.MyCloudCodeScript))]
502
+ public partial class MyCloudCodeScriptClient
503
+ {
504
+ }
505
+ }
506
+ ```
507
+
508
+ ### Adding Another Script to an Existing Module
509
+
510
+ Right-click the module's **`Cloud/` folder** -> **Create > Services > Cloud Code Module Script**. The same
511
+ menu item detects the existing module and creates the cloud/client pair inside it instead of starting a
512
+ new module. Creating a script in the `Client/` folder is rejected -- always start from `Cloud/`.
513
+
514
+ ---
515
+
516
+ ## Module State and Persistence
517
+
518
+ A module class annotated `[StateScope]` keeps state between calls. The runtime holds one instance per
519
+ scope — per player, or per multiplayer session — and every change to a persisted member is saved for you.
520
+ Saving is guaranteed, but not necessarily complete by the time a call returns, so do not treat "the call
521
+ finished" as "the state is on disk".
522
+
523
+ ```csharp
524
+ using System.Collections.Generic;
525
+ using Microsoft.Extensions.Logging;
526
+ using Unity.Services.CloudCode.Core;
527
+
528
+ [StateScope(Scope.MultiplayerSession)]
529
+ public class TurnTimer
530
+ {
531
+ public bool GameOver; // public members persist
532
+ public int TurnCount;
533
+ public List<string> History = new();
534
+
535
+ [CloudCodeSerializeProperty]
536
+ private string _secretAnswer; // private, but persisted
537
+
538
+ [CloudCodeIgnoreProperty]
539
+ public int CallsThisSession; // public, but not persisted
540
+
541
+ readonly ILogger<TurnTimer> _logger; // not persisted; injected by the constructor below
542
+
543
+ // Services are injected through the constructor or a [CloudCodeService] parameter -- never into a
544
+ // bare field. A field nothing assigns stays null.
545
+ public TurnTimer(ILogger<TurnTimer> logger) => _logger = logger;
546
+
547
+ [CloudCodeFunction("PlayTurn")]
548
+ public void PlayTurn(string move) { TurnCount++; }
549
+ }
550
+ ```
551
+
552
+ | Scope | Instance per | Typical use |
553
+ | :-- | :-- | :-- |
554
+ | `Scope.Player` | player | inventory, progression, per-player counters |
555
+ | `Scope.MultiplayerSession` | session | turn order, shared board, match state |
556
+ | *(no `[StateScope]`)* | none — stateless | validation, rewards, calls to other services |
557
+
558
+ ### Targeting an instance from the client
559
+
560
+ A `.ccmu` client targets an instance through its constructor: the generated client takes the player ID or the session ID that its cloud class's `[StateScope]` needs (see [Generated Client Bindings](#generated-client-bindings)), and passes the matching `CloudCodeScope` for you.
561
+
562
+ ```csharp
563
+ // Scope to a multiplayer session: the generated client takes the session ID
564
+ var client = new TurnTimerClient(sessionId);
565
+ await client.PlayTurn(move);
566
+ ```
567
+
568
+ `CloudCodeScope` and `ScopeType` (namespace `Unity.Services.CloudCode`) are what the generated client sends on your behalf.
569
+
570
+ #### `ScopeType` Enum
571
+
572
+ | Scope Type | Value | Description |
573
+ |---|---|---|
574
+ | `MultiplayerSession` | 1 | Scoped to a multiplayer session ID |
575
+ | `Player` | 2 | Scoped to the calling player |
576
+
577
+ **There is no default scope.** The `scope` argument defaults to `null`, which is sent as "no scope", not as
578
+ `Player`. A function on a `[StateScope]` class called without a scope is rejected server-side with
579
+ *"Function's ... class in module ... requires a scope and must be called with a scope"*. Conversely a
580
+ non-scoped function called *with* a scope is rejected too, and a mismatched scope
581
+ (`Player` against a `[StateScope(Scope.MultiplayerSession)]` class) fails the same way. The generated client
582
+ gets this right on its own — it passes the scope its cloud class declares — which is one more reason to always call a `.ccmu` module through it.
583
+
584
+ ---
585
+
586
+
587
+ ### What persists
588
+
589
+ - **public members persist** — fields and properties alike
590
+ - `[CloudCodeSerializeProperty]` persists a non-public member
591
+ - `[CloudCodeIgnoreProperty]` excludes a public one
592
+ - anything else — plain private fields — is not persisted
593
+
594
+ **Accessibility decides this, not what the member holds.** The serializer asks only: is it ignored, is it
595
+ explicitly marked, is it public? There is no exemption for service types. So a service or logger assigned to
596
+ a **public** field *is* persisted, with two consequences worth avoiding:
597
+
598
+ - Its object graph is walked and written into your scope state — which for `IExecutionContext` means the
599
+ service token, and for `IGameApiClient` means client configuration.
600
+ - Persisted members are written back when state is loaded, so the value the constructor injected is overwritten by
601
+ whatever came out of storage — and an interface cannot be reconstructed from the stored JSON.
602
+
603
+ Keep injected services and loggers in **private** fields, which are excluded by default:
604
+
605
+ ```csharp
606
+ readonly IGameApiClient _client; // private: not persisted
607
+ readonly ILogger<MyModule> _logger;
608
+ ```
609
+
610
+ If one genuinely has to be public, exclude it explicitly:
611
+
612
+ ```csharp
613
+ [CloudCodeIgnoreProperty]
614
+ public IGameApiClient Client; // public, but excluded
615
+ ```
616
+
617
+ `[CloudCodeIgnoreProperty]` is checked before `[CloudCodeSerializeProperty]`, so ignore always wins.
618
+
619
+ "Not persisted" is not the same as "reset every call". The runtime keeps one instance per scope and can
620
+ reuse it across invocations. Do not build on that: a non-persisted field may hold its value across
621
+ invocations but can be discarded at any point. Keep anything that must survive in a persisted member.
622
+
623
+ ### Custom serialization
624
+
625
+ Implementing `IStateSerializer` on the module class replaces the default serialization entirely:
626
+
627
+ ```csharp
628
+ public byte[] OnSerialize();
629
+ public void OnDeserialize(byte[] input);
630
+ ```
631
+
632
+ The runtime checks the module instance for the interface and uses it when present, so this works because
633
+ the class you author is the class that gets deployed. Reach for it when the default serialization is
634
+ unworkable — large binary blobs, custom compression, or a schema you want to version by hand.
635
+
636
+ ### Evolving a persisted class
637
+
638
+ Persisted state outlives the code that wrote it. A deployed module reads records written by every
639
+ earlier version of itself, so the shape of a `[StateScope]` class is a storage contract, not just a
640
+ class declaration. Nothing warns you: the module compiles, deploys and runs, and the damage shows up
641
+ later as a value that is gone, a list that keeps growing, or a scope that no longer loads.
642
+
643
+ | Change to a persisted class | What happens to already-persisted records |
644
+ | :-- | :-- |
645
+ | **Add** a member | Keeps its field initializer (or the value the constructor set). Loading only overwrites members that are present in the stored record. |
646
+ | **Rename** a member | Treated as a remove plus an add: the stored value is stranded and the new member keeps its initializer. |
647
+ | **Remove** a member | Value is dropped on the next write. |
648
+ | **Retype** a member | A compatible stored value converts (a number into a `string` field). An incompatible one (`"abc"` into an `int`, an object into a number) throws on load, and every call for that scope fails with `CloudCodeExecutionScopeStateException` until the state is fixed. |
649
+ | **Rename the class** | Instance state is keyed on the class name, so a rename orphans that scope's entire state — every field, not one. |
650
+ | **Change the `Scope`** | Different instance key. The old state is unreachable. |
651
+
652
+ **Give a new member the initializer you want; it applies to old records.** A new `bool AllowSpectators = true;`
653
+ reads `true` for every player or session that existed before the change, because the instance is
654
+ constructed first and the stored record only overwrites the members it contains.
655
+
656
+ **Initialize persisted collections empty.** Loading adds stored items to the collection the
657
+ initializer already created, so `public List<string> Tags = new() { "starter" };` gains another
658
+ `"starter"` on every load and save. A `HashSet` or `Dictionary` does not duplicate, but its
659
+ initializer entries come back after the player's state removed them. Declare persisted collections
660
+ as `= new();` and add starting items from code the first time the state is set up.
661
+
662
+ **Design the state so migration stays cheap:**
663
+
664
+ - Keep the persisted surface small and explicit. Private fields plus `[CloudCodeIgnoreProperty]` on
665
+ anything derived or cached means fewer members that have to be migrated later.
666
+ - Put game state in one payload class, versioned as a whole, rather than a wide set of loose fields
667
+ on the module class.
668
+ - Never reuse a member name for a new meaning, and never renumber or reorder an enum that is
669
+ persisted — the stored value is what comes back.
670
+ - Do not hide the real schema inside a hand-serialized string. A single opaque `string` field keeps
671
+ every one of these problems and moves them into your own serializer.
672
+
673
+ **Migrate with a version envelope and a chain of forms.** Implement `IStateSerializer`, stamp a
674
+ schema version alongside the payload, and let each version own the single hop to the next. A module
675
+ never writes a migration between two arbitrary versions: it deserializes whichever form was
676
+ persisted and calls `Migrate` until it reaches the latest.
677
+
678
+ ```csharp
679
+ using System;
680
+ using System.Text;
681
+ using Newtonsoft.Json;
682
+ using Newtonsoft.Json.Linq;
683
+ using Unity.Services.CloudCode.Core;
684
+
685
+ public interface ISchema
686
+ {
687
+ ISchema Migrate(); // next form, or null when this is the latest
688
+ }
689
+
690
+ public class SchemaV1 : ISchema
691
+ {
692
+ public string Name = "";
693
+ public ISchema Migrate() => new SchemaV2 { CharacterName = Name };
694
+ }
695
+
696
+ public class SchemaV2 : ISchema
697
+ {
698
+ public string CharacterName = "";
699
+ public ISchema Migrate() => null;
700
+ }
701
+
702
+ [StateScope(Scope.Player)]
703
+ public class PlayerProfile : IStateSerializer
704
+ {
705
+ const int SchemaVersion = 2;
706
+
707
+ public SchemaV2 Data = new();
708
+
709
+ public byte[] OnSerialize()
710
+ {
711
+ var envelope = new JObject
712
+ {
713
+ ["SchemaVersion"] = SchemaVersion,
714
+ ["Data"] = JObject.FromObject(Data),
715
+ };
716
+ return Encoding.UTF8.GetBytes(envelope.ToString(Formatting.None));
717
+ }
718
+
719
+ public void OnDeserialize(byte[] input)
720
+ {
721
+ // Nothing stored for this scope -- keep the instance as constructed.
722
+ if (input == null || input.Length == 0)
723
+ return;
724
+
725
+ var envelope = JObject.Parse(Encoding.UTF8.GetString(input));
726
+ var version = envelope["SchemaVersion"]?.Value<int>() ?? 1;
727
+ // A record written before this serializer existed is the bare v1 member set, with no envelope.
728
+ var payload = envelope["SchemaVersion"] == null ? envelope : (JObject)envelope["Data"];
729
+
730
+ ISchema schema = version switch
731
+ {
732
+ 1 => payload.ToObject<SchemaV1>(),
733
+ 2 => payload.ToObject<SchemaV2>(),
734
+ // State written by a newer version cannot be migrated backwards, and running on a
735
+ // default payload would silently discard the player's data.
736
+ _ => throw new Exception($"cannot read schema version {version}, this module writes {SchemaVersion}"),
737
+ };
738
+
739
+ while (schema?.Migrate() is { } next) schema = next;
740
+
741
+ Data = schema as SchemaV2 ?? throw new Exception($"chain from version {version} did not end at SchemaV2");
742
+ }
743
+ }
744
+ ```
745
+
746
+ `JObject` needs `Newtonsoft.Json.dll` in the **cloud** asmdef's `precompiledReferences`. The generated
747
+ asmdef ships that array empty with `overrideReferences: true`, so the reference has to be added by hand —
748
+ without it the `Newtonsoft.Json` namespace does not resolve in the module assembly at all:
749
+
750
+ ```json
751
+ "overrideReferences": true,
752
+ "precompiledReferences": [ "Newtonsoft.Json.dll" ],
753
+ ```
754
+
755
+ Adding a `SchemaV3` later means writing `SchemaV2.Migrate`, bumping `SchemaVersion`, adding a `3` case
756
+ to the switch and changing both the `Data` field type and the final type check to `SchemaV3`. The
757
+ earlier hops do not change. The default serializer stores the persisted members as a JSON object
758
+ keyed by member name, so a record written before the envelope existed is that bare v1 payload. Keep the old
759
+ `SchemaV*` classes — deleting one breaks every record still stored in that form. A hop is also where
760
+ a value is repaired rather than defaulted: a list that did not exist in v1, a cosmetic an older
761
+ record claims the player owns.
762
+
763
+ **Verify against what is actually stored, not against the class.** Before changing a deployed
764
+ `[StateScope]` class, look at what real records hold. There is no API or CLI that reads a module's
765
+ server-side state, so add a temporary read-only `[CloudCodeFunction]` that returns only the members
766
+ you need to check, deploy it to a non-production environment, call it once for a known player or
767
+ session, and remove it afterwards. A deployed function is callable by clients, so never return
768
+ secret state such as `_secretAnswer`. This shows the values after deserialization, not the stored
769
+ format.
770
+
771
+ ## Generated Client Bindings
772
+
773
+ `.ccmu` and `.ccmr` both give you a strongly-typed client instead of raw `CallModuleEndpointAsync`, but
774
+ they generate it in completely different ways. Do not mix the two flows.
775
+
776
+ ### `.ccmu` -- generated at compile time
777
+
778
+ You do not write either half of this. The creation flow generates the cloud script and its client partial,
779
+ and the client partial already carries `[CloudModuleClient(typeof(CloudClass))]`. From there the source
780
+ generator emits `<ClientClass>.g.cs` on every compile. Nothing to click, nothing to deploy first, no
781
+ `GeneratedModuleBindings/` folder.
782
+
783
+ The constructor depends on the cloud class's `[StateScope]`:
784
+
785
+ | Cloud class | Constructor |
786
+ | :-- | :-- |
787
+ | `[StateScope(Scope.Player)]` | `new MyScriptClient(playerId)` |
788
+ | `[StateScope(Scope.MultiplayerSession)]` | `new MyScriptClient(sessionId)` |
789
+ | *(no `[StateScope]`)* | `new MyScriptClient()` |
790
+
791
+ Each also has an overload taking an `ICloudCodeService`, for tests or a non-default instance.
792
+
793
+ ```csharp
794
+ var client = new MyCloudCodeScriptClient(AuthenticationService.Instance.PlayerId);
795
+ var score = await client.GetScoreAsync();
796
+ ```
797
+
798
+ The generated methods return `Task`/`Task<T>` and pass the **cloud assembly name** as the module name, so
799
+ a rename of that assembly changes the deployed endpoint the client calls.
800
+ An `Access.Service` function gets no client method, since only Cloud Code itself (timers, for example)
801
+ can call it; calling it from the client is a compile error, not a runtime `403`.
802
+
803
+ **Types in endpoint signatures.** Declare a class or enum that an endpoint takes or returns once, in the cloud
804
+ assembly, and use that type from client code. The generator emits a data-only stub of it, with the same name and
805
+ namespace, into the client assembly, in the Editor and in player builds. The game assembly sees the stub through the client assembly and never references the Editor-only cloud assembly. A class is reduced to its public instance fields and properties that have both a public getter and a public setter, and each one is emitted on the stub as a `{ get; set; }` property. Get-only, computed, `readonly` and private-setter members, non-public members, indexers, statics, consts, methods, constructors and initializers are not copied. The generator warns only about public members it leaves out because they are read-only (CCSG216) or computed (CCSG229); non-public, static, const and indexer members are skipped silently. Declare a model type as plain data with public settable members, and do not declare a second copy on the client. A type from any other assembly is referenced directly and is not stubbed.
806
+
807
+ ### `.ccmr` -- generated on demand from the deployed module
808
+
809
+ The generator reads the *deployed* module's metadata and writes one file per class under
810
+ `Assets/CloudCode/GeneratedModuleBindings/`. Deploy first, then generate. Do not edit those files -- they
811
+ are overwritten on regeneration.
812
+
813
+ - Select the `.ccmr` in the **Project window**, then click **Generate Bindings** in the Inspector, or
814
+ - **Services > CloudCode > Generate All Modules Bindings** to regenerate every `.ccmr` at once.
815
+
816
+ ```csharp
817
+ // Assets/CloudCode/GeneratedModuleBindings/MyModuleBindings.cs
818
+ // This file was generated by Cloud Code Bindings Generator. Modifications will be lost upon regeneration.
819
+ public class MyModuleBindings
820
+ {
821
+ readonly ICloudCodeService k_Service;
822
+ public MyModuleBindings(ICloudCodeService service) { k_Service = service; }
823
+
824
+ public async Task<string> SayHello(string name)
825
+ => await k_Service.CallModuleEndpointAsync<string>("MyModule", "SayHello",
826
+ new Dictionary<string, object> { { "name", name } });
827
+ }
828
+ ```
829
+
830
+ ```csharp
831
+ var bindings = new MyModuleBindings(CloudCodeService.Instance);
832
+ var greeting = await bindings.SayHello("World");
833
+ ```
834
+
835
+ **Known limitations (`.ccmr`):** no distinction between required/optional parameters; tuples are not
836
+ supported.
837
+
838
+ ---
839
+
840
+ ## Legacy Modules (`.ccmr`) - Maintenance Only
841
+
842
+ **On Unity 6000.5+, do not create new `.ccmr` modules**; see
843
+ [Creating a Cloud Code Module](#creating-a-cloud-code-module-ccmu) instead. This section covers reading,
844
+ fixing and redeploying the `.ccmr` modules a project already has, and creating a new one on an older Editor,
845
+ which cannot author `.ccmu`.
846
+
847
+ A legacy module is a .NET class library (.NET 8, up to .NET 10) living outside `Assets/`, built and published by the Deployment
848
+ Window, and referenced from Unity by a `.ccmr` file.
849
+
850
+ ### Directory Structure
851
+
852
+ Place the module at the **project root** (alongside `Assets/`). Unity does not scan the project root, so no `~` suffix is needed.
853
+
854
+ > **Tilde rule:** Only add `~` to a folder name (e.g. `MyModule~/`) when the module lives **inside `Assets/`** -- the suffix tells Unity to skip that folder during compilation. At the project root, omit it.
855
+
856
+ ```
857
+ <ProjectRoot>/
858
+ Assets/
859
+ CloudCode/
860
+ MyModule.ccmr <-- Unity asset pointing to the .sln
861
+ MyModuleCCM/
862
+ MyModule.sln
863
+ MyModule/
864
+ MyModule.csproj
865
+ MyModule.cs <-- [CloudCodeFunction] entry points
866
+ ModuleSetup.cs <-- registers IGameApiClient via DI
867
+ Properties/
868
+ PublishProfiles/
869
+ FolderProfile.pubxml <-- publish to linux-x64 (required)
870
+ MyModule.Tests/
871
+ MyModule.Tests.csproj <-- IsPublishable=false, never deployed
872
+ MyModuleTests.cs
873
+ ```
874
+
875
+ ### `.sln` File Template
876
+
877
+ Generate fresh GUIDs for `{MAIN-GUID}`, `{TEST-GUID}`, and `{SLN-GUID}` using `[System.Guid]::NewGuid()` in PowerShell or any GUID generator. The test project intentionally has no `Release Build.0` entry to exclude it from Release builds.
878
+
879
+ ```
880
+ Microsoft Visual Studio Solution File, Format Version 12.00
881
+ # Visual Studio Version 16
882
+ VisualStudioVersion = 16.0.30114.105
883
+ MinimumVisualStudioVersion = 10.0.40219.1
884
+ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MyModule", "MyModule\MyModule.csproj", "{MAIN-GUID}"
885
+ EndProject
886
+ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MyModule.Tests", "MyModule.Tests\MyModule.Tests.csproj", "{TEST-GUID}"
887
+ EndProject
888
+ Global
889
+ GlobalSection(SolutionConfigurationPlatforms) = preSolution
890
+ Debug|Any CPU = Debug|Any CPU
891
+ Release|Any CPU = Release|Any CPU
892
+ EndGlobalSection
893
+ GlobalSection(ProjectConfigurationPlatforms) = postSolution
894
+ {MAIN-GUID}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
895
+ {MAIN-GUID}.Debug|Any CPU.Build.0 = Debug|Any CPU
896
+ {MAIN-GUID}.Release|Any CPU.ActiveCfg = Release|Any CPU
897
+ {MAIN-GUID}.Release|Any CPU.Build.0 = Release|Any CPU
898
+ {TEST-GUID}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
899
+ {TEST-GUID}.Debug|Any CPU.Build.0 = Debug|Any CPU
900
+ {TEST-GUID}.Release|Any CPU.ActiveCfg = Release|Any CPU
901
+ EndGlobalSection
902
+ GlobalSection(SolutionProperties) = preSolution
903
+ HideSolutionNode = FALSE
904
+ EndGlobalSection
905
+ GlobalSection(ExtensibilityGlobals) = postSolution
906
+ SolutionGuid = {SLN-GUID}
907
+ EndGlobalSection
908
+ EndGlobal
909
+ ```
910
+
911
+ ### `.csproj` (net8.0, CloudCode.Apis 0.0.27, CloudCode.Core 0.0.7)
912
+
913
+ ```xml
914
+ <Project Sdk="Microsoft.NET.Sdk">
915
+
916
+ <PropertyGroup>
917
+ <TargetFramework>net8.0</TargetFramework>
918
+ <Nullable>enable</Nullable>
919
+ <Configurations>Debug;Release</Configurations>
920
+ </PropertyGroup>
921
+
922
+ <ItemGroup>
923
+ <PackageReference Include="Com.Unity.Services.CloudCode.Apis" Version="0.0.27" />
924
+ <PackageReference Include="Com.Unity.Services.CloudCode.Core" Version="0.0.7" />
925
+ <PackageReference Include="Microsoft.Extensions.Logging.Abstractions" Version="7.0.1" />
926
+ </ItemGroup>
927
+
928
+ <PropertyGroup>
929
+ <PublishReadyToRunComposite>true</PublishReadyToRunComposite>
930
+ </PropertyGroup>
931
+
932
+ </Project>
933
+ ```
934
+
935
+ ### `FolderProfile.pubxml` (linux-x64, SelfContained=false)
936
+
937
+ Cloud Code runs on Linux. `SelfContained=false` keeps the output small -- the runtime is provided by the
938
+ Cloud Code host.
939
+
940
+ ```xml
941
+ <?xml version="1.0" encoding="utf-8"?>
942
+ <Project ToolsVersion="4.0" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
943
+ <PropertyGroup>
944
+ <Configuration>Release</Configuration>
945
+ <Platform>Any CPU</Platform>
946
+ <PublishDir>bin\Release\net8.0\publish\</PublishDir>
947
+ <PublishProtocol>FileSystem</PublishProtocol>
948
+ <TargetFramework>net8.0</TargetFramework>
949
+ <RuntimeIdentifier>linux-x64</RuntimeIdentifier>
950
+ <SelfContained>false</SelfContained>
951
+ <PublishSingleFile>False</PublishSingleFile>
952
+ </PropertyGroup>
953
+ </Project>
954
+ ```
955
+
956
+ ### `ModuleSetup.cs` (registers GameApiClient)
957
+
958
+ Required once per module if any endpoint needs `IGameApiClient`. This is what the Editor's `.ccmr`
959
+ template generates:
960
+
961
+ ```csharp
962
+ using Unity.Services.CloudCode.Apis.Extensions;
963
+ using Unity.Services.CloudCode.Core;
964
+
965
+ public class ModuleSetup : ICloudCodeSetup
966
+ {
967
+ public void Setup(ICloudCodeConfig config)
968
+ {
969
+ config.AddGameApiClient();
970
+ }
971
+ }
972
+ ```
973
+
974
+ An older module may instead contain `config.Dependencies.AddSingleton(GameApiClient.Create())`. That still
975
+ works, but `GameApiClient.Create()` is `[Obsolete]` and its own message points at `AddGameApiClient()`, so
976
+ prefer the form above when you touch the file.
977
+
978
+ ### `MyModule.cs` ([CloudCodeFunction], IExecutionContext, IGameApiClient)
979
+
980
+ ```csharp
981
+ using System;
982
+ using System.Globalization;
983
+ using Microsoft.Extensions.Logging;
984
+ using Unity.Services.CloudCode.Apis;
985
+ using Unity.Services.CloudCode.Core;
986
+
987
+ public class MyModule
988
+ {
989
+ readonly IGameApiClient m_GameApiClient;
990
+ readonly ILogger<MyModule> m_Logger;
991
+
992
+ public MyModule(IGameApiClient gameApiClient, ILogger<MyModule> logger)
993
+ {
994
+ m_GameApiClient = gameApiClient;
995
+ m_Logger = logger;
996
+ }
997
+
998
+ // No context needed -- pure computation.
999
+ [CloudCodeFunction("SayHello")]
1000
+ public string SayHello(string name) => $"Hello, {name}!";
1001
+
1002
+ // Add IExecutionContext as a method parameter only when you need player/project info.
1003
+ [CloudCodeFunction("GetServerTime")]
1004
+ public string GetServerTime(IExecutionContext context)
1005
+ => DateTime.UtcNow.ToString(CultureInfo.InvariantCulture);
1006
+ }
1007
+ ```
1008
+
1009
+ **Key concepts:**
1010
+
1011
+ | File / Concept | Purpose |
1012
+ |---|---|
1013
+ | `[CloudCodeFunction]` | Marks a public method as a callable endpoint |
1014
+ | `IExecutionContext` | Optional method parameter -- player ID, project ID, service token |
1015
+ | `IGameApiClient` | Constructor-injected via DI -- typed clients for UGS APIs |
1016
+ | `ModuleSetup.cs` | Registers `GameApiClient` via `ICloudCodeSetup` -- required once per module |
1017
+ | `FolderProfile.pubxml` | Publish profile targeting `linux-x64` -- Cloud Code runs on Linux |
1018
+ | `IsPublishable=false` | Prevents test project from being included in `dotnet publish` |
1019
+
1020
+ **Dependency injection:** `IGameApiClient` and `ILogger<T>` are constructor-injected. `IExecutionContext` is a method parameter (only add it when the function needs player/project info).
1021
+
1022
+ ### Test Project `.csproj` (IsPublishable=false)
1023
+
1024
+ `IsPublishable=false` is enforced in two ways: this property, and the omission of `Release Build.0` in the `.sln`. Both are intentional.
1025
+
1026
+ ```xml
1027
+ <Project Sdk="Microsoft.NET.Sdk">
1028
+
1029
+ <PropertyGroup>
1030
+ <TargetFramework>net8.0</TargetFramework>
1031
+ <LangVersion>latest</LangVersion>
1032
+ <ImplicitUsings>enable</ImplicitUsings>
1033
+ <Nullable>enable</Nullable>
1034
+ <IsPackable>false</IsPackable>
1035
+ <IsPublishable>false</IsPublishable>
1036
+ </PropertyGroup>
1037
+
1038
+ <ItemGroup>
1039
+ <PackageReference Include="coverlet.collector" Version="6.0.2" />
1040
+ <PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
1041
+ <PackageReference Include="NUnit" Version="4.2.2" />
1042
+ <PackageReference Include="NUnit.Analyzers" Version="4.4.0" />
1043
+ <PackageReference Include="NUnit3TestAdapter" Version="4.6.0" />
1044
+ </ItemGroup>
1045
+
1046
+ <ItemGroup>
1047
+ <Using Include="NUnit.Framework" />
1048
+ </ItemGroup>
1049
+
1050
+ <ItemGroup>
1051
+ <ProjectReference Include="..\MyModule\MyModule.csproj" />
1052
+ </ItemGroup>
1053
+
1054
+ </Project>
1055
+ ```
1056
+
1057
+ ### `.ccmr` File Format
1058
+
1059
+ ```json
1060
+ {
1061
+ "modulePath": "../../MyModuleCCM/MyModule.sln"
1062
+ }
1063
+ ```
1064
+
1065
+ Path is relative to the `.ccmr` file. `../../` goes up from `Assets/CloudCode/` to the project root, then into `MyModuleCCM/`. The filename without `.ccmr` (`MyModule`) is the module name used in `CallModuleEndpointAsync`.
1066
+
1067
+ ### Migrating a `.ccmr` to `.ccmu`
1068
+
1069
+ Create a `.ccmu` module and move each `[CloudCodeFunction]` class into its `Cloud/` folder. `[StateScope]`
1070
+ and the function bodies carry over unchanged, and so does constructor injection — with one exception. What
1071
+ changes:
1072
+
1073
+ | `.ccmr` | becomes |
1074
+ | :-- | :-- |
1075
+ | `.sln`, `.csproj`, `.pubxml`, test project | deleted -- Unity compiles the cloud assembly |
1076
+ | constructor-injected `IGameApiClient` / `ILogger<T>` | works as-is; the class needs exactly one public constructor |
1077
+ | constructor-injected `IExecutionContext` | **must move** to a `[CloudCodeService]` method parameter -- it is a scoped service and cannot be constructor-injected here |
1078
+ | bare `IExecutionContext` **method parameter** | same parameter, now marked `[CloudCodeService]` |
1079
+ | `ModuleSetup.cs` with `GameApiClient.Create()` | `CloudSetup.cs` with `config.AddGameApiClient()` |
1080
+
1081
+ NuGet `PackageReference`s do not survive either: a `.ccmu` compiles under Unity, so a dependency has to be
1082
+ available to the Editor. Keep the module name stable (name the cloud asmdef after the old `.ccmr`) so the deployed module keeps its name, and replace every
1083
+ `CallModuleEndpointAsync` call site with the new module's generated client.
1084
+
1085
+ ---
1086
+
1087
+ ## Code Templates
1088
+
1089
+ JavaScript scripts: maintain, deploy and call existing ones; write new server logic as a C# module.
1090
+
1091
+ ### Call a Script Endpoint
1092
+
1093
+ ```csharp
1094
+ using Unity.Services.CloudCode;
1095
+ using System.Collections.Generic;
1096
+
1097
+ var args = new Dictionary<string, object>
1098
+ {
1099
+ { "level", 5 },
1100
+ { "difficulty", "hard" }
1101
+ };
1102
+
1103
+ int reward = await CloudCodeService.Instance.CallEndpointAsync<int>("CalculateReward", args);
1104
+ Debug.Log($"Reward: {reward}");
1105
+ ```
1106
+
1107
+ ### Call a Cloud Code Module (`.ccmu`, generated client)
1108
+
1109
+ ```csharp
1110
+ // Cloud class PlayerProgress is [StateScope(Scope.Player)], so the client takes a player ID.
1111
+ var progress = new PlayerProgressClient(AuthenticationService.Instance.PlayerId);
1112
+ var result = await progress.AwardXp(50);
1113
+
1114
+ Debug.Log($"Total XP: {result.TotalXp}");
1115
+ ```
1116
+
1117
+ ### Call a Module Endpoint (Typed Result, raw)
1118
+
1119
+ For legacy `.ccmr` modules only. A `.ccmu` module is always called through its generated client, as above.
1120
+
1121
+ ```csharp
1122
+ // Module class name: "ProgressionModule", method: "AwardXp"
1123
+ var result = await CloudCodeService.Instance.CallModuleEndpointAsync<ProgressResult>(
1124
+ "ProgressionModule", "AwardXp",
1125
+ new Dictionary<string, object> { { "amount", 50 } });
1126
+ Debug.Log($"Total XP: {result.TotalXp}");
1127
+ ```
1128
+
1129
+ ### Subscribe to Player Messages (Full Example)
1130
+
1131
+ ```csharp
1132
+ ISubscriptionEvents subscription;
1133
+
1134
+ async Task SubscribeToMessages()
1135
+ {
1136
+ // Attach every handler before subscribing, so nothing can arrive unhandled.
1137
+ var callbacks = new SubscriptionEventCallbacks();
1138
+ callbacks.MessageReceived += OnMessageReceived;
1139
+ callbacks.ConnectionStateChanged += state =>
1140
+ Debug.Log($"Subscription state: {state}");
1141
+ callbacks.Error += error =>
1142
+ Debug.LogError($"Subscription error: {error}");
1143
+ callbacks.Kicked += () =>
1144
+ Debug.LogWarning("Kicked from subscription");
1145
+
1146
+ subscription = await CloudCodeService.Instance.SubscribeToPlayerMessagesAsync(callbacks);
1147
+ }
1148
+
1149
+ void OnMessageReceived(IMessageReceivedEvent evt)
1150
+ {
1151
+ Debug.Log($"[{evt.MessageType}] {evt.Message}");
1152
+ // var data = JsonUtility.FromJson<MyPayload>(evt.Message);
1153
+ }
1154
+
1155
+ async Task Unsubscribe()
1156
+ {
1157
+ await subscription.UnsubscribeAsync();
1158
+ subscription = null;
1159
+ }
1160
+ ```
1161
+
1162
+ ---
1163
+
1164
+ ## Deploying via the Deployment Window
1165
+
1166
+ 1. Open **Services > Deployment** in the Unity Editor.
1167
+ 2. All `.js`, `.ccmu` and `.ccmr` files under `Assets/` are listed. **Select only what you mean to deploy**
1168
+ -- deploying everything can overwrite modules that are not ready to go out.
1169
+ 3. A `.ccmu` deploys the compiled cloud assembly, under the **cloud asmdef's name**. Its client bindings
1170
+ already exist -- they were generated when Unity compiled the module, so there is nothing to regenerate.
1171
+ 4. A `.ccmr` builds and publishes its solution. After it deploys, generate or regenerate its bindings
1172
+ (see [Generated Client Bindings](#generated-client-bindings)).
1173
+
1174
+ **The local Cloud Code server never deploys during play mode.** Entering play mode does not deploy modules to
1175
+ it, and nothing is deployed to it while the Editor is in play mode. Edit and deploy in edit mode, then
1176
+ enter play mode. Changes made during play mode do not reach the local server until you exit play mode and
1177
+ deploy again.
1178
+
1179
+ A `.ccmu` deploy fails with **"Unsupported API Compatibility Level"** unless the project's Player Settings
1180
+ have Api Compatibility Level on `.NET Standard 2.1`. It also fails if the project has compile errors --
1181
+ the module is deployed from its compiled assembly, so it has to build first.
1182
+
1183
+ **Deploying a `.ccmu` needs a running Editor.** Nothing packages a `.ccmu` outside the Editor, and
1184
+ `unity ugs deploy` skips `.ccmu` (see `references/ugs-cli.md`), so a CI pipeline that deploys `.ccmu` modules has
1185
+ to run the Editor. Only legacy `.ccmr` modules deploy without one, through their `.sln`; do not create a
1186
+ `.ccmr` to get around this.
1187
+
1188
+ **Local development needs no deploy.** While the local Cloud Code server runs (Cloud Code button on the
1189
+ Editor toolbar > **Start Local Server**; it needs an active environment), each successful compile redeploys
1190
+ changed `.ccmu` modules onto it, outside Play mode. **Nothing deploys to the local server during Play mode**,
1191
+ not even an explicit deploy, which is refused: exit Play mode before recompiling and deploying. A
1192
+ `404 function-not-found` for an endpoint added while playing means exactly this; exiting Play mode redeploys
1193
+ it and logs `Local Cloud Code server reloaded`.
1194
+
1195
+ **Known limitation.** An unfocused Editor doesn't notice file edits or run the local auto-deploy until it
1196
+ regains focus. After editing module code without focusing the Editor, run `unity command recompile`, then
1197
+ deploy with the `Deploy.cs` script from
1198
+ `references/deployment.md`: while the local
1199
+ server runs, the deploy targets it, not the environment. Stop the server before deploying remotely.
1200
+
1201
+ To deploy without the window, run the deploy script in
1202
+ the Trigger Deployment Programmatically section of `references/deployment.md`.
1203
+
1204
+ ---
1205
+
1206
+ ## Running the Local Cloud Code Server
1207
+
1208
+ The local server runs the project's modules in a process on this machine, and the SDK routes
1209
+ `CallModuleEndpointAsync` to it instead of the cloud. Start and stop it with the Cloud Code button on the
1210
+ Editor toolbar (**Start Local Server** / **Stop Local Server**), outside Play mode; it needs Unity 6000.3+.
1211
+ Redeploy on compile, and what to do when the Editor is unfocused, are covered in
1212
+ [Deploying via the Deployment Window](#deploying-via-the-deployment-window).
1213
+
1214
+ The server listens on port **14750** by default. To run several Editors, each with its own local server,
1215
+ give each project a distinct port in **Edit > Project Settings > Services > Cloud Code > Local Debugging >
1216
+ Port** while its server is stopped; a port already in use fails startup with *"Server Port <port> is not
1217
+ available."*
1218
+ Play mode reads the port and whether a server is running from Editor preferences shared by every Editor on
1219
+ the machine, so calls go to the most recently started server, and stopping any Editor's server sends the
1220
+ others' calls to the cloud.
1221
+
1222
+ ### It will not start until an active environment is set
1223
+
1224
+ Startup validates the environment first, and a project with no active environment fails with:
1225
+
1226
+ > Cannot start the local Cloud Code server. The environment has not been set. Please use the Environment
1227
+ > Selector, found under Edit → Project Settings → Services → Environments, to set it.
1228
+
1229
+ A fresh clone or a CI checkout has no active environment, so this is usually the first thing that fails.
1230
+ Set one in **Edit > Project Settings > Services > Environments** (ask the user, or drive the Editor UI).
1231
+
1232
+ ---
1233
+
1234
+ ## Error Handling
1235
+
1236
+ ```csharp
1237
+ try
1238
+ {
1239
+ var result = await client.MyFunction(arg);
1240
+ }
1241
+ catch (CloudCodeRateLimitedException ex)
1242
+ {
1243
+ Debug.LogError($"Rate limited. Retry after {ex.RetryAfter}s");
1244
+ }
1245
+ catch (CloudCodeException ex)
1246
+ {
1247
+ Debug.LogError($"Cloud Code error: {ex.Message} (reason: {ex.Reason})");
1248
+ }
1249
+ ```
1250
+
1251
+ ### `CloudCodeExceptionReason` Enum
1252
+
1253
+ Read the `CloudCodeExceptionReason` API reference for the installed package before writing a handler that
1254
+ branches on `ex.Reason`, because the set of reasons changes between package versions:
1255
+
1256
+ `https://docs.unity3d.com/Packages/com.unity.services.cloudcode@<VERSION>/api/Unity.Services.CloudCode.CloudCodeExceptionReason.html`
1257
+
1258
+ Take `<VERSION>` from the installed `com.unity.services.cloudcode` version in
1259
+ `Packages/packages-lock.json` (for `3.0.0`, use `3.0`). That file lists the package even when it arrives as
1260
+ a dependency of another package, which `Packages/manifest.json` does not. If a reason the code needs is missing from that page, the installed version does not
1261
+ have it.
1262
+
1263
+ ---
1264
+
1265
+ ## Error Messages
1266
+
1267
+ | Error string | Cause | Fix |
1268
+ | :-- | :-- | :-- |
1269
+ | `Unsupported API Compatibility Level` | The project's Api Compatibility Level is not `.NET Standard 2.1` | Set it in Player Settings, then redeploy the `.ccmu` |
1270
+ | `Invalid constructor: type X must have exactly one public constructor` | The module class has no public constructor or several | Keep exactly one public constructor |
1271
+ | `Function's ... class in module ... requires a scope and must be called with a scope` | A `[StateScope]` function was called without a scope, or with the wrong one | Pass a `CloudCodeScope` that matches the class's `[StateScope]`, or use the generated client |
1272
+ | `This Cloud Code module's server Assembly Definition (.asmdef) is missing or misconfigured...` | The cloud asmdef is not Editor-only, has engine references, is auto-referenced, or lacks the Core and Apis references | Fix the asmdef, then create the script again |
1273
+ | `Assembly Failure -- Multiple CCMs reference the same assembly definition` | Two modules share one cloud assembly | Give each module its own cloud assembly |
1274
+ | `Server Port <port> is not available.` | Another process, often another Editor's local server, holds the port | Set a distinct port under Local Debugging > Port while the server is stopped |
1275
+ | `Cannot start the local Cloud Code server. The environment has not been set...` | The project has no active environment | Set one in **Edit > Project Settings > Services > Environments** |
1276
+ | `CloudCodeExecutionScopeStateException` | Persisted state no longer deserializes after an incompatible member change | Restore a compatible member type, or migrate with `IStateSerializer` |