bmad-method 6.0.0-alpha.17 → 6.0.0-alpha.19
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.
- package/CHANGELOG.md +117 -0
- package/package.json +1 -1
- package/src/modules/bmgd/_module-installer/installer.js +160 -0
- package/src/modules/bmgd/_module-installer/platform-specifics/claude-code.js +23 -0
- package/src/modules/bmgd/_module-installer/platform-specifics/windsurf.js +18 -0
- package/src/modules/bmgd/agents/game-architect.agent.yaml +23 -8
- package/src/modules/bmgd/agents/game-designer.agent.yaml +38 -18
- package/src/modules/bmgd/agents/game-dev.agent.yaml +30 -14
- package/src/modules/bmgd/agents/game-qa.agent.yaml +64 -0
- package/src/modules/bmgd/agents/game-scrum-master.agent.yaml +27 -39
- package/src/modules/bmgd/agents/game-solo-dev.agent.yaml +56 -0
- package/src/modules/bmgd/docs/README.md +180 -0
- package/src/modules/bmgd/docs/agents-guide.md +407 -0
- package/src/modules/bmgd/docs/game-types-guide.md +503 -0
- package/src/modules/bmgd/docs/glossary.md +294 -0
- package/src/modules/bmgd/docs/quick-flow-guide.md +288 -0
- package/src/modules/bmgd/docs/quick-start.md +250 -0
- package/src/modules/bmgd/docs/troubleshooting.md +259 -0
- package/src/modules/bmgd/docs/workflow-overview.jpg +0 -0
- package/src/modules/bmgd/docs/workflows-guide.md +463 -0
- package/src/modules/bmgd/gametest/knowledge/balance-testing.md +220 -0
- package/src/modules/bmgd/gametest/knowledge/certification-testing.md +319 -0
- package/src/modules/bmgd/gametest/knowledge/compatibility-testing.md +228 -0
- package/src/modules/bmgd/gametest/knowledge/godot-testing.md +376 -0
- package/src/modules/bmgd/gametest/knowledge/input-testing.md +315 -0
- package/src/modules/bmgd/gametest/knowledge/localization-testing.md +304 -0
- package/src/modules/bmgd/gametest/knowledge/multiplayer-testing.md +322 -0
- package/src/modules/bmgd/gametest/knowledge/performance-testing.md +204 -0
- package/src/modules/bmgd/gametest/knowledge/playtesting.md +384 -0
- package/src/modules/bmgd/gametest/knowledge/qa-automation.md +190 -0
- package/src/modules/bmgd/gametest/knowledge/regression-testing.md +280 -0
- package/src/modules/bmgd/gametest/knowledge/save-testing.md +280 -0
- package/src/modules/bmgd/gametest/knowledge/smoke-testing.md +404 -0
- package/src/modules/bmgd/gametest/knowledge/test-priorities.md +271 -0
- package/src/modules/bmgd/gametest/knowledge/unity-testing.md +383 -0
- package/src/modules/bmgd/gametest/knowledge/unreal-testing.md +388 -0
- package/src/modules/bmgd/gametest/qa-index.csv +17 -0
- package/src/modules/bmgd/module.yaml +25 -9
- package/src/modules/bmgd/teams/default-party.csv +2 -0
- package/src/modules/bmgd/teams/team-gamedev.yaml +12 -1
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-01-init.md +164 -0
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-02-context.md +210 -0
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-03-ideation.md +289 -0
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/steps/step-04-complete.md +275 -0
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/workflow.md +49 -0
- package/src/modules/bmgd/workflows/1-preproduction/brainstorm-game/workflow.yaml +29 -8
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-01-init.md +223 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-01b-continue.md +151 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-02-vision.md +218 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-03-market.md +218 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-04-fundamentals.md +231 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-05-scope.md +242 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-06-references.md +224 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-07-content.md +282 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/steps/step-08-complete.md +296 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/workflow.md +62 -0
- package/src/modules/bmgd/workflows/1-preproduction/game-brief/workflow.yaml +40 -9
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-01-init.md +248 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-01b-continue.md +173 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-02-context.md +332 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-03-platforms.md +245 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-04-vision.md +229 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-05-core-gameplay.md +258 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-06-mechanics.md +249 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-07-game-type.md +266 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-08-progression.md +272 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-09-levels.md +264 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-10-art-audio.md +255 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-11-technical.md +275 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-12-epics.md +284 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-13-metrics.md +250 -0
- package/src/modules/bmgd/workflows/2-design/gdd/steps/step-14-complete.md +335 -0
- package/src/modules/bmgd/workflows/2-design/gdd/workflow.md +61 -0
- package/src/modules/bmgd/workflows/2-design/gdd/workflow.yaml +27 -7
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-01-init.md +228 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-01b-continue.md +163 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-02-foundation.md +262 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-03-story.md +238 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-04-characters.md +297 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-05-world.md +262 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-06-dialogue.md +250 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-07-environmental.md +244 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-08-delivery.md +264 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-09-integration.md +254 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-10-production.md +262 -0
- package/src/modules/bmgd/workflows/2-design/narrative/steps/step-11-complete.md +331 -0
- package/src/modules/bmgd/workflows/2-design/narrative/workflow.md +57 -0
- package/src/modules/bmgd/workflows/2-design/narrative/workflow.yaml +53 -8
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-01-init.md +223 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-01b-continue.md +153 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-02-context.md +262 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-03-starter.md +290 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-04-decisions.md +300 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-05-crosscutting.md +319 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-06-structure.md +304 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-07-patterns.md +349 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-08-validation.md +293 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/steps/step-09-complete.md +302 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/workflow.md +55 -0
- package/src/modules/bmgd/workflows/3-technical/game-architecture/workflow.yaml +50 -21
- package/src/modules/bmgd/workflows/4-production/code-review/checklist.md +23 -0
- package/src/modules/bmgd/workflows/4-production/code-review/instructions.xml +225 -0
- package/src/modules/bmgd/workflows/4-production/code-review/workflow.yaml +18 -15
- package/src/modules/bmgd/workflows/4-production/correct-course/checklist.md +1 -1
- package/src/modules/bmgd/workflows/4-production/correct-course/instructions.md +1 -1
- package/src/modules/bmgd/workflows/4-production/correct-course/workflow.yaml +11 -6
- package/src/modules/bmgd/workflows/4-production/create-story/checklist.md +332 -214
- package/src/modules/bmgd/workflows/4-production/create-story/instructions.xml +298 -0
- package/src/modules/bmgd/workflows/4-production/create-story/template.md +3 -5
- package/src/modules/bmgd/workflows/4-production/create-story/workflow.yaml +12 -7
- package/src/modules/bmgd/workflows/4-production/dev-story/checklist.md +65 -23
- package/src/modules/bmgd/workflows/4-production/dev-story/instructions.xml +409 -0
- package/src/modules/bmgd/workflows/4-production/dev-story/workflow.yaml +13 -3
- package/src/modules/bmgd/workflows/4-production/retrospective/instructions.md +4 -4
- package/src/modules/bmgd/workflows/4-production/retrospective/workflow.yaml +12 -7
- package/src/modules/bmgd/workflows/4-production/sprint-planning/instructions.md +32 -41
- package/src/modules/bmgd/workflows/4-production/sprint-planning/sprint-status-template.yaml +13 -13
- package/src/modules/bmgd/workflows/4-production/sprint-planning/workflow.yaml +6 -1
- package/src/modules/bmgd/workflows/4-production/sprint-status/instructions.md +229 -0
- package/src/modules/bmgd/workflows/4-production/sprint-status/workflow.yaml +35 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/create-tech-spec/instructions.md +140 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/create-tech-spec/workflow.yaml +27 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-dev/checklist.md +37 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-dev/instructions.md +220 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-dev/workflow.yaml +45 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-prototype/checklist.md +26 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-prototype/instructions.md +156 -0
- package/src/modules/bmgd/workflows/bmgd-quick-flow/quick-prototype/workflow.yaml +36 -0
- package/src/modules/bmgd/workflows/gametest/automate/checklist.md +93 -0
- package/src/modules/bmgd/workflows/gametest/automate/instructions.md +317 -0
- package/src/modules/bmgd/workflows/gametest/automate/workflow.yaml +50 -0
- package/src/modules/bmgd/workflows/gametest/performance/checklist.md +96 -0
- package/src/modules/bmgd/workflows/gametest/performance/instructions.md +323 -0
- package/src/modules/bmgd/workflows/gametest/performance/performance-template.md +256 -0
- package/src/modules/bmgd/workflows/gametest/performance/workflow.yaml +48 -0
- package/src/modules/bmgd/workflows/gametest/playtest-plan/checklist.md +93 -0
- package/src/modules/bmgd/workflows/gametest/playtest-plan/instructions.md +297 -0
- package/src/modules/bmgd/workflows/gametest/playtest-plan/playtest-template.md +208 -0
- package/src/modules/bmgd/workflows/gametest/playtest-plan/workflow.yaml +59 -0
- package/src/modules/bmgd/workflows/gametest/test-design/checklist.md +98 -0
- package/src/modules/bmgd/workflows/gametest/test-design/instructions.md +280 -0
- package/src/modules/bmgd/workflows/gametest/test-design/test-design-template.md +205 -0
- package/src/modules/bmgd/workflows/gametest/test-design/workflow.yaml +47 -0
- package/src/modules/bmgd/workflows/gametest/test-framework/checklist.md +103 -0
- package/src/modules/bmgd/workflows/gametest/test-framework/instructions.md +348 -0
- package/src/modules/bmgd/workflows/gametest/test-framework/workflow.yaml +48 -0
- package/src/modules/bmgd/workflows/gametest/test-review/checklist.md +87 -0
- package/src/modules/bmgd/workflows/gametest/test-review/instructions.md +272 -0
- package/src/modules/bmgd/workflows/gametest/test-review/test-review-template.md +203 -0
- package/src/modules/bmgd/workflows/gametest/test-review/workflow.yaml +48 -0
- package/src/modules/bmgd/workflows/workflow-status/init/instructions.md +299 -0
- package/src/modules/bmgd/workflows/workflow-status/init/workflow.yaml +29 -0
- package/src/modules/bmgd/workflows/workflow-status/instructions.md +395 -0
- package/src/modules/bmgd/workflows/workflow-status/paths/gamedev-brownfield.yaml +65 -0
- package/src/modules/bmgd/workflows/workflow-status/paths/gamedev-greenfield.yaml +71 -0
- package/src/modules/bmgd/workflows/workflow-status/paths/quickflow-brownfield.yaml +29 -0
- package/src/modules/bmgd/workflows/workflow-status/paths/quickflow-greenfield.yaml +39 -0
- package/src/modules/bmgd/workflows/workflow-status/project-levels.yaml +63 -0
- package/src/modules/bmgd/workflows/workflow-status/workflow-status-template.yaml +24 -0
- package/src/modules/bmgd/workflows/workflow-status/workflow.yaml +30 -0
- package/tools/cli/commands/install.js +9 -0
- package/tools/cli/installers/lib/core/installer.js +140 -592
- package/tools/cli/installers/lib/modules/manager.js +15 -3
- package/tools/cli/lib/agent/compiler.js +99 -0
- package/tools/cli/lib/ui.js +78 -27
- package/src/modules/bmgd/workflows/2-design/gdd/instructions-gdd.md +0 -502
- package/src/modules/bmgd/workflows/4-production/code-review/instructions.md +0 -398
- package/src/modules/bmgd/workflows/4-production/create-story/instructions.md +0 -256
- package/src/modules/bmgd/workflows/4-production/dev-story/instructions.md +0 -267
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/checklist.md +0 -17
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/instructions.md +0 -164
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/template.md +0 -76
- package/src/modules/bmgd/workflows/4-production/epic-tech-context/workflow.yaml +0 -58
- package/src/modules/bmgd/workflows/4-production/story-context/checklist.md +0 -16
- package/src/modules/bmgd/workflows/4-production/story-context/context-template.xml +0 -34
- package/src/modules/bmgd/workflows/4-production/story-context/instructions.md +0 -209
- package/src/modules/bmgd/workflows/4-production/story-context/workflow.yaml +0 -63
- package/src/modules/bmgd/workflows/4-production/story-done/instructions.md +0 -111
- package/src/modules/bmgd/workflows/4-production/story-done/workflow.yaml +0 -28
- package/src/modules/bmgd/workflows/4-production/story-ready/instructions.md +0 -117
- package/src/modules/bmgd/workflows/4-production/story-ready/workflow.yaml +0 -25
- /package/src/modules/bmgd/workflows/1-preproduction/game-brief/{template.md → templates/game-brief-template.md} +0 -0
- /package/src/modules/bmgd/workflows/2-design/gdd/{gdd-template.md → templates/gdd-template.md} +0 -0
- /package/src/modules/bmgd/workflows/2-design/narrative/{narrative-template.md → templates/narrative-template.md} +0 -0
- /package/src/modules/bmgd/workflows/3-technical/game-architecture/{architecture-template.md → templates/architecture-template.md} +0 -0
|
@@ -0,0 +1,304 @@
|
|
|
1
|
+
# Localization Testing Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Localization testing ensures games work correctly across languages, regions, and cultures. Beyond translation, it validates text display, cultural appropriateness, and regional compliance.
|
|
6
|
+
|
|
7
|
+
## Test Categories
|
|
8
|
+
|
|
9
|
+
### Linguistic Testing
|
|
10
|
+
|
|
11
|
+
| Category | Focus | Examples |
|
|
12
|
+
| -------------------- | ----------------------- | ------------------------------ |
|
|
13
|
+
| Translation accuracy | Meaning preserved | Idioms, game terminology |
|
|
14
|
+
| Grammar/spelling | Language correctness | Verb tense, punctuation |
|
|
15
|
+
| Consistency | Same terms throughout | "Health" vs "HP" vs "Life" |
|
|
16
|
+
| Context | Meaning in game context | Item names, skill descriptions |
|
|
17
|
+
|
|
18
|
+
### Functional Testing
|
|
19
|
+
|
|
20
|
+
| Category | Focus | Examples |
|
|
21
|
+
| -------------- | ----------------------- | --------------------------- |
|
|
22
|
+
| Text display | Fits in UI | Button labels, dialog boxes |
|
|
23
|
+
| Font support | Characters render | CJK, Cyrillic, Arabic |
|
|
24
|
+
| Text expansion | Longer translations | German is ~30% longer |
|
|
25
|
+
| RTL support | Right-to-left languages | Arabic, Hebrew layouts |
|
|
26
|
+
|
|
27
|
+
### Cultural Testing
|
|
28
|
+
|
|
29
|
+
| Category | Focus | Examples |
|
|
30
|
+
| -------------------- | ------------------ | ------------------------- |
|
|
31
|
+
| Cultural sensitivity | Offensive content | Gestures, symbols, colors |
|
|
32
|
+
| Regional compliance | Legal requirements | Ratings, gambling laws |
|
|
33
|
+
| Date/time formats | Local conventions | DD/MM/YYYY vs MM/DD/YYYY |
|
|
34
|
+
| Number formats | Decimal separators | 1,000.00 vs 1.000,00 |
|
|
35
|
+
|
|
36
|
+
## Test Scenarios
|
|
37
|
+
|
|
38
|
+
### Text Display
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
SCENARIO: Text Fits UI Elements
|
|
42
|
+
GIVEN all localized strings
|
|
43
|
+
WHEN displayed in target language
|
|
44
|
+
THEN text fits within UI boundaries
|
|
45
|
+
AND no truncation or overflow occurs
|
|
46
|
+
AND text remains readable
|
|
47
|
+
|
|
48
|
+
SCENARIO: Dynamic Text Insertion
|
|
49
|
+
GIVEN template "Player {name} scored {points} points"
|
|
50
|
+
WHEN name="Alexander" and points=1000
|
|
51
|
+
THEN German: "Spieler Alexander hat 1.000 Punkte erzielt"
|
|
52
|
+
AND text fits UI element
|
|
53
|
+
AND variables are correctly formatted for locale
|
|
54
|
+
|
|
55
|
+
SCENARIO: Plural Forms
|
|
56
|
+
GIVEN English "1 coin" / "5 coins"
|
|
57
|
+
WHEN displaying in Polish (4 plural forms)
|
|
58
|
+
THEN correct plural form is used
|
|
59
|
+
AND all plural forms are translated
|
|
60
|
+
```
|
|
61
|
+
|
|
62
|
+
### Character Support
|
|
63
|
+
|
|
64
|
+
```
|
|
65
|
+
SCENARIO: CJK Character Rendering
|
|
66
|
+
GIVEN Japanese localization
|
|
67
|
+
WHEN displaying text with kanji/hiragana/katakana
|
|
68
|
+
THEN all characters render correctly
|
|
69
|
+
AND no missing glyphs (tofu boxes)
|
|
70
|
+
AND line breaks respect CJK rules
|
|
71
|
+
|
|
72
|
+
SCENARIO: Special Characters
|
|
73
|
+
GIVEN text with accented characters (é, ñ, ü)
|
|
74
|
+
WHEN displayed in-game
|
|
75
|
+
THEN all characters render correctly
|
|
76
|
+
AND sorting works correctly
|
|
77
|
+
|
|
78
|
+
SCENARIO: User-Generated Content
|
|
79
|
+
GIVEN player can name character
|
|
80
|
+
WHEN name includes non-Latin characters
|
|
81
|
+
THEN name displays correctly
|
|
82
|
+
AND name saves/loads correctly
|
|
83
|
+
AND name appears correctly to other players
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Layout and Direction
|
|
87
|
+
|
|
88
|
+
```
|
|
89
|
+
SCENARIO: Right-to-Left Layout
|
|
90
|
+
GIVEN Arabic localization
|
|
91
|
+
WHEN viewing UI
|
|
92
|
+
THEN text reads right-to-left
|
|
93
|
+
AND UI elements mirror appropriately
|
|
94
|
+
AND numbers remain left-to-right
|
|
95
|
+
AND mixed content (Arabic + English) displays correctly
|
|
96
|
+
|
|
97
|
+
SCENARIO: Text Expansion Accommodation
|
|
98
|
+
GIVEN English UI "OK" / "Cancel" buttons
|
|
99
|
+
WHEN localized to German "OK" / "Abbrechen"
|
|
100
|
+
THEN button expands or text size adjusts
|
|
101
|
+
AND button remains clickable
|
|
102
|
+
AND layout doesn't break
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
## Locale-Specific Formatting
|
|
106
|
+
|
|
107
|
+
### Date and Time
|
|
108
|
+
|
|
109
|
+
| Locale | Date Format | Time Format |
|
|
110
|
+
| ------ | -------------- | ----------- |
|
|
111
|
+
| en-US | 12/25/2024 | 3:30 PM |
|
|
112
|
+
| en-GB | 25/12/2024 | 15:30 |
|
|
113
|
+
| de-DE | 25.12.2024 | 15:30 Uhr |
|
|
114
|
+
| ja-JP | 2024年12月25日 | 15時30分 |
|
|
115
|
+
|
|
116
|
+
### Numbers and Currency
|
|
117
|
+
|
|
118
|
+
| Locale | Number | Currency |
|
|
119
|
+
| ------ | -------- | ---------- |
|
|
120
|
+
| en-US | 1,234.56 | $1,234.56 |
|
|
121
|
+
| de-DE | 1.234,56 | 1.234,56 € |
|
|
122
|
+
| fr-FR | 1 234,56 | 1 234,56 € |
|
|
123
|
+
| ja-JP | 1,234.56 | ¥1,235 |
|
|
124
|
+
|
|
125
|
+
## Automated Test Examples
|
|
126
|
+
|
|
127
|
+
### Unity
|
|
128
|
+
|
|
129
|
+
```csharp
|
|
130
|
+
using UnityEngine.Localization;
|
|
131
|
+
|
|
132
|
+
[Test]
|
|
133
|
+
public void Localization_AllKeysHaveTranslations([Values("en", "de", "ja", "zh-CN")] string locale)
|
|
134
|
+
{
|
|
135
|
+
var stringTable = LocalizationSettings.StringDatabase
|
|
136
|
+
.GetTable("GameStrings", new Locale(locale));
|
|
137
|
+
|
|
138
|
+
foreach (var entry in stringTable)
|
|
139
|
+
{
|
|
140
|
+
Assert.IsFalse(string.IsNullOrEmpty(entry.Value.LocalizedValue),
|
|
141
|
+
$"Missing translation for '{entry.Key}' in {locale}");
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
[Test]
|
|
146
|
+
public void TextFits_AllUIElements()
|
|
147
|
+
{
|
|
148
|
+
var languages = new[] { "en", "de", "fr", "ja" };
|
|
149
|
+
|
|
150
|
+
foreach (var lang in languages)
|
|
151
|
+
{
|
|
152
|
+
LocalizationSettings.SelectedLocale = new Locale(lang);
|
|
153
|
+
|
|
154
|
+
foreach (var textElement in FindObjectsOfType<LocalizedText>())
|
|
155
|
+
{
|
|
156
|
+
var rectTransform = textElement.GetComponent<RectTransform>();
|
|
157
|
+
var textComponent = textElement.GetComponent<Text>();
|
|
158
|
+
|
|
159
|
+
Assert.LessOrEqual(
|
|
160
|
+
textComponent.preferredWidth,
|
|
161
|
+
rectTransform.rect.width,
|
|
162
|
+
$"Text overflows in {lang}: {textElement.name}");
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
[TestCase("en", 1, "1 coin")]
|
|
168
|
+
[TestCase("en", 5, "5 coins")]
|
|
169
|
+
[TestCase("ru", 1, "1 монета")]
|
|
170
|
+
[TestCase("ru", 2, "2 монеты")]
|
|
171
|
+
[TestCase("ru", 5, "5 монет")]
|
|
172
|
+
public void Pluralization_ReturnsCorrectForm(string locale, int count, string expected)
|
|
173
|
+
{
|
|
174
|
+
var result = Localization.GetPlural("coin", count, locale);
|
|
175
|
+
Assert.AreEqual(expected, result);
|
|
176
|
+
}
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Unreal
|
|
180
|
+
|
|
181
|
+
```cpp
|
|
182
|
+
bool FLocalizationTest::RunTest(const FString& Parameters)
|
|
183
|
+
{
|
|
184
|
+
TArray<FString> Cultures = {"en", "de", "ja", "ko"};
|
|
185
|
+
|
|
186
|
+
for (const FString& Culture : Cultures)
|
|
187
|
+
{
|
|
188
|
+
FInternationalization::Get().SetCurrentCulture(Culture);
|
|
189
|
+
|
|
190
|
+
// Test critical strings exist
|
|
191
|
+
FText LocalizedText = NSLOCTEXT("Game", "StartButton", "Start");
|
|
192
|
+
TestFalse(
|
|
193
|
+
FString::Printf(TEXT("Missing StartButton in %s"), *Culture),
|
|
194
|
+
LocalizedText.IsEmpty());
|
|
195
|
+
|
|
196
|
+
// Test number formatting
|
|
197
|
+
FText NumberText = FText::AsNumber(1234567);
|
|
198
|
+
TestTrue(
|
|
199
|
+
TEXT("Number should be formatted"),
|
|
200
|
+
NumberText.ToString().Len() > 7); // Has separators
|
|
201
|
+
}
|
|
202
|
+
|
|
203
|
+
return true;
|
|
204
|
+
}
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Godot
|
|
208
|
+
|
|
209
|
+
```gdscript
|
|
210
|
+
func test_all_translations_complete():
|
|
211
|
+
var locales = ["en", "de", "ja", "es"]
|
|
212
|
+
var keys = TranslationServer.get_all_keys()
|
|
213
|
+
|
|
214
|
+
for locale in locales:
|
|
215
|
+
TranslationServer.set_locale(locale)
|
|
216
|
+
for key in keys:
|
|
217
|
+
var translated = tr(key)
|
|
218
|
+
assert_ne(translated, key,
|
|
219
|
+
"Missing translation for '%s' in %s" % [key, locale])
|
|
220
|
+
|
|
221
|
+
func test_plural_forms():
|
|
222
|
+
TranslationServer.set_locale("ru")
|
|
223
|
+
|
|
224
|
+
assert_eq(tr_n("coin", "coins", 1), "1 монета")
|
|
225
|
+
assert_eq(tr_n("coin", "coins", 2), "2 монеты")
|
|
226
|
+
assert_eq(tr_n("coin", "coins", 5), "5 монет")
|
|
227
|
+
assert_eq(tr_n("coin", "coins", 21), "21 монета")
|
|
228
|
+
|
|
229
|
+
func test_text_fits_buttons():
|
|
230
|
+
var locales = ["en", "de", "fr"]
|
|
231
|
+
|
|
232
|
+
for locale in locales:
|
|
233
|
+
TranslationServer.set_locale(locale)
|
|
234
|
+
await get_tree().process_frame # Allow UI update
|
|
235
|
+
|
|
236
|
+
for button in get_tree().get_nodes_in_group("localized_buttons"):
|
|
237
|
+
var label = button.get_node("Label")
|
|
238
|
+
assert_lt(label.size.x, button.size.x,
|
|
239
|
+
"Button text overflows in %s: %s" % [locale, button.name])
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Visual Verification Checklist
|
|
243
|
+
|
|
244
|
+
### Text Display
|
|
245
|
+
|
|
246
|
+
- [ ] No truncation in any language
|
|
247
|
+
- [ ] Consistent font sizing
|
|
248
|
+
- [ ] Proper line breaks
|
|
249
|
+
- [ ] No overlapping text
|
|
250
|
+
|
|
251
|
+
### UI Layout
|
|
252
|
+
|
|
253
|
+
- [ ] Buttons accommodate longer text
|
|
254
|
+
- [ ] Dialog boxes resize appropriately
|
|
255
|
+
- [ ] Menu items align correctly
|
|
256
|
+
- [ ] Scrollbars appear when needed
|
|
257
|
+
|
|
258
|
+
### Cultural Elements
|
|
259
|
+
|
|
260
|
+
- [ ] Icons are culturally appropriate
|
|
261
|
+
- [ ] Colors don't have negative connotations
|
|
262
|
+
- [ ] Gestures are region-appropriate
|
|
263
|
+
- [ ] No unintended political references
|
|
264
|
+
|
|
265
|
+
## Regional Compliance
|
|
266
|
+
|
|
267
|
+
### Ratings Requirements
|
|
268
|
+
|
|
269
|
+
| Region | Rating Board | Special Requirements |
|
|
270
|
+
| ------------- | ------------ | ------------------------- |
|
|
271
|
+
| North America | ESRB | Content descriptors |
|
|
272
|
+
| Europe | PEGI | Age-appropriate icons |
|
|
273
|
+
| Japan | CERO | Strict content guidelines |
|
|
274
|
+
| Germany | USK | Violence restrictions |
|
|
275
|
+
| China | GRAC | Approval process |
|
|
276
|
+
|
|
277
|
+
### Common Regional Issues
|
|
278
|
+
|
|
279
|
+
| Issue | Regions Affected | Solution |
|
|
280
|
+
| ---------------- | ---------------- | ------------------------ |
|
|
281
|
+
| Blood color | Japan, Germany | Option for green/disable |
|
|
282
|
+
| Gambling imagery | Many regions | Remove or modify |
|
|
283
|
+
| Skulls/bones | China | Alternative designs |
|
|
284
|
+
| Nazi imagery | Germany | Remove entirely |
|
|
285
|
+
|
|
286
|
+
## Best Practices
|
|
287
|
+
|
|
288
|
+
### DO
|
|
289
|
+
|
|
290
|
+
- Test with native speakers
|
|
291
|
+
- Plan for text expansion (reserve 30% extra space)
|
|
292
|
+
- Use placeholder text during development (Lorem ipsum-style)
|
|
293
|
+
- Support multiple input methods (IME for CJK)
|
|
294
|
+
- Test all language combinations (UI language + audio language)
|
|
295
|
+
- Validate string format parameters
|
|
296
|
+
|
|
297
|
+
### DON'T
|
|
298
|
+
|
|
299
|
+
- Hard-code strings in source code
|
|
300
|
+
- Assume left-to-right layout
|
|
301
|
+
- Concatenate translated strings
|
|
302
|
+
- Use machine translation without review
|
|
303
|
+
- Forget about date/time/number formatting
|
|
304
|
+
- Ignore cultural context of images and icons
|
|
@@ -0,0 +1,322 @@
|
|
|
1
|
+
# Multiplayer Testing Guide
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Multiplayer testing validates network code, synchronization, and the player experience under real-world conditions. Network bugs are notoriously hard to reproduce—systematic testing is essential.
|
|
6
|
+
|
|
7
|
+
## Test Categories
|
|
8
|
+
|
|
9
|
+
### Synchronization Testing
|
|
10
|
+
|
|
11
|
+
| Test Type | Description | Priority |
|
|
12
|
+
| ------------------- | ---------------------------------------- | -------- |
|
|
13
|
+
| State sync | All clients see consistent game state | P0 |
|
|
14
|
+
| Position sync | Character positions match across clients | P0 |
|
|
15
|
+
| Event ordering | Actions occur in correct sequence | P0 |
|
|
16
|
+
| Conflict resolution | Simultaneous actions handled correctly | P1 |
|
|
17
|
+
| Late join | New players sync correctly mid-game | P1 |
|
|
18
|
+
|
|
19
|
+
### Network Conditions
|
|
20
|
+
|
|
21
|
+
| Condition | Simulation Method | Test Focus |
|
|
22
|
+
| --------------- | ----------------- | ------------------------ |
|
|
23
|
+
| High latency | 200-500ms delay | Input responsiveness |
|
|
24
|
+
| Packet loss | 5-20% drop rate | State recovery |
|
|
25
|
+
| Jitter | Variable delay | Interpolation smoothness |
|
|
26
|
+
| Bandwidth limit | Throttle to 1Mbps | Data prioritization |
|
|
27
|
+
| Disconnection | Kill connection | Reconnection handling |
|
|
28
|
+
|
|
29
|
+
## Test Scenarios
|
|
30
|
+
|
|
31
|
+
### Basic Multiplayer
|
|
32
|
+
|
|
33
|
+
```
|
|
34
|
+
SCENARIO: Player Join/Leave
|
|
35
|
+
GIVEN host has started multiplayer session
|
|
36
|
+
WHEN Player 2 joins
|
|
37
|
+
THEN Player 2 appears in host's game
|
|
38
|
+
AND Player 1 appears in Player 2's game
|
|
39
|
+
AND player counts sync across all clients
|
|
40
|
+
|
|
41
|
+
SCENARIO: State Synchronization
|
|
42
|
+
GIVEN 4 players in match
|
|
43
|
+
WHEN Player 1 picks up item at position (10, 5)
|
|
44
|
+
THEN item disappears for all players
|
|
45
|
+
AND Player 1's inventory updates for all players
|
|
46
|
+
AND no duplicate pickups possible
|
|
47
|
+
|
|
48
|
+
SCENARIO: Combat Synchronization
|
|
49
|
+
GIVEN Player 1 attacks Player 2
|
|
50
|
+
WHEN attack hits
|
|
51
|
+
THEN damage is consistent on all clients
|
|
52
|
+
AND hit effects play for all players
|
|
53
|
+
AND health updates sync within 100ms
|
|
54
|
+
```
|
|
55
|
+
|
|
56
|
+
### Network Degradation
|
|
57
|
+
|
|
58
|
+
```
|
|
59
|
+
SCENARIO: High Latency Gameplay
|
|
60
|
+
GIVEN 200ms latency between players
|
|
61
|
+
WHEN Player 1 moves forward
|
|
62
|
+
THEN movement is smooth on Player 1's screen
|
|
63
|
+
AND other players see interpolated movement
|
|
64
|
+
AND position converges within 500ms
|
|
65
|
+
|
|
66
|
+
SCENARIO: Packet Loss Recovery
|
|
67
|
+
GIVEN 10% packet loss
|
|
68
|
+
WHEN important game event occurs (goal, kill, etc.)
|
|
69
|
+
THEN event is eventually delivered
|
|
70
|
+
AND game state remains consistent
|
|
71
|
+
AND no duplicate events processed
|
|
72
|
+
|
|
73
|
+
SCENARIO: Player Disconnection
|
|
74
|
+
GIVEN Player 2 disconnects unexpectedly
|
|
75
|
+
WHEN 5 seconds pass
|
|
76
|
+
THEN other players are notified
|
|
77
|
+
AND Player 2's character handles gracefully (despawn/AI takeover)
|
|
78
|
+
AND game continues without crash
|
|
79
|
+
```
|
|
80
|
+
|
|
81
|
+
### Edge Cases
|
|
82
|
+
|
|
83
|
+
```
|
|
84
|
+
SCENARIO: Simultaneous Actions
|
|
85
|
+
GIVEN Player 1 and Player 2 grab same item simultaneously
|
|
86
|
+
WHEN both inputs arrive at server
|
|
87
|
+
THEN only one player receives item
|
|
88
|
+
AND other player sees consistent state
|
|
89
|
+
AND no item duplication
|
|
90
|
+
|
|
91
|
+
SCENARIO: Host Migration
|
|
92
|
+
GIVEN host disconnects
|
|
93
|
+
WHEN migration begins
|
|
94
|
+
THEN new host is selected
|
|
95
|
+
AND game state transfers correctly
|
|
96
|
+
AND gameplay resumes within 10 seconds
|
|
97
|
+
|
|
98
|
+
SCENARIO: Reconnection
|
|
99
|
+
GIVEN Player 2 disconnects temporarily
|
|
100
|
+
WHEN Player 2 reconnects within 60 seconds
|
|
101
|
+
THEN Player 2 rejoins same session
|
|
102
|
+
AND state is synchronized
|
|
103
|
+
AND progress is preserved
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
## Network Simulation Tools
|
|
107
|
+
|
|
108
|
+
### Unity
|
|
109
|
+
|
|
110
|
+
```csharp
|
|
111
|
+
// Using Unity Transport with Network Simulator
|
|
112
|
+
using Unity.Netcode;
|
|
113
|
+
|
|
114
|
+
public class NetworkSimulator : MonoBehaviour
|
|
115
|
+
{
|
|
116
|
+
[SerializeField] private int latencyMs = 100;
|
|
117
|
+
[SerializeField] private float packetLossPercent = 5f;
|
|
118
|
+
[SerializeField] private int jitterMs = 20;
|
|
119
|
+
|
|
120
|
+
void Start()
|
|
121
|
+
{
|
|
122
|
+
var transport = NetworkManager.Singleton.GetComponent<UnityTransport>();
|
|
123
|
+
var simulator = transport.GetSimulatorParameters();
|
|
124
|
+
|
|
125
|
+
simulator.PacketDelayMS = latencyMs;
|
|
126
|
+
simulator.PacketDropRate = (int)(packetLossPercent * 100);
|
|
127
|
+
simulator.PacketJitterMS = jitterMs;
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
// Test
|
|
132
|
+
[UnityTest]
|
|
133
|
+
public IEnumerator Position_UnderLatency_ConvergesWithinThreshold()
|
|
134
|
+
{
|
|
135
|
+
EnableNetworkSimulation(latencyMs: 200);
|
|
136
|
+
|
|
137
|
+
// Move player
|
|
138
|
+
player1.Move(Vector3.forward * 10);
|
|
139
|
+
|
|
140
|
+
yield return new WaitForSeconds(1f);
|
|
141
|
+
|
|
142
|
+
// Check other client's view
|
|
143
|
+
var player1OnClient2 = client2.GetPlayerPosition(player1.Id);
|
|
144
|
+
var actualPosition = player1.transform.position;
|
|
145
|
+
|
|
146
|
+
Assert.Less(Vector3.Distance(player1OnClient2, actualPosition), 0.5f);
|
|
147
|
+
}
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
### Unreal
|
|
151
|
+
|
|
152
|
+
```cpp
|
|
153
|
+
// Using Network Emulation
|
|
154
|
+
void UNetworkTestHelper::EnableLatencySimulation(int32 LatencyMs)
|
|
155
|
+
{
|
|
156
|
+
if (UNetDriver* NetDriver = GetWorld()->GetNetDriver())
|
|
157
|
+
{
|
|
158
|
+
FPacketSimulationSettings Settings;
|
|
159
|
+
Settings.PktLag = LatencyMs;
|
|
160
|
+
Settings.PktLagVariance = LatencyMs / 10;
|
|
161
|
+
Settings.PktLoss = 0;
|
|
162
|
+
|
|
163
|
+
NetDriver->SetPacketSimulationSettings(Settings);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
// Functional test for sync
|
|
168
|
+
void AMultiplayerSyncTest::StartTest()
|
|
169
|
+
{
|
|
170
|
+
Super::StartTest();
|
|
171
|
+
|
|
172
|
+
// Spawn item on server
|
|
173
|
+
APickupItem* Item = GetWorld()->SpawnActor<APickupItem>(
|
|
174
|
+
ItemClass, FVector(0, 0, 100));
|
|
175
|
+
|
|
176
|
+
// Wait for replication
|
|
177
|
+
FTimerHandle TimerHandle;
|
|
178
|
+
GetWorld()->GetTimerManager().SetTimer(TimerHandle, [this, Item]()
|
|
179
|
+
{
|
|
180
|
+
// Verify client has item
|
|
181
|
+
if (VerifyItemExistsOnAllClients(Item))
|
|
182
|
+
{
|
|
183
|
+
FinishTest(EFunctionalTestResult::Succeeded, "Item replicated");
|
|
184
|
+
}
|
|
185
|
+
else
|
|
186
|
+
{
|
|
187
|
+
FinishTest(EFunctionalTestResult::Failed, "Item not found on clients");
|
|
188
|
+
}
|
|
189
|
+
}, 2.0f, false);
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
### Godot
|
|
194
|
+
|
|
195
|
+
```gdscript
|
|
196
|
+
# Network simulation
|
|
197
|
+
extends Node
|
|
198
|
+
|
|
199
|
+
var simulated_latency_ms := 0
|
|
200
|
+
var packet_loss_percent := 0.0
|
|
201
|
+
|
|
202
|
+
func _ready():
|
|
203
|
+
# Hook into network to simulate conditions
|
|
204
|
+
multiplayer.peer_packet_received.connect(_on_packet_received)
|
|
205
|
+
|
|
206
|
+
func _on_packet_received(id: int, packet: PackedByteArray):
|
|
207
|
+
if packet_loss_percent > 0 and randf() < packet_loss_percent / 100:
|
|
208
|
+
return # Drop packet
|
|
209
|
+
|
|
210
|
+
if simulated_latency_ms > 0:
|
|
211
|
+
await get_tree().create_timer(simulated_latency_ms / 1000.0).timeout
|
|
212
|
+
|
|
213
|
+
_process_packet(id, packet)
|
|
214
|
+
|
|
215
|
+
# Test
|
|
216
|
+
func test_position_sync_under_latency():
|
|
217
|
+
NetworkSimulator.simulated_latency_ms = 200
|
|
218
|
+
|
|
219
|
+
# Move player on host
|
|
220
|
+
host_player.position = Vector3(100, 0, 100)
|
|
221
|
+
|
|
222
|
+
await get_tree().create_timer(1.0).timeout
|
|
223
|
+
|
|
224
|
+
# Check client view
|
|
225
|
+
var client_view_position = client.get_remote_player_position(host_player.id)
|
|
226
|
+
var distance = host_player.position.distance_to(client_view_position)
|
|
227
|
+
|
|
228
|
+
assert_lt(distance, 1.0, "Position should converge within 1 unit")
|
|
229
|
+
```
|
|
230
|
+
|
|
231
|
+
## Dedicated Server Testing
|
|
232
|
+
|
|
233
|
+
### Test Matrix
|
|
234
|
+
|
|
235
|
+
| Scenario | Test Focus |
|
|
236
|
+
| --------------------- | ------------------------------------ |
|
|
237
|
+
| Server startup | Clean initialization, port binding |
|
|
238
|
+
| Client authentication | Login validation, session management |
|
|
239
|
+
| Server tick rate | Consistent updates under load |
|
|
240
|
+
| Maximum players | Performance at player cap |
|
|
241
|
+
| Server crash recovery | State preservation, reconnection |
|
|
242
|
+
|
|
243
|
+
### Load Testing
|
|
244
|
+
|
|
245
|
+
```
|
|
246
|
+
SCENARIO: Maximum Players
|
|
247
|
+
GIVEN server configured for 64 players
|
|
248
|
+
WHEN 64 players connect
|
|
249
|
+
THEN all connections succeed
|
|
250
|
+
AND server tick rate stays above 60Hz
|
|
251
|
+
AND latency stays below 50ms
|
|
252
|
+
|
|
253
|
+
SCENARIO: Stress Test
|
|
254
|
+
GIVEN 64 players performing actions simultaneously
|
|
255
|
+
WHEN running for 10 minutes
|
|
256
|
+
THEN no memory leaks
|
|
257
|
+
AND no desync events
|
|
258
|
+
AND server CPU below 80%
|
|
259
|
+
```
|
|
260
|
+
|
|
261
|
+
## Matchmaking Testing
|
|
262
|
+
|
|
263
|
+
```
|
|
264
|
+
SCENARIO: Skill-Based Matching
|
|
265
|
+
GIVEN players with skill ratings [1000, 1050, 2000, 2100]
|
|
266
|
+
WHEN matchmaking runs
|
|
267
|
+
THEN [1000, 1050] are grouped together
|
|
268
|
+
AND [2000, 2100] are grouped together
|
|
269
|
+
|
|
270
|
+
SCENARIO: Region Matching
|
|
271
|
+
GIVEN players from US-East, US-West, EU
|
|
272
|
+
WHEN matchmaking runs
|
|
273
|
+
THEN players prefer same-region matches
|
|
274
|
+
AND cross-region only when necessary
|
|
275
|
+
AND latency is acceptable for all players
|
|
276
|
+
|
|
277
|
+
SCENARIO: Queue Timeout
|
|
278
|
+
GIVEN player waiting in queue
|
|
279
|
+
WHEN 3 minutes pass without match
|
|
280
|
+
THEN matchmaking expands search criteria
|
|
281
|
+
AND player is notified of expanded search
|
|
282
|
+
```
|
|
283
|
+
|
|
284
|
+
## Security Testing
|
|
285
|
+
|
|
286
|
+
| Vulnerability | Test Method |
|
|
287
|
+
| ---------------- | --------------------------- |
|
|
288
|
+
| Speed hacking | Validate movement on server |
|
|
289
|
+
| Teleportation | Check position delta limits |
|
|
290
|
+
| Damage hacking | Server-authoritative damage |
|
|
291
|
+
| Packet injection | Validate packet checksums |
|
|
292
|
+
| Replay attacks | Use unique session tokens |
|
|
293
|
+
|
|
294
|
+
## Performance Metrics
|
|
295
|
+
|
|
296
|
+
| Metric | Good | Acceptable | Poor |
|
|
297
|
+
| --------------------- | --------- | ---------- | ---------- |
|
|
298
|
+
| Round-trip latency | < 50ms | < 100ms | > 150ms |
|
|
299
|
+
| Sync delta | < 100ms | < 200ms | > 500ms |
|
|
300
|
+
| Packet loss tolerance | < 5% | < 10% | > 15% |
|
|
301
|
+
| Bandwidth per player | < 10 KB/s | < 50 KB/s | > 100 KB/s |
|
|
302
|
+
| Server tick rate | 60+ Hz | 30+ Hz | < 20 Hz |
|
|
303
|
+
|
|
304
|
+
## Best Practices
|
|
305
|
+
|
|
306
|
+
### DO
|
|
307
|
+
|
|
308
|
+
- Test with real network conditions, not just localhost
|
|
309
|
+
- Simulate worst-case scenarios (high latency + packet loss)
|
|
310
|
+
- Use server-authoritative design for competitive games
|
|
311
|
+
- Implement lag compensation for fast-paced games
|
|
312
|
+
- Test host migration paths
|
|
313
|
+
- Log network events for debugging
|
|
314
|
+
|
|
315
|
+
### DON'T
|
|
316
|
+
|
|
317
|
+
- Trust client data for important game state
|
|
318
|
+
- Assume stable connections
|
|
319
|
+
- Skip testing with maximum player counts
|
|
320
|
+
- Ignore edge cases (simultaneous actions)
|
|
321
|
+
- Test only in ideal network conditions
|
|
322
|
+
- Forget to test reconnection flows
|