diff --git a/.github/workflows/javadoc.yml b/.github/workflows/javadoc.yml new file mode 100644 index 0000000..37ec691 --- /dev/null +++ b/.github/workflows/javadoc.yml @@ -0,0 +1,29 @@ +name: Publish Javadoc + +on: + push: + branches: [ main, master, dev ] + pull_request: + branches: [ main, master, dev ] + +jobs: + build-javadoc: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Set up JDK 21 + uses: actions/setup-java@v4 + with: + distribution: 'temurin' + java-version: '21' + + - name: Build Javadoc + run: ./gradlew.bat javadoc javadocJar --no-daemon + + - name: Upload Javadoc artifact + uses: actions/upload-artifact@v4 + with: + name: javadoc + path: build/libs/*-javadoc.jar \ No newline at end of file diff --git a/CHANGELOG.md b/CHANGELOG.md index feaf2b3..2167513 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -43,6 +43,11 @@ All notable changes to the Matchbox plugin will be documented in this file. - Integration testing for complex game lifecycle scenarios ### Changed +- **API annotations and stability markers**: Added explicit nullability and API status annotations across the `com.ohacd.matchbox.api` module + - Introduced `@com.ohacd.matchbox.api.annotation.Internal` and `@com.ohacd.matchbox.api.annotation.Experimental` to mark implementation and unstable APIs + - Adopted JetBrains `@NotNull/@Nullable` consistently on public API surfaces and added `@since` Javadoc where appropriate + - Updated `GameConfig` nullability for optional settings and annotated event classes and listeners +- **API documentation**: Added focused API Javadoc generation and a `javadocJar` artifact for distribution; added missing `@since` tags to experimental methods and performed minor doc cleanups to improve clarity and usability - **Default Configuration**: Updated default config with optimized phase durations - Discussion phase duration set to 60 seconds by default (was 30 seconds) - Voting phase duration set to 30 seconds by default (was 15 seconds) diff --git a/build.gradle b/build.gradle index c7fb7e1..d0d528b 100644 --- a/build.gradle +++ b/build.gradle @@ -77,3 +77,29 @@ processResources { expand props } } + +// Configure Javadoc to generate public-facing API docs only (com.ohacd.matchbox.api) +tasks.named('javadoc', Javadoc) { + description = 'Generates Javadoc for the public API (com.ohacd.matchbox.api) only' + group = 'Documentation' + // Limit sources to API package to avoid internal implementation warnings + source = fileTree('src/main/java') { include 'com/ohacd/matchbox/api/**' } + // Make sure referenced internal types are resolvable by depending on compilation output + dependsOn tasks.named('classes') + classpath = sourceSets.main.output + sourceSets.main.compileClasspath + options.encoding = 'UTF-8' + // External links disabled to avoid network fetch errors during build + // If desired, add stable links manually after verifying package-list availability + +} + +// Javadoc JAR for distribution +tasks.register('javadocJar', Jar) { + dependsOn tasks.named('javadoc') + archiveClassifier.set('javadoc') + from tasks.named('javadoc').get().destinationDir +} + +artifacts { + archives tasks.named('javadocJar') +} diff --git a/src/main/java/com/ohacd/matchbox/api/ApiGameSession.java b/src/main/java/com/ohacd/matchbox/api/ApiGameSession.java index 2ba833f..9dd36a1 100644 --- a/src/main/java/com/ohacd/matchbox/api/ApiGameSession.java +++ b/src/main/java/com/ohacd/matchbox/api/ApiGameSession.java @@ -10,6 +10,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.ohacd.matchbox.api.annotation.Internal; import java.util.*; @@ -390,6 +391,7 @@ public String getStatusDescription() { * @return the wrapped GameSession * @deprecated This method exposes internal implementation details. Use the provided API methods instead. */ + @Internal @Deprecated public GameSession getInternalSession() { return session; diff --git a/src/main/java/com/ohacd/matchbox/api/ChatMessage.java b/src/main/java/com/ohacd/matchbox/api/ChatMessage.java index 32f0a16..e3760f5 100644 --- a/src/main/java/com/ohacd/matchbox/api/ChatMessage.java +++ b/src/main/java/com/ohacd/matchbox/api/ChatMessage.java @@ -11,6 +11,15 @@ * Immutable representation of a chat message with all metadata needed for routing. * Used throughout the chat pipeline system. * + * @param originalMessage original message content (unmodified) + * @param formattedMessage formatted message used for display + * @param sender player who sent the message + * @param senderId UUID of the sender + * @param channel chat channel the message belongs to + * @param sessionName session name the message was sent in + * @param isAlivePlayer whether the sender is an alive player + * @param timestamp instant the message was recorded + * * @since 0.9.5 * @author Matchbox Team */ @@ -26,6 +35,13 @@ public record ChatMessage( ) { /** * Creates a new ChatMessage with the current timestamp. + * + * @param originalMessage original message content (unmodified) + * @param formattedMessage formatted message used for display + * @param sender sender player + * @param channel channel of message + * @param sessionName session name + * @param isAlivePlayer whether sender is alive */ public ChatMessage( @NotNull Component originalMessage, @@ -41,6 +57,9 @@ public ChatMessage( /** * Creates a copy of this message with a modified formatted message. * Useful for processors that want to modify message content. + * + * @param newFormattedMessage the updated formatted message component + * @return a new ChatMessage with the modified formatted message */ public ChatMessage withFormattedMessage(@NotNull Component newFormattedMessage) { return new ChatMessage(originalMessage, newFormattedMessage, sender, senderId, channel, sessionName, isAlivePlayer, timestamp); @@ -49,6 +68,9 @@ public ChatMessage withFormattedMessage(@NotNull Component newFormattedMessage) /** * Creates a copy of this message with a modified channel. * Useful for processors that want to reroute messages. + * + * @param newChannel new chat channel for the message + * @return a new ChatMessage routed to the provided channel */ public ChatMessage withChannel(@NotNull ChatChannel newChannel) { return new ChatMessage(originalMessage, formattedMessage, sender, senderId, newChannel, sessionName, isAlivePlayer, timestamp); diff --git a/src/main/java/com/ohacd/matchbox/api/ChatProcessor.java b/src/main/java/com/ohacd/matchbox/api/ChatProcessor.java index 82845ae..b59fe2f 100644 --- a/src/main/java/com/ohacd/matchbox/api/ChatProcessor.java +++ b/src/main/java/com/ohacd/matchbox/api/ChatProcessor.java @@ -45,11 +45,17 @@ public interface ChatProcessor { /** * Result of chat processing with optional modified message. + * + * @param result the processing result enum + * @param message the (possibly modified) message */ record ChatProcessingResult(@NotNull ChatResult result, @NotNull ChatMessage message) { /** * Creates an ALLOW result with the original message. + * + * @param message original chat message + * @return a ChatProcessingResult indicating ALLOW with the provided message */ public static ChatProcessingResult allow(@NotNull ChatMessage message) { return new ChatProcessingResult(ChatResult.ALLOW, message); @@ -57,6 +63,9 @@ public static ChatProcessingResult allow(@NotNull ChatMessage message) { /** * Creates an ALLOW result with a modified message. + * + * @param modifiedMessage modified chat message + * @return a ChatProcessingResult indicating ALLOW with the modified message */ public static ChatProcessingResult allowModified(@NotNull ChatMessage modifiedMessage) { return new ChatProcessingResult(ChatResult.ALLOW, modifiedMessage); @@ -64,6 +73,9 @@ public static ChatProcessingResult allowModified(@NotNull ChatMessage modifiedMe /** * Creates a DENY result. + * + * @param message original chat message + * @return a ChatProcessingResult indicating DENY */ public static ChatProcessingResult deny(@NotNull ChatMessage message) { return new ChatProcessingResult(ChatResult.DENY, message); @@ -71,6 +83,9 @@ public static ChatProcessingResult deny(@NotNull ChatMessage message) { /** * Creates a CANCEL result. + * + * @param message original chat message + * @return a ChatProcessingResult indicating CANCEL */ public static ChatProcessingResult cancel(@NotNull ChatMessage message) { return new ChatProcessingResult(ChatResult.CANCEL, message); diff --git a/src/main/java/com/ohacd/matchbox/api/GameConfig.java b/src/main/java/com/ohacd/matchbox/api/GameConfig.java index 37175cd..85590d0 100644 --- a/src/main/java/com/ohacd/matchbox/api/GameConfig.java +++ b/src/main/java/com/ohacd/matchbox/api/GameConfig.java @@ -1,6 +1,7 @@ package com.ohacd.matchbox.api; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Configuration class for game sessions. @@ -85,7 +86,7 @@ public int getVotingDuration() { * * @return spark ability setting ("random", "hunter_vision", "spark_swap", "delusion") */ - @NotNull + @Nullable public String getSparkSecondaryAbility() { return sparkSecondaryAbility; } @@ -93,9 +94,9 @@ public String getSparkSecondaryAbility() { /** * Gets the Medic secondary ability setting. * - * @return medic ability setting ("random", "healing_sight") + * @return medic ability setting ("random", "healing_sight") or null if unset */ - @NotNull + @Nullable public String getMedicSecondaryAbility() { return medicSecondaryAbility; } diff --git a/src/main/java/com/ohacd/matchbox/api/MatchboxAPI.java b/src/main/java/com/ohacd/matchbox/api/MatchboxAPI.java index 12cbd7c..f277e49 100644 --- a/src/main/java/com/ohacd/matchbox/api/MatchboxAPI.java +++ b/src/main/java/com/ohacd/matchbox/api/MatchboxAPI.java @@ -10,6 +10,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.ohacd.matchbox.api.annotation.Experimental; import java.util.*; import java.util.concurrent.ConcurrentHashMap; @@ -42,6 +43,7 @@ private MatchboxAPI() { * @return a new SessionBuilder instance * @throws IllegalArgumentException if name is null or empty */ + @NotNull public static SessionBuilder createSessionBuilder(@NotNull String name) { if (name == null || name.trim().isEmpty()) { throw new IllegalArgumentException("Session name cannot be null or empty"); @@ -55,6 +57,7 @@ public static SessionBuilder createSessionBuilder(@NotNull String name) { * @param name the session name (case-insensitive) * @return Optional containing the session if found, empty otherwise */ + @NotNull public static Optional getSession(@Nullable String name) { if (name == null || name.trim().isEmpty()) { return Optional.empty(); @@ -170,6 +173,7 @@ public static int endAllSessions() { * @param player the player to check * @return Optional containing the session if the player is in one, empty otherwise */ + @NotNull public static Optional getPlayerSession(@Nullable Player player) { if (player == null) return Optional.empty(); @@ -195,6 +199,7 @@ public static Optional getPlayerSession(@Nullable Player player) * @param player the player to check * @return Optional containing the player's role if in a game, empty otherwise */ + @NotNull public static Optional getPlayerRole(@Nullable Player player) { if (player == null) return Optional.empty(); @@ -217,6 +222,7 @@ public static Optional getPlayerRole(@Nullable Player player) { * @param sessionName the session name * @return Optional containing the current phase if session exists, empty otherwise */ + @NotNull public static Optional getCurrentPhase(@Nullable String sessionName) { if (sessionName == null || sessionName.trim().isEmpty()) { return Optional.empty(); @@ -275,7 +281,9 @@ public static Set getListeners() { * @param processor the chat processor to register * @return true if the processor was registered, false if session not found * @throws IllegalArgumentException if sessionName or processor is null + * @since 0.9.5 */ + @Experimental public static boolean registerChatProcessor(@NotNull String sessionName, @NotNull ChatProcessor processor) { if (sessionName == null || sessionName.trim().isEmpty()) { throw new IllegalArgumentException("Session name cannot be null or empty"); @@ -314,7 +322,9 @@ public static boolean registerChatProcessor(@NotNull String sessionName, @NotNul * @param processor the chat processor to unregister * @return true if the processor was unregistered, false if not found * @throws IllegalArgumentException if sessionName or processor is null + * @since 0.9.5 */ + @Experimental public static boolean unregisterChatProcessor(@NotNull String sessionName, @NotNull ChatProcessor processor) { if (sessionName == null || sessionName.trim().isEmpty()) { throw new IllegalArgumentException("Session name cannot be null or empty"); @@ -350,7 +360,9 @@ public static boolean unregisterChatProcessor(@NotNull String sessionName, @NotN * @param sessionName the session name to clear processors from * @return true if processors were cleared, false if session not found * @throws IllegalArgumentException if sessionName is null + * @since 0.9.5 */ + @Experimental public static boolean clearChatProcessors(@NotNull String sessionName) { if (sessionName == null || sessionName.trim().isEmpty()) { throw new IllegalArgumentException("Session name cannot be null or empty"); @@ -383,6 +395,7 @@ public static boolean clearChatProcessors(@NotNull String sessionName) { * * @param event the event to fire */ + @com.ohacd.matchbox.api.annotation.Internal static void fireEvent(@NotNull MatchboxEvent event) { if (event == null) return; diff --git a/src/main/java/com/ohacd/matchbox/api/SessionBuilder.java b/src/main/java/com/ohacd/matchbox/api/SessionBuilder.java index fe63984..5a4e2a3 100644 --- a/src/main/java/com/ohacd/matchbox/api/SessionBuilder.java +++ b/src/main/java/com/ohacd/matchbox/api/SessionBuilder.java @@ -9,6 +9,7 @@ import org.bukkit.plugin.java.JavaPlugin; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; +import com.ohacd.matchbox.api.annotation.Experimental; import java.util.*; @@ -78,6 +79,7 @@ public SessionBuilder(@NotNull String sessionName) { * @param players the players to include in the session * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withPlayers(@Nullable Collection players) { this.players = players != null ? new ArrayList<>(players) : new ArrayList<>(); return this; @@ -89,6 +91,7 @@ public SessionBuilder withPlayers(@Nullable Collection players) { * @param players the players to include in the session * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withPlayers(@Nullable Player... players) { this.players = players != null ? new ArrayList<>(Arrays.asList(players)) : new ArrayList<>(); return this; @@ -100,6 +103,7 @@ public SessionBuilder withPlayers(@Nullable Player... players) { * @param spawnPoints list of spawn locations * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withSpawnPoints(@Nullable List spawnPoints) { this.spawnPoints = spawnPoints != null ? new ArrayList<>(spawnPoints) : new ArrayList<>(); return this; @@ -111,6 +115,7 @@ public SessionBuilder withSpawnPoints(@Nullable List spawnPoints) { * @param spawnPoints array of spawn locations * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withSpawnPoints(@Nullable Location... spawnPoints) { this.spawnPoints = spawnPoints != null ? new ArrayList<>(Arrays.asList(spawnPoints)) : new ArrayList<>(); return this; @@ -122,6 +127,7 @@ public SessionBuilder withSpawnPoints(@Nullable Location... spawnPoints) { * @param discussionLocation the location where discussions take place * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withDiscussionLocation(@Nullable Location discussionLocation) { this.discussionLocation = discussionLocation; return this; @@ -133,6 +139,7 @@ public SessionBuilder withDiscussionLocation(@Nullable Location discussionLocati * @param seatLocations map of seat numbers to locations * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withSeatLocations(@Nullable Map seatLocations) { this.seatLocations = seatLocations != null ? new HashMap<>(seatLocations) : new HashMap<>(); return this; @@ -144,6 +151,7 @@ public SessionBuilder withSeatLocations(@Nullable Map seatLoc * @param gameConfig the game configuration to use * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withCustomConfig(@Nullable GameConfig gameConfig) { this.gameConfig = gameConfig != null ? gameConfig : new GameConfig.Builder().build(); return this; @@ -155,6 +163,7 @@ public SessionBuilder withCustomConfig(@Nullable GameConfig gameConfig) { * @param gameConfig the game configuration to use * @return this builder instance for method chaining */ + @NotNull public SessionBuilder withConfig(@Nullable GameConfig gameConfig) { return withCustomConfig(gameConfig); } @@ -213,8 +222,9 @@ public Optional validate() { * * @return Optional containing the created session, empty if creation failed */ + @NotNull public Optional start() { - return startWithResult().toOptional(); + return startWithResult().getSession(); } /** @@ -223,7 +233,10 @@ public Optional start() { * but don't want to trigger full game initialization. * * @return Optional containing the created session, empty if creation failed + * @since 0.9.5 (experimental) */ + @NotNull + @Experimental public Optional createSessionOnly() { // Validate configuration first Optional validationError = validate(); diff --git a/src/main/java/com/ohacd/matchbox/api/SessionCreationResult.java b/src/main/java/com/ohacd/matchbox/api/SessionCreationResult.java index 02aa014..bfb3439 100644 --- a/src/main/java/com/ohacd/matchbox/api/SessionCreationResult.java +++ b/src/main/java/com/ohacd/matchbox/api/SessionCreationResult.java @@ -67,6 +67,11 @@ public enum ErrorType { this.defaultMessage = defaultMessage; } + /** + * Gets the default human-readable message associated with this error type. + * + * @return default error message suitable for logging or display + */ public String getDefaultMessage() { return defaultMessage; } diff --git a/src/main/java/com/ohacd/matchbox/api/annotation/Experimental.java b/src/main/java/com/ohacd/matchbox/api/annotation/Experimental.java new file mode 100644 index 0000000..bf5ba14 --- /dev/null +++ b/src/main/java/com/ohacd/matchbox/api/annotation/Experimental.java @@ -0,0 +1,19 @@ +package com.ohacd.matchbox.api.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks APIs that are experimental and may change in future releases. + * Use with caution; experimental APIs may be promoted to stable or removed. + * + * @since 0.9.5 + */ +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.CONSTRUCTOR}) +public @interface Experimental { +} diff --git a/src/main/java/com/ohacd/matchbox/api/annotation/Internal.java b/src/main/java/com/ohacd/matchbox/api/annotation/Internal.java new file mode 100644 index 0000000..03966cf --- /dev/null +++ b/src/main/java/com/ohacd/matchbox/api/annotation/Internal.java @@ -0,0 +1,19 @@ +package com.ohacd.matchbox.api.annotation; + +import java.lang.annotation.Documented; +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Marks APIs that are internal to the implementation and not intended for public consumption. + * These APIs may change or be removed without notice. + * + * @since 0.9.5 + */ +@Documented +@Retention(RetentionPolicy.CLASS) +@Target({ElementType.TYPE, ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.CONSTRUCTOR}) +public @interface Internal { +} diff --git a/src/main/java/com/ohacd/matchbox/api/events/AbilityUseEvent.java b/src/main/java/com/ohacd/matchbox/api/events/AbilityUseEvent.java index 28a46d0..ce0c10e 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/AbilityUseEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/AbilityUseEvent.java @@ -3,6 +3,8 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; /** * Event fired when a player uses a special ability. @@ -43,7 +45,7 @@ public enum AbilityType { * @param ability the type of ability used * @param target the target player (may be null for self-targeted abilities) */ - public AbilityUseEvent(String sessionName, Player player, AbilityType ability, Player target) { + public AbilityUseEvent(@NotNull String sessionName, @NotNull Player player, @NotNull AbilityType ability, @Nullable Player target) { this.sessionName = sessionName; this.player = player; this.ability = ability; @@ -51,7 +53,7 @@ public AbilityUseEvent(String sessionName, Player player, AbilityType ability, P } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onAbilityUse(this); } @@ -60,6 +62,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -69,6 +72,7 @@ public String getSessionName() { * * @return the player */ + @NotNull public Player getPlayer() { return player; } @@ -78,6 +82,7 @@ public Player getPlayer() { * * @return the ability type */ + @NotNull public AbilityType getAbility() { return ability; } @@ -87,6 +92,7 @@ public AbilityType getAbility() { * * @return the target player, or null if the ability is self-targeted */ + @Nullable public Player getTarget() { return target; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/CureEvent.java b/src/main/java/com/ohacd/matchbox/api/events/CureEvent.java index d81ebc4..598bcd1 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/CureEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/CureEvent.java @@ -3,6 +3,7 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; /** * Event fired when a cure action is performed (Medic cures an infected player). @@ -25,7 +26,7 @@ public class CureEvent extends MatchboxEvent { * @param target the player being cured * @param realInfection whether the target had a real infection (false if it was delusion) */ - public CureEvent(String sessionName, Player medic, Player target, boolean realInfection) { + public CureEvent(@NotNull String sessionName, @NotNull Player medic, @NotNull Player target, boolean realInfection) { this.sessionName = sessionName; this.medic = medic; this.target = target; @@ -33,7 +34,7 @@ public CureEvent(String sessionName, Player medic, Player target, boolean realIn } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onCure(this); } diff --git a/src/main/java/com/ohacd/matchbox/api/events/GameEndEvent.java b/src/main/java/com/ohacd/matchbox/api/events/GameEndEvent.java index a02ef0e..72fa5f4 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/GameEndEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/GameEndEvent.java @@ -4,6 +4,7 @@ import com.ohacd.matchbox.api.MatchboxEventListener; import com.ohacd.matchbox.game.utils.Role; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.Map; @@ -47,8 +48,8 @@ public enum EndReason { * @param finalRoles mapping of players to their final roles * @param totalRounds total number of rounds played */ - public GameEndEvent(String sessionName, EndReason reason, Collection remainingPlayers, - Map finalRoles, int totalRounds) { + public GameEndEvent(@NotNull String sessionName, @NotNull EndReason reason, @NotNull Collection remainingPlayers, + @NotNull Map finalRoles, int totalRounds) { this.sessionName = sessionName; this.reason = reason; this.remainingPlayers = remainingPlayers; @@ -57,7 +58,7 @@ public GameEndEvent(String sessionName, EndReason reason, Collection rem } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onGameEnd(this); } @@ -66,6 +67,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -75,6 +77,7 @@ public String getSessionName() { * * @return the end reason */ + @NotNull public EndReason getReason() { return reason; } @@ -84,6 +87,7 @@ public EndReason getReason() { * * @return collection of remaining players */ + @NotNull public Collection getRemainingPlayers() { return remainingPlayers; } @@ -93,6 +97,7 @@ public Collection getRemainingPlayers() { * * @return mapping of players to their final roles */ + @NotNull public Map getFinalRoles() { return finalRoles; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/GameStartEvent.java b/src/main/java/com/ohacd/matchbox/api/events/GameStartEvent.java index a29a427..7ea4d3f 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/GameStartEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/GameStartEvent.java @@ -1,9 +1,11 @@ package com.ohacd.matchbox.api.events; +import com.google.common.annotations.Beta; import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import com.ohacd.matchbox.game.utils.Role; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; import java.util.Collection; import java.util.Map; @@ -12,7 +14,7 @@ * Event fired when a new game starts. * * @since 0.9.5 - * @author Matchbox Team + * @author OhACD */ public class GameStartEvent extends MatchboxEvent { @@ -27,14 +29,14 @@ public class GameStartEvent extends MatchboxEvent { * @param players all players in the game * @param roleAssignments mapping of players to their roles */ - public GameStartEvent(String sessionName, Collection players, Map roleAssignments) { + public GameStartEvent(@NotNull String sessionName, @NotNull Collection players, @NotNull Map roleAssignments) { this.sessionName = sessionName; this.players = players; this.roleAssignments = roleAssignments; } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onGameStart(this); } @@ -43,6 +45,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -52,6 +55,7 @@ public String getSessionName() { * * @return collection of all players */ + @NotNull public Collection getPlayers() { return players; } @@ -61,6 +65,7 @@ public Collection getPlayers() { * * @return mapping of players to their assigned roles */ + @NotNull public Map getRoleAssignments() { return roleAssignments; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/PhaseChangeEvent.java b/src/main/java/com/ohacd/matchbox/api/events/PhaseChangeEvent.java index 5c3fc07..5ad969e 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/PhaseChangeEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/PhaseChangeEvent.java @@ -3,6 +3,7 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import com.ohacd.matchbox.game.utils.GamePhase; +import org.jetbrains.annotations.NotNull; /** * Event fired when the game phase changes. @@ -25,7 +26,7 @@ public class PhaseChangeEvent extends MatchboxEvent { * @param toPhase the new phase * @param currentRound the current round number */ - public PhaseChangeEvent(String sessionName, GamePhase fromPhase, GamePhase toPhase, int currentRound) { + public PhaseChangeEvent(@NotNull String sessionName, @NotNull GamePhase fromPhase, @NotNull GamePhase toPhase, int currentRound) { this.sessionName = sessionName; this.fromPhase = fromPhase; this.toPhase = toPhase; @@ -33,7 +34,7 @@ public PhaseChangeEvent(String sessionName, GamePhase fromPhase, GamePhase toPha } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onPhaseChange(this); } @@ -42,6 +43,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -51,6 +53,7 @@ public String getSessionName() { * * @return the previous phase */ + @NotNull public GamePhase getFromPhase() { return fromPhase; } @@ -60,6 +63,7 @@ public GamePhase getFromPhase() { * * @return the new phase */ + @NotNull public GamePhase getToPhase() { return toPhase; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/PlayerEliminateEvent.java b/src/main/java/com/ohacd/matchbox/api/events/PlayerEliminateEvent.java index 0302ba3..01932b3 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/PlayerEliminateEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/PlayerEliminateEvent.java @@ -53,12 +53,13 @@ public PlayerEliminateEvent(String sessionName, Player eliminatedPlayer, Role ro } /** - * Creates a new player elimination event with current timestamp. + * Creates a new player elimination event with explicit timestamp. * * @param sessionName the session where elimination occurred * @param eliminatedPlayer the player who was eliminated * @param role the role of the eliminated player * @param reason the reason for elimination + * @param timestamp epoch millis when the event occurred */ public PlayerEliminateEvent(String sessionName, Player eliminatedPlayer, Role role, EliminationReason reason, long timestamp) { super(timestamp); diff --git a/src/main/java/com/ohacd/matchbox/api/events/PlayerJoinEvent.java b/src/main/java/com/ohacd/matchbox/api/events/PlayerJoinEvent.java index 1c340d2..17d934a 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/PlayerJoinEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/PlayerJoinEvent.java @@ -3,6 +3,7 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; /** * Event fired when a player joins a game session. @@ -21,13 +22,13 @@ public class PlayerJoinEvent extends MatchboxEvent { * @param sessionName the session name * @param player the player who joined */ - public PlayerJoinEvent(String sessionName, Player player) { + public PlayerJoinEvent(@NotNull String sessionName, @NotNull Player player) { this.sessionName = sessionName; this.player = player; } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onPlayerJoin(this); } @@ -36,6 +37,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -45,6 +47,7 @@ public String getSessionName() { * * @return the player */ + @NotNull public Player getPlayer() { return player; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/PlayerLeaveEvent.java b/src/main/java/com/ohacd/matchbox/api/events/PlayerLeaveEvent.java index d1460ce..856dc23 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/PlayerLeaveEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/PlayerLeaveEvent.java @@ -3,6 +3,7 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; /** * Event fired when a player leaves a game session. @@ -39,14 +40,14 @@ public enum LeaveReason { * @param player the player who left * @param reason the reason for leaving */ - public PlayerLeaveEvent(String sessionName, Player player, LeaveReason reason) { + public PlayerLeaveEvent(@NotNull String sessionName, @NotNull Player player, @NotNull LeaveReason reason) { this.sessionName = sessionName; this.player = player; this.reason = reason; } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onPlayerLeave(this); } @@ -55,7 +56,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ - public String getSessionName() { + public @NotNull String getSessionName() { return sessionName; } @@ -64,6 +65,7 @@ public String getSessionName() { * * @return the player */ + @NotNull public Player getPlayer() { return player; } @@ -73,6 +75,7 @@ public Player getPlayer() { * * @return the leave reason */ + @NotNull public LeaveReason getReason() { return reason; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/PlayerVoteEvent.java b/src/main/java/com/ohacd/matchbox/api/events/PlayerVoteEvent.java index 259d9a4..8ec409f 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/PlayerVoteEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/PlayerVoteEvent.java @@ -3,6 +3,7 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; /** * Event fired when a player casts a vote during the voting phase. @@ -23,14 +24,14 @@ public class PlayerVoteEvent extends MatchboxEvent { * @param voter the player who voted * @param target the player who was voted for */ - public PlayerVoteEvent(String sessionName, Player voter, Player target) { + public PlayerVoteEvent(@NotNull String sessionName, @NotNull Player voter, @NotNull Player target) { this.sessionName = sessionName; this.voter = voter; this.target = target; } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onPlayerVote(this); } @@ -39,6 +40,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -48,6 +50,7 @@ public String getSessionName() { * * @return the voter */ + @NotNull public Player getVoter() { return voter; } @@ -57,6 +60,7 @@ public Player getVoter() { * * @return the voted target */ + @NotNull public Player getTarget() { return target; } diff --git a/src/main/java/com/ohacd/matchbox/api/events/SwipeEvent.java b/src/main/java/com/ohacd/matchbox/api/events/SwipeEvent.java index 3b037db..00e1440 100644 --- a/src/main/java/com/ohacd/matchbox/api/events/SwipeEvent.java +++ b/src/main/java/com/ohacd/matchbox/api/events/SwipeEvent.java @@ -3,6 +3,7 @@ import com.ohacd.matchbox.api.MatchboxEvent; import com.ohacd.matchbox.api.MatchboxEventListener; import org.bukkit.entity.Player; +import org.jetbrains.annotations.NotNull; /** * Event fired when the swipe action is performed (Spark attacks another player). @@ -25,7 +26,7 @@ public class SwipeEvent extends MatchboxEvent { * @param victim the player being attacked * @param successful whether the swipe was successful (not blocked/cured) */ - public SwipeEvent(String sessionName, Player attacker, Player victim, boolean successful) { + public SwipeEvent(@NotNull String sessionName, @NotNull Player attacker, @NotNull Player victim, boolean successful) { this.sessionName = sessionName; this.attacker = attacker; this.victim = victim; @@ -33,7 +34,7 @@ public SwipeEvent(String sessionName, Player attacker, Player victim, boolean su } @Override - public void dispatch(MatchboxEventListener listener) { + public void dispatch(@NotNull MatchboxEventListener listener) { listener.onSwipe(this); } @@ -42,6 +43,7 @@ public void dispatch(MatchboxEventListener listener) { * * @return the session name */ + @NotNull public String getSessionName() { return sessionName; } @@ -51,6 +53,7 @@ public String getSessionName() { * * @return the attacker */ + @NotNull public Player getAttacker() { return attacker; } @@ -60,6 +63,7 @@ public Player getAttacker() { * * @return the victim */ + @NotNull public Player getVictim() { return victim; } diff --git a/src/main/java/com/ohacd/matchbox/api/package-info.java b/src/main/java/com/ohacd/matchbox/api/package-info.java new file mode 100644 index 0000000..b0aaae3 --- /dev/null +++ b/src/main/java/com/ohacd/matchbox/api/package-info.java @@ -0,0 +1,16 @@ +/** + * Public API for Matchbox. + * + *

API policy: + *

    + *
  • Use JetBrains annotations (`@NotNull` / `@Nullable`) for nullability on all public API surfaces.
  • + *
  • Use Javadoc `@since` on public classes and when introducing new public methods.
  • + *
  • Use `@Deprecated` (and Javadoc `@deprecated`) when removing or replacing behavior; supply a replacement if available.
  • + *
  • Use `@com.ohacd.matchbox.api.annotation.Experimental` for unstable APIs and `@com.ohacd.matchbox.api.annotation.Internal` for internal-only APIs.
  • + *
+ * + *

This package contains the public-facing API types and should remain stable across patch releases where possible. + * + * @since 0.9.5 + */ +package com.ohacd.matchbox.api; \ No newline at end of file diff --git a/src/main/java/com/ohacd/matchbox/game/ability/AbilityEventListener.java b/src/main/java/com/ohacd/matchbox/game/ability/AbilityEventListener.java index 82f9628..a131bb0 100644 --- a/src/main/java/com/ohacd/matchbox/game/ability/AbilityEventListener.java +++ b/src/main/java/com/ohacd/matchbox/game/ability/AbilityEventListener.java @@ -13,21 +13,41 @@ public class AbilityEventListener implements Listener { private final AbilityManager abilityManager; + /** + * Creates a listener that forwards Bukkit events to the given {@link AbilityManager}. + * + * @param abilityManager manager used to dispatch ability events + */ public AbilityEventListener(AbilityManager abilityManager) { this.abilityManager = abilityManager; } @EventHandler + /** + * Handle inventory click events and forward to registered abilities. + * + * @param event the inventory click event + */ public void onInventoryClick(InventoryClickEvent event) { abilityManager.handleInventoryClick(event); } @EventHandler + /** + * Handle player interact (block/item) events and forward to registered abilities. + * + * @param event the player interact event + */ public void onPlayerInteract(PlayerInteractEvent event) { abilityManager.handlePlayerInteract(event); } @EventHandler + /** + * Handle player interact-entity events and forward to registered abilities. + * + * @param event the player interact entity event + */ public void onPlayerInteractEntity(PlayerInteractEntityEvent event) { abilityManager.handlePlayerInteractEntity(event); } diff --git a/src/main/java/com/ohacd/matchbox/game/ability/AbilityHandler.java b/src/main/java/com/ohacd/matchbox/game/ability/AbilityHandler.java index 692c4de..c3438ce 100644 --- a/src/main/java/com/ohacd/matchbox/game/ability/AbilityHandler.java +++ b/src/main/java/com/ohacd/matchbox/game/ability/AbilityHandler.java @@ -9,10 +9,28 @@ * Minimal contract for ability handlers so a single listener can route events. */ public interface AbilityHandler { + /** + * Handle inventory click events for this ability. + * + * @param event the inventory click event + * @param context the session game context + */ default void handleInventoryClick(InventoryClickEvent event, SessionGameContext context) { } + /** + * Handle player interact events for this ability. + * + * @param event the player interact event + * @param context the session game context + */ default void handlePlayerInteract(PlayerInteractEvent event, SessionGameContext context) { } + /** + * Handle player interact-entity events for this ability. + * + * @param event the player interact entity event + * @param context the session game context + */ default void handlePlayerInteractEntity(PlayerInteractEntityEvent event, SessionGameContext context) { } } diff --git a/src/main/java/com/ohacd/matchbox/game/ability/AbilityManager.java b/src/main/java/com/ohacd/matchbox/game/ability/AbilityManager.java index 71dfb0b..8f0798a 100644 --- a/src/main/java/com/ohacd/matchbox/game/ability/AbilityManager.java +++ b/src/main/java/com/ohacd/matchbox/game/ability/AbilityManager.java @@ -22,20 +22,40 @@ public class AbilityManager { private final GameManager gameManager; private final List abilities = new ArrayList<>(); + /** + * Creates a manager responsible for routing ability events. + * + * @param gameManager the central {@link GameManager} used to obtain contexts + */ public AbilityManager(GameManager gameManager) { this.gameManager = gameManager; } + /** + * Registers an ability handler to receive routed events. + * + * @param ability the ability handler to register (ignored if null) + */ public void registerAbility(AbilityHandler ability) { if (ability != null) { abilities.add(ability); } } + /** + * Returns an unmodifiable list of registered ability handlers. + * + * @return list of registered {@link AbilityHandler} instances + */ public List getAbilities() { return Collections.unmodifiableList(abilities); } + /** + * Routes an inventory click event to registered abilities when applicable. + * + * @param event the inventory click event from Bukkit + */ public void handleInventoryClick(InventoryClickEvent event) { Player player = getPlayer(event.getWhoClicked()); if (player == null) { @@ -53,6 +73,11 @@ public void handleInventoryClick(InventoryClickEvent event) { } } + /** + * Routes a player interact event to registered abilities when applicable. + * + * @param event the player interact event from Bukkit + */ public void handlePlayerInteract(PlayerInteractEvent event) { Player player = getPlayer(event.getPlayer()); if (player == null) { @@ -70,6 +95,11 @@ public void handlePlayerInteract(PlayerInteractEvent event) { } } + /** + * Routes a player-interact-entity event to registered abilities when applicable. + * + * @param event the player interact entity event from Bukkit + */ public void handlePlayerInteractEntity(PlayerInteractEntityEvent event) { Player player = getPlayer(event.getPlayer()); if (player == null) { diff --git a/src/main/java/com/ohacd/matchbox/game/chat/ChatListener.java b/src/main/java/com/ohacd/matchbox/game/chat/ChatListener.java index 868fac7..690be54 100644 --- a/src/main/java/com/ohacd/matchbox/game/chat/ChatListener.java +++ b/src/main/java/com/ohacd/matchbox/game/chat/ChatListener.java @@ -21,12 +21,23 @@ public class ChatListener implements Listener { private final HologramManager hologramManager; private final GameManager gameManager; + /** + * Creates a chat listener that integrates chat pipeline and holograms. + * + * @param manager hologram manager used for in-game messages + * @param gameManager central game manager for session lookups + */ public ChatListener(HologramManager manager, GameManager gameManager) { this.hologramManager = manager; this.gameManager = gameManager; } @EventHandler + /** + * Handles asynchronous chat events and routes them through the chat pipeline. + * + * @param event the asynchronous chat event + */ public void onChat(AsyncChatEvent event) { // Only handle asynchronous chat events if (!event.isAsynchronous()) { diff --git a/src/main/java/com/ohacd/matchbox/game/config/ConfigManager.java b/src/main/java/com/ohacd/matchbox/game/config/ConfigManager.java index b30ed52..059629d 100644 --- a/src/main/java/com/ohacd/matchbox/game/config/ConfigManager.java +++ b/src/main/java/com/ohacd/matchbox/game/config/ConfigManager.java @@ -156,6 +156,8 @@ public void reloadConfig() { /** * Gets the FileConfiguration object. + * + * @return the loaded {@link FileConfiguration} */ public FileConfiguration getConfig() { return config; @@ -164,6 +166,8 @@ public FileConfiguration getConfig() { /** * Gets the list of valid seat numbers for discussion phase spawns. * Returns a list of integers representing seat numbers (1-indexed). + * + * @return a list of valid seat numbers */ public List getDiscussionSeatSpawns() { List rawList = config.getList("discussion.seat-spawns"); @@ -189,6 +193,8 @@ public List getDiscussionSeatSpawns() { /** * Gets the discussion phase duration in seconds. * Validates and clamps to reasonable range (5-300 seconds). + * + * @return discussion duration in seconds */ public int getDiscussionDuration() { int duration = config.getInt("discussion.duration", 30); @@ -206,6 +212,8 @@ public int getDiscussionDuration() { /** * Gets the swipe phase duration in seconds. * Validates and clamps to reasonable range (30-600 seconds). + * + * @return swipe duration in seconds */ public int getSwipeDuration() { int duration = config.getInt("swipe.duration", 180); @@ -223,6 +231,8 @@ public int getSwipeDuration() { /** * Gets the voting phase duration in seconds. * Validates and clamps to reasonable range (5-120 seconds). + * + * @return voting duration in seconds */ public int getVotingDuration() { int duration = config.getInt("voting.duration", 15); @@ -240,6 +250,8 @@ public int getVotingDuration() { /** * Gets the minimum number of players required to start a game. * Validates and clamps to reasonable range (2-7). + * + * @return minimum number of players */ public int getMinPlayers() { int min = config.getInt("session.min-players", 2); @@ -264,6 +276,8 @@ public int getMinPlayers() { /** * Gets the maximum number of players allowed per session. * Validates and clamps to reasonable range (2-20). + * + * @return maximum number of players */ public int getMaxPlayers() { int max = config.getInt("session.max-players", 7); @@ -288,6 +302,8 @@ public int getMaxPlayers() { /** * Gets the minimum number of spawn locations required before starting a game. * Validates and clamps to reasonable range (1-50). + * + * @return minimum number of spawn locations */ public int getMinSpawnLocations() { int min = config.getInt("session.min-spawn-locations", 1); @@ -304,6 +320,8 @@ public int getMinSpawnLocations() { /** * Gets whether random skins are enabled. + * + * @return true if random skins are enabled */ public boolean isRandomSkinsEnabled() { return config.getBoolean("cosmetics.random-skins-enabled", true); @@ -312,6 +330,8 @@ public boolean isRandomSkinsEnabled() { /** * Gets whether Steve skins should be used for all players. * When enabled, all players will have the default Steve skin regardless of random-skins-enabled setting. + * + * @return true if Steve skins should be used */ public boolean isUseSteveSkins() { return config.getBoolean("cosmetics.use-steve-skins", false); @@ -320,6 +340,8 @@ public boolean isUseSteveSkins() { /** * Gets the voting threshold percentage at 20 players. * Validates and clamps to reasonable range (0.05-1.0). + * + * @return threshold percentage for 20 players (0.0 - 1.0) */ public double getVotingThresholdAt20Players() { double threshold = config.getDouble("voting.threshold.at-20-players", 0.20); @@ -337,6 +359,8 @@ public double getVotingThresholdAt20Players() { /** * Gets the voting threshold percentage at 7 players. * Validates and clamps to reasonable range (0.05-1.0). + * + * @return threshold percentage for 7 players (0.0 - 1.0) */ public double getVotingThresholdAt7Players() { double threshold = config.getDouble("voting.threshold.at-7-players", 0.30); @@ -354,6 +378,8 @@ public double getVotingThresholdAt7Players() { /** * Gets the voting threshold percentage at 3 players and below. * Validates and clamps to reasonable range (0.05-1.0). + * + * @return threshold percentage for 3 players (0.0 - 1.0) */ public double getVotingThresholdAt3Players() { double threshold = config.getDouble("voting.threshold.at-3-players", 0.50); @@ -371,6 +397,8 @@ public double getVotingThresholdAt3Players() { /** * Gets the penalty percentage applied per voting phase without elimination. * Validates and clamps to reasonable range (0.0-0.5). + * + * @return penalty percentage applied per phase (0.0 - 1.0) */ public double getVotingPenaltyPerPhase() { double penalty = config.getDouble("voting.penalty.per-phase", 0.0333); @@ -388,6 +416,8 @@ public double getVotingPenaltyPerPhase() { /** * Gets the maximum number of phases that can accumulate penalty. * Validates and clamps to reasonable range (1-10). + * + * @return maximum penalty phases */ public int getVotingMaxPenaltyPhases() { int maxPhases = config.getInt("voting.penalty.max-phases", 3); @@ -405,6 +435,8 @@ public int getVotingMaxPenaltyPhases() { /** * Gets the maximum penalty reduction percentage. * Validates and clamps to reasonable range (0.0-0.5). + * + * @return maximum penalty reduction (0.0 - 1.0) */ public double getVotingMaxPenalty() { double maxPenalty = config.getDouble("voting.penalty.max-reduction", 0.10); @@ -458,6 +490,8 @@ public String getMedicSecondaryAbility() { /** * Loads seat locations from config. * Returns a map of seat numbers to locations. + * + * @return map of seat number -> {@link Location} */ public Map loadSeatLocations() { Map seatLocations = new HashMap<>(); @@ -491,6 +525,9 @@ public Map loadSeatLocations() { /** * Saves a seat location to config. + * + * @param seatNumber the seat number to save + * @param location the location to store for the seat */ public void saveSeatLocation(int seatNumber, Location location) { if (location == null || location.getWorld() == null) { @@ -504,6 +541,8 @@ public void saveSeatLocation(int seatNumber, Location location) { /** * Removes a seat location from config. + * + * @param seatNumber the seat number to remove */ public void removeSeatLocation(int seatNumber) { config.set("discussion.seat-locations." + seatNumber, null); @@ -513,6 +552,8 @@ public void removeSeatLocation(int seatNumber) { /** * Loads spawn locations from config. * Returns a list of locations. + * + * @return list of spawn {@link Location}s */ public List loadSpawnLocations() { List spawnLocations = new ArrayList<>(); @@ -541,8 +582,8 @@ public List loadSpawnLocations() { } /** - * Adds a spawn location to config. - */ + * Adds a spawn location to config. * + * @param location location to add to the spawn list */ public void addSpawnLocation(Location location) { if (location == null || location.getWorld() == null) { return; @@ -572,8 +613,9 @@ public void clearSpawnLocations() { } /** - * Removes a spawn location from config by index. - */ + * Removes a spawn location from config by index. * + * @param index index of the spawn location to remove + * @return true if the location was removed, false otherwise */ public boolean removeSpawnLocation(int index) { List rawList = config.getList("session.spawn-locations"); if (rawList == null || rawList.isEmpty()) { diff --git a/src/main/java/com/ohacd/matchbox/game/phase/DiscussionPhaseHandler.java b/src/main/java/com/ohacd/matchbox/game/phase/DiscussionPhaseHandler.java index 161f2c3..925b016 100644 --- a/src/main/java/com/ohacd/matchbox/game/phase/DiscussionPhaseHandler.java +++ b/src/main/java/com/ohacd/matchbox/game/phase/DiscussionPhaseHandler.java @@ -26,6 +26,13 @@ public class DiscussionPhaseHandler { private final Map> currentPlayerIds = new ConcurrentHashMap<>(); private final int DEFAULT_DISCUSSION_SECONDS = 30; // 30 seconds discussion + /** + * Creates a handler for discussion phase logic. + * + * @param plugin Bukkit plugin instance + * @param messageUtils helper used to send messages and titles + * @param configManager configuration provider + */ public DiscussionPhaseHandler(Plugin plugin, MessageUtils messageUtils, ConfigManager configManager) { this.plugin = plugin; this.messageUtils = messageUtils; @@ -34,6 +41,11 @@ public DiscussionPhaseHandler(Plugin plugin, MessageUtils messageUtils, ConfigMa /** * Starts the discussion phase with a countdown timer for a specific session. + * + * @param sessionName the session name to start the discussion for + * @param seconds duration in seconds for the discussion phase + * @param alivePlayerIds collection of alive player UUIDs participating in the phase + * @param onPhaseEnd callback to execute when the phase ends */ public void startDiscussionPhase(String sessionName, int seconds, Collection alivePlayerIds, Runnable onPhaseEnd) { startDiscussionPhase(sessionName, seconds, alivePlayerIds, onPhaseEnd, null); @@ -41,7 +53,12 @@ public void startDiscussionPhase(String sessionName, int seconds, Collection alivePlayerIds, Runnable onPhaseEnd, Map seatLocations) { if (sessionName == null || sessionName.trim().isEmpty()) { @@ -145,6 +162,8 @@ public void startDiscussionPhase(String sessionName, Collection alivePlaye /** * Cancels the discussion phase task for a specific session. + * + * @param sessionName the session name whose task should be cancelled */ public void cancelDiscussionTask(String sessionName) { if (sessionName == null) { @@ -193,11 +212,20 @@ private void clearActionBars(String sessionName) { /** * Checks if discussion phase is currently active for a session. + * + * @param sessionName the session name to check + * @return true if a discussion task exists for the session */ public boolean isActive(String sessionName) { return discussionTasks.containsKey(sessionName); } + /** + * Returns online Player objects for the provided player UUIDs. + * + * @param playerIds collection of player UUIDs + * @return collection of online {@link Player} objects + */ public Collection getAlivePlayerObjects(Collection playerIds) { return playerIds.stream() .map(Bukkit::getPlayer) diff --git a/src/main/java/com/ohacd/matchbox/game/state/GameState.java b/src/main/java/com/ohacd/matchbox/game/state/GameState.java index b67f92f..5ba0daf 100644 --- a/src/main/java/com/ohacd/matchbox/game/state/GameState.java +++ b/src/main/java/com/ohacd/matchbox/game/state/GameState.java @@ -363,7 +363,7 @@ public Long getPendingDeathTime(UUID playerId) { } /** - * Returns a snapshot of player UUIDs whose pending death time is <= provided epoch millis. + * Returns a snapshot of player UUIDs whose pending death time is {@code <=} provided epoch millis. * Useful for processing due pending deaths. */ public Set getPendingDeathsDueAt(long epochMillis) { diff --git a/src/main/java/com/ohacd/matchbox/game/utils/CheckProjectVersion.java b/src/main/java/com/ohacd/matchbox/game/utils/CheckProjectVersion.java index 5acf7c8..d80c758 100644 --- a/src/main/java/com/ohacd/matchbox/game/utils/CheckProjectVersion.java +++ b/src/main/java/com/ohacd/matchbox/game/utils/CheckProjectVersion.java @@ -19,10 +19,20 @@ public class CheckProjectVersion { private final Matchbox plugin; + /** + * Creates the version checker for the plugin. + * + * @param plugin plugin instance used for scheduling and logging + */ public CheckProjectVersion(Matchbox plugin) { this.plugin = plugin; } + /** + * Asynchronously checks the latest project version from the remote API and invokes the callback. + * + * @param callback consumer receiving the latest version string when available + */ public void checkLatestVersion(Consumer callback) { Bukkit.getScheduler().runTaskAsynchronously(plugin, () -> { try { diff --git a/src/main/java/com/ohacd/matchbox/game/utils/listeners/BlockInteractionProtectionListener.java b/src/main/java/com/ohacd/matchbox/game/utils/listeners/BlockInteractionProtectionListener.java index 54c8f08..9b4c91d 100644 --- a/src/main/java/com/ohacd/matchbox/game/utils/listeners/BlockInteractionProtectionListener.java +++ b/src/main/java/com/ohacd/matchbox/game/utils/listeners/BlockInteractionProtectionListener.java @@ -17,6 +17,11 @@ public class BlockInteractionProtectionListener implements Listener { private final GameManager gameManager; + /** + * Creates a listener that prevents block interactions during active games. + * + * @param gameManager the game manager used to check active sessions + */ public BlockInteractionProtectionListener(GameManager gameManager) { this.gameManager = gameManager; } diff --git a/src/main/java/com/ohacd/matchbox/game/utils/listeners/DamageProtectionListener.java b/src/main/java/com/ohacd/matchbox/game/utils/listeners/DamageProtectionListener.java index 7c14fc1..b6d3109 100644 --- a/src/main/java/com/ohacd/matchbox/game/utils/listeners/DamageProtectionListener.java +++ b/src/main/java/com/ohacd/matchbox/game/utils/listeners/DamageProtectionListener.java @@ -18,6 +18,11 @@ public class DamageProtectionListener implements Listener { private final GameManager gameManager; + /** + * Creates a listener that prevents damage/hunger/death during active games. + * + * @param gameManager the game manager used to check active sessions + */ public DamageProtectionListener(GameManager gameManager) { this.gameManager = gameManager; } @@ -27,6 +32,11 @@ public DamageProtectionListener(GameManager gameManager) { * Arrow damage is allowed for nametag revelation. */ @EventHandler(priority = EventPriority.HIGHEST) + /** + * Prevents damage to players during active games (arrow damage is allowed/handled). + * + * @param event the entity damage event + */ public void onEntityDamage(EntityDamageEvent event) { if (!(event.getEntity() instanceof Player)) { return; @@ -58,6 +68,11 @@ public void onEntityDamage(EntityDamageEvent event) { * Prevents player death during active games. */ @EventHandler(priority = EventPriority.HIGHEST) + /** + * Prevents player death during active games. + * + * @param event the player death event + */ public void onPlayerDeath(PlayerDeathEvent event) { Player player = event.getEntity(); @@ -77,6 +92,11 @@ public void onPlayerDeath(PlayerDeathEvent event) { * Prevents hunger loss during active games. */ @EventHandler(priority = EventPriority.HIGHEST) + /** + * Prevents hunger loss during active games. + * + * @param event the food level change event + */ public void onFoodLevelChange(FoodLevelChangeEvent event) { if (!(event.getEntity() instanceof Player)) { return; diff --git a/src/main/java/com/ohacd/matchbox/game/vote/DynamicVotingThreshold.java b/src/main/java/com/ohacd/matchbox/game/vote/DynamicVotingThreshold.java index a9d66db..a78b8df 100644 --- a/src/main/java/com/ohacd/matchbox/game/vote/DynamicVotingThreshold.java +++ b/src/main/java/com/ohacd/matchbox/game/vote/DynamicVotingThreshold.java @@ -34,6 +34,9 @@ public DynamicVotingThreshold(ConfigManager configManager) { /** * Calculates the base threshold percentage for a given number of alive players. * Uses logarithmic interpolation between key points. + * + * @param alivePlayerCount the number of currently alive players + * @return threshold percentage (0.0 - 1.0) */ public double calculateBaseThreshold(int alivePlayerCount) { if (alivePlayerCount < 2) {