refactor: decompose god-classes, add lint gates, restructure packages
- Decompose all 11 god-classes (>200 lines) into facade + collaborators (command/, schematic/, config/, generator/, mode/, papi/, adaptive/, storage/, player/, leaderboard/) — every file is now <=200 lines - Add PMD 7 (report-only) + stricter checkstyle rules (NPath, IllegalCatch, NestedDepth, Whitespace, MissingOverride); fix real bugs found (printStackTrace, resource leaks in ConfigLoader/SQLStatsStorage) - docs/ARCHITECTURE.md: target structure + 'one folder = one purpose' rule - Pilot restructure: command/core|util/, mode/impl/solo|multi|barrier/, hook/papi/resolver/; cross-package classes made public - TODO.md: track warning cleanup (132-138) + restructure progress
This commit is contained in:
parent
1d57972038
commit
81788e71ed
70 changed files with 3428 additions and 1701 deletions
|
|
@ -1,26 +1,13 @@
|
|||
package dev.loki.loparkour.hook.papi;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.api.core.Registry;
|
||||
import dev.loki.loparkour.generator.core.coordinator.ParkourGenerator;
|
||||
import dev.loki.loparkour.leaderboard.core.Leaderboard;
|
||||
import dev.loki.loparkour.leaderboard.model.Score;
|
||||
import dev.loki.loparkour.mode.base.Mode;
|
||||
import dev.loki.loparkour.mode.base.Modes;
|
||||
import dev.loki.loparkour.player.core.ParkourPlayer;
|
||||
import dev.loki.loparkour.player.spectator.ParkourSpectator;
|
||||
import dev.loki.loparkour.player.core.ParkourUser;
|
||||
import me.clip.placeholderapi.expansion.PlaceholderExpansion;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PAPIHook extends PlaceholderExpansion {
|
||||
|
||||
private static final Pattern INFINITE_REGEX = Pattern.compile("(.+)_(\\d+)");
|
||||
private final PlaceholderDispatcher dispatcher = new PlaceholderDispatcher();
|
||||
|
||||
@Override
|
||||
public @NotNull String getIdentifier() {
|
||||
|
|
@ -48,173 +35,7 @@ public class PAPIHook extends PlaceholderExpansion {
|
|||
}
|
||||
|
||||
@Override
|
||||
@SuppressWarnings({"checkstyle:MethodLength", "checkstyle:CyclomaticComplexity"})
|
||||
public String onPlaceholderRequest(Player player, @NotNull String params) {
|
||||
// placeholders that don't require a player
|
||||
switch (params) {
|
||||
case "version", "ver" -> {
|
||||
return LoParkour.getPlugin().getDescription().getVersion();
|
||||
}
|
||||
case "leader", "record_player" -> {
|
||||
Score score = Modes.DEFAULT.getLeaderboard().getScoreAtRank(1);
|
||||
return score != null ? score.name() : "?";
|
||||
}
|
||||
case "leader_score", "record_score", "record" -> {
|
||||
Score score = Modes.DEFAULT.getLeaderboard().getScoreAtRank(1);
|
||||
return score != null ? Integer.toString(score.score()) : "?";
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
|
||||
if (params.contains("player_rank_")) {
|
||||
return getInfiniteScore(params.replace("player_rank_", ""), Score::name);
|
||||
} else if (params.contains("score_rank_")) {
|
||||
return getInfiniteScore(params.replace("score_rank_", ""), Score::score);
|
||||
} else if (params.contains("time_rank_")) {
|
||||
return getInfiniteScore(params.replace("time_rank_", ""), Score::time);
|
||||
} else if (params.contains("difficulty_rank_")) {
|
||||
return getInfiniteScore(params.replace("difficulty_rank_", ""), Score::difficulty);
|
||||
} else if (params.contains("difficulty_string_rank_")) {
|
||||
return getInfiniteScore(params.replace("difficulty_string_rank_", ""),
|
||||
score -> {
|
||||
String diff = score.difficulty();
|
||||
if ("?".equals(diff)) {
|
||||
return parseDifficulty(2.0);
|
||||
}
|
||||
try {
|
||||
return parseDifficulty(Double.parseDouble(diff));
|
||||
} catch (NumberFormatException e) {
|
||||
return parseDifficulty(2.0);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// placeholders that require player
|
||||
if (player == null) {
|
||||
return "player doesn't exist";
|
||||
}
|
||||
|
||||
switch (params) {
|
||||
case "rank" -> {
|
||||
return Integer.toString(Modes.DEFAULT.getLeaderboard().getRank(player.getUniqueId()));
|
||||
}
|
||||
case "highscore", "high_score" -> {
|
||||
return Integer.toString(Modes.DEFAULT.getLeaderboard().get(player.getUniqueId()).score());
|
||||
}
|
||||
case "high_score_time" -> {
|
||||
return Modes.DEFAULT.getLeaderboard().get(player.getUniqueId()).time();
|
||||
}
|
||||
default -> {}
|
||||
}
|
||||
|
||||
ParkourUser user = ParkourUser.getUser(player);
|
||||
ParkourPlayer pp = null;
|
||||
if (user instanceof ParkourPlayer) {
|
||||
pp = (ParkourPlayer) user;
|
||||
} else if (user instanceof ParkourSpectator) {
|
||||
pp = ((ParkourSpectator) user).closest;
|
||||
}
|
||||
|
||||
if (pp != null && pp.session.generator != null) {
|
||||
ParkourGenerator generator = pp.session.generator;
|
||||
switch (params) {
|
||||
case "score", "current_score" -> {
|
||||
return Integer.toString(generator.state.score);
|
||||
}
|
||||
case "time", "current_time" -> {
|
||||
return generator.getFormattedTime();
|
||||
}
|
||||
case "blocklead", "lead" -> {
|
||||
return Integer.toString(pp.blockLead);
|
||||
}
|
||||
case "style" -> {
|
||||
return pp.style;
|
||||
}
|
||||
case "time_pref", "time_preference" -> {
|
||||
return Integer.toString(pp.selectedTime);
|
||||
}
|
||||
case "scoreboard" -> {
|
||||
return pp.showScoreboard.toString();
|
||||
}
|
||||
case "difficulty" -> {
|
||||
return Double.toString(pp.schematicDifficulty);
|
||||
}
|
||||
case "difficulty_string" -> {
|
||||
return parseDifficulty(pp.schematicDifficulty);
|
||||
}
|
||||
default -> {
|
||||
if (params.contains("score_until_")) {
|
||||
String replaced = params.replace("score_until_", "");
|
||||
try {
|
||||
int interval = Integer.parseInt(replaced);
|
||||
if (interval > 0) {
|
||||
return Integer.toString(interval - (generator.state.score % interval));
|
||||
} else {
|
||||
return "0";
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
return dispatcher.dispatch(player, params);
|
||||
}
|
||||
|
||||
private String parseDifficulty(double difficulty) {
|
||||
if (difficulty <= 0.25) {
|
||||
return "easy";
|
||||
} else if (difficulty <= 0.5) {
|
||||
return "medium";
|
||||
} else if (difficulty <= 0.75) {
|
||||
return "hard";
|
||||
} else if (difficulty <= 1) {
|
||||
return "very hard";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
private String getInfiniteScore(String rankData, Function<Score, ?> f) {
|
||||
int rank;
|
||||
Leaderboard leaderboard = null;
|
||||
Matcher matcher = INFINITE_REGEX.matcher(rankData);
|
||||
|
||||
try {
|
||||
// use mode-specific format
|
||||
// x_mode_rank
|
||||
if (matcher.matches()) {
|
||||
String name = matcher.group(1);
|
||||
rank = Integer.parseInt(matcher.group(2));
|
||||
|
||||
Mode mode = Registry.getMode(name);
|
||||
if (mode != null) {
|
||||
leaderboard = mode.getLeaderboard();
|
||||
}
|
||||
// use generic format
|
||||
// x_rank
|
||||
} else {
|
||||
rank = Integer.parseInt(rankData);
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
return "?";
|
||||
}
|
||||
|
||||
if (leaderboard == null) {
|
||||
leaderboard = Modes.DEFAULT.getLeaderboard();
|
||||
}
|
||||
|
||||
if (rank > 0) {
|
||||
Score score = leaderboard.getScoreAtRank(rank);
|
||||
|
||||
if (score == null) {
|
||||
return "?";
|
||||
} else {
|
||||
return String.valueOf(f.apply(score));
|
||||
}
|
||||
} else {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package dev.loki.loparkour.hook.papi;
|
||||
|
||||
import dev.loki.loparkour.hook.papi.resolver.GlobalPlaceholderResolver;
|
||||
import dev.loki.loparkour.hook.papi.resolver.PlayerPlaceholderResolver;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
class PlaceholderDispatcher {
|
||||
|
||||
private final GlobalPlaceholderResolver globalResolver = new GlobalPlaceholderResolver();
|
||||
private final PlayerPlaceholderResolver playerResolver = new PlayerPlaceholderResolver();
|
||||
|
||||
String dispatch(Player player, @NotNull String params) {
|
||||
String resolved = globalResolver.resolve(params);
|
||||
if (resolved != null) {
|
||||
return resolved;
|
||||
}
|
||||
if (player == null) {
|
||||
return "player doesn't exist";
|
||||
}
|
||||
return playerResolver.resolve(player, params);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package dev.loki.loparkour.hook.papi.resolver;
|
||||
|
||||
import dev.loki.loparkour.LoParkour;
|
||||
import dev.loki.loparkour.leaderboard.model.Score;
|
||||
import dev.loki.loparkour.mode.base.Modes;
|
||||
|
||||
public class GlobalPlaceholderResolver {
|
||||
|
||||
private final ScoreRankResolver rankResolver = new ScoreRankResolver();
|
||||
private final PlaceholderFormatters formatters = new PlaceholderFormatters();
|
||||
|
||||
public String resolve(String params) {
|
||||
String value = resolveStatic(params);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
return resolveRanked(params);
|
||||
}
|
||||
|
||||
private String resolveStatic(String params) {
|
||||
switch (params) {
|
||||
case "version", "ver" -> {
|
||||
return LoParkour.getPlugin().getDescription().getVersion();
|
||||
}
|
||||
case "leader", "record_player" -> {
|
||||
Score score = Modes.DEFAULT.getLeaderboard().getScoreAtRank(1);
|
||||
return score != null ? score.name() : "?";
|
||||
}
|
||||
case "leader_score", "record_score", "record" -> {
|
||||
Score score = Modes.DEFAULT.getLeaderboard().getScoreAtRank(1);
|
||||
return score != null ? Integer.toString(score.score()) : "?";
|
||||
}
|
||||
default -> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveRanked(String params) {
|
||||
if (params.contains("player_rank_")) {
|
||||
return rankResolver.resolve(params.replace("player_rank_", ""), Score::name);
|
||||
}
|
||||
if (params.contains("score_rank_")) {
|
||||
return rankResolver.resolve(params.replace("score_rank_", ""), Score::score);
|
||||
}
|
||||
if (params.contains("time_rank_")) {
|
||||
return rankResolver.resolve(params.replace("time_rank_", ""), Score::time);
|
||||
}
|
||||
if (params.contains("difficulty_rank_")) {
|
||||
return rankResolver.resolve(params.replace("difficulty_rank_", ""), Score::difficulty);
|
||||
}
|
||||
if (params.contains("difficulty_string_rank_")) {
|
||||
return rankResolver.resolve(params.replace("difficulty_string_rank_", ""),
|
||||
formatters::difficultyString);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package dev.loki.loparkour.hook.papi.resolver;
|
||||
|
||||
import dev.loki.loparkour.leaderboard.model.Score;
|
||||
|
||||
class PlaceholderFormatters {
|
||||
|
||||
String parseDifficulty(double difficulty) {
|
||||
if (difficulty <= 0.25) {
|
||||
return "easy";
|
||||
} else if (difficulty <= 0.5) {
|
||||
return "medium";
|
||||
} else if (difficulty <= 0.75) {
|
||||
return "hard";
|
||||
} else if (difficulty <= 1) {
|
||||
return "very hard";
|
||||
}
|
||||
return "?";
|
||||
}
|
||||
|
||||
String difficultyString(Score score) {
|
||||
String diff = score.difficulty();
|
||||
if ("?".equals(diff)) {
|
||||
return parseDifficulty(2.0);
|
||||
}
|
||||
try {
|
||||
return parseDifficulty(Double.parseDouble(diff));
|
||||
} catch (NumberFormatException e) {
|
||||
return parseDifficulty(2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package dev.loki.loparkour.hook.papi.resolver;
|
||||
|
||||
import dev.loki.loparkour.mode.base.Modes;
|
||||
import dev.loki.loparkour.player.core.ParkourPlayer;
|
||||
import dev.loki.loparkour.player.core.ParkourUser;
|
||||
import dev.loki.loparkour.player.spectator.ParkourSpectator;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PlayerPlaceholderResolver {
|
||||
|
||||
private final PlaceholderFormatters formatters = new PlaceholderFormatters();
|
||||
|
||||
public String resolve(Player player, String params) {
|
||||
String value = resolveLeaderboard(player, params);
|
||||
if (value != null) {
|
||||
return value;
|
||||
}
|
||||
return resolveSession(player, params);
|
||||
}
|
||||
|
||||
private String resolveLeaderboard(Player player, String params) {
|
||||
switch (params) {
|
||||
case "rank" -> {
|
||||
return Integer.toString(Modes.DEFAULT.getLeaderboard().getRank(player.getUniqueId()));
|
||||
}
|
||||
case "highscore", "high_score" -> {
|
||||
return Integer.toString(Modes.DEFAULT.getLeaderboard().get(player.getUniqueId()).score());
|
||||
}
|
||||
case "high_score_time" -> {
|
||||
return Modes.DEFAULT.getLeaderboard().get(player.getUniqueId()).time();
|
||||
}
|
||||
default -> {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveSession(Player player, String params) {
|
||||
ParkourUser user = ParkourUser.getUser(player);
|
||||
ParkourPlayer pp = extractParkourPlayer(user);
|
||||
if (pp == null || pp.session.generator == null) {
|
||||
return null;
|
||||
}
|
||||
return resolveGenerator(pp, params);
|
||||
}
|
||||
|
||||
private ParkourPlayer extractParkourPlayer(ParkourUser user) {
|
||||
if (user instanceof ParkourPlayer) {
|
||||
return (ParkourPlayer) user;
|
||||
}
|
||||
if (user instanceof ParkourSpectator) {
|
||||
return ((ParkourSpectator) user).closest;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private String resolveGenerator(ParkourPlayer pp, String params) {
|
||||
switch (params) {
|
||||
case "score", "current_score" -> {
|
||||
return Integer.toString(pp.session.generator.state.score);
|
||||
}
|
||||
case "time", "current_time" -> {
|
||||
return pp.session.generator.getFormattedTime();
|
||||
}
|
||||
case "blocklead", "lead" -> {
|
||||
return Integer.toString(pp.blockLead);
|
||||
}
|
||||
case "style" -> {
|
||||
return pp.style;
|
||||
}
|
||||
case "time_pref", "time_preference" -> {
|
||||
return Integer.toString(pp.selectedTime);
|
||||
}
|
||||
case "scoreboard" -> {
|
||||
return pp.showScoreboard.toString();
|
||||
}
|
||||
case "difficulty" -> {
|
||||
return Double.toString(pp.schematicDifficulty);
|
||||
}
|
||||
case "difficulty_string" -> {
|
||||
return formatters.parseDifficulty(pp.schematicDifficulty);
|
||||
}
|
||||
default -> {
|
||||
return resolveScoreUntil(pp, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveScoreUntil(ParkourPlayer pp, String params) {
|
||||
if (!params.contains("score_until_")) {
|
||||
return null;
|
||||
}
|
||||
String replaced = params.replace("score_until_", "");
|
||||
try {
|
||||
int interval = Integer.parseInt(replaced);
|
||||
if (interval > 0) {
|
||||
return Integer.toString(interval - (pp.session.generator.state.score % interval));
|
||||
}
|
||||
return "0";
|
||||
} catch (NumberFormatException e) {
|
||||
return "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,59 @@
|
|||
package dev.loki.loparkour.hook.papi.resolver;
|
||||
|
||||
import dev.loki.loparkour.api.core.Registry;
|
||||
import dev.loki.loparkour.leaderboard.core.Leaderboard;
|
||||
import dev.loki.loparkour.leaderboard.model.Score;
|
||||
import dev.loki.loparkour.mode.base.Mode;
|
||||
import dev.loki.loparkour.mode.base.Modes;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
class ScoreRankResolver {
|
||||
|
||||
private static final Pattern INFINITE_REGEX = Pattern.compile("(.+)_(\\d+)");
|
||||
|
||||
String resolve(String rankData, Function<Score, ?> valueFunction) {
|
||||
Matcher matcher = INFINITE_REGEX.matcher(rankData);
|
||||
if (matcher.matches()) {
|
||||
return resolveModeRank(matcher, valueFunction);
|
||||
}
|
||||
return resolveGenericRank(rankData, valueFunction);
|
||||
}
|
||||
|
||||
private String resolveModeRank(Matcher matcher, Function<Score, ?> valueFunction) {
|
||||
try {
|
||||
int rank = Integer.parseInt(matcher.group(2));
|
||||
String name = matcher.group(1);
|
||||
Leaderboard leaderboard = Modes.DEFAULT.getLeaderboard();
|
||||
Mode mode = Registry.getMode(name);
|
||||
if (mode != null) {
|
||||
leaderboard = mode.getLeaderboard();
|
||||
}
|
||||
return resolveScore(leaderboard, rank, valueFunction);
|
||||
} catch (NumberFormatException e) {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveGenericRank(String rankData, Function<Score, ?> valueFunction) {
|
||||
try {
|
||||
int rank = Integer.parseInt(rankData);
|
||||
return resolveScore(Modes.DEFAULT.getLeaderboard(), rank, valueFunction);
|
||||
} catch (NumberFormatException e) {
|
||||
return "?";
|
||||
}
|
||||
}
|
||||
|
||||
private String resolveScore(Leaderboard leaderboard, int rank, Function<Score, ?> valueFunction) {
|
||||
if (rank <= 0) {
|
||||
return "?";
|
||||
}
|
||||
Score score = leaderboard.getScoreAtRank(rank);
|
||||
if (score == null) {
|
||||
return "?";
|
||||
}
|
||||
return String.valueOf(valueFunction.apply(score));
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue