beyond-all-reason / beyond-all-reason/RecoilEngine

Expose weapon EndBurst events to synced Lua

Open
#3,285 0 comments 0 reactions 0 assignees View on GitHub
Dominant language
C++
Stars
679
Forks
290
Avg merge
3d 2h
Merged PRs (30d)
40

Description

## Problem

Synced Lua sometimes needs to know when a weapon has completed a full burst.

The motivating case is BAR's ground-attack cycling in beyond-all-reason/Beyond-All-Reason#8773. Ground area attack is implemented in Lua by inserting a generated ground-attack command. After the weapon completes a burst, Lua needs to finish that generated target so the area command can choose another position. The same event can support explicit gameplay policies such as advancing an opted-in queued ground attack after a configured number of salvos.

The engine already knows the exact transition in `CWeapon::UpdateSalvo` and exposes it to COB/Lua unit scripts through `EndBurst`. However, synced LuaRules has no equivalent call-in. This was also identified in [review of the BAR implementation](https://github.com/beyond-all-reason/Beyond-All-Reason/pull/8773#discussion_r3853631694).

## Why projectile counting is only a workaround

The current game-side implementation watches `ProjectileCreated` and reconstructs completed bursts by counting projectiles. This can work for BAR's currently configured artillery because those weapons happen to create one projectile per shot, but a projectile is not the engine's burst-completion event.

Projectile counting requires Lua to duplicate weapon details such as burst size and associate projectile events with the correct unit and weapon. The approximation can diverge for weapons that create multiple projectiles per shot, create no projectile for a shot, use custom projectile-spawning behavior, or have a final shot cancelled. It also makes games watch and process every relevant projectile merely to infer state the weapon simulation already knows directly.

Consequently it is fragile as a general API and can silently become incorrect when weapon behavior or definitions change.

## Proposed API

Expose a synced, weaponDef-watch-gated call-in when the engine completes or terminates a burst, for example:

```lua
function gadget:UnitWeaponBurstEnd(
unitID,
unitDefID,
unitTeam,
weaponNum,
weaponDefID,
commandID,
commandTag
)
end
```

The notification should be queued at the exact point where the engine currently calls the unit-script `EndBurst`, but delivered after the simulation frame has completed. Calling arbitrary Lua inline from `CWeapon::UpdateSalvo` would allow Lua to mutate commands or units while the weapon and command AI are still on the stack.

For command-cycling consumers, `commandID` and `commandTag` should be snapshots from the instant the burst ended. Looking up the front command only during deferred delivery is racy because `WeaponFired` may already have advanced or changed the queue.

A watch API analogous to the existing weapon/projectile watch methods would avoid invoking Lua for unrelated weapons.

## References

- beyond-all-reason/Beyond-All-Reason#8773
- [Suggestion to expose the existing EndBurst event](https://github.com/beyond-all-reason/Beyond-All-Reason/pull/8773#discussion_r3853631694)

## AI usage

OpenAI Codex was used to help investigate the engine/Lua event lifecycle and draft this issue. The submitter requested the issue and is responsible for reviewing and editing it.

Contributor guide

Open the contributing guide

Research direction

Start at CWeapon::UpdateSalvo and trace the existing EndBurst path into COB/Lua unit scripts, then inspect the analogous weapon/projectile watch methods. The work is done when synced LuaRules receives a watch-gated UnitWeaponBurstEnd notification after the simulation frame, with commandID and commandTag captured when the burst ends.

Written by the indexing model from the issue text.

Assessment

Tech stack
cpp, lua
Domain
api, game-dev
Issue type
Feature
Difficulty
4/5
Estimated time
3-5 days
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
52/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.