This commit is contained in:
1 parent
27f38818ae
commit
1361ba3fb2
6 files changed
+516
-1
No files matched your search
@@ -0,0 +1,369 @@
|
||||
package games.dmg.fantasystick;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.*;
|
||||
import static org.mockito.ArgumentMatchers.*;
|
||||
import static org.mockito.Mockito.*;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.nio.file.Path;
|
||||
import org.junit.jupiter.api.BeforeAll;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.junit.jupiter.api.io.TempDir;
|
||||
|
||||
class GreatSwordNativeTest {
|
||||
@TempDir Path data;
|
||||
@BeforeAll static void bootstrap() throws Exception { NativeRuntime.bootstrap(); }
|
||||
|
||||
@Test void bookAcquisitionAndFullyChargedEquippedStrikeReplaceVanillaDamage() throws Exception {
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
var a = new FantasyStickLifecycleNativeTest.Actor(data);
|
||||
withStrength(data, a, 12);
|
||||
f.players.put(a.core.id, a.player); f.activate(a);
|
||||
|
||||
a.core.inventory.getInventory().setSelectedSlot(0);
|
||||
PartyBookNativeTest.open(f, a);
|
||||
String book = PartyBookNativeTest.text(a);
|
||||
assertTrue(book.contains("Great Sword"));
|
||||
assertTrue(book.contains("STR 12"));
|
||||
assertTrue(book.contains("1.2"));
|
||||
var learn = abilityButton(a, "[Learn]", "great_sword");
|
||||
PartyBookNativeTest.click(f, a, learn); PartyBookNativeTest.click(f, a, learn);
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
PartyBookNativeTest.click(f, a, abilityButton(a, "[3]", "great_sword"));
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
|
||||
var storage = (games.dmg.fantasystick.persistence.CharacterStorage)
|
||||
FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "characters");
|
||||
var assigned = storage.find(a.core.record.id()).get().orElseThrow();
|
||||
assertTrue(assigned.learned().contains("great_sword"));
|
||||
assertEquals("great_sword", assigned.loadout().getFirst());
|
||||
assertEquals(BigInteger.valueOf(39), assigned.unspentPoints());
|
||||
assertEquals(org.bukkit.Material.WOODEN_SWORD, a.core.inventory.getItem(2).getType());
|
||||
|
||||
when(a.player.getAttackCooldown()).thenReturn(1.0f);
|
||||
var target = mock(org.bukkit.entity.LivingEntity.class);
|
||||
when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
|
||||
when(target.getType()).thenReturn(org.bukkit.entity.EntityType.ZOMBIE);
|
||||
when(a.world.getUID()).thenReturn(java.util.UUID.randomUUID());
|
||||
when(target.getLocation()).thenReturn(new org.bukkit.Location(a.world, 4, 64, 0));
|
||||
var damages = new java.util.ArrayList<org.bukkit.event.entity.EntityDamageByEntityEvent>();
|
||||
doAnswer(call -> {
|
||||
var source = (org.bukkit.damage.DamageSource) call.getArgument(1);
|
||||
var event = new org.bukkit.event.entity.EntityDamageByEntityEvent(a.player, target,
|
||||
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK, source,
|
||||
(Double) call.getArgument(0));
|
||||
damages.add(event); f.dispatcher.accept(event); return null;
|
||||
}).when(target).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
|
||||
a.core.inventory.getInventory().setSelectedSlot(2);
|
||||
var before = java.time.Instant.now();
|
||||
var attack = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, target, true);
|
||||
f.dispatcher.accept(attack);
|
||||
assertTrue(attack.isCancelled(), "The bound sword must never continue into vanilla damage");
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
assertEquals(1, damages.size());
|
||||
assertEquals(8.0, damages.getFirst().getDamage());
|
||||
assertSame(a.player, damages.getFirst().getDamager());
|
||||
assertEquals(org.bukkit.damage.DamageType.PLAYER_ATTACK, damages.getFirst().getDamageSource().getDamageType());
|
||||
|
||||
var saved = storage.find(a.core.record.id()).get().orElseThrow();
|
||||
var deadline = saved.cooldowns().get("great_sword");
|
||||
assertNotNull(deadline);
|
||||
assertFalse(deadline.isBefore(before.plusMillis(1200)));
|
||||
assertFalse(deadline.isAfter(java.time.Instant.now().plusMillis(1200)));
|
||||
f.dispatcher.accept(new org.bukkit.event.entity.EntityDeathEvent(target, damages.getFirst().getDamageSource(),
|
||||
new java.util.ArrayList<>(), 0));
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
assertEquals(BigInteger.TEN, storage.find(a.core.record.id()).get().orElseThrow().experience(),
|
||||
"Accepted direct damage is attributed to the originating character");
|
||||
f.dispatcher.accept(new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, target, true));
|
||||
PartyBookNativeTest.drain(f);
|
||||
assertEquals(1, damages.size(), "The persisted recovery prevents a repeated strike");
|
||||
assertTrue(a.messages.stream().anyMatch(message -> message.contains("ready in")));
|
||||
}
|
||||
}
|
||||
|
||||
@Test void partialChargeUsesTheApprovedNativeCurveWithoutVanillaContinuation() throws Exception {
|
||||
java.nio.file.Files.writeString(data.resolve("config.yml"), "great-sword-recovery-seconds: 0\n");
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
var a = new FantasyStickLifecycleNativeTest.Actor(data);
|
||||
withGreatSword(data, a, 12);
|
||||
f.players.put(a.core.id, a.player); f.activate(a);
|
||||
when(a.player.getAttackCooldown()).thenReturn(0.5f);
|
||||
var target = mock(org.bukkit.entity.LivingEntity.class);
|
||||
when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
|
||||
var damages = new java.util.ArrayList<Double>();
|
||||
doAnswer(call -> {
|
||||
double amount = call.getArgument(0); damages.add(amount);
|
||||
var source = (org.bukkit.damage.DamageSource) call.getArgument(1);
|
||||
f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(a.player, target,
|
||||
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK, source, amount));
|
||||
return null;
|
||||
}).when(target).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
a.core.inventory.getInventory().setSelectedSlot(2);
|
||||
var attack = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, target, true);
|
||||
f.dispatcher.accept(attack); PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
assertTrue(attack.isCancelled());
|
||||
assertEquals(java.util.List.of(3.2), damages);
|
||||
}
|
||||
}
|
||||
|
||||
@Test void refusedPlayersAndCancelledNativeDamagePreserveProtectionWithoutFreeVanillaHits() throws Exception {
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
var a = new FantasyStickLifecycleNativeTest.Actor(data);
|
||||
var b = new FantasyStickLifecycleNativeTest.Actor(data);
|
||||
withGreatSword(data, a, 12);
|
||||
f.players.put(a.core.id, a.player); f.players.put(b.core.id, b.player);
|
||||
f.activate(a); f.activate(b);
|
||||
var parties = PartyLifecycleNativeTest.parties(f);
|
||||
var party = parties.create(a.core.id).orElseThrow();
|
||||
assertTrue(parties.accept(b.core.id,
|
||||
parties.invite(a.core.id, party.id(), b.core.id).orElseThrow().id()));
|
||||
when(a.player.getAttackCooldown()).thenReturn(1.0f);
|
||||
a.core.inventory.getInventory().setSelectedSlot(2);
|
||||
|
||||
var partyAttack = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, b.player, true);
|
||||
f.dispatcher.accept(partyAttack); PartyBookNativeTest.drain(f);
|
||||
assertTrue(partyAttack.isCancelled());
|
||||
verify(b.player, never()).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
|
||||
var ordinary = mock(org.bukkit.entity.Player.class);
|
||||
when(ordinary.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
|
||||
var ordinaryAttack = new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, ordinary, true);
|
||||
f.dispatcher.accept(ordinaryAttack); PartyBookNativeTest.drain(f);
|
||||
assertTrue(ordinaryAttack.isCancelled());
|
||||
verify(ordinary, never()).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
|
||||
var target = mock(org.bukkit.entity.LivingEntity.class);
|
||||
when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
|
||||
when(target.getType()).thenReturn(org.bukkit.entity.EntityType.ZOMBIE);
|
||||
when(a.world.getUID()).thenReturn(java.util.UUID.randomUUID());
|
||||
when(target.getLocation()).thenReturn(new org.bukkit.Location(a.world, 4, 64, 0));
|
||||
var damage = new java.util.concurrent.atomic.AtomicReference<org.bukkit.event.entity.EntityDamageByEntityEvent>();
|
||||
doAnswer(call -> {
|
||||
var source = (org.bukkit.damage.DamageSource) call.getArgument(1);
|
||||
var event = new org.bukkit.event.entity.EntityDamageByEntityEvent(a.player, target,
|
||||
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK, source,
|
||||
(Double) call.getArgument(0));
|
||||
event.setCancelled(true); damage.set(event); f.dispatcher.accept(event); return null;
|
||||
}).when(target).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
f.dispatcher.accept(new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, target, true));
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
assertNotNull(damage.get()); assertTrue(damage.get().isCancelled());
|
||||
var storage = (games.dmg.fantasystick.persistence.CharacterStorage)
|
||||
FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "characters");
|
||||
assertNotNull(storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("great_sword"),
|
||||
"An acknowledged recovery is not refunded by later native cancellation");
|
||||
f.dispatcher.accept(new org.bukkit.event.entity.EntityDeathEvent(target, damage.get().getDamageSource(),
|
||||
new java.util.ArrayList<>(), 0));
|
||||
PartyBookNativeTest.drain(f);
|
||||
assertEquals(BigInteger.ZERO, storage.find(a.core.record.id()).get().orElseThrow().experience());
|
||||
}
|
||||
}
|
||||
|
||||
@Test void unlearnRelearnAndWholeCharacterTransferRetainTheOriginalRecovery() throws Exception {
|
||||
java.nio.file.Files.writeString(data.resolve("config.yml"), "great-sword-recovery-seconds: 60\n");
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
var a = new FantasyStickLifecycleNativeTest.Actor(data); withStrength(data, a, 12);
|
||||
f.players.put(a.core.id, a.player); f.activate(a);
|
||||
learnAndAssign(f, a);
|
||||
when(a.player.getAttackCooldown()).thenReturn(1.0f);
|
||||
var target = mock(org.bukkit.entity.LivingEntity.class);
|
||||
when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
|
||||
var hits = new java.util.concurrent.atomic.AtomicInteger();
|
||||
doAnswer(call -> {
|
||||
hits.incrementAndGet();
|
||||
var source = (org.bukkit.damage.DamageSource) call.getArgument(1);
|
||||
f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(a.player, target,
|
||||
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK, source,
|
||||
(Double) call.getArgument(0))); return null;
|
||||
}).when(target).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
a.core.inventory.getInventory().setSelectedSlot(2);
|
||||
f.dispatcher.accept(new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, target, true));
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
assertEquals(1, hits.get());
|
||||
var storage = (games.dmg.fantasystick.persistence.CharacterStorage)
|
||||
FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "characters");
|
||||
var deadline = storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("great_sword");
|
||||
assertNotNull(deadline);
|
||||
|
||||
a.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, a);
|
||||
var unlearn = abilityButton(a, "[Unlearn]", "great_sword");
|
||||
PartyBookNativeTest.click(f, a, unlearn); PartyBookNativeTest.click(f, a, unlearn);
|
||||
PartyBookNativeTest.drain(f); PartyBookNativeTest.drain(f);
|
||||
var refunded = storage.find(a.core.record.id()).get().orElseThrow();
|
||||
assertEquals(BigInteger.valueOf(40), refunded.unspentPoints());
|
||||
assertFalse(refunded.learned().contains("great_sword"));
|
||||
assertTrue(refunded.loadout().stream().noneMatch("great_sword"::equals));
|
||||
assertEquals(deadline, refunded.cooldowns().get("great_sword"));
|
||||
assertTrue(new games.dmg.fantasystick.items.SessionControls(
|
||||
(games.dmg.fantasystick.ability.AbilityRegistry) FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "abilityRegistry"))
|
||||
.ability(a.core.inventory.getItem(2)).isEmpty());
|
||||
|
||||
learnAndAssign(f, a);
|
||||
assertEquals(deadline, storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("great_sword"));
|
||||
a.core.inventory.getInventory().setSelectedSlot(2);
|
||||
f.dispatcher.accept(new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(a.player, target, true));
|
||||
PartyBookNativeTest.drain(f);
|
||||
assertEquals(1, hits.get());
|
||||
assertTrue(a.messages.stream().anyMatch(message -> message.contains("ready in")));
|
||||
|
||||
var sheet = a.core.inventory.getItemInOffHand().clone();
|
||||
a.core.inventory.setItemInOffHand(null); f.changed(a); PartyBookNativeTest.drain(f); f.awaitCharacterAndReceipt(a);
|
||||
var b = new FantasyStickLifecycleNativeTest.Actor(data); b.core.inventory.setItemInOffHand(sheet);
|
||||
f.players.put(b.core.id, b.player); f.activate(b);
|
||||
when(b.player.getAttackCooldown()).thenReturn(1.0f);
|
||||
b.core.inventory.getInventory().setSelectedSlot(2);
|
||||
f.dispatcher.accept(new io.papermc.paper.event.player.PrePlayerAttackEntityEvent(b.player, target, true));
|
||||
PartyBookNativeTest.drain(f);
|
||||
assertEquals(1, hits.get(), "Transfer cannot reset the character-bound recovery");
|
||||
assertEquals(deadline, storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("great_sword"));
|
||||
}
|
||||
}
|
||||
|
||||
@Test void failedCooldownPersistenceDealsNoDamageOrFreeEffect() {
|
||||
var storage = mock(games.dmg.fantasystick.persistence.CharacterStorage.class);
|
||||
var sessions = mock(games.dmg.fantasystick.session.EquipmentSessions.class);
|
||||
var parties = new games.dmg.fantasystick.party.PartyRoster(java.time.Clock.systemUTC(), ignored -> true);
|
||||
var registry = new games.dmg.fantasystick.ability.AbilityRegistry();
|
||||
var sword = new games.dmg.fantasystick.ability.GreatSword(
|
||||
games.dmg.fantasystick.ability.GreatSword.Settings.defaults());
|
||||
registry.register(sword.definition());
|
||||
var base = new games.dmg.fantasystick.crafting.CharacterFactory().create(
|
||||
games.dmg.fantasystick.progression.ProgressionRules.defaults());
|
||||
var stats = new java.util.EnumMap<>(base.stats());
|
||||
stats.put(games.dmg.fantasystick.progression.Stat.STR, BigInteger.valueOf(12));
|
||||
var record = new games.dmg.fantasystick.persistence.CharacterRecord(base.id(), base.name(), base.revision(), stats,
|
||||
base.level(), base.experience(), base.unspentPoints(), base.health(), java.util.Set.of("great_sword"),
|
||||
java.util.List.of("great_sword", "", "", "", "", "", ""), base.cooldowns(), base.restrictedKills(),
|
||||
false, null, null);
|
||||
var active = new games.dmg.fantasystick.session.EquipmentSessions.Active(java.util.UUID.randomUUID(),
|
||||
java.util.UUID.randomUUID(), record.id());
|
||||
var player = mock(org.bukkit.entity.Player.class);
|
||||
var target = mock(org.bukkit.entity.LivingEntity.class);
|
||||
when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());
|
||||
when(sessions.current(active)).thenReturn(true);
|
||||
when(sessions.currentRecord(active)).thenReturn(java.util.Optional.of(record));
|
||||
var failed = new java.util.concurrent.CompletableFuture<games.dmg.fantasystick.persistence.CharacterStorage.AbilityMutation>();
|
||||
failed.completeExceptionally(new java.io.IOException("simulated Great Sword cooldown failure"));
|
||||
when(storage.commitAbilityCooldown(eq(record.id()), eq(record.revision()), eq("great_sword"), any()))
|
||||
.thenReturn(failed);
|
||||
var failures = new java.util.ArrayList<games.dmg.fantasystick.ability.AbilityEngine.Failure>();
|
||||
var engine = new games.dmg.fantasystick.ability.AbilityEngine(registry, storage, sessions, parties,
|
||||
java.time.Clock.systemUTC(), Runnable::run, (delay, action) -> () -> {}, ignored -> {}, failures::add);
|
||||
engine.accept(new games.dmg.fantasystick.session.ControlInput(player, active, 2, "great_sword",
|
||||
games.dmg.fantasystick.session.ControlInput.Kind.ABILITY,
|
||||
games.dmg.fantasystick.session.ControlInput.Gesture.ATTACK, target, 0, 1, () -> true));
|
||||
verify(target, never()).damage(anyDouble(), any(org.bukkit.damage.DamageSource.class));
|
||||
assertEquals(1, failures.size());
|
||||
engine.close(); sword.close(); parties.close();
|
||||
}
|
||||
|
||||
@Test void invalidGreatSwordBalanceFailsBeforeInstallingGameplay() throws Exception {
|
||||
for (String configuration : java.util.List.of("great-sword-base-damage: -1\n",
|
||||
"great-sword-recovery-seconds: -0.1\n", "great-sword-recovery-seconds: 31536001\n",
|
||||
"great-sword-recovery-seconds: 0.0000000001\n", "great-sword-base-damage: nope\n")) {
|
||||
var directory = data.resolve(Integer.toHexString(configuration.hashCode()));
|
||||
java.nio.file.Files.createDirectories(directory);
|
||||
java.nio.file.Files.writeString(directory.resolve("config.yml"), configuration);
|
||||
try (var fixture = new FantasyStickLifecycleNativeTest.Fixture(directory)) {
|
||||
assertThrows(IllegalArgumentException.class, () -> fixture.plugin.setEnabled(true));
|
||||
assertTrue(fixture.order.isEmpty()); assertTrue(fixture.recipes.isEmpty());
|
||||
assertFalse(java.nio.file.Files.exists(directory.resolve("characters")));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Test void configuredDefinitionAndChargeCurvePreserveExactUncappedScaling() throws Exception {
|
||||
java.nio.file.Files.writeString(data.resolve("config.yml"),
|
||||
"great-sword-base-damage: 9\ngreat-sword-recovery-seconds: 2.5\n");
|
||||
try (var f = new FantasyStickLifecycleNativeTest.Fixture(data)) {
|
||||
f.plugin.setEnabled(true);
|
||||
var registry = (games.dmg.fantasystick.ability.AbilityRegistry)
|
||||
FantasyStickLifecycleNativeTest.Fixture.field(f.plugin, "abilityRegistry");
|
||||
var definition = registry.find("great_sword").orElseThrow();
|
||||
assertEquals(java.time.Duration.ofMillis(2500), definition.cooldown());
|
||||
assertEquals(new java.math.BigDecimal("9"), definition.parameters().get("base-damage"));
|
||||
assertEquals("Great Sword", definition.name());
|
||||
assertEquals(org.bukkit.Material.WOODEN_SWORD, definition.icon());
|
||||
assertEquals(java.util.Map.of(games.dmg.fantasystick.progression.Stat.STR, BigInteger.valueOf(12)),
|
||||
definition.requirements());
|
||||
assertEquals(games.dmg.fantasystick.session.ControlInput.Gesture.ATTACK, definition.gesture());
|
||||
var unavailable = new FantasyStickLifecycleNativeTest.Actor(data);
|
||||
f.players.put(unavailable.core.id, unavailable.player); f.activate(unavailable);
|
||||
unavailable.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(f, unavailable);
|
||||
String text = PartyBookNativeTest.text(unavailable);
|
||||
assertTrue(text.contains("Great Sword"));
|
||||
assertTrue(text.replaceAll("\\s+", "").contains("Unavailable:requirements"), text);
|
||||
assertThrows(AssertionError.class, () -> abilityButton(unavailable, "[Learn]", "great_sword"));
|
||||
}
|
||||
assertEquals(new java.math.BigDecimal("8"),
|
||||
games.dmg.fantasystick.ability.GreatSword.damage(BigInteger.valueOf(12), 1.0f));
|
||||
assertEquals(new java.math.BigDecimal("3.2"),
|
||||
games.dmg.fantasystick.ability.GreatSword.damage(BigInteger.valueOf(12), 0.5f));
|
||||
assertEquals(new java.math.BigDecimal("1.6"),
|
||||
games.dmg.fantasystick.ability.GreatSword.damage(BigInteger.valueOf(12), 0.0f));
|
||||
assertEquals(new java.math.BigDecimal(BigInteger.TEN.pow(500).subtract(BigInteger.TEN)
|
||||
.divide(BigInteger.TWO).add(BigInteger.valueOf(7))),
|
||||
games.dmg.fantasystick.ability.GreatSword.damage(BigInteger.TEN.pow(500), 1.0f));
|
||||
}
|
||||
|
||||
private static void learnAndAssign(FantasyStickLifecycleNativeTest.Fixture fixture,
|
||||
FantasyStickLifecycleNativeTest.Actor actor) throws Exception {
|
||||
actor.core.inventory.getInventory().setSelectedSlot(0); PartyBookNativeTest.open(fixture, actor);
|
||||
PartyBookNativeTest.click(fixture, actor, abilityButton(actor, "[Learn]", "great_sword"));
|
||||
PartyBookNativeTest.drain(fixture); PartyBookNativeTest.drain(fixture);
|
||||
PartyBookNativeTest.click(fixture, actor, abilityButton(actor, "[3]", "great_sword"));
|
||||
PartyBookNativeTest.drain(fixture); PartyBookNativeTest.drain(fixture);
|
||||
}
|
||||
|
||||
private static net.minecraft.network.chat.ClickEvent.Custom abilityButton(
|
||||
FantasyStickLifecycleNativeTest.Actor actor, String label, String ability) {
|
||||
var book = org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(actor.books.getLast())
|
||||
.get(net.minecraft.core.component.DataComponents.WRITTEN_BOOK_CONTENT);
|
||||
assertNotNull(book);
|
||||
for (var page : book.pages()) {
|
||||
var found = abilityButton(page.raw(), label, ability);
|
||||
if (found != null) return found;
|
||||
}
|
||||
throw new AssertionError("Missing " + label + " action for " + ability);
|
||||
}
|
||||
|
||||
private static net.minecraft.network.chat.ClickEvent.Custom abilityButton(
|
||||
net.minecraft.network.chat.Component component, String label, String ability) {
|
||||
if (component.getString().equals(label)
|
||||
&& component.getStyle().getClickEvent() instanceof net.minecraft.network.chat.ClickEvent.Custom custom
|
||||
&& custom.payload().orElse(null) instanceof net.minecraft.nbt.StringTag payload
|
||||
&& payload.value().contains(":" + ability)) return custom;
|
||||
for (var child : component.getSiblings()) {
|
||||
var found = abilityButton(child, label, ability);
|
||||
if (found != null) return found;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static void withGreatSword(Path data, FantasyStickLifecycleNativeTest.Actor actor, int strength) throws Exception {
|
||||
var repository = new games.dmg.fantasystick.persistence.YamlCharacterRepository(data);
|
||||
var old = repository.load(actor.core.record.id()).orElseThrow();
|
||||
var stats = new java.util.EnumMap<>(old.stats());
|
||||
stats.put(games.dmg.fantasystick.progression.Stat.STR, BigInteger.valueOf(strength));
|
||||
repository.replace(new games.dmg.fantasystick.persistence.CharacterRecord(old.id(), old.name(),
|
||||
old.revision().add(BigInteger.ONE), stats, old.level(), old.experience(), old.unspentPoints(), old.health(),
|
||||
java.util.Set.of("great_sword"), java.util.List.of("great_sword", "", "", "", "", "", ""),
|
||||
old.cooldowns(), old.restrictedKills(), false, null, null), old.revision());
|
||||
}
|
||||
|
||||
private static void withStrength(Path data, FantasyStickLifecycleNativeTest.Actor actor, int strength) throws Exception {
|
||||
var repository = new games.dmg.fantasystick.persistence.YamlCharacterRepository(data);
|
||||
var old = repository.load(actor.core.record.id()).orElseThrow();
|
||||
var stats = new java.util.EnumMap<>(old.stats());
|
||||
stats.put(games.dmg.fantasystick.progression.Stat.STR, BigInteger.valueOf(strength));
|
||||
repository.replace(new games.dmg.fantasystick.persistence.CharacterRecord(old.id(), old.name(),
|
||||
old.revision().add(BigInteger.ONE), stats, old.level(), old.experience(), old.unspentPoints(), old.health(),
|
||||
old.learned(), old.loadout(), old.cooldowns(), old.restrictedKills(), false, null, null), old.revision());
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user