Skip to content

Fix duplicate key errors when a character enters the world - #926

Open
sven-n wants to merge 1 commit into
masterfrom
claude/fix-and-create-pr-6uddgn
Open

Fix duplicate key errors when a character enters the world#926
sven-n wants to merge 1 commit into
masterfrom
claude/fix-and-create-pr-6uddgn

Conversation

@sven-n

@sven-n sven-n commented Sep 1, 2026

Copy link
Copy Markdown
Member

Two System.ArgumentException: An item with the same key has already been added errors could keep a character - and offline/bot players - from entering the game:

Error while processing the message: C1 0E F3 03 45 72 69 63 44 72 61 76 65 6E
System.ArgumentException: An item with the same key has already been added. Key: Nearby party member count
   at MUnique.OpenMU.GameLogic.Attributes.ItemAwareAttributeSystem..ctor(...)
   at MUnique.OpenMU.GameLogic.Player.OnPlayerEnteredWorldAsync()

Failed to initialize offline player for "bot0040".
System.ArgumentException: An item with the same key has already been added. Key: 238
   at MUnique.OpenMU.GameLogic.SkillList..ctor(Player player)
   at MUnique.OpenMU.GameLogic.Player.OnPlayerEnteredWorldAsync()

Cause

The AttributeSystem holds exactly one attribute per AttributeDefinition and the SkillList one entry per skill number, so a character which holds the same stat attribute (or the same learned skill) twice can't enter the game at all.

The duplicated stat attributes come from the Regenerations Refactor update: it adds the Is resting and Nearby party member count stat attributes to every character class without checking whether the class already has them. Since the character classes of a freshly initialized configuration contain both attributes, a configuration which was initialized after they were introduced and then received the update ends up with each of them twice - and every character of such a class gets the attribute twice as well. The same applies to the attribute definitions the update adds to the game configuration.

Changes

Don't create the duplicates

  • RegenerationsRefactorPlugInBase / RegenerationsRefactorPlugInSeason6 only add attribute definitions and stat attributes which don't exist yet.
  • CreateCharacterAction and BotGenerator take the class' stat attributes distinctly.
  • AddInitialSkillPlugInBase doesn't add a skill the character already knows (it is also called for characters which were created outside the game).

Repair the existing data

  • New RemoveDuplicateStatAttributes update (075 / 095d / Season 6) removes the duplicated stat attributes from the character classes.
  • Player.AddMissingStatAttributes removes stat attributes which the character holds more than once, keeping the one with the highest value, so nothing that was invested into a stat is lost.
  • The SkillList constructor removes duplicated learned skills, keeping the entry with the highest level.
  • Both repairs are logged as a warning.

Never fail on such data again

  • The attribute system of a character is built from the distinct stat attributes of the character and its account.

Item skill removal fix
While looking at the skill list, RemoveItemSkillAsync looked its entry up in the available skills, which holds the learned entry when the same skill is also learned. As a result a skill granted by two equipped items stayed in the list forever after both items were taken off, and the item skill list leaked entries. The entry is now looked up in the item skills, and the skill is only removed from the list when the last item granting it is gone and it isn't learned.

Tests

  • SkillListTest.DuplicateLearnedSkillIsRemovedAsync
  • SkillListTest.LearnedSkillKeptWhenItemSkillRemovedAsync
  • SkillListTest.ItemSkillRemovedWithLastItemAsync
  • DuplicateStatAttributeTests.AttributeSystemIsCreatedForDuplicatedStatAttributeAsync
  • DuplicateStatAttributeTests.DuplicatedStatAttributesAreRemovedWhenEnteringWorldAsync

MUnique.OpenMU.Tests (814 tests) and MUnique.OpenMU.Persistence.Initialization.Tests pass.

🤖 Generated with Claude Code

https://claude.ai/code/session_01LYr3urpQESKCEPXEpBV6rh


Generated by Claude Code

Two "An item with the same key has already been added" errors could keep a
character (and offline/bot players) from entering the game:

* "Key: Nearby party member count" in the ItemAwareAttributeSystem, when the
  character holds the same stat attribute twice.
* "Key: 238" in the SkillList, when the character has the same skill twice in
  its learned skills.

Root cause of the duplicated stat attributes is the "Regenerations Refactor"
update, which added the "Is resting" and "Nearby party member count" stat
attributes to every character class without checking whether the class already
had them. A configuration which was initialized after these attributes were
introduced got them twice, and so did every character of such a class.

Changes:

* The update plugins only add attribute definitions and stat attributes which
  don't exist yet.
* A new "Remove duplicate stat attributes" update removes the duplicates which
  the previous update created in the character classes.
* Characters are repaired when they enter the world: duplicated stat attributes
  are removed (the one with the highest value is kept), and duplicated learned
  skills are removed (the one with the highest level is kept). Both are logged.
* Attributes and skills are no longer duplicated when they are created:
  character creation and the bot generator take the class' stat attributes
  distinctly, and the initial skill plugin doesn't add a skill the character
  already knows.
* The attribute system of a character is built from distinct stat attributes,
  so it can never fail because of such data again.
* Fixed the removal of item skills: the entry is now looked up in the item
  skills instead of the available skills, so a skill which is also learned
  isn't taken away when the item is unequipped, and a skill granted by multiple
  equipped items is properly removed with the last of them.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01LYr3urpQESKCEPXEpBV6rh
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