Fix duplicate key errors when a character enters the world - #926
Open
sven-n wants to merge 1 commit into
Open
Conversation
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Two
System.ArgumentException: An item with the same key has already been addederrors could keep a character - and offline/bot players - from entering the game:Cause
The
AttributeSystemholds exactly one attribute perAttributeDefinitionand theSkillListone 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 restingandNearby party member countstat 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/RegenerationsRefactorPlugInSeason6only add attribute definitions and stat attributes which don't exist yet.CreateCharacterActionandBotGeneratortake the class' stat attributes distinctly.AddInitialSkillPlugInBasedoesn't add a skill the character already knows (it is also called for characters which were created outside the game).Repair the existing data
RemoveDuplicateStatAttributesupdate (075 / 095d / Season 6) removes the duplicated stat attributes from the character classes.Player.AddMissingStatAttributesremoves 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.SkillListconstructor removes duplicated learned skills, keeping the entry with the highest level.Never fail on such data again
Item skill removal fix
While looking at the skill list,
RemoveItemSkillAsynclooked 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.DuplicateLearnedSkillIsRemovedAsyncSkillListTest.LearnedSkillKeptWhenItemSkillRemovedAsyncSkillListTest.ItemSkillRemovedWithLastItemAsyncDuplicateStatAttributeTests.AttributeSystemIsCreatedForDuplicatedStatAttributeAsyncDuplicateStatAttributeTests.DuplicatedStatAttributesAreRemovedWhenEnteringWorldAsyncMUnique.OpenMU.Tests(814 tests) andMUnique.OpenMU.Persistence.Initialization.Testspass.🤖 Generated with Claude Code
https://claude.ai/code/session_01LYr3urpQESKCEPXEpBV6rh
Generated by Claude Code