@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,757 @@
1
+ # Achievements Reference
2
+
3
+ ## Table of Contents
4
+
5
+ - [Architecture Overview](#architecture-overview)
6
+ - [Data Models](#data-models)
7
+ - [API Notes](#api-notes)
8
+ - [Namespace Aliases](#namespace-aliases-required)
9
+ - [Access Class Options](#access-class-options-reference)
10
+ - [Bucket Selection](#bucket-selection)
11
+ - [Error Handling](#error-handling)
12
+ - [Load Definitions from Remote Config](#load-definitions-from-remote-config)
13
+ - [Load Player Records from Cloud Save](#load-player-records-from-cloud-save)
14
+ - [Save Player Records (Direct Write)](#save-player-records-direct-write)
15
+ - [Server-Authoritative Writes via Cloud Code](#server-authoritative-writes-via-cloud-code)
16
+ - [Full Client Implementation](#full-client-implementation)
17
+ - [Cloud Code Module](#cloud-code-module)
18
+ - [AchievementModule.cs](#achievementmodulecs)
19
+ - [Server-Side Model](#server-side-model)
20
+ - [Cloud Resources](#cloud-resources)
21
+ - [Deployment Checklist](#deployment-checklist)
22
+ - [Official Unity Reference](#official-unity-reference)
23
+ - [Validation](#validation)
24
+
25
+ ---
26
+
27
+ ## Architecture Overview
28
+
29
+ Achievements combine Remote Config (static definitions), Cloud Save (per-player progress), and Cloud Code (server-authoritative writes). An Access Control policy locks down direct client writes in production.
30
+
31
+ ### Service Mapping
32
+
33
+ | Concern | Service | Key / Endpoint |
34
+ |---|---|---|
35
+ | Achievement definitions | Remote Config | `"achievements"` key (JSON array) |
36
+ | Player records | Cloud Save (Protected or Public) | `"achievements"` key (JSON array) |
37
+ | Server-authoritative writes | Cloud Code Module | `AchievementModule` |
38
+ | Block direct writes | Access Control | `.ac` policy denying player Cloud Save writes |
39
+
40
+ ### Data Flow
41
+
42
+ ```
43
+ Remote Config Cloud Save
44
+ "achievements" key "achievements" key
45
+ ┌─────────────────┐ ┌─────────────────┐
46
+ │ AchievementDef- │ client │ AchievementRe- │
47
+ │ inition[] │───reads────────>│ cord[] │
48
+ │ │ │ │
49
+ │ Id │ │ Id │
50
+ │ Title │ │ Unlocked │
51
+ │ Description │ │ ProgressCount │
52
+ │ IsHidden │ │ │
53
+ │ ProgressTarget │ └────────┬────────┘
54
+ └─────────────────┘ │
55
+ two write paths
56
+ ┌──────────────┴──────────────┐
57
+ │ │
58
+ Direct Write Trusted Write
59
+ (dev / prototype) (production)
60
+ │ │
61
+ ▼ ▼
62
+ Cloud Save Cloud Code
63
+ PublicWriteAccess- "AchievementModule"
64
+ ClassOptions │
65
+ ▼
66
+ Cloud Save
67
+ SetProtectedItemAsync
68
+ (server token bypass)
69
+ ```
70
+
71
+ **Key principle:** In production, route all writes through the Cloud Code module. The Access Control `.ac` file denies direct player writes to the Protected bucket, so only the server can mutate achievement records.
72
+
73
+ ---
74
+
75
+ ## Data Models
76
+
77
+ ### AchievementDefinition (client-side)
78
+
79
+ Stored in Remote Config as a JSON array under the `"achievements"` key. Read-only from the client.
80
+
81
+ ```csharp
82
+ using System;
83
+
84
+ [Serializable]
85
+ public class AchievementDefinition
86
+ {
87
+ public string Id;
88
+ public string Title;
89
+ public string Description;
90
+ public bool IsHidden;
91
+ public int ProgressTarget; // <= 1 = single unlock, > 1 = multi-stage
92
+ }
93
+ ```
94
+
95
+ | Field | Type | Description |
96
+ |---|---|---|
97
+ | `Id` | `string` | Unique identifier (e.g. `"first_win"`) |
98
+ | `Title` | `string` | Display name shown to the player |
99
+ | `Description` | `string` | What the player must do |
100
+ | `IsHidden` | `bool` | If true, hide until unlocked (secret achievements) |
101
+ | `ProgressTarget` | `int` | Target count for multi-stage achievements; 0 or 1 = single unlock |
102
+
103
+ ### AchievementRecord (defined once, in the cloud assembly)
104
+
105
+ Stored in Cloud Save as a JSON array under the `"achievements"` key. Define it once, in `AchievementModule.cs` (see [Server-Side Model](#server-side-model)), as a class of public settable members. The source generator emits a data-only stub of the same name and namespace, `AchievementModule.Cloud.AchievementRecord`, into the client assembly, so client code uses that type and never declares its own copy. `Id` matches `AchievementDefinition.Id`; `ProgressCount` is the current progress toward `ProgressTarget`.
106
+
107
+ ---
108
+
109
+ ## API Notes
110
+
111
+ ### Namespace Aliases (Required)
112
+
113
+ Cloud Save has identically named option classes at different namespace levels. Always use these
114
+ aliases to avoid ambiguity:
115
+
116
+ ```csharp
117
+ using PlayerLoadOptions = Unity.Services.CloudSave.Models.Data.Player.LoadOptions;
118
+ using PlayerSaveOptions = Unity.Services.CloudSave.Models.Data.Player.SaveOptions;
119
+ using PlayerDeleteOptions = Unity.Services.CloudSave.Models.Data.Player.DeleteOptions;
120
+ ```
121
+
122
+ Without these aliases, the compiler will report ambiguous type references.
123
+
124
+ ### Access Class Options Reference
125
+
126
+ | Class | Read | Write | Use case |
127
+ |---|---|---|---|
128
+ | `DefaultWriteAccessClassOptions` / `DefaultReadAccessClassOptions` | Owner only | Owner only | Private player data |
129
+ | `PublicReadAccessClassOptions(playerId)` / `PublicWriteAccessClassOptions` | Anyone | Owner + server | Achievements, scores, public profiles |
130
+ | `ProtectedReadAccessClassOptions` | Owner only | Server only (Cloud Code) | Anti-cheat, server-awarded state |
131
+
132
+ ### Bucket Selection
133
+
134
+ The read access class **must** match the bucket that was written to. Cloud Save has three
135
+ separate buckets — Default, Public, and Protected. Data written to one bucket is **invisible**
136
+ when reading from another.
137
+
138
+ - **Trusted path** (Cloud Code `SetProtectedItemAsync`) — data lands in the **Protected** bucket — read with `ProtectedReadAccessClassOptions()`
139
+ - **Direct path** (`PublicWriteAccessClassOptions`) — data lands in the **Public** bucket — read with `PublicReadAccessClassOptions(playerId)`
140
+
141
+ > **Common mistake:** Switching from direct writes to trusted writes (or vice versa) without
142
+ > updating the read access class. The data appears to vanish — it's still there, just in
143
+ > the other bucket.
144
+
145
+ ### Error Handling
146
+
147
+ Cloud Code and Cloud Save errors surface as typed exceptions on the client:
148
+
149
+ ```csharp
150
+ try
151
+ {
152
+ await m_Client.UnlockAchievement("first_win");
153
+ }
154
+ catch (CloudCodeException ex)
155
+ {
156
+ // ex.Reason: CloudCodeExceptionReason (e.g. ScriptError for module-thrown exceptions)
157
+ Debug.LogError($"[Achievements] Cloud Code error: {ex.Reason} — {ex.Message}");
158
+ }
159
+ catch (CloudSaveException ex)
160
+ {
161
+ // ex.Reason: CloudSaveExceptionReason
162
+ // A 403 on the Protected bucket means the client attempted a direct write —
163
+ // all writes must go through the Cloud Code module when Access Control is deployed.
164
+ Debug.LogError($"[Achievements] Cloud Save error: {ex.Reason} — {ex.Message}");
165
+ }
166
+ ```
167
+
168
+ | Error | Cause | Fix |
169
+ | :-- | :-- | :-- |
170
+ | `CloudCodeException` with reason `ScriptError` | The module threw, for example on a failed validation | Read `ex.Message`, then correct the arguments or the player's state |
171
+ | `CloudSaveException` with a `403` | The client attempted a direct write to the Protected bucket | Route the write through the Cloud Code module |
172
+
173
+ ---
174
+
175
+ ## Load Definitions from Remote Config
176
+
177
+ Fetch the `"achievements"` Remote Config key and deserialize the JSON array into a list of definitions.
178
+
179
+ ```csharp
180
+ using Unity.Services.RemoteConfig;
181
+ using Newtonsoft.Json.Linq;
182
+ using System.Collections.Generic;
183
+ using System.Threading.Tasks;
184
+
185
+ struct UserAttributes {}
186
+ struct AppAttributes {}
187
+
188
+ async Task<List<AchievementDefinition>> LoadDefinitionsAsync()
189
+ {
190
+ var result = await RemoteConfigService.Instance.FetchConfigsAsync(
191
+ new UserAttributes(), new AppAttributes());
192
+
193
+ var token = result.config["achievements"];
194
+ return token.ToObject<List<AchievementDefinition>>();
195
+ }
196
+ ```
197
+
198
+ ---
199
+
200
+ ## Load Player Records from Cloud Save
201
+
202
+ **CRITICAL -- bucket selection:** The read access class must match the bucket that was written to.
203
+
204
+ - **Trusted path (production):** The Cloud Code module writes to the **Protected** bucket. The client reads with `ProtectedReadAccessClassOptions()`.
205
+ - **Direct path (dev only):** The client writes to the **Public** bucket. The client reads with `PublicReadAccessClassOptions(playerId)`.
206
+
207
+ If you read from the wrong bucket, the data will appear empty.
208
+
209
+ ```csharp
210
+ using System.Collections.Generic;
211
+ using System.Threading.Tasks;
212
+ using Newtonsoft.Json;
213
+ using Unity.Services.CloudSave;
214
+ using Unity.Services.CloudSave.Models.Data.Player;
215
+ using PlayerLoadOptions = Unity.Services.CloudSave.Models.Data.Player.LoadOptions;
216
+
217
+ async Task<List<AchievementRecord>> LoadRecordsAsync(string playerId, bool useTrustedWrites)
218
+ {
219
+ // Read from whichever bucket was written to -- Protected (trusted) or Public (direct).
220
+ ReadAccessClassOptions accessClass = useTrustedWrites
221
+ ? new ProtectedReadAccessClassOptions()
222
+ : new PublicReadAccessClassOptions(playerId);
223
+
224
+ var result = await CloudSaveService.Instance.Data.Player.LoadAsync(
225
+ new HashSet<string> { "achievements" },
226
+ new PlayerLoadOptions(accessClass));
227
+
228
+ if (!result.TryGetValue("achievements", out var item))
229
+ return new List<AchievementRecord>();
230
+
231
+ return JsonConvert.DeserializeObject<List<AchievementRecord>>(item.Value.GetAsString());
232
+ }
233
+ ```
234
+
235
+ **`ProtectedReadAccessClassOptions`** — reads the current player's own Protected data (no player ID parameter; always reads self).
236
+
237
+ **`PublicReadAccessClassOptions(playerId)`** — reads another player's Public data. Pass `AuthenticationService.Instance.PlayerId` for the current player.
238
+
239
+ ---
240
+
241
+ ## Save Player Records (Direct Write)
242
+
243
+ Direct writes use the **Public** access class. This path is for development and prototyping only -- in production, deploy an Access Control policy to block direct player writes and route everything through Cloud Code.
244
+
245
+ ```csharp
246
+ using System.Collections.Generic;
247
+ using System.Threading.Tasks;
248
+ using Newtonsoft.Json;
249
+ using Unity.Services.CloudSave;
250
+ using Unity.Services.CloudSave.Models;
251
+ using Unity.Services.CloudSave.Models.Data.Player;
252
+ using PlayerSaveOptions = Unity.Services.CloudSave.Models.Data.Player.SaveOptions;
253
+
254
+ async Task SaveRecordsAsync(List<AchievementRecord> records)
255
+ {
256
+ var json = JsonConvert.SerializeObject(records);
257
+ await CloudSaveService.Instance.Data.Player.SaveAsync(
258
+ new Dictionary<string, SaveItem>
259
+ {
260
+ { "achievements", new SaveItem(json, null) }
261
+ },
262
+ new PlayerSaveOptions(new PublicWriteAccessClassOptions()));
263
+ }
264
+ ```
265
+
266
+ ---
267
+
268
+ ## Server-Authoritative Writes via Cloud Code
269
+
270
+ In production, route all mutations through Cloud Code module endpoints. The module uses its service token to write to the Protected bucket, bypassing Access Control restrictions that block the player client.
271
+
272
+ The module's endpoints are `UnlockAchievement(achievementId)`, `UpdateAchievementProgress(achievementId, count)` and `ResetAchievements()`. The client calls them through the generated `AchievementModuleClient`, as in the client implementation below: `await m_Client.UnlockAchievement(id)`. `count` is the amount to add, not the new total.
273
+
274
+ ### Delete / Reset Player Records (Direct)
275
+
276
+ ```csharp
277
+ await CloudSaveService.Instance.Data.Player.DeleteAsync(
278
+ "achievements",
279
+ new PlayerDeleteOptions(new PublicWriteAccessClassOptions()));
280
+ ```
281
+
282
+ ---
283
+
284
+ ## Full Client Implementation
285
+
286
+ Complete `AchievementManager` MonoBehaviour with dual-path support (trusted vs direct writes).
287
+
288
+ ```csharp
289
+ using System;
290
+ using System.Collections.Generic;
291
+ using System.Linq;
292
+ using System.Threading.Tasks;
293
+ using AchievementModule.Client;
294
+ using AchievementModule.Cloud;
295
+ using Newtonsoft.Json;
296
+ using Unity.Services.Authentication;
297
+ using Unity.Services.CloudSave;
298
+ using Unity.Services.CloudSave.Models;
299
+ using Unity.Services.CloudSave.Models.Data.Player;
300
+ using PlayerSaveOptions = Unity.Services.CloudSave.Models.Data.Player.SaveOptions;
301
+ using PlayerLoadOptions = Unity.Services.CloudSave.Models.Data.Player.LoadOptions;
302
+ using PlayerDeleteOptions = Unity.Services.CloudSave.Models.Data.Player.DeleteOptions;
303
+ using Unity.Services.Core;
304
+ using Unity.Services.RemoteConfig;
305
+ using UnityEngine;
306
+
307
+ public class AchievementManager : MonoBehaviour
308
+ {
309
+ // Set to true to route writes through Cloud Code (required if Access Control is deployed).
310
+ // Set to false for direct Cloud Save writes (development only).
311
+ [SerializeField] bool m_UseTrustedWrites = true;
312
+
313
+ AchievementModuleClient m_Client;
314
+
315
+ public List<AchievementDefinition> Definitions { get; private set; } = new();
316
+ public List<AchievementRecord> Records { get; private set; } = new();
317
+
318
+ public event Action<AchievementDefinition> AchievementUnlocked;
319
+ public event Action Loaded;
320
+
321
+ async void Start()
322
+ {
323
+ await UnityServices.InitializeAsync();
324
+ await AuthenticationService.Instance.SignInAnonymouslyAsync();
325
+ m_Client = new AchievementModuleClient();
326
+ await LoadAsync();
327
+ Loaded?.Invoke();
328
+ }
329
+
330
+ // -- Load ------------------------------------------------------------------
331
+
332
+ public async Task LoadAsync()
333
+ {
334
+ Definitions = await LoadDefinitionsAsync();
335
+ Records = await LoadRecordsAsync(AuthenticationService.Instance.PlayerId);
336
+ }
337
+
338
+ struct UserAttributes {}
339
+ struct AppAttributes {}
340
+
341
+ async Task<List<AchievementDefinition>> LoadDefinitionsAsync()
342
+ {
343
+ var result = await RemoteConfigService.Instance.FetchConfigsAsync(
344
+ new UserAttributes(), new AppAttributes());
345
+
346
+ var token = result.config["achievements"];
347
+ return token.ToObject<List<AchievementDefinition>>();
348
+ }
349
+
350
+ async Task<List<AchievementRecord>> LoadRecordsAsync(string playerId)
351
+ {
352
+ // Read from whichever bucket was written to -- Protected (trusted) or Public (direct).
353
+ ReadAccessClassOptions accessClass = m_UseTrustedWrites
354
+ ? new ProtectedReadAccessClassOptions()
355
+ : new PublicReadAccessClassOptions(playerId);
356
+
357
+ var result = await CloudSaveService.Instance.Data.Player.LoadAsync(
358
+ new HashSet<string> { "achievements" },
359
+ new PlayerLoadOptions(accessClass));
360
+
361
+ if (!result.TryGetValue("achievements", out var item))
362
+ return new List<AchievementRecord>();
363
+
364
+ return JsonConvert.DeserializeObject<List<AchievementRecord>>(item.Value.GetAsString());
365
+ }
366
+
367
+ // -- Unlock ----------------------------------------------------------------
368
+
369
+ public async Task UnlockAsync(string achievementId)
370
+ {
371
+ var def = Definitions.FirstOrDefault(d => d.Id == achievementId);
372
+ if (def == null)
373
+ {
374
+ Debug.LogWarning($"[Achievements] Unknown achievement: {achievementId}");
375
+ return;
376
+ }
377
+
378
+ var record = GetOrCreateRecord(achievementId);
379
+ if (record.Unlocked)
380
+ return;
381
+
382
+ if (m_UseTrustedWrites)
383
+ {
384
+ // Server validates and writes -- bypasses Access Control restrictions.
385
+ await m_Client.UnlockAchievement(achievementId);
386
+ }
387
+ else
388
+ {
389
+ record.Unlocked = true;
390
+ await SaveRecordsAsync(Records);
391
+ }
392
+
393
+ record.Unlocked = true;
394
+ AchievementUnlocked?.Invoke(def);
395
+ Debug.Log($"[Achievements] Unlocked: {def.Title}");
396
+ }
397
+
398
+ // -- Progress (multi-stage) ------------------------------------------------
399
+
400
+ public async Task AddProgressAsync(string achievementId, int amount)
401
+ {
402
+ var def = Definitions.FirstOrDefault(d => d.Id == achievementId);
403
+ if (def == null || def.ProgressTarget <= 1)
404
+ return;
405
+
406
+ var record = GetOrCreateRecord(achievementId);
407
+ if (record.Unlocked)
408
+ return;
409
+
410
+ var newCount = record.ProgressCount + amount;
411
+
412
+ if (m_UseTrustedWrites)
413
+ {
414
+ await m_Client.UpdateAchievementProgress(achievementId, amount);
415
+ }
416
+ else
417
+ {
418
+ record.ProgressCount = newCount;
419
+ await SaveRecordsAsync(Records);
420
+ }
421
+
422
+ record.ProgressCount = newCount;
423
+
424
+ if (record.ProgressCount >= def.ProgressTarget)
425
+ await UnlockAsync(achievementId);
426
+ }
427
+
428
+ // -- Reset -----------------------------------------------------------------
429
+
430
+ public async Task ResetAsync()
431
+ {
432
+ await CloudSaveService.Instance.Data.Player.DeleteAsync(
433
+ "achievements",
434
+ new PlayerDeleteOptions(new PublicWriteAccessClassOptions()));
435
+
436
+ Records.Clear();
437
+ }
438
+
439
+ // -- Helpers ---------------------------------------------------------------
440
+
441
+ AchievementRecord GetOrCreateRecord(string id)
442
+ {
443
+ var record = Records.FirstOrDefault(r => r.Id == id);
444
+ if (record == null)
445
+ {
446
+ record = new AchievementRecord { Id = id };
447
+ Records.Add(record);
448
+ }
449
+ return record;
450
+ }
451
+
452
+ async Task SaveRecordsAsync(List<AchievementRecord> records)
453
+ {
454
+ var json = JsonConvert.SerializeObject(records);
455
+ await CloudSaveService.Instance.Data.Player.SaveAsync(
456
+ new Dictionary<string, SaveItem>
457
+ {
458
+ { "achievements", new SaveItem(json, null) }
459
+ },
460
+ new PlayerSaveOptions(new PublicWriteAccessClassOptions()));
461
+ }
462
+ }
463
+ ```
464
+
465
+ ---
466
+
467
+ ## Cloud Code Module
468
+
469
+ The `AchievementModule` reads and writes to the **Protected** Cloud Save bucket using its service token, bypassing Access Control restrictions imposed on the player client.
470
+
471
+ > **Create the module with the Editor, not by hand.** Right-click a folder under `Assets/` ->
472
+ > **Create > Services > Cloud Code Module Script** and name it `AchievementModule`. See
473
+ > the Creating a Cloud Code Module section of `references/cloud-code-modules.md`.
474
+ >
475
+ > The Editor generates the following. Use the list to check what you got — there is nothing here to
476
+ > type out, and no `.sln`, `.csproj`, `.pubxml` or test project:
477
+ >
478
+ > - [ ] `Assets/CloudCode/AchievementModule/AchievementModule.ccmu` (holds the two asmdef GUIDs)
479
+ > - [ ] `Cloud/AchievementModule.asmdef` — Editor-only, `noEngineReferences`, `autoReferenced: false`
480
+ > - [ ] `Cloud/AchievementModule.cs` — rename/replace with the `[CloudCodeFunction]` endpoints below
481
+ > - [ ] `Client/AchievementModuleClient.asmdef` — references the cloud assembly
482
+ > - [ ] `Client/AchievementModuleClient.cs` — `[CloudModuleClient(typeof(AchievementModule))]` partial
483
+ >
484
+ > One file the Editor does **not** generate, which this module needs because its endpoints inject
485
+ > `IGameApiClient`:
486
+ >
487
+ > - [ ] `Cloud/CloudSetup.cs` — an `ICloudCodeSetup` calling `config.AddGameApiClient()`
488
+ > - [ ] `Newtonsoft.Json.dll` added to `precompiledReferences` in `Cloud/AchievementModule.asmdef` — the generated asmdef ships that array empty, and this module's code uses `JsonConvert` (see `references/cloud-code-modules.md`)
489
+ >
490
+ > The deployed module name is the **cloud asmdef's name** (`AchievementModule`), not the `.ccmu` filename.
491
+ >
492
+ > The client calls the module through the generated `AchievementModuleClient`. The assembly that holds `AchievementManager` must reference the module's client assembly; the Editor creates it auto-referenced, so the default game assembly already does.
493
+
494
+ ### AchievementModule.cs
495
+
496
+ ```csharp
497
+ using System.Collections.Generic;
498
+ using System.Linq;
499
+ using System.Threading.Tasks;
500
+ using Newtonsoft.Json;
501
+ using Unity.Services.CloudCode.Apis;
502
+ using Unity.Services.CloudCode.Core;
503
+ using Unity.Services.CloudSave.Model;
504
+
505
+ namespace AchievementModule.Cloud
506
+ {
507
+ // Each public method decorated with [CloudCodeFunction] becomes a callable endpoint.
508
+ // Injected services are method parameters marked [CloudCodeService]. Without the attribute a
509
+ // parameter leaks into the generated client binding as an argument the caller must supply.
510
+ public class AchievementModule
511
+ {
512
+ const string AchievementsKey = "achievements";
513
+
514
+ [CloudCodeFunction("UnlockAchievement")]
515
+ public async Task<AchievementRecord> UnlockAchievement(
516
+ [CloudCodeService] IExecutionContext context, [CloudCodeService] IGameApiClient client, string achievementId)
517
+ {
518
+ var records = await LoadRecordsAsync(context, client);
519
+
520
+ var record = records.FirstOrDefault(r => r.Id == achievementId);
521
+ if (record == null)
522
+ {
523
+ record = new AchievementRecord { Id = achievementId, Unlocked = true };
524
+ records.Add(record);
525
+ }
526
+ else
527
+ {
528
+ record.Unlocked = true;
529
+ }
530
+
531
+ await SaveRecordsAsync(context, client, records);
532
+ return record;
533
+ }
534
+
535
+ [CloudCodeFunction("UpdateAchievementProgress")]
536
+ public async Task<AchievementRecord> UpdateAchievementProgress(
537
+ [CloudCodeService] IExecutionContext context, [CloudCodeService] IGameApiClient client, string achievementId, int count)
538
+ {
539
+ var records = await LoadRecordsAsync(context, client);
540
+
541
+ var record = records.FirstOrDefault(r => r.Id == achievementId);
542
+ if (record == null)
543
+ {
544
+ record = new AchievementRecord { Id = achievementId, ProgressCount = count };
545
+ records.Add(record);
546
+ }
547
+ else
548
+ {
549
+ record.ProgressCount += count;
550
+ }
551
+
552
+ await SaveRecordsAsync(context, client, records);
553
+ return record;
554
+ }
555
+
556
+ [CloudCodeFunction("ResetAchievements")]
557
+ public async Task ResetAchievements([CloudCodeService] IExecutionContext context, [CloudCodeService] IGameApiClient client)
558
+ {
559
+ // Uses ServiceToken so the write bypasses Access Control restrictions on the player client.
560
+ await client.CloudSaveData.DeleteProtectedItemAsync(
561
+ context, context.ServiceToken, AchievementsKey,
562
+ context.ProjectId, context.PlayerId!);
563
+ }
564
+
565
+ async Task<List<AchievementRecord>> LoadRecordsAsync(
566
+ IExecutionContext context, IGameApiClient client)
567
+ {
568
+ var result = await client.CloudSaveData.GetProtectedItemsAsync(
569
+ context, context.ServiceToken, context.ProjectId,
570
+ context.PlayerId, new List<string> { AchievementsKey });
571
+
572
+ var value = result.Data?.Results?.FirstOrDefault()?.Value?.ToString();
573
+ if (string.IsNullOrEmpty(value))
574
+ return new List<AchievementRecord>();
575
+
576
+ return JsonConvert.DeserializeObject<List<AchievementRecord>>(value);
577
+ }
578
+
579
+ async Task SaveRecordsAsync(
580
+ IExecutionContext context, IGameApiClient client, List<AchievementRecord> records)
581
+ {
582
+ var json = JsonConvert.SerializeObject(records);
583
+ var body = new SetItemBody(AchievementsKey, json);
584
+ await client.CloudSaveData.SetProtectedItemAsync(
585
+ context, context.ServiceToken, context.ProjectId, context.PlayerId, body);
586
+ }
587
+ }
588
+ }
589
+ ```
590
+
591
+ ### Server-Side Model
592
+
593
+ The single definition of the record, in `AchievementModule.cs`. Use public members with a public getter and setter, as the auto-properties below: the generator copies only those into the client stub, as `{ get; set; }` properties, and `Newtonsoft.Json` serializes them for the Cloud Save round-trip. Keep it in the module's `Cloud` namespace, and do not declare a second `AchievementRecord` in client code.
594
+
595
+ ```csharp
596
+ namespace AchievementModule.Cloud
597
+ {
598
+ public class AchievementRecord
599
+ {
600
+ public string Id { get; set; }
601
+ public bool Unlocked { get; set; }
602
+ public int ProgressCount { get; set; }
603
+ }
604
+ }
605
+ ```
606
+
607
+ ---
608
+
609
+ ## Cloud Resources
610
+
611
+ ### Package Setup -- `manifest.json`
612
+
613
+ Add these entries to your Unity project's `Packages/manifest.json` dependencies:
614
+
615
+ ```json
616
+ {
617
+ "dependencies": {
618
+ "com.unity.services.authentication": "3.6.1",
619
+ "com.unity.services.cloudcode": "3.0.0",
620
+ "com.unity.services.cloudsave": "3.4.0",
621
+ "com.unity.services.core": "1.16.0",
622
+ "com.unity.services.deployment": "1.7.2",
623
+ "com.unity.remote-config": "4.2.5",
624
+ "com.unity.services.tooling": "1.4.1"
625
+ }
626
+ }
627
+ ```
628
+
629
+ > `com.unity.services.cloudcode` **`3.0.0`** is the native-authoring line, which the `.ccmu` module
630
+ > below requires — see the Requirements section of `references/cloud-code-modules.md`. The `2.10.x` line
631
+ > deploys legacy `.ccmr` modules only; use it when maintaining one, not for new work.
632
+
633
+
634
+ The `com.unity.services.tooling` package is required for `.ac` file deployment. The `com.unity.services.deployment` package provides the Deployment Window. `Newtonsoft.Json` is provided as a transitive dependency and does not need an explicit entry.
635
+
636
+ ### Remote Config -- `Assets/Config/Achievements.rc`
637
+
638
+ Right-click in the Project window → **Assets > Create > Services > Remote Config**. Name the file `Achievements`. Replace the generated contents with:
639
+
640
+ ```json
641
+ {
642
+ "$schema": "https://ugs-config-schemas.unity3d.com/v1/remote-config.schema.json",
643
+ "entries": {
644
+ "achievements": [
645
+ {
646
+ "Id": "first_win",
647
+ "Title": "First Win",
648
+ "Description": "Win your first match.",
649
+ "IsHidden": false,
650
+ "ProgressTarget": 0
651
+ },
652
+ {
653
+ "Id": "kill_100_enemies",
654
+ "Title": "Centurion",
655
+ "Description": "Defeat 100 enemies.",
656
+ "IsHidden": false,
657
+ "ProgressTarget": 100
658
+ },
659
+ {
660
+ "Id": "secret_ending",
661
+ "Title": "???",
662
+ "Description": "Find the secret ending.",
663
+ "IsHidden": true,
664
+ "ProgressTarget": 0
665
+ }
666
+ ]
667
+ },
668
+ "types": {
669
+ "achievements": "JSON"
670
+ }
671
+ }
672
+ ```
673
+
674
+ **Rules:**
675
+
676
+ - `Id` must be unique across all achievements.
677
+ - `ProgressTarget <= 1` means single-unlock (call `UnlockAsync`).
678
+ - `ProgressTarget > 1` means multi-stage (call `AddProgressAsync`).
679
+ - `IsHidden = true` — show obfuscated title/description until unlocked.
680
+
681
+ Deploy via **Services > Deployment** — the Deployment Window auto-discovers `.rc` files under `Assets/`.
682
+
683
+ ### Cloud Code Module
684
+
685
+ > Create the module files listed in [Cloud Code Module](#cloud-code-module) above.
686
+ > See the Creating a Cloud Code Module section of `references/cloud-code-modules.md`
687
+ > for the generic templates; replace `MyModule` with `AchievementModule`.
688
+ >
689
+ > The `.ccmu` is deployed by the Deployment Window like any other cloud asset, but its code is compiled by
690
+ > Unity — a project that does not compile has nothing to deploy.
691
+
692
+ ### Access Control -- `Assets/Config/DenyPlayerCloudSaveWrites.ac`
693
+
694
+ Right-click in the Project window → **Assets > Create > Services > Access Control**. Name the file `DenyPlayerCloudSaveWrites`. Replace the generated contents with:
695
+
696
+ ```json
697
+ {
698
+ "$schema": "https://ugs-config-schemas.unity3d.com/v1/project-access-policy.schema.json",
699
+ "Statements": [
700
+ {
701
+ "Sid": "DenyPlayerCloudSaveWrites",
702
+ "Action": [
703
+ "Write"
704
+ ],
705
+ "Effect": "Deny",
706
+ "Principal": "Player",
707
+ "Resource": "urn:ugs:cloud-save:*",
708
+ "Version": "1.0.0"
709
+ }
710
+ ]
711
+ }
712
+ ```
713
+
714
+ **Effect:** With this policy active, `AchievementManager` must have `m_UseTrustedWrites = true`. Direct Cloud Save writes from the player client will return `403`.
715
+
716
+ **Without this policy:** `m_UseTrustedWrites = false` works fine — suitable for development or games where anti-cheat is not a concern.
717
+
718
+ Deploy via **Services > Deployment** alongside your other files.
719
+
720
+ ---
721
+
722
+ ## Deployment Checklist
723
+
724
+ Deploy all cloud resources via **Services > Deployment** before testing:
725
+
726
+ - [ ] All packages added to `Packages/manifest.json` with correct minimum versions
727
+ - [ ] `Assets/Config/Achievements.rc` -- Remote Config achievement definitions
728
+ - [ ] `Assets/Config/DenyPlayerCloudSaveWrites.ac` -- Access Control policy blocking direct player writes
729
+ - [ ] Cloud Code module authored as a `.ccmu`: module asset, `Cloud/` + `Client/` asmdefs, endpoint class, `CloudSetup.cs` (see file list in [Cloud Code Module](#cloud-code-module))
730
+ - [ ] `AchievementModule.cs` added to the module project with `UnlockAchievement`, `UpdateAchievementProgress`, `ResetAchievements` functions
731
+ - [ ] Environment selected in the Deployment Window dropdown
732
+ - [ ] All resources deployed via the Deployment Window
733
+ - [ ] Project linked in **Edit > Project Settings > Services**
734
+
735
+ ---
736
+
737
+ ## Official Unity Reference
738
+
739
+ - **Unity Cloud Save documentation:** https://docs.unity.com/en-us/cloud-save.md
740
+ - **Unity Remote Config documentation:** https://docs.unity.com/en-us/remote-config.md
741
+ - **Unity Cloud Code documentation:** https://docs.unity.com/en-us/cloud-code.md
742
+ - **Access Control documentation:** https://docs.unity.com/en-us/cloud-code/modules/how-to-guides/access-control.md
743
+
744
+ ---
745
+
746
+ ## Validation
747
+
748
+ After implementing achievements, verify:
749
+
750
+ 1. **Compilation:** The project compiles without errors. Ensure namespace aliases (`PlayerLoadOptions`, `PlayerSaveOptions`, `PlayerDeleteOptions`) are present.
751
+ 2. **Initialization order:** `UnityServices.InitializeAsync()` then `AuthenticationService.Instance.SignInAnonymouslyAsync()` then service calls.
752
+ 3. **Access class match:** If `m_UseTrustedWrites` is true, reads use `ProtectedReadAccessClassOptions()`. If false, reads use `PublicReadAccessClassOptions(playerId)`. Mismatched access classes return empty data.
753
+ 4. **Cloud Code module builds:** `AchievementModule` compiles as part of the Unity project — the Editor-only cloud assembly has no compile errors, and the project's Api Compatibility Level is `.NET Standard 2.1`.
754
+ 5. **One record definition:** `AchievementRecord` is declared only in the Cloud Code module, as `{ get; set; }` properties, and the client uses the generated stub of that type.
755
+ 6. **Access Control deployed:** The `.ac` file denies direct player writes to Cloud Save. Without this, the trusted-write path has no enforcement advantage.
756
+ 7. **Remote Config key matches:** The `.rc` file key (`"achievements"`) matches the key used in `result.config["achievements"]` on the client and `AchievementsKey` in the module.
757
+ 8. **All cloud resources deployable:** The `.rc`, `.ac`, and `.ccmu` files are in the `Assets/` folder hierarchy and appear in the Deployment Window.