style: apply spotless (trim whitespace, unused imports)
This commit is contained in:
parent
b771cc1c98
commit
4d999c89a8
64 changed files with 317 additions and 317 deletions
|
|
@ -45,4 +45,4 @@ public class JumpTimingTracker {
|
|||
lastBlockCache.remove(playerUuid);
|
||||
lastLandTimeCache.remove(playerUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -71,4 +71,4 @@ public class MetricEventCollector {
|
|||
public void unload(@NotNull UUID playerUuid) {
|
||||
timingTracker.unload(playerUuid);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -97,4 +97,4 @@ public class MetricsCacheStore {
|
|||
autoSaveTask = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -123,4 +123,4 @@ class CommandRouter {
|
|||
}
|
||||
SchematicCommandHandler.handleCreateWithDifficulty(a3, a4, sender, p, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -187,4 +187,4 @@ class CommandTabCompleter {
|
|||
final String lower = input.toLowerCase();
|
||||
return options.stream().filter(s -> s.toLowerCase().startsWith(lower)).toList();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,4 +46,4 @@ public class LoParkourCommand implements CommandExecutor, TabCompleter {
|
|||
@NotNull String alias, @NotNull String[] args) {
|
||||
return CommandTabCompleter.complete(sender, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -65,4 +65,4 @@ public class JoinCommandExecutor {
|
|||
Modes.SPECTATOR.create(p, session);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ public class LeaderboardCommandExecutor {
|
|||
Menus.SINGLE_LEADERBOARD.open(p, mode, Leaderboard.Sort.SCORE);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -88,4 +88,4 @@ public class SchematicCommandHandler {
|
|||
static boolean isValidSchematicName(String name) {
|
||||
return SchematicHandler.isValidSchematicName(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -52,4 +52,4 @@ final class SchematicDispatcher {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -92,4 +92,4 @@ final class SchematicHandler {
|
|||
}
|
||||
return name.matches("^[a-zA-Z0-9_-]+$");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,4 +31,4 @@ final class SchematicMessenger {
|
|||
send(player, Locales.getString(player, "schematic.help.line_docs"));
|
||||
send(player, "");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -54,4 +54,4 @@ final class SchematicWand {
|
|||
cachedWand = item;
|
||||
return item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,4 +24,4 @@ final class SelectionStore {
|
|||
updated[index] = loc.clone();
|
||||
SchematicCommandHandler.SELECTIONS.put(player, updated);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,4 +11,4 @@ public final class CommandUtil {
|
|||
public static void send(CommandSender sender, String msg) {
|
||||
sender.sendMessage(ColorUtil.color(msg));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -69,4 +69,4 @@ public class ConfigUpdater {
|
|||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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()) {
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
));
|
||||
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -122,4 +122,4 @@ public class BlockPlacer {
|
|||
generator.state.history.add(selectedBlock);
|
||||
generator.state.generatedBlocks++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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 ||
|
||||
|
|
|
|||
|
|
@ -49,4 +49,4 @@ class BlockTargetSelector {
|
|||
blocks.add(nextBlock);
|
||||
return blocks;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -50,4 +50,4 @@ class BlockWorldPlacer {
|
|||
generator.state.schematicBlocks.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -61,4 +61,4 @@ class SchematicBlockPlacer {
|
|||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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 -> {}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -38,4 +38,4 @@ public class PAPIHook extends PlaceholderExpansion {
|
|||
public String onPlaceholderRequest(Player player, @NotNull String params) {
|
||||
return dispatcher.dispatch(player, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -20,4 +20,4 @@ class PlaceholderDispatcher {
|
|||
}
|
||||
return playerResolver.resolve(player, params);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,4 +55,4 @@ public class GlobalPlaceholderResolver {
|
|||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -32,4 +32,4 @@ class PlaceholderFormatters {
|
|||
return parseDifficulty(2.0);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -101,4 +101,4 @@ public class PlayerPlaceholderResolver {
|
|||
return "0";
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -53,4 +53,4 @@ class ScoreRankResolver {
|
|||
}
|
||||
return String.valueOf(valueFunction.apply(score));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -46,4 +46,4 @@ class BarrierGenerator extends ParkourGenerator {
|
|||
public Mode getMode() {
|
||||
return Modes.INVISIBLE_BARRIER;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -156,4 +156,4 @@ class BarrierRenderer {
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,4 +47,4 @@ public class InvisibleBarrierMode implements Mode {
|
|||
player.closeInventory();
|
||||
Session.create(session -> new BarrierGenerator(session), null, null, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -184,4 +184,4 @@ public class ParkourPlayer extends ParkourUser {
|
|||
|
||||
public record OptionContainer(ParkourOption option, BiConsumer<ParkourPlayer, String> consumer) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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);
|
||||
|
|
|
|||
|
|
@ -18,4 +18,4 @@ final class PlayerPersistence {
|
|||
write.run();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,4 +28,4 @@ final class PlayerScoringTracker {
|
|||
private static String blockKey(Block block) {
|
||||
return block.getX() + "," + block.getY() + "," + block.getZ();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -31,4 +31,4 @@ final class PlayerSpawnSetup {
|
|||
void updateHotbar(ParkourPlayer player) {
|
||||
ParkourHotbar.apply(player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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)) {
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -131,4 +131,4 @@ public class StorageSQL {
|
|||
}
|
||||
SQLPlayerRepository.writePlayer(connectionManager, player);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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.
|
||||
*/
|
||||
|
|
|
|||
|
|
@ -65,4 +65,4 @@ public class SQLPlayerRepository {
|
|||
LOGGER.severe("Failed to write player data: " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -68,4 +68,4 @@ public class SQLScoreRepository {
|
|||
LOGGER.severe("Failed to write scores for mode " + mode + ": " + e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -56,4 +56,4 @@ public class SQLSchemaManager {
|
|||
stmt.executeUpdate();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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");
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue