refactor(player): encapsulate game state behind PlayerSettings, clear VisibilityModifier and HiddenField

- ParkourUser/ParkourPlayer/GeneratorState public mutable fields -> private + short accessors
- per-player settings extracted to player/data/PlayerSettings (ParkourPlayer 188 -> 96 lines,
  PMD-counted methods 20 -> 9); this is what fixed the TooManyMethods violation that the
  encapsulation itself introduced — by decomposition, not by lowering the threshold
- disk storage reads and writes the same canonical 12-key map as the SQL JSON column;
  legacy key names normalized on read, @Expose dropped from domain classes
- 39 settings call sites rewritten across 7 files
- HiddenField backlog cleared (Config, ObstacleGenerator, GhostService, Leaderboard,
  PagedMenu, Reward, ParticleData, World)
- checkstyle ratchet: VisibilityModifier, HiddenField, EmptyLineSeparator and
  MissingDeprecated flipped to error once their counters hit zero; suppressions.xml empty
- javac -Xmaxwarns raised so NullAway/Error Prone counts are honest
  (baseline 165/289, now 164/265)

checkstyle 0 errors / 135 warnings, PMD 0 violations, tests 94/0 fail, ./gradlew check green.
TODO.md: items 30 and 107 updated, new items 167-170, ПРОГРЕСС-6/7 recorded.
This commit is contained in:
loki5512344 2026-10-06 18:57:39 +02:00
parent c120309663
commit 02e2947f47
Signed by: boba
GPG key ID: 253067914055423B
90 changed files with 1103 additions and 660 deletions

View file

@ -26,7 +26,7 @@ public abstract class LPMenu {
protected String locale(@NotNull Player player) {
final var user = dev.loki.loparkour.player.core.ParkourUser.getUser(player);
final String loc = user != null ? user.locale : OptionGeneral.optionsDefaults().get(ParkourOption.LANG);
final String loc = user != null ? user.locale() : OptionGeneral.optionsDefaults().get(ParkourOption.LANG);
return (loc != null && !loc.isBlank()) ? loc : "en";
}

View file

@ -20,26 +20,26 @@ public final class Menus {
}
// main
public static MainMenu MAIN = new MainMenu();
public static final MainMenu MAIN = new MainMenu();
// play
public static PlayMenu PLAY = new PlayMenu();
public static SingleMenu SINGLE = new SingleMenu();
public static SpectatorMenu SPECTATOR = new SpectatorMenu();
public static final PlayMenu PLAY = new PlayMenu();
public static final SingleMenu SINGLE = new SingleMenu();
public static final SpectatorMenu SPECTATOR = new SpectatorMenu();
// community
public static CommunityMenu COMMUNITY = new CommunityMenu();
public static LeaderboardsMenu LEADERBOARDS = new LeaderboardsMenu();
public static SingleLeaderboardMenu SINGLE_LEADERBOARD = new SingleLeaderboardMenu();
public static final CommunityMenu COMMUNITY = new CommunityMenu();
public static final LeaderboardsMenu LEADERBOARDS = new LeaderboardsMenu();
public static final SingleLeaderboardMenu SINGLE_LEADERBOARD = new SingleLeaderboardMenu();
// settings
public static SettingsMenu SETTINGS = new SettingsMenu();
public static LangMenu LANG = new LangMenu();
public static ParkourSettingsMenu PARKOUR_SETTINGS = new ParkourSettingsMenu();
public static final SettingsMenu SETTINGS = new SettingsMenu();
public static final LangMenu LANG = new LangMenu();
public static final ParkourSettingsMenu PARKOUR_SETTINGS = new ParkourSettingsMenu();
// lobby
public static DuelsMenu DUELS = new DuelsMenu();
public static LobbyMenu LOBBY = new LobbyMenu();
public static PlayerManagementMenu PLAYER_MANAGEMENT = new PlayerManagementMenu();
public static final DuelsMenu DUELS = new DuelsMenu();
public static final LobbyMenu LOBBY = new LobbyMenu();
public static final PlayerManagementMenu PLAYER_MANAGEMENT = new PlayerManagementMenu();
}

View file

@ -19,8 +19,8 @@ public class PagedMenu {
this.title = title;
}
public PagedMenu addToDisplay(List<Item> items) {
this.items = items;
public PagedMenu addToDisplay(List<Item> menuItems) {
items = menuItems;
return this;
}

View file

@ -59,7 +59,7 @@ public class DuelsMenu extends LPMenu {
final Session session = sessions.get(i);
final int slot = FIRST_SLOT + (i - startIndex);
gui = gui.setItem(slot, sessionItem(player, session), e -> {
Modes.DUELS.join(player, session);
Modes.duels().join(player, session);
player.closeInventory();
});
}
@ -78,7 +78,7 @@ public class DuelsMenu extends LPMenu {
}
private List<Session> collectOpenSessions() {
final int maxPlayers = Modes.DUELS.getMaxPlayers();
final int maxPlayers = Modes.duels().getMaxPlayers();
final List<Session> sessions = new ArrayList<>();
for (final Session session : Divider.SECTIONS.keySet()) {
if (isOpenForJoining(session, maxPlayers)) {
@ -89,13 +89,13 @@ public class DuelsMenu extends LPMenu {
}
private boolean isOpenForJoining(Session session, int maxPlayers) {
return session.generator instanceof DuelsGenerator generator
&& generator.allowJoining
return session.generator() instanceof DuelsGenerator generator
&& generator.allowJoining()
&& session.getPlayers().size() < maxPlayers;
}
private ItemStack sessionItem(@NotNull Player player, @NotNull Session session) {
final DuelsGenerator generator = (DuelsGenerator) session.generator;
final DuelsGenerator generator = (DuelsGenerator) session.generator();
final ItemStack item = new ItemStack(Material.PLAYER_HEAD);
applySkullOwner(player, item, generator.owner);

View file

@ -30,7 +30,7 @@ public class LobbyMenu extends LPMenu {
return;
}
final String locale = user.locale;
final String locale = user.locale();
final String title = Locales.getString(locale, "lobby.name");
final boolean isHost = !user.session.getPlayers().isEmpty()
@ -60,7 +60,7 @@ public class LobbyMenu extends LPMenu {
}
private ItemStack visibilityItem(ParkourUser user) {
final String locale = user.locale;
final String locale = user.locale();
final List<String> values = Locales.getStringList(locale, "lobby.visibility.values");
final String label = switch (user.session.getVisibility()) {
case PUBLIC -> values.size() > 2 ? values.get(2) : "Public";

View file

@ -9,6 +9,7 @@ import dev.loki.loparkour.player.core.ParkourUser;
import dev.loki.loparkour.session.core.Session;
import dev.loki.loparkour.util.text.ColorUtil;
import dev.loki.loparkour.menu.gui.inventory.InventoryGui;
import dev.loki.loparkour.player.service.UserRegistry;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.event.inventory.ClickType;
@ -29,13 +30,13 @@ public class PlayerManagementMenu extends LPMenu {
@Override
public void open(@NotNull Player player) {
final ParkourPlayer viewer = ParkourPlayer.getPlayer(player);
final ParkourPlayer viewer = UserRegistry.getPlayer(player);
if (viewer == null) {
return;
}
final var session = viewer.session;
final String locale = viewer.locale;
final String locale = viewer.locale();
final String title = Locales.getString(locale, "lobby.player_management.name");
final List<ParkourUser> others = new ArrayList<>();
@ -102,7 +103,7 @@ public class PlayerManagementMenu extends LPMenu {
@NotNull Session session, @NotNull ParkourUser other,
@NotNull ClickType click) {
if (click == ClickType.LEFT) {
Modes.DEFAULT.create(other.player);
Modes.defaultMode().create(other.player);
other.sendTranslated("lobby.player_management.kicked");
viewer.sendTranslated("lobby.player_management.advice");
} else if (click == ClickType.RIGHT) {

View file

@ -48,7 +48,7 @@ public class SpectatorMenu extends LPMenu {
for (int i = startIndex; i < endIndex; i++) {
final Session session = sessions.get(i);
final int slot = FIRST_SLOT + (i - startIndex); // Slots 10-16
gui = gui.setItem(slot, items.get(i), e -> Modes.SPECTATOR.create(player, session));
gui = gui.setItem(slot, items.get(i), e -> Modes.spectator().create(player, session));
}
if (currentPage > 0) {

View file

@ -6,6 +6,7 @@ import dev.loki.loparkour.menu.core.Menus;
import dev.loki.loparkour.player.core.ParkourPlayer;
import dev.loki.loparkour.util.text.ColorUtil;
import dev.loki.loparkour.menu.gui.inventory.InventoryGui;
import dev.loki.loparkour.player.service.UserRegistry;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -30,12 +31,12 @@ public class LangMenu extends LPMenu {
@Override
public void open(@NotNull Player player) {
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final ParkourPlayer pp = UserRegistry.getPlayer(player);
if (pp == null) {
return;
}
final String locale = pp.locale;
final String locale = pp.locale();
final String title = Locales.getString(locale, "settings.lang.name");
final List<String> langs = new ArrayList<>(Locales.getLocaleKeys());
@ -52,7 +53,7 @@ public class LangMenu extends LPMenu {
item.setItemMeta(meta);
}
gui = gui.setItem(FIRST_SLOT + i, item, e -> {
pp.locale = lang;
pp.setLocale(lang);
pp.updateHotbar(); // Update hotbar with new language
Menus.SETTINGS.open(player);
});

View file

@ -10,6 +10,7 @@ import dev.loki.loparkour.player.core.ParkourPlayer;
import dev.loki.loparkour.style.core.Style;
import dev.loki.loparkour.util.text.ColorUtil;
import dev.loki.loparkour.menu.gui.inventory.InventoryGui;
import dev.loki.loparkour.player.service.UserRegistry;
import org.bukkit.Material;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;
@ -47,27 +48,27 @@ public class ParkourSettingsMenu extends LPMenu {
@Override
public void open(@NotNull Player player) {
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final ParkourPlayer pp = UserRegistry.getPlayer(player);
if (pp == null) {
return;
}
final String locale = pp.locale;
final String locale = pp.locale();
final String title = Locales.getString(locale, "settings.name");
baseGui(title, ROWS_MAIN)
.setItem(SLOT_PARTICLES, toggleItem(locale, "particles", pp.particles),
e -> toggleSetting(pp, () -> pp.particles = !pp.particles))
.setItem(SLOT_SOUND, toggleItem(locale, "sound", pp.sound),
e -> toggleSetting(pp, () -> pp.sound = !pp.sound))
.setItem(SLOT_SPECIAL_BLOCKS, toggleItem(locale, "special_blocks", pp.useSpecialBlocks),
.setItem(SLOT_PARTICLES, toggleItem(locale, "particles", pp.settings().particles()),
e -> toggleSetting(pp, () -> pp.settings().setParticles(!pp.settings().particles())))
.setItem(SLOT_SOUND, toggleItem(locale, "sound", pp.settings().sound()),
e -> toggleSetting(pp, () -> pp.settings().setSound(!pp.settings().sound())))
.setItem(SLOT_SPECIAL_BLOCKS, toggleItem(locale, "special_blocks", pp.settings().useSpecialBlocks()),
e -> toggleSpecialBlocks(pp))
.setItem(SLOT_FALL_MESSAGE, toggleItem(locale, "fall_message", pp.showFallMessage),
e -> toggleSetting(pp, () -> pp.showFallMessage = !pp.showFallMessage))
.setItem(SLOT_SCOREBOARD, toggleItem(locale, "scoreboard", pp.showScoreboard),
e -> toggleSetting(pp, () -> pp.showScoreboard = !pp.showScoreboard))
.setItem(SLOT_FALL_MESSAGE, toggleItem(locale, "fall_message", pp.settings().showFallMessage()),
e -> toggleSetting(pp, () -> pp.settings().setShowFallMessage(!pp.settings().showFallMessage())))
.setItem(SLOT_SCOREBOARD, toggleItem(locale, "scoreboard", pp.settings().showScoreboard()),
e -> toggleSetting(pp, () -> pp.settings().setShowScoreboard(!pp.settings().showScoreboard())))
.setItem(SLOT_GHOST_RECORDING, toggleItem(locale, "ghost_recording",
Boolean.TRUE.equals(pp.ghostRecording)), e -> toggleGhostRecording(pp))
Boolean.TRUE.equals(pp.settings().ghostRecording())), e -> toggleGhostRecording(pp))
.setItem(SLOT_STYLE, styleItem(pp), e -> openStyleMenu(pp))
.setItem(SLOT_SCHEM_DIFF, schemDiffItem(pp), e -> cycleSchematicDifficulty(pp))
.setItem(SLOT_CLOSE, closeButton(player), e -> Menus.SETTINGS.open(player))
@ -76,30 +77,30 @@ public class ParkourSettingsMenu extends LPMenu {
private void toggleSetting(ParkourPlayer pp, Runnable update) {
update.run();
pp.updateGeneratorSettings(pp.session.generator);
pp.updateGeneratorSettings(pp.session.generator());
open(pp);
}
private void toggleSpecialBlocks(ParkourPlayer pp) {
if (pp.session.generator.state.score == 0) {
pp.useSpecialBlocks = !pp.useSpecialBlocks;
pp.updateGeneratorSettings(pp.session.generator);
if (pp.session.generator().state.score() == 0) {
pp.settings().setUseSpecialBlocks(!pp.settings().useSpecialBlocks());
pp.updateGeneratorSettings(pp.session.generator());
}
open(pp);
}
private void cycleSchematicDifficulty(ParkourPlayer pp) {
if (pp.session.generator.state.score == 0) {
if (pp.session.generator().state.score() == 0) {
final List<Double> diffs = List.of(0.0, DIFF_QUARTER, DIFF_HALF, DIFF_THREE_QUARTER, 1.0);
final int idx = diffs.indexOf(pp.schematicDifficulty);
pp.schematicDifficulty = diffs.get((idx + 1) % diffs.size());
pp.updateGeneratorSettings(pp.session.generator);
final int idx = diffs.indexOf(pp.settings().schematicDifficulty());
pp.settings().setSchematicDifficulty(diffs.get((idx + 1) % diffs.size()));
pp.updateGeneratorSettings(pp.session.generator());
}
open(pp);
}
private void toggleGhostRecording(ParkourPlayer pp) {
pp.ghostRecording = !Boolean.TRUE.equals(pp.ghostRecording);
pp.settings().setGhostRecording(!Boolean.TRUE.equals(pp.settings().ghostRecording()));
pp.save(false);
open(pp);
}
@ -122,16 +123,16 @@ public class ParkourSettingsMenu extends LPMenu {
private ItemStack schemDiffItem(ParkourPlayer pp) {
final List<Double> diffs = List.of(0.0, DIFF_QUARTER, DIFF_HALF, DIFF_THREE_QUARTER, 1.0);
final List<String> values = Locales.getStringList(pp.locale, "settings.parkour_settings.items.schematics.values");
final int idx = Math.max(0, diffs.indexOf(pp.schematicDifficulty));
final String label = idx < values.size() ? values.get(idx) : String.valueOf(pp.schematicDifficulty);
final List<String> values = Locales.getStringList(pp.locale(), "settings.parkour_settings.items.schematics.values");
final int idx = Math.max(0, diffs.indexOf(pp.settings().schematicDifficulty()));
final String label = idx < values.size() ? values.get(idx) : String.valueOf(pp.settings().schematicDifficulty());
final Material[] mats = {Material.RED_STAINED_GLASS_PANE, Material.LIME_STAINED_GLASS_PANE,
Material.YELLOW_STAINED_GLASS_PANE, Material.ORANGE_STAINED_GLASS_PANE, Material.SKELETON_SKULL};
final ItemStack item = new ItemStack(idx < mats.length ? mats[idx] : Material.PAPER);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
final String name = Locales.getString(pp.locale, "settings.parkour_settings.items.schematics.name");
final String lore = Locales.getString(pp.locale, "settings.parkour_settings.items.schematics.lore");
final String name = Locales.getString(pp.locale(), "settings.parkour_settings.items.schematics.name");
final String lore = Locales.getString(pp.locale(), "settings.parkour_settings.items.schematics.lore");
meta.setDisplayName(ColorUtil.color(name.replace("%s", label)));
applyLore(meta, lore, label);
item.setItemMeta(meta);
@ -140,13 +141,13 @@ public class ParkourSettingsMenu extends LPMenu {
}
private ItemStack styleItem(ParkourPlayer pp) {
final String name = Locales.getString(pp.locale, "settings.parkour_settings.items.styles.item.name");
final String lore = Locales.getString(pp.locale, "settings.parkour_settings.items.styles.item.lore");
final String name = Locales.getString(pp.locale(), "settings.parkour_settings.items.styles.item.name");
final String lore = Locales.getString(pp.locale(), "settings.parkour_settings.items.styles.item.lore");
final ItemStack item = new ItemStack(Material.CRAFTING_TABLE);
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
meta.setDisplayName(ColorUtil.color(name.replace("%s", pp.style)));
applyLore(meta, lore, pp.style);
meta.setDisplayName(ColorUtil.color(name.replace("%s", pp.settings().style())));
applyLore(meta, lore, pp.settings().style());
item.setItemMeta(meta);
}
return item;
@ -165,7 +166,7 @@ public class ParkourSettingsMenu extends LPMenu {
private void openStyleMenu(ParkourPlayer pp) {
final Player player = pp.player;
final String locale = pp.locale;
final String locale = pp.locale();
final String title = Locales.getString(locale, "settings.parkour_settings.styles.name");
InventoryGui gui = baseGui(title, ROWS_STYLE);
@ -187,10 +188,9 @@ public class ParkourSettingsMenu extends LPMenu {
item.setItemMeta(meta);
}
final Style s = style;
gui = gui.setItem(slot++, item, e -> {
pp.style = s.getName();
pp.updateGeneratorSettings(pp.session.generator);
pp.settings().setStyle(style.getName());
pp.updateGeneratorSettings(pp.session.generator());
open(pp);
});
}

View file

@ -7,6 +7,7 @@ import dev.loki.loparkour.menu.core.screen.ParkourOption;
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 org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
@ -24,11 +25,11 @@ public class SettingsMenu extends LPMenu {
InventoryGui gui = baseGui(title, ROWS);
if (ParkourOption.PARKOUR_SETTINGS.mayPerform(player) && ParkourPlayer.isPlayer(player)) {
if (ParkourOption.PARKOUR_SETTINGS.mayPerform(player) && UserRegistry.isPlayer(player)) {
gui = gui.setItem(SLOT_PARKOUR_SETTINGS, localeItem(player, "settings.parkour_settings.item"), e -> {
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final ParkourPlayer pp = UserRegistry.getPlayer(player);
if (pp != null) {
pp.session.generator.menu(pp);
pp.session.generator().menu(pp);
}
});
}
@ -36,7 +37,7 @@ public class SettingsMenu extends LPMenu {
if (ParkourOption.LANG.mayPerform(player) && ParkourUser.isUser(player)) {
final String langName = Locales.getString(locale, "name");
gui = gui.setItem(SLOT_LANG, localeItem(locale, "settings.lang.item", langName), e -> {
final ParkourPlayer pp = ParkourPlayer.getPlayer(player);
final ParkourPlayer pp = UserRegistry.getPlayer(player);
if (pp != null) {
Menus.LANG.open(pp);
}