summer-engine 3.1.0 → 3.2.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 (366) hide show
  1. package/.claude-plugin/marketplace.json +2 -2
  2. package/.claude-plugin/plugin.json +27 -5
  3. package/.codex-plugin/plugin.json +28 -6
  4. package/.cursor-plugin/plugin.json +27 -5
  5. package/.factory-plugin/plugin.json +27 -5
  6. package/.opencode/plugins/summer.js +1 -1
  7. package/CHANGELOG.md +102 -0
  8. package/README.md +18 -3
  9. package/assets/audit/scene_audit.gd +4136 -0
  10. package/assets/seeing/seeing_probe.gd +1873 -0
  11. package/dist/cli/commands/skills.js +20 -2
  12. package/dist/core/api-client.d.ts +9 -1
  13. package/dist/core/api-client.js +21 -4
  14. package/dist/core/capabilities/agent-playbook.js +46 -0
  15. package/dist/core/capabilities/audit/accept.d.ts +55 -0
  16. package/dist/core/capabilities/audit/accept.js +147 -0
  17. package/dist/core/capabilities/audit/args.d.ts +95 -0
  18. package/dist/core/capabilities/audit/args.js +89 -0
  19. package/dist/core/capabilities/audit/audit.d.ts +56 -0
  20. package/dist/core/capabilities/audit/audit.js +287 -0
  21. package/dist/core/capabilities/audit/frame.d.ts +14 -0
  22. package/dist/core/capabilities/audit/frame.js +35 -0
  23. package/dist/core/capabilities/audit/gaps.d.ts +96 -0
  24. package/dist/core/capabilities/audit/gaps.js +257 -0
  25. package/dist/core/capabilities/audit/judge.d.ts +162 -0
  26. package/dist/core/capabilities/audit/judge.js +1134 -0
  27. package/dist/core/capabilities/audit/math.d.ts +110 -0
  28. package/dist/core/capabilities/audit/math.js +263 -0
  29. package/dist/core/capabilities/audit/summary.d.ts +74 -0
  30. package/dist/core/capabilities/audit/summary.js +212 -0
  31. package/dist/core/capabilities/board.d.ts +31 -0
  32. package/dist/core/capabilities/board.js +43 -0
  33. package/dist/core/capabilities/camera-view.d.ts +4 -2
  34. package/dist/core/capabilities/camera-view.js +6 -3
  35. package/dist/core/capabilities/connect-signal.d.ts +85 -0
  36. package/dist/core/capabilities/connect-signal.js +285 -0
  37. package/dist/core/capabilities/engine-fallbacks.d.ts +5 -0
  38. package/dist/core/capabilities/engine-fallbacks.js +5 -0
  39. package/dist/core/capabilities/engine-ops.d.ts +5 -1
  40. package/dist/core/capabilities/engine-ops.js +0 -3
  41. package/dist/core/capabilities/engine-receipt.d.ts +12 -0
  42. package/dist/core/capabilities/engine-receipt.js +26 -0
  43. package/dist/core/capabilities/file-read.d.ts +64 -0
  44. package/dist/core/capabilities/file-read.js +325 -0
  45. package/dist/core/capabilities/game-task-plan.js +4 -2
  46. package/dist/core/capabilities/grep.d.ts +60 -0
  47. package/dist/core/capabilities/grep.js +190 -0
  48. package/dist/core/capabilities/inspect-node.d.ts +56 -0
  49. package/dist/core/capabilities/inspect-node.js +225 -0
  50. package/dist/core/capabilities/inspect-resource.d.ts +61 -0
  51. package/dist/core/capabilities/inspect-resource.js +376 -0
  52. package/dist/core/capabilities/math3d.d.ts +28 -0
  53. package/dist/core/capabilities/math3d.js +88 -0
  54. package/dist/core/capabilities/motion-generation.d.ts +62 -0
  55. package/dist/core/capabilities/motion-generation.js +138 -0
  56. package/dist/core/capabilities/placement-batch.d.ts +102 -0
  57. package/dist/core/capabilities/placement-batch.js +483 -0
  58. package/dist/core/capabilities/placement-math.d.ts +70 -0
  59. package/dist/core/capabilities/placement-math.js +209 -0
  60. package/dist/core/capabilities/placement-script.d.ts +42 -0
  61. package/dist/core/capabilities/placement-script.js +1096 -0
  62. package/dist/core/capabilities/placement.d.ts +485 -0
  63. package/dist/core/capabilities/placement.js +1731 -0
  64. package/dist/core/capabilities/project-context.d.ts +33 -2
  65. package/dist/core/capabilities/project-context.js +87 -4
  66. package/dist/core/capabilities/replace-node.d.ts +91 -0
  67. package/dist/core/capabilities/replace-node.js +423 -0
  68. package/dist/core/capabilities/runtime-control.d.ts +18 -2
  69. package/dist/core/capabilities/runtime-control.js +67 -2
  70. package/dist/core/capabilities/scene-batch.d.ts +63 -0
  71. package/dist/core/capabilities/scene-batch.js +394 -0
  72. package/dist/core/capabilities/scene-readback.d.ts +36 -0
  73. package/dist/core/capabilities/scene-readback.js +54 -0
  74. package/dist/core/capabilities/seeing/args.d.ts +348 -0
  75. package/dist/core/capabilities/seeing/args.js +178 -0
  76. package/dist/core/capabilities/seeing/candidates.d.ts +127 -0
  77. package/dist/core/capabilities/seeing/candidates.js +282 -0
  78. package/dist/core/capabilities/seeing/math.d.ts +134 -0
  79. package/dist/core/capabilities/seeing/math.js +269 -0
  80. package/dist/core/capabilities/seeing/probe.d.ts +62 -0
  81. package/dist/core/capabilities/seeing/probe.js +188 -0
  82. package/dist/core/capabilities/seeing/scoring.d.ts +235 -0
  83. package/dist/core/capabilities/seeing/scoring.js +639 -0
  84. package/dist/core/capabilities/seeing/seeing.d.ts +233 -0
  85. package/dist/core/capabilities/seeing/seeing.js +1341 -0
  86. package/dist/core/capabilities/seeing/shot-store.d.ts +52 -0
  87. package/dist/core/capabilities/seeing/shot-store.js +204 -0
  88. package/dist/core/capabilities/surface-snap-mesh.d.ts +88 -0
  89. package/dist/core/capabilities/surface-snap-mesh.js +425 -0
  90. package/dist/core/capabilities/surface-snap.d.ts +77 -0
  91. package/dist/core/capabilities/surface-snap.js +461 -0
  92. package/dist/core/capabilities/tool-dispatch.js +231 -72
  93. package/dist/core/capabilities/tscn.d.ts +85 -0
  94. package/dist/core/capabilities/tscn.js +391 -0
  95. package/dist/core/capabilities/world-snapshot.d.ts +58 -0
  96. package/dist/core/capabilities/world-snapshot.js +150 -0
  97. package/dist/core/capability-skew.d.ts +5 -5
  98. package/dist/core/capability-skew.js +14 -6
  99. package/dist/core/headless/worker-engine-client.d.ts +1 -1
  100. package/dist/core/headless/worker-engine-client.js +2 -2
  101. package/dist/core/library-read.d.ts +37 -5
  102. package/dist/core/library-read.js +264 -33
  103. package/dist/core/library-search.d.ts +2 -2
  104. package/dist/installer/agent-config.js +5 -3
  105. package/dist/installer/agent-table.d.ts +16 -0
  106. package/dist/installer/agent-table.js +52 -17
  107. package/dist/mcp/server.js +9 -3
  108. package/dist/mcp/tools/asset-tools.js +21 -3
  109. package/dist/mcp/tools/audit-tools.d.ts +23 -0
  110. package/dist/mcp/tools/audit-tools.js +60 -0
  111. package/dist/mcp/tools/debug-tools.js +3 -1
  112. package/dist/mcp/tools/file-tools.js +17 -4
  113. package/dist/mcp/tools/generate-tools.js +74 -66
  114. package/dist/mcp/tools/library-tools.js +2 -0
  115. package/dist/mcp/tools/perception-tools.js +6 -19
  116. package/dist/mcp/tools/placement-tools.d.ts +24 -0
  117. package/dist/mcp/tools/placement-tools.js +91 -0
  118. package/dist/mcp/tools/project-tools.js +18 -15
  119. package/dist/mcp/tools/scene-tools.js +71 -83
  120. package/dist/mcp/tools/seeing-tools.d.ts +24 -0
  121. package/dist/mcp/tools/seeing-tools.js +64 -0
  122. package/dist/mcp/tools/spatial-tools.js +17 -9
  123. package/dist/mcp/tools/visual-tools.js +59 -7
  124. package/gemini-extension.json +26 -4
  125. package/integrations/amp/README.md +1 -1
  126. package/integrations/crush/README.md +1 -1
  127. package/integrations/grok-build/README.md +1 -1
  128. package/integrations/hermes/README.md +1 -1
  129. package/integrations/kimi-code/README.md +1 -1
  130. package/integrations/mistral-vibe/README.md +1 -1
  131. package/integrations/opencode/README.md +1 -1
  132. package/integrations/rovo-dev/README.md +1 -1
  133. package/integrations/vscode-copilot/README.md +1 -1
  134. package/integrations/warp/README.md +1 -1
  135. package/integrations/windsurf/README.md +1 -1
  136. package/library/references/mcp-tools-reference/mcp-tools-reference.md +59 -15
  137. package/library/references/mcp-tools-reference/resource.yaml +1 -1
  138. package/library/references/summer-folder/resource.yaml +1 -1
  139. package/library/references/summer-folder/summer-folder.md +1 -1
  140. package/library/skills/3d-lighting/SKILL.md +1 -1
  141. package/library/skills/README.md +36 -14
  142. package/library/skills/adaptive-music/SKILL.md +1 -1
  143. package/library/skills/agent-playtesting/SKILL.md +1 -1
  144. package/library/skills/ai-characters-in-games/SKILL.md +220 -0
  145. package/library/skills/ai-characters-in-games/resource.yaml +30 -0
  146. package/library/skills/ambient-bed/SKILL.md +1 -1
  147. package/library/skills/animated-loop/SKILL.md +1 -1
  148. package/library/skills/animation-tree/SKILL.md +1 -1
  149. package/library/skills/art-direction/SKILL.md +1 -1
  150. package/library/skills/asset-strategy/SKILL.md +2 -1
  151. package/library/skills/asset-strategy/resource.yaml +2 -1
  152. package/library/skills/audio-direction/SKILL.md +1 -1
  153. package/library/skills/auto-fire-targeting/SKILL.md +1 -1
  154. package/library/skills/brainstorm-game/SKILL.md +1 -1
  155. package/library/skills/brainstorming/SKILL.md +1 -1
  156. package/library/skills/browse-templates/SKILL.md +3 -3
  157. package/library/skills/browse-templates/resource.yaml +1 -1
  158. package/library/skills/camera-rigs/SKILL.md +128 -0
  159. package/library/skills/camera-rigs/resource.yaml +29 -0
  160. package/library/skills/celeste-momentum-platforming/SKILL.md +1 -1
  161. package/library/skills/character-animation-wiring/SKILL.md +1 -1
  162. package/library/skills/character-model/SKILL.md +1 -1
  163. package/library/skills/character-movement/SKILL.md +326 -0
  164. package/library/skills/character-movement/references/default-third-person-controller.gd +201 -0
  165. package/library/skills/character-movement/references/default-third-person-verification-probe.gd +154 -0
  166. package/library/skills/character-movement/references/movement-3d.md +136 -0
  167. package/library/skills/character-movement/references/platformer-feel.md +83 -0
  168. package/library/skills/character-movement/resource.yaml +40 -0
  169. package/library/skills/character-portrait/SKILL.md +1 -1
  170. package/library/skills/cinematic-cutscene/SKILL.md +1 -1
  171. package/library/skills/combat-basics/SKILL.md +159 -0
  172. package/library/skills/combat-basics/references/projectiles-and-aoe.md +100 -0
  173. package/library/skills/combat-basics/resource.yaml +34 -0
  174. package/library/skills/concept-art/SKILL.md +1 -1
  175. package/library/skills/create-asset-sheet/SKILL.md +1 -1
  176. package/library/skills/debug/SKILL.md +1 -1
  177. package/library/skills/debugging-game-feel/SKILL.md +1 -1
  178. package/library/skills/design-level/SKILL.md +1 -1
  179. package/library/skills/design-mechanic/SKILL.md +1 -1
  180. package/library/skills/design-npc/SKILL.md +1 -1
  181. package/library/skills/diagnosing-perf-regressions/SKILL.md +1 -1
  182. package/library/skills/dispatching-parallel-agents/SKILL.md +1 -1
  183. package/library/skills/driving-the-editor-ui/SKILL.md +1 -1
  184. package/library/skills/environment-kit/SKILL.md +1 -1
  185. package/library/skills/export-and-ship/SKILL.md +1 -1
  186. package/library/skills/fabricating-assets/SKILL.md +1 -1
  187. package/library/skills/facial-and-lipsync/SKILL.md +1 -1
  188. package/library/skills/fps-controller/SKILL.md +9 -7
  189. package/library/skills/fps-controller/resource.yaml +4 -1
  190. package/library/skills/game-feel/SKILL.md +1 -1
  191. package/library/skills/gameskill/SKILL.md +1 -1
  192. package/library/skills/gdscript-patterns/SKILL.md +1 -1
  193. package/library/skills/generate-motion/SKILL.md +9 -9
  194. package/library/skills/generate-motion/resource.yaml +2 -1
  195. package/library/skills/godogen-visual-proof-game-generation/SKILL.md +1 -1
  196. package/library/skills/headless-scripting/SKILL.md +1 -1
  197. package/library/skills/in-game-purchases/SKILL.md +254 -0
  198. package/library/skills/in-game-purchases/resource.yaml +29 -0
  199. package/library/skills/instantiate-asset-pack/SKILL.md +1 -1
  200. package/library/skills/investigating-bugs/SKILL.md +1 -1
  201. package/library/skills/lumera-single-image-scene-reconstruction/SKILL.md +1 -1
  202. package/library/skills/make-game/SKILL.md +25 -3
  203. package/library/skills/make-game/references/2d-platformer-polish.md +93 -0
  204. package/library/skills/make-game/references/2d-platformer.md +117 -0
  205. package/library/skills/make-game/references/2d-rpg-content.md +234 -0
  206. package/library/skills/make-game/references/2d-rpg.md +241 -0
  207. package/library/skills/make-game/references/2d-survivors-progression.md +201 -0
  208. package/library/skills/make-game/references/2d-survivors.md +237 -0
  209. package/library/skills/make-game/references/3d-fps-systems.md +216 -0
  210. package/library/skills/make-game/references/3d-fps.md +177 -0
  211. package/library/skills/make-game/references/3d-horror-systems.md +186 -0
  212. package/library/skills/make-game/references/3d-horror.md +201 -0
  213. package/library/skills/make-game/references/3d-third-person-systems.md +220 -0
  214. package/library/skills/make-game/references/3d-third-person.md +215 -0
  215. package/library/skills/make-game/resource.yaml +6 -1
  216. package/library/skills/multiplayer/SKILL.md +150 -0
  217. package/library/skills/multiplayer/resource.yaml +33 -0
  218. package/library/skills/multiplayer-movement/SKILL.md +510 -0
  219. package/library/skills/multiplayer-movement/files.md +501 -0
  220. package/library/skills/multiplayer-movement/resource.yaml +30 -0
  221. package/library/skills/multiplayer-project/SKILL.md +521 -0
  222. package/library/skills/multiplayer-project/files.md +448 -0
  223. package/library/skills/multiplayer-project/resource.yaml +36 -0
  224. package/library/skills/multiplayer-publish/SKILL.md +229 -0
  225. package/library/skills/multiplayer-publish/export-errors.md +89 -0
  226. package/library/skills/multiplayer-publish/resource.yaml +28 -0
  227. package/library/skills/multiplayer-state/SKILL.md +438 -0
  228. package/library/skills/multiplayer-state/files.md +592 -0
  229. package/library/skills/multiplayer-state/resource.yaml +35 -0
  230. package/library/skills/multiplayer-testing/SKILL.md +236 -0
  231. package/library/skills/multiplayer-testing/resource.yaml +39 -0
  232. package/library/skills/music-track/SKILL.md +1 -1
  233. package/library/skills/navigate-summer/SKILL.md +1 -1
  234. package/library/skills/new-project/SKILL.md +1 -1
  235. package/library/skills/organic-model/SKILL.md +1 -1
  236. package/library/skills/pixel-art/SKILL.md +1 -1
  237. package/library/skills/play/SKILL.md +1 -1
  238. package/library/skills/playtesting-a-feature/SKILL.md +1 -1
  239. package/library/skills/procedural-animation/SKILL.md +2 -2
  240. package/library/skills/procedural-animation/resource.yaml +1 -1
  241. package/library/skills/prop-model/SKILL.md +1 -1
  242. package/library/skills/psx-retro-rendering/SKILL.md +1 -1
  243. package/library/skills/realtime-wet-surfaces/SKILL.md +2 -2
  244. package/library/skills/remote-deploy/SKILL.md +1 -1
  245. package/library/skills/retarget/SKILL.md +1 -1
  246. package/library/skills/running-in-the-cloud/SKILL.md +1 -1
  247. package/library/skills/save-load/SKILL.md +156 -0
  248. package/library/skills/save-load/resource.yaml +27 -0
  249. package/library/skills/scene-composition/SKILL.md +1 -1
  250. package/library/skills/scene-hierarchy-design/SKILL.md +1 -1
  251. package/library/skills/scene-scripting/SKILL.md +1 -1
  252. package/library/skills/scene-to-level/SKILL.md +1 -1
  253. package/library/skills/skill-create/SKILL.md +1 -1
  254. package/library/skills/skill-improve/SKILL.md +1 -1
  255. package/library/skills/skill-test/SKILL.md +1 -1
  256. package/library/skills/skintokens-auto-rigging/SKILL.md +1 -1
  257. package/library/skills/skybox-panorama/SKILL.md +1 -1
  258. package/library/skills/sound-effect/SKILL.md +1 -1
  259. package/library/skills/spatial-placement/SKILL.md +134 -3
  260. package/library/skills/spatial-placement/references/kit-placement-tools.md +364 -0
  261. package/library/skills/spatial-placement/resource.yaml +16 -2
  262. package/library/skills/sprite-sheet/SKILL.md +1 -1
  263. package/library/skills/summer-analytics/SKILL.md +147 -0
  264. package/library/skills/summer-analytics/resource.yaml +28 -0
  265. package/library/skills/summer-friends/SKILL.md +226 -0
  266. package/library/skills/summer-friends/resource.yaml +28 -0
  267. package/library/skills/summer-leaderboards/SKILL.md +231 -0
  268. package/library/skills/summer-leaderboards/resource.yaml +30 -0
  269. package/library/skills/summer-match-results/SKILL.md +286 -0
  270. package/library/skills/summer-match-results/resource.yaml +32 -0
  271. package/library/skills/summer-matchmaking/SKILL.md +301 -0
  272. package/library/skills/summer-matchmaking/resource.yaml +32 -0
  273. package/library/skills/summer-parties/SKILL.md +253 -0
  274. package/library/skills/summer-parties/resource.yaml +30 -0
  275. package/library/skills/summer-player-data/SKILL.md +322 -0
  276. package/library/skills/summer-player-data/resource.yaml +30 -0
  277. package/library/skills/summer-store/SKILL.md +271 -0
  278. package/library/skills/summer-store/resource.yaml +29 -0
  279. package/library/skills/summer-world-chat/SKILL.md +195 -0
  280. package/library/skills/summer-world-chat/resource.yaml +30 -0
  281. package/library/skills/summer-world-saves/SKILL.md +284 -0
  282. package/library/skills/summer-world-saves/resource.yaml +29 -0
  283. package/library/skills/text-to-motion/SKILL.md +99 -0
  284. package/library/skills/text-to-motion/prompts-and-controls.md +34 -0
  285. package/library/skills/text-to-motion/resource.yaml +41 -0
  286. package/library/skills/text-to-motion/rigging-for-text-motion.md +54 -0
  287. package/library/skills/tileable-texture/SKILL.md +1 -1
  288. package/library/skills/trailer-shot/SKILL.md +1 -1
  289. package/library/skills/tune-performance/SKILL.md +1 -1
  290. package/library/skills/ui-basics/SKILL.md +10 -1
  291. package/library/skills/ui-graphics/SKILL.md +1 -1
  292. package/library/skills/use-widget-asset/SKILL.md +1 -1
  293. package/library/skills/using-summer/SKILL.md +2 -2
  294. package/library/skills/using-summer/resource.yaml +2 -2
  295. package/library/skills/vehicle-model/SKILL.md +1 -1
  296. package/library/skills/verification-before-completion/SKILL.md +1 -1
  297. package/library/skills/verifying-scenes/SKILL.md +76 -2
  298. package/library/skills/verifying-scenes/resource.yaml +13 -2
  299. package/library/skills/vfx-dissolve/SKILL.md +1 -1
  300. package/library/skills/vfx-fire/SKILL.md +1 -1
  301. package/library/skills/vfx-hit-spark/SKILL.md +1 -1
  302. package/library/skills/vfx-lightning/SKILL.md +1 -1
  303. package/library/skills/vfx-magic-glow/SKILL.md +1 -1
  304. package/library/skills/vfx-muzzle-flash/SKILL.md +1 -1
  305. package/library/skills/vfx-smoke/SKILL.md +1 -1
  306. package/library/skills/vfx-water-ripple/SKILL.md +1 -1
  307. package/library/skills/voice-line/SKILL.md +1 -1
  308. package/library/skills/web-and-touch-input/SKILL.md +38 -0
  309. package/library/skills/web-and-touch-input/resource.yaml +28 -0
  310. package/library/skills/web-compatibility-look/SKILL.md +62 -0
  311. package/library/skills/web-compatibility-look/resource.yaml +30 -0
  312. package/library/skills/world-building-3d/SKILL.md +8 -1
  313. package/library/skills/world-building-3d/references/spatial-tools.md +1 -1
  314. package/library/skills/world-building-3d/resource.yaml +2 -1
  315. package/library/skills/writing-plans/SKILL.md +1 -1
  316. package/library/skills/writing-skills/SKILL.md +1 -1
  317. package/library/templates/3d-lan-multiplayer-starter/resource.yaml +2 -2
  318. package/library/tools/attach-to-surface/resource.yaml +142 -0
  319. package/library/tools/batch/resource.yaml +9 -3
  320. package/library/tools/connect-ports/resource.yaml +120 -0
  321. package/library/tools/connect-signal/resource.yaml +3 -2
  322. package/library/tools/debug-views/resource.yaml +94 -0
  323. package/library/tools/frame-nodes/resource.yaml +104 -0
  324. package/library/tools/frame-shot/resource.yaml +134 -0
  325. package/library/tools/generate-motion/resource.yaml +44 -9
  326. package/library/tools/get-board/resource.yaml +50 -0
  327. package/library/tools/get-project-context/resource.yaml +13 -2
  328. package/library/tools/grep/resource.yaml +77 -0
  329. package/library/tools/inspect-asset/resource.yaml +71 -0
  330. package/library/tools/inspect-node/resource.yaml +9 -2
  331. package/library/tools/inspect-resource/resource.yaml +16 -5
  332. package/library/tools/instantiate-scene/resource.yaml +27 -2
  333. package/library/tools/measure/resource.yaml +96 -0
  334. package/library/tools/place-adjacent/resource.yaml +113 -0
  335. package/library/tools/play/resource.yaml +15 -2
  336. package/library/tools/raycast/resource.yaml +101 -0
  337. package/library/tools/read-file/resource.yaml +36 -2
  338. package/library/tools/read-library/resource.yaml +2 -2
  339. package/library/tools/repeat-along/resource.yaml +129 -0
  340. package/library/tools/replace-node/resource.yaml +11 -5
  341. package/library/tools/scene-audit/resource.yaml +144 -0
  342. package/library/tools/screenshot/resource.yaml +13 -2
  343. package/library/tools/search-assets/resource.yaml +18 -0
  344. package/library/tools/shot-sheet/resource.yaml +110 -0
  345. package/library/tools/snap-to-surface/resource.yaml +4 -1
  346. package/library/tools/world-snapshot/resource.yaml +24 -3
  347. package/library/tools/zoom/resource.yaml +105 -0
  348. package/package.json +1 -1
  349. package/registry/generated/aliases.json +17 -3
  350. package/registry/generated/counts.json +3 -3
  351. package/registry/generated/gemini-extension.json +26 -4
  352. package/registry/generated/index.json +2154 -469
  353. package/registry/generated/marketplace.claude.json +2 -2
  354. package/registry/generated/plugin.claude.json +27 -5
  355. package/registry/generated/plugin.codex.json +28 -6
  356. package/registry/generated/plugin.cursor.json +27 -5
  357. package/registry/generated/plugin.factory.json +27 -5
  358. package/registry/generated/skills-index.md +36 -14
  359. package/registry/generated/skills-registry.json +421 -124
  360. package/registry/generated/templates-registry.json +2 -2
  361. package/library/skills/host-authoritative-state/SKILL.md +0 -332
  362. package/library/skills/host-authoritative-state/resource.yaml +0 -28
  363. package/library/skills/peer-to-peer-multiplayer/SKILL.md +0 -373
  364. package/library/skills/peer-to-peer-multiplayer/resource.yaml +0 -28
  365. package/library/skills/setup-multiplayer/SKILL.md +0 -336
  366. package/library/skills/setup-multiplayer/resource.yaml +0 -28
@@ -0,0 +1,30 @@
1
+ id: skill/summer-leaderboards
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "Leaderboards in a Summer game: queue ratings from matches, and Game rankings your authority scores."
5
+ use_when:
6
+ - "the user wants a leaderboard, high scores, ranks, MMR, Elo or a 'top 50' screen in a Summer game"
7
+ - "a rated queue should show each player's rating, standing or percentile"
8
+ - "the authority should write a score, such as total coins or best time, to a Game-wide ranking"
9
+ - "a co-op mode should rate players against the content with authority_v1 rating deltas"
10
+ facets:
11
+ lifecycle:
12
+ - build
13
+ domains:
14
+ - multiplayer
15
+ - ui
16
+ modalities:
17
+ - scripts
18
+ - project
19
+ compatibility:
20
+ engine: ">=4.6"
21
+ related:
22
+ skills:
23
+ - skill/multiplayer
24
+ - skill/summer-matchmaking
25
+ - skill/summer-match-results
26
+ - skill/summer-player-data
27
+ source: official
28
+ license: MIT
29
+ status: preview
30
+ recommended: false
@@ -0,0 +1,286 @@
1
+ ---
2
+ name: summer-match-results
3
+ description: "End a Summer match: report each player's win, loss or draw, show results on clients, then close the World."
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: multiplayer-and-networking
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Edit Write summer_read_file summer_replace_text summer_write_file summer_get_script_errors summer_project_setting summer_play summer_stop summer_get_diagnostics
9
+ paths: ["authority/**/*.gd", "client/**/*.gd", "world.json"]
10
+ ---
11
+
12
+ # /summer-match-results — who won, and closing the match
13
+
14
+ ## Overview
15
+
16
+ A match ends when **the authority** says so. It decides the outcome for every
17
+ player, then:
18
+
19
+ 1. **Concludes** the match: `Summer.authority.match.conclude(outcomes, reason)`.
20
+ Summer settles it once and returns a settlement, including each player's
21
+ rating change on a rated queue.
22
+ 2. Summer delivers each player **their own** result on the client
23
+ (`Summer.client.ratings.match_result`), and later their committed rating
24
+ (`rating_committed`). The authority never relays results or ratings.
25
+ 3. **Completes** the World: `Summer.authority.world.complete()` for a
26
+ match-scoped World. Clients are disconnected and go back to your menu.
27
+
28
+ Where it works: all of this runs under Local Play with a deterministic
29
+ settlement, so the whole flow is testable locally. Rating values are real only
30
+ when hosted.
31
+
32
+ This skill extends the Courtyard game (`skill/multiplayer-project` and
33
+ `skill/multiplayer-state`): the first player to collect `WIN_COINS` coins wins.
34
+ With a team queue (`skill/summer-matchmaking`), their whole team wins.
35
+
36
+ ## Steps
37
+
38
+ ### 1. Track who is in the match
39
+
40
+ In `authority/main.gd`, keep every Session the engine admitted, and the
41
+ players who left. Add these variables:
42
+
43
+ ```gdscript
44
+ const WIN_COINS := 1 # coins that win the match
45
+ var ended := false
46
+ var departed := {} # session_id of players who left before the end
47
+ var sessions := {} # session_id -> SummerSession
48
+ ```
49
+
50
+ In `_ready()`, next to the other World signals (skip this line if
51
+ `skill/summer-player-data` already connected it):
52
+
53
+ ```gdscript
54
+ world.session_joined.connect(_on_session_joined)
55
+ ```
56
+
57
+ ```gdscript
58
+ ## Every player admitted into this match, kept as the exact Session object
59
+ ## the engine handed over: conclude accepts only these.
60
+ func _on_session_joined(session: SummerSession) -> void:
61
+ sessions[session.session_id] = session
62
+ ```
63
+
64
+ If the game already has `_on_session_joined` (`skill/summer-player-data`
65
+ adds one), put the line at its start instead of defining it twice.
66
+
67
+ At the top of `_on_session_left`:
68
+
69
+ ```gdscript
70
+ departed[session.session_id] = true
71
+ ```
72
+
73
+ Keep a Session in `sessions` after it leaves: it stays on the match roster
74
+ until the match is delivered, and it still needs an outcome.
75
+
76
+ Presence signals on the authority's `SummerNetworkWorld`:
77
+
78
+ | Signal | Meaning | Typical response |
79
+ |---|---|---|
80
+ | `session_joined(session)` | First admission into this World | Nothing extra: clients send `join` when their network is ready |
81
+ | `session_disconnected(session)` | Transport lost; the seat is kept | Pause or freeze that player; don't end the match yet |
82
+ | `session_reconnected(session)` | Same Session is back | Resume them |
83
+ | `session_left(session, reason)` | The Session ended, exactly once | Count them as departed; retire their groups |
84
+
85
+ Hosted, a seat waits `lifecycle.reconnect_seconds` (`world.json`) before
86
+ Summer ends the Session. Under Local Play a quitting player only
87
+ disconnects; `session_left` arrives when the World ends.
88
+
89
+ ### 2. Decide the outcome and conclude
90
+
91
+ At the end of `_collect`, after `request.accept(...)`:
92
+
93
+ ```gdscript
94
+ if wallets[session.session_id] >= WIN_COINS:
95
+ _end_match(session)
96
+ ```
97
+
98
+ Then add:
99
+
100
+ ```gdscript
101
+ ## Ends the match once: every player gets an outcome, Summer settles it, and
102
+ ## the World closes after a short results screen.
103
+ func _end_match(winner: SummerSession) -> void:
104
+ if ended:
105
+ return
106
+ ended = true
107
+ var winner_team := Summer.authority.match.get_participant(winner).team
108
+ var outcomes: Dictionary[SummerSession, SummerAuthorityMatch.MatchOutcome] = {}
109
+ for id: String in sessions:
110
+ var session: SummerSession = sessions[id]
111
+ var participant := Summer.authority.match.get_participant(session)
112
+ if participant == null or not participant.outcome_eligible:
113
+ continue # spectators get no outcome
114
+ if departed.has(id):
115
+ outcomes[session] = SummerAuthorityMatch.MATCH_OUTCOME_ABANDON
116
+ elif (participant.team == winner_team) if winner_team >= 0 else (id == winner.session_id):
117
+ outcomes[session] = SummerAuthorityMatch.MATCH_OUTCOME_WIN
118
+ else:
119
+ outcomes[session] = SummerAuthorityMatch.MATCH_OUTCOME_LOSS
120
+ match_doc.winner = winner.player.display_name
121
+ match_group.reset(Game.pack(match_doc))
122
+ var settled := await _conclude(outcomes)
123
+ # Let players read the results screen, then end the World.
124
+ await get_tree().create_timer(3.0).timeout
125
+ await Summer.authority.world.complete("match_complete").get_result_or_completed_signal()
126
+
127
+
128
+ ## Commits the outcomes. A retryable failure is retried with the same
129
+ ## arguments: Summer settles a match at most once.
130
+ func _conclude(outcomes: Dictionary[SummerSession, SummerAuthorityMatch.MatchOutcome]) -> SummerMatchSettlement:
131
+ for attempt in 3:
132
+ var concluding := Summer.authority.match.conclude(outcomes, "coins_collected")
133
+ var concluded: SummerResult = await concluding.get_result_or_completed_signal()
134
+ if concluded.ok:
135
+ return concluding.settlement
136
+ if not concluded.retryable:
137
+ push_error("conclude: %s %s" % [concluded.code, concluded.message])
138
+ return null
139
+ await get_tree().create_timer(1.0 + attempt).timeout
140
+ return null
141
+ ```
142
+
143
+ Give `match_doc` a `"winner": ""` entry so clients can show the winner's name.
144
+
145
+ The rules `conclude` enforces:
146
+
147
+ - **One outcome for every outcome-eligible player admitted into the match**,
148
+ including players who already left (`MATCH_OUTCOME_ABANDON`). A missing or
149
+ extra player fails with `invalid_roster`; spectators are skipped.
150
+ - **Keys must be the exact `SummerSession` objects the engine delivered**
151
+ (`session_joined`, or `request.get_session()` in a Command). Copies, such as
152
+ the Sessions in `Summer.authority.context.participants`, fail with
153
+ `invalid_roster`.
154
+ - Outcomes are `MATCH_OUTCOME_WIN`, `MATCH_OUTCOME_LOSS`, `MATCH_OUTCOME_DRAW`
155
+ and `MATCH_OUTCOME_ABANDON`. On a team queue give every member of a team the
156
+ same outcome; Summer scores the sides it formed.
157
+ - **It settles once.** Retrying with identical arguments replays the same
158
+ settlement (`concluding.replayed` is true); different arguments are
159
+ refused. A rejected conclusion (`invalid_request`) commits nothing, so you
160
+ may conclude again with corrected arguments.
161
+ - `rating_deltas`, the third argument, is only for `authority_v1` queues
162
+ (`skill/summer-leaderboards`).
163
+
164
+ The settlement lists each player's committed rating changes:
165
+
166
+ ```gdscript
167
+ if settled != null:
168
+ for player: SummerPlayerSettlement in settled.players:
169
+ for change: SummerRatingChange in player.ratings:
170
+ print("%s %s %d -> %d" % [player.session.player.display_name, change.system, change.before.value, change.after.value])
171
+ ```
172
+
173
+ Use it for authority logic (logs, rewards). Players get their own numbers
174
+ directly from Summer, step 3.
175
+
176
+ ### 3. Show the result on each client
177
+
178
+ In `client/main.gd`'s `_ready()`, connect the result signals right after
179
+ `Summer.initialize` succeeds and before joining (`Summer.client` is null
180
+ until then), and handle the end of the World:
181
+
182
+ ```gdscript
183
+ Summer.client.ratings.match_result.connect(_on_match_result)
184
+ Summer.client.ratings.rating_committed.connect(_on_rating_committed)
185
+ $World.server_disconnected.connect(_on_server_disconnected)
186
+ ```
187
+
188
+ ```gdscript
189
+ func _on_match_result(result: SummerMatchResult) -> void:
190
+ var words := {
191
+ SummerMatchResult.OUTCOME_WIN: "You win!",
192
+ SummerMatchResult.OUTCOME_LOSS: "You lose.",
193
+ SummerMatchResult.OUTCOME_DRAW: "Draw.",
194
+ }
195
+ show_status(words.get(result.outcome, "Match over."))
196
+
197
+
198
+ ## Arrives later, privately, once Summer committed this player's rating.
199
+ func _on_rating_committed(result: SummerMatchResult) -> void:
200
+ var change := result.rating
201
+ show_status("Rating %d (%+d)" % [change.after.value, change.delta])
202
+
203
+
204
+ func _on_server_disconnected(code: String, _detail: String) -> void:
205
+ show_status("The match has ended.")
206
+ ```
207
+
208
+ `show_status` and the `Hud/Status` label come from `skill/summer-matchmaking`.
209
+
210
+ - `match_result` arrives when the authority concludes. Its `rating_state` is
211
+ `RATING_STATE_PENDING` on a rated queue, or `RATING_STATE_NONE`.
212
+ - `rating_committed` follows when Summer committed the rating, with
213
+ `result.rating.before`, `after` and `delta`. Hosted only.
214
+ - `Summer.client.ratings.last_result` and `results` keep recent results, so a
215
+ results screen opened later can read them.
216
+ - Drive the results screen from `match_result`, not from a disconnect. Give
217
+ it a "Back to menu" button that awaits `Summer.client.leave()`, then offers
218
+ "Play again" (`find_match` again).
219
+ - Hosted, completing the World ends every Session and Summer stops the server,
220
+ so clients get `server_disconnected`. Under Local Play the World completes
221
+ but clients stay connected until they leave or Local Play stops.
222
+
223
+ ### 4. Close the World
224
+
225
+ - **Match-scoped World** (`"lifetime": "match_scoped"`, the project skill's
226
+ default): conclude, then `Summer.authority.world.complete(reason)`. This
227
+ permanently ends the World; Summer stops the server. Completing before a
228
+ successful conclusion fails with `settlement_required`.
229
+ - **Persistent or multi-match World**: conclude, then
230
+ `Summer.authority.match.complete_delivery()`. Match-bound Sessions end,
231
+ World-bound Sessions stay, and the World keeps serving. Never call
232
+ `world.complete()` on a World that should keep running.
233
+ - `draining(deadline_unix)` on the World means Summer is shutting the server
234
+ down (maintenance). Conclude or save before the deadline
235
+ (`skill/summer-world-saves`).
236
+
237
+ A match that never concludes holds its players until the World is stopped;
238
+ every match needs an ending, including "everyone else left".
239
+
240
+ ### 5. Test it with Local Play
241
+
242
+ ```
243
+ summer_project_setting name="summer/local_play/players" value=2
244
+ summer_play
245
+ summer_get_diagnostics
246
+ summer_stop
247
+ ```
248
+
249
+ Make one player win. Expect, in order: the authority's conclusion succeeds,
250
+ with a settlement of deterministic test ratings (system `deterministic-v1`);
251
+ every client receives `match_result` with its own outcome and `rating_state`
252
+ `RATING_STATE_PENDING` on a rated queue; about 3 seconds later the authority
253
+ logs `session_left` with reason `match_complete` for each player and
254
+ `world.complete()` succeeds. `rating_committed` does not fire locally, and
255
+ clients stay connected until they leave.
256
+
257
+ ## Checklist
258
+
259
+ - [ ] There is exactly one place that ends the match, guarded so it runs once.
260
+ - [ ] Outcomes cover every outcome-eligible participant, including those who left (`MATCH_OUTCOME_ABANDON`).
261
+ - [ ] Team queues give a whole team the same outcome.
262
+ - [ ] A retryable conclusion failure is retried with identical arguments.
263
+ - [ ] Clients show `match_result`, and `rating_committed` when it arrives.
264
+ - [ ] Match-scoped Worlds call `world.complete()` after concluding; persistent Worlds call `match.complete_delivery()`.
265
+ - [ ] Local Play shows the result on every client, and "Back to menu" leaves cleanly.
266
+
267
+ ## Common mistakes
268
+
269
+ | Don't | Do | Why |
270
+ |---|---|---|
271
+ | Decide the winner on a client | Decide on the authority and conclude there | Only the authority's outcome is settled |
272
+ | Build outcomes from players still connected | Every Session from `session_joined`, leavers as `MATCH_OUTCOME_ABANDON` | Leavers stay on the roster; a missing one fails `invalid_roster` |
273
+ | Key outcomes by `Summer.authority.context.participants` sessions or copied ids | The exact Session objects from `session_joined` | Copies are rejected with `invalid_roster` |
274
+ | Wait for `server_disconnected` to show results | Show results on `match_result` | Local Play keeps clients connected after completion |
275
+ | Send results or ratings to clients yourself | Let `Summer.client.ratings` deliver them | Each player gets their own result privately; the authority never relays account data |
276
+ | Retry a conclusion with changed outcomes | Retry with identical arguments | A match settles once; divergent retries are refused |
277
+ | `world.complete()` in a persistent World | `match.complete_delivery()` | `complete()` ends the World for good |
278
+ | Call `world.complete()` before concluding | Conclude, show results, then complete | Completion ends every Session |
279
+ | End the match when one player disconnects | Wait for `session_left` | A disconnect keeps the seat for the reconnect window |
280
+
281
+ ## See also
282
+
283
+ - `skill/summer-matchmaking` — queues and teams that the outcome refers to
284
+ - `skill/summer-leaderboards` — ratings and `authority_v1` rating moves
285
+ - `skill/summer-world-saves` — persistent Worlds that outlive a match
286
+ - `skill/multiplayer-testing` — running bots through a whole match
@@ -0,0 +1,32 @@
1
+ id: skill/summer-match-results
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "End a Summer match: report each player's win, loss or draw, show results on clients, then close the World."
5
+ use_when:
6
+ - "a multiplayer Summer game needs a winner, a game-over screen or a match that ends"
7
+ - "reporting match outcomes, abandons or rating changes from the authority"
8
+ - "players disconnect, reconnect or leave mid-match and the authority must handle it"
9
+ - "the World should shut down after a match, or a persistent World runs several matches"
10
+ facets:
11
+ lifecycle:
12
+ - build
13
+ domains:
14
+ - multiplayer
15
+ - gameplay
16
+ modalities:
17
+ - scripts
18
+ compatibility:
19
+ engine: ">=4.6"
20
+ related:
21
+ skills:
22
+ - skill/multiplayer
23
+ - skill/multiplayer-state
24
+ - skill/summer-matchmaking
25
+ - skill/summer-leaderboards
26
+ - skill/summer-world-saves
27
+ - skill/multiplayer-testing
28
+ - skill/summer-analytics
29
+ source: official
30
+ license: MIT
31
+ status: stable
32
+ recommended: false
@@ -0,0 +1,301 @@
1
+ ---
2
+ name: summer-matchmaking
3
+ description: "Get players into matches with Summer matchmaking: queues, teams, accept prompts, join progress and failures."
4
+ license: MIT
5
+ compatibility: [Cursor, Claude Code, Windsurf, Codex]
6
+ category: multiplayer-and-networking
7
+ user-invocable: true
8
+ allowed-tools: Read Grep Edit Write summer_read_file summer_replace_text summer_write_file summer_get_script_errors summer_project_setting summer_play summer_stop summer_get_diagnostics
9
+ paths: ["summer.build.json", "client/**/*.gd", "authority/**/*.gd", "client/**/*.tscn"]
10
+ ---
11
+
12
+ # /summer-matchmaking — queues, teams and the way into a match
13
+
14
+ ## Overview
15
+
16
+ A **queue** is a game mode players search in: "casual 2–8", "duel 1v1",
17
+ "ranked 2v2". You declare queues in `summer.build.json`; Summer matchmaking
18
+ groups searching players, reserves a server for them, and every player's
19
+ `Summer.client.join(SummerJoinTarget.queue(...))` completes in the same World.
20
+ The authority then reads each player's team from the verified Session.
21
+
22
+ There is no lobby object, invite code or server browser. Friends who want to
23
+ play together use a party (`skill/summer-parties`), which enters a queue as one group.
24
+
25
+ Where it works:
26
+
27
+ | Piece | Local Play | Hosted |
28
+ |---|---|---|
29
+ | Joining a queue, progress, failures | Yes: players are placed at once | Yes |
30
+ | Teams (`get_participant(session).team`) | Yes: round-robin in roster order | Yes: balanced by rating, parties kept together |
31
+ | Accept/Decline prompt | No: no proposal happens | Yes, when the queue declares `acceptance` |
32
+ | Rating-based grouping | No | Yes |
33
+
34
+ This skill extends the Courtyard game from `skill/multiplayer-project` and
35
+ `skill/multiplayer-state`. Its client already joins `Game.QUEUE` and sends a
36
+ `join` Command; its authority publishes `match_doc`.
37
+
38
+ ## Steps
39
+
40
+ ### 1. Declare the queues
41
+
42
+ Each queue in `runtime.queues` of `summer.build.json` names the
43
+ WorldDefinition its matches run. A casual mode and a 1v1 rated duel:
44
+
45
+ ```json
46
+ "queues": [
47
+ { "name": "courtyard", "minPlayers": 2, "maxPlayers": 8, "worldDefinition": "courtyard", "policy": "fifo", "transport": "enet" },
48
+ {
49
+ "name": "duel", "minPlayers": 2, "maxPlayers": 2, "worldDefinition": "courtyard",
50
+ "policy": "rating", "ratingSystemRef": "elo_v1",
51
+ "teams": { "count": 2, "size": 1 },
52
+ "acceptance": { "mode": "all", "ttl": "20s" },
53
+ "searchTtl": { "min": "30s", "default": "2m", "max": "5m" },
54
+ "transport": "enet"
55
+ }
56
+ ]
57
+ ```
58
+
59
+ The fields Summer accepts, and their rules:
60
+
61
+ | Field | Meaning | Rules |
62
+ |---|---|---|
63
+ | `name` | The id clients join | Unique; ASCII letters, digits, `_ . : -` |
64
+ | `minPlayers` / `maxPlayers` | Players per match | `minPlayers` ≥ 1, `maxPlayers` ≥ `minPlayers`. Measured support is up to 16 per match |
65
+ | `worldDefinition` | The WorldDefinition's `definition_id` | Required; every WorldDefinition must be used by a queue |
66
+ | `policy` | `fifo` (first come) or `rating` (group by skill) | `rating` needs `ratingSystemRef`; `fifo` must not declare one |
67
+ | `ratingSystemRef` | `elo_v1` (Summer rates two sides) or `authority_v1` (your authority reports rating moves) | See `skill/summer-leaderboards` |
68
+ | `teams` | `{count, size}`: fixed sides, such as 2v2 = `{2, 2}` | `count` 2..64, `size` 1..16, `minPlayers` = `maxPlayers` = count × size; `elo_v1` needs exactly 2 teams |
69
+ | `acceptance` | `{"mode": "all", "ttl": "20s"}` asks every player to accept; `{"mode": "none"}` skips it | `ttl` required with `all`, forbidden with `none` |
70
+ | `searchTtl` | `{min, default, max}` search lifetime | Go durations (`30s`, `2m`); min ≤ default ≤ max |
71
+ | `regions` | Regions this queue may use | Omit to allow all |
72
+ | `transport` | `enet` (UDP, default) or `ws` (WebSocket) | |
73
+
74
+ Don't add `lobby` fields or `backfill`: Summer rejects both when you publish.
75
+ Teams and acceptance need `runtime.interfaces.multiplayer` 5 or higher; the
76
+ project skill's `summer.build.json` declares 6.
77
+
78
+ ### 2. Search, with progress the player can see
79
+
80
+ Add a status label and two hidden buttons to the client scene,
81
+ `client/main.tscn` (position them in the editor as you like):
82
+
83
+ ```
84
+ [node name="Hud" type="CanvasLayer" parent="."]
85
+
86
+ [node name="Status" type="Label" parent="Hud"]
87
+
88
+ [node name="Accept" type="Button" parent="Hud"]
89
+ visible = false
90
+ text = "Accept"
91
+
92
+ [node name="Decline" type="Button" parent="Hud"]
93
+ visible = false
94
+ text = "Decline"
95
+
96
+ [connection signal="pressed" from="Hud/Accept" to="." method="_on_accept_pressed"]
97
+ [connection signal="pressed" from="Hud/Decline" to="." method="_on_decline_pressed"]
98
+ ```
99
+
100
+ In `client/main.gd`, replace the join in `_ready()`, from `var join :=`
101
+ through the `if not joined.ok:` block, with a call to `find_match`:
102
+
103
+ ```gdscript
104
+ var joined := await find_match(Game.QUEUE)
105
+ if not joined.ok:
106
+ return
107
+ ```
108
+
109
+ and add the matchmaking functions:
110
+
111
+ ```gdscript
112
+ var proposal: SummerMatchmakingProposal # a found match waiting for Accept/Decline
113
+
114
+
115
+ ## Searches `queue` until the player is in a match, showing progress.
116
+ func find_match(queue: StringName) -> SummerResult:
117
+ var join := Summer.client.join(SummerJoinTarget.queue(queue))
118
+ join.progress_changed.connect(_on_progress)
119
+ join.acceptance_required.connect(_on_match_found)
120
+ var joined: SummerResult = await join.get_result_or_completed_signal()
121
+ proposal = null
122
+ $Hud/Accept.hide()
123
+ $Hud/Decline.hide()
124
+ show_status("" if joined.ok else join_failure_text(joined))
125
+ return joined
126
+
127
+
128
+ ## Stages carry no tickets or addresses, so they are safe to show.
129
+ func _on_progress(progress: SummerJoinProgress) -> void:
130
+ match progress.stage:
131
+ SummerJoinProgress.STAGE_RESOLVING:
132
+ show_status("Searching for players… %ds" % (progress.elapsed_msec / 1000))
133
+ SummerJoinProgress.STAGE_RESERVED, SummerJoinProgress.STAGE_PROPOSED:
134
+ show_status("Match found")
135
+ SummerJoinProgress.STAGE_LAUNCHING, SummerJoinProgress.STAGE_CONNECTING, SummerJoinProgress.STAGE_ADMITTING:
136
+ show_status("Joining the match…")
137
+ SummerJoinProgress.STAGE_RECONNECTING:
138
+ show_status("Reconnecting…")
139
+
140
+
141
+ func show_status(text: String) -> void:
142
+ $Hud/Status.text = text
143
+ ```
144
+
145
+ ### 3. Accept or decline a found match
146
+
147
+ With `"acceptance": {"mode": "all"}`, Summer reserves a server first, then asks
148
+ every player. The match starts only when all accept before the deadline. The
149
+ engine never decides for the player: connect `acceptance_required`, or the
150
+ join waits until the proposal expires.
151
+
152
+ ```gdscript
153
+ ## Summer reserved a server for these players. The match starts only when
154
+ ## everyone accepts before the deadline.
155
+ func _on_match_found(found: SummerMatchmakingProposal) -> void:
156
+ proposal = found
157
+ var seconds_left := maxi(0, (found.accept_by_unix_msec - int(Time.get_unix_time_from_system() * 1000.0)) / 1000)
158
+ show_status("Match found! Accept within %ds" % seconds_left)
159
+ $Hud/Accept.show()
160
+ $Hud/Decline.show()
161
+
162
+
163
+ func _on_accept_pressed() -> void: _decide(true)
164
+ func _on_decline_pressed() -> void: _decide(false)
165
+
166
+
167
+ func _decide(accept: bool) -> void:
168
+ if proposal == null or proposal.is_decided():
169
+ return
170
+ var decided: SummerResult = proposal.accept() if accept else proposal.decline()
171
+ if not decided.ok:
172
+ show_status(join_failure_text(decided))
173
+ $Hud/Accept.hide()
174
+ $Hud/Decline.hide()
175
+ ```
176
+
177
+ After an accept, `find_match` keeps waiting until everyone accepted. A
178
+ decline ends it with `proposal_declined`. A game that always accepts (one
179
+ "Play" button) connects `acceptance_required` straight to `proposal.accept()`.
180
+
181
+ ### 4. Tell players what went wrong
182
+
183
+ Every failure is a `SummerResult` with a stable `code` and `retryable`:
184
+
185
+ ```gdscript
186
+ ## Turns a typed failure into words for the player. `retryable` says whether
187
+ ## offering "Try again" makes sense.
188
+ func join_failure_text(result: SummerResult) -> String:
189
+ match String(result.code):
190
+ "proposal_declined":
191
+ return "You declined the match."
192
+ "proposal_expired":
193
+ return "The match wasn't accepted in time."
194
+ "queue_not_found", "queue_closed":
195
+ return "This mode isn't available right now."
196
+ "capacity_exhausted", "world_full", "world_start_timeout", "region_unavailable":
197
+ return "Servers are busy. Try again in a moment."
198
+ "rate_limited":
199
+ return "Too many tries. Wait a moment."
200
+ "cancelled":
201
+ return ""
202
+ return "Couldn't join. Try again." if result.retryable else "Couldn't join: %s" % result.message
203
+ ```
204
+
205
+ Other codes: `proposal_stale` and `proposal_already_decided` (a second
206
+ decision), `world_waking` (a persistent World is restoring), `qos_stale`,
207
+ `platform_error`, and `unavailable` (Local Play hosts a different queue).
208
+
209
+ ### 5. Cancel the search, or leave
210
+
211
+ `Summer.client.leave()` cancels a search in flight, or leaves the current
212
+ match. Await it before quitting the game, so the platform knows the player is
213
+ gone and doesn't hold a seat for them:
214
+
215
+ ```gdscript
216
+ ## Stops searching, or leaves the current match. Await it before quitting.
217
+ func leave_match() -> void:
218
+ var left: SummerResult = await Summer.client.leave().get_result_or_completed_signal()
219
+ if not left.ok:
220
+ push_warning("leave: %s" % left.code)
221
+ ```
222
+
223
+ To offer "Play online" only when it can work, read
224
+ `Summer.client.matchmaking.availability.hosted_sessions_available` (and
225
+ `hosted_unavailable_reason`) before showing the button.
226
+
227
+ ### 6. Read teams and the queue on the authority
228
+
229
+ The authority learns each player's team from the verified Session. In
230
+ `authority/main.gd`, give `match_doc` a `"teams": {}` entry and add this to
231
+ `_join` just before `request.accept(...)`:
232
+
233
+ ```gdscript
234
+ # The team matchmaking seated this player on: 0..count-1, or -1 without teams.
235
+ var participant := Summer.authority.match.get_participant(session)
236
+ var team := participant.team if participant != null else -1
237
+ match_doc.teams[session.player.display_name] = team
238
+ match_group.reset(Game.pack(match_doc))
239
+ ```
240
+
241
+ Players learn teams only from what the authority publishes, here the shared
242
+ match document. `Summer.get_world().queue` on the authority names the queue
243
+ this match came from, so one authority scene can serve several modes.
244
+
245
+ ### 7. Test it with Local Play
246
+
247
+ Local Play stands in for one queue at a time: the first one declared, or the
248
+ one you name. In the editor and with `summer_play`, name it with the
249
+ `summer/local_play/queue` project setting:
250
+
251
+ ```
252
+ summer_project_setting name="summer/local_play/queue" value="duel"
253
+ summer_project_setting name="summer/local_play/players" value=2
254
+ summer_play
255
+ summer_get_diagnostics
256
+ summer_stop
257
+ ```
258
+
259
+ A terminal run ignores that setting; pass the queue instead:
260
+ `<summer> --path . --summer-local-play 2 --summer-local-play-queue duel --summer-local-play-smoke`.
261
+
262
+ - The client must join the queue Local Play stands in for. Another queue
263
+ fails with `unavailable`: "Local Play is hosting queue 'courtyard'. Start
264
+ Local Play with queue 'duel' to test that queue."
265
+ - Players are placed at once: progress goes straight to `STAGE_CONNECTED`,
266
+ with no search and no Accept/Decline.
267
+ - A team queue seats players round-robin in roster order (player-1 on team 0,
268
+ player-2 on team 1, and so on), whatever order they connect in.
269
+ - `Summer.client.matchmaking.availability` reports hosted sessions as
270
+ available.
271
+
272
+ Test the accept prompt and rating-based grouping on a hosted staging build.
273
+
274
+ ## Checklist
275
+
276
+ - [ ] Every queue names a WorldDefinition; teams queues have `minPlayers` = `maxPlayers` = count × size.
277
+ - [ ] The client shows search progress and a readable message for each failure code.
278
+ - [ ] Queues with `acceptance` show Accept/Decline with the deadline; nothing auto-accepts unless the game means to.
279
+ - [ ] Cancel and quit both await `Summer.client.leave()`.
280
+ - [ ] The authority reads `get_participant(session).team` and publishes teams to players.
281
+ - [ ] Local Play with `summer/local_play/queue` set runs each queue you declared.
282
+
283
+ ## Common mistakes
284
+
285
+ | Don't | Do | Why |
286
+ |---|---|---|
287
+ | Build a lobby, invite codes or join-by-IP | Queues, plus parties for friends | Summer has no lobby object; invite, follow, portal and resume joins return `unsupported_placement` |
288
+ | Ignore `acceptance_required` on a queue with `acceptance` | Show Accept/Decline, or connect it to `proposal.accept()` | The engine never accepts for the player; the join waits until `proposal_expired` |
289
+ | `teams` with `minPlayers` ≠ count × size | Equal sizes: 2v2 is 4 and 4 | Summer rejects the queue when you publish |
290
+ | Read the team on the client from matchmaking | Publish it from the authority | Clients only learn teams through the game's own state |
291
+ | Join `courtyard` while Local Play stands in for `duel` | Set `summer/local_play/queue` to the queue the client joins | Local Play hosts one queue per run; the other fails `unavailable` |
292
+ | Quit right after "Cancel" | Await `Summer.client.leave()` first | The search may keep holding a ticket for the player |
293
+ | Show raw `result.message` for known codes | Map codes to your own words | Codes are stable; messages are diagnostics |
294
+
295
+ ## See also
296
+
297
+ - `skill/multiplayer` — how Summer multiplayer fits together
298
+ - `skill/summer-match-results` — ending a match and reporting who won
299
+ - `skill/summer-leaderboards` — ratings and leaderboards for rated queues
300
+ - `skill/summer-parties` — friends entering a queue together
301
+ - `skill/multiplayer-testing` — Local Play options and bots
@@ -0,0 +1,32 @@
1
+ id: skill/summer-matchmaking
2
+ kind: skill
3
+ version: 1.0.0
4
+ summary: "Get players into matches with Summer matchmaking: queues, teams, accept prompts, join progress and failures."
5
+ use_when:
6
+ - "the user wants matchmaking, a lobby, a play button, quick play, ranked or casual modes in a multiplayer Summer game"
7
+ - "declaring queues, player counts, teams (2v2, 5v5), rated queues or a ready check in summer.build.json"
8
+ - "showing search progress, an Accept/Decline prompt, cancel search or join errors to players"
9
+ - "the authority needs to know which team or queue each player is on"
10
+ facets:
11
+ lifecycle:
12
+ - build
13
+ domains:
14
+ - multiplayer
15
+ - ux
16
+ modalities:
17
+ - scripts
18
+ - project
19
+ compatibility:
20
+ engine: ">=4.6"
21
+ related:
22
+ skills:
23
+ - skill/multiplayer
24
+ - skill/multiplayer-project
25
+ - skill/multiplayer-testing
26
+ - skill/summer-match-results
27
+ - skill/summer-leaderboards
28
+ - skill/summer-parties
29
+ source: official
30
+ license: MIT
31
+ status: preview
32
+ recommended: false