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 @@ -37,6 +37,14 @@ public static boolean isActiveCast(Skill cast) {
return lower != null && Cache.castTriggers.contains(lower.toUpperCase(Locale.ROOT));
}

/**
* True for a skill cast from an MMOCore class skill bar. Class skills are not runes:
* Magic leaves them alone (no refusal, whiff, weapon wear or cast drift).
*/
public static boolean isClassCast(Skill cast) {
return cast instanceof CastableSkill;
}

/**
* Spells come from MMOItems key combinations, whose {@code AbilityData} is a plain
* MythicLib {@link Skill} and never an MMOCore {@link CastableSkill}. The handler id
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ public void onSkillCast(SkillCastEvent event) {
return;
}
Skill cast = event.getCast();
if (!SkillIdResolver.isActiveCast(cast)) {
if (!SkillIdResolver.isActiveCast(cast) || SkillIdResolver.isClassCast(cast)) {
return;
}
Player player = event.getPlayer();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ public void onPlayerCastSkill(PlayerCastSkillEvent event) {
return;
}
Skill cast = event.getCast();
if (!SkillIdResolver.isActiveCast(cast)) {
if (!SkillIdResolver.isActiveCast(cast) || SkillIdResolver.isClassCast(cast)) {
return;
}
String skillId = SkillIdResolver.resolveSkillId(cast);
Expand Down
83 changes: 83 additions & 0 deletions src/test/java/net/tfminecraft/magic/ClassCastSkipTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
package net.tfminecraft.magic;

import static org.junit.jupiter.api.Assertions.*;
import static org.mockito.Mockito.*;

import io.lumine.mythic.lib.api.event.skill.PlayerCastSkillEvent;
import io.lumine.mythic.lib.api.event.skill.SkillCastEvent;
import io.lumine.mythic.lib.skill.Skill;
import io.lumine.mythic.lib.skill.trigger.TriggerType;
import net.Indyuce.mmocore.skill.CastableSkill;
import net.tfminecraft.magic.gear.GearHand;
import net.tfminecraft.magic.integration.SkillIdResolver;
import net.tfminecraft.magic.listener.CastDriftListener;
import net.tfminecraft.magic.listener.ResonanceCastListener;
import net.tfminecraft.magic.registry.SkillElementRegistry;
import net.tfminecraft.magic.session.ResonanceSessionManager;
import org.junit.jupiter.api.*;
import org.mockbukkit.mockbukkit.*;

/** MMOCore class skills are cast from the skill bar, not from runes: Magic must not touch them. */
class ClassCastSkipTest {
ServerMock server;

@BeforeEach
void setup() {
server = MockBukkit.mock();
Magic.plugin = mock(Magic.class, RETURNS_DEEP_STUBS);
SkillElementRegistry.clear();
}

@AfterEach
void cleanup() {
Magic.plugin = null;
SkillElementRegistry.clear();
MockBukkit.unmock();
}

@Test
void onlyMmocoreCastableSkillsCountAsClassCasts() {
assertTrue(SkillIdResolver.isClassCast(mock(CastableSkill.class)));
assertFalse(SkillIdResolver.isClassCast(mock(Skill.class)));
assertFalse(SkillIdResolver.isClassCast(null));
}

@Test
void resonanceGateIgnoresClassCastsEvenForBoundSpells() {
var listener = new ResonanceCastListener();
var event = mock(PlayerCastSkillEvent.class);
var cast = mock(CastableSkill.class);
when(event.getCast()).thenReturn(cast);
when(event.getPlayer()).thenReturn(server.addPlayer());
SkillElementRegistry.register("fire_shard", "oseni", 1);
try (var ids = mockStatic(SkillIdResolver.class);
var hand = mockStatic(GearHand.class)) {
ids.when(() -> SkillIdResolver.isActiveCast(cast)).thenReturn(true);
ids.when(() -> SkillIdResolver.isClassCast(cast)).thenReturn(true);
ids.when(() -> SkillIdResolver.resolveSkillId(cast)).thenReturn("fire_shard");
listener.onPlayerCastSkill(event);
ids.verify(() -> SkillIdResolver.resolveSkillId(cast), never());
hand.verifyNoInteractions();
}
verify(event, never()).setCancelled(anyBoolean());
verify(cast, never()).whenCast(any());
}

@Test
void castDriftIgnoresClassCasts() {
var listener = new CastDriftListener();
var event = mock(SkillCastEvent.class);
var cast = mock(CastableSkill.class);
when(cast.getTrigger()).thenReturn(TriggerType.CAST);
when(cast.getParameter("mana")).thenReturn(40.);
when(event.getCast()).thenReturn(cast);
var player = server.addPlayer();
when(event.getPlayer()).thenReturn(player);
var sessions = new ResonanceSessionManager();
when(Magic.plugin.getResonanceGuiManager().getSessionManager()).thenReturn(sessions);
var session = sessions.getOrCreate(player);
listener.onSkillCast(event);
assertEquals(0., session.getEquilibrium());
verify(Magic.plugin, never()).syncSpellModifiers(player, session);
}
}
Loading