reznok/gmcabilitysystem/gmas-testing
Claude Code and agent skill by reznok/gmcabilitysystem
- community
Checking that the SKILL.md file is still in the repository.
Use when writing or running automation tests for GMC/GMAS gameplay - headless GMAS specs or networked play-in-editor tests with a dedicated server and clients.
Install
npx vskill@latest install reznok/gmcabilitysystem/gmas-testingSKILL.md
Behavior below was verified against GMC 2.3.x and GMAS 1.4. Confirm signatures in this project's own headers (paths are relative to each plugin's root, e.g.Source/GMCCore/Public/Components/GMCReplicationComponent.h); GMC's source is not part of this plugin.
GMAS gameplay is tested at three depths: the pure structs, the ability component driven through a stub movement component without a world, and the real move loop in a networked play-in-editor (PIE) session. The authoring skills (gmas:gmas-ability, gmas:gmas-effect, gmas:gmas-attribute, gmas:gmas-task) say which spec to write for each class; this skill is the mechanics: the spec harness and its limits, the headless run, and a PIE harness that starts a dedicated server plus clients, waits until every player has a pawn, asserts inside confirm windows and tears the session down. The harness code is in references/net-test-skeleton.md. What a healthy session logs and how to read a bad one: gmas:gmas-debug. GMAS paths below are relative to Source/GMCAbilitySystem/; engine paths to Engine/Source/.
Three layers
| Layer | What runs | Proves | Cannot prove | |
|---|---|---|---|---|
| 1. Structs | FAttribute, FGMCAttributeModifier, FAttributeClamp, your own math; no UObject graph beyond a rooted effect instance | arithmetic, modifier layering, clamp resolution, temporal history | anything that needs the component, a move or a network | |
| 2. Component through a stub | a UGMC_AbilitySystemComponent whose GMCMovementComponent is an empty UGMC_MovementUtilityCmp subclass, both NewObject without owner or world; the sub-steps of the prediction tick and the …ForTest seams drive it (1.4.1+: SetActionTimerForTest, TickActiveAbilitiesForTest, CleanupStaleAbilitiesForTest for a controlled clock) | activation gates, lifecycle and end paths (cancel versus end), cost and cooldown, effect application, event order and expiry, tags, task payload dispatch and completion, server-operation routing | prediction, confirmation, replay, combined moves, RPCs, heartbeats, smoothing, actor spawning, anything about two machines | |
| 3. Real move loop | PIE with a dedicated server and one or more clients in one process, network emulation on the clients | that owner and server agree after a round trip, that others see it, that nothing fires twice, that respawn and death transitions hold | fine-grained arithmetic (slow, noisy): push that down to layer 1 or 2 |
Which layer for which claim: "the value is X after N ticks" → 1 or 2; "the gate refuses when the tag is set" → 2; "the server accepts the client's spend without a correction", "the shot exists once on every machine", "the effect reaches the other client", "the ability survives 1 % loss" → 3. Every checklist line in the authoring skills that says verified under networked PIE is a layer-3 claim; a green layer-2 spec with a red PIE session puts the fault in the network path (gmas:gmas-debug). Standalone PIE proves nothing about prediction: its pawn is a locally controlled server pawn, never predicted, replayed or smoothed (gmas:gmc-prediction).
GMAS specs
The bundled specs are the model: on 1.4.1+ the test module Source/GMCAbilitySystemTests/ (UncookedOnly: built for the editor and uncooked targets, never into a cooked or Shipping game; 533 cases under GMAS.*, all passing), on 1.4.0 Source/GMCAbilitySystem/Private/Tests/ inside the runtime module (449 cases, about 150 failing). A spec is a BEGIN_DEFINE_SPEC block whose members are the harness, a Define() with BeforeEach / AfterEach / Describe / It, guarded by #if WITH_DEV_AUTOMATION_TESTS (Runtime/Core/Public/Misc/AutomationTest.h; GMAS 1.4.0 used WITH_AUTOMATION_WORKER). Put yours in a test module of the same kind that depends on GMCAbilitySystem, GMCCore, GameplayTags and GameplayTasks, as GMCAbilitySystemTests.Build.cs does: test-only UCLASSes then never ship.
The stub. An ownerless component reports NM_Standalone from GetNetMode() and false from HasAuthority(), which is exactly what makes the harness cheap and what bounds it: no net role, no moves, no world. UGMAS_TestMovementCmp is that empty subclass (Source/GMCAbilitySystemTests/Private/ on 1.4.1+, Private/Tests/ on 1.4.0); write your own in your module rather than including a plugin-private header (1.4.1 no longer exports the test folder). On a negative clock (-1.0) each effect-id generator wraps into its range and reports it once ([EffectID], an Error, 1.4.1+): call SilenceEffectIDWrapReportForTest() in a harness that is not about ids.
Test classes. The bundled stubs (UGMAS_TestAbility, UGMAS_TestAbilityB, UGMAS_TestCostEffect, same folder) are empty subclasses whose configuration is written to the class default object per test (an instance copies every property of its class default object, 1.4.1+). 1.4.1 adds GMAS_TestHelpers.h (GMASTest::MakeAttr / MakeClampedAttr for bare attributes with an explicit clamp, and the clock seeds StableActionTimer = -1.0 and ClientAuthActionTimer = 1.0), UGMAS_TestEventRecorder (binds the component's dynamic delegates and records effect ids, ability activated / ended / cancelled counts and custom events; it can remove an effect or cancel an ability from inside a listener) and UGMAS_TestCountingEffect (records Start / Tick / Period / End in order). Configuration per test: GetMutableDefault<UMyAbility_Dash>()->AbilityTag = …, GetMutableDefault<UMyEffect_Burn>()->EffectData.Modifiers = …, with every field restored in AfterEach. Testing your real classes the same way works as long as they read their configuration from class defaults and not from assets that exist only in a cooked map.
Driving the component. Pick the call by what you need to advance:
| Call | Advances | Caveat | |
|---|---|---|---|
TryActivateAbility(Class), TryActivateAbilitiesByInputTag(InputTag, …) after AddAbilityMapData(FAbilityMapData) | activation, gates, candidate order | QueueAbility returns silently here: the component is neither an autonomous proxy nor the authority | |
GenPredictionTick(Dt) | the operation slot, ability ticks, effect ticks, ProcessAttributes, purge of ended instances | overwrites `ActionTimer` from the stub's GetMoveTimestamp() (Source/GMCCore/Public/Components/GMCMovementUtilityComponent.h), which is -1.0 on a component that never executed a move. Use it to recalculate attributes after a modifier (as gmas:gmas-attribute does) or with 0.f to purge ended instances, never to pass time; a later time-driven step must write ActionTimer again | |
SetActionTimerForTest(T) (1.4.1+; write ActionTimer before), then TickActiveEffects(Dt) + ProcessAttributes(true) | effect duration, periods, expiry; attribute recalculation | the two sub-steps of the prediction tick with a clock you control (GMAS_DurationSpec.cpp). Set Data.bServerAuth = true when the clock jumps past ClientEffectApplicationTimeout (0.5 s) and the instance is still Pending, or it times out | |
TickActiveAbilitiesForTest(Dt), CleanupStaleAbilitiesForTest() (1.4.1+); the instance's public Tick(Dt) / AncillaryTick(Dt) | every active ability's Tick (TickEvent, TickTasks, pending cancels and ends), the purge of ended instances; AncillaryTickEvent, AncillaryTickTasks | keep the clock within ServerConfirmTimeout (2 s, 1.4+; 1 s before) of activation, or set bForceAuthorityForTest (1.4.1+): without authority UGMCAbility::Tick sees a client and cuts an unconfirmed instance with an [AbilityCut] Error (which also fails the test unless AddExpectedErrorPlain registered it; AddExpectedError is a regex and the bracketed tag a character class). Or raise the protected default in the test ability's constructor | |
GenAncillaryTick(Dt, false) | cooldown expiry, task-payload dispatch for bActivateOnMovementTick = false abilities, OnAttributeChanged / OnActiveTagsChanged | runs no gameplay replay logic (it does consume the replay-burst diagnostic's per-frame flag, 1.4+); safe to call freely | |
PreLocalMoveExecution() | moves the oldest queued task payload and operation into their bound slots | one payload per call: N payloads take N moves |
Seams (1.4+, `WITH_AUTOMATION_WORKER` only, bottom of `Public/Components/GMCAbilityComponent.h`). They exist because GMC's role and replay queries are not virtual and several dispatch paths are private. GMAS_BugFixSpec.cpp, GMAS_ClientAuthSpec.cpp, GMAS_TaskSpec.cpp and GMAS_AbilityEndSpec.cpp show each in use. They are inspection hatches, not a substitute for layer 3: a forced flag proves the branch runs, not that the network takes it.
This is the start of the file. Read the full SKILL.md on GitHub.
Security
- Security scanPassed, 95 of 100Pattern checks on the skill's files.
- Model reviewPassed
Quality evaluation
- Task evaluationNot runNo evaluation yet. Run one in Skill Studio.
Source
- SKILL.md in the repositoryCheckingClaude/gmas/skills/gmas-testing/SKILL.md
Popularity
- 7-day trend score
- 0
Not refreshed yet.
Works with
Any agent vskill installs to: 56 targets in all. These 39 have a page on this site.
- Claude Code
- Cursor
- GitHub Copilot
- Windsurf
- Codex
- Gemini CLI
- Cline
- Amp
- Roo Code
- Goose
- Continue
- Kilo Code
- Junie
- Trae
- OpenHands
- Qwen Code
- AI Agent
- Tabnine Chat
- Sourcegraph Cody
- Amazon Q
- Firebase Genkit
- Sweep
- Devin
- Phind
- Mentat
- Claude Desktop
- Aider
- GPT Pilot
- Plandex
- bolt.new
- v0
- Replit Agent
- Anse
- TypingMind
- BetterChatGPT
- LibreChat
- Warp AI
- Pieces
- Fig AI
Embed badge
[](https://verified-skill.com/skills/reznok/gmcabilitysystem/gmas-testing)