|
|
|
@@ -2,24 +2,223 @@ package games.dmg.fantasystick;
|
|
|
|
|
import static org.junit.jupiter.api.Assertions.*;import static org.mockito.Mockito.*;
|
|
|
|
|
import games.dmg.fantasystick.persistence.*;import games.dmg.fantasystick.progression.Stat;import java.math.BigInteger;import java.nio.file.Path;import java.util.*;import net.minecraft.network.chat.ClickEvent;import org.bukkit.event.player.PlayerInteractEvent;import org.bukkit.inventory.EquipmentSlot;import org.junit.jupiter.api.*;import org.junit.jupiter.api.io.TempDir;
|
|
|
|
|
class InspireNativeTest{@TempDir Path data;@BeforeAll static void bootstrap()throws Exception{NativeRuntime.bootstrap();}
|
|
|
|
|
@Test void registeredBookSelfCastExpiryReachesExportedJsonlWithoutInventingPrevention()throws Exception{
|
|
|
|
|
UUID playerId,characterId,sessionId;
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var actor=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,actor,false);
|
|
|
|
|
f.players.put(actor.core.id,actor.player);f.activate(actor);playerId=actor.core.id;characterId=actor.core.record.id();
|
|
|
|
|
var sessions=(games.dmg.fantasystick.session.EquipmentSessions)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"sessions");
|
|
|
|
|
sessionId=sessions.active(playerId).orElseThrow().session();
|
|
|
|
|
learnAndAssign(f,actor);var absorption=new java.util.concurrent.atomic.AtomicReference<>(2.0);
|
|
|
|
|
doAnswer(call->absorption.get()).when(actor.player).getAbsorptionAmount();
|
|
|
|
|
doAnswer(call->{absorption.set(call.getArgument(0));return null;}).when(actor.player).setAbsorptionAmount(anyDouble());
|
|
|
|
|
doReturn(true).when(actor.player).isSneaking();use(f,actor);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
|
|
|
|
|
assertEquals(7,absorption.get(),1e-9);f.delayed.getLast().run();assertEquals(2,absorption.get(),1e-9);
|
|
|
|
|
}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"ability.learned"));assertEquals(1,count(own,"ability.assigned"));
|
|
|
|
|
assertEquals(1,count(own,"ability.cast"));assertEquals(1,count(own,"effect.applied"));
|
|
|
|
|
assertEquals(1,count(own,"effect.ended"));assertEquals(0,count(own,"combat.prevented"));
|
|
|
|
|
var cast=record(own,"ability.cast");var applied=record(own,"effect.applied");var ended=record(own,"effect.ended");
|
|
|
|
|
assertEquals(playerId.toString(),cast.get("player_id").getAsString());
|
|
|
|
|
assertEquals(characterId.toString(),cast.get("character_id").getAsString());
|
|
|
|
|
assertEquals(sessionId.toString(),cast.get("session_id").getAsString());
|
|
|
|
|
assertTrue(cast.has("cooldown_until"));assertEquals("5",applied.get("granted_amount").getAsString());
|
|
|
|
|
assertEquals(applied.get("application_id").getAsString(),ended.get("application_id").getAsString());
|
|
|
|
|
assertEquals("5",ended.get("remaining_amount").getAsString(),"unused native protection expires without prevention");
|
|
|
|
|
assertEquals("expired",ended.get("reason").getAsString());
|
|
|
|
|
assertEquals("expired",record(own,"ability.resolved").get("outcome").getAsString());
|
|
|
|
|
}
|
|
|
|
|
@Test void registeredAllyAbsorptionRecordsOnlyObservedConsumedHealth()throws Exception{
|
|
|
|
|
UUID actorId,characterId,sessionId,targetId,targetCharacterId,targetSessionId,worldId;
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);var b=new FantasyStickLifecycleNativeTest.Actor(data);
|
|
|
|
|
withInspire(data,a,true);f.players.put(a.core.id,a.player);f.players.put(b.core.id,b.player);f.activate(a);f.activate(b);
|
|
|
|
|
var sessions=(games.dmg.fantasystick.session.EquipmentSessions)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"sessions");
|
|
|
|
|
actorId=a.core.id;characterId=a.core.record.id();sessionId=sessions.active(actorId).orElseThrow().session();
|
|
|
|
|
targetId=b.core.id;targetCharacterId=b.core.record.id();targetSessionId=sessions.active(targetId).orElseThrow().session();
|
|
|
|
|
worldId=UUID.randomUUID();when(a.world.getUID()).thenReturn(worldId);
|
|
|
|
|
doReturn(false).when(a.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(a.player).getLocation();
|
|
|
|
|
doReturn(new org.bukkit.Location(a.world,8,64,0)).when(b.player).getLocation();
|
|
|
|
|
doReturn(true).when(a.player).hasLineOfSight(b.player);doReturn(b.player).when(a.player).getTargetEntity(64);
|
|
|
|
|
var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);
|
|
|
|
|
doAnswer(call->absorption.get()).when(b.player).getAbsorptionAmount();
|
|
|
|
|
doAnswer(call->{absorption.set(call.getArgument(0));return null;}).when(b.player).setAbsorptionAmount(anyDouble());
|
|
|
|
|
assertTrue(f.feedbackCommand.execute(a.player,"fantasyfeedback",new String[]{"off"}));f.tick();
|
|
|
|
|
use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(5,absorption.get(),1e-9);
|
|
|
|
|
var enemy=mock(org.bukkit.entity.LivingEntity.class);when(enemy.getUniqueId()).thenReturn(UUID.randomUUID());
|
|
|
|
|
when(enemy.getType()).thenReturn(org.bukkit.entity.EntityType.ZOMBIE);
|
|
|
|
|
when(enemy.getLocation()).thenReturn(new org.bukkit.Location(a.world,8,64,1));
|
|
|
|
|
var source=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK)
|
|
|
|
|
.withCausingEntity(enemy).withDirectEntity(enemy).build();
|
|
|
|
|
var cancelled=new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,b.player,
|
|
|
|
|
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3);cancelled.setCancelled(true);
|
|
|
|
|
f.dispatcher.accept(cancelled);PartyBookNativeTest.drain(f);assertEquals(5,absorption.get(),1e-9);
|
|
|
|
|
var hit=new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,b.player,
|
|
|
|
|
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3);
|
|
|
|
|
f.dispatcher.accept(hit);absorption.set(2.0);PartyBookNativeTest.drain(f);
|
|
|
|
|
assertEquals(2,absorption.get(),1e-9);
|
|
|
|
|
}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"ability.cast"));assertEquals(1,count(own,"effect.applied"));
|
|
|
|
|
assertEquals(1,count(own,"combat.prevented"));var consumed=record(own,"combat.prevented");
|
|
|
|
|
assertEquals(actorId.toString(),consumed.get("player_id").getAsString());
|
|
|
|
|
assertEquals(characterId.toString(),consumed.get("character_id").getAsString());
|
|
|
|
|
assertEquals(sessionId.toString(),consumed.get("session_id").getAsString());
|
|
|
|
|
assertEquals(targetId.toString(),consumed.get("protected_target_id").getAsString());
|
|
|
|
|
assertEquals(targetCharacterId.toString(),consumed.get("protected_character_id").getAsString());
|
|
|
|
|
assertEquals(targetSessionId.toString(),consumed.get("protected_session_id").getAsString());
|
|
|
|
|
assertEquals(worldId.toString(),consumed.getAsJsonObject("protected_location").get("world_id").getAsString());
|
|
|
|
|
assertEquals(8,consumed.getAsJsonObject("protected_location").get("x").getAsDouble(),1e-9);
|
|
|
|
|
assertEquals(3,consumed.get("actual_amount").getAsDouble(),1e-9);
|
|
|
|
|
assertEquals(record(own,"ability.cast").get("action_id").getAsString(),consumed.get("action_id").getAsString());
|
|
|
|
|
assertEquals(record(own,"effect.applied").get("application_id").getAsString(),consumed.get("effect_application_id").getAsString());
|
|
|
|
|
}
|
|
|
|
|
@Test void unavailableAuditOnlyAttackerLocationCannotInterruptNativeAbsorption()throws Exception{
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);
|
|
|
|
|
f.players.put(a.core.id,a.player);f.activate(a);var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);
|
|
|
|
|
doAnswer(call->absorption.get()).when(a.player).getAbsorptionAmount();
|
|
|
|
|
doAnswer(call->{absorption.set(call.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());
|
|
|
|
|
doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
|
|
|
|
|
var enemy=mock(org.bukkit.entity.Zombie.class);when(enemy.getUniqueId()).thenReturn(UUID.randomUUID());
|
|
|
|
|
when(enemy.getLocation()).thenThrow(new IllegalStateException("unavailable audit location"));
|
|
|
|
|
var source=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK)
|
|
|
|
|
.withCausingEntity(enemy).withDirectEntity(enemy).build();
|
|
|
|
|
var hit=new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,a.player,
|
|
|
|
|
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3);
|
|
|
|
|
var owner=(games.dmg.fantasystick.ability.TemporaryHealth)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"temporaryHealth");
|
|
|
|
|
owner.damage(hit);absorption.set(2.0);PartyBookNativeTest.drain(f);assertEquals(2,absorption.get(),1e-9);
|
|
|
|
|
}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"combat.prevented"));
|
|
|
|
|
assertFalse(record(own,"combat.prevented").has("attacker_location"));
|
|
|
|
|
}
|
|
|
|
|
@Test void rejectedNativeAbsorptionSetterCannotLeaveAnOrphanOwnedGrant()throws Exception{
|
|
|
|
|
var attempts=new java.util.concurrent.atomic.AtomicInteger();
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);
|
|
|
|
|
f.players.put(a.core.id,a.player);f.activate(a);
|
|
|
|
|
doReturn(0.0).when(a.player).getAbsorptionAmount();
|
|
|
|
|
doAnswer(call->{if(attempts.incrementAndGet()==1)throw new IllegalStateException("native refused");
|
|
|
|
|
return null;}).when(a.player).setAbsorptionAmount(anyDouble());
|
|
|
|
|
doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
|
|
|
|
|
assertEquals(1,attempts.get(),"native admission was attempted once");
|
|
|
|
|
}
|
|
|
|
|
assertEquals(1,attempts.get(),"an unadmitted effect must not be cleaned up as an owned native grant");
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"ability.cast"));
|
|
|
|
|
assertEquals(0,count(own,"effect.applied"));assertEquals(0,count(own,"combat.prevented"));
|
|
|
|
|
assertEquals("failed",record(own,"ability.resolved").get("outcome").getAsString());
|
|
|
|
|
}
|
|
|
|
|
@Test void duplicateNativeCallbackCannotDoubleClaimOneAbsorptionDrop()throws Exception{
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);
|
|
|
|
|
f.players.put(a.core.id,a.player);f.activate(a);var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);
|
|
|
|
|
doAnswer(call->absorption.get()).when(a.player).getAbsorptionAmount();
|
|
|
|
|
doAnswer(call->{absorption.set(call.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());
|
|
|
|
|
doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
|
|
|
|
|
assertEquals(5,absorption.get(),1e-9);
|
|
|
|
|
var enemy=mock(org.bukkit.entity.Zombie.class);when(enemy.getUniqueId()).thenReturn(UUID.randomUUID());
|
|
|
|
|
var source=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK)
|
|
|
|
|
.withCausingEntity(enemy).withDirectEntity(enemy).build();
|
|
|
|
|
var hit=new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,a.player,
|
|
|
|
|
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3);
|
|
|
|
|
f.dispatcher.accept(hit);f.dispatcher.accept(hit);absorption.set(2.0);PartyBookNativeTest.drain(f);
|
|
|
|
|
assertEquals(2,absorption.get(),1e-9);
|
|
|
|
|
}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"combat.prevented"));
|
|
|
|
|
assertEquals(3,record(own,"combat.prevented").get("actual_amount").getAsDouble(),1e-9);
|
|
|
|
|
}
|
|
|
|
|
@Test void rejectedWriterCannotChangeNativeAbsorptionOrInventPrevention()throws Exception{
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);
|
|
|
|
|
f.players.put(a.core.id,a.player);f.activate(a);var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);
|
|
|
|
|
doAnswer(call->absorption.get()).when(a.player).getAbsorptionAmount();
|
|
|
|
|
doAnswer(call->{absorption.set(call.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());
|
|
|
|
|
doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
|
|
|
|
|
((games.dmg.fantasystick.events.LocalEventLog)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"eventLog")).close();
|
|
|
|
|
var enemy=mock(org.bukkit.entity.Zombie.class);when(enemy.getUniqueId()).thenReturn(UUID.randomUUID());
|
|
|
|
|
var source=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK)
|
|
|
|
|
.withCausingEntity(enemy).withDirectEntity(enemy).build();
|
|
|
|
|
var hit=new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,a.player,
|
|
|
|
|
org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3);
|
|
|
|
|
f.dispatcher.accept(hit);absorption.set(2.0);PartyBookNativeTest.drain(f);
|
|
|
|
|
assertEquals(2,absorption.get(),1e-9);f.delayed.getLast().run();assertEquals(0,absorption.get(),1e-9);
|
|
|
|
|
}
|
|
|
|
|
assertEquals(0,count(inspireEvents(data),"combat.prevented"));
|
|
|
|
|
}
|
|
|
|
|
@Test void acknowledgedInspireConfigurationReadAndChangeReachExportedJsonl()throws Exception{
|
|
|
|
|
try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){
|
|
|
|
|
f.plugin.setEnabled(true);var admin=new EquipmentAdminCommandNativeTest.Sender();admin.allowed=true;
|
|
|
|
|
f.command.execute(admin.port,"fstickadmin",new String[]{"config","inspire-base-temporary-health"});
|
|
|
|
|
assertTrue(admin.messages.getLast().contains("inspire-base-temporary-health=4"));
|
|
|
|
|
f.command.execute(admin.port,"fstickadmin",new String[]{"config","inspire-base-temporary-health","9"});
|
|
|
|
|
var response=f.tasks.poll(5,java.util.concurrent.TimeUnit.SECONDS);assertNotNull(response);response.run();
|
|
|
|
|
var registry=(games.dmg.fantasystick.ability.AbilityRegistry)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"abilityRegistry");
|
|
|
|
|
assertEquals(new java.math.BigDecimal("9"),registry.find("inspire").orElseThrow().parameters().get("base-temporary-health"));
|
|
|
|
|
try(var channel=java.nio.channels.FileChannel.open(data.resolve(".config.lock"),java.nio.file.StandardOpenOption.CREATE,java.nio.file.StandardOpenOption.WRITE);
|
|
|
|
|
var lock=channel.lock()){
|
|
|
|
|
assertTrue(lock.isValid());
|
|
|
|
|
f.command.execute(admin.port,"fstickadmin",new String[]{"config","inspire-base-temporary-health","10"});
|
|
|
|
|
var failed=f.tasks.poll(5,java.util.concurrent.TimeUnit.SECONDS);assertNotNull(failed);failed.run();
|
|
|
|
|
}
|
|
|
|
|
admin.allowed=false;f.command.execute(admin.port,"fstickadmin",new String[]{"config","inspire-base-temporary-health"});
|
|
|
|
|
}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"config.read"));assertEquals(1,count(own,"config.changed"));
|
|
|
|
|
var changed=record(own,"config.changed");assertEquals("4",changed.get("before").getAsString());
|
|
|
|
|
assertEquals("9",changed.get("after").getAsString());
|
|
|
|
|
}
|
|
|
|
|
@Test void bookAcquisitionSneakUseAddsOwnedTemporaryHealthAndExpiryPreservesUnrelatedAbsorption()throws Exception{try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,false);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).replaceAll("\\s+","");assertTrue(book.contains("Inspire"));assertTrue(book.contains("CHR12"));assertTrue(book.contains("WIS10"));assertFalse(book.contains("Cost:"));assertTrue(book.contains("12"));assertTrue(book.contains("6s"));PartyBookNativeTest.click(f,a,button(a,"[Learn]","inspire"));PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);
|
|
|
|
|
double maximum=a.maximumHealth.getBaseValue();var absorption=new java.util.concurrent.atomic.AtomicReference<>(2.0);doAnswer(c->absorption.get()).when(a.player).getAbsorptionAmount();doAnswer(c->{absorption.set(c.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());doReturn(true).when(a.player).isSneaking();a.core.inventory.getInventory().setSelectedSlot(2);f.dispatcher.accept(new PlayerInteractEvent(a.player,org.bukkit.event.block.Action.RIGHT_CLICK_AIR,a.core.inventory.getItem(2),null,org.bukkit.block.BlockFace.SELF,EquipmentSlot.HAND));PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(7,absorption.get(),1e-9);assertEquals(maximum,a.maximumHealth.getBaseValue(),1e-9);assertEquals(120L,f.delayedTicks.getLast());f.delayed.getLast().run();assertEquals(2,absorption.get(),1e-9);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");assertNotNull(storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("inspire"));}}
|
|
|
|
|
@Test void aimedPartyAllyActualAbsorptionCreatesPersistedSupportShare()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);withInspire(data,a,true);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()));
|
|
|
|
|
doReturn(false).when(a.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(a.player).getLocation();doReturn(new org.bukkit.Location(a.world,8,64,0)).when(b.player).getLocation();doReturn(true).when(a.player).hasLineOfSight(b.player);doReturn(b.player).when(a.player).getTargetEntity(64);var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);doAnswer(c->absorption.get()).when(b.player).getAbsorptionAmount();doAnswer(c->{absorption.set(c.getArgument(0));return null;}).when(b.player).setAbsorptionAmount(anyDouble());use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(5,absorption.get(),1e-9);
|
|
|
|
|
var enemy=mock(org.bukkit.entity.LivingEntity.class);when(enemy.getUniqueId()).thenReturn(java.util.UUID.randomUUID());when(enemy.getType()).thenReturn(org.bukkit.entity.EntityType.ZOMBIE);when(a.world.getUID()).thenReturn(java.util.UUID.randomUUID());when(enemy.getLocation()).thenReturn(new org.bukkit.Location(a.world,8,64,0));var enemySource=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK).withCausingEntity(enemy).withDirectEntity(enemy).build();f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,b.player,org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,enemySource,3));absorption.set(2.0);PartyBookNativeTest.drain(f);String feedback="Inspire prevented 3 damage to "+b.core.record.name()+".";assertEquals(1,a.messages.stream().filter(feedback::equals).count());assertEquals(1,b.messages.stream().filter(feedback::equals).count());var sourceSheet=a.core.inventory.getItemInOffHand().clone();a.core.inventory.setItemInOffHand(null);f.changed(a);PartyBookNativeTest.drain(f);f.awaitCharacterAndReceipt(a);var holder=new FantasyStickLifecycleNativeTest.Actor(data);holder.core.inventory.setItemInOffHand(sourceSheet);f.players.put(holder.core.id,holder.player);f.activate(holder);
|
|
|
|
|
var allySource=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.PLAYER_ATTACK).withCausingEntity(b.player).withDirectEntity(b.player).build();f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(b.player,enemy,org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,allySource,3));f.dispatcher.accept(new org.bukkit.event.entity.EntityDeathEvent(enemy,allySource,new java.util.ArrayList<>(),0));for(int i=0;i<4;i++)PartyBookNativeTest.drain(f);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");assertEquals(BigInteger.valueOf(5),storage.find(a.core.record.id()).get().orElseThrow().experience());assertEquals(BigInteger.valueOf(5),storage.find(b.core.record.id()).get().orElseThrow().experience());}}
|
|
|
|
|
@Test void normalSelfOrdinaryOutOfRangeAndObstructedTargetsRefuseBeforeCooldown()throws Exception{for(int route=0;route<4;route++){var dir=data.resolve("refuse-"+route);try(var f=new FantasyStickLifecycleNativeTest.Fixture(dir)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(dir);withInspire(dir,a,true);f.players.put(a.core.id,a.player);f.activate(a);org.bukkit.entity.Player target;if(route==0)target=a.player;else if(route==1){target=mock(org.bukkit.entity.Player.class);when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());}else{var b=new FantasyStickLifecycleNativeTest.Actor(dir);target=b.player;f.players.put(b.core.id,b.player);f.activate(b);}doReturn(false).when(a.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(a.player).getLocation();doReturn(new org.bukkit.Location(a.world,route==2?13:8,64,0)).when(target).getLocation();doReturn(route!=3).when(a.player).hasLineOfSight(target);doReturn(target).when(a.player).getTargetEntity(64);use(f,a);PartyBookNativeTest.drain(f);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");assertFalse(storage.find(a.core.record.id()).get().orElseThrow().cooldowns().containsKey("inspire"));}}}
|
|
|
|
|
@Test void normalSelfOrdinaryOutOfRangeAndObstructedTargetsRefuseBeforeCooldown()throws Exception{for(int route=0;route<4;route++){var dir=data.resolve("refuse-"+route);try(var f=new FantasyStickLifecycleNativeTest.Fixture(dir)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(dir);withInspire(dir,a,true);f.players.put(a.core.id,a.player);f.activate(a);org.bukkit.entity.Player target;if(route==0)target=a.player;else if(route==1){target=mock(org.bukkit.entity.Player.class);when(target.getUniqueId()).thenReturn(java.util.UUID.randomUUID());}else{var b=new FantasyStickLifecycleNativeTest.Actor(dir);target=b.player;f.players.put(b.core.id,b.player);f.activate(b);}doReturn(false).when(a.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(a.player).getLocation();doReturn(new org.bukkit.Location(a.world,route==2?13:8,64,0)).when(target).getLocation();doReturn(route!=3).when(a.player).hasLineOfSight(target);doReturn(target).when(a.player).getTargetEntity(64);use(f,a);PartyBookNativeTest.drain(f);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");assertFalse(storage.find(a.core.record.id()).get().orElseThrow().cooldowns().containsKey("inspire"));}
|
|
|
|
|
var own=inspireEvents(dir);assertEquals(0,count(own,"ability.cast"));assertEquals(0,count(own,"effect.applied"));
|
|
|
|
|
assertEquals("refused",record(own,"ability.resolved").get("outcome").getAsString());
|
|
|
|
|
}}
|
|
|
|
|
@Test void nonPartyTargetIsAllowedAndStrongestRemainingCopiesPreserveUnrelatedAbsorption()throws Exception{java.nio.file.Files.writeString(data.resolve("config.yml"),"inspire-cooldown-seconds: 0\n");try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);var c=new FantasyStickLifecycleNativeTest.Actor(data);var b=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);withInspire(data,c,true);f.players.put(a.core.id,a.player);f.players.put(c.core.id,c.player);f.players.put(b.core.id,b.player);f.activate(a);f.activate(c);f.activate(b);var absorption=new java.util.concurrent.atomic.AtomicReference<>(2.0);doAnswer(x->absorption.get()).when(b.player).getAbsorptionAmount();doAnswer(x->{absorption.set(x.getArgument(0));return null;}).when(b.player).setAbsorptionAmount(anyDouble());for(var caster:List.of(a,c)){doReturn(false).when(caster.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(caster.player).getLocation();doReturn(true).when(caster.player).hasLineOfSight(b.player);doReturn(b.player).when(caster.player).getTargetEntity(64);}doReturn(new org.bukkit.Location(a.world,8,64,0)).when(b.player).getLocation();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(7,absorption.get(),1e-9);var sender=new EquipmentAdminCommandNativeTest.Sender();f.command.execute(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health","6"});var response=f.tasks.poll(5,java.util.concurrent.TimeUnit.SECONDS);assertNotNull(response);response.run();use(f,c);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(9,absorption.get(),1e-9);
|
|
|
|
|
var enemy=mock(org.bukkit.entity.Zombie.class);when(enemy.getUniqueId()).thenReturn(java.util.UUID.randomUUID());var source=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK).withCausingEntity(enemy).withDirectEntity(enemy).build();f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,b.player,org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3));absorption.set(6.0);PartyBookNativeTest.drain(f);f.delayed.getLast().run();assertEquals(4,absorption.get(),1e-9);f.delayed.getFirst().run();assertEquals(2,absorption.get(),1e-9);}}
|
|
|
|
|
var enemy=mock(org.bukkit.entity.Zombie.class);when(enemy.getUniqueId()).thenReturn(java.util.UUID.randomUUID());var source=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK).withCausingEntity(enemy).withDirectEntity(enemy).build();f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,b.player,org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,source,3));absorption.set(6.0);PartyBookNativeTest.drain(f);f.delayed.getLast().run();assertEquals(4,absorption.get(),1e-9);f.delayed.getFirst().run();assertEquals(2,absorption.get(),1e-9);}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(2,count(own,"ability.cast"));assertEquals(2,count(own,"effect.applied"));
|
|
|
|
|
assertEquals(1,count(own,"combat.prevented"));assertEquals(2,count(own,"effect.ended"));
|
|
|
|
|
var applied=own.stream().filter(event->event.get("type").getAsString().endsWith("effect.applied")).toList();
|
|
|
|
|
var prevented=record(own,"combat.prevented");
|
|
|
|
|
assertEquals(applied.getLast().getAsJsonObject("data").get("application_id").getAsString(),
|
|
|
|
|
prevented.get("effect_application_id").getAsString(),"strongest accepted grant owns observed absorption");
|
|
|
|
|
assertEquals("7",applied.getLast().getAsJsonObject("data").get("granted_amount").getAsString());
|
|
|
|
|
}
|
|
|
|
|
@Test void cancelledOrSelfOnlyProtectionCannotManufactureSupportShare()throws Exception{for(int route=0;route<2;route++){var dir=data.resolve("no-support-"+route);try(var f=new FantasyStickLifecycleNativeTest.Fixture(dir)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(dir);var b=new FantasyStickLifecycleNativeTest.Actor(dir);withInspire(dir,a,true);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()));var target=route==0?b.player:a.player;var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);doAnswer(x->absorption.get()).when(target).getAbsorptionAmount();doAnswer(x->{absorption.set(x.getArgument(0));return null;}).when(target).setAbsorptionAmount(anyDouble());doReturn(route==1).when(a.player).isSneaking();doReturn(new org.bukkit.Location(a.world,0,64,0)).when(a.player).getLocation();doReturn(new org.bukkit.Location(a.world,8,64,0)).when(b.player).getLocation();doReturn(true).when(a.player).hasLineOfSight(b.player);doReturn(b.player).when(a.player).getTargetEntity(64);use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);var enemy=mock(org.bukkit.entity.LivingEntity.class);when(enemy.getUniqueId()).thenReturn(java.util.UUID.randomUUID());when(enemy.getType()).thenReturn(org.bukkit.entity.EntityType.ZOMBIE);when(enemy.getLocation()).thenReturn(new org.bukkit.Location(a.world,8,64,0));when(a.world.getUID()).thenReturn(java.util.UUID.randomUUID());var enemySource=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.MOB_ATTACK).withCausingEntity(enemy).withDirectEntity(enemy).build();var hit=new org.bukkit.event.entity.EntityDamageByEntityEvent(enemy,target,org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,enemySource,3);if(route==0)hit.setCancelled(true);f.dispatcher.accept(hit);if(route==1){absorption.set(2.0);PartyBookNativeTest.drain(f);}var allySource=org.bukkit.damage.DamageSource.builder(org.bukkit.damage.DamageType.PLAYER_ATTACK).withCausingEntity(b.player).withDirectEntity(b.player).build();f.dispatcher.accept(new org.bukkit.event.entity.EntityDamageByEntityEvent(b.player,enemy,org.bukkit.event.entity.EntityDamageEvent.DamageCause.ENTITY_ATTACK,allySource,3));f.dispatcher.accept(new org.bukkit.event.entity.EntityDeathEvent(enemy,allySource,new java.util.ArrayList<>(),0));for(int i=0;i<4;i++)PartyBookNativeTest.drain(f);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");assertEquals(BigInteger.valueOf(5),storage.find(a.core.record.id()).get().orElseThrow().experience());assertEquals(BigInteger.valueOf(5),storage.find(b.core.record.id()).get().orElseThrow().experience());}}}
|
|
|
|
|
@Test void exactFormulaSupportsFiniteUncappedCharisma(){assertEquals(BigInteger.valueOf(5),games.dmg.fantasystick.ability.Inspire.amount(BigInteger.valueOf(12)));assertEquals(BigInteger.valueOf(3),games.dmg.fantasystick.ability.Inspire.amount(BigInteger.valueOf(9)));var huge=BigInteger.TEN.pow(500);assertEquals(huge.subtract(BigInteger.TEN).divide(BigInteger.TWO).add(BigInteger.valueOf(4)),games.dmg.fantasystick.ability.Inspire.amount(huge));}
|
|
|
|
|
@Test void failedCooldownPersistencePublishesNoTemporaryHealth(){var storage=mock(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 temporary=new games.dmg.fantasystick.ability.TemporaryHealth(sessions,parties,Runnable::run,ignored->{});var inspire=new games.dmg.fantasystick.ability.Inspire(games.dmg.fantasystick.ability.Inspire.Settings.defaults(),temporary);var registry=new games.dmg.fantasystick.ability.AbilityRegistry();registry.register(inspire.definition());var base=new games.dmg.fantasystick.crafting.CharacterFactory().create(games.dmg.fantasystick.progression.ProgressionRules.defaults());var stats=new EnumMap<>(base.stats());stats.put(Stat.CHR,BigInteger.valueOf(12));stats.put(Stat.WIS,BigInteger.TEN);var record=new CharacterRecord(base.id(),base.name(),base.revision(),stats,base.level(),base.experience(),base.unspentPoints(),base.health(),Set.of("inspire"),List.of("inspire","","","","","",""),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);when(player.getUniqueId()).thenReturn(active.player());when(player.isSneaking()).thenReturn(true);when(sessions.active(active.player())).thenReturn(java.util.Optional.of(active));when(sessions.current(active)).thenReturn(true);when(sessions.currentRecord(active)).thenReturn(java.util.Optional.of(record));var failed=new java.util.concurrent.CompletableFuture<CharacterStorage.AbilityMutation>();failed.completeExceptionally(new java.io.IOException("simulated"));when(storage.commitAbilityCooldown(eq(record.id()),eq(record.revision()),eq("inspire"),any())).thenReturn(failed);var engine=new games.dmg.fantasystick.ability.AbilityEngine(registry,storage,sessions,parties,java.time.Clock.systemUTC(),Runnable::run,(delay,action)->()->{},ignored->{},ignored->{});engine.accept(new games.dmg.fantasystick.session.ControlInput(player,active,2,"inspire",games.dmg.fantasystick.session.ControlInput.Kind.ABILITY,games.dmg.fantasystick.session.ControlInput.Gesture.USE,player,0,0,()->true));verify(storage).commitAbilityCooldown(eq(record.id()),eq(record.revision()),eq("inspire"),any());verify(player,never()).setAbsorptionAmount(anyDouble());engine.close();inspire.close();temporary.close();parties.close();}
|
|
|
|
|
@Test void unlearnRelearnAndTransferRetainCooldownAndClearOnlyOwnedTemporaryHealth()throws Exception{java.nio.file.Files.writeString(data.resolve("config.yml"),"inspire-cooldown-seconds: 60\n");try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);f.players.put(a.core.id,a.player);f.activate(a);var absorption=new java.util.concurrent.atomic.AtomicReference<>(2.0);doAnswer(x->absorption.get()).when(a.player).getAbsorptionAmount();doAnswer(x->{absorption.set(x.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(7,absorption.get(),1e-9);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");var deadline=storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("inspire");a.core.inventory.getInventory().setSelectedSlot(0);PartyBookNativeTest.open(f,a);var unlearn=button(a,"[Unlearn]","inspire");PartyBookNativeTest.click(f,a,unlearn);PartyBookNativeTest.click(f,a,unlearn);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(2,absorption.get(),1e-9);var refunded=storage.find(a.core.record.id()).get().orElseThrow();assertEquals(BigInteger.valueOf(40),refunded.unspentPoints());assertEquals(deadline,refunded.cooldowns().get("inspire"));learnAndAssign(f,a);use(f,a);assertTrue(a.messages.stream().anyMatch(m->m.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);doReturn(true).when(b.player).isSneaking();use(f,b);assertTrue(b.messages.stream().anyMatch(m->m.contains("ready in")));assertEquals(deadline,storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("inspire"));}}
|
|
|
|
|
@Test void unlearnRelearnAndTransferRetainCooldownAndClearOnlyOwnedTemporaryHealth()throws Exception{java.nio.file.Files.writeString(data.resolve("config.yml"),"inspire-cooldown-seconds: 60\n");try(var f=new FantasyStickLifecycleNativeTest.Fixture(data)){f.plugin.setEnabled(true);var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);f.players.put(a.core.id,a.player);f.activate(a);var absorption=new java.util.concurrent.atomic.AtomicReference<>(2.0);doAnswer(x->absorption.get()).when(a.player).getAbsorptionAmount();doAnswer(x->{absorption.set(x.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(7,absorption.get(),1e-9);var storage=(CharacterStorage)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"characters");var deadline=storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("inspire");a.core.inventory.getInventory().setSelectedSlot(0);PartyBookNativeTest.open(f,a);var unlearn=button(a,"[Unlearn]","inspire");PartyBookNativeTest.click(f,a,unlearn);PartyBookNativeTest.click(f,a,unlearn);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(2,absorption.get(),1e-9);var refunded=storage.find(a.core.record.id()).get().orElseThrow();assertEquals(BigInteger.valueOf(40),refunded.unspentPoints());assertEquals(deadline,refunded.cooldowns().get("inspire"));learnAndAssign(f,a);use(f,a);assertTrue(a.messages.stream().anyMatch(m->m.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);doReturn(true).when(b.player).isSneaking();use(f,b);assertTrue(b.messages.stream().anyMatch(m->m.contains("ready in")));assertEquals(deadline,storage.find(a.core.record.id()).get().orElseThrow().cooldowns().get("inspire"));}
|
|
|
|
|
var own=inspireEvents(data);assertEquals(1,count(own,"ability.cast"));
|
|
|
|
|
assertEquals(1,count(own,"effect.applied"));assertEquals(1,count(own,"effect.ended"));
|
|
|
|
|
assertEquals(0,count(own,"combat.prevented"));
|
|
|
|
|
assertEquals("interrupted",record(own,"effect.ended").get("reason").getAsString());
|
|
|
|
|
assertEquals("5",record(own,"effect.ended").get("remaining_amount").getAsString());
|
|
|
|
|
}
|
|
|
|
|
@Test void configuredDefinitionAdminRestartFutureCastAndStartupValidationCoverEverySetting()throws Exception{java.nio.file.Files.writeString(data.resolve("config.yml"),"inspire-base-temporary-health: 8\ninspire-cooldown-seconds: 0\ninspire-range-blocks: 16\ninspire-duration-seconds: 8\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 d=registry.find("inspire").orElseThrow();assertEquals(java.time.Duration.ZERO,d.cooldown());assertEquals(new java.math.BigDecimal("8"),d.parameters().get("base-temporary-health"));assertEquals(0,new java.math.BigDecimal("16").compareTo(d.parameters().get("range")));assertEquals(0,new java.math.BigDecimal("8").compareTo(d.parameters().get("duration-seconds")));
|
|
|
|
|
var sender=new EquipmentAdminCommandNativeTest.Sender();sender.allowed=false;assertTrue(f.command.tabComplete(sender.port,"fantasystick",new String[]{"config","inspire-"}).isEmpty());f.command.execute(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health","9"});assertTrue(sender.messages.getLast().contains("Permission denied"));sender.allowed=true;assertEquals(List.of("inspire-base-temporary-health","inspire-cooldown-seconds","inspire-duration-seconds","inspire-range-blocks"),f.command.tabComplete(sender.port,"fantasystick",new String[]{"config","inspire-"}));assertEquals(List.of("4","8"),f.command.tabComplete(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health",""}));f.command.execute(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health"});assertTrue(sender.messages.getLast().contains("=8"));f.command.execute(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health","9"});var response=f.tasks.poll(5,java.util.concurrent.TimeUnit.SECONDS);assertNotNull(response);response.run();assertEquals(new java.math.BigDecimal("9"),registry.find("inspire").orElseThrow().parameters().get("base-temporary-health"));
|
|
|
|
|
var a=new FantasyStickLifecycleNativeTest.Actor(data);withInspire(data,a,true);f.players.put(a.core.id,a.player);f.activate(a);var absorption=new java.util.concurrent.atomic.AtomicReference<>(0.0);doAnswer(c->absorption.get()).when(a.player).getAbsorptionAmount();doAnswer(c->{absorption.set(c.getArgument(0));return null;}).when(a.player).setAbsorptionAmount(anyDouble());doReturn(true).when(a.player).isSneaking();use(f,a);PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);assertEquals(10,absorption.get(),1e-9);assertEquals(160L,f.delayedTicks.getLast());
|
|
|
|
|
f.command.execute(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health","-1"});assertTrue(sender.messages.getLast().contains("invalid"));f.command.execute(sender.port,"fantasystick",new String[]{"config","inspire-base-temporary-health","9","extra"});assertTrue(sender.messages.getLast().contains("Usage"));f.plugin.setEnabled(false);f.plugin.setEnabled(true);var reload=(games.dmg.fantasystick.ability.AbilityRegistry)FantasyStickLifecycleNativeTest.Fixture.field(f.plugin,"abilityRegistry");assertEquals(new java.math.BigDecimal("9"),reload.find("inspire").orElseThrow().parameters().get("base-temporary-health"));}
|
|
|
|
|
for(String invalid:List.of("inspire-base-temporary-health: -1\n","inspire-cooldown-seconds: -1\n","inspire-range-blocks: 0\n","inspire-duration-seconds: 0\n")){var dir=data.resolve(Integer.toHexString(invalid.hashCode()));java.nio.file.Files.createDirectories(dir);java.nio.file.Files.writeString(dir.resolve("config.yml"),invalid);try(var f=new FantasyStickLifecycleNativeTest.Fixture(dir)){assertThrows(IllegalArgumentException.class,()->f.plugin.setEnabled(true));assertTrue(f.order.isEmpty());}}}
|
|
|
|
|
private static List<com.google.gson.JsonObject> inspireEvents(Path root)throws Exception{
|
|
|
|
|
var results=new java.util.ArrayList<com.google.gson.JsonObject>();
|
|
|
|
|
try(var days=java.nio.file.Files.list(root.resolve("events"))){
|
|
|
|
|
for(var day:days.filter(path->path.getFileName().toString().matches("\\d{4}-\\d{2}-\\d{2}")).toList())
|
|
|
|
|
try(var segments=java.nio.file.Files.list(day)){
|
|
|
|
|
for(var path:segments.filter(file->file.getFileName().toString().startsWith("events-")
|
|
|
|
|
&&file.getFileName().toString().endsWith(".jsonl")).toList())
|
|
|
|
|
for(var line:java.nio.file.Files.readAllLines(path))
|
|
|
|
|
if(!line.isBlank()){
|
|
|
|
|
var event=com.google.gson.JsonParser.parseString(line).getAsJsonObject();
|
|
|
|
|
var data=event.getAsJsonObject("data");
|
|
|
|
|
if(data!=null&&data.has("ability_id")&&data.get("ability_id").getAsString().equals("inspire"))results.add(event);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
return results;
|
|
|
|
|
}
|
|
|
|
|
private static long count(List<com.google.gson.JsonObject> own,String suffix){return own.stream().filter(event->event.get("type").getAsString().endsWith(suffix)).count();}
|
|
|
|
|
private static com.google.gson.JsonObject record(List<com.google.gson.JsonObject> own,String suffix){return own.stream().filter(event->event.get("type").getAsString().endsWith(suffix)).findFirst().orElseThrow().getAsJsonObject("data");}
|
|
|
|
|
private static void learnAndAssign(FantasyStickLifecycleNativeTest.Fixture f,FantasyStickLifecycleNativeTest.Actor a)throws Exception{a.core.inventory.getInventory().setSelectedSlot(0);PartyBookNativeTest.open(f,a);PartyBookNativeTest.click(f,a,button(a,"[Learn]","inspire"));PartyBookNativeTest.drain(f);PartyBookNativeTest.drain(f);}
|
|
|
|
|
private static void use(FantasyStickLifecycleNativeTest.Fixture f,FantasyStickLifecycleNativeTest.Actor a){a.core.inventory.getInventory().setSelectedSlot(2);f.dispatcher.accept(new PlayerInteractEvent(a.player,org.bukkit.event.block.Action.RIGHT_CLICK_AIR,a.core.inventory.getItem(2),null,org.bukkit.block.BlockFace.SELF,EquipmentSlot.HAND));}
|
|
|
|
|
private static ClickEvent.Custom button(FantasyStickLifecycleNativeTest.Actor a,String label,String ability){var b=org.bukkit.craftbukkit.inventory.CraftItemStack.asNMSCopy(a.books.getLast()).get(net.minecraft.core.component.DataComponents.WRITTEN_BOOK_CONTENT);assertNotNull(b);for(var p:b.pages()){var x=button(p.raw(),label,ability);if(x!=null)return x;}throw new AssertionError("missing action");}
|
|
|
|
|