<freeStyleBuild _class='hudson.model.FreeStyleBuild'><action _class='hudson.model.CauseAction'><cause _class='hudson.triggers.SCMTrigger$SCMTriggerCause'><shortDescription>Started by an SCM change</shortDescription></cause></action><action></action><action _class='hudson.plugins.git.util.BuildData'><buildsByBranchName><refsremotesoriginmaster _class='hudson.plugins.git.util.Build'><buildNumber>328</buildNumber><marked><SHA1>9fe5731a229f180386880ad1fbc289808650b558</SHA1><branch><SHA1>9fe5731a229f180386880ad1fbc289808650b558</SHA1><name>refs/remotes/origin/master</name></branch></marked><revision><SHA1>9fe5731a229f180386880ad1fbc289808650b558</SHA1><branch><SHA1>9fe5731a229f180386880ad1fbc289808650b558</SHA1><name>refs/remotes/origin/master</name></branch></revision></refsremotesoriginmaster></buildsByBranchName><lastBuiltRevision><SHA1>9fe5731a229f180386880ad1fbc289808650b558</SHA1><branch><SHA1>9fe5731a229f180386880ad1fbc289808650b558</SHA1><name>refs/remotes/origin/master</name></branch></lastBuiltRevision><remoteUrl>https://github.com/mcMMO-Dev/mcMMO.git</remoteUrl><scmName></scmName></action><action></action><action></action><action></action><action _class='org.jenkinsci.plugins.displayurlapi.actions.RunDisplayAction'><artifactsUrl>https://popicraft.net/jenkins/job/mcMMO/328/artifact</artifactsUrl><changesUrl>https://popicraft.net/jenkins/job/mcMMO/changes</changesUrl><displayUrl>https://popicraft.net/jenkins/job/mcMMO/328/</displayUrl><testsUrl>https://popicraft.net/jenkins/job/mcMMO/328/testReport</testsUrl></action><artifact><displayPath>mcMMO.jar</displayPath><fileName>mcMMO.jar</fileName><relativePath>target/mcMMO.jar</relativePath></artifact><artifact><displayPath>original-mcMMO.jar</displayPath><fileName>original-mcMMO.jar</fileName><relativePath>target/original-mcMMO.jar</relativePath></artifact><building>false</building><displayName>#328</displayName><duration>53553</duration><estimatedDuration>135282</estimatedDuration><fullDisplayName>mcMMO #328</fullDisplayName><id>328</id><inProgress>false</inProgress><keepLog>false</keepLog><number>328</number><queueId>198</queueId><result>SUCCESS</result><timestamp>1783409649554</timestamp><url>https://popicraft.net/jenkins/job/mcMMO/328/</url><builtOn>Builder</builtOn><changeSet _class='hudson.plugins.git.GitChangeSetList'><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/skills/salvage/SalvageTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java</affectedPath><commitId>fc4fcddd3cd0d6961a5a80ca852b4827a184a1a1</commitId><timestamp>1783397859000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix Salvage yielding nothing for damaged items with low max quantity

Salvage.calculateSalvageableAmount floored the salvageable amount to
zero for any damaged item when the configured maximum quantity was 1,
so such items could only be salvaged at full durability. Damaged items
now salvage at least one material unless fully broken.

Fixes #4760
</comment><date>2026-07-06 21:17:39 -0700</date><id>fc4fcddd3cd0d6961a5a80ca852b4827a184a1a1</id><msg>Fix Salvage yielding nothing for damaged items with low max quantity</msg><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/skills/salvage/SalvageTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/skills/salvage/Salvage.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/resources/locale/locale_en_US.properties</affectedPath><affectedPath>src/main/resources/skillranks.yml</affectedPath><commitId>ea309678096dbee0c83c0aa3539dd65743544a95</commitId><timestamp>1783397859000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix wrong unlock levels in Leaf Blower and Catalysis guide text

Also removes the unused Leaf Blower Rank_2 and Rank_3 entries from
skillranks.yml; the subskill only defines a single rank.

Fixes #4847
</comment><date>2026-07-06 21:17:39 -0700</date><id>ea309678096dbee0c83c0aa3539dd65743544a95</id><msg>Fix wrong unlock levels in Leaf Blower and Catalysis guide text</msg><path><editType>edit</editType><file>src/main/resources/locale/locale_en_US.properties</file></path><path><editType>edit</editType><file>src/main/resources/skillranks.yml</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardManagerTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java</affectedPath><commitId>b14183fea45e2ad3c2fec0a770a1dc586c662855</commitId><timestamp>1783397878000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix skill scoreboards not updating for child skills

XP and level events only fire for parent skills, so a kept Salvage or
Smelting sidebar never matched the event skill and never refreshed
until the command was run again. Boards displaying a child skill now
refresh when one of its parent skills changes.

Fixes #5184
</comment><date>2026-07-06 21:17:58 -0700</date><id>b14183fea45e2ad3c2fec0a770a1dc586c662855</id><msg>Fix skill scoreboards not updating for child skills</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardManagerTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdaterTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdater.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/backend/BukkitScoreboardBackendTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/backend/BukkitScoreboardBackend.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java</affectedPath><commitId>df1570de49b72e7b700f717f608e4190f2867b86</commitId><timestamp>1783397878000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix power level tags dropping updates and leftover objectives

The power level heartbeat cleared all pending refreshes even when a
player's profile had not loaded yet, leaving their below-name tag at 0
until the next level-up. Pending names now stay queued until they can
be resolved. Also removes a persisted mcmmo_pwrlvl objective left in
world scoreboard data by older versions when the packet or noop
backend is active, which otherwise kept rendering stale tags.

Fixes #5003
</comment><date>2026-07-06 21:17:58 -0700</date><id>df1570de49b72e7b700f717f608e4190f2867b86</id><msg>Fix power level tags dropping updates and leftover objectives</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdaterTest.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/backend/BukkitScoreboardBackendTest.java</file></path><path><editType>add</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdater.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/backend/BukkitScoreboardBackend.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/listeners/PlayerListener.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/listeners/PlayerListenerCommandAliasTest.java</affectedPath><commitId>5a6692a026fa3e3b8e4dd1152ed95dda6ad1d5a1</commitId><timestamp>1783397901000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix localized skill commands being blocked by command whitelist plugins

The locale alias rewrite ran at LOWEST priority, tying with command
whitelist plugins listening on the same event, so which name they saw
depended on plugin load order. The rewrite now runs at LOW priority and
ignores cancelled events, letting whitelist plugins deterministically
see the command exactly as the player typed it.

Fixes #5250
</comment><date>2026-07-06 21:18:21 -0700</date><id>5a6692a026fa3e3b8e4dd1152ed95dda6ad1d5a1</id><msg>Fix localized skill commands being blocked by command whitelist plugins</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/listeners/PlayerListener.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/listeners/PlayerListenerCommandAliasTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/skills/salvage/SalvageManagerTest.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/listeners/PlayerListenerSalvageInteractTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/listeners/PlayerListener.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/skills/repair/RepairManagerTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java</affectedPath><commitId>a6079cf951b37081a91326c47442e9365211b0b6</commitId><timestamp>1783397902000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix salvage and repair confirmations acting on the wrong item

The confirmation window was time based only, so armor swapped into the
hand by a mis-click could be salvaged with no new prompt, including
worn armor via the vanilla quick-swap. Confirmations are now bound to
the prompted item and re-prompt when the held item changes. Also denies
item use while a confirmation is pending, closing the path where the
follow-up use-item interact event equipped the armor instead when the
server's re-raytrace missed the anvil.

Fixes #5268
Fixes #4896
</comment><date>2026-07-06 21:18:22 -0700</date><id>a6079cf951b37081a91326c47442e9365211b0b6</id><msg>Fix salvage and repair confirmations acting on the wrong item</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/listeners/PlayerListener.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/skills/repair/RepairManagerTest.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/skills/salvage/SalvageManagerTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/skills/salvage/SalvageManager.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/listeners/PlayerListenerSalvageInteractTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapperStatsPowerLevelTest.java</affectedPath><commitId>29a65b9fb7b201d0caa112dd3846e5e8ea545d6e</commitId><timestamp>1783397902000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix stats scoreboard power level counting permission-hidden skills

The stats sidebar summed every skill into its power level line while
hiding rows for skills the player lacked permission for, disagreeing
with chat stats and the power level cap, which both use the
permission-aware total.

Fixes #3790
</comment><date>2026-07-06 21:18:22 -0700</date><id>29a65b9fb7b201d0caa112dd3846e5e8ea545d6e</id><msg>Fix stats scoreboard power level counting permission-hidden skills</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapperStatsPowerLevelTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java</affectedPath><commitId>d0ad3ad67515426da787c1fdc4bde3114e859813</commitId><timestamp>1783397902000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix database purge never removing inactive users

The SQL purge compared a seconds-based last login delta against a
milliseconds cutoff, requiring roughly 83 years of inactivity per
configured month. The flatfile purge had an inverted check that only
removed users with an unknown last login while keeping genuinely
inactive ones.

Fixes #4251
</comment><date>2026-07-06 21:18:22 -0700</date><id>d0ad3ad67515426da787c1fdc4bde3114e859813</id><msg>Fix database purge never removing inactive users</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/database/SQLDatabaseManager.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/database/SQLDatabaseManagerTest.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/util/player/UserManagerTest.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/util/text/TextComponentFactoryTest.java</affectedPath><commitId>d171e20b7c0af2689aea34e3e164d532dd9f790c</commitId><timestamp>1783397902000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Add regression tests for previously fixed defects

Covers the UserManager shutdown null guard (#4131), legacy color codes
leaking into level-up notification components (#5125), the Green Thumb
probability guarantee at max bonus level (#4365), and dynamic subskill
chance caps for the levels reported against Dodge (#5210).
</comment><date>2026-07-06 21:18:22 -0700</date><id>d171e20b7c0af2689aea34e3e164d532dd9f790c</id><msg>Add regression tests for previously fixed defects</msg><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/util/random/ProbabilityUtilTest.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/util/player/UserManagerTest.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/util/text/TextComponentFactoryTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>Changelog.txt</affectedPath><commitId>9044066e4fd7a3da549ef52a9d28ca2b1dd5656d</commitId><timestamp>1783397999000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Update changelog
</comment><date>2026-07-06 21:19:59 -0700</date><id>9044066e4fd7a3da549ef52a9d28ca2b1dd5656d</id><msg>Update changelog</msg><path><editType>edit</editType><file>Changelog.txt</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/config/AdvancedConfig.java</affectedPath><affectedPath>src/main/resources/advanced.yml</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/skills/mining/MiningManagerTest.java</affectedPath><commitId>9e29417042a8d8bf9798134830342bcaaaf3ded8</commitId><timestamp>1783399261000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Add config option to limit Blast Mining remote detonation distance

Server admins can now set Skills.Mining.BlastMining.RemoteDetonationDistance
in advanced.yml to control how far away players can remotely detonate TNT.
Defaults to 100, matching the previous hardcoded limit, and is added to
existing advanced.yml files automatically on startup. Values below 1 fail
config validation.

Fixes #4330
</comment><date>2026-07-06 21:41:01 -0700</date><id>9e29417042a8d8bf9798134830342bcaaaf3ded8</id><msg>Add config option to limit Blast Mining remote detonation distance</msg><path><editType>edit</editType><file>src/main/resources/advanced.yml</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/config/AdvancedConfig.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/skills/mining/MiningManagerTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/skills/mining/MiningManager.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/resources/plugin.yml</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/MMOTestEnvironment.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/commands/player/InspectCommandTest.java</affectedPath><commitId>13e1dcb9d6eca7b97f4c64f4a436740473a19d11</commitId><timestamp>1783399414000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Make /inspect on offline players respect inspect permissions

Inspecting an offline player previously skipped the permission checks
that gate inspecting distant online players. /inspect now requires
mcmmo.commands.inspect.far (default: op) to view players who are
offline, and vanished players hidden from the sender are gated the same
way so they stay indistinguishable from offline players. Grant
mcmmo.commands.inspect.far to any ranks that should keep inspecting
offline players.

Fixes #4399
</comment><date>2026-07-06 21:43:34 -0700</date><id>13e1dcb9d6eca7b97f4c64f4a436740473a19d11</id><msg>Make /inspect on offline players respect inspect permissions</msg><path><editType>edit</editType><file>src/main/resources/plugin.yml</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/commands/player/InspectCommandTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/commands/player/InspectCommand.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/MMOTestEnvironment.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/util/player/NotificationManager.java</affectedPath><affectedPath>src/main/resources/advanced.yml</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/util/player/NotificationManagerTest.java</affectedPath><commitId>8dc2c7e4a87710cbbbc307d03d54062a3a17e27b</commitId><timestamp>1783399435000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix ActionBarNotifications.SubSkillUnlocked settings being ignored

Skill rank unlock messages were always sent to chat, ignoring the
Feedback.ActionBarNotifications.SubSkillUnlocked settings in
advanced.yml. Unlock notifications now use the same routing as other
notification types: setting
Feedback.ActionBarNotifications.SubSkillUnlocked.Enabled to true sends
them to the action bar, and
Feedback.ActionBarNotifications.SubSkillUnlocked.SendCopyOfMessageToChat
controls whether the chat still receives a copy. The shipped default for
Enabled is now false so unlock messages stay in chat out of the box.
These notifications also fire McMMOPlayerNotificationEvent, matching the
other notification types.

Fixes #4091
</comment><date>2026-07-06 21:43:55 -0700</date><id>8dc2c7e4a87710cbbbc307d03d54062a3a17e27b</id><msg>Fix ActionBarNotifications.SubSkillUnlocked settings being ignored</msg><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/util/player/NotificationManagerTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/player/NotificationManager.java</file></path><path><editType>edit</editType><file>src/main/resources/advanced.yml</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/party/PartyManager.java</affectedPath><affectedPath>src/main/resources/plugin.yml</affectedPath><affectedPath>src/main/resources/locale/locale_en_US.properties</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/datatypes/player/McMMOPlayerLevelUpSoundTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/commands/McLevelUpSoundCommand.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/datatypes/party/Party.java</affectedPath><commitId>c3018f1be5b8caa23c3d693685b3854433b05d1b</commitId><timestamp>1783399697000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Add /mclevelupsound to toggle the level-up sound per player

Players can now silence the mcMMO level-up sound for themselves with
/mclevelupsound (alias /levelupsound) without touching notifications
or the server-wide General.LevelUp_Sounds config setting. The toggle
also mutes the party level-up sound for that player.

Permission node: mcmmo.commands.mclevelupsound (granted by
mcmmo.commands.defaults). Like /mcnotify, the preference is
per-session and resets to on at login.

Fixes #5307
</comment><date>2026-07-06 21:48:17 -0700</date><id>c3018f1be5b8caa23c3d693685b3854433b05d1b</id><msg>Add /mclevelupsound to toggle the level-up sound per player</msg><path><editType>add</editType><file>src/main/java/com/gmail/nossr50/commands/McLevelUpSoundCommand.java</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/datatypes/player/McMMOPlayerLevelUpSoundTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/party/PartyManager.java</file></path><path><editType>edit</editType><file>src/main/resources/plugin.yml</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/datatypes/party/Party.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/datatypes/player/McMMOPlayer.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java</file></path><path><editType>edit</editType><file>src/main/resources/locale/locale_en_US.properties</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/resources/locale/locale_en_US.properties</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/commands/XprateCommand.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/commands/XprateCommandTest.java</affectedPath><commitId>31902ccd1e5be8bbe00cefb3e6b8654fcbb9601a</commitId><timestamp>1783399928000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Allow decimal values in /xprate

The XP rate argument now accepts positive decimal numbers such as 1.5
instead of integers only. Zero, negative, and non-finite rates are
rejected, and an invalid rate no longer toggles the XP event state.
Whole-number rates still display without a trailing .0 in broadcasts
and admin notifications.

Fixes #3390
</comment><date>2026-07-06 21:52:08 -0700</date><id>31902ccd1e5be8bbe00cefb3e6b8654fcbb9601a</id><msg>Allow decimal values in /xprate</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/commands/XprateCommand.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/commands/CommandUtils.java</file></path><path><editType>edit</editType><file>src/main/resources/locale/locale_en_US.properties</file></path><path><editType>add</editType><file>src/test/java/com/gmail/nossr50/commands/XprateCommandTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java</affectedPath><affectedPath>src/main/resources/locale/locale_en_US.properties</affectedPath><affectedPath>src/main/resources/plugin.yml</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/commands/XprateCommand.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/Permissions.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/commands/XprateCommandTest.java</affectedPath><commitId>35adf1110a8f818f6ab8626128decb20864d6c80</commitId><timestamp>1783399928000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Show the current XP rate with /xprate

Running /xprate with no arguments now tells the sender the current
global XP rate. Access is controlled by the new permission node
mcmmo.commands.xprate.show, granted to players by default through
mcmmo.commands.defaults since the rate is already broadcast publicly
when events start and shown on login.

Fixes #4602
</comment><date>2026-07-06 21:52:08 -0700</date><id>35adf1110a8f818f6ab8626128decb20864d6c80</id><msg>Show the current XP rate with /xprate</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/commands/CommandRegistrationManager.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/commands/XprateCommand.java</file></path><path><editType>edit</editType><file>src/main/resources/locale/locale_en_US.properties</file></path><path><editType>edit</editType><file>src/main/resources/plugin.yml</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/Permissions.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/commands/XprateCommandTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>Changelog.txt</affectedPath><commitId>93b005500fe88d648cb9a1b0fe6a1c2fb12e59fd</commitId><timestamp>1783400030000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Update changelog
</comment><date>2026-07-06 21:53:50 -0700</date><id>93b005500fe88d648cb9a1b0fe6a1c2fb12e59fd</id><msg>Update changelog</msg><path><editType>edit</editType><file>Changelog.txt</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/commands/XprateCommand.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/commands/XprateCommandTest.java</affectedPath><commitId>bc023b15ef65ba7651943d2d0f0f2a1a98d2f098</commitId><timestamp>1783404622000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix /xprate rate display using a shared DecimalFormat across threads

The formatted XP rate came from a single static DecimalFormat, which is
not thread safe. Regionized servers like Folia execute player commands
on multiple region threads, and every player can run /xprate to view
the rate, so simultaneous use could garble the broadcast or displayed
rate. The format is now created per call, matching how locale strings
already build a fresh MessageFormat per message.
</comment><date>2026-07-06 23:10:22 -0700</date><id>bc023b15ef65ba7651943d2d0f0f2a1a98d2f098</id><msg>Fix /xprate rate display using a shared DecimalFormat across threads</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/commands/XprateCommand.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/commands/XprateCommandTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/resources/plugin.yml</affectedPath><affectedPath>src/main/resources/locale/locale_en_US.properties</affectedPath><commitId>3c6ab95d01e9a0e9a1059b6a5d11c37770b953fc</commitId><timestamp>1783404741000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Mention viewing the current rate in the /xprate command descriptions

The /xprate description in plugin.yml and the
Commands.Description.xprate locale entry only mentioned modifying the
rate, but the command now also shows the current XP rate when run with
no arguments.
</comment><date>2026-07-06 23:12:21 -0700</date><id>3c6ab95d01e9a0e9a1059b6a5d11c37770b953fc</id><msg>Mention viewing the current rate in the /xprate command descriptions</msg><path><editType>edit</editType><file>src/main/resources/plugin.yml</file></path><path><editType>edit</editType><file>src/main/resources/locale/locale_en_US.properties</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>Changelog.txt</affectedPath><commitId>9aa347b58d56652798be2f5c28cc429f3ff4442c</commitId><timestamp>1783404741000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Correct 2.2.055 changelog entries

The Salvage note used wooden tools as an example of items that salvage
into a single material, but most wooden tools return more than one
material in the default salvage.vanilla.yml; wooden shovels are the
accurate example. Also moves the skillranks.yml removal line ahead of
the locale entries to match the usual entry ordering, and documents the
updated /xprate locale entries, the rank unlock notifications now
firing McMMOPlayerNotificationEvent, and the new regression tests.
</comment><date>2026-07-06 23:12:21 -0700</date><id>9aa347b58d56652798be2f5c28cc429f3ff4442c</id><msg>Correct 2.2.055 changelog entries</msg><path><editType>edit</editType><file>Changelog.txt</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdater.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdaterTest.java</affectedPath><commitId>295647a85e5f9252d93c04ef2833074bd9cf08a3</commitId><timestamp>1783404871000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix power level tag re-marks being lost during a heartbeat write

The heartbeat removed a pending name after resolving and writing it, so
a level-up that re-marked the same player mid-write was erased along
with the processed entry, leaving the below-name tag stale until the
player's next level-up. Names are now removed before resolving so a
concurrent re-mark always survives to the next pass.
</comment><date>2026-07-06 23:14:31 -0700</date><id>295647a85e5f9252d93c04ef2833074bd9cf08a3</id><msg>Fix power level tag re-marks being lost during a heartbeat write</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdater.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/PowerLevelTagUpdaterTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardManagerTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java</affectedPath><commitId>1f28520b892cdc7273d8887ae46299094d415209</commitId><timestamp>1783404871000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix inspect stats boards never refreshing on the watched player's level up

The otherboard scan in handleLevelUp found stats boards inspecting the
leveling player but then checked and refreshed the leveling player's
own board instead of the matching one, so an inspect board kept showing
stale levels until re-run while the watched player's board could be
redrawn spuriously. The scan now refreshes the board it matched.
</comment><date>2026-07-06 23:14:31 -0700</date><id>1f28520b892cdc7273d8887ae46299094d415209</id><msg>Fix inspect stats boards never refreshing on the watched player's level up</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardManager.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardManagerTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapperStatsPowerLevelTest.java</affectedPath><affectedPath>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java</affectedPath><commitId>c41387bb8fdd55c4804962e2d120b05df32978e8</commitId><timestamp>1783404871000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix stats scoreboard power level line vanishing for full-permission players

The stats sidebar appended the power level line after sorting the skill
rows, so once 15 or more skill rows were shown (a player permitted all
17 skills) the line cap truncated it away entirely. The line now takes
part in the sort; the sum is never smaller than any single row, so it
ranks first and always survives truncation, matching the old
score-sorted Bukkit board where the highest score displayed on top.
</comment><date>2026-07-06 23:14:31 -0700</date><id>c41387bb8fdd55c4804962e2d120b05df32978e8</id><msg>Fix stats scoreboard power level line vanishing for full-permission players</msg><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapperStatsPowerLevelTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/util/scoreboards/ScoreboardWrapper.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/listeners/PlayerListener.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/listeners/PlayerListenerSalvageInteractTest.java</affectedPath><commitId>95babed7bb3140658a4bddf813cb7ad567ef3c88</commitId><timestamp>1783405137000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix anvil confirmation item-use denial never applying to right-click air

The deny guard ran inside onPlayerInteractLowest, which is registered
with ignoreCancelled. A PlayerInteractEvent with no clicked block
reports itself as cancelled from the moment it is constructed, so the
follow-up use-item interaction that equips armor mid-confirmation never
reached the guard. Clicking the anvil could also override the denial,
because the use-item allowance for anvil blocks is applied after it.

The guard now runs in its own handler at LOW priority without ignoring
cancelled events, so it sees right-click-air interactions and takes
precedence over the anvil use-item allowance. The listener tests now
dispatch through the interact handlers honoring their real EventHandler
settings, which is what exposed the dead path.
</comment><date>2026-07-06 23:18:57 -0700</date><id>95babed7bb3140658a4bddf813cb7ad567ef3c88</id><msg>Fix anvil confirmation item-use denial never applying to right-click air</msg><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/listeners/PlayerListenerSalvageInteractTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/listeners/PlayerListener.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/skills/repair/RepairManagerTest.java</affectedPath><commitId>53b16a5a0e67c5cfe274df04d28a565407e4891f</commitId><timestamp>1783405137000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix repair confirmations re-prompting after every partial repair

Repair confirmations are bound to the prompted item, but a repair
changes the item's damage, so the pending confirmation stopped matching
as soon as the repair completed. Partial repairs are the norm, so
continuing to repair the same item re-prompted after every repair
instead of only when the held item actually changed.

A matching confirmation is now rebound to the item's repaired state, so
repairing the same item within the confirmation window keeps going
without new prompts. This also keeps the use-item denial covering the
just-repaired item, which unlike salvage stays in the player's hand.
</comment><date>2026-07-06 23:18:57 -0700</date><id>53b16a5a0e67c5cfe274df04d28a565407e4891f</id><msg>Fix repair confirmations re-prompting after every partial repair</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/skills/repair/RepairManager.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/skills/repair/RepairManagerTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java</affectedPath><commitId>3885c1c07f2177a58c1c35cd2d4924ced4a93867</commitId><timestamp>1783405243000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix database purge deleting flatfile users with unreadable last login

An unparseable last-login value was treated as a real timestamp of 0,
so the user looked ancient and was removed even though their last login
could not be determined. Unreadable values are now treated like an
unknown last login: the purge tries to recover a real timestamp from
the server's offline player data and keeps the user otherwise.
</comment><date>2026-07-06 23:20:43 -0700</date><id>3885c1c07f2177a58c1c35cd2d4924ced4a93867</id><msg>Fix database purge deleting flatfile users with unreadable last login</msg><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java</file></path><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java</affectedPath><affectedPath>src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java</affectedPath><commitId>8e2a45dced709f7f110076528ec0e92f488ce04a</commitId><timestamp>1783405243000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Fix powerless user purge deleting comments from the flatfile database

Purging powerless users treated every line in mcmmo.users as a user,
so the generated comment header had no skill data, counted as a
powerless user, and was removed while inflating the purged total.
Comments and empty lines are now preserved like the other file
rewrites.
</comment><date>2026-07-06 23:20:43 -0700</date><id>8e2a45dced709f7f110076528ec0e92f488ce04a</id><msg>Fix powerless user purge deleting comments from the flatfile database</msg><path><editType>edit</editType><file>src/test/java/com/gmail/nossr50/database/FlatFileDatabaseManagerTest.java</file></path><path><editType>edit</editType><file>src/main/java/com/gmail/nossr50/database/FlatFileDatabaseManager.java</file></path></item><item _class='hudson.plugins.git.GitChangeSet'><affectedPath>Changelog.txt</affectedPath><commitId>9fe5731a229f180386880ad1fbc289808650b558</commitId><timestamp>1783405342000</timestamp><author><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName></author><authorEmail>nossr50@gmail.com</authorEmail><comment>Update changelog
</comment><date>2026-07-06 23:22:22 -0700</date><id>9fe5731a229f180386880ad1fbc289808650b558</id><msg>Update changelog</msg><path><editType>edit</editType><file>Changelog.txt</file></path></item><kind>git</kind></changeSet><culprit><absoluteUrl>https://popicraft.net/jenkins/user/nossr50</absoluteUrl><fullName>nossr50</fullName><id>nossr50</id></culprit></freeStyleBuild>