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);
|
lastBlockCache.remove(playerUuid);
|
||||||
lastLandTimeCache.remove(playerUuid);
|
lastLandTimeCache.remove(playerUuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -71,4 +71,4 @@ public class MetricEventCollector {
|
||||||
public void unload(@NotNull UUID playerUuid) {
|
public void unload(@NotNull UUID playerUuid) {
|
||||||
timingTracker.unload(playerUuid);
|
timingTracker.unload(playerUuid);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -97,4 +97,4 @@ public class MetricsCacheStore {
|
||||||
autoSaveTask = null;
|
autoSaveTask = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -123,4 +123,4 @@ class CommandRouter {
|
||||||
}
|
}
|
||||||
SchematicCommandHandler.handleCreateWithDifficulty(a3, a4, sender, p, player);
|
SchematicCommandHandler.handleCreateWithDifficulty(a3, a4, sender, p, player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -187,4 +187,4 @@ class CommandTabCompleter {
|
||||||
final String lower = input.toLowerCase();
|
final String lower = input.toLowerCase();
|
||||||
return options.stream().filter(s -> s.toLowerCase().startsWith(lower)).toList();
|
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) {
|
@NotNull String alias, @NotNull String[] args) {
|
||||||
return CommandTabCompleter.complete(sender, args);
|
return CommandTabCompleter.complete(sender, args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -65,4 +65,4 @@ public class JoinCommandExecutor {
|
||||||
Modes.SPECTATOR.create(p, session);
|
Modes.SPECTATOR.create(p, session);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,4 +24,4 @@ public class LeaderboardCommandExecutor {
|
||||||
Menus.SINGLE_LEADERBOARD.open(p, mode, Leaderboard.Sort.SCORE);
|
Menus.SINGLE_LEADERBOARD.open(p, mode, Leaderboard.Sort.SCORE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -88,4 +88,4 @@ public class SchematicCommandHandler {
|
||||||
static boolean isValidSchematicName(String name) {
|
static boolean isValidSchematicName(String name) {
|
||||||
return SchematicHandler.isValidSchematicName(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_-]+$");
|
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, Locales.getString(player, "schematic.help.line_docs"));
|
||||||
send(player, "");
|
send(player, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -54,4 +54,4 @@ final class SchematicWand {
|
||||||
cachedWand = item;
|
cachedWand = item;
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -24,4 +24,4 @@ final class SelectionStore {
|
||||||
updated[index] = loc.clone();
|
updated[index] = loc.clone();
|
||||||
SchematicCommandHandler.SELECTIONS.put(player, updated);
|
SchematicCommandHandler.SELECTIONS.put(player, updated);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -11,4 +11,4 @@ public final class CommandUtil {
|
||||||
public static void send(CommandSender sender, String msg) {
|
public static void send(CommandSender sender, String msg) {
|
||||||
sender.sendMessage(ColorUtil.color(msg));
|
sender.sendMessage(ColorUtil.color(msg));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -22,7 +22,7 @@ public enum Config {
|
||||||
public final String fileName;
|
public final String fileName;
|
||||||
public final List<String> ignoredSections;
|
public final List<String> ignoredSections;
|
||||||
public FileConfiguration fileConfiguration;
|
public FileConfiguration fileConfiguration;
|
||||||
|
|
||||||
private ConfigAccessor accessor;
|
private ConfigAccessor accessor;
|
||||||
|
|
||||||
Config(String fileName, @Nullable List<String> ignoredSections) {
|
Config(String fileName, @Nullable List<String> ignoredSections) {
|
||||||
|
|
@ -36,7 +36,7 @@ public enum Config {
|
||||||
*/
|
*/
|
||||||
public static void reload(boolean initialLoad) {
|
public static void reload(boolean initialLoad) {
|
||||||
ConfigLoader.reloadAllConfigs(initialLoad);
|
ConfigLoader.reloadAllConfigs(initialLoad);
|
||||||
|
|
||||||
// Update accessors for all configs
|
// Update accessors for all configs
|
||||||
for (final Config config : values()) {
|
for (final Config config : values()) {
|
||||||
if (config.fileConfiguration != null) {
|
if (config.fileConfiguration != null) {
|
||||||
|
|
@ -55,7 +55,7 @@ public enum Config {
|
||||||
if (path == null) {
|
if (path == null) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.fileConfiguration = ConfigLoader.loadConfig(path);
|
this.fileConfiguration = ConfigLoader.loadConfig(path);
|
||||||
this.accessor = new ConfigAccessor(fileConfiguration, fileName);
|
this.accessor = new ConfigAccessor(fileConfiguration, fileName);
|
||||||
}
|
}
|
||||||
|
|
@ -70,7 +70,7 @@ public enum Config {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Delegate all accessor methods to ConfigAccessor
|
// Delegate all accessor methods to ConfigAccessor
|
||||||
|
|
||||||
public boolean isPath(@NotNull String path) {
|
public boolean isPath(@NotNull String path) {
|
||||||
return accessor != null && accessor.isPath(path);
|
return accessor != null && accessor.isPath(path);
|
||||||
}
|
}
|
||||||
|
|
@ -90,7 +90,7 @@ public enum Config {
|
||||||
public int getInt(@NotNull String path) {
|
public int getInt(@NotNull String path) {
|
||||||
return accessor.getInt(path);
|
return accessor.getInt(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getInt(@NotNull String path, int defaultValue) {
|
public int getInt(@NotNull String path, int defaultValue) {
|
||||||
return accessor != null ? accessor.getInt(path, defaultValue) : 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.
|
* Provides safe access to configuration values with validation.
|
||||||
*/
|
*/
|
||||||
public class ConfigAccessor {
|
public class ConfigAccessor {
|
||||||
|
|
||||||
private final FileConfiguration config;
|
private final FileConfiguration config;
|
||||||
private final String fileName;
|
private final String fileName;
|
||||||
private final Set<String> warnedMissingPaths = ConcurrentHashMap.newKeySet();
|
private final Set<String> warnedMissingPaths = ConcurrentHashMap.newKeySet();
|
||||||
|
|
||||||
public ConfigAccessor(@NotNull FileConfiguration config, @NotNull String fileName) {
|
public ConfigAccessor(@NotNull FileConfiguration config, @NotNull String fileName) {
|
||||||
this.config = config;
|
this.config = config;
|
||||||
this.fileName = fileName;
|
this.fileName = fileName;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if path exists in configuration.
|
* Check if path exists in configuration.
|
||||||
*/
|
*/
|
||||||
public boolean isPath(@NotNull String path) {
|
public boolean isPath(@NotNull String path) {
|
||||||
return config.isSet(path);
|
return config.isSet(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get raw object value at path.
|
* Get raw object value at path.
|
||||||
*/
|
*/
|
||||||
|
|
@ -38,7 +38,7 @@ public class ConfigAccessor {
|
||||||
warnIfMissing(path);
|
warnIfMissing(path);
|
||||||
return config.get(path);
|
return config.get(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get boolean value at path.
|
* Get boolean value at path.
|
||||||
*/
|
*/
|
||||||
|
|
@ -56,7 +56,7 @@ public class ConfigAccessor {
|
||||||
}
|
}
|
||||||
return config.getBoolean(path, defaultValue);
|
return config.getBoolean(path, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get integer value at path.
|
* Get integer value at path.
|
||||||
*/
|
*/
|
||||||
|
|
@ -64,7 +64,7 @@ public class ConfigAccessor {
|
||||||
warnIfMissing(path);
|
warnIfMissing(path);
|
||||||
return config.getInt(path, 0);
|
return config.getInt(path, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get integer value at path with default.
|
* Get integer value at path with default.
|
||||||
*/
|
*/
|
||||||
|
|
@ -74,7 +74,7 @@ public class ConfigAccessor {
|
||||||
}
|
}
|
||||||
return config.getInt(path, defaultValue);
|
return config.getInt(path, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get double value at path.
|
* Get double value at path.
|
||||||
*/
|
*/
|
||||||
|
|
@ -90,7 +90,7 @@ public class ConfigAccessor {
|
||||||
warnIfMissing(path);
|
warnIfMissing(path);
|
||||||
return config.getDouble(path, defaultValue);
|
return config.getDouble(path, defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get string value at path.
|
* Get string value at path.
|
||||||
* Forces conversion to String even if YAML parsed as Boolean/Number.
|
* 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
|
// Force toString() to handle Boolean/Number values
|
||||||
return String.valueOf(value);
|
return String.valueOf(value);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get string list at path.
|
* Get string list at path.
|
||||||
*/
|
*/
|
||||||
|
|
@ -114,7 +114,7 @@ public class ConfigAccessor {
|
||||||
warnIfMissing(path);
|
warnIfMissing(path);
|
||||||
return config.getStringList(path);
|
return config.getStringList(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get integer list at path.
|
* Get integer list at path.
|
||||||
*/
|
*/
|
||||||
|
|
@ -123,7 +123,7 @@ public class ConfigAccessor {
|
||||||
warnIfMissing(path);
|
warnIfMissing(path);
|
||||||
return config.getIntegerList(path);
|
return config.getIntegerList(path);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get child keys from configuration section.
|
* Get child keys from configuration section.
|
||||||
*/
|
*/
|
||||||
|
|
@ -133,16 +133,16 @@ public class ConfigAccessor {
|
||||||
warnIfMissing(path);
|
warnIfMissing(path);
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
final ConfigurationSection section = config.getConfigurationSection(path);
|
final ConfigurationSection section = config.getConfigurationSection(path);
|
||||||
if (section == null) {
|
if (section == null) {
|
||||||
return new ArrayList<>();
|
return new ArrayList<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
final boolean isDeep = deep.length > 0 && deep[0];
|
final boolean isDeep = deep.length > 0 && deep[0];
|
||||||
return new ArrayList<>(section.getKeys(isDeep));
|
return new ArrayList<>(section.getKeys(isDeep));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void warnIfMissing(@NotNull String path) {
|
private void warnIfMissing(@NotNull String path) {
|
||||||
if (isPath(path)) {
|
if (isPath(path)) {
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -69,4 +69,4 @@ public class ConfigUpdater {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -13,13 +13,13 @@ import java.time.Duration;
|
||||||
* Manages generator statistics and time formatting.
|
* Manages generator statistics and time formatting.
|
||||||
*/
|
*/
|
||||||
public class GeneratorStatistics {
|
public class GeneratorStatistics {
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
|
|
||||||
public GeneratorStatistics(@NotNull ParkourGenerator generator) {
|
public GeneratorStatistics(@NotNull ParkourGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get formatted time string.
|
* Get formatted time string.
|
||||||
*/
|
*/
|
||||||
|
|
@ -27,7 +27,7 @@ public class GeneratorStatistics {
|
||||||
public String getFormattedTime() {
|
public String getFormattedTime() {
|
||||||
return getTime("mm:ss.SSS");
|
return getTime("mm:ss.SSS");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get detailed time string.
|
* Get detailed time string.
|
||||||
*/
|
*/
|
||||||
|
|
@ -35,14 +35,14 @@ public class GeneratorStatistics {
|
||||||
public String getDetailedTime() {
|
public String getDetailedTime() {
|
||||||
return getTime("HH:mm:ss.SSS");
|
return getTime("HH:mm:ss.SSS");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Register score in leaderboard.
|
* Register score in leaderboard.
|
||||||
*/
|
*/
|
||||||
public void registerScore(@NotNull String time, @NotNull String difficulty, int score) {
|
public void registerScore(@NotNull String time, @NotNull String difficulty, int score) {
|
||||||
final Mode mode = generator.getMode();
|
final Mode mode = generator.getMode();
|
||||||
final Leaderboard leaderboard = mode.getLeaderboard();
|
final Leaderboard leaderboard = mode.getLeaderboard();
|
||||||
|
|
||||||
for (final ParkourPlayer player : generator.getPlayers()) {
|
for (final ParkourPlayer player : generator.getPlayers()) {
|
||||||
final Score playerScore = new Score(
|
final Score playerScore = new Score(
|
||||||
player.player.getName(),
|
player.player.getName(),
|
||||||
|
|
@ -50,18 +50,18 @@ public class GeneratorStatistics {
|
||||||
difficulty,
|
difficulty,
|
||||||
score
|
score
|
||||||
);
|
);
|
||||||
|
|
||||||
leaderboard.put(player.getUUID(), playerScore);
|
leaderboard.put(player.getUUID(), playerScore);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Send fall message to players.
|
* Send fall message to players.
|
||||||
*/
|
*/
|
||||||
public void sendFallMessage(int record) {
|
public void sendFallMessage(int record) {
|
||||||
for (final ParkourPlayer player : generator.getPlayers()) {
|
for (final ParkourPlayer player : generator.getPlayers()) {
|
||||||
final String message;
|
final String message;
|
||||||
|
|
||||||
if (generator.state.score > record) {
|
if (generator.state.score > record) {
|
||||||
// New record
|
// New record
|
||||||
message = Locales.getString(player.player, "parkour.fall.new-record")
|
message = Locales.getString(player.player, "parkour.fall.new-record")
|
||||||
|
|
@ -74,11 +74,11 @@ public class GeneratorStatistics {
|
||||||
.replace("%record%", String.valueOf(record))
|
.replace("%record%", String.valueOf(record))
|
||||||
.replace("%time%", getFormattedTime());
|
.replace("%time%", getFormattedTime());
|
||||||
}
|
}
|
||||||
|
|
||||||
player.player.sendMessage(message);
|
player.player.sendMessage(message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private String getTime(@NotNull String format) {
|
private String getTime(@NotNull String format) {
|
||||||
if (generator.state.start == null) {
|
if (generator.state.start == null) {
|
||||||
|
|
|
||||||
|
|
@ -26,13 +26,13 @@ import java.util.List;
|
||||||
* Coordinates profile management, statistics, and core generation.
|
* Coordinates profile management, statistics, and core generation.
|
||||||
*/
|
*/
|
||||||
public class ParkourGenerator {
|
public class ParkourGenerator {
|
||||||
|
|
||||||
public final Session session;
|
public final Session session;
|
||||||
public final Island island;
|
public final Island island;
|
||||||
public final Profile profile;
|
public final Profile profile;
|
||||||
public final GeneratorState state;
|
public final GeneratorState state;
|
||||||
public final GeneratorOption[] generatorOptions;
|
public final GeneratorOption[] generatorOptions;
|
||||||
|
|
||||||
protected final BlockPlacer placer;
|
protected final BlockPlacer placer;
|
||||||
protected final GeneratorLifecycle lifecycle;
|
protected final GeneratorLifecycle lifecycle;
|
||||||
public final GeneratorProfileManager profileManager;
|
public final GeneratorProfileManager profileManager;
|
||||||
|
|
@ -40,7 +40,7 @@ public class ParkourGenerator {
|
||||||
|
|
||||||
// Event listeners for adaptive system integration
|
// Event listeners for adaptive system integration
|
||||||
private final List<GeneratorEventListener> eventListeners;
|
private final List<GeneratorEventListener> eventListeners;
|
||||||
|
|
||||||
public ParkourGenerator(@NotNull Session session, GeneratorOption... generatorOptions) {
|
public ParkourGenerator(@NotNull Session session, GeneratorOption... generatorOptions) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
this.generatorOptions = generatorOptions;
|
this.generatorOptions = generatorOptions;
|
||||||
|
|
@ -68,8 +68,8 @@ public class ParkourGenerator {
|
||||||
profileManager.overrideProfile();
|
profileManager.overrideProfile();
|
||||||
profileManager.calculateChances();
|
profileManager.calculateChances();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Core generation methods
|
// Core generation methods
|
||||||
public void generate() {
|
public void generate() {
|
||||||
placer.generate();
|
placer.generate();
|
||||||
|
|
@ -99,52 +99,52 @@ public class ParkourGenerator {
|
||||||
protected void score() {
|
protected void score() {
|
||||||
lifecycle.score();
|
lifecycle.score();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void reset(boolean regenerate) {
|
public void reset(boolean regenerate) {
|
||||||
lifecycle.reset(regenerate);
|
lifecycle.reset(regenerate);
|
||||||
|
|
||||||
if (regenerate) {
|
if (regenerate) {
|
||||||
profileManager.overrideProfile();
|
profileManager.overrideProfile();
|
||||||
profileManager.calculateChances();
|
profileManager.calculateChances();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Statistics and scoring
|
// Statistics and scoring
|
||||||
public void registerScore(String time, String difficulty, int score) {
|
public void registerScore(String time, String difficulty, int score) {
|
||||||
statistics.registerScore(time, difficulty, score);
|
statistics.registerScore(time, difficulty, score);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getDifficultyScore() {
|
public double getDifficultyScore() {
|
||||||
return profileManager.getDifficultyScore();
|
return profileManager.getDifficultyScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getFormattedTime() {
|
public String getFormattedTime() {
|
||||||
return statistics.getFormattedTime();
|
return statistics.getFormattedTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
public String getDetailedTime() {
|
public String getDetailedTime() {
|
||||||
return statistics.getDetailedTime();
|
return statistics.getDetailedTime();
|
||||||
}
|
}
|
||||||
|
|
||||||
// UI and player management
|
// UI and player management
|
||||||
public void menu(ParkourPlayer player) {
|
public void menu(ParkourPlayer player) {
|
||||||
Menus.PARKOUR_SETTINGS.open(player);
|
Menus.PARKOUR_SETTINGS.open(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
public Mode getMode() {
|
public Mode getMode() {
|
||||||
return Modes.DEFAULT;
|
return Modes.DEFAULT;
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<ParkourPlayer> getPlayers() {
|
public List<ParkourPlayer> getPlayers() {
|
||||||
return session.getPlayers();
|
return session.getPlayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<ParkourSpectator> getSpectators() {
|
public List<ParkourSpectator> getSpectators() {
|
||||||
return session.getSpectators();
|
return session.getSpectators();
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Last generated block, or {@code null} if history is empty. */
|
/** Last generated block, or {@code null} if history is empty. */
|
||||||
public @Nullable Block getLatest() {
|
public @Nullable Block getLatest() {
|
||||||
if (state.history.isEmpty()) {
|
if (state.history.isEmpty()) {
|
||||||
|
|
|
||||||
|
|
@ -92,7 +92,7 @@ public class JumpOffsetGenerator {
|
||||||
final Map<Double, Double> distribution = java.util.stream.IntStream.range(-maxOffset, maxOffset + 1)
|
final Map<Double, Double> distribution = java.util.stream.IntStream.range(-maxOffset, maxOffset + 1)
|
||||||
.boxed()
|
.boxed()
|
||||||
.collect(Collectors.toMap(
|
.collect(Collectors.toMap(
|
||||||
offset -> (double) offset,
|
offset -> (double) offset,
|
||||||
offset -> Probs.normalpdf(mean, standardDeviation, (double) offset)
|
offset -> Probs.normalpdf(mean, standardDeviation, (double) offset)
|
||||||
));
|
));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -43,13 +43,13 @@ public class JumpValidator {
|
||||||
if (from == null || to == null) {
|
if (from == null || to == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if jumping from a bottom slab - adjust limits accordingly
|
// Check if jumping from a bottom slab - adjust limits accordingly
|
||||||
final double heightAdjustment = getSlabHeightAdjustment(from);
|
final double heightAdjustment = getSlabHeightAdjustment(from);
|
||||||
|
|
||||||
return canJumpWithAdjustment(from.toVector(), to.toVector(), heightAdjustment);
|
return canJumpWithAdjustment(from.toVector(), to.toVector(), heightAdjustment);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get height adjustment for slab blocks.
|
* Get height adjustment for slab blocks.
|
||||||
* Returns negative value for bottom slabs (player is lower).
|
* Returns negative value for bottom slabs (player is lower).
|
||||||
|
|
@ -71,13 +71,13 @@ public class JumpValidator {
|
||||||
}
|
}
|
||||||
return 0.0; // No adjustment for full blocks
|
return 0.0; // No adjustment for full blocks
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean canJumpWithAdjustment(@NotNull Vector from, @NotNull Vector to, double heightAdjustment) {
|
private boolean canJumpWithAdjustment(@NotNull Vector from, @NotNull Vector to, double heightAdjustment) {
|
||||||
// Null safety check
|
// Null safety check
|
||||||
if (from == null || to == null) {
|
if (from == null || to == null) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
final double dx = to.getX() - from.getX();
|
final double dx = to.getX() - from.getX();
|
||||||
final double dy = to.getY() - from.getY();
|
final double dy = to.getY() - from.getY();
|
||||||
final double dz = to.getZ() - from.getZ();
|
final double dz = to.getZ() - from.getZ();
|
||||||
|
|
@ -96,7 +96,7 @@ public class JumpValidator {
|
||||||
// Adjust vertical limits based on slab height
|
// Adjust vertical limits based on slab height
|
||||||
double adjustedMaxVerticalUp = maxVerticalUp;
|
double adjustedMaxVerticalUp = maxVerticalUp;
|
||||||
double adjustedMaxVerticalDown = maxVerticalDown;
|
double adjustedMaxVerticalDown = maxVerticalDown;
|
||||||
|
|
||||||
if (heightAdjustment < 0) {
|
if (heightAdjustment < 0) {
|
||||||
// Player is lower (bottom slab), reduce upward jump capability
|
// Player is lower (bottom slab), reduce upward jump capability
|
||||||
adjustedMaxVerticalUp = maxVerticalUp + heightAdjustment; // Reduce max up jump
|
adjustedMaxVerticalUp = maxVerticalUp + heightAdjustment; // Reduce max up jump
|
||||||
|
|
@ -107,7 +107,7 @@ public class JumpValidator {
|
||||||
if (dy > adjustedMaxVerticalUp || dy < -adjustedMaxVerticalDown) {
|
if (dy > adjustedMaxVerticalUp || dy < -adjustedMaxVerticalDown) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// For upward jumps, reduce max horizontal distance
|
// For upward jumps, reduce max horizontal distance
|
||||||
// Player can't jump as far when jumping up
|
// Player can't jump as far when jumping up
|
||||||
if (dy > 0) {
|
if (dy > 0) {
|
||||||
|
|
|
||||||
|
|
@ -122,4 +122,4 @@ public class BlockPlacer {
|
||||||
generator.state.history.add(selectedBlock);
|
generator.state.history.add(selectedBlock);
|
||||||
generator.state.generatedBlocks++;
|
generator.state.generatedBlocks++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,13 +16,13 @@ import java.util.List;
|
||||||
* Handles selection of block types and materials for parkour generation.
|
* Handles selection of block types and materials for parkour generation.
|
||||||
*/
|
*/
|
||||||
public class BlockSelector {
|
public class BlockSelector {
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
|
|
||||||
public BlockSelector(@NotNull ParkourGenerator generator) {
|
public BlockSelector(@NotNull ParkourGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static final int MAX_STYLE_PICKS = 64;
|
private static final int MAX_STYLE_PICKS = 64;
|
||||||
private static final int MAX_SLAB_PICKS = 20;
|
private static final int MAX_SLAB_PICKS = 20;
|
||||||
|
|
||||||
|
|
@ -66,7 +66,7 @@ public class BlockSelector {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Select jump type based on current configuration and probabilities.
|
* Select jump type based on current configuration and probabilities.
|
||||||
*/
|
*/
|
||||||
|
|
@ -76,7 +76,7 @@ public class BlockSelector {
|
||||||
final JumpType[] types = JumpType.values();
|
final JumpType[] types = JumpType.values();
|
||||||
return types[(int) (Math.random() * types.length)];
|
return types[(int) (Math.random() * types.length)];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get a slab material from the current player's style.
|
* Get a slab material from the current player's style.
|
||||||
*/
|
*/
|
||||||
|
|
@ -87,7 +87,7 @@ public class BlockSelector {
|
||||||
if (style == null) {
|
if (style == null) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Try to get a slab material from the style multiple times
|
// Try to get a slab material from the style multiple times
|
||||||
for (int i = 0; i < MAX_SLAB_PICKS; i++) {
|
for (int i = 0; i < MAX_SLAB_PICKS; i++) {
|
||||||
final Material material = style.getNext();
|
final Material material = style.getNext();
|
||||||
|
|
@ -100,7 +100,7 @@ public class BlockSelector {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if material is a special block type that affects jump mechanics.
|
* Check if material is a special block type that affects jump mechanics.
|
||||||
*/
|
*/
|
||||||
|
|
@ -114,7 +114,7 @@ public class BlockSelector {
|
||||||
isTrapdoorMaterial(material) ||
|
isTrapdoorMaterial(material) ||
|
||||||
material == Material.LADDER;
|
material == Material.LADDER;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isFenceMaterial(@NotNull Material material) {
|
public boolean isFenceMaterial(@NotNull Material material) {
|
||||||
return material == Material.OAK_FENCE ||
|
return material == Material.OAK_FENCE ||
|
||||||
material == Material.BIRCH_FENCE ||
|
material == Material.BIRCH_FENCE ||
|
||||||
|
|
@ -127,7 +127,7 @@ public class BlockSelector {
|
||||||
material == Material.WARPED_FENCE ||
|
material == Material.WARPED_FENCE ||
|
||||||
material == Material.NETHER_BRICK_FENCE;
|
material == Material.NETHER_BRICK_FENCE;
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isTrapdoorMaterial(@NotNull Material material) {
|
public boolean isTrapdoorMaterial(@NotNull Material material) {
|
||||||
return material == Material.OAK_TRAPDOOR ||
|
return material == Material.OAK_TRAPDOOR ||
|
||||||
material == Material.BIRCH_TRAPDOOR ||
|
material == Material.BIRCH_TRAPDOOR ||
|
||||||
|
|
|
||||||
|
|
@ -49,4 +49,4 @@ class BlockTargetSelector {
|
||||||
blocks.add(nextBlock);
|
blocks.add(nextBlock);
|
||||||
return blocks;
|
return blocks;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,4 +50,4 @@ class BlockWorldPlacer {
|
||||||
generator.state.schematicBlocks.clear();
|
generator.state.schematicBlocks.clear();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -61,4 +61,4 @@ class SchematicBlockPlacer {
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,7 +8,7 @@ import org.jetbrains.annotations.NotNull;
|
||||||
/**
|
/**
|
||||||
* Refactored GeneratorLifecycle using composition pattern.
|
* Refactored GeneratorLifecycle using composition pattern.
|
||||||
* Coordinates tick management, player interactions, and visual updates.
|
* Coordinates tick management, player interactions, and visual updates.
|
||||||
*
|
*
|
||||||
* Responsibilities delegated to:
|
* Responsibilities delegated to:
|
||||||
* - LifecycleTickManager: Tick cycle and periodic operations
|
* - LifecycleTickManager: Tick cycle and periodic operations
|
||||||
* - PlayerInteractionHandler: Block interactions and scoring
|
* - PlayerInteractionHandler: Block interactions and scoring
|
||||||
|
|
@ -23,7 +23,7 @@ public class GeneratorLifecycle {
|
||||||
private final LifecycleVisualUpdater visualUpdater;
|
private final LifecycleVisualUpdater visualUpdater;
|
||||||
private final LifecycleEventManager eventManager;
|
private final LifecycleEventManager eventManager;
|
||||||
private final GeneratorCleanup cleanup;
|
private final GeneratorCleanup cleanup;
|
||||||
|
|
||||||
public GeneratorLifecycle(@NotNull ParkourGenerator generator) {
|
public GeneratorLifecycle(@NotNull ParkourGenerator generator) {
|
||||||
this.eventManager = new LifecycleEventManager(generator);
|
this.eventManager = new LifecycleEventManager(generator);
|
||||||
this.cleanup = new GeneratorCleanup(generator);
|
this.cleanup = new GeneratorCleanup(generator);
|
||||||
|
|
@ -31,14 +31,14 @@ public class GeneratorLifecycle {
|
||||||
this.tickManager = new LifecycleTickManager(generator, cleanup, visualUpdater);
|
this.tickManager = new LifecycleTickManager(generator, cleanup, visualUpdater);
|
||||||
this.interactionHandler = new PlayerInteractionHandler(generator, eventManager, cleanup);
|
this.interactionHandler = new PlayerInteractionHandler(generator, eventManager, cleanup);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the tick cycle.
|
* Start the tick cycle.
|
||||||
*/
|
*/
|
||||||
public void startTick() {
|
public void startTick() {
|
||||||
tickManager.startTick();
|
tickManager.startTick();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main tick method called every server tick.
|
* Main tick method called every server tick.
|
||||||
*/
|
*/
|
||||||
|
|
@ -46,21 +46,21 @@ public class GeneratorLifecycle {
|
||||||
tickManager.tick();
|
tickManager.tick();
|
||||||
interactionHandler.checkAllPlayers();
|
interactionHandler.checkAllPlayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle player scoring.
|
* Handle player scoring.
|
||||||
*/
|
*/
|
||||||
public void score() {
|
public void score() {
|
||||||
interactionHandler.handleScore();
|
interactionHandler.handleScore();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle player falling.
|
* Handle player falling.
|
||||||
*/
|
*/
|
||||||
public void fall() {
|
public void fall() {
|
||||||
interactionHandler.handleFall();
|
interactionHandler.handleFall();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset the lifecycle state.
|
* Reset the lifecycle state.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -19,13 +19,13 @@ import java.util.Map;
|
||||||
* Manages lifecycle events for parkour generator.
|
* Manages lifecycle events for parkour generator.
|
||||||
*/
|
*/
|
||||||
public class LifecycleEventManager {
|
public class LifecycleEventManager {
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
|
|
||||||
public LifecycleEventManager(@NotNull ParkourGenerator generator) {
|
public LifecycleEventManager(@NotNull ParkourGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle score event and check rewards.
|
* Handle score event and check rewards.
|
||||||
*/
|
*/
|
||||||
|
|
@ -35,11 +35,11 @@ public class LifecycleEventManager {
|
||||||
final ParkourScoreEvent scoreEvent = new ParkourScoreEvent(player);
|
final ParkourScoreEvent scoreEvent = new ParkourScoreEvent(player);
|
||||||
Bukkit.getPluginManager().callEvent(scoreEvent);
|
Bukkit.getPluginManager().callEvent(scoreEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for rewards
|
// Check for rewards
|
||||||
checkRewards();
|
checkRewards();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle fall event.
|
* Handle fall event.
|
||||||
*/
|
*/
|
||||||
|
|
@ -49,18 +49,18 @@ public class LifecycleEventManager {
|
||||||
final ParkourFallEvent fallEvent = new ParkourFallEvent(player);
|
final ParkourFallEvent fallEvent = new ParkourFallEvent(player);
|
||||||
Bukkit.getPluginManager().callEvent(fallEvent);
|
Bukkit.getPluginManager().callEvent(fallEvent);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Process fall logic
|
// Process fall logic
|
||||||
processFall();
|
processFall();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void checkRewards() {
|
private void checkRewards() {
|
||||||
if (!Rewards.REWARDS_ENABLED) {
|
if (!Rewards.REWARDS_ENABLED) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
final Mode mode = generator.getMode();
|
final Mode mode = generator.getMode();
|
||||||
|
|
||||||
for (final ParkourPlayer player : generator.getPlayers()) {
|
for (final ParkourPlayer player : generator.getPlayers()) {
|
||||||
final int score = generator.state.score;
|
final int score = generator.state.score;
|
||||||
applyScoreRewards(player, mode, score);
|
applyScoreRewards(player, mode, score);
|
||||||
|
|
@ -68,7 +68,7 @@ public class LifecycleEventManager {
|
||||||
applyOneTimeRewards(player, mode, score);
|
applyOneTimeRewards(player, mode, score);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyScoreRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
|
private void applyScoreRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
|
||||||
if (!Rewards.SCORE_REWARDS.containsKey(score)) {
|
if (!Rewards.SCORE_REWARDS.containsKey(score)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -77,7 +77,7 @@ public class LifecycleEventManager {
|
||||||
reward.execute(player, mode);
|
reward.execute(player, mode);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void applyIntervalRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
|
private void applyIntervalRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
|
||||||
for (final Map.Entry<Integer, List<Reward>> entry : Rewards.INTERVAL_REWARDS.entrySet()) {
|
for (final Map.Entry<Integer, List<Reward>> entry : Rewards.INTERVAL_REWARDS.entrySet()) {
|
||||||
if (score > 0 && score % entry.getKey() == 0) {
|
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) {
|
private void applyOneTimeRewards(@NotNull ParkourPlayer player, @NotNull Mode mode, int score) {
|
||||||
if (!Rewards.ONE_TIME_REWARDS.containsKey(score)) {
|
if (!Rewards.ONE_TIME_REWARDS.containsKey(score)) {
|
||||||
return;
|
return;
|
||||||
|
|
@ -105,7 +105,7 @@ public class LifecycleEventManager {
|
||||||
player.collectedRewards.add(rewardKey);
|
player.collectedRewards.add(rewardKey);
|
||||||
player.save(false);
|
player.save(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void processFall() {
|
private void processFall() {
|
||||||
// Record statistics
|
// Record statistics
|
||||||
final int score = generator.state.score;
|
final int score = generator.state.score;
|
||||||
|
|
|
||||||
|
|
@ -10,18 +10,18 @@ import org.jetbrains.annotations.NotNull;
|
||||||
* Manages tick cycle and periodic operations for generator lifecycle.
|
* Manages tick cycle and periodic operations for generator lifecycle.
|
||||||
*/
|
*/
|
||||||
public class LifecycleTickManager {
|
public class LifecycleTickManager {
|
||||||
|
|
||||||
private static final int TIME_UI_INTERVAL = 20; // 1 second — time display tick
|
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 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 FALL_THRESHOLD_OFFSET = 30;
|
||||||
private static final int MAX_GENERATE_PER_TICK = 5;
|
private static final int MAX_GENERATE_PER_TICK = 5;
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
private final GeneratorCleanup cleanup;
|
private final GeneratorCleanup cleanup;
|
||||||
private final LifecycleVisualUpdater visualUpdater;
|
private final LifecycleVisualUpdater visualUpdater;
|
||||||
|
|
||||||
private int tickCounter = 0;
|
private int tickCounter = 0;
|
||||||
|
|
||||||
public LifecycleTickManager(
|
public LifecycleTickManager(
|
||||||
@NotNull ParkourGenerator generator,
|
@NotNull ParkourGenerator generator,
|
||||||
@NotNull GeneratorCleanup cleanup,
|
@NotNull GeneratorCleanup cleanup,
|
||||||
|
|
@ -30,7 +30,7 @@ public class LifecycleTickManager {
|
||||||
this.cleanup = cleanup;
|
this.cleanup = cleanup;
|
||||||
this.visualUpdater = visualUpdater;
|
this.visualUpdater = visualUpdater;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Start the tick cycle.
|
* Start the tick cycle.
|
||||||
*/
|
*/
|
||||||
|
|
@ -40,7 +40,7 @@ public class LifecycleTickManager {
|
||||||
// Generate initial blocks ahead of the player
|
// Generate initial blocks ahead of the player
|
||||||
generator.generate(2);
|
generator.generate(2);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Main tick method called every server tick.
|
* Main tick method called every server tick.
|
||||||
*/
|
*/
|
||||||
|
|
@ -83,14 +83,14 @@ public class LifecycleTickManager {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset tick counter.
|
* Reset tick counter.
|
||||||
*/
|
*/
|
||||||
public void reset() {
|
public void reset() {
|
||||||
tickCounter = 0;
|
tickCounter = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void maintainBlockLead() {
|
private void maintainBlockLead() {
|
||||||
final int currentBlocks = generator.state.generatedBlocks;
|
final int currentBlocks = generator.state.generatedBlocks;
|
||||||
final int targetBlocks = generator.state.score + generationLead();
|
final int targetBlocks = generator.state.score + generationLead();
|
||||||
|
|
|
||||||
|
|
@ -8,13 +8,13 @@ import org.jetbrains.annotations.NotNull;
|
||||||
* Manages visual updates for players during parkour lifecycle.
|
* Manages visual updates for players during parkour lifecycle.
|
||||||
*/
|
*/
|
||||||
public class LifecycleVisualUpdater {
|
public class LifecycleVisualUpdater {
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
|
|
||||||
public LifecycleVisualUpdater(@NotNull ParkourGenerator generator) {
|
public LifecycleVisualUpdater(@NotNull ParkourGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update visuals for all players.
|
* Update visuals for all players.
|
||||||
*/
|
*/
|
||||||
|
|
@ -23,7 +23,7 @@ public class LifecycleVisualUpdater {
|
||||||
updatePlayerVisuals(player);
|
updatePlayerVisuals(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update time displays for all players.
|
* Update time displays for all players.
|
||||||
*/
|
*/
|
||||||
|
|
@ -32,17 +32,17 @@ public class LifecycleVisualUpdater {
|
||||||
updatePlayerTimeDisplay(player);
|
updatePlayerTimeDisplay(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updatePlayerVisuals(@NotNull ParkourPlayer player) {
|
private void updatePlayerVisuals(@NotNull ParkourPlayer player) {
|
||||||
// Update scoreboard if enabled
|
// Update scoreboard if enabled
|
||||||
if (player.showScoreboard != null && player.showScoreboard) {
|
if (player.showScoreboard != null && player.showScoreboard) {
|
||||||
player.updateScoreboard(generator);
|
player.updateScoreboard(generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update action bar with time and score
|
// Update action bar with time and score
|
||||||
updatePlayerTimeDisplay(player);
|
updatePlayerTimeDisplay(player);
|
||||||
}
|
}
|
||||||
|
|
||||||
@SuppressWarnings("unused") // reserved for action bar
|
@SuppressWarnings("unused") // reserved for action bar
|
||||||
private void updatePlayerTimeDisplay(@NotNull ParkourPlayer player) {
|
private void updatePlayerTimeDisplay(@NotNull ParkourPlayer player) {
|
||||||
// Placeholder for action bar (Paper adventure); scoreboard already shows time/score.
|
// 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 static final int FIRST_BLOCK_OFFSET = 6;
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
|
|
||||||
public GeneratorCleanup(@NotNull ParkourGenerator generator) {
|
public GeneratorCleanup(@NotNull ParkourGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove only trail blocks <strong>behind</strong> players (oldest indices).
|
* Remove only trail blocks <strong>behind</strong> players (oldest indices).
|
||||||
* Distance-based cleanup was removing blocks ahead of the player and breaking scoring.
|
* 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();
|
final Block below = loc.subtract(0, 1, 0).getBlock();
|
||||||
return below.getType() != Material.AIR ? below : null;
|
return below.getType() != Material.AIR ? below : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove schematic blocks once the player completes them.
|
* Remove schematic blocks once the player completes them.
|
||||||
* The end block is kept in history so the landing player can score it.
|
* 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.history.removeIf(remove::contains);
|
||||||
generator.state.schematicBlocks = null;
|
generator.state.schematicBlocks = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reset generator state and clean up all blocks.
|
* Reset generator state and clean up all blocks.
|
||||||
*/
|
*/
|
||||||
public void reset(boolean regenerate) {
|
public void reset(boolean regenerate) {
|
||||||
clearBlocks(generator.state.history);
|
clearBlocks(generator.state.history);
|
||||||
clearSchematicBlocks();
|
clearSchematicBlocks();
|
||||||
|
|
||||||
// Reset state
|
// Reset state
|
||||||
generator.state.history.clear();
|
generator.state.history.clear();
|
||||||
generator.state.generatedBlocks = 0;
|
generator.state.generatedBlocks = 0;
|
||||||
generator.state.score = 0;
|
generator.state.score = 0;
|
||||||
generator.state.start = null;
|
generator.state.start = null;
|
||||||
|
|
||||||
if (regenerate) {
|
if (regenerate) {
|
||||||
regenerateFirstBlock();
|
regenerateFirstBlock();
|
||||||
}
|
}
|
||||||
|
|
@ -172,5 +172,5 @@ public class GeneratorCleanup {
|
||||||
default -> {}
|
default -> {}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -18,14 +18,14 @@ import java.util.List;
|
||||||
* Handles player interactions with parkour blocks.
|
* Handles player interactions with parkour blocks.
|
||||||
*/
|
*/
|
||||||
public class PlayerInteractionHandler {
|
public class PlayerInteractionHandler {
|
||||||
|
|
||||||
private static final int GENERATION_LEAD = 5;
|
private static final int GENERATION_LEAD = 5;
|
||||||
private static final double BLOCK_CENTER_XZ_OFFSET = 0.5;
|
private static final double BLOCK_CENTER_XZ_OFFSET = 0.5;
|
||||||
|
|
||||||
private final ParkourGenerator generator;
|
private final ParkourGenerator generator;
|
||||||
private final LifecycleEventManager eventManager;
|
private final LifecycleEventManager eventManager;
|
||||||
private final GeneratorCleanup cleanup;
|
private final GeneratorCleanup cleanup;
|
||||||
|
|
||||||
public PlayerInteractionHandler(
|
public PlayerInteractionHandler(
|
||||||
@NotNull ParkourGenerator generator,
|
@NotNull ParkourGenerator generator,
|
||||||
@NotNull LifecycleEventManager eventManager,
|
@NotNull LifecycleEventManager eventManager,
|
||||||
|
|
@ -34,7 +34,7 @@ public class PlayerInteractionHandler {
|
||||||
this.eventManager = eventManager;
|
this.eventManager = eventManager;
|
||||||
this.cleanup = cleanup;
|
this.cleanup = cleanup;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check all players for block interactions.
|
* Check all players for block interactions.
|
||||||
*/
|
*/
|
||||||
|
|
@ -61,7 +61,7 @@ public class PlayerInteractionHandler {
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle player scoring on a block.
|
* Handle player scoring on a block.
|
||||||
*/
|
*/
|
||||||
|
|
@ -88,7 +88,7 @@ public class PlayerInteractionHandler {
|
||||||
// Block generation is handled by LifecycleTickManager.maintainBlockLead()
|
// Block generation is handled by LifecycleTickManager.maintainBlockLead()
|
||||||
// to avoid runaway generation in multiplayer (N players = N generates per tick otherwise).
|
// to avoid runaway generation in multiplayer (N players = N generates per tick otherwise).
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle player falling.
|
* Handle player falling.
|
||||||
*/
|
*/
|
||||||
|
|
@ -108,7 +108,7 @@ public class PlayerInteractionHandler {
|
||||||
}
|
}
|
||||||
AdaptiveServices.refreshGeneratorDifficulty(generator);
|
AdaptiveServices.refreshGeneratorDifficulty(generator);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleBlockInteraction(@NotNull ParkourPlayer player, @NotNull Block block) {
|
private void handleBlockInteraction(@NotNull ParkourPlayer player, @NotNull Block block) {
|
||||||
// Check if it's a schematic end block
|
// Check if it's a schematic end block
|
||||||
if (isSchematicEndBlock(block)) {
|
if (isSchematicEndBlock(block)) {
|
||||||
|
|
@ -130,14 +130,14 @@ public class PlayerInteractionHandler {
|
||||||
return generator.state.schematicBlocks != null
|
return generator.state.schematicBlocks != null
|
||||||
&& historyContains(generator.state.schematicBlocks, block);
|
&& historyContains(generator.state.schematicBlocks, block);
|
||||||
}
|
}
|
||||||
|
|
||||||
private void handleSchematicEndBlock() {
|
private void handleSchematicEndBlock() {
|
||||||
cleanup.removeSchematicBlocks();
|
cleanup.removeSchematicBlocks();
|
||||||
|
|
||||||
// Continue normal generation
|
// Continue normal generation
|
||||||
generator.generate(GENERATION_LEAD);
|
generator.generate(GENERATION_LEAD);
|
||||||
}
|
}
|
||||||
|
|
||||||
private boolean isSchematicEndBlock(@NotNull Block block) {
|
private boolean isSchematicEndBlock(@NotNull Block block) {
|
||||||
final List<Block> schematicBlocks = generator.state.schematicBlocks;
|
final List<Block> schematicBlocks = generator.state.schematicBlocks;
|
||||||
if (schematicBlocks == null || schematicBlocks.isEmpty()) {
|
if (schematicBlocks == null || schematicBlocks.isEmpty()) {
|
||||||
|
|
@ -147,7 +147,7 @@ public class PlayerInteractionHandler {
|
||||||
final Block last = schematicBlocks.get(schematicBlocks.size() - 1);
|
final Block last = schematicBlocks.get(schematicBlocks.size() - 1);
|
||||||
return isSameBlock(block, last);
|
return isSameBlock(block, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Block directly under feet; {@code null} in air — scoring runs when landed. */
|
/** Block directly under feet; {@code null} in air — scoring runs when landed. */
|
||||||
@Nullable
|
@Nullable
|
||||||
private Block getBlockBelow(@NotNull ParkourPlayer player) {
|
private Block getBlockBelow(@NotNull ParkourPlayer player) {
|
||||||
|
|
|
||||||
|
|
@ -38,4 +38,4 @@ public class PAPIHook extends PlaceholderExpansion {
|
||||||
public String onPlaceholderRequest(Player player, @NotNull String params) {
|
public String onPlaceholderRequest(Player player, @NotNull String params) {
|
||||||
return dispatcher.dispatch(player, params);
|
return dispatcher.dispatch(player, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -20,4 +20,4 @@ class PlaceholderDispatcher {
|
||||||
}
|
}
|
||||||
return playerResolver.resolve(player, params);
|
return playerResolver.resolve(player, params);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -55,4 +55,4 @@ public class GlobalPlaceholderResolver {
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -32,4 +32,4 @@ class PlaceholderFormatters {
|
||||||
return parseDifficulty(2.0);
|
return parseDifficulty(2.0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -101,4 +101,4 @@ public class PlayerPlaceholderResolver {
|
||||||
return "0";
|
return "0";
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -53,4 +53,4 @@ class ScoreRankResolver {
|
||||||
}
|
}
|
||||||
return String.valueOf(valueFunction.apply(score));
|
return String.valueOf(valueFunction.apply(score));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import org.jetbrains.annotations.NotNull;
|
||||||
*/
|
*/
|
||||||
public class MenuItem {
|
public class MenuItem {
|
||||||
private final ItemStack item;
|
private final ItemStack item;
|
||||||
|
|
||||||
public MenuItem(@NotNull ItemStack item) {
|
public MenuItem(@NotNull ItemStack item) {
|
||||||
this.item = item;
|
this.item = item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack getItem() {
|
public ItemStack getItem() {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,11 @@ import java.util.function.Consumer;
|
||||||
* Temporary stub for SliderItem during migration
|
* Temporary stub for SliderItem during migration
|
||||||
*/
|
*/
|
||||||
public class SliderItem {
|
public class SliderItem {
|
||||||
|
|
||||||
public SliderItem initial(int value) {
|
public SliderItem initial(int value) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public SliderItem add(int index, Item item, Consumer<InventoryClickEvent> handler) {
|
public SliderItem add(int index, Item item, Consumer<InventoryClickEvent> handler) {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -46,4 +46,4 @@ class BarrierGenerator extends ParkourGenerator {
|
||||||
public Mode getMode() {
|
public Mode getMode() {
|
||||||
return Modes.INVISIBLE_BARRIER;
|
return Modes.INVISIBLE_BARRIER;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -156,4 +156,4 @@ class BarrierRenderer {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -47,4 +47,4 @@ public class InvisibleBarrierMode implements Mode {
|
||||||
player.closeInventory();
|
player.closeInventory();
|
||||||
Session.create(session -> new BarrierGenerator(session), null, null, player);
|
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) {
|
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))) {
|
if (Boolean.parseBoolean(Option.OPTIONS_DEFAULTS.get(ParkourOption.SCOREBOARD))) {
|
||||||
this.board = Bukkit.getScoreboardManager().getNewScoreboard();
|
this.board = Bukkit.getScoreboardManager().getNewScoreboard();
|
||||||
this.scoreboardManager = new ScoreboardManager(player, player.getUniqueId(), board, locale);
|
this.scoreboardManager = new ScoreboardManager(player, player.getUniqueId(), board, locale);
|
||||||
|
|
||||||
final Objective obj = this.board.registerNewObjective("lp_sidebar", "dummy",
|
final Objective obj = this.board.registerNewObjective("lp_sidebar", "dummy",
|
||||||
ColorUtil.color(Locales.getString(locale, "scoreboard.title")));
|
ColorUtil.color(Locales.getString(locale, "scoreboard.title")));
|
||||||
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
|
obj.setDisplaySlot(DisplaySlot.SIDEBAR);
|
||||||
|
|
|
||||||
|
|
@ -18,4 +18,4 @@ final class PlayerPersistence {
|
||||||
write.run();
|
write.run();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -28,4 +28,4 @@ final class PlayerScoringTracker {
|
||||||
private static String blockKey(Block block) {
|
private static String blockKey(Block block) {
|
||||||
return block.getX() + "," + block.getY() + "," + block.getZ();
|
return block.getX() + "," + block.getY() + "," + block.getZ();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -31,4 +31,4 @@ final class PlayerSpawnSetup {
|
||||||
void updateHotbar(ParkourPlayer player) {
|
void updateHotbar(ParkourPlayer player) {
|
||||||
ParkourHotbar.apply(player);
|
ParkourHotbar.apply(player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -50,7 +50,7 @@ public class Rewards {
|
||||||
INTERVAL_REWARDS = parseScores("interval-rewards");
|
INTERVAL_REWARDS = parseScores("interval-rewards");
|
||||||
ONE_TIME_REWARDS = parseScores("one-time-rewards");
|
ONE_TIME_REWARDS = parseScores("one-time-rewards");
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all reward maps to prevent memory leaks on reload
|
* 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.
|
* Coordinates player management and state management.
|
||||||
*/
|
*/
|
||||||
public class Session {
|
public class Session {
|
||||||
|
|
||||||
public ParkourGenerator generator;
|
public ParkourGenerator generator;
|
||||||
|
|
||||||
private final SessionPlayerManager playerManager;
|
private final SessionPlayerManager playerManager;
|
||||||
private final SessionStateManager stateManager;
|
private final SessionStateManager stateManager;
|
||||||
|
|
||||||
private Session() {
|
private Session() {
|
||||||
this.playerManager = new SessionPlayerManager(this);
|
this.playerManager = new SessionPlayerManager(this);
|
||||||
this.stateManager = new SessionStateManager(this);
|
this.stateManager = new SessionStateManager(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a new session with specified parameters.
|
* Create a new session with specified parameters.
|
||||||
*/
|
*/
|
||||||
|
|
@ -40,9 +40,9 @@ public class Session {
|
||||||
Function<Session, Boolean> isAcceptingPlayers,
|
Function<Session, Boolean> isAcceptingPlayers,
|
||||||
Function<Session, Boolean> isAcceptingSpectators,
|
Function<Session, Boolean> isAcceptingSpectators,
|
||||||
Player... players) {
|
Player... players) {
|
||||||
|
|
||||||
final Session session = new Session();
|
final Session session = new Session();
|
||||||
|
|
||||||
// Set acceptance functions
|
// Set acceptance functions
|
||||||
if (isAcceptingPlayers != null) {
|
if (isAcceptingPlayers != null) {
|
||||||
session.playerManager.setAcceptingPlayers(isAcceptingPlayers);
|
session.playerManager.setAcceptingPlayers(isAcceptingPlayers);
|
||||||
|
|
@ -50,7 +50,7 @@ public class Session {
|
||||||
if (isAcceptingSpectators != null) {
|
if (isAcceptingSpectators != null) {
|
||||||
session.playerManager.setAcceptingSpectators(isAcceptingSpectators);
|
session.playerManager.setAcceptingSpectators(isAcceptingSpectators);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add initial players
|
// Add initial players
|
||||||
final List<ParkourPlayer> parkourPlayers = new ArrayList<>();
|
final List<ParkourPlayer> parkourPlayers = new ArrayList<>();
|
||||||
if (players != null) {
|
if (players != null) {
|
||||||
|
|
@ -60,97 +60,97 @@ public class Session {
|
||||||
parkourPlayers.add(pp);
|
parkourPlayers.add(pp);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize session state
|
// Initialize session state
|
||||||
session.stateManager.initialize(generatorFunction);
|
session.stateManager.initialize(generatorFunction);
|
||||||
|
|
||||||
// Update generator settings for players
|
// Update generator settings for players
|
||||||
if (session.generator != null) {
|
if (session.generator != null) {
|
||||||
parkourPlayers.forEach(p -> p.updateGeneratorSettings(session.generator));
|
parkourPlayers.forEach(p -> p.updateGeneratorSettings(session.generator));
|
||||||
}
|
}
|
||||||
|
|
||||||
return session;
|
return session;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Visibility management
|
// Visibility management
|
||||||
public void setVisibility(@NotNull Visibility visibility) {
|
public void setVisibility(@NotNull Visibility visibility) {
|
||||||
stateManager.setVisibility(visibility);
|
stateManager.setVisibility(visibility);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public Visibility getVisibility() {
|
public Visibility getVisibility() {
|
||||||
return stateManager.getVisibility();
|
return stateManager.getVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Player management
|
// Player management
|
||||||
public void addPlayers(@NotNull ParkourPlayer... toAdd) {
|
public void addPlayers(@NotNull ParkourPlayer... toAdd) {
|
||||||
playerManager.addPlayers(toAdd);
|
playerManager.addPlayers(toAdd);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
|
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
|
||||||
playerManager.removePlayers(toRemove);
|
playerManager.removePlayers(toRemove);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<ParkourPlayer> getPlayers() {
|
public List<ParkourPlayer> getPlayers() {
|
||||||
return playerManager.getPlayers();
|
return playerManager.getPlayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Spectator management
|
// Spectator management
|
||||||
public void addSpectators(@NotNull ParkourSpectator... spectators) {
|
public void addSpectators(@NotNull ParkourSpectator... spectators) {
|
||||||
playerManager.addSpectators(spectators);
|
playerManager.addSpectators(spectators);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void removeSpectators(@NotNull ParkourSpectator... spectators) {
|
public void removeSpectators(@NotNull ParkourSpectator... spectators) {
|
||||||
playerManager.removeSpectators(spectators);
|
playerManager.removeSpectators(spectators);
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<ParkourSpectator> getSpectators() {
|
public List<ParkourSpectator> getSpectators() {
|
||||||
return playerManager.getSpectators();
|
return playerManager.getSpectators();
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public List<ParkourUser> getUsers() {
|
public List<ParkourUser> getUsers() {
|
||||||
return playerManager.getUsers();
|
return playerManager.getUsers();
|
||||||
}
|
}
|
||||||
|
|
||||||
// State management
|
// State management
|
||||||
public Location getSpawnLocation() {
|
public Location getSpawnLocation() {
|
||||||
return stateManager.getSpawnLocation();
|
return stateManager.getSpawnLocation();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void toggleMute(@NotNull ParkourUser user) {
|
public void toggleMute(@NotNull ParkourUser user) {
|
||||||
stateManager.toggleMute(user);
|
stateManager.toggleMute(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isMuted(@NotNull ParkourUser user) {
|
public boolean isMuted(@NotNull ParkourUser user) {
|
||||||
return stateManager.isMuted(user);
|
return stateManager.isMuted(user);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Acceptance checks
|
// Acceptance checks
|
||||||
public boolean isAcceptingPlayers() {
|
public boolean isAcceptingPlayers() {
|
||||||
return playerManager.isAcceptingPlayers();
|
return playerManager.isAcceptingPlayers();
|
||||||
}
|
}
|
||||||
|
|
||||||
public boolean isAcceptingSpectators() {
|
public boolean isAcceptingSpectators() {
|
||||||
return playerManager.isAcceptingSpectators();
|
return playerManager.isAcceptingSpectators();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Lifecycle
|
// Lifecycle
|
||||||
public void onAllPlayersLeft() {
|
public void onAllPlayersLeft() {
|
||||||
stateManager.cleanup();
|
stateManager.cleanup();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void setGenerator(@NotNull ParkourGenerator generator) {
|
public void setGenerator(@NotNull ParkourGenerator generator) {
|
||||||
this.generator = generator;
|
this.generator = generator;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Enums
|
// Enums
|
||||||
public enum Visibility {
|
public enum Visibility {
|
||||||
PRIVATE, ID_ONLY, PUBLIC
|
PRIVATE, ID_ONLY, PUBLIC
|
||||||
}
|
}
|
||||||
|
|
||||||
public enum ChatType {
|
public enum ChatType {
|
||||||
LOBBY_ONLY, PLAYERS_ONLY, PUBLIC
|
LOBBY_ONLY, PLAYERS_ONLY, PUBLIC
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,46 +16,46 @@ import java.util.function.Function;
|
||||||
* Manages players and spectators in a session.
|
* Manages players and spectators in a session.
|
||||||
*/
|
*/
|
||||||
public class SessionPlayerManager {
|
public class SessionPlayerManager {
|
||||||
|
|
||||||
private final Session session;
|
private final Session session;
|
||||||
private final List<ParkourPlayer> players = new ArrayList<>();
|
private final List<ParkourPlayer> players = new ArrayList<>();
|
||||||
private final List<ParkourSpectator> spectators = new ArrayList<>();
|
private final List<ParkourSpectator> spectators = new ArrayList<>();
|
||||||
|
|
||||||
private Function<Session, Boolean> isAcceptingPlayers = s -> false;
|
private Function<Session, Boolean> isAcceptingPlayers = s -> false;
|
||||||
private Function<Session, Boolean> isAcceptingSpectators = s -> s.getVisibility() == Session.Visibility.PUBLIC;
|
private Function<Session, Boolean> isAcceptingSpectators = s -> s.getVisibility() == Session.Visibility.PUBLIC;
|
||||||
|
|
||||||
public SessionPlayerManager(@NotNull Session session) {
|
public SessionPlayerManager(@NotNull Session session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set player acceptance function.
|
* Set player acceptance function.
|
||||||
*/
|
*/
|
||||||
public void setAcceptingPlayers(@NotNull Function<Session, Boolean> function) {
|
public void setAcceptingPlayers(@NotNull Function<Session, Boolean> function) {
|
||||||
this.isAcceptingPlayers = function;
|
this.isAcceptingPlayers = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set spectator acceptance function.
|
* Set spectator acceptance function.
|
||||||
*/
|
*/
|
||||||
public void setAcceptingSpectators(@NotNull Function<Session, Boolean> function) {
|
public void setAcceptingSpectators(@NotNull Function<Session, Boolean> function) {
|
||||||
this.isAcceptingSpectators = function;
|
this.isAcceptingSpectators = function;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if session is accepting players.
|
* Check if session is accepting players.
|
||||||
*/
|
*/
|
||||||
public boolean isAcceptingPlayers() {
|
public boolean isAcceptingPlayers() {
|
||||||
return isAcceptingPlayers.apply(session);
|
return isAcceptingPlayers.apply(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if session is accepting spectators.
|
* Check if session is accepting spectators.
|
||||||
*/
|
*/
|
||||||
public boolean isAcceptingSpectators() {
|
public boolean isAcceptingSpectators() {
|
||||||
return isAcceptingSpectators.apply(session);
|
return isAcceptingSpectators.apply(session);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add players to session.
|
* Add players to session.
|
||||||
*/
|
*/
|
||||||
|
|
@ -63,20 +63,20 @@ public class SessionPlayerManager {
|
||||||
players.addAll(Arrays.asList(toAdd));
|
players.addAll(Arrays.asList(toAdd));
|
||||||
updateVisibility();
|
updateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove players from session.
|
* Remove players from session.
|
||||||
*/
|
*/
|
||||||
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
|
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
|
||||||
players.removeAll(Arrays.asList(toRemove));
|
players.removeAll(Arrays.asList(toRemove));
|
||||||
|
|
||||||
if (players.isEmpty()) {
|
if (players.isEmpty()) {
|
||||||
session.onAllPlayersLeft();
|
session.onAllPlayersLeft();
|
||||||
} else {
|
} else {
|
||||||
updateVisibility();
|
updateVisibility();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add spectators to session.
|
* Add spectators to session.
|
||||||
*/
|
*/
|
||||||
|
|
@ -84,7 +84,7 @@ public class SessionPlayerManager {
|
||||||
spectators.addAll(Arrays.asList(toAdd));
|
spectators.addAll(Arrays.asList(toAdd));
|
||||||
updateVisibility();
|
updateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove spectators from session.
|
* Remove spectators from session.
|
||||||
*/
|
*/
|
||||||
|
|
@ -92,7 +92,7 @@ public class SessionPlayerManager {
|
||||||
spectators.removeAll(Arrays.asList(toRemove));
|
spectators.removeAll(Arrays.asList(toRemove));
|
||||||
updateVisibility();
|
updateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all players.
|
* Get all players.
|
||||||
*/
|
*/
|
||||||
|
|
@ -100,7 +100,7 @@ public class SessionPlayerManager {
|
||||||
public List<ParkourPlayer> getPlayers() {
|
public List<ParkourPlayer> getPlayers() {
|
||||||
return new ArrayList<>(players);
|
return new ArrayList<>(players);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all spectators.
|
* Get all spectators.
|
||||||
*/
|
*/
|
||||||
|
|
@ -108,7 +108,7 @@ public class SessionPlayerManager {
|
||||||
public List<ParkourSpectator> getSpectators() {
|
public List<ParkourSpectator> getSpectators() {
|
||||||
return new ArrayList<>(spectators);
|
return new ArrayList<>(spectators);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get all users (players + spectators).
|
* Get all users (players + spectators).
|
||||||
*/
|
*/
|
||||||
|
|
@ -119,25 +119,25 @@ public class SessionPlayerManager {
|
||||||
users.addAll(spectators);
|
users.addAll(spectators);
|
||||||
return users;
|
return users;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get total user count.
|
* Get total user count.
|
||||||
*/
|
*/
|
||||||
public int getTotalUsers() {
|
public int getTotalUsers() {
|
||||||
return players.size() + spectators.size();
|
return players.size() + spectators.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if session has any users.
|
* Check if session has any users.
|
||||||
*/
|
*/
|
||||||
public boolean hasUsers() {
|
public boolean hasUsers() {
|
||||||
return !players.isEmpty() || !spectators.isEmpty();
|
return !players.isEmpty() || !spectators.isEmpty();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateVisibility() {
|
private void updateVisibility() {
|
||||||
// Update player visibility for all users
|
// Update player visibility for all users
|
||||||
final List<ParkourUser> allUsers = getUsers();
|
final List<ParkourUser> allUsers = getUsers();
|
||||||
|
|
||||||
for (final ParkourUser user : allUsers) {
|
for (final ParkourUser user : allUsers) {
|
||||||
for (final ParkourUser other : allUsers) {
|
for (final ParkourUser other : allUsers) {
|
||||||
if (!user.equals(other)) {
|
if (!user.equals(other)) {
|
||||||
|
|
|
||||||
|
|
@ -21,17 +21,17 @@ import java.util.function.Function;
|
||||||
* Manages session state and lifecycle.
|
* Manages session state and lifecycle.
|
||||||
*/
|
*/
|
||||||
public class SessionStateManager {
|
public class SessionStateManager {
|
||||||
|
|
||||||
private final Session session;
|
private final Session session;
|
||||||
private Location spawnLocation;
|
private Location spawnLocation;
|
||||||
private Session.Visibility visibility = Session.Visibility.PUBLIC;
|
private Session.Visibility visibility = Session.Visibility.PUBLIC;
|
||||||
private final Map<ParkourUser, Boolean> mutedUsers = new HashMap<>();
|
private final Map<ParkourUser, Boolean> mutedUsers = new HashMap<>();
|
||||||
private ScheduledTask tickTask = null;
|
private ScheduledTask tickTask = null;
|
||||||
|
|
||||||
public SessionStateManager(@NotNull Session session) {
|
public SessionStateManager(@NotNull Session session) {
|
||||||
this.session = session;
|
this.session = session;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Initialize session with generator and spawn location.
|
* Initialize session with generator and spawn location.
|
||||||
*/
|
*/
|
||||||
|
|
@ -50,7 +50,7 @@ public class SessionStateManager {
|
||||||
// Start tick cycle for generator
|
// Start tick cycle for generator
|
||||||
startTickCycle();
|
startTickCycle();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clean up session resources.
|
* Clean up session resources.
|
||||||
*/
|
*/
|
||||||
|
|
@ -98,14 +98,14 @@ public class SessionStateManager {
|
||||||
tickTask = null;
|
tickTask = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set session visibility.
|
* Set session visibility.
|
||||||
*/
|
*/
|
||||||
public void setVisibility(@NotNull Session.Visibility visibility) {
|
public void setVisibility(@NotNull Session.Visibility visibility) {
|
||||||
this.visibility = visibility;
|
this.visibility = visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get session visibility.
|
* Get session visibility.
|
||||||
*/
|
*/
|
||||||
|
|
@ -113,7 +113,7 @@ public class SessionStateManager {
|
||||||
public Session.Visibility getVisibility() {
|
public Session.Visibility getVisibility() {
|
||||||
return visibility;
|
return visibility;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get spawn location.
|
* Get spawn location.
|
||||||
*/
|
*/
|
||||||
|
|
@ -121,28 +121,28 @@ public class SessionStateManager {
|
||||||
public Location getSpawnLocation() {
|
public Location getSpawnLocation() {
|
||||||
return spawnLocation != null ? spawnLocation.clone() : null;
|
return spawnLocation != null ? spawnLocation.clone() : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Toggle mute status for user.
|
* Toggle mute status for user.
|
||||||
*/
|
*/
|
||||||
public void toggleMute(@NotNull ParkourUser user) {
|
public void toggleMute(@NotNull ParkourUser user) {
|
||||||
mutedUsers.put(user, !isMuted(user));
|
mutedUsers.put(user, !isMuted(user));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Check if user is muted.
|
* Check if user is muted.
|
||||||
*/
|
*/
|
||||||
public boolean isMuted(@NotNull ParkourUser user) {
|
public boolean isMuted(@NotNull ParkourUser user) {
|
||||||
return mutedUsers.getOrDefault(user, false);
|
return mutedUsers.getOrDefault(user, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get muted users count.
|
* Get muted users count.
|
||||||
*/
|
*/
|
||||||
public int getMutedUsersCount() {
|
public int getMutedUsersCount() {
|
||||||
return (int) mutedUsers.values().stream().filter(muted -> muted).count();
|
return (int) mutedUsers.values().stream().filter(muted -> muted).count();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Clear all muted users.
|
* Clear all muted users.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -37,21 +37,21 @@ public class SQLDataMapper {
|
||||||
@NotNull
|
@NotNull
|
||||||
public static Map<UUID, Score> mapScores(@NotNull ResultSet rs) throws SQLException {
|
public static Map<UUID, Score> mapScores(@NotNull ResultSet rs) throws SQLException {
|
||||||
final Map<UUID, Score> scores = new HashMap<>();
|
final Map<UUID, Score> scores = new HashMap<>();
|
||||||
|
|
||||||
while (rs.next()) {
|
while (rs.next()) {
|
||||||
final UUID uuid = UUID.fromString(rs.getString("uuid"));
|
final UUID uuid = UUID.fromString(rs.getString("uuid"));
|
||||||
final String name = rs.getString("name");
|
final String name = rs.getString("name");
|
||||||
final int score = rs.getInt("score");
|
final int score = rs.getInt("score");
|
||||||
final String time = rs.getString("time");
|
final String time = rs.getString("time");
|
||||||
final String difficulty = rs.getString("difficulty");
|
final String difficulty = rs.getString("difficulty");
|
||||||
|
|
||||||
final Score scoreObj = new Score(name, time, difficulty, score);
|
final Score scoreObj = new Score(name, time, difficulty, score);
|
||||||
scores.put(uuid, scoreObj);
|
scores.put(uuid, scoreObj);
|
||||||
}
|
}
|
||||||
|
|
||||||
return scores;
|
return scores;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set Score parameters in PreparedStatement.
|
* Set Score parameters in PreparedStatement.
|
||||||
*/
|
*/
|
||||||
|
|
@ -63,7 +63,7 @@ public class SQLDataMapper {
|
||||||
stmt.setString(DIFFICULTY_PARAM_INDEX, score.difficulty());
|
stmt.setString(DIFFICULTY_PARAM_INDEX, score.difficulty());
|
||||||
stmt.setLong(TIMESTAMP_PARAM_INDEX, System.currentTimeMillis());
|
stmt.setLong(TIMESTAMP_PARAM_INDEX, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Map ResultSet to ParkourPlayer data.
|
* Map ResultSet to ParkourPlayer data.
|
||||||
*/
|
*/
|
||||||
|
|
@ -72,17 +72,17 @@ public class SQLDataMapper {
|
||||||
if (!rs.next()) {
|
if (!rs.next()) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
final UUID uuid = UUID.fromString(rs.getString("uuid"));
|
final UUID uuid = UUID.fromString(rs.getString("uuid"));
|
||||||
final String name = rs.getString("name");
|
final String name = rs.getString("name");
|
||||||
final String locale = rs.getString("locale");
|
final String locale = rs.getString("locale");
|
||||||
final String styleName = rs.getString("style");
|
final String styleName = rs.getString("style");
|
||||||
final String settings = rs.getString("settings");
|
final String settings = rs.getString("settings");
|
||||||
final long lastSeen = rs.getLong("last_seen");
|
final long lastSeen = rs.getLong("last_seen");
|
||||||
|
|
||||||
return new PlayerData(uuid, name, locale, styleName, settings, lastSeen);
|
return new PlayerData(uuid, name, locale, styleName, settings, lastSeen);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Set ParkourPlayer parameters in PreparedStatement.
|
* Set ParkourPlayer parameters in PreparedStatement.
|
||||||
*/
|
*/
|
||||||
|
|
@ -94,7 +94,7 @@ public class SQLDataMapper {
|
||||||
stmt.setString(SETTINGS_PARAM_INDEX, serializeSettings(player));
|
stmt.setString(SETTINGS_PARAM_INDEX, serializeSettings(player));
|
||||||
stmt.setLong(TIMESTAMP_PARAM_INDEX, System.currentTimeMillis());
|
stmt.setLong(TIMESTAMP_PARAM_INDEX, System.currentTimeMillis());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Apply player data to ParkourPlayer object.
|
* Apply player data to ParkourPlayer object.
|
||||||
*/
|
*/
|
||||||
|
|
@ -114,7 +114,7 @@ public class SQLDataMapper {
|
||||||
player.setSettings(new HashMap<>());
|
player.setSettings(new HashMap<>());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static String serializeSettings(@NotNull ParkourPlayer player) {
|
private static String serializeSettings(@NotNull ParkourPlayer player) {
|
||||||
final Map<String, Object> settings = new HashMap<>();
|
final Map<String, Object> settings = new HashMap<>();
|
||||||
|
|
@ -132,7 +132,7 @@ public class SQLDataMapper {
|
||||||
settings.put("sound", player.sound);
|
settings.put("sound", player.sound);
|
||||||
return LoParkour.getGson().toJson(settings);
|
return LoParkour.getGson().toJson(settings);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void deserializeSettings(@NotNull ParkourPlayer player, @NotNull String settings) {
|
private static void deserializeSettings(@NotNull ParkourPlayer player, @NotNull String settings) {
|
||||||
final Type type = new TypeToken<Map<String, Object>>() {}.getType();
|
final Type type = new TypeToken<Map<String, Object>>() {}.getType();
|
||||||
final Map<String, Object> parsed = LoParkour.getGson().fromJson(settings, type);
|
final Map<String, Object> parsed = LoParkour.getGson().fromJson(settings, type);
|
||||||
|
|
@ -143,7 +143,7 @@ public class SQLDataMapper {
|
||||||
normalizeNumericSettings(parsed);
|
normalizeNumericSettings(parsed);
|
||||||
player.setSettings(parsed);
|
player.setSettings(parsed);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static void normalizeNumericSettings(@NotNull Map<String, Object> settings) {
|
private static void normalizeNumericSettings(@NotNull Map<String, Object> settings) {
|
||||||
for (final Map.Entry<String, Object> entry : settings.entrySet()) {
|
for (final Map.Entry<String, Object> entry : settings.entrySet()) {
|
||||||
final Object value = entry.getValue();
|
final Object value = entry.getValue();
|
||||||
|
|
@ -155,7 +155,7 @@ public class SQLDataMapper {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Player data record for mapping.
|
* Player data record for mapping.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -131,4 +131,4 @@ public class StorageSQL {
|
||||||
}
|
}
|
||||||
SQLPlayerRepository.writePlayer(connectionManager, player);
|
SQLPlayerRepository.writePlayer(connectionManager, player);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ public class SQLQueryBuilder {
|
||||||
)
|
)
|
||||||
""", tableName);
|
""", tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build CREATE TABLE query for players.
|
* Build CREATE TABLE query for players.
|
||||||
*/
|
*/
|
||||||
|
|
@ -43,7 +43,7 @@ public class SQLQueryBuilder {
|
||||||
)
|
)
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build SELECT query for scores.
|
* Build SELECT query for scores.
|
||||||
*/
|
*/
|
||||||
|
|
@ -54,7 +54,7 @@ public class SQLQueryBuilder {
|
||||||
tableName
|
tableName
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build INSERT/UPDATE query for scores.
|
* Build INSERT/UPDATE query for scores.
|
||||||
*/
|
*/
|
||||||
|
|
@ -71,7 +71,7 @@ public class SQLQueryBuilder {
|
||||||
timestamp = VALUES(timestamp)
|
timestamp = VALUES(timestamp)
|
||||||
""", tableName);
|
""", tableName);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build SELECT query for player data.
|
* Build SELECT query for player data.
|
||||||
*/
|
*/
|
||||||
|
|
@ -79,7 +79,7 @@ public class SQLQueryBuilder {
|
||||||
public static String selectPlayer() {
|
public static String selectPlayer() {
|
||||||
return "SELECT uuid, name, locale, style, settings, last_seen FROM players WHERE uuid = ?";
|
return "SELECT uuid, name, locale, style, settings, last_seen FROM players WHERE uuid = ?";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Build INSERT/UPDATE query for player data.
|
* Build INSERT/UPDATE query for player data.
|
||||||
*/
|
*/
|
||||||
|
|
@ -96,7 +96,7 @@ public class SQLQueryBuilder {
|
||||||
last_seen = VALUES(last_seen)
|
last_seen = VALUES(last_seen)
|
||||||
""";
|
""";
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get table name for specific mode.
|
* Get table name for specific mode.
|
||||||
*/
|
*/
|
||||||
|
|
|
||||||
|
|
@ -65,4 +65,4 @@ public class SQLPlayerRepository {
|
||||||
LOGGER.severe("Failed to write player data: " + e.getMessage());
|
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());
|
LOGGER.severe("Failed to write scores for mode " + mode + ": " + e.getMessage());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,4 +56,4 @@ public class SQLSchemaManager {
|
||||||
stmt.executeUpdate();
|
stmt.executeUpdate();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -17,7 +17,7 @@ import java.util.function.Function;
|
||||||
public class Item {
|
public class Item {
|
||||||
private final ItemStack item;
|
private final ItemStack item;
|
||||||
private Consumer<org.bukkit.event.inventory.InventoryClickEvent> clickHandler;
|
private Consumer<org.bukkit.event.inventory.InventoryClickEvent> clickHandler;
|
||||||
|
|
||||||
public Item(@NotNull Material material, @NotNull String name) {
|
public Item(@NotNull Material material, @NotNull String name) {
|
||||||
this.item = new ItemStack(material);
|
this.item = new ItemStack(material);
|
||||||
final ItemMeta meta = item.getItemMeta();
|
final ItemMeta meta = item.getItemMeta();
|
||||||
|
|
@ -26,7 +26,7 @@ public class Item {
|
||||||
item.setItemMeta(meta);
|
item.setItemMeta(meta);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item lore(@NotNull String... lore) {
|
public Item lore(@NotNull String... lore) {
|
||||||
final ItemMeta meta = item.getItemMeta();
|
final ItemMeta meta = item.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
|
|
@ -39,7 +39,7 @@ public class Item {
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item lore(@NotNull List<String> lore) {
|
public Item lore(@NotNull List<String> lore) {
|
||||||
final ItemMeta meta = item.getItemMeta();
|
final ItemMeta meta = item.getItemMeta();
|
||||||
if (meta != null) {
|
if (meta != null) {
|
||||||
|
|
@ -52,17 +52,17 @@ public class Item {
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item material(@NotNull Material material) {
|
public Item material(@NotNull Material material) {
|
||||||
item.setType(material);
|
item.setType(material);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item click(@NotNull Consumer<org.bukkit.event.inventory.InventoryClickEvent> handler) {
|
public Item click(@NotNull Consumer<org.bukkit.event.inventory.InventoryClickEvent> handler) {
|
||||||
this.clickHandler = handler;
|
this.clickHandler = handler;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item modifyLore(@NotNull Function<String, String> modifier) {
|
public Item modifyLore(@NotNull Function<String, String> modifier) {
|
||||||
final ItemMeta meta = item.getItemMeta();
|
final ItemMeta meta = item.getItemMeta();
|
||||||
if (meta != null && meta.hasLore()) {
|
if (meta != null && meta.hasLore()) {
|
||||||
|
|
@ -78,7 +78,7 @@ public class Item {
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item modifyName(@NotNull Function<String, String> modifier) {
|
public Item modifyName(@NotNull Function<String, String> modifier) {
|
||||||
final ItemMeta meta = item.getItemMeta();
|
final ItemMeta meta = item.getItemMeta();
|
||||||
if (meta != null && meta.hasDisplayName()) {
|
if (meta != null && meta.hasDisplayName()) {
|
||||||
|
|
@ -87,12 +87,12 @@ public class Item {
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Item meta(@NotNull ItemMeta meta) {
|
public Item meta(@NotNull ItemMeta meta) {
|
||||||
item.setItemMeta(meta);
|
item.setItemMeta(meta);
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@SuppressWarnings("NoClone")
|
@SuppressWarnings("NoClone")
|
||||||
public Item clone() {
|
public Item clone() {
|
||||||
|
|
@ -101,11 +101,11 @@ public class Item {
|
||||||
cloned.clickHandler = this.clickHandler;
|
cloned.clickHandler = this.clickHandler;
|
||||||
return cloned;
|
return cloned;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ItemStack build() {
|
public ItemStack build() {
|
||||||
return item;
|
return item;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Consumer<org.bukkit.event.inventory.InventoryClickEvent> getClickHandler() {
|
public Consumer<org.bukkit.event.inventory.InventoryClickEvent> getClickHandler() {
|
||||||
return clickHandler;
|
return clickHandler;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -34,7 +34,7 @@ public class Probs {
|
||||||
public static <T> T random(Map<T, Double> chances, Random random) {
|
public static <T> T random(Map<T, Double> chances, Random random) {
|
||||||
final double totalWeight = chances.values().stream().mapToDouble(Double::doubleValue).sum();
|
final double totalWeight = chances.values().stream().mapToDouble(Double::doubleValue).sum();
|
||||||
final double randomValue = random.nextDouble() * totalWeight;
|
final double randomValue = random.nextDouble() * totalWeight;
|
||||||
|
|
||||||
double currentWeight = 0;
|
double currentWeight = 0;
|
||||||
for (final Map.Entry<T, Double> entry : chances.entrySet()) {
|
for (final Map.Entry<T, Double> entry : chances.entrySet()) {
|
||||||
currentWeight += entry.getValue();
|
currentWeight += entry.getValue();
|
||||||
|
|
@ -42,7 +42,7 @@ public class Probs {
|
||||||
return entry.getKey();
|
return entry.getKey();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fallback to first entry
|
// Fallback to first entry
|
||||||
return chances.keySet().iterator().next();
|
return chances.keySet().iterator().next();
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,62 +15,62 @@ public class ParticleData<T> {
|
||||||
private double offsetX = 0.0;
|
private double offsetX = 0.0;
|
||||||
private double offsetY = 0.0;
|
private double offsetY = 0.0;
|
||||||
private double offsetZ = 0.0;
|
private double offsetZ = 0.0;
|
||||||
|
|
||||||
public ParticleData(@NotNull Particle particle, @Nullable T data, int size) {
|
public ParticleData(@NotNull Particle particle, @Nullable T data, int size) {
|
||||||
this.particle = particle;
|
this.particle = particle;
|
||||||
this.data = data;
|
this.data = data;
|
||||||
this.size = size;
|
this.size = size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParticleData<T> size(int size) {
|
public ParticleData<T> size(int size) {
|
||||||
this.size = size;
|
this.size = size;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParticleData<T> speed(double speed) {
|
public ParticleData<T> speed(double speed) {
|
||||||
this.speed = speed;
|
this.speed = speed;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParticleData<T> offsetX(double offsetX) {
|
public ParticleData<T> offsetX(double offsetX) {
|
||||||
this.offsetX = offsetX;
|
this.offsetX = offsetX;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParticleData<T> offsetY(double offsetY) {
|
public ParticleData<T> offsetY(double offsetY) {
|
||||||
this.offsetY = offsetY;
|
this.offsetY = offsetY;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ParticleData<T> offsetZ(double offsetZ) {
|
public ParticleData<T> offsetZ(double offsetZ) {
|
||||||
this.offsetZ = offsetZ;
|
this.offsetZ = offsetZ;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
public Particle getParticle() {
|
public Particle getParticle() {
|
||||||
return particle;
|
return particle;
|
||||||
}
|
}
|
||||||
|
|
||||||
public T getData() {
|
public T getData() {
|
||||||
return data;
|
return data;
|
||||||
}
|
}
|
||||||
|
|
||||||
public int getSize() {
|
public int getSize() {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getSpeed() {
|
public double getSpeed() {
|
||||||
return speed;
|
return speed;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getOffsetX() {
|
public double getOffsetX() {
|
||||||
return offsetX;
|
return offsetX;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getOffsetY() {
|
public double getOffsetY() {
|
||||||
return offsetY;
|
return offsetY;
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getOffsetZ() {
|
public double getOffsetZ() {
|
||||||
return offsetZ;
|
return offsetZ;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -16,7 +16,7 @@ import static org.junit.jupiter.api.Assertions.*;
|
||||||
class JumpValidatorTest {
|
class JumpValidatorTest {
|
||||||
|
|
||||||
private JumpValidator validator;
|
private JumpValidator validator;
|
||||||
|
|
||||||
@Mock
|
@Mock
|
||||||
private World world;
|
private World world;
|
||||||
|
|
||||||
|
|
@ -31,7 +31,7 @@ class JumpValidatorTest {
|
||||||
// 1 block forward, same height - always possible
|
// 1 block forward, same height - always possible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 1, 100, 0);
|
Location to = new Location(world, 1, 100, 0);
|
||||||
|
|
||||||
assertTrue(validator.canJump(from, to), "1 block jump at same level should be possible");
|
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
|
// 4 blocks forward, same height - possible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 4, 100, 0);
|
Location to = new Location(world, 4, 100, 0);
|
||||||
|
|
||||||
assertTrue(validator.canJump(from, to), "4 block jump at same level should be possible");
|
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
|
// 5 blocks forward, same height - impossible without speed
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 5, 100, 0);
|
Location to = new Location(world, 5, 100, 0);
|
||||||
|
|
||||||
assertFalse(validator.canJump(from, to), "5 block jump at same level should be impossible");
|
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
|
// 3 blocks forward, 1 block up - possible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 3, 101, 0);
|
Location to = new Location(world, 3, 101, 0);
|
||||||
|
|
||||||
assertTrue(validator.canJump(from, to), "3 block jump with 1 up should be possible");
|
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
|
// 4 blocks forward, 1 block up - impossible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 4, 101, 0);
|
Location to = new Location(world, 4, 101, 0);
|
||||||
|
|
||||||
assertFalse(validator.canJump(from, to), "4 block jump with 1 up should be impossible");
|
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
|
// 4 blocks forward, 1 block down - possible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 4, 99, 0);
|
Location to = new Location(world, 4, 99, 0);
|
||||||
|
|
||||||
assertTrue(validator.canJump(from, to), "4 block jump with 1 down should be possible");
|
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
|
// 4 blocks forward, 2 blocks down - possible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 4, 98, 0);
|
Location to = new Location(world, 4, 98, 0);
|
||||||
|
|
||||||
assertTrue(validator.canJump(from, to), "4 block jump with 2 down should be possible");
|
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)
|
// 1 block forward, 2 blocks up - impossible (max jump height is 1.25)
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 1, 102, 0);
|
Location to = new Location(world, 1, 102, 0);
|
||||||
|
|
||||||
assertFalse(validator.canJump(from, to), "Jump 2 blocks up should be impossible");
|
assertFalse(validator.canJump(from, to), "Jump 2 blocks up should be impossible");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -112,11 +112,11 @@ class JumpValidatorTest {
|
||||||
void testCanJump_NullLocations() {
|
void testCanJump_NullLocations() {
|
||||||
// Test null safety
|
// Test null safety
|
||||||
Location validLoc = new Location(world, 0, 100, 0);
|
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");
|
"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");
|
"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");
|
"Should return false for both null locations");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -124,7 +124,7 @@ class JumpValidatorTest {
|
||||||
void testCanJump_SameLocation() {
|
void testCanJump_SameLocation() {
|
||||||
// Jump to same location - should be false
|
// Jump to same location - should be false
|
||||||
Location loc = new Location(world, 0, 100, 0);
|
Location loc = new Location(world, 0, 100, 0);
|
||||||
|
|
||||||
assertFalse(validator.canJump(loc, loc), "Jump to same location should be impossible");
|
assertFalse(validator.canJump(loc, loc), "Jump to same location should be impossible");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -133,7 +133,7 @@ class JumpValidatorTest {
|
||||||
// 10 blocks forward - impossible
|
// 10 blocks forward - impossible
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 10, 100, 0);
|
Location to = new Location(world, 10, 100, 0);
|
||||||
|
|
||||||
assertFalse(validator.canJump(from, to), "10 block jump should be impossible");
|
assertFalse(validator.canJump(from, to), "10 block jump should be impossible");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -144,7 +144,7 @@ class JumpValidatorTest {
|
||||||
// but it documents the expected behavior
|
// but it documents the expected behavior
|
||||||
Location from = new Location(world, 0, 100, 0);
|
Location from = new Location(world, 0, 100, 0);
|
||||||
Location to = new Location(world, 2, 101, 0);
|
Location to = new Location(world, 2, 101, 0);
|
||||||
|
|
||||||
// This should still pass with mock objects (no slab detection)
|
// 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");
|
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<>();
|
List<GhostFrame> frames = new ArrayList<>();
|
||||||
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
|
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
|
||||||
frames.add(new GhostFrame(1000, 1, 100, 0, 90, 0));
|
frames.add(new GhostFrame(1000, 1, 100, 0, 90, 0));
|
||||||
|
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
GhostData data = new GhostData(uuid, "TestPlayer", 42, frames);
|
GhostData data = new GhostData(uuid, "TestPlayer", 42, frames);
|
||||||
|
|
||||||
assertEquals("TestPlayer", data.getPlayerName());
|
assertEquals("TestPlayer", data.getPlayerName());
|
||||||
assertEquals(uuid, data.getPlayerUuid());
|
assertEquals(uuid, data.getPlayerUuid());
|
||||||
assertEquals(42, data.getScore());
|
assertEquals(42, data.getScore());
|
||||||
|
|
@ -47,21 +47,21 @@ class GhostDataTest {
|
||||||
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
|
frames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
|
||||||
frames.add(new GhostFrame(500, 1, 100, 0, 45, 0));
|
frames.add(new GhostFrame(500, 1, 100, 0, 45, 0));
|
||||||
frames.add(new GhostFrame(1000, 2, 100, 0, 90, 0));
|
frames.add(new GhostFrame(1000, 2, 100, 0, 90, 0));
|
||||||
|
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
long timestamp = 1_700_000_000_000L;
|
long timestamp = 1_700_000_000_000L;
|
||||||
GhostData original = new GhostData(uuid, "Player1", 100, timestamp, "world", frames);
|
GhostData original = new GhostData(uuid, "Player1", 100, timestamp, "world", frames);
|
||||||
|
|
||||||
// Save to file
|
// Save to file
|
||||||
File file = tempDir.resolve("test.ghost").toFile();
|
File file = tempDir.resolve("test.ghost").toFile();
|
||||||
original.saveToFile(file);
|
original.saveToFile(file);
|
||||||
|
|
||||||
assertTrue(file.exists(), "Ghost file should be created");
|
assertTrue(file.exists(), "Ghost file should be created");
|
||||||
assertTrue(file.length() > 0, "Ghost file should not be empty");
|
assertTrue(file.length() > 0, "Ghost file should not be empty");
|
||||||
|
|
||||||
// Load from file
|
// Load from file
|
||||||
GhostData loaded = GhostData.loadFromFile(file);
|
GhostData loaded = GhostData.loadFromFile(file);
|
||||||
|
|
||||||
// Verify data
|
// Verify data
|
||||||
assertEquals(original.getPlayerName(), loaded.getPlayerName());
|
assertEquals(original.getPlayerName(), loaded.getPlayerName());
|
||||||
assertEquals(original.getPlayerUuid(), loaded.getPlayerUuid());
|
assertEquals(original.getPlayerUuid(), loaded.getPlayerUuid());
|
||||||
|
|
@ -70,12 +70,12 @@ class GhostDataTest {
|
||||||
assertEquals(original.getWorldName(), loaded.getWorldName());
|
assertEquals(original.getWorldName(), loaded.getWorldName());
|
||||||
assertEquals("world", loaded.getWorldName());
|
assertEquals("world", loaded.getWorldName());
|
||||||
assertEquals(original.getFrames().size(), loaded.getFrames().size());
|
assertEquals(original.getFrames().size(), loaded.getFrames().size());
|
||||||
|
|
||||||
// Verify frames
|
// Verify frames
|
||||||
for (int i = 0; i < original.getFrames().size(); i++) {
|
for (int i = 0; i < original.getFrames().size(); i++) {
|
||||||
GhostFrame origFrame = original.getFrames().get(i);
|
GhostFrame origFrame = original.getFrames().get(i);
|
||||||
GhostFrame loadedFrame = loaded.getFrames().get(i);
|
GhostFrame loadedFrame = loaded.getFrames().get(i);
|
||||||
|
|
||||||
assertEquals(origFrame.getTimestamp(), loadedFrame.getTimestamp());
|
assertEquals(origFrame.getTimestamp(), loadedFrame.getTimestamp());
|
||||||
assertEquals(origFrame.getX(), loadedFrame.getX(), 0.001);
|
assertEquals(origFrame.getX(), loadedFrame.getX(), 0.001);
|
||||||
assertEquals(origFrame.getY(), loadedFrame.getY(), 0.001);
|
assertEquals(origFrame.getY(), loadedFrame.getY(), 0.001);
|
||||||
|
|
@ -90,12 +90,12 @@ class GhostDataTest {
|
||||||
// Test with no frames
|
// Test with no frames
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
GhostData data = new GhostData(uuid, "EmptyPlayer", 0, new ArrayList<>());
|
GhostData data = new GhostData(uuid, "EmptyPlayer", 0, new ArrayList<>());
|
||||||
|
|
||||||
File file = tempDir.resolve("empty.ghost").toFile();
|
File file = tempDir.resolve("empty.ghost").toFile();
|
||||||
data.saveToFile(file);
|
data.saveToFile(file);
|
||||||
|
|
||||||
GhostData loaded = GhostData.loadFromFile(file);
|
GhostData loaded = GhostData.loadFromFile(file);
|
||||||
|
|
||||||
assertEquals(0, loaded.getFrames().size());
|
assertEquals(0, loaded.getFrames().size());
|
||||||
assertEquals("EmptyPlayer", loaded.getPlayerName());
|
assertEquals("EmptyPlayer", loaded.getPlayerName());
|
||||||
}
|
}
|
||||||
|
|
@ -114,15 +114,15 @@ class GhostDataTest {
|
||||||
0 // Pitch
|
0 // Pitch
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
GhostData data = new GhostData(uuid, "LongRunner", 1200, frames);
|
GhostData data = new GhostData(uuid, "LongRunner", 1200, frames);
|
||||||
|
|
||||||
File file = tempDir.resolve("large.ghost").toFile();
|
File file = tempDir.resolve("large.ghost").toFile();
|
||||||
data.saveToFile(file);
|
data.saveToFile(file);
|
||||||
|
|
||||||
GhostData loaded = GhostData.loadFromFile(file);
|
GhostData loaded = GhostData.loadFromFile(file);
|
||||||
|
|
||||||
assertEquals(1200, loaded.getFrames().size());
|
assertEquals(1200, loaded.getFrames().size());
|
||||||
assertEquals(1200, loaded.getScore());
|
assertEquals(1200, loaded.getScore());
|
||||||
}
|
}
|
||||||
|
|
@ -133,16 +133,16 @@ class GhostDataTest {
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
GhostData data = new GhostData(
|
GhostData data = new GhostData(
|
||||||
uuid,
|
uuid,
|
||||||
"Player_123-ABC",
|
"Player_123-ABC",
|
||||||
50,
|
50,
|
||||||
List.of(new GhostFrame(0, 0, 100, 0, 0, 0))
|
List.of(new GhostFrame(0, 0, 100, 0, 0, 0))
|
||||||
);
|
);
|
||||||
|
|
||||||
File file = tempDir.resolve("special.ghost").toFile();
|
File file = tempDir.resolve("special.ghost").toFile();
|
||||||
data.saveToFile(file);
|
data.saveToFile(file);
|
||||||
|
|
||||||
GhostData loaded = GhostData.loadFromFile(file);
|
GhostData loaded = GhostData.loadFromFile(file);
|
||||||
|
|
||||||
assertEquals("Player_123-ABC", loaded.getPlayerName());
|
assertEquals("Player_123-ABC", loaded.getPlayerName());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -152,15 +152,15 @@ class GhostDataTest {
|
||||||
List<GhostFrame> frames = new ArrayList<>();
|
List<GhostFrame> frames = new ArrayList<>();
|
||||||
frames.add(new GhostFrame(0, -100, 50, -200, -90, -45));
|
frames.add(new GhostFrame(0, -100, 50, -200, -90, -45));
|
||||||
frames.add(new GhostFrame(1000, -99, 51, -199, -45, 0));
|
frames.add(new GhostFrame(1000, -99, 51, -199, -45, 0));
|
||||||
|
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
GhostData data = new GhostData(uuid, "NegativePlayer", 10, frames);
|
GhostData data = new GhostData(uuid, "NegativePlayer", 10, frames);
|
||||||
|
|
||||||
File file = tempDir.resolve("negative.ghost").toFile();
|
File file = tempDir.resolve("negative.ghost").toFile();
|
||||||
data.saveToFile(file);
|
data.saveToFile(file);
|
||||||
|
|
||||||
GhostData loaded = GhostData.loadFromFile(file);
|
GhostData loaded = GhostData.loadFromFile(file);
|
||||||
|
|
||||||
GhostFrame frame = loaded.getFrames().get(0);
|
GhostFrame frame = loaded.getFrames().get(0);
|
||||||
assertEquals(-100, frame.getX(), 0.001);
|
assertEquals(-100, frame.getX(), 0.001);
|
||||||
assertEquals(50, frame.getY(), 0.001);
|
assertEquals(50, frame.getY(), 0.001);
|
||||||
|
|
@ -173,7 +173,7 @@ class GhostDataTest {
|
||||||
void testLoadNonExistentFile() {
|
void testLoadNonExistentFile() {
|
||||||
// Test loading from non-existent file
|
// Test loading from non-existent file
|
||||||
File file = new File("nonexistent.ghost");
|
File file = new File("nonexistent.ghost");
|
||||||
|
|
||||||
assertThrows(IOException.class, () -> {
|
assertThrows(IOException.class, () -> {
|
||||||
GhostData.loadFromFile(file);
|
GhostData.loadFromFile(file);
|
||||||
}, "Should throw IOException for non-existent file");
|
}, "Should throw IOException for non-existent file");
|
||||||
|
|
@ -184,15 +184,15 @@ class GhostDataTest {
|
||||||
// Test that frames list is copied (defensive copy)
|
// Test that frames list is copied (defensive copy)
|
||||||
List<GhostFrame> originalFrames = new ArrayList<>();
|
List<GhostFrame> originalFrames = new ArrayList<>();
|
||||||
originalFrames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
|
originalFrames.add(new GhostFrame(0, 0, 100, 0, 0, 0));
|
||||||
|
|
||||||
UUID uuid = UUID.randomUUID();
|
UUID uuid = UUID.randomUUID();
|
||||||
GhostData data = new GhostData(uuid, "Player", 10, originalFrames);
|
GhostData data = new GhostData(uuid, "Player", 10, originalFrames);
|
||||||
|
|
||||||
// Modify original list
|
// Modify original list
|
||||||
originalFrames.add(new GhostFrame(1000, 1, 100, 0, 0, 0));
|
originalFrames.add(new GhostFrame(1000, 1, 100, 0, 0, 0));
|
||||||
|
|
||||||
// GhostData should still have only 1 frame
|
// 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");
|
"GhostData should create defensive copy of frames list");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue