Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 64 additions & 0 deletions playtime-api/src/main/java/com/github/imdmk/playtime/PlayTime.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package com.github.imdmk.playtime;

import org.jetbrains.annotations.NotNull;

import java.time.Duration;
import java.util.concurrent.TimeUnit;

public record PlayTime(long millis) implements Comparable<PlayTime> {

private static final long MILLIS_PER_TICK = 50L;

public static final PlayTime ZERO = new PlayTime(0L);

public PlayTime {
if (millis < 0L) {
throw new IllegalArgumentException("PlayTime millis cannot be negative");
}
}

public static PlayTime of(@NotNull Duration duration) {
return new PlayTime(duration.toMillis());
}

public static PlayTime ofMillis(long millis) {
return new PlayTime(millis);
}

public static PlayTime ofTicks(long ticks) {
return new PlayTime(Math.multiplyExact(ticks, MILLIS_PER_TICK));
}

public long toMillis() {
return millis;
}

public Duration toDuration() {
return Duration.ofMillis(millis);
}

public long toSeconds() {
return TimeUnit.MILLISECONDS.toSeconds(millis);
}

public int toTicks() {
return Math.toIntExact(millis / MILLIS_PER_TICK);
}

public boolean isZero() {
return millis == 0;
}

public PlayTime plus(@NotNull PlayTime other) {
return new PlayTime(Math.addExact(millis, other.millis));
}

public PlayTime minus(@NotNull PlayTime other) {
return new PlayTime(Math.subtractExact(millis, other.millis));
}

@Override
public int compareTo(PlayTime o) {
return Long.compare(millis, o.millis);
}
}
Original file line number Diff line number Diff line change
@@ -1,59 +1,17 @@
package com.github.imdmk.playtime;

import com.github.imdmk.playtime.user.UserService;
import org.jetbrains.annotations.NotNull;

/**
* Central API contract for interacting with the PlayTime plugin’s core services.
*
* <p>This interface provides unified access to the main subsystems of the plugin:</p>
*
* <ul>
* <li>{@link UserService} – manages player data persistence, synchronization,
* and user-specific statistics.</li>
* <li>{@link PlaytimeService} – handles retrieval and manipulation of player
* playtime data.</li>
* </ul>
*
* <p>External plugins can use this interface to integrate with PlayTime features
* without depending on internal implementation details. The implementation is provided
* automatically by the PlayTime plugin during runtime initialization.</p>
*
* <p><b>Usage Example:</b></p>
*
* <pre>{@code
* PlayTimeApi api = PlayTimeApiProvider.get();
*
* UserService userService = api.userService();
* PlaytimeService playtimeService = api.playtimeService();
*
* UUID uuid = player.getUniqueId();
* UserTime time = playtimeService.getTime(uuid);
* }</pre>
*
* @see PlaytimeService
* @see com.github.imdmk.playtime.user.UserService
* @see com.github.imdmk.playtime.user.UserTime
*/
import java.util.UUID;
import java.util.concurrent.CompletableFuture;

public interface PlayTimeApi {

/**
* Returns the {@link UserService}, which provides access to user-management operations
* such as creating, saving, and retrieving user data including playtime,
* ranks, and metadata.
*
* @return non-null {@link UserService} instance
*/
@NotNull UserService userService();
CompletableFuture<PlayTime> getTime(@NotNull UUID uuid);

CompletableFuture<Void> setTime(@NotNull UUID uuid, @NotNull PlayTime time);
CompletableFuture<Void> addTime(@NotNull UUID uuid, @NotNull PlayTime delta);

CompletableFuture<Void> resetTime(@NotNull UUID uuid);

/**
* Returns the {@link PlaytimeService}, which provides high-level operations for
* retrieving and modifying player playtime data.
*
* <p>This service acts as the bridge between the plugin’s internal user model
* and the underlying storage or platform-specific systems.</p>
*
* @return non-null {@link PlaytimeService} instance
*/
@NotNull PlaytimeService playtimeService();
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,6 @@

import org.jetbrains.annotations.NotNull;

/**
* Static access point for the {@link PlayTimeApi}.
* <p>
* Thread-safe: publication via synchronized register/unregister and a volatile reference.
*/
public final class PlayTimeApiProvider {

private static volatile PlayTimeApi API; // visibility across threads
Expand All @@ -15,56 +10,26 @@ private PlayTimeApiProvider() {
throw new UnsupportedOperationException("This class cannot be instantiated.");
}

/**
* Returns the registered {@link PlayTimeApi}.
*
* @return the registered API
* @throws IllegalStateException if the API is not registered
*/
public static @NotNull PlayTimeApi get() {
PlayTimeApi api = API;
@NotNull
public static PlayTimeApi get() {
final PlayTimeApi api = API;
if (api == null) {
throw new IllegalStateException("PlayTimeAPI is not registered.");
}
return api;
}

/**
* Checks if the API is registered
*
* @return {@code true} if the API is registered.
*/
public static boolean isRegistered() {
return API != null;
}

/**
* Registers the {@link PlayTimeApi} instance.
*
* @param api the API instance to register
* @throws IllegalStateException if already registered
*/
static synchronized void register(@NotNull PlayTimeApi api) {
if (API != null) {
throw new IllegalStateException("PlayTimeAPI is already registered.");
}
API = api;
}

/**
* Forces registration of the {@link PlayTimeApi} instance.
* <p>
* Intended for tests/bootstrap only; overwrites any existing instance.
*/
static synchronized void forceRegister(@NotNull PlayTimeApi api) {
API = api;
}

/**
* Unregisters the {@link PlayTimeApi}.
*
* @throws IllegalStateException if no API was registered
*/
static synchronized void unregister() {
if (API == null) {
throw new IllegalStateException("PlayTimeAPI is not registered.");
Expand Down

This file was deleted.

Loading
Loading