Blueprint API: wiring your weapons¶
What to call, from where, and what the plugin never asks of you.
The one thing to know¶
The plugin never looks for your weapons. Your weapon calls the plugin.
There is no damage pipeline to opt into, no interface your projectile has to implement, no component your character needs, and no dependency on the Gameplay Ability System. Wherever your game already decides "this shot hit that surface", you add one function call.
Two entry points. Pick one.¶
| Path A: direct | Path B: tag table | |
|---|---|---|
| Call | Apply Grid Damage on GridDataComponent |
Notify Hit By Tag on GridDestructionBridgeComponent |
| You supply | every number: depth, radius, face | where the hit landed and which way it was going |
| Numbers come from | your call site | a data asset, keyed by GameplayTag |
| Needs | nothing | one data asset |
| Needs GameplayTags | no | yes |
| Good for | one weapon, a prototype, a system that already has per-weapon numbers | a shipping game with a weapon table |
Both are BlueprintCallable, both are server-only, and both do the same thing
once the numbers are resolved: Path B is Path A with a lookup in front of it.
Start on A; move to B when you have more than a couple of weapons.
Path A: no Bridge, no tags, no GAS¶
Everything you need is on the GridDataComponent that every wall already has.
After your trace, in Blueprint or C++:
- From the hit actor, Get Component by Class →
GridDataComponent. None means it is not a destructible wall; that is your branch. -
Fill an
FGridDamageParams:field value HitLocationthe impact point, world space HitDirectionthe direction the round was travelling, normalised PeakDepthCmhow deep it bites into reference material; a rifle bullet is 3–5 RadiusCmthe crater's radius. 0 lets the wall's preset decide ( MinSpallRadiusCells, a crater of a cell or more). 2–5 cm leaves a small mark for a pistol round, on walls that subdivide. Above that, a blastImpactFaceleave at Auto: it is derived fromHitDirection -
Call Apply Grid Damage.
That is the whole integration, and it works from a Blueprint-only project.
Use the shot's travel direction, not the surface normal
The crater is shaped by the angle the round arrived at, so a glancing hit
leaves a furrow along its path. The impact normal is the surface's normal
and throws exactly that away. In a trace, the direction is
Normalize(TraceEnd − TraceStart).
Apply Grid Damage returns an FGridDamageResult: which cells opened, whether
the wall was penetrated, how much penetration depth is left for whatever is
behind it, Obliquity and bGrazing. Read it if you want the round to carry on
through, or to spark off a ricochet.
Path B: the tag table¶
Worth the setup as soon as "how deep does a 7.62 go into brick" stops being a number you want at a call site.
Every GridDestructibleWall adds a GridDestructionBridgeComponent to itself
at BeginPlay. To opt a wall out, clear that entry from its CompanionComponents
list. For an actor with a GridDataComponent that is not a
GridDestructibleWall, call Get Or Add Grid Bridge: it returns the one there,
or adds one.
Create the weapon table, in this order:
- One or more
GridImpactProfiledata assets, each holding the numbers:PeakDepthCm,RadiusCm,bIsPenetrating. - One
GridImpactProfileSet. Each row is a GameplayTag and a profile asset. SetDefaultProfileso an unmapped weapon does something visible instead of nothing. The picker lists only saved profiles, so it is empty until step 1 is done.
At the call site: Notify Hit By Tag, passing the set, the weapon's tag, the impact point and the direction.
Resolution is hierarchical. A hit tagged Damage.Type.Rifle.556 uses a row
for Damage.Type.Rifle.556 if there is one, otherwise Damage.Type.Rifle, then
Damage.Type. Ship one row for a whole family and override a single calibre when
it earns it.
It returns false when no row matched and there is no default, so "this weapon is not in the table" is distinguishable from "the wall ignored it".
GAS¶
There is nothing GAS-specific to do. Call Notify Hit By Tag from wherever your
damage lands: a Gameplay Ability, a GameplayEffectExecutionCalculation reading
the hit from the effect's context, or a target-data callback. The tag you pass is
usually one the Gameplay Effect already carries.
Walls have no Ability System Component and do not need one. If your damage pipeline only applies effects to actors with an ASC, it skips walls silently. Call the plugin where you have the hit result, before the ASC check.
Any weapon system¶
The plugin does not care what fired.
| weapon | call |
|---|---|
| Hitscan | once per hit; RadiusCm = 0 for the preset's crater, or a few cm for a small round |
| Projectile | from your impact handler, with the projectile's velocity as the direction |
| Explosion | one call at the blast centre with RadiusCm set. You do not find the cells yourself |
| Melee, thrown, vehicle impact | the same call |
| Lyra Starter Game | step by step in Example: Lyra Starter Game |
Authority¶
Every entry point is server-only and does nothing on a client. Cell state replicates from the server; clients render what they are told. That makes the calls safe in code that runs on both machines, such as a weapon ability or a shared damage function, without guarding them yourself.
Called only on a client, nothing happens and nothing is logged
"I call it and the wall does not break" is almost always this. Check Has Authority on the calling actor first.
For multiplayer, add GridNetClientComponent to your PlayerController or
pawn. It needs no code: it lets a client ask the server to resend a wall that went
out of sync, so it heals at once. See Multiplayer.
Other calls worth knowing¶
| call | on | what it does |
|---|---|---|
| Capture Damage Snapshot / Apply Damage Snapshot | GridDataComponent | save and restore a wall's damage (Setup) |
| Reset Damage | the wall | back to its Initial Damage, else intact (server) |
Example: Lyra Starter Game¶
The plugin was also tested in a copy of Epic's Lyra Starter Game, a common starting point for shooters. Lyra needs no adapter and no code: the wiring below is a few Blueprint nodes and two data assets in your project, and nothing in Lyra's source changes. It is also a worked example of Path B for any GAS-based weapon system.
1. Walls¶
Place GridDestructibleWalls and apply presets as usual. Lyra's weapons trace on
Lyra_TraceChannel_Weapon, and Lyra's DefaultEngine.ini makes the BlockAll
profile block it; the wall's collider uses BlockAll. If you give the collider
your own profile, make it block that channel.
2. Impact numbers¶
Lyra never calls TakeDamage, so a weapon hit is passed to the wall through the
tag table (Path B):
- A
GridImpactProfiledata asset, for exampleDA_Impact_Bullet:Peak Depth Cm3–5,Radius Cm0. - A
GridImpactProfileSet, for exampleDA_GridImpacts_Lyra:Default Profile=DA_Impact_Bullet. Add rows (Tag→Profile) per weapon later.
3. Hitscan weapons¶
Content Browser → Settings → Show Plugin Content, then open GA_Weapon_Fire
from ShooterCore (the parent of GA_Weapon_Fire_Pistol and the others; if the
children's parent is the C++ class LyraGameplayAbility_RangedWeapon, edit each
child instead). In its Event Graph, find
Event On Ranged Weapon Target Data Ready:
- Put a Sequence after the event: Then 0 → Lyra's existing damage logic (Ctrl-drag the existing wire, do not delete it); Then 1 → the nodes below.
- For Loop from 0 to
Get Data Count From Target Data(Target Data) − 1. - In the loop body:
Get Hit Result From Target Data(Target Data, Index) → Break Hit Result. Hit Actor→ Get Or Add Grid Bridge → Is Valid (not a wall: skip).- On the Bridge: Notify Hit By Tag with
Profile Set=DA_GridImpacts_Lyra,Impact Tagempty (the set's Default Profile) or the weapon's tag;Origin=Impact Point;Hit Direction=Normalize(Trace End − Trace Start);Hit Instigator=Get Avatar Actor From Actor Info.
- Compile and save. Children without their own
On Ranged Weapon Target Data Readyinherit this; a child that has one overrides it, so add the same nodes there or Add Call to Parent Function.
The event also runs on the client (shot prediction). That is fine: Notify Hit By Tag does nothing off the server and returns false there.
Worked when
A shot in a listen-server PIE session makes a hole in both windows, and Notify Hit By Tag returns true on the server. False on the server: the set has no profile for the tag and no Default Profile. No hole and the node never runs: the shot went through a child ability with its own event (step 6).
4. Grenades and projectiles¶
In the explosion's or projectile's impact Blueprint, on the server: the same
Get Or Add Grid Bridge → Notify Hit By Tag, at the blast centre, with a
profile whose Radius Cm is set. One call per blast; the wall finds the cells.
5. Fast resync¶
Put GridNetClientComponent on the controller: open
the ShooterCore GameFeatureData (or your Experience's) → Actions → Add
Components → Actor Class LyraPlayerController, Component Class
GridNetClientComponent, Client ✓ Server ✓. Lyra sets MaxClientRate to
200000, so the default MaxBytesPerSecond leaves room for everything else.
Cost at the call site¶
- Path A is a component lookup and a function call. No allocation.
- Path B adds a walk over your profile rows once per hit. Tag comparison is name comparison, not string comparison.
- Neither path allocates per shot. The damage work is proportional to the cells the hit touches, not to the size of the wall.