Skip to content

Conversation

@qaisjp
Copy link
Member

@qaisjp qaisjp commented Jan 19, 2026

Summary (I recommend reading commit by commit)

  • Prefer member initializer over ctor-initializer (we should have one, not both)
  • Instead of calling ResetDamageData before every return false in ReadOptionalDamage, just have the caller do it when ReadOptionalDamage returns false
  • remove dead code

Motivation

We were talking about packet architecture in the dev Discord and noticed that there was some dead code, so I thought I'd fix it. While I was here, I noticed other minor improvements that could be made.

Test plan

CI

Comment on lines +187 to +190
// todo: do we really need to reset damage data when we're returning
// false? returning false deletes the packet, and other packets don't
// reset internal data based on validation failures.
ResetDamageData();
Copy link
Member Author

Choose a reason for hiding this comment

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

I think we could get rid of ResetDamageData but not sure if it was added for a specific reason.

I asked AI to double check whether I am right and it agrees:

Looking at the code, when Read() returns false, the packet is indeed dropped and won't be processed further.

1. Packet is deleted immediately after Read() returns false

In CPacketTranslator.cpp (lines 252-256):

// Attempt to read the content, if we fail, delete the packet again
if (!pTemp->Read(BitStream))
{
    delete pTemp;
    pTemp = NULL;
}

This confirms that when Read() returns false, the packet object is immediately destroyed and not used further.

2. Other packets DON'T reset state on validation failure

Checking similar packet implementations:

None of the other packets reset their member variables before returning false from validation.

Conclusion

The ResetDamageData() call at line 192 is not necessary because:

  1. The packet is deleted immediately after Read() returns false
  2. No other packet implementations reset state on validation failure
  3. The pattern across the codebase is to simply return false and let the packet translator handle cleanup

You could safely remove the ResetDamageData() call to be consistent with other packet implementations.

Comment on lines 202 to 213
const auto* pPlayer = static_cast<const CPlayer*>(m_pSourceElement);
if (!pPlayer)
return false;

const ElementID id = pPlayer->GetID();

if (id == INVALID_ELEMENT_ID)
return false;

// why?
if (id == 0)
return false;
Copy link
Member Author

@qaisjp qaisjp Jan 19, 2026

Choose a reason for hiding this comment

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

It shouldn't be possible for Write to be called when m_pSourceElement doesn't exist or is invalid - this would indicate server corruption further up the stack.

this check should probably be removed, or moved to an outer function instead of here

Copy link
Member Author

Choose a reason for hiding this comment

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

I asked the LLM when would this return INVALID_ELEMENT_ID or 0? and it seems to agree:

Based on my investigation, here's when pPlayer->GetID() would return these values:

INVALID_ELEMENT_ID (0xFFFFFFFF)

Returns when:

ID 0

Returns when:

  • ID 0 is actually assigned from the stack - Looking at the CStack implementation, IDs are added starting from ulOldSize + 1. With initial capacity expansion, the stack is populated with IDs from 1 to INITIAL_MAX_STACK_SIZE
  • However, ID 0 could theoretically be assigned if manually pushed back into the stack (e.g., via PushUniqueID(0)), though this would be unusual

The comment // why? next to the id == 0 check is questioning why this check exists. Based on the code:

  1. Element IDs should normally start from 1 (based on the stack initialization logic)
  2. ID 0 being reserved/invalid is likely a defensive check or legacy code
  3. The MAX_SERVER_ELEMENTS - 2 capacity suggests IDs 0 and RESERVED_ELEMENT_ID are intentionally excluded from the valid range

In practice, these conditions should be extremely rare in normal operation - they would only occur if:

  • The server has run out of element IDs (server created 131,070+ elements)
  • There's a bug causing ID 0 to be pushed back into the stack
  • Memory corruption or initialization failure

Comment on lines -161 to -163
CPlayer* pPlayer = static_cast<CPlayer*>(m_pSourceElement);
if (pPlayer)
{
Copy link
Member Author

Choose a reason for hiding this comment

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

See #4651 (comment) for more details on this code being deleted

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