feat: elytra firework boost, obstacle mode, duels menu, tests

- ElytraBoost: one-shot firework boost (v*0.7+dir*0.6, FIREWORKS_SPARK,
  rocket sounds) on entering ascending section + sustained thrust; Particle.
  FIREWORK doesn't exist in spigot-api 1.20.4 -> FIREWORKS_SPARK
- ObstacleGenerator (client-side obstacles: PILLARS/LINES/HOLE_IN_WALL/
  CIRCLE/DIAMOND via ClientBlockChanger.sendNow) + ObstacleMode + locales
- DuelsMenu (lists open duels sessions, click to join) + /parkour duels
  command + tab completion + locales play.multi.duels.{name,menu_empty}
- Tests: ElytraSection/PointType/KnotDirector/SingleDuelsGenerator (15 new)
- checkstyle 0/0 (main+test), PMD 0, 41 tests pass
This commit is contained in:
loki5512344 2026-08-05 21:49:11 +02:00
parent 5707cf2d24
commit 3b5d3d97d5
Signed by: boba
GPG key ID: 253067914055423B
19 changed files with 804 additions and 28 deletions

View file

@ -0,0 +1,55 @@
package dev.loki.loparkour.elytra.mode;
import dev.loki.loparkour.config.locale.Locales;
import dev.loki.loparkour.elytra.generator.ObstacleGenerator;
import dev.loki.loparkour.leaderboard.core.Leaderboard;
import dev.loki.loparkour.mode.base.Mode;
import dev.loki.loparkour.mode.base.ModeMessages;
import dev.loki.loparkour.player.core.ParkourPlayer;
import dev.loki.loparkour.session.core.Session;
import dev.loki.loparkour.util.item.Item;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
/**
* Elytra mode with client-side obstacles to fly around.
*/
public class ObstacleMode implements Mode {
private final Leaderboard leaderboard = new Leaderboard(getName(), Leaderboard.Sort.SCORE);
@Override
@NotNull
public String getName() {
return "obstacle";
}
@Override
@Nullable
public Item getItem(String locale) {
return Locales.getItem(locale, "play.elytra.obstacle");
}
@Override
@NotNull
public Leaderboard getLeaderboard() {
return leaderboard;
}
@Override
public void create(Player player) {
if (!ModeMessages.checkJoiningEnabled(player)) {
return;
}
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
if (pp != null && pp.session.generator != null && pp.session.generator.getMode() instanceof ObstacleMode) {
return;
}
player.closeInventory();
Session.create(ObstacleGenerator::new, null, null, player);
}
}