style: apply spotless (trim whitespace, unused imports)

This commit is contained in:
loki5512344 2026-10-06 13:50:26 +02:00
parent b771cc1c98
commit 4d999c89a8
Signed by: boba
GPG key ID: 253067914055423B
64 changed files with 317 additions and 317 deletions

View file

@ -45,4 +45,4 @@ public class JumpTimingTracker {
lastBlockCache.remove(playerUuid);
lastLandTimeCache.remove(playerUuid);
}
}
}

View file

@ -71,4 +71,4 @@ public class MetricEventCollector {
public void unload(@NotNull UUID playerUuid) {
timingTracker.unload(playerUuid);
}
}
}

View file

@ -97,4 +97,4 @@ public class MetricsCacheStore {
autoSaveTask = null;
}
}
}
}

View file

@ -123,4 +123,4 @@ class CommandRouter {
}
SchematicCommandHandler.handleCreateWithDifficulty(a3, a4, sender, p, player);
}
}
}

View file

@ -187,4 +187,4 @@ class CommandTabCompleter {
final String lower = input.toLowerCase();
return options.stream().filter(s -> s.toLowerCase().startsWith(lower)).toList();
}
}
}

View file

@ -46,4 +46,4 @@ public class LoParkourCommand implements CommandExecutor, TabCompleter {
@NotNull String alias, @NotNull String[] args) {
return CommandTabCompleter.complete(sender, args);
}
}
}

View file

@ -65,4 +65,4 @@ public class JoinCommandExecutor {
Modes.SPECTATOR.create(p, session);
}
}
}
}

View file

@ -24,4 +24,4 @@ public class LeaderboardCommandExecutor {
Menus.SINGLE_LEADERBOARD.open(p, mode, Leaderboard.Sort.SCORE);
}
}
}
}

View file

@ -88,4 +88,4 @@ public class SchematicCommandHandler {
static boolean isValidSchematicName(String name) {
return SchematicHandler.isValidSchematicName(name);
}
}
}

View file

@ -52,4 +52,4 @@ final class SchematicDispatcher {
}
}
}
}
}

View file

@ -92,4 +92,4 @@ final class SchematicHandler {
}
return name.matches("^[a-zA-Z0-9_-]+$");
}
}
}

View file

@ -31,4 +31,4 @@ final class SchematicMessenger {
send(player, Locales.getString(player, "schematic.help.line_docs"));
send(player, "");
}
}
}

View file

@ -54,4 +54,4 @@ final class SchematicWand {
cachedWand = item;
return item;
}
}
}

View file

@ -24,4 +24,4 @@ final class SelectionStore {
updated[index] = loc.clone();
SchematicCommandHandler.SELECTIONS.put(player, updated);
}
}
}

View file

@ -11,4 +11,4 @@ public final class CommandUtil {
public static void send(CommandSender sender, String msg) {
sender.sendMessage(ColorUtil.color(msg));
}
}
}

View file

@ -22,7 +22,7 @@ public enum Config {
public final String fileName;
public final List<String> ignoredSections;
public FileConfiguration fileConfiguration;
private ConfigAccessor accessor;
Config(String fileName, @Nullable List<String> ignoredSections) {
@ -36,7 +36,7 @@ public enum Config {
*/
public static void reload(boolean initialLoad) {
ConfigLoader.reloadAllConfigs(initialLoad);
// Update accessors for all configs
for (final Config config : values()) {
if (config.fileConfiguration != null) {
@ -55,7 +55,7 @@ public enum Config {
if (path == null) {
return;
}
this.fileConfiguration = ConfigLoader.loadConfig(path);
this.accessor = new ConfigAccessor(fileConfiguration, fileName);
}
@ -70,7 +70,7 @@ public enum Config {
}
// Delegate all accessor methods to ConfigAccessor
public boolean isPath(@NotNull String path) {
return accessor != null && accessor.isPath(path);
}
@ -90,7 +90,7 @@ public enum Config {
public int getInt(@NotNull String path) {
return accessor.getInt(path);
}
public int getInt(@NotNull String path, int defaultValue) {
return accessor != null ? accessor.getInt(path, defaultValue) : defaultValue;
}

View file

@ -14,23 +14,23 @@ import java.util.concurrent.ConcurrentHashMap;
* Provides safe access to configuration values with validation.
*/
public class ConfigAccessor {
private final FileConfiguration config;
private final String fileName;
private final Set<String> warnedMissingPaths = ConcurrentHashMap.newKeySet();
public ConfigAccessor(@NotNull FileConfiguration config, @NotNull String fileName) {
this.config = config;
this.fileName = fileName;
}
/**
* Check if path exists in configuration.
*/
public boolean isPath(@NotNull String path) {
return config.isSet(path);
}
/**
* Get raw object value at path.
*/
@ -38,7 +38,7 @@ public class ConfigAccessor {
warnIfMissing(path);
return config.get(path);
}
/**
* Get boolean value at path.
*/
@ -56,7 +56,7 @@ public class ConfigAccessor {
}
return config.getBoolean(path, defaultValue);
}
/**
* Get integer value at path.
*/
@ -64,7 +64,7 @@ public class ConfigAccessor {
warnIfMissing(path);
return config.getInt(path, 0);
}
/**
* Get integer value at path with default.
*/
@ -74,7 +74,7 @@ public class ConfigAccessor {
}
return config.getInt(path, defaultValue);
}
/**
* Get double value at path.
*/
@ -90,7 +90,7 @@ public class ConfigAccessor {
warnIfMissing(path);
return config.getDouble(path, defaultValue);
}
/**
* Get string value at path.
* Forces conversion to String even if YAML parsed as Boolean/Number.
@ -105,7 +105,7 @@ public class ConfigAccessor {
// Force toString() to handle Boolean/Number values
return String.valueOf(value);
}
/**
* Get string list at path.
*/
@ -114,7 +114,7 @@ public class ConfigAccessor {
warnIfMissing(path);
return config.getStringList(path);
}
/**
* Get integer list at path.
*/
@ -123,7 +123,7 @@ public class ConfigAccessor {
warnIfMissing(path);
return config.getIntegerList(path);
}
/**
* Get child keys from configuration section.
*/
@ -133,16 +133,16 @@ public class ConfigAccessor {
warnIfMissing(path);
return new ArrayList<>();
}
final ConfigurationSection section = config.getConfigurationSection(path);
if (section == null) {
return new ArrayList<>();
}
final boolean isDeep = deep.length > 0 && deep[0];
return new ArrayList<>(section.getKeys(isDeep));
}
private void warnIfMissing(@NotNull String path) {
if (isPath(path)) {
return;

View file

@ -69,4 +69,4 @@ public class ConfigUpdater {
return null;
}
}
}
}

View file

@ -13,13 +13,13 @@ import java.time.Duration;
* Manages generator statistics and time formatting.
*/
public class GeneratorStatistics {
private final ParkourGenerator generator;
public GeneratorStatistics(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
/**
* Get formatted time string.
*/
@ -27,7 +27,7 @@ public class GeneratorStatistics {
public String getFormattedTime() {
return getTime("mm:ss.SSS");
}
/**
* Get detailed time string.
*/
@ -35,14 +35,14 @@ public class GeneratorStatistics {
public String getDetailedTime() {
return getTime("HH:mm:ss.SSS");
}
/**
* Register score in leaderboard.
*/
public void registerScore(@NotNull String time, @NotNull String difficulty, int score) {
final Mode mode = generator.getMode();
final Leaderboard leaderboard = mode.getLeaderboard();
for (final ParkourPlayer player : generator.getPlayers()) {
final Score playerScore = new Score(
player.player.getName(),
@ -50,18 +50,18 @@ public class GeneratorStatistics {
difficulty,
score
);
leaderboard.put(player.getUUID(), playerScore);
}
}
/**
* Send fall message to players.
*/
public void sendFallMessage(int record) {
for (final ParkourPlayer player : generator.getPlayers()) {
final String message;
if (generator.state.score > record) {
// New record
message = Locales.getString(player.player, "parkour.fall.new-record")
@ -74,11 +74,11 @@ public class GeneratorStatistics {
.replace("%record%", String.valueOf(record))
.replace("%time%", getFormattedTime());
}
player.player.sendMessage(message);
}
}
@NotNull
private String getTime(@NotNull String format) {
if (generator.state.start == null) {

View file

@ -26,13 +26,13 @@ import java.util.List;
* Coordinates profile management, statistics, and core generation.
*/
public class ParkourGenerator {
public final Session session;
public final Island island;
public final Profile profile;
public final GeneratorState state;
public final GeneratorOption[] generatorOptions;
protected final BlockPlacer placer;
protected final GeneratorLifecycle lifecycle;
public final GeneratorProfileManager profileManager;
@ -40,7 +40,7 @@ public class ParkourGenerator {
// Event listeners for adaptive system integration
private final List<GeneratorEventListener> eventListeners;
public ParkourGenerator(@NotNull Session session, GeneratorOption... generatorOptions) {
this.session = session;
this.generatorOptions = generatorOptions;
@ -68,8 +68,8 @@ public class ParkourGenerator {
profileManager.overrideProfile();
profileManager.calculateChances();
}
// Core generation methods
public void generate() {
placer.generate();
@ -99,52 +99,52 @@ public class ParkourGenerator {
protected void score() {
lifecycle.score();
}
public void reset(boolean regenerate) {
lifecycle.reset(regenerate);
if (regenerate) {
profileManager.overrideProfile();
profileManager.calculateChances();
}
}
// Statistics and scoring
public void registerScore(String time, String difficulty, int score) {
statistics.registerScore(time, difficulty, score);
}
public double getDifficultyScore() {
return profileManager.getDifficultyScore();
}
public String getFormattedTime() {
return statistics.getFormattedTime();
}
public String getDetailedTime() {
return statistics.getDetailedTime();
}
// UI and player management
public void menu(ParkourPlayer player) {
Menus.PARKOUR_SETTINGS.open(player);
public void menu(ParkourPlayer player) {
Menus.PARKOUR_SETTINGS.open(player);
}
public Mode getMode() {
return Modes.DEFAULT;
public Mode getMode() {
return Modes.DEFAULT;
}
@NotNull
public List<ParkourPlayer> getPlayers() {
return session.getPlayers();
@NotNull
public List<ParkourPlayer> getPlayers() {
return session.getPlayers();
}
@NotNull
public List<ParkourSpectator> getSpectators() {
return session.getSpectators();
@NotNull
public List<ParkourSpectator> getSpectators() {
return session.getSpectators();
}
/** Last generated block, or {@code null} if history is empty. */
public @Nullable Block getLatest() {
if (state.history.isEmpty()) {

View file

@ -92,7 +92,7 @@ public class JumpOffsetGenerator {
final Map<Double, Double> distribution = java.util.stream.IntStream.range(-maxOffset, maxOffset + 1)
.boxed()
.collect(Collectors.toMap(
offset -> (double) offset,
offset -> (double) offset,
offset -> Probs.normalpdf(mean, standardDeviation, (double) offset)
));

View file

@ -43,13 +43,13 @@ public class JumpValidator {
if (from == null || to == null) {
return false;
}
// Check if jumping from a bottom slab - adjust limits accordingly
final double heightAdjustment = getSlabHeightAdjustment(from);
return canJumpWithAdjustment(from.toVector(), to.toVector(), heightAdjustment);
}
/**
* Get height adjustment for slab blocks.
* Returns negative value for bottom slabs (player is lower).
@ -71,13 +71,13 @@ public class JumpValidator {
}
return 0.0; // No adjustment for full blocks
}
private boolean canJumpWithAdjustment(@NotNull Vector from, @NotNull Vector to, double heightAdjustment) {
// Null safety check
if (from == null || to == null) {
return false;
}
final double dx = to.getX() - from.getX();
final double dy = to.getY() - from.getY();
final double dz = to.getZ() - from.getZ();
@ -96,7 +96,7 @@ public class JumpValidator {
// Adjust vertical limits based on slab height
double adjustedMaxVerticalUp = maxVerticalUp;
double adjustedMaxVerticalDown = maxVerticalDown;
if (heightAdjustment < 0) {
// Player is lower (bottom slab), reduce upward jump capability
adjustedMaxVerticalUp = maxVerticalUp + heightAdjustment; // Reduce max up jump
@ -107,7 +107,7 @@ public class JumpValidator {
if (dy > adjustedMaxVerticalUp || dy < -adjustedMaxVerticalDown) {
return false;
}
// For upward jumps, reduce max horizontal distance
// Player can't jump as far when jumping up
if (dy > 0) {

View file

@ -122,4 +122,4 @@ public class BlockPlacer {
generator.state.history.add(selectedBlock);
generator.state.generatedBlocks++;
}
}
}

View file

@ -16,13 +16,13 @@ import java.util.List;
* Handles selection of block types and materials for parkour generation.
*/
public class BlockSelector {
private final ParkourGenerator generator;
public BlockSelector(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
private static final int MAX_STYLE_PICKS = 64;
private static final int MAX_SLAB_PICKS = 20;
@ -66,7 +66,7 @@ public class BlockSelector {
}
return false;
}
/**
* Select jump type based on current configuration and probabilities.
*/
@ -76,7 +76,7 @@ public class BlockSelector {
final JumpType[] types = JumpType.values();
return types[(int) (Math.random() * types.length)];
}
/**
* Get a slab material from the current player's style.
*/
@ -87,7 +87,7 @@ public class BlockSelector {
if (style == null) {
return null;
}
// Try to get a slab material from the style multiple times
for (int i = 0; i < MAX_SLAB_PICKS; i++) {
final Material material = style.getNext();
@ -100,7 +100,7 @@ public class BlockSelector {
}
return null;
}
/**
* Check if material is a special block type that affects jump mechanics.
*/
@ -114,7 +114,7 @@ public class BlockSelector {
isTrapdoorMaterial(material) ||
material == Material.LADDER;
}
public boolean isFenceMaterial(@NotNull Material material) {
return material == Material.OAK_FENCE ||
material == Material.BIRCH_FENCE ||
@ -127,7 +127,7 @@ public class BlockSelector {
material == Material.WARPED_FENCE ||
material == Material.NETHER_BRICK_FENCE;
}
public boolean isTrapdoorMaterial(@NotNull Material material) {
return material == Material.OAK_TRAPDOOR ||
material == Material.BIRCH_TRAPDOOR ||

View file

@ -49,4 +49,4 @@ class BlockTargetSelector {
blocks.add(nextBlock);
return blocks;
}
}
}

View file

@ -50,4 +50,4 @@ class BlockWorldPlacer {
generator.state.schematicBlocks.clear();
}
}
}
}

View file

@ -61,4 +61,4 @@ class SchematicBlockPlacer {
}
return true;
}
}
}

View file

@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
/**
* Refactored GeneratorLifecycle using composition pattern.
* Coordinates tick management, player interactions, and visual updates.
*
*
* Responsibilities delegated to:
* - LifecycleTickManager: Tick cycle and periodic operations
* - PlayerInteractionHandler: Block interactions and scoring
@ -23,7 +23,7 @@ public class GeneratorLifecycle {
private final LifecycleVisualUpdater visualUpdater;
private final LifecycleEventManager eventManager;
private final GeneratorCleanup cleanup;
public GeneratorLifecycle(@NotNull ParkourGenerator generator) {
this.eventManager = new LifecycleEventManager(generator);
this.cleanup = new GeneratorCleanup(generator);
@ -31,14 +31,14 @@ public class GeneratorLifecycle {
this.tickManager = new LifecycleTickManager(generator, cleanup, visualUpdater);
this.interactionHandler = new PlayerInteractionHandler(generator, eventManager, cleanup);
}
/**
* Start the tick cycle.
*/
public void startTick() {
tickManager.startTick();
}
/**
* Main tick method called every server tick.
*/
@ -46,21 +46,21 @@ public class GeneratorLifecycle {
tickManager.tick();
interactionHandler.checkAllPlayers();
}
/**
* Handle player scoring.
*/
public void score() {
interactionHandler.handleScore();
}
/**
* Handle player falling.
*/
public void fall() {
interactionHandler.handleFall();
}
/**
* Reset the lifecycle state.
*/

View file

@ -19,13 +19,13 @@ import java.util.Map;
* Manages lifecycle events for parkour generator.
*/
public class LifecycleEventManager {
private final ParkourGenerator generator;
public LifecycleEventManager(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
/**
* Handle score event and check rewards.
*/
@ -35,11 +35,11 @@ public class LifecycleEventManager {
final ParkourScoreEvent scoreEvent = new ParkourScoreEvent(player);
Bukkit.getPluginManager().callEvent(scoreEvent);
}
// Check for rewards
checkRewards();
}
/**
* Handle fall event.
*/
@ -49,18 +49,18 @@ public class LifecycleEventManager {
final ParkourFallEvent fallEvent = new ParkourFallEvent(player);
Bukkit.getPluginManager().callEvent(fallEvent);
}
// Process fall logic
processFall();
}
private void checkRewards() {
if (!Rewards.REWARDS_ENABLED) {
return;
}
final Mode mode = generator.getMode();
for (final ParkourPlayer player : generator.getPlayers()) {
final int score = generator.state.score;
applyScoreRewards(player, mode, score);
@ -68,7 +68,7 @@ public class LifecycleEventManager {
applyOneTimeRewards(player, mode, score);
}
}
private void applyScoreRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
if (!Rewards.SCORE_REWARDS.containsKey(score)) {
return;
@ -77,7 +77,7 @@ public class LifecycleEventManager {
reward.execute(player, mode);
}
}
private void applyIntervalRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
for (final Map.Entry<Integer, List<Reward>> entry : Rewards.INTERVAL_REWARDS.entrySet()) {
if (score > 0 && score % entry.getKey() == 0) {
@ -87,7 +87,7 @@ public class LifecycleEventManager {
}
}
}
private void applyOneTimeRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
if (!Rewards.ONE_TIME_REWARDS.containsKey(score)) {
return;
@ -105,7 +105,7 @@ public class LifecycleEventManager {
player.collectedRewards.add(rewardKey);
player.save(false);
}
private void processFall() {
// Record statistics
final int score = generator.state.score;

View file

@ -10,18 +10,18 @@ import org.jetbrains.annotations.NotNull;
* Manages tick cycle and periodic operations for generator lifecycle.
*/
public class LifecycleTickManager {
private static final int TIME_UI_INTERVAL = 20; // 1 second — time display tick
private static final int GENERATION_LEAD = 2; // keep only 2 blocks ahead, generate more when player approaches end
private static final int FALL_THRESHOLD_OFFSET = 30;
private static final int MAX_GENERATE_PER_TICK = 5;
private final ParkourGenerator generator;
private final GeneratorCleanup cleanup;
private final LifecycleVisualUpdater visualUpdater;
private int tickCounter = 0;
public LifecycleTickManager(
@NotNull ParkourGenerator generator,
@NotNull GeneratorCleanup cleanup,
@ -30,7 +30,7 @@ public class LifecycleTickManager {
this.cleanup = cleanup;
this.visualUpdater = visualUpdater;
}
/**
* Start the tick cycle.
*/
@ -40,7 +40,7 @@ public class LifecycleTickManager {
// Generate initial blocks ahead of the player
generator.generate(2);
}
/**
* Main tick method called every server tick.
*/
@ -83,14 +83,14 @@ public class LifecycleTickManager {
}
}
}
/**
* Reset tick counter.
*/
public void reset() {
tickCounter = 0;
}
private void maintainBlockLead() {
final int currentBlocks = generator.state.generatedBlocks;
final int targetBlocks = generator.state.score + generationLead();

View file

@ -8,13 +8,13 @@ import org.jetbrains.annotations.NotNull;
* Manages visual updates for players during parkour lifecycle.
*/
public class LifecycleVisualUpdater {
private final ParkourGenerator generator;
public LifecycleVisualUpdater(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
/**
* Update visuals for all players.
*/
@ -23,7 +23,7 @@ public class LifecycleVisualUpdater {
updatePlayerVisuals(player);
}
}
/**
* Update time displays for all players.
*/
@ -32,17 +32,17 @@ public class LifecycleVisualUpdater {
updatePlayerTimeDisplay(player);
}
}
private void updatePlayerVisuals(@NotNull ParkourPlayer player) {
// Update scoreboard if enabled
if (player.showScoreboard != null && player.showScoreboard) {
player.updateScoreboard(generator);
}
// Update action bar with time and score
updatePlayerTimeDisplay(player);
}
@SuppressWarnings("unused") // reserved for action bar
private void updatePlayerTimeDisplay(@NotNull ParkourPlayer player) {
// Placeholder for action bar (Paper adventure); scoreboard already shows time/score.

View file

@ -21,11 +21,11 @@ public class GeneratorCleanup {
private static final int FIRST_BLOCK_OFFSET = 6;
private final ParkourGenerator generator;
public GeneratorCleanup(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
/**
* Remove only trail blocks <strong>behind</strong> players (oldest indices).
* Distance-based cleanup was removing blocks ahead of the player and breaking scoring.
@ -91,7 +91,7 @@ public class GeneratorCleanup {
final Block below = loc.subtract(0, 1, 0).getBlock();
return below.getType() != Material.AIR ? below : null;
}
/**
* Remove schematic blocks once the player completes them.
* The end block is kept in history so the landing player can score it.
@ -116,20 +116,20 @@ public class GeneratorCleanup {
generator.state.history.removeIf(remove::contains);
generator.state.schematicBlocks = null;
}
/**
* Reset generator state and clean up all blocks.
*/
public void reset(boolean regenerate) {
clearBlocks(generator.state.history);
clearSchematicBlocks();
// Reset state
generator.state.history.clear();
generator.state.generatedBlocks = 0;
generator.state.score = 0;
generator.state.start = null;
if (regenerate) {
regenerateFirstBlock();
}
@ -172,5 +172,5 @@ public class GeneratorCleanup {
default -> {}
}
}
}

View file

@ -18,14 +18,14 @@ import java.util.List;
* Handles player interactions with parkour blocks.
*/
public class PlayerInteractionHandler {
private static final int GENERATION_LEAD = 5;
private static final double BLOCK_CENTER_XZ_OFFSET = 0.5;
private final ParkourGenerator generator;
private final LifecycleEventManager eventManager;
private final GeneratorCleanup cleanup;
public PlayerInteractionHandler(
@NotNull ParkourGenerator generator,
@NotNull LifecycleEventManager eventManager,
@ -34,7 +34,7 @@ public class PlayerInteractionHandler {
this.eventManager = eventManager;
this.cleanup = cleanup;
}
/**
* Check all players for block interactions.
*/
@ -61,7 +61,7 @@ public class PlayerInteractionHandler {
}
return false;
}
/**
* Handle player scoring on a block.
*/
@ -88,7 +88,7 @@ public class PlayerInteractionHandler {
// Block generation is handled by LifecycleTickManager.maintainBlockLead()
// to avoid runaway generation in multiplayer (N players = N generates per tick otherwise).
}
/**
* Handle player falling.
*/
@ -108,7 +108,7 @@ public class PlayerInteractionHandler {
}
AdaptiveServices.refreshGeneratorDifficulty(generator);
}
private void handleBlockInteraction(@NotNull ParkourPlayer player, @NotNull Block block) {
// Check if it's a schematic end block
if (isSchematicEndBlock(block)) {
@ -130,14 +130,14 @@ public class PlayerInteractionHandler {
return generator.state.schematicBlocks != null
&& historyContains(generator.state.schematicBlocks, block);
}
private void handleSchematicEndBlock() {
cleanup.removeSchematicBlocks();
// Continue normal generation
generator.generate(GENERATION_LEAD);
}
private boolean isSchematicEndBlock(@NotNull Block block) {
final List<Block> schematicBlocks = generator.state.schematicBlocks;
if (schematicBlocks == null || schematicBlocks.isEmpty()) {
@ -147,7 +147,7 @@ public class PlayerInteractionHandler {
final Block last = schematicBlocks.get(schematicBlocks.size() - 1);
return isSameBlock(block, last);
}
/** Block directly under feet; {@code null} in air — scoring runs when landed. */
@Nullable
private Block getBlockBelow(@NotNull ParkourPlayer player) {

View file

@ -38,4 +38,4 @@ public class PAPIHook extends PlaceholderExpansion {
public String onPlaceholderRequest(Player player, @NotNull String params) {
return dispatcher.dispatch(player, params);
}
}
}

View file

@ -20,4 +20,4 @@ class PlaceholderDispatcher {
}
return playerResolver.resolve(player, params);
}
}
}

View file

@ -55,4 +55,4 @@ public class GlobalPlaceholderResolver {
}
return null;
}
}
}

View file

@ -32,4 +32,4 @@ class PlaceholderFormatters {
return parseDifficulty(2.0);
}
}
}
}

View file

@ -101,4 +101,4 @@ public class PlayerPlaceholderResolver {
return "0";
}
}
}
}

View file

@ -53,4 +53,4 @@ class ScoreRankResolver {
}
return String.valueOf(valueFunction.apply(score));
}
}
}

View file

@ -8,11 +8,11 @@ import org.jetbrains.annotations.NotNull;
*/
public class MenuItem {
private final ItemStack item;
public MenuItem(@NotNull ItemStack item) {
this.item = item;
}
public ItemStack getItem() {
return item;
}

View file

@ -8,11 +8,11 @@ import java.util.function.Consumer;
* Temporary stub for SliderItem during migration
*/
public class SliderItem {
public SliderItem initial(int value) {
return this;
}
public SliderItem add(int index, Item item, Consumer<InventoryClickEvent> handler) {
return this;
}

View file

@ -46,4 +46,4 @@ class BarrierGenerator extends ParkourGenerator {
public Mode getMode() {
return Modes.INVISIBLE_BARRIER;
}
}
}

View file

@ -156,4 +156,4 @@ class BarrierRenderer {
}
}
}
}
}

View file

@ -47,4 +47,4 @@ public class InvisibleBarrierMode implements Mode {
player.closeInventory();
Session.create(session -> new BarrierGenerator(session), null, null, player);
}
}
}

View file

@ -184,4 +184,4 @@ public class ParkourPlayer extends ParkourUser {
public record OptionContainer(ParkourOption option, BiConsumer<ParkourPlayer, String> consumer) {
}
}
}

View file

@ -83,7 +83,7 @@ public abstract class ParkourUser {
if (Boolean.parseBoolean(Option.OPTIONS_DEFAULTS.get(ParkourOption.SCOREBOARD))) {
this.board = Bukkit.getScoreboardManager().getNewScoreboard();
this.scoreboardManager = new ScoreboardManager(player, player.getUniqueId(), board, locale);
final Objective obj = this.board.registerNewObjective("lp_sidebar", "dummy",
ColorUtil.color(Locales.getString(locale, "scoreboard.title")));
obj.setDisplaySlot(DisplaySlot.SIDEBAR);

View file

@ -18,4 +18,4 @@ final class PlayerPersistence {
write.run();
}
}
}
}

View file

@ -28,4 +28,4 @@ final class PlayerScoringTracker {
private static String blockKey(Block block) {
return block.getX() + "," + block.getY() + "," + block.getZ();
}
}
}

View file

@ -31,4 +31,4 @@ final class PlayerSpawnSetup {
void updateHotbar(ParkourPlayer player) {
ParkourHotbar.apply(player);
}
}
}

View file

@ -50,7 +50,7 @@ public class Rewards {
INTERVAL_REWARDS = parseScores("interval-rewards");
ONE_TIME_REWARDS = parseScores("one-time-rewards");
}
/**
* Clear all reward maps to prevent memory leaks on reload
*/

View file

@ -20,17 +20,17 @@ import java.util.function.Function;
* Coordinates player management and state management.
*/
public class Session {
public ParkourGenerator generator;
private final SessionPlayerManager playerManager;
private final SessionStateManager stateManager;
private Session() {
this.playerManager = new SessionPlayerManager(this);
this.stateManager = new SessionStateManager(this);
}
/**
* Create a new session with specified parameters.
*/
@ -40,9 +40,9 @@ public class Session {
Function<Session, Boolean> isAcceptingPlayers,
Function<Session, Boolean> isAcceptingSpectators,
Player... players) {
final Session session = new Session();
// Set acceptance functions
if (isAcceptingPlayers != null) {
session.playerManager.setAcceptingPlayers(isAcceptingPlayers);
@ -50,7 +50,7 @@ public class Session {
if (isAcceptingSpectators != null) {
session.playerManager.setAcceptingSpectators(isAcceptingSpectators);
}
// Add initial players
final List<ParkourPlayer> parkourPlayers = new ArrayList<>();
if (players != null) {
@ -60,97 +60,97 @@ public class Session {
parkourPlayers.add(pp);
}
}
// Initialize session state
session.stateManager.initialize(generatorFunction);
// Update generator settings for players
if (session.generator != null) {
parkourPlayers.forEach(p -> p.updateGeneratorSettings(session.generator));
}
return session;
}
// Visibility management
public void setVisibility(@NotNull Visibility visibility) {
stateManager.setVisibility(visibility);
}
@NotNull
public Visibility getVisibility() {
return stateManager.getVisibility();
}
// Player management
public void addPlayers(@NotNull ParkourPlayer... toAdd) {
playerManager.addPlayers(toAdd);
}
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
playerManager.removePlayers(toRemove);
}
@NotNull
public List<ParkourPlayer> getPlayers() {
return playerManager.getPlayers();
}
// Spectator management
public void addSpectators(@NotNull ParkourSpectator... spectators) {
playerManager.addSpectators(spectators);
}
public void removeSpectators(@NotNull ParkourSpectator... spectators) {
playerManager.removeSpectators(spectators);
}
@NotNull
public List<ParkourSpectator> getSpectators() {
return playerManager.getSpectators();
}
@NotNull
public List<ParkourUser> getUsers() {
return playerManager.getUsers();
}
// State management
public Location getSpawnLocation() {
return stateManager.getSpawnLocation();
}
public void toggleMute(@NotNull ParkourUser user) {
stateManager.toggleMute(user);
}
public boolean isMuted(@NotNull ParkourUser user) {
return stateManager.isMuted(user);
}
// Acceptance checks
public boolean isAcceptingPlayers() {
return playerManager.isAcceptingPlayers();
}
public boolean isAcceptingSpectators() {
return playerManager.isAcceptingSpectators();
}
// Lifecycle
public void onAllPlayersLeft() {
stateManager.cleanup();
}
public void setGenerator(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
// Enums
public enum Visibility {
PRIVATE, ID_ONLY, PUBLIC
}
public enum ChatType {
LOBBY_ONLY, PLAYERS_ONLY, PUBLIC
}

View file

@ -16,46 +16,46 @@ import java.util.function.Function;
* Manages players and spectators in a session.
*/
public class SessionPlayerManager {
private final Session session;
private final List<ParkourPlayer> players = new ArrayList<>();
private final List<ParkourSpectator> spectators = new ArrayList<>();
private Function<Session, Boolean> isAcceptingPlayers = s -> false;
private Function<Session, Boolean> isAcceptingSpectators = s -> s.getVisibility() == Session.Visibility.PUBLIC;
public SessionPlayerManager(@NotNull Session session) {
this.session = session;
}
/**
* Set player acceptance function.
*/
public void setAcceptingPlayers(@NotNull Function<Session, Boolean> function) {
this.isAcceptingPlayers = function;
}
/**
* Set spectator acceptance function.
*/
public void setAcceptingSpectators(@NotNull Function<Session, Boolean> function) {
this.isAcceptingSpectators = function;
}
/**
* Check if session is accepting players.
*/
public boolean isAcceptingPlayers() {
return isAcceptingPlayers.apply(session);
}
/**
* Check if session is accepting spectators.
*/
public boolean isAcceptingSpectators() {
return isAcceptingSpectators.apply(session);
}
/**
* Add players to session.
*/
@ -63,20 +63,20 @@ public class SessionPlayerManager {
players.addAll(Arrays.asList(toAdd));
updateVisibility();
}
/**
* Remove players from session.
*/
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
players.removeAll(Arrays.asList(toRemove));
if (players.isEmpty()) {
session.onAllPlayersLeft();
} else {
updateVisibility();
}
}
/**
* Add spectators to session.
*/
@ -84,7 +84,7 @@ public class SessionPlayerManager {
spectators.addAll(Arrays.asList(toAdd));
updateVisibility();
}
/**
* Remove spectators from session.
*/
@ -92,7 +92,7 @@ public class SessionPlayerManager {
spectators.removeAll(Arrays.asList(toRemove));
updateVisibility();
}
/**
* Get all players.
*/
@ -100,7 +100,7 @@ public class SessionPlayerManager {
public List<ParkourPlayer> getPlayers() {
return new ArrayList<>(players);
}
/**
* Get all spectators.
*/
@ -108,7 +108,7 @@ public class SessionPlayerManager {
public List<ParkourSpectator> getSpectators() {
return new ArrayList<>(spectators);
}
/**
* Get all users (players + spectators).
*/
@ -119,25 +119,25 @@ public class SessionPlayerManager {
users.addAll(spectators);
return users;
}
/**
* Get total user count.
*/
public int getTotalUsers() {
return players.size() + spectators.size();
}
/**
* Check if session has any users.
*/
public boolean hasUsers() {
return !players.isEmpty() || !spectators.isEmpty();
}
private void updateVisibility() {
// Update player visibility for all users
final List<ParkourUser> allUsers = getUsers();
for (final ParkourUser user : allUsers) {
for (final ParkourUser other : allUsers) {
if (!user.equals(other)) {

View file

@ -21,17 +21,17 @@ import java.util.function.Function;
* Manages session state and lifecycle.
*/
public class SessionStateManager {
private final Session session;
private Location spawnLocation;
private Session.Visibility visibility = Session.Visibility.PUBLIC;
private final Map<ParkourUser, Boolean> mutedUsers = new HashMap<>();
private ScheduledTask tickTask = null;
public SessionStateManager(@NotNull Session session) {
this.session = session;
}
/**
* Initialize session with generator and spawn location.
*/
@ -50,7 +50,7 @@ public class SessionStateManager {
// Start tick cycle for generator
startTickCycle();
}
/**
* Clean up session resources.
*/
@ -98,14 +98,14 @@ public class SessionStateManager {
tickTask = null;
}
}
/**
* Set session visibility.
*/
public void setVisibility(@NotNull Session.Visibility visibility) {
this.visibility = visibility;
}
/**
* Get session visibility.
*/
@ -113,7 +113,7 @@ public class SessionStateManager {
public Session.Visibility getVisibility() {
return visibility;
}
/**
* Get spawn location.
*/
@ -121,28 +121,28 @@ public class SessionStateManager {
public Location getSpawnLocation() {
return spawnLocation != null ? spawnLocation.clone() : null;
}
/**
* Toggle mute status for user.
*/
public void toggleMute(@NotNull ParkourUser user) {
mutedUsers.put(user, !isMuted(user));
}
/**
* Check if user is muted.
*/
public boolean isMuted(@NotNull ParkourUser user) {
return mutedUsers.getOrDefault(user, false);
}
/**
* Get muted users count.
*/
public int getMutedUsersCount() {
return (int) mutedUsers.values().stream().filter(muted -> muted).count();
}
/**
* Clear all muted users.
*/

View file

@ -37,21 +37,21 @@ public class SQLDataMapper {
@NotNull
public static Map<UUID, Score> mapScores(@NotNull ResultSet rs) throws SQLException {
final Map<UUID, Score> scores = new HashMap<>();
while (rs.next()) {
final UUID uuid = UUID.fromString(rs.getString("uuid"));
final String name = rs.getString("name");
final int score = rs.getInt("score");
final String time = rs.getString("time");
final String difficulty = rs.getString("difficulty");
final Score scoreObj = new Score(name, time, difficulty, score);
scores.put(uuid, scoreObj);
}
return scores;
}
/**
* Set Score parameters in PreparedStatement.
*/
@ -63,7 +63,7 @@ public class SQLDataMapper {
stmt.setString(DIFFICULTY_PARAM_INDEX, score.difficulty());
stmt.setLong(TIMESTAMP_PARAM_INDEX, System.currentTimeMillis());
}
/**
* Map ResultSet to ParkourPlayer data.
*/
@ -72,17 +72,17 @@ public class SQLDataMapper {
if (!rs.next()) {
return null;
}
final UUID uuid = UUID.fromString(rs.getString("uuid"));
final String name = rs.getString("name");
final String locale = rs.getString("locale");
final String styleName = rs.getString("style");
final String settings = rs.getString("settings");
final long lastSeen = rs.getLong("last_seen");
return new PlayerData(uuid, name, locale, styleName, settings, lastSeen);
}
/**
* Set ParkourPlayer parameters in PreparedStatement.
*/
@ -94,7 +94,7 @@ public class SQLDataMapper {
stmt.setString(SETTINGS_PARAM_INDEX, serializeSettings(player));
stmt.setLong(TIMESTAMP_PARAM_INDEX, System.currentTimeMillis());
}
/**
* Apply player data to ParkourPlayer object.
*/
@ -114,7 +114,7 @@ public class SQLDataMapper {
player.setSettings(new HashMap<>());
}
}
@NotNull
private static String serializeSettings(@NotNull ParkourPlayer player) {
final Map<String, Object> settings = new HashMap<>();
@ -132,7 +132,7 @@ public class SQLDataMapper {
settings.put("sound", player.sound);
return LoParkour.getGson().toJson(settings);
}
private static void deserializeSettings(@NotNull ParkourPlayer player, @NotNull String settings) {
final Type type = new TypeToken<Map<String, Object>>() {}.getType();
final Map<String, Object> parsed = LoParkour.getGson().fromJson(settings, type);
@ -143,7 +143,7 @@ public class SQLDataMapper {
normalizeNumericSettings(parsed);
player.setSettings(parsed);
}
private static void normalizeNumericSettings(@NotNull Map<String, Object> settings) {
for (final Map.Entry<String, Object> entry : settings.entrySet()) {
final Object value = entry.getValue();
@ -155,7 +155,7 @@ public class SQLDataMapper {
}
}
}
/**
* Player data record for mapping.
*/

View file

@ -131,4 +131,4 @@ public class StorageSQL {
}
SQLPlayerRepository.writePlayer(connectionManager, player);
}
}
}

View file

@ -26,7 +26,7 @@ public class SQLQueryBuilder {
)
""", tableName);
}
/**
* Build CREATE TABLE query for players.
*/
@ -43,7 +43,7 @@ public class SQLQueryBuilder {
)
""";
}
/**
* Build SELECT query for scores.
*/
@ -54,7 +54,7 @@ public class SQLQueryBuilder {
tableName
);
}
/**
* Build INSERT/UPDATE query for scores.
*/
@ -71,7 +71,7 @@ public class SQLQueryBuilder {
timestamp = VALUES(timestamp)
""", tableName);
}
/**
* Build SELECT query for player data.
*/
@ -79,7 +79,7 @@ public class SQLQueryBuilder {
public static String selectPlayer() {
return "SELECT uuid, name, locale, style, settings, last_seen FROM players WHERE uuid = ?";
}
/**
* Build INSERT/UPDATE query for player data.
*/
@ -96,7 +96,7 @@ public class SQLQueryBuilder {
last_seen = VALUES(last_seen)
""";
}
/**
* Get table name for specific mode.
*/

View file

@ -65,4 +65,4 @@ public class SQLPlayerRepository {
LOGGER.severe("Failed to write player data: " + e.getMessage());
}
}
}
}

View file

@ -68,4 +68,4 @@ public class SQLScoreRepository {
LOGGER.severe("Failed to write scores for mode " + mode + ": " + e.getMessage());
}
}
}
}

View file

@ -56,4 +56,4 @@ public class SQLSchemaManager {
stmt.executeUpdate();
}
}
}
}

View file

@ -17,7 +17,7 @@ import java.util.function.Function;
public class Item {
private final ItemStack item;
private Consumer<org.bukkit.event.inventory.InventoryClickEvent> clickHandler;
public Item(@NotNull Material material, @NotNull String name) {
this.item = new ItemStack(material);
final ItemMeta meta = item.getItemMeta();
@ -26,7 +26,7 @@ public class Item {
item.setItemMeta(meta);
}
}
public Item lore(@NotNull String... lore) {
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
@ -39,7 +39,7 @@ public class Item {
}
return this;
}
public Item lore(@NotNull List<String> lore) {
final ItemMeta meta = item.getItemMeta();
if (meta != null) {
@ -52,17 +52,17 @@ public class Item {
}
return this;
}
public Item material(@NotNull Material material) {
item.setType(material);
return this;
}
public Item click(@NotNull Consumer<org.bukkit.event.inventory.InventoryClickEvent> handler) {
this.clickHandler = handler;
return this;
}
public Item modifyLore(@NotNull Function<String, String> modifier) {
final ItemMeta meta = item.getItemMeta();
if (meta != null && meta.hasLore()) {
@ -78,7 +78,7 @@ public class Item {
}
return this;
}
public Item modifyName(@NotNull Function<String, String> modifier) {
final ItemMeta meta = item.getItemMeta();
if (meta != null && meta.hasDisplayName()) {
@ -87,12 +87,12 @@ public class Item {
}
return this;
}
public Item meta(@NotNull ItemMeta meta) {
item.setItemMeta(meta);
return this;
}
@Override
@SuppressWarnings("NoClone")
public Item clone() {
@ -101,11 +101,11 @@ public class Item {
cloned.clickHandler = this.clickHandler;
return cloned;
}
public ItemStack build() {
return item;
}
public Consumer<org.bukkit.event.inventory.InventoryClickEvent> getClickHandler() {
return clickHandler;
}

View file

@ -34,7 +34,7 @@ public class Probs {
public static <T> T random(Map<T, Double> chances, Random random) {
final double totalWeight = chances.values().stream().mapToDouble(Double::doubleValue).sum();
final double randomValue = random.nextDouble() * totalWeight;
double currentWeight = 0;
for (final Map.Entry<T, Double> entry : chances.entrySet()) {
currentWeight += entry.getValue();
@ -42,7 +42,7 @@ public class Probs {
return entry.getKey();
}
}
// Fallback to first entry
return chances.keySet().iterator().next();
}

View file

@ -15,62 +15,62 @@ public class ParticleData<T> {
private double offsetX = 0.0;
private double offsetY = 0.0;
private double offsetZ = 0.0;
public ParticleData(@NotNull Particle particle, @Nullable T data, int size) {
this.particle = particle;
this.data = data;
this.size = size;
}
public ParticleData<T> size(int size) {
this.size = size;
return this;
}
public ParticleData<T> speed(double speed) {
this.speed = speed;
return this;
}
public ParticleData<T> offsetX(double offsetX) {
this.offsetX = offsetX;
return this;
}
public ParticleData<T> offsetY(double offsetY) {
this.offsetY = offsetY;
return this;
}
public ParticleData<T> offsetZ(double offsetZ) {
this.offsetZ = offsetZ;
return this;
}
public Particle getParticle() {
return particle;
}
public T getData() {
return data;
}
public int getSize() {
return size;
}
public double getSpeed() {
return speed;
}
public double getOffsetX() {
return offsetX;
}
public double getOffsetY() {
return offsetY;
}
public double getOffsetZ() {
return offsetZ;
}

View file

@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*;
class JumpValidatorTest {
private JumpValidator validator;
@Mock
private World world;
@ -31,7 +31,7 @@ class JumpValidatorTest {
// 1 block forward, same height - always possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 1, 100, 0);
assertTrue(validator.canJump(from, to), "1 block jump at same level should be possible");
}
@ -40,7 +40,7 @@ class JumpValidatorTest {
// 4 blocks forward, same height - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 100, 0);
assertTrue(validator.canJump(from, to), "4 block jump at same level should be possible");
}
@ -49,7 +49,7 @@ class JumpValidatorTest {
// 5 blocks forward, same height - impossible without speed
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 5, 100, 0);
assertFalse(validator.canJump(from, to), "5 block jump at same level should be impossible");
}
@ -58,7 +58,7 @@ class JumpValidatorTest {
// 3 blocks forward, 1 block up - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 3, 101, 0);
assertTrue(validator.canJump(from, to), "3 block jump with 1 up should be possible");
}
@ -67,7 +67,7 @@ class JumpValidatorTest {
// 4 blocks forward, 1 block up - impossible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 101, 0);
assertFalse(validator.canJump(from, to), "4 block jump with 1 up should be impossible");
}
@ -76,7 +76,7 @@ class JumpValidatorTest {
// 4 blocks forward, 1 block down - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 99, 0);
assertTrue(validator.canJump(from, to), "4 block jump with 1 down should be possible");
}
@ -85,7 +85,7 @@ class JumpValidatorTest {
// 4 blocks forward, 2 blocks down - possible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 4, 98, 0);
assertTrue(validator.canJump(from, to), "4 block jump with 2 down should be possible");
}
@ -94,7 +94,7 @@ class JumpValidatorTest {
// 1 block forward, 2 blocks up - impossible (max jump height is 1.25)
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 1, 102, 0);
assertFalse(validator.canJump(from, to), "Jump 2 blocks up should be impossible");
}
@ -112,11 +112,11 @@ class JumpValidatorTest {
void testCanJump_NullLocations() {
// Test null safety
Location validLoc = new Location(world, 0, 100, 0);
assertFalse(validator.canJump((Location)null, validLoc),
assertFalse(validator.canJump((Location)null, validLoc),
"Should return false for null from location");
assertFalse(validator.canJump(validLoc, (Location)null),
assertFalse(validator.canJump(validLoc, (Location)null),
"Should return false for null to location");
assertFalse(validator.canJump((Location)null, (Location)null),
assertFalse(validator.canJump((Location)null, (Location)null),
"Should return false for both null locations");
}
@ -124,7 +124,7 @@ class JumpValidatorTest {
void testCanJump_SameLocation() {
// Jump to same location - should be false
Location loc = new Location(world, 0, 100, 0);
assertFalse(validator.canJump(loc, loc), "Jump to same location should be impossible");
}
@ -133,7 +133,7 @@ class JumpValidatorTest {
// 10 blocks forward - impossible
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 10, 100, 0);
assertFalse(validator.canJump(from, to), "10 block jump should be impossible");
}
@ -144,7 +144,7 @@ class JumpValidatorTest {
// but it documents the expected behavior
Location from = new Location(world, 0, 100, 0);
Location to = new Location(world, 2, 101, 0);
// This should still pass with mock objects (no slab detection)
assertTrue(validator.canJump(from, to), "2 block jump with 1 up should be possible from mock location");
}

View file

@ -29,10 +29,10 @@ class GhostDataTest {
List<GhostFrame> frames = new ArrayList<>();
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
frames.add(new GhostFrame(1000, 1, 100, 0, 90, 0));
UUID uuid = UUID.randomUUID();
GhostData data = new GhostData(uuid, "TestPlayer", 42, frames);
assertEquals("TestPlayer", data.getPlayerName());
assertEquals(uuid, data.getPlayerUuid());
assertEquals(42, data.getScore());
@ -47,21 +47,21 @@ class GhostDataTest {
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
frames.add(new GhostFrame(500, 1, 100, 0, 45, 0));
frames.add(new GhostFrame(1000, 2, 100, 0, 90, 0));
UUID uuid = UUID.randomUUID();
long timestamp = 1_700_000_000_000L;
GhostData original = new GhostData(uuid, "Player1", 100, timestamp, "world", frames);
// Save to file
File file = tempDir.resolve("test.ghost").toFile();
original.saveToFile(file);
assertTrue(file.exists(), "Ghost file should be created");
assertTrue(file.length() > 0, "Ghost file should not be empty");
// Load from file
GhostData loaded = GhostData.loadFromFile(file);
// Verify data
assertEquals(original.getPlayerName(), loaded.getPlayerName());
assertEquals(original.getPlayerUuid(), loaded.getPlayerUuid());
@ -70,12 +70,12 @@ class GhostDataTest {
assertEquals(original.getWorldName(), loaded.getWorldName());
assertEquals("world", loaded.getWorldName());
assertEquals(original.getFrames().size(), loaded.getFrames().size());
// Verify frames
for (int i = 0; i < original.getFrames().size(); i++) {
GhostFrame origFrame = original.getFrames().get(i);
GhostFrame loadedFrame = loaded.getFrames().get(i);
assertEquals(origFrame.getTimestamp(), loadedFrame.getTimestamp());
assertEquals(origFrame.getX(), loadedFrame.getX(), 0.001);
assertEquals(origFrame.getY(), loadedFrame.getY(), 0.001);
@ -90,12 +90,12 @@ class GhostDataTest {
// Test with no frames
UUID uuid = UUID.randomUUID();
GhostData data = new GhostData(uuid, "EmptyPlayer", 0, new ArrayList<>());
File file = tempDir.resolve("empty.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
assertEquals(0, loaded.getFrames().size());
assertEquals("EmptyPlayer", loaded.getPlayerName());
}
@ -114,15 +114,15 @@ class GhostDataTest {
0 // Pitch
));
}
UUID uuid = UUID.randomUUID();
GhostData data = new GhostData(uuid, "LongRunner", 1200, frames);
File file = tempDir.resolve("large.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
assertEquals(1200, loaded.getFrames().size());
assertEquals(1200, loaded.getScore());
}
@ -133,16 +133,16 @@ class GhostDataTest {
UUID uuid = UUID.randomUUID();
GhostData data = new GhostData(
uuid,
"Player_123-ABC",
50,
"Player_123-ABC",
50,
List.of(new GhostFrame(0, 0, 100, 0, 0, 0))
);
File file = tempDir.resolve("special.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
assertEquals("Player_123-ABC", loaded.getPlayerName());
}
@ -152,15 +152,15 @@ class GhostDataTest {
List<GhostFrame> frames = new ArrayList<>();
frames.add(new GhostFrame(0, -100, 50, -200, -90, -45));
frames.add(new GhostFrame(1000, -99, 51, -199, -45, 0));
UUID uuid = UUID.randomUUID();
GhostData data = new GhostData(uuid, "NegativePlayer", 10, frames);
File file = tempDir.resolve("negative.ghost").toFile();
data.saveToFile(file);
GhostData loaded = GhostData.loadFromFile(file);
GhostFrame frame = loaded.getFrames().get(0);
assertEquals(-100, frame.getX(), 0.001);
assertEquals(50, frame.getY(), 0.001);
@ -173,7 +173,7 @@ class GhostDataTest {
void testLoadNonExistentFile() {
// Test loading from non-existent file
File file = new File("nonexistent.ghost");
assertThrows(IOException.class, () -> {
GhostData.loadFromFile(file);
}, "Should throw IOException for non-existent file");
@ -184,15 +184,15 @@ class GhostDataTest {
// Test that frames list is copied (defensive copy)
List<GhostFrame> originalFrames = new ArrayList<>();
originalFrames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
UUID uuid = UUID.randomUUID();
GhostData data = new GhostData(uuid, "Player", 10, originalFrames);
// Modify original list
originalFrames.add(new GhostFrame(1000, 1, 100, 0, 0, 0));
// GhostData should still have only 1 frame
assertEquals(1, data.getFrames().size(),
assertEquals(1, data.getFrames().size(),
"GhostData should create defensive copy of frames list");
}