Update dependencies and improve configuration management

- Updated LoLib dependency to version 3.0.0 in build.gradle.kts
- Added HikariCP and MySQL connector dependencies for improved database handling
- Enhanced jar minimization process to exclude JDBC pool and driver
- Refactored configuration management by introducing ConfigAccessor and ConfigLoader for better file handling and validation
- Removed deprecated GenerationOptions class and integrated its functionality into the new structure
- Improved command error handling and added cooldown hints for admin commands
This commit is contained in:
loki 2026-04-01 16:21:09 +02:00
parent 978f739045
commit 3100c53229
86 changed files with 4324 additions and 3248 deletions

View file

@ -1,244 +1,154 @@
package dev.loki.loparkour.session;
import java.util.ArrayList;
import dev.loki.loparkour.LoParkour;
import dev.loki.loparkour.config.Locales;
import dev.loki.loparkour.generator.ParkourGenerator;
import dev.loki.loparkour.player.ParkourPlayer;
import dev.loki.loparkour.player.ParkourSpectator;
import dev.loki.loparkour.player.ParkourUser;
import dev.loki.loparkour.world.Divider;
import org.bukkit.Location;
import org.bukkit.entity.Player;
import org.jetbrains.annotations.NotNull;
import java.util.*;
import java.util.ArrayList;
import java.util.List;
import java.util.function.Function;
/**
* <p>A session is bound to a {@link Divider} section.
* It manages all players, all spectators, visibility, the generator, etc.</p>
* <p>Iteration 2.</p>
*
* @author loki
* @since 5.0.0
* Refactored Session using composition pattern.
* Coordinates player management and state management.
*/
public class Session {
/**
* The spawn location of this session.
*/
private Location spawnLocation;
/**
* The generator.
*/
public ParkourGenerator generator;
private final SessionPlayerManager playerManager;
private final SessionStateManager stateManager;
private Session() {
this.playerManager = new SessionPlayerManager(this);
this.stateManager = new SessionStateManager(this);
}
/**
* The visibility of this session. Default public.
* Create a new session with specified parameters.
*/
private Visibility visibility = Visibility.PUBLIC;
/**
* Manages users (players and spectators) in this session.
*/
private final SessionUserManager userManager = new SessionUserManager(this);
/**
* Function that takes the current session and returns whether new players should be accepted.
*/
private Function<Session, Boolean> isAcceptingPlayers = session -> false;
/**
* Function that takes the current session and returns whether new spectators should be accepted.
*/
private Function<Session, Boolean> isAcceptingSpectators = session -> session.visibility == Visibility.PUBLIC;
/**
* Creates a new session.
*
* @param generatorFunction The generator function.
* @param isAcceptingPlayers The function that takes the current session and returns whether new players should be accepted.
* @param isAcceptingSpectators The function that takes the current session and returns whether new spectators should be accepted.
* @param players The players.
* @return The session.
*/
public static Session create(Function<Session, ParkourGenerator> generatorFunction,
Function<Session, Boolean> isAcceptingPlayers,
Function<Session, Boolean> isAcceptingSpectators,
Player... players) {
@NotNull
public static Session create(
@NotNull Function<Session, ParkourGenerator> generatorFunction,
Function<Session, Boolean> isAcceptingPlayers,
Function<Session, Boolean> isAcceptingSpectators,
Player... players) {
Session session = new Session();
if (isAcceptingPlayers != null) session.isAcceptingPlayers = isAcceptingPlayers;
if (isAcceptingSpectators != null) session.isAcceptingSpectators = isAcceptingSpectators;
List<ParkourPlayer> pps = new ArrayList<>();
// Set acceptance functions
if (isAcceptingPlayers != null) {
session.playerManager.setAcceptingPlayers(isAcceptingPlayers);
}
if (isAcceptingSpectators != null) {
session.playerManager.setAcceptingSpectators(isAcceptingSpectators);
}
// Add initial players
List<ParkourPlayer> parkourPlayers = new ArrayList<>();
if (players != null) {
for (Player player : players) {
ParkourPlayer pp = ParkourUser.register(player, session);
session.addPlayers(pp);
pps.add(pp);
parkourPlayers.add(pp);
}
}
session.spawnLocation = Divider.add(session);
session.generator = generatorFunction.apply(session);
if (players != null) {
pps.forEach(p -> p.updateGeneratorSettings(session.generator));
// Initialize session state
session.stateManager.initialize(generatorFunction);
// Update generator settings for players
if (session.generator != null) {
parkourPlayers.forEach(p -> p.updateGeneratorSettings(session.generator));
}
session.generator.island.build(session.spawnLocation);
return session;
}
/**
* Sets the visibility of this session.
* @param visibility The visibility.
*/
public void setVisibility(Visibility visibility) {
this.visibility = visibility;
// Visibility management
public void setVisibility(@NotNull Visibility visibility) {
stateManager.setVisibility(visibility);
}
/**
* @return The visibility of this session.
*/
@NotNull
public Visibility getVisibility() {
return visibility;
return stateManager.getVisibility();
}
/**
* Adds provided players to this session's player list.
*
* @param toAdd The players to add.
*/
public void addPlayers(ParkourPlayer... toAdd) {
userManager.addPlayers(toAdd);
// Player management
public void addPlayers(@NotNull ParkourPlayer... toAdd) {
playerManager.addPlayers(toAdd);
}
/**
* Removes provided players from this session's player list.
*
* @param toRemove The players to remove.
*/
public void removePlayers(ParkourPlayer... toRemove) {
userManager.removePlayers(toRemove);
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
playerManager.removePlayers(toRemove);
}
/**
* @return The players.
*/
@NotNull
public List<ParkourPlayer> getPlayers() {
return userManager.getPlayers();
return playerManager.getPlayers();
}
/**
* Adds provided spectators to this session's spectator list.
*
* @param spectators The spectators to add.
*/
public void addSpectators(ParkourSpectator... spectators) {
userManager.addSpectators(spectators);
// Spectator management
public void addSpectators(@NotNull ParkourSpectator... spectators) {
playerManager.addSpectators(spectators);
}
/**
* Removes provided spectators from this session's spectator list.
*
* @param spectators The spectators to remove.
*/
public void removeSpectators(ParkourSpectator... spectators) {
userManager.removeSpectators(spectators);
public void removeSpectators(@NotNull ParkourSpectator... spectators) {
playerManager.removeSpectators(spectators);
}
/**
* @return The spectators.
*/
@NotNull
public List<ParkourSpectator> getSpectators() {
return userManager.getSpectators();
return playerManager.getSpectators();
}
/**
* @return The users.
*/
@NotNull
public List<ParkourUser> getUsers() {
return userManager.getUsers();
return playerManager.getUsers();
}
/**
* @return the spawn location for this {@link Session}.
*/
@SuppressWarnings("unused")
// State management
public Location getSpawnLocation() {
return spawnLocation.clone();
return stateManager.getSpawnLocation();
}
/**
* Toggles mute for the specified user.
*
* @param user The user to (un)mute.
*/
public void toggleMute(@NotNull ParkourUser user) {
userManager.toggleMute(user);
stateManager.toggleMute(user);
}
/**
* @param user The user.
* @return True when the user is muted, false if not.
*/
public boolean isMuted(@NotNull ParkourUser user) {
return userManager.isMuted(user);
return stateManager.isMuted(user);
}
/**
* Called when all players have left the session.
*/
void onAllPlayersLeft() {
generator.reset(false);
Divider.remove(this);
}
/**
* @return True when players may join this session, false if not.
*/
// Acceptance checks
public boolean isAcceptingPlayers() {
return isAcceptingPlayers.apply(this);
return playerManager.isAcceptingPlayers();
}
/**
* @return True when spectators may join this session, false if not.
*/
public boolean isAcceptingSpectators() {
return isAcceptingSpectators.apply(this);
return playerManager.isAcceptingSpectators();
}
// Lifecycle
public void onAllPlayersLeft() {
stateManager.cleanup();
}
void setGenerator(@NotNull ParkourGenerator generator) {
this.generator = generator;
}
// Enums
public enum Visibility {
/**
* No-one can join.
*/
PRIVATE,
/**
* Only people with the session id can join.
*/
ID_ONLY,
/**
* Anyone can join.
*/
PUBLIC,
PRIVATE, ID_ONLY, PUBLIC
}
/**
* An enum for all available chat types that a player can select while playing
*/
public enum ChatType {
LOBBY_ONLY, PLAYERS_ONLY, PUBLIC
}
}
}

View file

@ -0,0 +1,147 @@
package dev.loki.loparkour.session;
import dev.loki.loparkour.player.ParkourPlayer;
import dev.loki.loparkour.player.ParkourSpectator;
import dev.loki.loparkour.player.ParkourUser;
import org.jetbrains.annotations.NotNull;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.Function;
/**
* Manages players and spectators in a session.
*/
public class SessionPlayerManager {
private final Session session;
private final List<ParkourPlayer> players = new ArrayList<>();
private final List<ParkourSpectator> spectators = new ArrayList<>();
private Function<Session, Boolean> isAcceptingPlayers = s -> false;
private Function<Session, Boolean> isAcceptingSpectators = s -> s.getVisibility() == Session.Visibility.PUBLIC;
public SessionPlayerManager(@NotNull Session session) {
this.session = session;
}
/**
* Set player acceptance function.
*/
public void setAcceptingPlayers(@NotNull Function<Session, Boolean> function) {
this.isAcceptingPlayers = function;
}
/**
* Set spectator acceptance function.
*/
public void setAcceptingSpectators(@NotNull Function<Session, Boolean> function) {
this.isAcceptingSpectators = function;
}
/**
* Check if session is accepting players.
*/
public boolean isAcceptingPlayers() {
return isAcceptingPlayers.apply(session);
}
/**
* Check if session is accepting spectators.
*/
public boolean isAcceptingSpectators() {
return isAcceptingSpectators.apply(session);
}
/**
* Add players to session.
*/
public void addPlayers(@NotNull ParkourPlayer... toAdd) {
players.addAll(Arrays.asList(toAdd));
updateVisibility();
}
/**
* Remove players from session.
*/
public void removePlayers(@NotNull ParkourPlayer... toRemove) {
players.removeAll(Arrays.asList(toRemove));
if (players.isEmpty()) {
session.onAllPlayersLeft();
} else {
updateVisibility();
}
}
/**
* Add spectators to session.
*/
public void addSpectators(@NotNull ParkourSpectator... toAdd) {
spectators.addAll(Arrays.asList(toAdd));
updateVisibility();
}
/**
* Remove spectators from session.
*/
public void removeSpectators(@NotNull ParkourSpectator... toRemove) {
spectators.removeAll(Arrays.asList(toRemove));
updateVisibility();
}
/**
* Get all players.
*/
@NotNull
public List<ParkourPlayer> getPlayers() {
return new ArrayList<>(players);
}
/**
* Get all spectators.
*/
@NotNull
public List<ParkourSpectator> getSpectators() {
return new ArrayList<>(spectators);
}
/**
* Get all users (players + spectators).
*/
@NotNull
public List<ParkourUser> getUsers() {
List<ParkourUser> users = new ArrayList<>();
users.addAll(players);
users.addAll(spectators);
return users;
}
/**
* Get total user count.
*/
public int getTotalUsers() {
return players.size() + spectators.size();
}
/**
* Check if session has any users.
*/
public boolean hasUsers() {
return !players.isEmpty() || !spectators.isEmpty();
}
private void updateVisibility() {
// Update player visibility for all users
List<ParkourUser> allUsers = getUsers();
for (ParkourUser user : allUsers) {
for (ParkourUser other : allUsers) {
if (!user.equals(other)) {
user.player.showPlayer(dev.loki.loparkour.LoParkour.getPlugin(), other.player);
}
}
}
}
}

View file

@ -0,0 +1,105 @@
package dev.loki.loparkour.session;
import dev.loki.loparkour.generator.ParkourGenerator;
import dev.loki.loparkour.player.ParkourUser;
import dev.loki.loparkour.world.Divider;
import org.bukkit.Location;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.util.HashMap;
import java.util.Map;
import java.util.function.Function;
/**
* Manages session state and lifecycle.
*/
public class SessionStateManager {
private final Session session;
private Location spawnLocation;
private Session.Visibility visibility = Session.Visibility.PUBLIC;
private final Map<ParkourUser, Boolean> mutedUsers = new HashMap<>();
public SessionStateManager(@NotNull Session session) {
this.session = session;
}
/**
* Initialize session with generator and spawn location.
*/
public void initialize(@NotNull Function<Session, ParkourGenerator> generatorFunction) {
// Allocate spawn location
this.spawnLocation = Divider.add(session);
// Create generator
ParkourGenerator generator = generatorFunction.apply(session);
session.setGenerator(generator);
// Build island at spawn location
generator.island.build(spawnLocation);
}
/**
* Clean up session resources.
*/
public void cleanup() {
if (session.generator != null) {
session.generator.reset(false);
}
Divider.remove(session);
mutedUsers.clear();
}
/**
* Set session visibility.
*/
public void setVisibility(@NotNull Session.Visibility visibility) {
this.visibility = visibility;
}
/**
* Get session visibility.
*/
@NotNull
public Session.Visibility getVisibility() {
return visibility;
}
/**
* Get spawn location.
*/
@Nullable
public Location getSpawnLocation() {
return spawnLocation != null ? spawnLocation.clone() : null;
}
/**
* Toggle mute status for user.
*/
public void toggleMute(@NotNull ParkourUser user) {
mutedUsers.put(user, !isMuted(user));
}
/**
* Check if user is muted.
*/
public boolean isMuted(@NotNull ParkourUser user) {
return mutedUsers.getOrDefault(user, false);
}
/**
* Get muted users count.
*/
public int getMutedUsersCount() {
return (int) mutedUsers.values().stream().mapToInt(muted -> muted ? 1 : 0).sum();
}
/**
* Clear all muted users.
*/
public void clearMutedUsers() {
mutedUsers.clear();
}
}