fix(elytra,chat): make elytra sub-modes report their mode and wire the chat-scope toggle

- ElytraGenerator no longer hardcodes Modes.elytra(): the mode is passed
  through the constructor (canonical (session, pointType, mode) plus two
  convenience overloads); CloseGenerator/MinSpeed/Obstacle/SpeedDemon/
  TimeTrial now declare their own mode, so getMode() is reachable
- Session.ChatType gets next(); ParkourUser gets setChatType(); SettingsMenu
  gains a chat-scope cycle button (slot 15) so LOBBY_ONLY/PLAYERS_ONLY are
  no longer dead branches
- ChatTypeTest covers the cycle order and wrap-around
- TODO.md: PROGRESS-8 records both fixes

checkstyle 0 error / 135 warning, PMD 0, tests 96/0 fail (1 skipped)
This commit is contained in:
loki5512344 2026-10-06 19:57:00 +02:00
parent 02e2947f47
commit 8ff02cff18
Signed by: boba
GPG key ID: 253067914055423B
11 changed files with 122 additions and 17 deletions

View file

@ -2,6 +2,7 @@ package dev.loki.loparkour.elytra.close;
import dev.loki.loparkour.elytra.core.ElytraGenerator;
import dev.loki.loparkour.elytra.section.ElytraPointType;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.session.core.Session;
/**
@ -10,6 +11,6 @@ import dev.loki.loparkour.session.core.Session;
public class CloseGenerator extends ElytraGenerator {
public CloseGenerator(Session session) {
super(session, ElytraPointType.FLAT);
super(session, ElytraPointType.FLAT, Modes.close());
}
}

View file

@ -31,17 +31,23 @@ public class ElytraGenerator extends ParkourGenerator {
private Vector blockSpawn;
private Random random;
protected final ElytraPointType pointType;
private final Mode mode;
private final int radius;
private final Material material;
private final ElytraBoost boost = new ElytraBoost();
public ElytraGenerator(Session session) {
this(session, ElytraPointType.CIRCLE);
this(session, ElytraPointType.CIRCLE, Modes.elytra());
}
protected ElytraGenerator(Session session, ElytraPointType pointType) {
protected ElytraGenerator(Session session, Mode mode) {
this(session, ElytraPointType.CIRCLE, mode);
}
protected ElytraGenerator(Session session, ElytraPointType pointType, Mode mode) {
super(session);
this.pointType = pointType;
this.mode = mode;
this.radius = Config.GENERATION.getInt("elytra.radius", DEFAULT_RADIUS);
this.material = Materials.parseOr(Config.GENERATION.getString("advanced.island.parkour.first-block-material"), Material.WHITE_STAINED_GLASS);
}
@ -133,7 +139,12 @@ public class ElytraGenerator extends ParkourGenerator {
@Override
public Mode getMode() {
return Modes.elytra();
return mode;
}
/** The configured {@code elytra.radius}. Sub-modes build their own geometry on top of the same value. */
protected int radius() {
return radius;
}
public int getElytraScore() {

View file

@ -2,6 +2,7 @@ package dev.loki.loparkour.elytra.minspeed;
import dev.loki.loparkour.config.core.Config;
import dev.loki.loparkour.elytra.core.ElytraGenerator;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.session.core.Session;
import org.bukkit.entity.Player;
@ -19,7 +20,7 @@ public class MinSpeedGenerator extends ElytraGenerator {
private int ticksTooSlow = 0;
public MinSpeedGenerator(Session session) {
super(session);
super(session, Modes.minSpeed());
}
@Override

View file

@ -1,9 +1,9 @@
package dev.loki.loparkour.elytra.obstacle;
import dev.loki.loparkour.config.core.Config;
import dev.loki.loparkour.elytra.core.ElytraGenerator;
import dev.loki.loparkour.elytra.section.ElytraPointType;
import dev.loki.loparkour.elytra.section.ElytraSection;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.session.core.Session;
import org.bukkit.Material;
import org.bukkit.entity.Player;
@ -22,16 +22,13 @@ import java.util.concurrent.ThreadLocalRandom;
*/
public class ObstacleGenerator extends ElytraGenerator {
private static final int DEFAULT_RADIUS = 3;
private static final int OBSTACLE_STEP = 3;
private static final int OBSTACLE_KNOT = 3;
private final Map<Integer, List<Vector>> obstacles = new HashMap<>();
private final int obstacleRadius;
public ObstacleGenerator(Session session) {
super(session);
obstacleRadius = Config.GENERATION.getInt("elytra.radius", DEFAULT_RADIUS);
super(session, Modes.obstacle());
}
@Override
@ -48,7 +45,7 @@ public class ObstacleGenerator extends ElytraGenerator {
private void generateObstacle(int idx, ElytraSection section, int knotIdx) {
final Obstacle obstacle = Obstacle.values()[ThreadLocalRandom.current().nextInt(Obstacle.values().length)];
final List<Vector> points = obstacle.getPoints(section.getKnot(knotIdx), obstacleRadius);
final List<Vector> points = obstacle.getPoints(section.getKnot(knotIdx), radius());
if (points.isEmpty()) {
return;
}

View file

@ -1,6 +1,7 @@
package dev.loki.loparkour.elytra.speeddemon;
import dev.loki.loparkour.elytra.core.ElytraGenerator;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.session.core.Session;
import org.bukkit.entity.Player;
@ -14,7 +15,7 @@ public class SpeedDemonGenerator extends ElytraGenerator {
private double maxSpeed = 0;
public SpeedDemonGenerator(Session session) {
super(session);
super(session, Modes.speedDemon());
}
@Override

View file

@ -2,6 +2,7 @@ package dev.loki.loparkour.elytra.timetrial;
import dev.loki.loparkour.config.core.Config;
import dev.loki.loparkour.elytra.core.ElytraGenerator;
import dev.loki.loparkour.mode.base.Modes;
import dev.loki.loparkour.session.core.Session;
/**
@ -12,7 +13,7 @@ public class TimeTrialGenerator extends ElytraGenerator {
private static final int SCORE = Config.GENERATION.getInt("mode-settings.time-trial.score", 500);
public TimeTrialGenerator(Session session) {
super(session);
super(session, Modes.timeTrial());
}
@Override

View file

@ -8,14 +8,19 @@ import dev.loki.loparkour.player.core.ParkourPlayer;
import dev.loki.loparkour.player.core.ParkourUser;
import dev.loki.loparkour.menu.gui.inventory.InventoryGui;
import dev.loki.loparkour.player.service.UserRegistry;
import dev.loki.loparkour.session.core.Session;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
import org.jetbrains.annotations.NotNull;
import java.util.List;
public class SettingsMenu extends LPMenu {
private static final int ROWS = 3;
private static final int SLOT_PARKOUR_SETTINGS = 11;
private static final int SLOT_LANG = 13;
private static final int SLOT_CHAT = 15;
private static final int SLOT_CLOSE = 22;
@Override
@ -44,7 +49,24 @@ public class SettingsMenu extends LPMenu {
});
}
final ParkourUser user = ParkourUser.getUser(player);
if (ParkourOption.CHAT.mayPerform(player) && user != null) {
gui = gui.setItem(SLOT_CHAT, chatItem(user), e -> {
user.setChatType(user.chatType().next());
open(player);
});
}
gui.setItem(SLOT_CLOSE, closeButton(player), e -> player.closeInventory())
.open(player);
}
/** Scope button — the locale lists its values in {@link Session.ChatType#next()} order. */
private ItemStack chatItem(@NotNull ParkourUser user) {
final String locale = user.locale();
final List<String> values = Locales.getStringList(locale, "settings.chat.values");
final Session.ChatType chatType = user.chatType();
final String label = chatType.ordinal() < values.size() ? values.get(chatType.ordinal()) : chatType.name();
return localeItem(locale, "settings.chat", label);
}
}

View file

@ -113,10 +113,15 @@ public abstract class ParkourUser {
return previousData;
}
public Session.ChatType chatType() {
public @NotNull Session.ChatType chatType() {
return chatType;
}
/** Who this player's messages are routed to while inside a parkour session. */
public void setChatType(@NotNull Session.ChatType chatType) {
this.chatType = chatType;
}
public boolean unregistering() {
return unregistering;
}

View file

@ -161,6 +161,11 @@ public final class Session {
}
public enum ChatType {
LOBBY_ONLY, PLAYERS_ONLY, PUBLIC
LOBBY_ONLY, PLAYERS_ONLY, PUBLIC;
/** Scope the chat button switches to; order matches {@code settings.chat.values} in the locales. */
public ChatType next() {
return values()[(ordinal() + 1) % values().length];
}
}
}

View file

@ -0,0 +1,27 @@
package dev.loki.loparkour.session.core;
import org.junit.jupiter.api.Test;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertSame;
/**
* The chat scope button cycles {@link Session.ChatType}; the locales list their labels in this order.
*/
class ChatTypeTest {
@Test
void cyclesThroughEveryScopeInDeclaredOrder() {
assertSame(Session.ChatType.PLAYERS_ONLY, Session.ChatType.LOBBY_ONLY.next());
assertSame(Session.ChatType.PUBLIC, Session.ChatType.PLAYERS_ONLY.next());
}
@Test
void wrapsBackToTheFirstScope() {
Session.ChatType type = Session.ChatType.PUBLIC;
for (int click = 0; click < Session.ChatType.values().length; click++) {
type = type.next();
}
assertEquals(Session.ChatType.PUBLIC, type);
}
}