Skip to content

Notify former owner when a unit is captured in combat (fixes BR#3370) - #167

Open
larrydgray wants to merge 1 commit into
FreeCol:sf-auto-mergefrom
larrydgray:fix-ghost-soldier-capture
Open

Notify former owner when a unit is captured in combat (fixes BR#3370)#167
larrydgray wants to merge 1 commit into
FreeCol:sf-auto-mergefrom
larrydgray:fix-ghost-soldier-capture

Conversation

@larrydgray

Copy link
Copy Markdown

Summary

When a unit loses a combat and the result is that it gets captured (rather than killed, losing equipment, or demoted), the losing player's client was never told that the unit changed hands.

ServerPlayer.csChangeOwner() transfers ownership correctly on the server, but the only ChangeSet update it sends is to the new owner:

cs.add(See.only(newOwner),
       ((ServerPlayer)newOwner).exploreForUnit(unit));

The former owner's client keeps its stale copy of the unit -- still theirs, still active, still with full moves -- so it keeps resurfacing as "needing orders" at every End Turn even though the server has already reassigned it. Trying to give it any order fails with "The server can not do that.", since the server no longer recognizes the client as the unit's owner.

Fix

In csCaptureUnit(), after the ownership transfer succeeds, explicitly notify the former owner to drop the unit via cs.addRemove(...), mirroring the See.only()/See.perhaps() visibility split csSlaughterUnit() already uses for the settlement/open-field cases.

Scoped to csCaptureUnit() rather than the shared csChangeOwner() utility, since csChangeOwner() has several other callers (colony capture, native conversion, REF defection) I have not individually verified are safe to change the same way -- they may share the same missing-notification pattern and could be worth a follow-up.

Verification

  • Diagnosed from a live game log: found the exact combat event (Combat attacker=... Attack LOSE CAPTURE_UNIT) and the subsequent client-side desync (client held the unit as [unit:8805 english veteranSoldier], server responded to a move attempt with Unit not owned by player:19: [unit:8805 russian freeColonist]).
  • Confirmed against a fresh in-game capture with the patch applied: the captured unit cleanly disappeared from the former owner's unit list, no stuck/ghost unit, no repeated "still waiting for orders" prompt.
  • Compiles cleanly against current sf-auto-merge (ant compile, no errors).

Fixes https://sourceforge.net/p/freecol/bugs/3370/

csChangeOwner() only sent the ChangeSet update to the new owner,
never to the player who lost the unit. Their client kept a stale
copy (still theirs, still active, still with full moves), which
resurfaced it as needing orders every End Turn even though the
server had already reassigned it -- a stuck "ghost unit" that
rejected all move orders since the server no longer recognized the
client as its owner.

Explicitly notify the former owner via csRemove(), mirroring the
See.only()/See.perhaps() visibility split csSlaughterUnit() already
uses for the settlement/open-field cases.

Fixes https://sourceforge.net/p/freecol/bugs/3370/
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