feat(progress): count creeper explosion encounters
This commit is contained in:
@@ -5,6 +5,7 @@ import games.dmg.creeperfear.aura.CreeperAuraListener;
|
||||
import games.dmg.creeperfear.feedback.ProgressDisplay;
|
||||
import games.dmg.creeperfear.feedback.ProgressFeedback;
|
||||
import games.dmg.creeperfear.listener.CreeperDeathListener;
|
||||
import games.dmg.creeperfear.listener.CreeperExplosionProgressListener;
|
||||
import games.dmg.creeperfear.listener.PlayerSessionListener;
|
||||
import games.dmg.creeperfear.progress.ProgressService;
|
||||
import games.dmg.creeperfear.progress.SqliteProgressRepository;
|
||||
@@ -27,6 +28,8 @@ public final class CreeperFearPlugin extends JavaPlugin {
|
||||
progressFeedback = new ProgressFeedback(this, new ProgressDisplay(auraRules), displayTicks);
|
||||
getServer().getPluginManager().registerEvents(
|
||||
new CreeperDeathListener(progressService, progressFeedback, getLogger()), this);
|
||||
getServer().getPluginManager().registerEvents(
|
||||
new CreeperExplosionProgressListener(progressService, progressFeedback, getLogger()), this);
|
||||
getServer().getPluginManager().registerEvents(
|
||||
new PlayerSessionListener(progressService, getLogger()), this);
|
||||
getServer().getPluginManager().registerEvents(
|
||||
|
||||
@@ -0,0 +1,85 @@
|
||||
package games.dmg.creeperfear.listener;
|
||||
|
||||
import games.dmg.creeperfear.feedback.KillFeedback;
|
||||
import games.dmg.creeperfear.progress.AuraRank;
|
||||
import games.dmg.creeperfear.progress.PlayerProgress;
|
||||
import games.dmg.creeperfear.progress.ProgressService;
|
||||
import java.util.LinkedHashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Function;
|
||||
import java.util.logging.Level;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.entity.Creeper;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.EventPriority;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
|
||||
public final class CreeperExplosionProgressListener implements Listener {
|
||||
private static final int RECENT_AWARD_LIMIT = 4096;
|
||||
|
||||
private final BiFunction<UUID, String, CompletableFuture<PlayerProgress>> recorder;
|
||||
private final Function<UUID, AuraRank> rankLookup;
|
||||
private final KillFeedback feedback;
|
||||
private final Logger logger;
|
||||
private final Map<ExplosionAward, Boolean> recentAwards = new LinkedHashMap<>(128, 0.75f, true) {
|
||||
@Override
|
||||
protected boolean removeEldestEntry(Map.Entry<ExplosionAward, Boolean> eldest) {
|
||||
return size() > RECENT_AWARD_LIMIT;
|
||||
}
|
||||
};
|
||||
|
||||
public CreeperExplosionProgressListener(
|
||||
ProgressService progressService, KillFeedback feedback, Logger logger) {
|
||||
this(
|
||||
progressService::recordCreeperKill,
|
||||
playerId -> progressService.cached(playerId).map(PlayerProgress::rank).orElse(AuraRank.LOCKED),
|
||||
feedback,
|
||||
logger);
|
||||
}
|
||||
|
||||
CreeperExplosionProgressListener(
|
||||
BiFunction<UUID, String, CompletableFuture<PlayerProgress>> recorder,
|
||||
Function<UUID, AuraRank> rankLookup,
|
||||
KillFeedback feedback,
|
||||
Logger logger) {
|
||||
this.recorder = recorder;
|
||||
this.rankLookup = rankLookup;
|
||||
this.feedback = feedback;
|
||||
this.logger = logger;
|
||||
}
|
||||
|
||||
@EventHandler(priority = EventPriority.LOWEST)
|
||||
public void onCreeperExplosionDamage(EntityDamageByEntityEvent event) {
|
||||
if (event.getCause() != DamageCause.ENTITY_EXPLOSION
|
||||
|| !(event.getDamager() instanceof Creeper creeper)
|
||||
|| !(event.getEntity() instanceof Player player)) {
|
||||
return;
|
||||
}
|
||||
UUID playerId = player.getUniqueId();
|
||||
if (!markNew(creeper.getUniqueId(), playerId)) {
|
||||
return;
|
||||
}
|
||||
AuraRank previousRank = rankLookup.apply(playerId);
|
||||
recorder.apply(playerId, player.getName()).whenComplete((progress, failure) -> {
|
||||
if (failure != null) {
|
||||
logger.log(Level.SEVERE,
|
||||
"Could not persist creeper explosion progress for " + playerId, failure);
|
||||
return;
|
||||
}
|
||||
feedback.show(player, previousRank, progress);
|
||||
});
|
||||
}
|
||||
|
||||
private synchronized boolean markNew(UUID creeperId, UUID playerId) {
|
||||
return recentAwards.putIfAbsent(new ExplosionAward(creeperId, playerId), Boolean.TRUE) == null;
|
||||
}
|
||||
|
||||
private record ExplosionAward(UUID creeperId, UUID playerId) {
|
||||
}
|
||||
}
|
||||
+49
@@ -0,0 +1,49 @@
|
||||
package games.dmg.creeperfear.listener;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.times;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import games.dmg.creeperfear.feedback.KillFeedback;
|
||||
import games.dmg.creeperfear.progress.AuraRank;
|
||||
import games.dmg.creeperfear.progress.PlayerProgress;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.logging.Logger;
|
||||
import org.bukkit.entity.Creeper;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.entity.EntityDamageByEntityEvent;
|
||||
import org.bukkit.event.entity.EntityDamageEvent.DamageCause;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class CreeperExplosionProgressListenerTest {
|
||||
@Test
|
||||
void awardsEachHitPlayerOnlyOnceAndShowsNormalKillFeedback() {
|
||||
UUID creeperId = UUID.randomUUID();
|
||||
UUID playerId = UUID.randomUUID();
|
||||
Creeper creeper = mock(Creeper.class);
|
||||
Player player = mock(Player.class);
|
||||
EntityDamageByEntityEvent event = mock(EntityDamageByEntityEvent.class);
|
||||
@SuppressWarnings("unchecked")
|
||||
BiFunction<UUID, String, CompletableFuture<PlayerProgress>> recorder = mock(BiFunction.class);
|
||||
KillFeedback feedback = mock(KillFeedback.class);
|
||||
PlayerProgress progress = new PlayerProgress(playerId, "Player", AuraRank.I, 0);
|
||||
when(event.getCause()).thenReturn(DamageCause.ENTITY_EXPLOSION);
|
||||
when(event.getDamager()).thenReturn(creeper);
|
||||
when(event.getEntity()).thenReturn(player);
|
||||
when(creeper.getUniqueId()).thenReturn(creeperId);
|
||||
when(player.getUniqueId()).thenReturn(playerId);
|
||||
when(player.getName()).thenReturn("Player");
|
||||
when(recorder.apply(playerId, "Player")).thenReturn(CompletableFuture.completedFuture(progress));
|
||||
CreeperExplosionProgressListener listener = new CreeperExplosionProgressListener(
|
||||
recorder, ignored -> AuraRank.LOCKED, feedback, Logger.getAnonymousLogger());
|
||||
|
||||
listener.onCreeperExplosionDamage(event);
|
||||
listener.onCreeperExplosionDamage(event);
|
||||
|
||||
verify(recorder, times(1)).apply(playerId, "Player");
|
||||
verify(feedback).show(player, AuraRank.LOCKED, progress);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user