Add SCOPENET developer API and plugin compatibility layer (LuckPerms, PlaceholderAPI, Vault, CoreProtect, WorldGuard, Spark)
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01DjMbLQujBHunCCu5GpsHaT
This commit is contained in:
38 files changed
+2185
-4
No files matched your search
@@ -0,0 +1,7 @@
|
||||
// The public SCOPENET API: depend on this (compileOnly) from your own plugin.
|
||||
// It is bundled inside the SCOPENET plugin jar, so there is nothing to shade.
|
||||
plugins { id 'java-library' }
|
||||
repositories { maven { url = 'https://hub.spigotmc.org/nexus/content/repositories/snapshots/' } }
|
||||
dependencies {
|
||||
compileOnly 'org.spigotmc:spigot-api:1.20.1-R0.1-SNAPSHOT'
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
/** A player's guild, as seen from the server they are on. */
|
||||
public record GuildSummary(String id, String name, String tag, String role, int claims) {
|
||||
public boolean isLeader() { return "leader".equalsIgnoreCase(role); }
|
||||
public boolean isOfficer() { return isLeader() || "officer".equalsIgnoreCase(role); }
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
/** How many of a player's quests for the current period they have finished. */
|
||||
public record QuestProgress(int total, int completed, int claimed) {
|
||||
/** "3/5", handy for scoreboards. */
|
||||
public String display() { return completed + "/" + total; }
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
/**
|
||||
* The SCOPENET developer API. Everything that talks to the panel returns a
|
||||
* {@link CompletableFuture} and never blocks the server thread; the
|
||||
* {@code getCached…} methods answer instantly from data SCOPENET already holds.
|
||||
* Futures complete on a worker thread, so hop back with the Bukkit scheduler
|
||||
* before touching the world.
|
||||
*
|
||||
* <pre>{@code
|
||||
* ScopenetApi api = ScopenetApiProvider.get();
|
||||
* api.getPlayer(player.getUniqueId()).thenAccept(p -> getLogger().info(p.name() + " is level " + p.globalLevel()));
|
||||
* api.addXP(player.getUniqueId(), XpScope.SERVER, 250, "boss kill");
|
||||
* }</pre>
|
||||
*
|
||||
* Events ({@link net.scopenet.api.event.ScopenetLevelUpEvent},
|
||||
* {@link net.scopenet.api.event.GuildJoinEvent},
|
||||
* {@link net.scopenet.api.event.GuildLeaveEvent},
|
||||
* {@link net.scopenet.api.event.AchievementUnlockEvent}) are ordinary Bukkit events.
|
||||
*/
|
||||
public interface ScopenetApi {
|
||||
/** Bumped when the API changes incompatibly. */
|
||||
int API_VERSION = 1;
|
||||
|
||||
/** Load a player's SCOPENET profile. Completes with empty if they have no SCOPENET account. */
|
||||
CompletableFuture<Optional<ScopenetPlayer>> getPlayer(UUID uuid);
|
||||
|
||||
/** The last profile loaded for a player (kept fresh for online players), if any. Never blocks. */
|
||||
Optional<ScopenetPlayer> getCachedPlayer(UUID uuid);
|
||||
|
||||
/** Find a guild on this server's instance by id, tag or name. */
|
||||
CompletableFuture<Optional<ScopenetGuild>> getGuild(String idTagOrName);
|
||||
|
||||
/** The guild a player belongs to. */
|
||||
CompletableFuture<Optional<ScopenetGuild>> getPlayerGuild(UUID uuid);
|
||||
|
||||
/** A player's balance on this server's economy. */
|
||||
CompletableFuture<Double> getBalance(UUID uuid);
|
||||
|
||||
/**
|
||||
* Give (positive) or take (negative) money. Completes with the new balance, or
|
||||
* exceptionally if the player can't afford it.
|
||||
*/
|
||||
CompletableFuture<Double> addBalance(UUID uuid, String playerName, double amount, String reason);
|
||||
|
||||
/** Give (positive) or take (negative) XP. Level-ups fire {@link net.scopenet.api.event.ScopenetLevelUpEvent}. */
|
||||
CompletableFuture<XpResult> addXP(UUID uuid, XpScope scope, long amount, String reason);
|
||||
|
||||
/**
|
||||
* Move a quest forward. {@code objective} is a quest id (with {@code amount} 0 meaning "complete it")
|
||||
* or an action like {@code block_broken:DIAMOND_ORE} that any matching quest counts.
|
||||
* Completes with whether any quest advanced.
|
||||
*/
|
||||
CompletableFuture<Boolean> completeQuestObjective(UUID uuid, String objective, int amount);
|
||||
|
||||
/** A player's accepted friends. */
|
||||
CompletableFuture<List<ScopenetFriend>> getFriends(UUID uuid);
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
/** Where other plugins find the API. Also registered with Bukkit's ServicesManager. */
|
||||
public final class ScopenetApiProvider {
|
||||
private static volatile ScopenetApi api;
|
||||
|
||||
private ScopenetApiProvider() {}
|
||||
|
||||
/** @throws IllegalStateException if SCOPENET isn't loaded (add it to your plugin's depend/softdepend) */
|
||||
public static ScopenetApi get() {
|
||||
ScopenetApi current = api;
|
||||
if (current == null) throw new IllegalStateException("SCOPENET is not enabled");
|
||||
return current;
|
||||
}
|
||||
|
||||
public static boolean isAvailable() { return api != null; }
|
||||
|
||||
/** Called by SCOPENET. */
|
||||
public static void register(ScopenetApi implementation) { api = implementation; }
|
||||
|
||||
/** Called by SCOPENET when it shuts down. */
|
||||
public static void unregister(ScopenetApi implementation) {
|
||||
if (api == implementation) api = null;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/** An accepted friend, and where they are playing right now (if anywhere). */
|
||||
public record ScopenetFriend(UUID uuid, String name, boolean online, String playingOn) {}
|
||||
@@ -0,0 +1,13 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A guild and its members. Balances and claim counts are for the server the plugin runs on. */
|
||||
public record ScopenetGuild(String id, String name, String tag, String description, UUID leader, int claims, double balance, List<Member> members) {
|
||||
public record Member(UUID uuid, String name, String role) {}
|
||||
|
||||
public boolean isMember(UUID player) {
|
||||
return members.stream().anyMatch(m -> m.uuid().equals(player));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* A snapshot of one SCOPENET account. It is a copy: fetch a new one (or use the
|
||||
* cached copy, which is refreshed every few seconds for online players) to see changes.
|
||||
*
|
||||
* @param rankTitle the title earned from global level rewards, or {@code null}
|
||||
* @param leaderboard the position on the global leaderboard, or 0 when unranked
|
||||
* @param rankGroup the player's LuckPerms primary group as reported by the server, or {@code null}
|
||||
* @param guild the player's guild on this server's instance, or {@code null}
|
||||
*/
|
||||
public record ScopenetPlayer(
|
||||
UUID uuid,
|
||||
String name,
|
||||
int globalLevel,
|
||||
long globalXp,
|
||||
long globalLevelXp,
|
||||
long globalNextLevelXp,
|
||||
double globalProgress,
|
||||
String rankTitle,
|
||||
int leaderboard,
|
||||
int serverLevel,
|
||||
long serverXp,
|
||||
String serverRank,
|
||||
GuildSummary guild,
|
||||
double balance,
|
||||
long playtimeSeconds,
|
||||
long serverPlaytimeSeconds,
|
||||
int kills,
|
||||
int deaths,
|
||||
int friends,
|
||||
int achievements,
|
||||
QuestProgress dailyQuests,
|
||||
QuestProgress weeklyQuests,
|
||||
String joined,
|
||||
String rankGroup,
|
||||
String rankPrefix) {
|
||||
|
||||
public boolean inGuild() { return guild != null; }
|
||||
|
||||
public double killDeathRatio() { return deaths == 0 ? kills : (double) kills / deaths; }
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
/** What a player's XP and level are after {@link ScopenetApi#addXP}. */
|
||||
public record XpResult(XpScope scope, long xp, int level, int previousLevel) {
|
||||
public boolean leveledUp() { return level > previousLevel; }
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package net.scopenet.api;
|
||||
|
||||
/** Which level track an XP change applies to. */
|
||||
public enum XpScope {
|
||||
/** The account-wide SCOPENET level, shared by every server. */
|
||||
GLOBAL,
|
||||
/** The level on the server the plugin is running on. */
|
||||
SERVER
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.scopenet.api.event;
|
||||
|
||||
import org.bukkit.event.HandlerList;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A player unlocked a SCOPENET achievement. */
|
||||
public final class AchievementUnlockEvent extends ScopenetEvent {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final String achievementId;
|
||||
private final String title;
|
||||
private final long xp;
|
||||
|
||||
public AchievementUnlockEvent(UUID playerId, String achievementId, String title, long xp) {
|
||||
super(playerId);
|
||||
this.achievementId = achievementId;
|
||||
this.title = title;
|
||||
this.xp = xp;
|
||||
}
|
||||
|
||||
public String getAchievementId() { return achievementId; }
|
||||
public String getTitle() { return title; }
|
||||
/** XP the achievement was worth. */
|
||||
public long getXp() { return xp; }
|
||||
|
||||
@Override public HandlerList getHandlers() { return HANDLERS; }
|
||||
public static HandlerList getHandlerList() { return HANDLERS; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.scopenet.api.event;
|
||||
|
||||
import org.bukkit.event.HandlerList;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A player founded or joined a guild. */
|
||||
public final class GuildJoinEvent extends ScopenetEvent {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final String guildId;
|
||||
private final String guildName;
|
||||
private final String guildTag;
|
||||
private final String role;
|
||||
|
||||
public GuildJoinEvent(UUID playerId, String guildId, String guildName, String guildTag, String role) {
|
||||
super(playerId);
|
||||
this.guildId = guildId;
|
||||
this.guildName = guildName;
|
||||
this.guildTag = guildTag;
|
||||
this.role = role;
|
||||
}
|
||||
|
||||
public String getGuildId() { return guildId; }
|
||||
public String getGuildName() { return guildName; }
|
||||
public String getGuildTag() { return guildTag; }
|
||||
/** {@code leader}, {@code officer} or {@code member}. */
|
||||
public String getRole() { return role; }
|
||||
|
||||
@Override public HandlerList getHandlers() { return HANDLERS; }
|
||||
public static HandlerList getHandlerList() { return HANDLERS; }
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package net.scopenet.api.event;
|
||||
|
||||
import org.bukkit.event.HandlerList;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A player left (or was removed from) a guild. */
|
||||
public final class GuildLeaveEvent extends ScopenetEvent {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final String guildId;
|
||||
private final String guildName;
|
||||
private final String guildTag;
|
||||
|
||||
public GuildLeaveEvent(UUID playerId, String guildId, String guildName, String guildTag) {
|
||||
super(playerId);
|
||||
this.guildId = guildId;
|
||||
this.guildName = guildName;
|
||||
this.guildTag = guildTag;
|
||||
}
|
||||
|
||||
public String getGuildId() { return guildId; }
|
||||
/** May be {@code null} if the guild no longer exists. */
|
||||
public String getGuildName() { return guildName; }
|
||||
public String getGuildTag() { return guildTag; }
|
||||
|
||||
@Override public HandlerList getHandlers() { return HANDLERS; }
|
||||
public static HandlerList getHandlerList() { return HANDLERS; }
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
package net.scopenet.api.event;
|
||||
|
||||
import org.bukkit.event.Event;
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Base class for SCOPENET events. They are fired on the server thread when the
|
||||
* panel reports a change for a player who is on this server.
|
||||
*/
|
||||
public abstract class ScopenetEvent extends Event {
|
||||
private final UUID playerId;
|
||||
|
||||
protected ScopenetEvent(UUID playerId) {
|
||||
this.playerId = playerId;
|
||||
}
|
||||
|
||||
public UUID getPlayerId() { return playerId; }
|
||||
}
|
||||
@@ -0,0 +1,30 @@
|
||||
package net.scopenet.api.event;
|
||||
|
||||
import net.scopenet.api.XpScope;
|
||||
import org.bukkit.event.HandlerList;
|
||||
import java.util.UUID;
|
||||
|
||||
/** A player's global or server level went up. */
|
||||
public final class ScopenetLevelUpEvent extends ScopenetEvent {
|
||||
private static final HandlerList HANDLERS = new HandlerList();
|
||||
private final XpScope scope;
|
||||
private final int level;
|
||||
private final int previousLevel;
|
||||
private final long xp;
|
||||
|
||||
public ScopenetLevelUpEvent(UUID playerId, XpScope scope, int level, int previousLevel, long xp) {
|
||||
super(playerId);
|
||||
this.scope = scope;
|
||||
this.level = level;
|
||||
this.previousLevel = previousLevel;
|
||||
this.xp = xp;
|
||||
}
|
||||
|
||||
public XpScope getScope() { return scope; }
|
||||
public int getLevel() { return level; }
|
||||
public int getPreviousLevel() { return previousLevel; }
|
||||
public long getXp() { return xp; }
|
||||
|
||||
@Override public HandlerList getHandlers() { return HANDLERS; }
|
||||
public static HandlerList getHandlerList() { return HANDLERS; }
|
||||
}
|
||||
Reference in new issue
Block a user