@musashishao/agent-kit 1.9.0 → 1.9.1

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 (125) hide show
  1. package/.agent/agents/ai-asset-factory.md +700 -0
  2. package/.agent/agents/ai-audio-factory.md +503 -0
  3. package/.agent/agents/game-developer.md +4 -4
  4. package/.agent/agents/orchestrator.md +113 -3
  5. package/.agent/agents/project-planner.md +67 -0
  6. package/.agent/agents/unity-mobile-master.md +949 -0
  7. package/.agent/mcp/config/registry.json +65 -51
  8. package/.agent/mcp/servers/notebooklm/README.md +114 -0
  9. package/.agent/mcp/servers/notebooklm/package.json +35 -0
  10. package/.agent/mcp/servers/notebooklm/src/auth/chrome.ts +225 -0
  11. package/.agent/mcp/servers/notebooklm/src/auth/index.ts +1 -0
  12. package/.agent/mcp/servers/notebooklm/src/index.ts +516 -0
  13. package/.agent/mcp/servers/notebooklm/src/services/index.ts +3 -0
  14. package/.agent/mcp/servers/notebooklm/src/services/library.ts +217 -0
  15. package/.agent/mcp/servers/notebooklm/src/services/notebooklm.ts +380 -0
  16. package/.agent/mcp/servers/notebooklm/tsconfig.json +15 -0
  17. package/.agent/mcp-gateway/README.md +169 -20
  18. package/.agent/mcp-gateway/package.json +22 -7
  19. package/.agent/mcp-gateway/src/auth/index.ts +55 -0
  20. package/.agent/mcp-gateway/src/auth/middleware.ts +242 -0
  21. package/.agent/mcp-gateway/src/auth/oauth.ts +462 -0
  22. package/.agent/mcp-gateway/src/auth/scopes.ts +227 -0
  23. package/.agent/mcp-gateway/src/index.ts +252 -105
  24. package/.agent/mcp-gateway/src/observability/index.ts +5 -0
  25. package/.agent/mcp-gateway/src/observability/otel.ts +405 -0
  26. package/.agent/mcp-gateway/src/transports/index.ts +5 -0
  27. package/.agent/mcp-gateway/src/transports/streamableHttp.ts +235 -0
  28. package/.agent/rules/CODEX.md +89 -0
  29. package/.agent/rules/CODE_RULES.md +73 -0
  30. package/.agent/rules/GEMINI.md +25 -0
  31. package/.agent/rules/MEMORY_STATE.md +110 -0
  32. package/.agent/rules/REFERENCE.md +33 -141
  33. package/.agent/rules/REF_SKILLS.md +116 -0
  34. package/.agent/rules/REF_WORKFLOWS.md +81 -0
  35. package/.agent/scripts/ak_cli.py +106 -5
  36. package/.agent/scripts/memory_manager.py +48 -9
  37. package/.agent/skills/anti-hallucination/SKILL.md +295 -0
  38. package/.agent/skills/anti-hallucination/scripts/check_hallucination.py +299 -0
  39. package/.agent/skills/bifurcation-analysis/SKILL.md +56 -0
  40. package/.agent/skills/brainstorming/SKILL.md +80 -6
  41. package/.agent/skills/decision-memory/SKILL.md +317 -0
  42. package/.agent/skills/emergence-detector/SKILL.md +230 -0
  43. package/.agent/skills/emergence-detector/scripts/check_emergence.py +265 -0
  44. package/.agent/skills/explained-qa/SKILL.md +142 -0
  45. package/.agent/skills/explained-qa/game-terminology.md +214 -0
  46. package/.agent/skills/game-development/ai-dialogue-engine/SKILL.md +442 -0
  47. package/.agent/skills/game-development/ai-graphics-generator/SKILL.md +463 -0
  48. package/.agent/skills/game-development/ai-playtest-framework/SKILL.md +570 -0
  49. package/.agent/skills/game-development/camera-systems/SKILL.md +607 -0
  50. package/.agent/skills/game-development/card-battle-engine/SKILL.md +618 -0
  51. package/.agent/skills/game-development/character-controller-3d/SKILL.md +908 -0
  52. package/.agent/skills/game-development/cloud-save-sync/SKILL.md +527 -0
  53. package/.agent/skills/game-development/combat-system/SKILL.md +748 -0
  54. package/.agent/skills/game-development/compliance-rating/SKILL.md +277 -0
  55. package/.agent/skills/game-development/crossplatform-build/SKILL.md +386 -0
  56. package/.agent/skills/game-development/cultivation-progression/SKILL.md +520 -0
  57. package/.agent/skills/game-development/data-driven-balance/SKILL.md +535 -0
  58. package/.agent/skills/game-development/game-analytics-integrator/SKILL.md +410 -0
  59. package/.agent/skills/game-development/game-audio-advanced/SKILL.md +646 -0
  60. package/.agent/skills/game-development/game-economy-designer/SKILL.md +375 -0
  61. package/.agent/skills/game-development/game-marketing/SKILL.md +85 -0
  62. package/.agent/skills/game-development/game-state-manager/SKILL.md +883 -0
  63. package/.agent/skills/game-development/hybrid-game-spec/SKILL.md +220 -0
  64. package/.agent/skills/game-development/inventory-quest/SKILL.md +747 -0
  65. package/.agent/skills/game-development/liveops/SKILL.md +308 -0
  66. package/.agent/skills/game-development/localization/SKILL.md +286 -0
  67. package/.agent/skills/game-development/mobile-input-patterns/SKILL.md +343 -0
  68. package/.agent/skills/game-development/monetization-strategy/SKILL.md +94 -0
  69. package/.agent/skills/game-development/multiplayer-master/SKILL.md +727 -0
  70. package/.agent/skills/game-development/narrative-branching/SKILL.md +593 -0
  71. package/.agent/skills/game-development/procedural-level-ai/SKILL.md +367 -0
  72. package/.agent/skills/game-development/prototyping-rapid/SKILL.md +205 -0
  73. package/.agent/skills/game-development/spec-ecosystem/SKILL.md +155 -0
  74. package/.agent/skills/game-development/spec-ecosystem/decision-log-format.md +129 -0
  75. package/.agent/skills/game-development/spec-ecosystem/templates/PLAN-template.md +178 -0
  76. package/.agent/skills/game-development/spec-ecosystem/templates/SPEC-template.md +110 -0
  77. package/.agent/skills/game-development/spec-ecosystem/templates/TASKS-template.md +156 -0
  78. package/.agent/skills/game-development/survival-systems/SKILL.md +493 -0
  79. package/.agent/skills/game-development/testing-qa/SKILL.md +270 -0
  80. package/.agent/skills/game-development/unity-mobile-optimization/SKILL.md +271 -0
  81. package/.agent/skills/intent-capture/SKILL.md +65 -0
  82. package/.agent/skills/mcp-composition/SKILL.md +362 -0
  83. package/.agent/skills/mcp-observability/SKILL.md +323 -0
  84. package/.agent/skills/mcp-security/SKILL.md +314 -0
  85. package/.agent/skills/trust-spectrum/SKILL.md +291 -0
  86. package/.agent/skills/vibe-coding-guard/SKILL.md +328 -0
  87. package/.agent/templates/AGENTS.game.md +63 -0
  88. package/.agent/templates/docs/WORKFLOW_GUIDE.en.md +100 -0
  89. package/.agent/templates/docs/WORKFLOW_GUIDE.vi.md +100 -0
  90. package/.agent/workflows/ai-agent.md +2 -0
  91. package/.agent/workflows/autofix.md +1 -0
  92. package/.agent/workflows/brainstorm.md +1 -0
  93. package/.agent/workflows/context.md +1 -0
  94. package/.agent/workflows/create.md +39 -8
  95. package/.agent/workflows/dashboard.md +1 -0
  96. package/.agent/workflows/debug.md +14 -0
  97. package/.agent/workflows/deploy.md +14 -0
  98. package/.agent/workflows/enhance.md +44 -0
  99. package/.agent/workflows/gamekit-init.md +177 -0
  100. package/.agent/workflows/gamekit-launch.md +338 -0
  101. package/.agent/workflows/gamekit-plan.md +204 -0
  102. package/.agent/workflows/gamekit-qa.md +153 -0
  103. package/.agent/workflows/gamekit-spec.md +243 -0
  104. package/.agent/workflows/gamekit-tasks.md +208 -0
  105. package/.agent/workflows/marketing.md +2 -0
  106. package/.agent/workflows/next.md +1 -0
  107. package/.agent/workflows/orchestrate.md +12 -0
  108. package/.agent/workflows/pentest.md +2 -0
  109. package/.agent/workflows/plan.md +42 -0
  110. package/.agent/workflows/preview.md +1 -0
  111. package/.agent/workflows/quality.md +1 -0
  112. package/.agent/workflows/saas.md +2 -0
  113. package/.agent/workflows/spec.md +42 -0
  114. package/.agent/workflows/status.md +1 -0
  115. package/.agent/workflows/test.md +14 -0
  116. package/.agent/workflows/ui-ux-pro-max.md +1 -0
  117. package/bin/cli.js +411 -111
  118. package/package.json +1 -2
  119. package/.agent/agents/game-asset-curator.md +0 -317
  120. package/.agent/agents/game-narrative-designer.md +0 -310
  121. package/.agent/agents/game-qa-agent.md +0 -441
  122. package/.agent/workflows/game-prototype.md +0 -154
  123. package/docs/AI_DATA_INFRASTRUCTURE.md +0 -288
  124. package/docs/CHANGELOG_AI_INFRA.md +0 -141
  125. package/docs/MIGRATION_GUIDE_V1.9.md +0 -55
@@ -0,0 +1,727 @@
1
+ ---
2
+ name: multiplayer-master
3
+ description: Complete multiplayer game development. Unity Netcode, Photon Fusion, Mirror, real-time sync, lag compensation, matchmaking, and anti-cheat patterns.
4
+ allowed-tools: Read, Write, Edit, Bash, Grep, WebSearch
5
+ ---
6
+
7
+ # Multiplayer Master Skill
8
+
9
+ > Build production-ready multiplayer games with proper networking architecture.
10
+
11
+ ---
12
+
13
+ ## When to Use
14
+
15
+ - Building real-time multiplayer games
16
+ - Implementing player synchronization
17
+ - Setting up dedicated servers
18
+ - Creating matchmaking systems
19
+ - Handling lag compensation
20
+
21
+ ---
22
+
23
+ ## Architecture Selection
24
+
25
+ ### Decision Matrix
26
+
27
+ ```
28
+ What type of multiplayer?
29
+
30
+ ├── Real-time Competitive (FPS, Fighting)
31
+ │ └── Dedicated Server + Netcode/Photon Fusion
32
+ │ └── Tick rate: 64-128 Hz
33
+ │ └── Lag compensation: CRITICAL
34
+
35
+ ├── Real-time Cooperative (Co-op, MMO)
36
+ │ └── Dedicated Server or Host-based
37
+ │ └── Tick rate: 20-60 Hz
38
+ │ └── Lag compensation: IMPORTANT
39
+
40
+ ├── Turn-based (Card games, Strategy)
41
+ │ └── Client-Server REST/WebSocket
42
+ │ └── No tick rate needed
43
+ │ └── Lag compensation: NOT NEEDED
44
+
45
+ └── Casual/Social
46
+ └── Host-based (P2P)
47
+ └── Tick rate: 10-30 Hz
48
+ └── Lag compensation: MINIMAL
49
+ ```
50
+
51
+ ### Framework Comparison
52
+
53
+ | Framework | Best For | Pros | Cons |
54
+ |-----------|----------|------|------|
55
+ | **Netcode for GameObjects** | Unity-first | Official, well documented | Learning curve |
56
+ | **Photon Fusion** | Fast iteration | Great tools, cloud hosting | Costs at scale |
57
+ | **Mirror** | Self-hosted | Free, flexible | More manual work |
58
+ | **FishNet** | Performance | Fast, modern | Smaller community |
59
+
60
+ ---
61
+
62
+ ## Unity Netcode for GameObjects
63
+
64
+ ### Project Setup
65
+
66
+ ```csharp
67
+ // 1. Install via Package Manager:
68
+ // com.unity.netcode.gameobjects
69
+
70
+ // 2. Create NetworkManager
71
+ public class GameNetworkManager : NetworkManager
72
+ {
73
+ public static GameNetworkManager Instance { get; private set; }
74
+
75
+ private void Awake()
76
+ {
77
+ Instance = this;
78
+ }
79
+
80
+ public override void OnServerStarted()
81
+ {
82
+ Debug.Log("Server started!");
83
+ NetworkManager.Singleton.SceneManager.LoadScene("GameScene", LoadSceneMode.Single);
84
+ }
85
+
86
+ public override void OnClientConnectedCallback(ulong clientId)
87
+ {
88
+ Debug.Log($"Client {clientId} connected");
89
+ }
90
+ }
91
+ ```
92
+
93
+ ### NetworkObject & NetworkBehaviour
94
+
95
+ ```csharp
96
+ public class PlayerController : NetworkBehaviour
97
+ {
98
+ [Header("Movement")]
99
+ [SerializeField] private float moveSpeed = 5f;
100
+
101
+ // Synced variable - server authoritative
102
+ private NetworkVariable<Vector3> _networkPosition = new NetworkVariable<Vector3>(
103
+ readPerm: NetworkVariableReadPermission.Everyone,
104
+ writePerm: NetworkVariableWritePermission.Server
105
+ );
106
+
107
+ private NetworkVariable<int> _health = new NetworkVariable<int>(100);
108
+
109
+ public override void OnNetworkSpawn()
110
+ {
111
+ if (IsOwner)
112
+ {
113
+ // Setup local player
114
+ Camera.main.GetComponent<CameraFollow>().SetTarget(transform);
115
+ }
116
+
117
+ _health.OnValueChanged += OnHealthChanged;
118
+ }
119
+
120
+ void Update()
121
+ {
122
+ if (!IsOwner) return;
123
+
124
+ // Client-side input
125
+ float h = Input.GetAxisRaw("Horizontal");
126
+ float v = Input.GetAxisRaw("Vertical");
127
+ Vector3 moveInput = new Vector3(h, 0, v).normalized;
128
+
129
+ if (moveInput.magnitude > 0.1f)
130
+ {
131
+ MoveServerRpc(moveInput);
132
+ }
133
+ }
134
+
135
+ [ServerRpc]
136
+ private void MoveServerRpc(Vector3 direction)
137
+ {
138
+ // Server validates and applies movement
139
+ Vector3 newPos = transform.position + direction * moveSpeed * Time.deltaTime;
140
+
141
+ // Validate movement (anti-cheat)
142
+ if (IsValidMovement(transform.position, newPos))
143
+ {
144
+ transform.position = newPos;
145
+ _networkPosition.Value = newPos;
146
+ }
147
+ }
148
+
149
+ private bool IsValidMovement(Vector3 from, Vector3 to)
150
+ {
151
+ float maxDistance = moveSpeed * Time.deltaTime * 1.5f; // Allow some tolerance
152
+ return Vector3.Distance(from, to) <= maxDistance;
153
+ }
154
+
155
+ private void OnHealthChanged(int oldValue, int newValue)
156
+ {
157
+ // Update UI
158
+ UIManager.Instance.UpdateHealthBar(newValue);
159
+
160
+ if (newValue <= 0)
161
+ {
162
+ HandleDeath();
163
+ }
164
+ }
165
+
166
+ [ServerRpc]
167
+ public void TakeDamageServerRpc(int damage, ServerRpcParams rpcParams = default)
168
+ {
169
+ _health.Value -= damage;
170
+
171
+ // Notify all clients of damage
172
+ TakeDamageClientRpc(damage);
173
+ }
174
+
175
+ [ClientRpc]
176
+ private void TakeDamageClientRpc(int damage)
177
+ {
178
+ // Play damage effects on all clients
179
+ PlayDamageEffect();
180
+ }
181
+ }
182
+ ```
183
+
184
+ ### NetworkTransform (Position Sync)
185
+
186
+ ```csharp
187
+ // For smooth interpolation, use NetworkTransform component
188
+ // Settings for different game types:
189
+
190
+ // FPS/Action Game:
191
+ // - Interpolate: ON
192
+ // - Sync Position: X, Y, Z
193
+ // - Sync Rotation: Y only (or X,Y for full aim)
194
+ // - Threshold: 0.001 (high precision)
195
+
196
+ // Casual Game:
197
+ // - Interpolate: ON
198
+ // - Sync Position: X, Z (no Y if grounded)
199
+ // - Threshold: 0.1 (lower precision OK)
200
+ ```
201
+
202
+ ---
203
+
204
+ ## Photon Fusion
205
+
206
+ ### Setup
207
+
208
+ ```csharp
209
+ // 1. Install Photon Fusion from Asset Store
210
+ // 2. Create App ID at photonengine.com
211
+
212
+ public class FusionBootstrap : MonoBehaviour
213
+ {
214
+ [SerializeField] private NetworkRunner _runnerPrefab;
215
+
216
+ async void Start()
217
+ {
218
+ var runner = Instantiate(_runnerPrefab);
219
+
220
+ await runner.StartGame(new StartGameArgs
221
+ {
222
+ GameMode = GameMode.AutoHostOrClient,
223
+ SessionName = "MyGame",
224
+ Scene = SceneManager.GetActiveScene().buildIndex,
225
+ SceneManager = gameObject.AddComponent<NetworkSceneManagerDefault>()
226
+ });
227
+ }
228
+ }
229
+ ```
230
+
231
+ ### NetworkBehaviour (Fusion style)
232
+
233
+ ```csharp
234
+ public class FusionPlayer : NetworkBehaviour
235
+ {
236
+ [Networked] public int Health { get; set; } = 100;
237
+ [Networked] public NetworkString<_32> PlayerName { get; set; }
238
+
239
+ // Tick-aligned input
240
+ [Networked] private NetworkButtons _buttons { get; set; }
241
+
242
+ public override void FixedUpdateNetwork()
243
+ {
244
+ if (GetInput(out NetworkInputData input))
245
+ {
246
+ // Process input (runs on both client and server)
247
+ Vector3 move = new Vector3(input.Direction.x, 0, input.Direction.y);
248
+ transform.position += move * Runner.DeltaTime * 5f;
249
+ }
250
+ }
251
+
252
+ // State change callback
253
+ public static void OnHealthChanged(Changed<FusionPlayer> changed)
254
+ {
255
+ changed.Behaviour.OnHealthChangedLocal();
256
+ }
257
+
258
+ private void OnHealthChangedLocal()
259
+ {
260
+ // Update UI
261
+ }
262
+ }
263
+
264
+ // Input structure
265
+ public struct NetworkInputData : INetworkInput
266
+ {
267
+ public Vector2 Direction;
268
+ public NetworkButtons Buttons;
269
+ }
270
+ ```
271
+
272
+ ---
273
+
274
+ ## Mirror (Open Source)
275
+
276
+ ### Basic Setup
277
+
278
+ ```csharp
279
+ // 1. Install Mirror from Asset Store (FREE)
280
+
281
+ public class MirrorPlayer : NetworkBehaviour
282
+ {
283
+ [SyncVar(hook = nameof(OnHealthChanged))]
284
+ public int health = 100;
285
+
286
+ [SyncVar]
287
+ public string playerName;
288
+
289
+ void Update()
290
+ {
291
+ if (!isLocalPlayer) return;
292
+
293
+ float h = Input.GetAxisRaw("Horizontal");
294
+ float v = Input.GetAxisRaw("Vertical");
295
+
296
+ if (h != 0 || v != 0)
297
+ {
298
+ CmdMove(new Vector3(h, 0, v));
299
+ }
300
+ }
301
+
302
+ [Command] // Client → Server
303
+ void CmdMove(Vector3 direction)
304
+ {
305
+ transform.position += direction.normalized * 5f * Time.deltaTime;
306
+ }
307
+
308
+ [Command]
309
+ void CmdShoot(Vector3 origin, Vector3 direction)
310
+ {
311
+ // Server validates and processes
312
+ if (Physics.Raycast(origin, direction, out RaycastHit hit, 100f))
313
+ {
314
+ if (hit.collider.TryGetComponent<MirrorPlayer>(out var target))
315
+ {
316
+ target.TakeDamage(25);
317
+ }
318
+ }
319
+
320
+ // Tell all clients to show effect
321
+ RpcShowShootEffect(origin, direction);
322
+ }
323
+
324
+ [ClientRpc] // Server → All Clients
325
+ void RpcShowShootEffect(Vector3 origin, Vector3 direction)
326
+ {
327
+ // Spawn tracer, play sound
328
+ }
329
+
330
+ [Server]
331
+ public void TakeDamage(int amount)
332
+ {
333
+ health -= amount;
334
+ if (health <= 0)
335
+ {
336
+ RpcDie();
337
+ }
338
+ }
339
+
340
+ void OnHealthChanged(int oldValue, int newValue)
341
+ {
342
+ // Update health UI
343
+ }
344
+ }
345
+ ```
346
+
347
+ ---
348
+
349
+ ## Lag Compensation
350
+
351
+ ### Client-Side Prediction
352
+
353
+ ```csharp
354
+ public class PredictedMovement : NetworkBehaviour
355
+ {
356
+ private Queue<InputFrame> _inputHistory = new();
357
+ private Vector3 _lastServerPosition;
358
+
359
+ struct InputFrame
360
+ {
361
+ public uint Tick;
362
+ public Vector3 Input;
363
+ public Vector3 PredictedPosition;
364
+ }
365
+
366
+ void Update()
367
+ {
368
+ if (!IsOwner) return;
369
+
370
+ // 1. Capture input
371
+ Vector3 input = new Vector3(
372
+ Input.GetAxisRaw("Horizontal"),
373
+ 0,
374
+ Input.GetAxisRaw("Vertical")
375
+ );
376
+
377
+ // 2. Predict locally
378
+ Vector3 predictedPos = transform.position + input * moveSpeed * Time.deltaTime;
379
+ transform.position = predictedPos;
380
+
381
+ // 3. Store for reconciliation
382
+ _inputHistory.Enqueue(new InputFrame
383
+ {
384
+ Tick = NetworkManager.Singleton.LocalTime.Tick,
385
+ Input = input,
386
+ PredictedPosition = predictedPos
387
+ });
388
+
389
+ // 4. Send to server
390
+ MoveServerRpc(input, NetworkManager.Singleton.LocalTime.Tick);
391
+ }
392
+
393
+ // When server confirms position
394
+ private void OnServerPositionReceived(Vector3 serverPos, uint serverTick)
395
+ {
396
+ _lastServerPosition = serverPos;
397
+
398
+ // Reconciliation: replay inputs since server tick
399
+ Vector3 reconciledPos = serverPos;
400
+
401
+ foreach (var frame in _inputHistory.Where(f => f.Tick > serverTick))
402
+ {
403
+ reconciledPos += frame.Input * moveSpeed * Time.fixedDeltaTime;
404
+ }
405
+
406
+ // Check for misprediction
407
+ if (Vector3.Distance(reconciledPos, transform.position) > 0.01f)
408
+ {
409
+ // Correct position smoothly
410
+ transform.position = Vector3.Lerp(transform.position, reconciledPos, 0.5f);
411
+ }
412
+
413
+ // Clean old history
414
+ while (_inputHistory.Count > 0 && _inputHistory.Peek().Tick <= serverTick)
415
+ {
416
+ _inputHistory.Dequeue();
417
+ }
418
+ }
419
+ }
420
+ ```
421
+
422
+ ### Server-Side Rewind (Hit Detection)
423
+
424
+ ```csharp
425
+ public class LagCompensatedCombat : NetworkBehaviour
426
+ {
427
+ // Store position history for rewind
428
+ private class PositionSnapshot
429
+ {
430
+ public float Timestamp;
431
+ public Vector3 Position;
432
+ public Quaternion Rotation;
433
+ }
434
+
435
+ private Queue<PositionSnapshot> _positionHistory = new();
436
+ private const int MAX_HISTORY = 64;
437
+ private const float MAX_REWIND_TIME = 0.5f; // 500ms max
438
+
439
+ void FixedUpdate()
440
+ {
441
+ if (IsServer)
442
+ {
443
+ // Record position history
444
+ _positionHistory.Enqueue(new PositionSnapshot
445
+ {
446
+ Timestamp = Time.time,
447
+ Position = transform.position,
448
+ Rotation = transform.rotation
449
+ });
450
+
451
+ while (_positionHistory.Count > MAX_HISTORY)
452
+ _positionHistory.Dequeue();
453
+ }
454
+ }
455
+
456
+ [ServerRpc]
457
+ public void ShootServerRpc(Vector3 origin, Vector3 direction, float clientTimestamp)
458
+ {
459
+ // Calculate client's RTT
460
+ float rtt = NetworkManager.Singleton.NetworkConfig.NetworkTransport.GetCurrentRtt(OwnerClientId) / 1000f;
461
+ float rewindTime = Mathf.Min(rtt + 0.1f, MAX_REWIND_TIME);
462
+
463
+ // Rewind all players to client's perspective
464
+ var originalPositions = new Dictionary<NetworkObject, Vector3>();
465
+
466
+ foreach (var player in FindObjectsOfType<LagCompensatedCombat>())
467
+ {
468
+ if (player == this) continue;
469
+
470
+ originalPositions[player.NetworkObject] = player.transform.position;
471
+ player.RewindTo(Time.time - rewindTime);
472
+ }
473
+
474
+ // Perform raycast in rewound state
475
+ if (Physics.Raycast(origin, direction, out RaycastHit hit, 100f))
476
+ {
477
+ if (hit.collider.TryGetComponent<LagCompensatedCombat>(out var target))
478
+ {
479
+ target.TakeDamage(25);
480
+ }
481
+ }
482
+
483
+ // Restore positions
484
+ foreach (var kvp in originalPositions)
485
+ {
486
+ kvp.Key.transform.position = kvp.Value;
487
+ }
488
+ }
489
+
490
+ private void RewindTo(float targetTime)
491
+ {
492
+ var snapshot = _positionHistory
493
+ .Where(s => s.Timestamp <= targetTime)
494
+ .LastOrDefault();
495
+
496
+ if (snapshot != null)
497
+ {
498
+ transform.position = snapshot.Position;
499
+ transform.rotation = snapshot.Rotation;
500
+ }
501
+ }
502
+ }
503
+ ```
504
+
505
+ ---
506
+
507
+ ## Matchmaking
508
+
509
+ ### Simple Lobby System
510
+
511
+ ```csharp
512
+ public class LobbyManager : NetworkBehaviour
513
+ {
514
+ public static LobbyManager Instance;
515
+
516
+ private NetworkList<LobbyPlayerData> _players;
517
+
518
+ public struct LobbyPlayerData : INetworkSerializable, IEquatable<LobbyPlayerData>
519
+ {
520
+ public ulong ClientId;
521
+ public FixedString32Bytes PlayerName;
522
+ public bool IsReady;
523
+
524
+ public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter
525
+ {
526
+ serializer.SerializeValue(ref ClientId);
527
+ serializer.SerializeValue(ref PlayerName);
528
+ serializer.SerializeValue(ref IsReady);
529
+ }
530
+
531
+ public bool Equals(LobbyPlayerData other) => ClientId == other.ClientId;
532
+ }
533
+
534
+ private void Awake()
535
+ {
536
+ Instance = this;
537
+ _players = new NetworkList<LobbyPlayerData>();
538
+ }
539
+
540
+ public override void OnNetworkSpawn()
541
+ {
542
+ if (IsServer)
543
+ {
544
+ NetworkManager.Singleton.OnClientConnectedCallback += OnClientConnected;
545
+ NetworkManager.Singleton.OnClientDisconnectCallback += OnClientDisconnected;
546
+ }
547
+
548
+ _players.OnListChanged += OnPlayersChanged;
549
+ }
550
+
551
+ private void OnClientConnected(ulong clientId)
552
+ {
553
+ _players.Add(new LobbyPlayerData
554
+ {
555
+ ClientId = clientId,
556
+ PlayerName = $"Player {clientId}",
557
+ IsReady = false
558
+ });
559
+ }
560
+
561
+ private void OnClientDisconnected(ulong clientId)
562
+ {
563
+ for (int i = 0; i < _players.Count; i++)
564
+ {
565
+ if (_players[i].ClientId == clientId)
566
+ {
567
+ _players.RemoveAt(i);
568
+ break;
569
+ }
570
+ }
571
+ }
572
+
573
+ [ServerRpc(RequireOwnership = false)]
574
+ public void SetReadyServerRpc(bool ready, ServerRpcParams rpcParams = default)
575
+ {
576
+ ulong clientId = rpcParams.Receive.SenderClientId;
577
+
578
+ for (int i = 0; i < _players.Count; i++)
579
+ {
580
+ if (_players[i].ClientId == clientId)
581
+ {
582
+ var player = _players[i];
583
+ player.IsReady = ready;
584
+ _players[i] = player;
585
+ break;
586
+ }
587
+ }
588
+
589
+ CheckAllReady();
590
+ }
591
+
592
+ private void CheckAllReady()
593
+ {
594
+ if (_players.Count >= 2 && _players.All(p => p.IsReady))
595
+ {
596
+ StartGame();
597
+ }
598
+ }
599
+
600
+ private void StartGame()
601
+ {
602
+ NetworkManager.Singleton.SceneManager.LoadScene("GameScene", LoadSceneMode.Single);
603
+ }
604
+ }
605
+ ```
606
+
607
+ ---
608
+
609
+ ## Anti-Cheat Patterns
610
+
611
+ ### Server Authority
612
+
613
+ ```csharp
614
+ public class ServerAuthorityExample : NetworkBehaviour
615
+ {
616
+ [ServerRpc]
617
+ private void AttackServerRpc(ulong targetId, ServerRpcParams rpcParams = default)
618
+ {
619
+ ulong attackerId = rpcParams.Receive.SenderClientId;
620
+
621
+ // 1. Validate attacker state
622
+ var attacker = NetworkManager.Singleton.SpawnManager.GetPlayerNetworkObject(attackerId);
623
+ if (!IsValidAttackState(attacker))
624
+ {
625
+ LogCheatAttempt(attackerId, "Invalid attack state");
626
+ return;
627
+ }
628
+
629
+ // 2. Validate target exists and is in range
630
+ var target = NetworkManager.Singleton.SpawnManager.SpawnedObjects[targetId];
631
+ if (target == null)
632
+ {
633
+ return;
634
+ }
635
+
636
+ float distance = Vector3.Distance(attacker.transform.position, target.transform.position);
637
+ if (distance > maxAttackRange * 1.2f) // Allow small tolerance
638
+ {
639
+ LogCheatAttempt(attackerId, $"Attack range exceeded: {distance}");
640
+ return;
641
+ }
642
+
643
+ // 3. Validate cooldown
644
+ if (!CanAttack(attackerId))
645
+ {
646
+ return;
647
+ }
648
+
649
+ // 4. Apply damage
650
+ target.GetComponent<Health>().TakeDamage(attackDamage);
651
+ }
652
+
653
+ private void LogCheatAttempt(ulong clientId, string reason)
654
+ {
655
+ Debug.LogWarning($"[ANTI-CHEAT] Client {clientId}: {reason}");
656
+
657
+ // Increment strike counter
658
+ if (++_cheatStrikes[clientId] >= 3)
659
+ {
660
+ // Kick player
661
+ NetworkManager.Singleton.DisconnectClient(clientId);
662
+ }
663
+ }
664
+ }
665
+ ```
666
+
667
+ ### Rate Limiting
668
+
669
+ ```csharp
670
+ public class RateLimiter
671
+ {
672
+ private Dictionary<ulong, Queue<float>> _actionTimestamps = new();
673
+
674
+ public bool IsAllowed(ulong clientId, int maxActions, float timeWindow)
675
+ {
676
+ if (!_actionTimestamps.ContainsKey(clientId))
677
+ {
678
+ _actionTimestamps[clientId] = new Queue<float>();
679
+ }
680
+
681
+ var timestamps = _actionTimestamps[clientId];
682
+ float now = Time.time;
683
+
684
+ // Remove old timestamps
685
+ while (timestamps.Count > 0 && now - timestamps.Peek() > timeWindow)
686
+ {
687
+ timestamps.Dequeue();
688
+ }
689
+
690
+ // Check limit
691
+ if (timestamps.Count >= maxActions)
692
+ {
693
+ return false;
694
+ }
695
+
696
+ timestamps.Enqueue(now);
697
+ return true;
698
+ }
699
+ }
700
+ ```
701
+
702
+ ---
703
+
704
+ ## Quick Reference
705
+
706
+ | Concept | Netcode | Photon Fusion | Mirror |
707
+ |---------|---------|---------------|--------|
708
+ | **Sync Variable** | NetworkVariable<T> | [Networked] | [SyncVar] |
709
+ | **Client → Server** | [ServerRpc] | RPC, Input | [Command] |
710
+ | **Server → Clients** | [ClientRpc] | RPC | [ClientRpc] |
711
+ | **Object Spawning** | NetworkObject.Spawn() | Runner.Spawn() | NetworkServer.Spawn() |
712
+
713
+ ---
714
+
715
+ ## Anti-Patterns
716
+
717
+ | ❌ Don't | ✅ Do |
718
+ |----------|-------|
719
+ | Trust client position | Server validates movement |
720
+ | Send full state every frame | Delta compression |
721
+ | No lag compensation | Implement prediction + reconciliation |
722
+ | Ignore bandwidth | Prioritize important data |
723
+ | Client-side hit detection | Server authoritative hits |
724
+
725
+ ---
726
+
727
+ > **Remember:** The server is the source of truth. Clients lie.