Skip to content

Fix ActivityArrayMap hashCode() using raw registry ids instead of Activity hashes#800

Merged
Dreeam-qwq merged 1 commit into
Winds-Studio:ver/26.2from
toprakdevx:fix/activity-map-hashcode
Jul 4, 2026
Merged

Fix ActivityArrayMap hashCode() using raw registry ids instead of Activity hashes#800
Dreeam-qwq merged 1 commit into
Winds-Studio:ver/26.2from
toprakdevx:fix/activity-map-hashcode

Conversation

@toprakdevx

Copy link
Copy Markdown
Contributor

Problem

ActivityArrayMap stores each key as its raw activity registry id (int), and two hashCode() implementations hash that raw id instead of the Activity:

  • MapEntry#hashCode() returns Objects.hashCode(key) ^ Objects.hashCode(value) where key is the int id — even though the same class's getKey() and equals() use the actual Activity via RegistryTypeManager.ACTIVITY_DIRECT[key]. So an entry's equals() and hashCode() disagree.
  • ActivityArrayMap#hashCode() sums Objects.hashCode(k[i]) ^ ... over the raw ids for the same reason.

The Map/Map.Entry contract defines an entry hash as key.hashCode() ^ value.hashCode(), and the key here is an Activity whose hashCode() is name.hashCode(), not its id. Since equals() compares against arbitrary Activity-keyed maps, an ActivityArrayMap (or its entries) can be equal to an ordinary HashMap holding the same contents while returning a different hashCode(), breaking the Object equals/hashCode contract.

Fix

Hash the Activity (via RegistryTypeManager.ACTIVITY_DIRECT[...], exactly as getKey()/equals() already do) instead of the raw id, in both hashCode() methods.

Testing

./gradlew applyAllPatches and ./gradlew :leaf-server:compileJava both build cleanly on a JDK 25 toolchain. Docs-level behaviour of a single map is unchanged; its hash is now correct when compared against other Map implementations.

…ivity hashes

MapEntry#hashCode() and ActivityArrayMap#hashCode() hashed the raw activity
registry id, while the entry key is the Activity itself - getKey() and equals()
already use RegistryTypeManager.ACTIVITY_DIRECT[...]. Per the Map/Map.Entry
contract an entry's hash is key.hashCode() ^ value.hashCode(), and
Activity#hashCode() is name.hashCode(), not the id. As a result an
ActivityArrayMap (and its entries) could be equal to an ordinary map with the
same contents while returning a different hashCode, breaking the equals/hashCode
contract. Hash the Activity instead, matching getKey()/equals().
@Dreeam-qwq Dreeam-qwq requested a review from hayanesuru July 3, 2026 21:07
@noramibu

noramibu commented Jul 3, 2026

Copy link
Copy Markdown
Contributor

This fix looks correct for ActivityArrayMap, but AttributeInstanceArrayMap seems to have the same issue. Maybe a follow-up PR, or dealing with in this PR would be better?

@Dreeam-qwq

Copy link
Copy Markdown
Member

This fix looks correct for ActivityArrayMap, but AttributeInstanceArrayMap seems to have the same issue. Maybe a follow-up PR, or dealing with in this PR would be better?

Thanks to your review! We can do it in another PR or commit, it’s fine =w=

@Dreeam-qwq Dreeam-qwq merged commit ce6a191 into Winds-Studio:ver/26.2 Jul 4, 2026
1 check passed
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.

4 participants