Skip to content

Fix transfer of manually built enhancements#7162

Open
lL1l1 wants to merge 12 commits into
developfrom
fix/enhancement-transfer
Open

Fix transfer of manually built enhancements#7162
lL1l1 wants to merge 12 commits into
developfrom
fix/enhancement-transfer

Conversation

@lL1l1

@lL1l1 lL1l1 commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Description of the proposed changes

Fixes #5233

The system was broken in 3 parts:

  1. The active enhancements table was always cleared due to checking t[1] instead of table.empty(t), causing enhancements to never be transferred.
  2. Preset enhancements happened 1 tick after OnCreate so they overrode active enhancements in enhancement sync
  3. Preset enhancements and transferred enhancements did not check for each other in any way so it was possible to have more than 1 enhancement in a slot
    1. is fixed by using table.empty
    1. and 3. are fixed by overriding the thread that creates preset enhancements with a similar one that creates the active enhancements instead of the preset ones

Testing done on the proposed changes

  1. Spawn paragon/buildpower and a preset:
   CreateUnitAtMouse('xab1401', 0,  -11.47,   -7.75, -0.00000)
   CreateUnitAtMouse('url0001', 0,    8.53,    5.25,  0.78058)
   for i = 1, 100 do
     CreateUnitAtMouse('xrb0304', 0,   -2.47,    1.25, -0.00000)
   end
   CreateUnitAtMouse('url0301_engineer', 0,    5.40,    1.24, -0.51868)
  1. upgrade the preset replacing one of its upgrades (EMP for the example)
  2. transfer it using the following command:
ConExecute([[SimLua 
ForkThread(function ()
    local focus = GetFocusArmy()
    local f = import('/lua/SimUtils.lua').TransferUnitsOwnership
    local units = DebugGetSelection()
    units = f(units, focus + 1, false, true)
    WaitTicks(10)
    f(units, focus, false, true)
end)
]])
  1. Verify that the UI shows the correct replacement upgrade that you built (ex: show EMP upgrade)
  2. Verify that only the replacement upgrade is applied (ex: a cybran engineer preset with EMP replacing engineering should not have 98 buildpower).

This test works the same for ACU, except ACU has no conflict with presets to check.

Checklist

Summary by CodeRabbit

  • Bug Fixes
    • Fixed unit transfers to preserve and correctly reapply blueprint enhancements after ownership changes.
    • Improved Intel recharge behavior: if a unit is destroyed mid-progress, updates stop immediately.
    • Fixed preset enhancement handling during unit build completion to ensure the deferred enhancement process is properly tracked and finishes reliably.
  • New Features
    • Added new optional AI brain callbacks to handle failed unit transfers and unit-cap limit conditions.

lL1l1 added 7 commits July 1, 2026 13:36
Was checking [1] but the table is keyed with slot name strings.
Also was creating the table and then checking afterwards instead of checking if its empty first.
Although it was never used, `return false` is from gpg so I kept it for backwards mod compatibility. True is now returned so there's a more legitimate way to identify the failure.
@lL1l1 lL1l1 requested review from Garanas and speed2CZ July 1, 2026 22:49
@lL1l1 lL1l1 added type: bug area: sim Area that is affected by the Simulation of the Game labels Jul 1, 2026
@coderabbitai

coderabbitai Bot commented Jul 1, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Warning

Review limit reached

@lL1l1, you've reached your PR review limit, so we couldn't start this review.

Next review available in: 51 minutes

Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available.
You're only billed for reviews past your plan's rate limits ($0.25/file).

How can I continue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews.

How do review limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please refer docs for additional details.

Review details
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 6b534855-f544-41ae-8173-b895e4c45dab

📥 Commits

Reviewing files that changed from the base of the PR and between 84c2a59 and 97c63b1.

📒 Files selected for processing (2)
  • lua/SimUtils.lua
  • lua/defaultcomponents.lua
📝 Walkthrough

Walkthrough

This PR defers preset enhancement creation during unit transfer, tracks the deferred thread on the unit, updates transfer-time enhancement harvesting, adds engine callback fields, guards intel recharge against destroyed units, and records the fix in the changelog.

Changes

Manual enhancement transfer fix

Layer / File(s) Summary
Preset enhancement thread tracking
lua/sim/Unit.lua
Adds OnStopBeingBuiltEnhancementsThread, stores the forked thread handle, always calls CreateEnhancement for presets, clears the thread on completion, and returns true from CreateEnhancement.
Ownership-transfer enhancement reapplication
lua/SimUtils.lua
Caches TableEmpty/KillThread, revises enhancement harvesting in TransferUnitsOwnership, defers enhancement recreation through a forked thread after transfer, and adds a Luau cast in GiveUnitsToPlayer.
Callbacks, destruction guard, and changelog
engine/Sim/CAiBrain.lua, lua/defaultcomponents.lua, changelog/snippets/fix.7162.md
Adds OnFailedUnitTransfer/OnUnitCapLimitReached, adds an IsDestroyed early-exit guard in the intel recharge thread, and documents the fix in the changelog.

Estimated code review effort: 3 (Moderate) | ~25 minutes

Sequence Diagram(s)

sequenceDiagram
  participant TransferUnitsOwnership
  participant NewUnit
  participant DeferredThread
  participant CreateEnhancement

  TransferUnitsOwnership->>TransferUnitsOwnership: inspect unit enhancements with TableEmpty
  TransferUnitsOwnership->>NewUnit: transfer ownership
  TransferUnitsOwnership->>NewUnit: kill existing enhancement thread
  TransferUnitsOwnership->>DeferredThread: fork deferred enhancement creation
  DeferredThread->>CreateEnhancement: create each enhancement
  CreateEnhancement-->>DeferredThread: returns true
  DeferredThread->>NewUnit: clear OnStopBeingBuiltEnhancementsThread
Loading

Possibly related PRs

  • FAForever/fa#6965 — Touches the unit transfer path in lua/SimUtils.lua, which overlaps with the enhancement reapplication flow changed here.

Suggested reviewers: Hdt80bro, BlackYps

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title is concise and accurately summarizes the main change: fixing transfer of manually built enhancements.
Description check ✅ Passed The description covers the required sections, includes testing, and documents the main fix plus checklist items.
Linked Issues check ✅ Passed The changes address #5233 by preserving gifted SACU upgrades and preventing preset enhancements from overwriting transferred ones.
Out of Scope Changes check ✅ Passed The modified files all support enhancement transfer behavior or its changelog, with no clear unrelated scope added.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/enhancement-transfer

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@lL1l1 lL1l1 marked this pull request as ready for review July 1, 2026 23:47

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@engine/Sim/CAiBrain.lua`:
- Around line 549-551: Update the callback annotation for
CAiBrain.OnUnitCapLimitReached so its receiver type matches a brain callback
instead of Unit; use the same self type pattern as OnFailedUnitTransfer in
CAiBrain.lua, and adjust the `@type` fun(self: ...) signature to the correct brain
object type.

In `@lua/SimUtils.lua`:
- Around line 329-334: The preset replay logic in SimUtils.lua only cancels the
preset thread when activeEnhancements exists, so units with no active
enhancements can still have presets re-applied. Update the preset handling path
around the activeEnhancements build and the thread cancellation check to cancel
the preset replay for preset units even when unitEnh is empty, using the preset
thread logic near the activeEnhancements/preset thread code path. Ensure the
condition depends on preset state, not on activeEnhancements being truthy.
- Around line 424-428: The delayed enhancement replay in
newUnit.OnStopBeingBuiltEnhancementsThread can run after the unit has been
destroyed, so add the same dead-unit guard used by
Unit.CreatePresetEnhancementsThread before iterating activeEnhancements and
calling newUnit:CreateEnhancement. Recheck newUnit after WaitTicks(1), and exit
early if the unit is no longer valid/alive to avoid touching bones or UI on a
dead unit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 373db206-d547-45e6-82bd-e2ef23a7567f

📥 Commits

Reviewing files that changed from the base of the PR and between 7b9f49c and a2eca49.

📒 Files selected for processing (5)
  • changelog/snippets/fix.7162.md
  • engine/Sim/CAiBrain.lua
  • lua/SimUtils.lua
  • lua/defaultcomponents.lua
  • lua/sim/Unit.lua

Comment thread engine/Sim/CAiBrain.lua
Comment thread lua/SimUtils.lua Outdated
Comment thread lua/SimUtils.lua Outdated
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: sim Area that is affected by the Simulation of the Game type: bug

Projects

None yet

Development

Successfully merging this pull request may close these issues.

SACUs Do Not Retain Upgrades When Gifted

1 participant