Skip to content

fix: entity removal for excluded entities (disconnect, respawn)#86

Merged
fank merged 7 commits intomainfrom
fix/entity-vanish-sparse-positions
Mar 1, 2026
Merged

fix: entity removal for excluded entities (disconnect, respawn)#86
fank merged 7 commits intomainfrom
fix/entity-vanish-sparse-positions

Conversation

@fank
Copy link
Member

@fank fank commented Mar 1, 2026

Summary

  • Report :SOLDIER:DELETE: on disconnect and respawn (corpse) instead of faking a dead state
  • Skip DELETE when _entity == _corpse (respawnOnStart reuses the same unit object) to prevent premature removal in streaming mode
  • Companion to OCAP2/extension#... (:SOLDIER:DELETE: / :VEHICLE:DELETE: commands)

Changes

  • fnc_eh_disconnected.sqf: Send :SOLDIER:DELETE: + exclude instead of injecting fake dead state
  • fnc_addEventMission.sqf (EntityRespawned): Send :SOLDIER:DELETE: for corpse, guarded by _entity != _corpse to handle respawnOnStart
  • fnc_init.sqf: Add settings snapshot log line, remove dead comment
  • XEH_preInit.sqf: Lower frameCaptureDelay minimum to 0.1

Test plan

  • hemtt build compiles
  • Disconnect → entity stops at disconnect frame (no frozen marker)
  • Respawn (different body) → corpse removed, new entity tracked
  • respawnOnStart (same body) → no spurious DELETE, entity continues under same ID
  • Reconnect → player takes over AI unit, tracked as new entity

fank added 7 commits March 1, 2026 00:09
The dedup optimization only sends state updates when data changes, but
excluded entities (disconnected players, respawn corpses) stop producing
states abruptly — the extension's gap-fill has no final state to extend.

- Disconnect: stop excluding the unit body so it continues being tracked
  as AI. The capture loop's reconnect logic handles re-inclusion.
- Respawn: send a final lifeState=0 state for the corpse before excluding
  it, so the extension knows the corpse's last frame for gap-filling.

Companion to OCAP2/extension#134.
Guard against potential script error if unitData is unexpectedly a
non-array type by checking isEqualType before using the + copy operator.
Restores exclude=true so disconnected player bodies stop being tracked,
but first sends a final lifeState=0 state so the extension knows the
entity's last frame. Combined with the extension's dead-entity handling,
the unit properly disappears from playback at the disconnect frame.
Send :SOLDIER:DELETE: on disconnect and respawn instead of injecting a
fake dead state. The extension now owns the gap-fill boundary logic.
respawnOnStart reuses the same unit object, so _entity == _corpse
in the EntityRespawned handler. Sending DELETE in this case caused
the entity to be prematurely removed in streaming mode while the
capture loop re-included it on the next frame.
@gemini-code-assist
Copy link

Summary of Changes

Hello, I'm Gemini Code Assist1! I'm currently reviewing this pull request and will post my feedback shortly. In the meantime, here's a summary to help you and other reviewers quickly get up to speed!

This pull request refines the entity tracking and removal mechanisms within the recording system, particularly for player disconnects and respawns. It ensures that entities are correctly marked for deletion by sending explicit commands, while also preventing unintended removals in specific respawn scenarios. Additionally, it includes minor configuration adjustments and enhances logging for better operational visibility.

Highlights

  • Entity Removal Logic: Implemented explicit :SOLDIER:DELETE: commands for entities upon player disconnect and when a corpse is left after respawn, ensuring proper removal from tracking.
  • Respawn Handling Refinement: Added a condition to skip the :SOLDIER:DELETE: command when _entity == _corpse during respawn, specifically addressing respawnOnStart scenarios to prevent premature entity removal.
  • Configuration Adjustment: Lowered the minimum allowed value for the frameCaptureDelay setting to 0.1.
  • Logging Improvements: Introduced new log entries for recording save operations and a snapshot of initial settings.
Changelog
  • addons/recorder/XEH_preInit.sqf
    • Updated the minimum value for the frameCaptureDelay setting from 0.30 to 0.10.
  • addons/recorder/fnc_addEventMission.sqf
    • Modified the EntityRespawned event handler to send a :SOLDIER:DELETE: command for the old corpse.
    • Added a conditional check (_entity != _corpse) to prevent sending :SOLDIER:DELETE: when respawnOnStart reuses the same unit object.
  • addons/recorder/fnc_eh_disconnected.sqf
    • Changed the disconnect event handler to send a :SOLDIER:DELETE: command for the disconnected unit instead of just setting its exclude variable.
  • addons/recorder/fnc_exportData.sqf
    • Added INFO_3 and INFO_2 log messages to indicate the start and end of the recording save process, including timing information.
  • addons/recorder/fnc_init.sqf
    • Removed a commented-out debug line.
    • Added an INFO_4 log message to output a snapshot of key settings during initialization.
Using Gemini Code Assist

The full guide for Gemini Code Assist can be found on our documentation page, here are some quick tips.

Invoking Gemini

You can request assistance from Gemini at any point by creating a comment using either /gemini <command> or @gemini-code-assist <command>. Below is a summary of the supported commands on the current page.

Feature Command Description
Code Review /gemini review Performs a code review for the current pull request in its current state.
Pull Request Summary /gemini summary Provides a summary of the current pull request in its current state.
Comment @gemini-code-assist Responds in comments when explicitly tagged, both in pull request comments and review comments.
Help /gemini help Displays a list of available commands.

Customization

To customize Gemini Code Assist for GitHub experience, repository maintainers can create a configuration file and/or provide a custom code review style guide (such as PEP-8 for Python) by creating and adding files to a .gemini/ folder in the base of the repository. Detailed instructions can be found here.

Limitations & Feedback

Gemini Code Assist may make mistakes. Please leave feedback on any instances where its feedback is incorrect or counter productive. You can react with 👍 and 👎 on @gemini-code-assist comments. If you're interested in giving your feedback about your experience with Gemini Code Assist for Github and other Google products, sign up here.

You can also get AI-powered code generation, chat, as well as code reviews directly in the IDE at no cost with the Gemini Code Assist IDE Extension.

Footnotes

  1. Review the Privacy Notices, Generative AI Prohibited Use Policy, Terms of Service, and learn how to configure Gemini Code Assist in GitHub here. Gemini can make mistakes, so double check it and use code with caution.

@fank fank merged commit 410780e into main Mar 1, 2026
1 check passed
@fank fank deleted the fix/entity-vanish-sparse-positions branch March 1, 2026 13:12
Copy link

@gemini-code-assist gemini-code-assist bot left a comment

Choose a reason for hiding this comment

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

Code Review

This pull request correctly implements entity deletion for disconnected players and respawned corpses by sending a :SOLDIER:DELETE: command, replacing the previous method of faking a dead state. The changes also properly handle the respawnOnStart scenario and add some useful logging for saving recordings and settings snapshots. My review includes suggestions to improve the robustness of the new entity deletion logic by adding checks for invalid IDs before sending data to the extension.

Comment on lines +78 to +82
[":SOLDIER:DELETE:", [
_corpse getVariable [QGVARMAIN(id), -1],
GVAR(captureFrameNo)
]] call EFUNC(extension,sendData);
_corpse setVariable [QGVARMAIN(exclude), true];

Choose a reason for hiding this comment

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

medium

The code retrieves the corpse's ID using _corpse getVariable [QGVARMAIN(id), -1], which defaults to -1 if the ID is not found. A :SOLDIER:DELETE: command is then sent with this ID. While the isInitialized check on line 76 should prevent this, other parts of the codebase, like fnc_eh_killed.sqf, explicitly check for an ID of -1 before processing. It would be more robust to add a similar check here to prevent sending delete commands for an invalid ID.

        private _corpseId = _corpse getVariable [QGVARMAIN(id), -1];
        if (_corpseId != -1) then {
          [":SOLDIER:DELETE:", [
            _corpseId,
            GVAR(captureFrameNo)
          ]] call EFUNC(extension,sendData);
        };
        _corpse setVariable [QGVARMAIN(exclude), true];

Comment on lines +40 to +44
[":SOLDIER:DELETE:", [
_unit getVariable [QGVARMAIN(id), -1],
GVAR(captureFrameNo)
]] call EFUNC(extension,sendData);
_unit setVariable [QGVARMAIN(exclude), true];

Choose a reason for hiding this comment

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

medium

Similar to the change in fnc_addEventMission.sqf, this code sends a :SOLDIER:DELETE: command using an ID that defaults to -1. For robustness and consistency with other parts of the code like fnc_eh_killed.sqf, it's better to check if the ID is valid (not -1) before sending the command.

  private _unitId = _unit getVariable [QGVARMAIN(id), -1];
  if (_unitId != -1) then {
    [":SOLDIER:DELETE:", [
      _unitId,
      GVAR(captureFrameNo)
    ]] call EFUNC(extension,sendData);
  };
  _unit setVariable [QGVARMAIN(exclude), true];

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant