feat(notification): announce earned tree unlocks
This commit is contained in:
@@ -0,0 +1,18 @@
|
||||
package games.dmg.treefeller;
|
||||
|
||||
import java.util.List;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/** Delivers one persisted progress update to each presentation observer in order. */
|
||||
public final class CompositeProgressObserver implements ProgressObserver {
|
||||
private final List<ProgressObserver> observers;
|
||||
|
||||
public CompositeProgressObserver(ProgressObserver... observers) {
|
||||
this.observers = List.of(observers);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(Player player, ProgressUpdate update) {
|
||||
observers.forEach(observer -> observer.onProgress(player, update));
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,9 @@ public final class TreeFellerPlugin extends JavaPlugin {
|
||||
playerStateRepository,
|
||||
species -> settingsService.current().threshold(species),
|
||||
automaticBreakRegistry,
|
||||
progressBossBarObserver,
|
||||
new CompositeProgressObserver(
|
||||
progressBossBarObserver,
|
||||
new TreeUnlockAnnouncement(settingsService::current)),
|
||||
exception -> getLogger().log(
|
||||
Level.SEVERE, "Unable to persist Tree Feller progress", exception));
|
||||
getServer().getPluginManager().registerEvents(progressListener, this);
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
package games.dmg.treefeller;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
/** Presents the one-time earned unlock title and safety guidance. */
|
||||
public final class TreeUnlockAnnouncement implements ProgressObserver {
|
||||
private final Supplier<TreeFellerSettings> settings;
|
||||
|
||||
public TreeUnlockAnnouncement(Supplier<TreeFellerSettings> settings) {
|
||||
this.settings = settings;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProgress(Player player, ProgressUpdate update) {
|
||||
if (!update.newlyUnlocked()) {
|
||||
return;
|
||||
}
|
||||
TreeFellerSettings current = settings.get();
|
||||
player.sendTitle(
|
||||
format(current.titleText(), update),
|
||||
format(current.subtitleText(), update),
|
||||
current.titleFadeInTicks(),
|
||||
current.titleStayTicks(),
|
||||
current.titleFadeOutTicks());
|
||||
player.sendMessage(format(current.message("unlock-guidance"), update));
|
||||
}
|
||||
|
||||
private String format(String template, ProgressUpdate update) {
|
||||
return template
|
||||
.replace("{species}", update.species().displayName())
|
||||
.replace("{progress}", Long.toString(update.progress()))
|
||||
.replace("{threshold}", Integer.toString(update.threshold()))
|
||||
.replace('&', '\u00a7');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
package games.dmg.treefeller;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.contains;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
|
||||
import java.io.InputStreamReader;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.configuration.file.YamlConfiguration;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
class TreeUnlockAnnouncementTest {
|
||||
@Test
|
||||
void celebratesANewUnlockAndExplainsSneakingAndUndo() throws Exception {
|
||||
TreeFellerSettings settings = defaults();
|
||||
Player player = mock(Player.class);
|
||||
PlayerTreeFellerState state = PlayerTreeFellerState.initial(UUID.randomUUID(), "Player")
|
||||
.withUnlocked(TreeSpecies.DARK_OAK, true);
|
||||
TreeUnlockAnnouncement announcement = new TreeUnlockAnnouncement(() -> settings);
|
||||
|
||||
announcement.onProgress(player, new ProgressUpdate(
|
||||
state, TreeSpecies.DARK_OAK, 100, 100, true));
|
||||
|
||||
verify(player).sendTitle(
|
||||
"§aDark Oak unlocked!",
|
||||
"§fYou can now fell this tree type.",
|
||||
10,
|
||||
70,
|
||||
20);
|
||||
verify(player).sendMessage(contains("Sneak"));
|
||||
verify(player).sendMessage(contains("/treefeller undo"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void doesNotAnnounceOrdinaryProgressOrAnExistingUnlock() throws Exception {
|
||||
Player player = mock(Player.class);
|
||||
PlayerTreeFellerState state = PlayerTreeFellerState.initial(UUID.randomUUID(), "Player");
|
||||
TreeUnlockAnnouncement announcement = new TreeUnlockAnnouncement(this::uncheckedDefaults);
|
||||
|
||||
announcement.onProgress(player, new ProgressUpdate(
|
||||
state, TreeSpecies.OAK, 5, 100, false));
|
||||
|
||||
verify(player, never()).sendTitle(
|
||||
org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.anyString(),
|
||||
org.mockito.ArgumentMatchers.anyInt(),
|
||||
org.mockito.ArgumentMatchers.anyInt(),
|
||||
org.mockito.ArgumentMatchers.anyInt());
|
||||
verify(player, never()).sendMessage(org.mockito.ArgumentMatchers.anyString());
|
||||
}
|
||||
|
||||
private TreeFellerSettings uncheckedDefaults() {
|
||||
try {
|
||||
return defaults();
|
||||
} catch (Exception exception) {
|
||||
throw new IllegalStateException(exception);
|
||||
}
|
||||
}
|
||||
|
||||
private TreeFellerSettings defaults() throws Exception {
|
||||
try (InputStreamReader reader = new InputStreamReader(
|
||||
getClass().getClassLoader().getResourceAsStream("config.yml"),
|
||||
StandardCharsets.UTF_8)) {
|
||||
return TreeFellerSettings.load(YamlConfiguration.loadConfiguration(reader));
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user