@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.
- package/.agent/agents/ai-asset-factory.md +700 -0
- package/.agent/agents/ai-audio-factory.md +503 -0
- package/.agent/agents/game-developer.md +4 -4
- package/.agent/agents/orchestrator.md +113 -3
- package/.agent/agents/project-planner.md +67 -0
- package/.agent/agents/unity-mobile-master.md +949 -0
- package/.agent/mcp/config/registry.json +65 -51
- package/.agent/mcp/servers/notebooklm/README.md +114 -0
- package/.agent/mcp/servers/notebooklm/package.json +35 -0
- package/.agent/mcp/servers/notebooklm/src/auth/chrome.ts +225 -0
- package/.agent/mcp/servers/notebooklm/src/auth/index.ts +1 -0
- package/.agent/mcp/servers/notebooklm/src/index.ts +516 -0
- package/.agent/mcp/servers/notebooklm/src/services/index.ts +3 -0
- package/.agent/mcp/servers/notebooklm/src/services/library.ts +217 -0
- package/.agent/mcp/servers/notebooklm/src/services/notebooklm.ts +380 -0
- package/.agent/mcp/servers/notebooklm/tsconfig.json +15 -0
- package/.agent/mcp-gateway/README.md +169 -20
- package/.agent/mcp-gateway/package.json +22 -7
- package/.agent/mcp-gateway/src/auth/index.ts +55 -0
- package/.agent/mcp-gateway/src/auth/middleware.ts +242 -0
- package/.agent/mcp-gateway/src/auth/oauth.ts +462 -0
- package/.agent/mcp-gateway/src/auth/scopes.ts +227 -0
- package/.agent/mcp-gateway/src/index.ts +252 -105
- package/.agent/mcp-gateway/src/observability/index.ts +5 -0
- package/.agent/mcp-gateway/src/observability/otel.ts +405 -0
- package/.agent/mcp-gateway/src/transports/index.ts +5 -0
- package/.agent/mcp-gateway/src/transports/streamableHttp.ts +235 -0
- package/.agent/rules/CODEX.md +89 -0
- package/.agent/rules/CODE_RULES.md +73 -0
- package/.agent/rules/GEMINI.md +25 -0
- package/.agent/rules/MEMORY_STATE.md +110 -0
- package/.agent/rules/REFERENCE.md +33 -141
- package/.agent/rules/REF_SKILLS.md +116 -0
- package/.agent/rules/REF_WORKFLOWS.md +81 -0
- package/.agent/scripts/ak_cli.py +106 -5
- package/.agent/scripts/memory_manager.py +48 -9
- package/.agent/skills/anti-hallucination/SKILL.md +295 -0
- package/.agent/skills/anti-hallucination/scripts/check_hallucination.py +299 -0
- package/.agent/skills/bifurcation-analysis/SKILL.md +56 -0
- package/.agent/skills/brainstorming/SKILL.md +80 -6
- package/.agent/skills/decision-memory/SKILL.md +317 -0
- package/.agent/skills/emergence-detector/SKILL.md +230 -0
- package/.agent/skills/emergence-detector/scripts/check_emergence.py +265 -0
- package/.agent/skills/explained-qa/SKILL.md +142 -0
- package/.agent/skills/explained-qa/game-terminology.md +214 -0
- package/.agent/skills/game-development/ai-dialogue-engine/SKILL.md +442 -0
- package/.agent/skills/game-development/ai-graphics-generator/SKILL.md +463 -0
- package/.agent/skills/game-development/ai-playtest-framework/SKILL.md +570 -0
- package/.agent/skills/game-development/camera-systems/SKILL.md +607 -0
- package/.agent/skills/game-development/card-battle-engine/SKILL.md +618 -0
- package/.agent/skills/game-development/character-controller-3d/SKILL.md +908 -0
- package/.agent/skills/game-development/cloud-save-sync/SKILL.md +527 -0
- package/.agent/skills/game-development/combat-system/SKILL.md +748 -0
- package/.agent/skills/game-development/compliance-rating/SKILL.md +277 -0
- package/.agent/skills/game-development/crossplatform-build/SKILL.md +386 -0
- package/.agent/skills/game-development/cultivation-progression/SKILL.md +520 -0
- package/.agent/skills/game-development/data-driven-balance/SKILL.md +535 -0
- package/.agent/skills/game-development/game-analytics-integrator/SKILL.md +410 -0
- package/.agent/skills/game-development/game-audio-advanced/SKILL.md +646 -0
- package/.agent/skills/game-development/game-economy-designer/SKILL.md +375 -0
- package/.agent/skills/game-development/game-marketing/SKILL.md +85 -0
- package/.agent/skills/game-development/game-state-manager/SKILL.md +883 -0
- package/.agent/skills/game-development/hybrid-game-spec/SKILL.md +220 -0
- package/.agent/skills/game-development/inventory-quest/SKILL.md +747 -0
- package/.agent/skills/game-development/liveops/SKILL.md +308 -0
- package/.agent/skills/game-development/localization/SKILL.md +286 -0
- package/.agent/skills/game-development/mobile-input-patterns/SKILL.md +343 -0
- package/.agent/skills/game-development/monetization-strategy/SKILL.md +94 -0
- package/.agent/skills/game-development/multiplayer-master/SKILL.md +727 -0
- package/.agent/skills/game-development/narrative-branching/SKILL.md +593 -0
- package/.agent/skills/game-development/procedural-level-ai/SKILL.md +367 -0
- package/.agent/skills/game-development/prototyping-rapid/SKILL.md +205 -0
- package/.agent/skills/game-development/spec-ecosystem/SKILL.md +155 -0
- package/.agent/skills/game-development/spec-ecosystem/decision-log-format.md +129 -0
- package/.agent/skills/game-development/spec-ecosystem/templates/PLAN-template.md +178 -0
- package/.agent/skills/game-development/spec-ecosystem/templates/SPEC-template.md +110 -0
- package/.agent/skills/game-development/spec-ecosystem/templates/TASKS-template.md +156 -0
- package/.agent/skills/game-development/survival-systems/SKILL.md +493 -0
- package/.agent/skills/game-development/testing-qa/SKILL.md +270 -0
- package/.agent/skills/game-development/unity-mobile-optimization/SKILL.md +271 -0
- package/.agent/skills/intent-capture/SKILL.md +65 -0
- package/.agent/skills/mcp-composition/SKILL.md +362 -0
- package/.agent/skills/mcp-observability/SKILL.md +323 -0
- package/.agent/skills/mcp-security/SKILL.md +314 -0
- package/.agent/skills/trust-spectrum/SKILL.md +291 -0
- package/.agent/skills/vibe-coding-guard/SKILL.md +328 -0
- package/.agent/templates/AGENTS.game.md +63 -0
- package/.agent/templates/docs/WORKFLOW_GUIDE.en.md +100 -0
- package/.agent/templates/docs/WORKFLOW_GUIDE.vi.md +100 -0
- package/.agent/workflows/ai-agent.md +2 -0
- package/.agent/workflows/autofix.md +1 -0
- package/.agent/workflows/brainstorm.md +1 -0
- package/.agent/workflows/context.md +1 -0
- package/.agent/workflows/create.md +39 -8
- package/.agent/workflows/dashboard.md +1 -0
- package/.agent/workflows/debug.md +14 -0
- package/.agent/workflows/deploy.md +14 -0
- package/.agent/workflows/enhance.md +44 -0
- package/.agent/workflows/gamekit-init.md +177 -0
- package/.agent/workflows/gamekit-launch.md +338 -0
- package/.agent/workflows/gamekit-plan.md +204 -0
- package/.agent/workflows/gamekit-qa.md +153 -0
- package/.agent/workflows/gamekit-spec.md +243 -0
- package/.agent/workflows/gamekit-tasks.md +208 -0
- package/.agent/workflows/marketing.md +2 -0
- package/.agent/workflows/next.md +1 -0
- package/.agent/workflows/orchestrate.md +12 -0
- package/.agent/workflows/pentest.md +2 -0
- package/.agent/workflows/plan.md +42 -0
- package/.agent/workflows/preview.md +1 -0
- package/.agent/workflows/quality.md +1 -0
- package/.agent/workflows/saas.md +2 -0
- package/.agent/workflows/spec.md +42 -0
- package/.agent/workflows/status.md +1 -0
- package/.agent/workflows/test.md +14 -0
- package/.agent/workflows/ui-ux-pro-max.md +1 -0
- package/bin/cli.js +411 -111
- package/package.json +1 -2
- package/.agent/agents/game-asset-curator.md +0 -317
- package/.agent/agents/game-narrative-designer.md +0 -310
- package/.agent/agents/game-qa-agent.md +0 -441
- package/.agent/workflows/game-prototype.md +0 -154
- package/docs/AI_DATA_INFRASTRUCTURE.md +0 -288
- package/docs/CHANGELOG_AI_INFRA.md +0 -141
- package/docs/MIGRATION_GUIDE_V1.9.md +0 -55
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: ai-playtest-framework
|
|
3
|
+
description: AI-powered automated playtesting framework. Deploy bots that play your game, find bugs, test balance, and measure player experience.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# AI Playtest Framework 🤖🎮
|
|
7
|
+
|
|
8
|
+
> **Let AI play your game 24/7.** Find bugs, test balance, and measure fun before players do.
|
|
9
|
+
|
|
10
|
+
## Overview
|
|
11
|
+
|
|
12
|
+
This skill provides patterns for implementing AI-powered playtesting bots that can:
|
|
13
|
+
- Play through your entire game automatically
|
|
14
|
+
- Find crashes, soft locks, and progression blockers
|
|
15
|
+
- Test game balance and identify exploits
|
|
16
|
+
- Measure difficulty curves and player experience
|
|
17
|
+
- Generate coverage and performance reports
|
|
18
|
+
|
|
19
|
+
---
|
|
20
|
+
|
|
21
|
+
## Bot Types
|
|
22
|
+
|
|
23
|
+
### 1. Random Bot (Monkey Testing)
|
|
24
|
+
|
|
25
|
+
**Purpose**: Find crashes and edge cases through random actions
|
|
26
|
+
|
|
27
|
+
```python
|
|
28
|
+
# random_bot.py
|
|
29
|
+
class RandomBot:
|
|
30
|
+
"""Executes random valid actions to find edge cases"""
|
|
31
|
+
|
|
32
|
+
def __init__(self, game_api):
|
|
33
|
+
self.game = game_api
|
|
34
|
+
self.action_log = []
|
|
35
|
+
self.crash_log = []
|
|
36
|
+
|
|
37
|
+
def run(self, max_steps=10000, max_crashes=10):
|
|
38
|
+
steps = 0
|
|
39
|
+
crashes = 0
|
|
40
|
+
|
|
41
|
+
while steps < max_steps and crashes < max_crashes:
|
|
42
|
+
try:
|
|
43
|
+
# Get current valid actions
|
|
44
|
+
actions = self.game.get_valid_actions()
|
|
45
|
+
|
|
46
|
+
if not actions:
|
|
47
|
+
self.log_softlock(steps)
|
|
48
|
+
self.game.reset()
|
|
49
|
+
continue
|
|
50
|
+
|
|
51
|
+
# Random action selection
|
|
52
|
+
action = random.choice(actions)
|
|
53
|
+
self.action_log.append(action)
|
|
54
|
+
|
|
55
|
+
# Execute
|
|
56
|
+
result = self.game.execute(action)
|
|
57
|
+
|
|
58
|
+
# Check for anomalies
|
|
59
|
+
self.check_anomalies(result, steps)
|
|
60
|
+
|
|
61
|
+
steps += 1
|
|
62
|
+
|
|
63
|
+
except Exception as e:
|
|
64
|
+
crashes += 1
|
|
65
|
+
self.log_crash(steps, e)
|
|
66
|
+
self.game.reset()
|
|
67
|
+
|
|
68
|
+
return self.generate_report()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
### 2. Explorer Bot (Coverage Testing)
|
|
72
|
+
|
|
73
|
+
**Purpose**: Maximize game state coverage
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
# explorer_bot.py
|
|
77
|
+
class ExplorerBot:
|
|
78
|
+
"""Systematically explores game states for maximum coverage"""
|
|
79
|
+
|
|
80
|
+
def __init__(self, game_api):
|
|
81
|
+
self.game = game_api
|
|
82
|
+
self.visited_states = set()
|
|
83
|
+
self.state_graph = {}
|
|
84
|
+
|
|
85
|
+
def run(self, target_coverage=0.8):
|
|
86
|
+
while self.get_coverage() < target_coverage:
|
|
87
|
+
# Prioritize unvisited states
|
|
88
|
+
current = self.game.get_state_hash()
|
|
89
|
+
|
|
90
|
+
if current not in self.visited_states:
|
|
91
|
+
self.visited_states.add(current)
|
|
92
|
+
self.map_connections(current)
|
|
93
|
+
|
|
94
|
+
# Move toward unexplored areas
|
|
95
|
+
next_action = self.find_path_to_unexplored()
|
|
96
|
+
|
|
97
|
+
if next_action:
|
|
98
|
+
self.game.execute(next_action)
|
|
99
|
+
else:
|
|
100
|
+
# Random exploration when stuck
|
|
101
|
+
self.random_action()
|
|
102
|
+
|
|
103
|
+
return self.generate_coverage_map()
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
### 3. Speedrun Bot (Exploit Detection)
|
|
107
|
+
|
|
108
|
+
**Purpose**: Find sequence breaks and exploits
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
# speedrun_bot.py
|
|
112
|
+
class SpeedrunBot:
|
|
113
|
+
"""Uses optimization to find fastest paths, exposing exploits"""
|
|
114
|
+
|
|
115
|
+
def __init__(self, game_api):
|
|
116
|
+
self.game = game_api
|
|
117
|
+
self.best_time = float('inf')
|
|
118
|
+
self.best_route = []
|
|
119
|
+
|
|
120
|
+
def run(self, iterations=1000):
|
|
121
|
+
for i in range(iterations):
|
|
122
|
+
self.game.reset()
|
|
123
|
+
route, time = self.attempt_speedrun()
|
|
124
|
+
|
|
125
|
+
if time < self.best_time:
|
|
126
|
+
self.best_time = time
|
|
127
|
+
self.best_route = route
|
|
128
|
+
self.check_for_exploits(route)
|
|
129
|
+
|
|
130
|
+
return self.generate_report()
|
|
131
|
+
|
|
132
|
+
def check_for_exploits(self, route):
|
|
133
|
+
"""Flag suspicious sequences"""
|
|
134
|
+
# Look for: skipped levels, duplicate rewards, etc.
|
|
135
|
+
for i, action in enumerate(route):
|
|
136
|
+
if self.is_sequence_break(route[max(0,i-5):i+1]):
|
|
137
|
+
self.log_potential_exploit(route[i-5:i+5])
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
### 4. Balance Bot (RL-Based)
|
|
141
|
+
|
|
142
|
+
**Purpose**: Find overpowered strategies using machine learning
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
# balance_bot.py
|
|
146
|
+
class BalanceBot:
|
|
147
|
+
"""Uses reinforcement learning to find optimal strategies"""
|
|
148
|
+
|
|
149
|
+
def __init__(self, game_api, model_path=None):
|
|
150
|
+
self.game = game_api
|
|
151
|
+
self.model = self.load_or_create_model(model_path)
|
|
152
|
+
self.strategy_stats = {}
|
|
153
|
+
|
|
154
|
+
def train(self, episodes=10000):
|
|
155
|
+
for episode in range(episodes):
|
|
156
|
+
state = self.game.reset()
|
|
157
|
+
total_reward = 0
|
|
158
|
+
strategy_used = []
|
|
159
|
+
|
|
160
|
+
while not self.game.is_done():
|
|
161
|
+
action = self.model.predict(state)
|
|
162
|
+
next_state, reward, done = self.game.step(action)
|
|
163
|
+
|
|
164
|
+
self.model.learn(state, action, reward, next_state)
|
|
165
|
+
|
|
166
|
+
strategy_used.append(action)
|
|
167
|
+
total_reward += reward
|
|
168
|
+
state = next_state
|
|
169
|
+
|
|
170
|
+
self.log_strategy(strategy_used, total_reward)
|
|
171
|
+
|
|
172
|
+
return self.analyze_dominant_strategies()
|
|
173
|
+
|
|
174
|
+
def analyze_dominant_strategies(self):
|
|
175
|
+
"""Find strategies that win too often"""
|
|
176
|
+
report = {
|
|
177
|
+
"dominant_strategies": [],
|
|
178
|
+
"underused_strategies": [],
|
|
179
|
+
"balance_issues": []
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
for strategy, stats in self.strategy_stats.items():
|
|
183
|
+
win_rate = stats['wins'] / stats['total']
|
|
184
|
+
|
|
185
|
+
if win_rate > 0.6:
|
|
186
|
+
report["dominant_strategies"].append({
|
|
187
|
+
"strategy": strategy,
|
|
188
|
+
"win_rate": win_rate,
|
|
189
|
+
"recommendation": "Consider nerfing"
|
|
190
|
+
})
|
|
191
|
+
elif win_rate < 0.4:
|
|
192
|
+
report["underused_strategies"].append({
|
|
193
|
+
"strategy": strategy,
|
|
194
|
+
"win_rate": win_rate,
|
|
195
|
+
"recommendation": "Consider buffing"
|
|
196
|
+
})
|
|
197
|
+
|
|
198
|
+
return report
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 5. New Player Bot (UX Testing)
|
|
202
|
+
|
|
203
|
+
**Purpose**: Simulate new player experience
|
|
204
|
+
|
|
205
|
+
```python
|
|
206
|
+
# newplayer_bot.py
|
|
207
|
+
class NewPlayerBot:
|
|
208
|
+
"""Simulates a new player to test onboarding and UX"""
|
|
209
|
+
|
|
210
|
+
def __init__(self, game_api, skill_level="novice"):
|
|
211
|
+
self.game = game_api
|
|
212
|
+
self.skill_level = skill_level
|
|
213
|
+
self.confusion_log = []
|
|
214
|
+
self.frustration_log = []
|
|
215
|
+
|
|
216
|
+
def run(self):
|
|
217
|
+
self.game.reset()
|
|
218
|
+
|
|
219
|
+
while not self.game.is_tutorial_complete():
|
|
220
|
+
# Simulate confusion: don't always pick optimal action
|
|
221
|
+
actions = self.game.get_valid_actions()
|
|
222
|
+
|
|
223
|
+
# New players might miss hints
|
|
224
|
+
if not self.noticed_hint():
|
|
225
|
+
self.confusion_log.append({
|
|
226
|
+
"state": self.game.get_state(),
|
|
227
|
+
"issue": "Missed tutorial hint"
|
|
228
|
+
})
|
|
229
|
+
|
|
230
|
+
# Simulate imperfect play
|
|
231
|
+
action = self.pick_suboptimal_action(actions)
|
|
232
|
+
result = self.game.execute(action)
|
|
233
|
+
|
|
234
|
+
# Track frustration
|
|
235
|
+
if result.is_failure:
|
|
236
|
+
self.track_frustration()
|
|
237
|
+
|
|
238
|
+
return self.generate_ux_report()
|
|
239
|
+
|
|
240
|
+
def track_frustration(self):
|
|
241
|
+
"""Track repeated failures at same point"""
|
|
242
|
+
current_level = self.game.get_current_level()
|
|
243
|
+
|
|
244
|
+
if current_level in self.failure_counts:
|
|
245
|
+
self.failure_counts[current_level] += 1
|
|
246
|
+
|
|
247
|
+
if self.failure_counts[current_level] > 3:
|
|
248
|
+
self.frustration_log.append({
|
|
249
|
+
"level": current_level,
|
|
250
|
+
"issue": "Difficulty spike - 3+ failures"
|
|
251
|
+
})
|
|
252
|
+
```
|
|
253
|
+
|
|
254
|
+
---
|
|
255
|
+
|
|
256
|
+
## Unity ML-Agents Integration
|
|
257
|
+
|
|
258
|
+
### Setup
|
|
259
|
+
|
|
260
|
+
```csharp
|
|
261
|
+
// PlaytestAgent.cs
|
|
262
|
+
using Unity.MLAgents;
|
|
263
|
+
using Unity.MLAgents.Sensors;
|
|
264
|
+
using Unity.MLAgents.Actuators;
|
|
265
|
+
|
|
266
|
+
public class PlaytestAgent : Agent
|
|
267
|
+
{
|
|
268
|
+
[Header("References")]
|
|
269
|
+
[SerializeField] private GameManager _gameManager;
|
|
270
|
+
|
|
271
|
+
[Header("Playtest Mode")]
|
|
272
|
+
[SerializeField] private PlaytestMode _mode = PlaytestMode.Explorer;
|
|
273
|
+
|
|
274
|
+
public enum PlaytestMode
|
|
275
|
+
{
|
|
276
|
+
Explorer, // Maximize coverage
|
|
277
|
+
Speedrunner, // Minimize time
|
|
278
|
+
Griefer, // Find exploits
|
|
279
|
+
NewPlayer // Simulate confusion
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
public override void OnEpisodeBegin()
|
|
283
|
+
{
|
|
284
|
+
_gameManager.ResetGame();
|
|
285
|
+
}
|
|
286
|
+
|
|
287
|
+
public override void CollectObservations(VectorSensor sensor)
|
|
288
|
+
{
|
|
289
|
+
// Add game state observations
|
|
290
|
+
sensor.AddObservation(_gameManager.PlayerPosition);
|
|
291
|
+
sensor.AddObservation(_gameManager.PlayerHealth);
|
|
292
|
+
sensor.AddObservation(_gameManager.EnemyPositions);
|
|
293
|
+
sensor.AddObservation(_gameManager.CurrentLevel);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
public override void OnActionReceived(ActionBuffers actions)
|
|
297
|
+
{
|
|
298
|
+
// Execute action
|
|
299
|
+
int action = actions.DiscreteActions[0];
|
|
300
|
+
var result = _gameManager.ExecuteAction(action);
|
|
301
|
+
|
|
302
|
+
// Reward based on mode
|
|
303
|
+
switch (_mode)
|
|
304
|
+
{
|
|
305
|
+
case PlaytestMode.Explorer:
|
|
306
|
+
AddReward(result.NewStateDiscovered ? 1f : 0f);
|
|
307
|
+
break;
|
|
308
|
+
case PlaytestMode.Speedrunner:
|
|
309
|
+
AddReward(-0.01f); // Penalize time
|
|
310
|
+
AddReward(result.LevelCompleted ? 10f : 0f);
|
|
311
|
+
break;
|
|
312
|
+
case PlaytestMode.Griefer:
|
|
313
|
+
AddReward(result.FoundExploit ? 100f : 0f);
|
|
314
|
+
break;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
// End episode on game over
|
|
318
|
+
if (result.GameOver)
|
|
319
|
+
{
|
|
320
|
+
LogPlaytestResult(result);
|
|
321
|
+
EndEpisode();
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
}
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
### Training Configuration
|
|
328
|
+
|
|
329
|
+
```yaml
|
|
330
|
+
# playtest_agent.yaml
|
|
331
|
+
behaviors:
|
|
332
|
+
PlaytestBot:
|
|
333
|
+
trainer_type: ppo
|
|
334
|
+
hyperparameters:
|
|
335
|
+
batch_size: 1024
|
|
336
|
+
buffer_size: 10240
|
|
337
|
+
learning_rate: 3.0e-4
|
|
338
|
+
beta: 5.0e-3
|
|
339
|
+
epsilon: 0.2
|
|
340
|
+
lambd: 0.95
|
|
341
|
+
num_epoch: 3
|
|
342
|
+
network_settings:
|
|
343
|
+
normalize: true
|
|
344
|
+
hidden_units: 256
|
|
345
|
+
num_layers: 2
|
|
346
|
+
reward_signals:
|
|
347
|
+
extrinsic:
|
|
348
|
+
gamma: 0.99
|
|
349
|
+
strength: 1.0
|
|
350
|
+
max_steps: 5000000
|
|
351
|
+
time_horizon: 128
|
|
352
|
+
summary_freq: 10000
|
|
353
|
+
```
|
|
354
|
+
|
|
355
|
+
---
|
|
356
|
+
|
|
357
|
+
## Godot RL Integration
|
|
358
|
+
|
|
359
|
+
### GDScript Agent
|
|
360
|
+
|
|
361
|
+
```gdscript
|
|
362
|
+
# playtest_agent.gd
|
|
363
|
+
extends Node
|
|
364
|
+
|
|
365
|
+
class_name PlaytestAgent
|
|
366
|
+
|
|
367
|
+
enum Mode { RANDOM, EXPLORER, SPEEDRUN, BALANCE }
|
|
368
|
+
|
|
369
|
+
@export var mode: Mode = Mode.EXPLORER
|
|
370
|
+
@export var max_steps: int = 10000
|
|
371
|
+
|
|
372
|
+
var step_count: int = 0
|
|
373
|
+
var visited_states: Dictionary = {}
|
|
374
|
+
var bug_log: Array = []
|
|
375
|
+
|
|
376
|
+
func _ready():
|
|
377
|
+
run_playtest()
|
|
378
|
+
|
|
379
|
+
func run_playtest():
|
|
380
|
+
while step_count < max_steps:
|
|
381
|
+
var state = get_game_state()
|
|
382
|
+
var action = select_action(state)
|
|
383
|
+
|
|
384
|
+
var result = execute_action(action)
|
|
385
|
+
|
|
386
|
+
check_for_issues(result)
|
|
387
|
+
|
|
388
|
+
step_count += 1
|
|
389
|
+
|
|
390
|
+
generate_report()
|
|
391
|
+
|
|
392
|
+
func select_action(state: Dictionary) -> int:
|
|
393
|
+
match mode:
|
|
394
|
+
Mode.RANDOM:
|
|
395
|
+
return randi() % get_action_count()
|
|
396
|
+
Mode.EXPLORER:
|
|
397
|
+
return find_unexplored_action(state)
|
|
398
|
+
Mode.SPEEDRUN:
|
|
399
|
+
return find_fastest_action(state)
|
|
400
|
+
_:
|
|
401
|
+
return 0
|
|
402
|
+
|
|
403
|
+
func check_for_issues(result: Dictionary):
|
|
404
|
+
if result.has("error"):
|
|
405
|
+
bug_log.append({
|
|
406
|
+
"step": step_count,
|
|
407
|
+
"error": result.error,
|
|
408
|
+
"state": get_game_state()
|
|
409
|
+
})
|
|
410
|
+
|
|
411
|
+
if result.get("stuck", false):
|
|
412
|
+
bug_log.append({
|
|
413
|
+
"step": step_count,
|
|
414
|
+
"issue": "Soft lock detected",
|
|
415
|
+
"state": get_game_state()
|
|
416
|
+
})
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
---
|
|
420
|
+
|
|
421
|
+
## Test Reports
|
|
422
|
+
|
|
423
|
+
### Coverage Report
|
|
424
|
+
|
|
425
|
+
```markdown
|
|
426
|
+
# Playtest Coverage Report
|
|
427
|
+
|
|
428
|
+
## Summary
|
|
429
|
+
- **Total States Explored**: 1,247
|
|
430
|
+
- **Estimated Coverage**: 78%
|
|
431
|
+
- **Unique Paths Found**: 342
|
|
432
|
+
- **Test Duration**: 4 hours
|
|
433
|
+
|
|
434
|
+
## Unexplored Areas
|
|
435
|
+
1. Level 7 secret room (requires specific item combo)
|
|
436
|
+
2. Boss phase 3 rage mode (never triggered)
|
|
437
|
+
3. Multiplayer lobby (not tested)
|
|
438
|
+
|
|
439
|
+
## Heatmap
|
|
440
|
+
[Generated level heatmap showing visited areas]
|
|
441
|
+
|
|
442
|
+
## Recommendations
|
|
443
|
+
- Add tutorial hint for secret room
|
|
444
|
+
- Lower boss phase 3 trigger threshold for testing
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
### Bug Report
|
|
448
|
+
|
|
449
|
+
```markdown
|
|
450
|
+
# Automated Bug Report
|
|
451
|
+
|
|
452
|
+
## Critical (2)
|
|
453
|
+
1. **Crash at Level 5 Boss**
|
|
454
|
+
- Steps to reproduce: [action log]
|
|
455
|
+
- Stack trace: NullReferenceException at BossAI.cs:147
|
|
456
|
+
|
|
457
|
+
2. **Soft Lock in Puzzle Room**
|
|
458
|
+
- Trigger: Push both blocks simultaneously
|
|
459
|
+
- Player cannot reset or escape
|
|
460
|
+
|
|
461
|
+
## High (5)
|
|
462
|
+
1. Out of bounds at coordinates (145, -20)
|
|
463
|
+
2. Duplicate reward on rapid retry
|
|
464
|
+
3. ...
|
|
465
|
+
|
|
466
|
+
## Medium (12)
|
|
467
|
+
...
|
|
468
|
+
|
|
469
|
+
## Low (34)
|
|
470
|
+
...
|
|
471
|
+
```
|
|
472
|
+
|
|
473
|
+
### Balance Report
|
|
474
|
+
|
|
475
|
+
```markdown
|
|
476
|
+
# Balance Analysis Report
|
|
477
|
+
|
|
478
|
+
## Dominant Strategies
|
|
479
|
+
| Strategy | Win Rate | Usage | Recommendation |
|
|
480
|
+
|----------|----------|-------|----------------|
|
|
481
|
+
| Spam Attack | 72% | 45% | Reduce attack speed |
|
|
482
|
+
| Corner Camp | 68% | 23% | Add anti-camping mechanic |
|
|
483
|
+
|
|
484
|
+
## Underused Strategies
|
|
485
|
+
| Strategy | Win Rate | Usage | Recommendation |
|
|
486
|
+
|----------|----------|-------|----------------|
|
|
487
|
+
| Defensive Build | 31% | 5% | Buff shield abilities |
|
|
488
|
+
| Stealth Approach | 28% | 3% | Reduce detection range |
|
|
489
|
+
|
|
490
|
+
## Difficulty Curve
|
|
491
|
+
[Graph showing expected vs actual difficulty by level]
|
|
492
|
+
- Level 6: Spike detected (35% more deaths than expected)
|
|
493
|
+
- Level 12-14: Too easy (consider adding challenge)
|
|
494
|
+
```
|
|
495
|
+
|
|
496
|
+
---
|
|
497
|
+
|
|
498
|
+
## CI/CD Integration
|
|
499
|
+
|
|
500
|
+
```yaml
|
|
501
|
+
# .github/workflows/playtest.yml
|
|
502
|
+
name: Automated Playtest
|
|
503
|
+
|
|
504
|
+
on:
|
|
505
|
+
push:
|
|
506
|
+
branches: [main, develop]
|
|
507
|
+
schedule:
|
|
508
|
+
- cron: '0 2 * * *' # Nightly
|
|
509
|
+
|
|
510
|
+
jobs:
|
|
511
|
+
playtest:
|
|
512
|
+
runs-on: ubuntu-latest
|
|
513
|
+
steps:
|
|
514
|
+
- uses: actions/checkout@v4
|
|
515
|
+
|
|
516
|
+
- name: Build Game
|
|
517
|
+
run: |
|
|
518
|
+
unity-builder --target StandaloneLinux64
|
|
519
|
+
|
|
520
|
+
- name: Run Random Bot (30 min)
|
|
521
|
+
run: |
|
|
522
|
+
python scripts/playtest/random_bot.py \
|
|
523
|
+
--duration 1800 \
|
|
524
|
+
--output reports/random_bot.json
|
|
525
|
+
|
|
526
|
+
- name: Run Explorer Bot (1 hour)
|
|
527
|
+
run: |
|
|
528
|
+
python scripts/playtest/explorer_bot.py \
|
|
529
|
+
--target-coverage 0.7 \
|
|
530
|
+
--max-duration 3600 \
|
|
531
|
+
--output reports/explorer.json
|
|
532
|
+
|
|
533
|
+
- name: Run Balance Bot (2 hours)
|
|
534
|
+
run: |
|
|
535
|
+
python scripts/playtest/balance_bot.py \
|
|
536
|
+
--episodes 1000 \
|
|
537
|
+
--output reports/balance.json
|
|
538
|
+
|
|
539
|
+
- name: Generate Report
|
|
540
|
+
run: |
|
|
541
|
+
python scripts/playtest/generate_report.py \
|
|
542
|
+
--inputs reports/*.json \
|
|
543
|
+
--output reports/final_report.md
|
|
544
|
+
|
|
545
|
+
- name: Upload Reports
|
|
546
|
+
uses: actions/upload-artifact@v4
|
|
547
|
+
with:
|
|
548
|
+
name: playtest-reports
|
|
549
|
+
path: reports/
|
|
550
|
+
|
|
551
|
+
- name: Fail on Critical Bugs
|
|
552
|
+
run: |
|
|
553
|
+
python scripts/playtest/check_critical.py reports/final_report.md
|
|
554
|
+
```
|
|
555
|
+
|
|
556
|
+
---
|
|
557
|
+
|
|
558
|
+
## Best Practices
|
|
559
|
+
|
|
560
|
+
| Practice | Why |
|
|
561
|
+
|----------|-----|
|
|
562
|
+
| Run nightly | Catch regressions early |
|
|
563
|
+
| Vary seed values | Different random paths |
|
|
564
|
+
| Combine bot types | Each finds different issues |
|
|
565
|
+
| Track metrics over time | Detect trends |
|
|
566
|
+
| Automate report creation | Reduce manual work |
|
|
567
|
+
|
|
568
|
+
---
|
|
569
|
+
|
|
570
|
+
> **AI playtesting runs while you sleep.** Wake up to bug reports and balance insights. 🌙
|