Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -74,22 +74,27 @@ public static SkillHandler<?> handlerForBinding(String skillId) {
if (skillId == null || skillId.isBlank() || MMOCore.plugin == null) {
return null;
}
RegisteredSkill exact = MMOCore.plugin.skillManager.getSkill(skillId);
if (exact != null && exact.getHandler() != null) {
return exact.getHandler();
// Binding keys are stored lowercase and MythicLib ids are uppercase, so the exact lookup
// needs the upper-cased id.
for (String id : new String[] {skillId, skillId.toUpperCase(Locale.ROOT)}) {
RegisteredSkill exact = MMOCore.plugin.skillManager.getSkill(id);
if (exact != null && exact.getHandler() != null) {
return exact.getHandler();
}
}
// Handler ids before display names: a class copy (CLASS_RESTORATION, shown as "Restoration")
// shares the rune's name, and a name match bound the rune's modifiers to the class skill.
for (RegisteredSkill skill : MMOCore.plugin.skillManager.getAll()) {
if (skill == null) {
continue;
}
if (skill.getName() != null && skill.getName().equalsIgnoreCase(skillId)) {
return skill.getHandler();
}
SkillHandler<?> handler = skill.getHandler();
SkillHandler<?> handler = skill == null ? null : skill.getHandler();
if (handler != null && skillId.equalsIgnoreCase(handler.getLowerCaseId())) {
return handler;
}
}
for (RegisteredSkill skill : MMOCore.plugin.skillManager.getAll()) {
if (skill != null && skill.getName() != null && skill.getName().equalsIgnoreCase(skillId)) {
return skill.getHandler();
}
}
return null;
}
}
26 changes: 26 additions & 0 deletions src/test/java/net/tfminecraft/magic/SkillResolverEdgeTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -84,4 +84,30 @@ void bindingLookupSupportsNamesAndHandlersCaseInsensitively() throws Exception {
assertSame(second, SkillIdResolver.handlerForBinding("ABILITY"));
assertNull(SkillIdResolver.handlerForBinding("unknown"));
}

@Test
void bindingPrefersTheRuneHandlerOverAClassCopyWithTheSameName() throws Exception {
MMOCore.plugin = mock(MMOCore.class);
var manager = mock(SkillManager.class);
var field = MMOCore.class.getDeclaredField("skillManager");
field.setAccessible(true);
field.set(MMOCore.plugin, manager);
// CLASS_RESTORATION is shown as "Restoration" and comes first; the rune RESTORATION has the handler id.
var classCopy = mock(RegisteredSkill.class);
var classHandler = mock(SkillHandler.class);
when(classCopy.getName()).thenReturn("Restoration");
when(classCopy.getHandler()).thenReturn(classHandler);
when(classHandler.getLowerCaseId()).thenReturn("class_restoration");
var rune = mock(RegisteredSkill.class);
var runeHandler = mock(SkillHandler.class);
when(rune.getName()).thenReturn("Restoration");
when(rune.getHandler()).thenReturn(runeHandler);
when(runeHandler.getLowerCaseId()).thenReturn("restoration");
when(manager.getAll()).thenReturn(List.of(classCopy, rune));
assertSame(runeHandler, SkillIdResolver.handlerForBinding("restoration"));
// skills.yml keys are stored lowercase; the MythicLib id is upper case
when(manager.getSkill("RESTORATION")).thenReturn(rune);
when(manager.getAll()).thenReturn(List.of()); // only the upper-cased exact lookup can find it now
assertSame(runeHandler, SkillIdResolver.handlerForBinding("restoration"));
}
}
Loading