Skip to Content
PluginsAquaTacDeveloper API

Developer API

New in 1.1.0. AquaTacAPI is a singleton reached with AquaTacAPI.get().

plugin.yml
softdepend: [AquaTac]

Depend on it at compile time only. The plugin ships the implementation at runtime, so shading it will break your add on.

Install

build.gradle.kts
repositories { maven("https://jitpack.io") } dependencies { compileOnly("com.github.aquatic-studios:AquaTac:1.1.0") }

Builds are published through JitPack .

Getting the API

if (!AquaTacAPI.isAvailable()) return; AquaTacAPI api = AquaTacAPI.get();

get() throws IllegalStateException while the plugin is not enabled, so check isAvailable() in anything that can run before AquaTac has loaded.

Matches

MethodReturns
isInMatch(UUID player)Whether they are playing
getMatch(Player player)Their Match, or null
getActiveMatches()How many are running
startMatch(Player first, Player second, double bet)A StartResult
startBotMatch(Player player, Bot.Difficulty difficulty)A StartResult
endMatch(Player player)Force ends theirs, if any
GameManager.StartResult result = api.startMatch(one, two, 250.0); if (result != GameManager.StartResult.OK) { one.sendMessage("Could not start: " + result); }
StartResultMeans
OKThe match started
ALREADY_IN_MATCHOne of them is busy
SENDER_NO_FUNDSThe first player cannot cover the stake
RECEIVER_NO_FUNDSThe second cannot
TRANSACTION_FAILEDThe economy refused the withdraw

startMatch skips the challenge step entirely, so it fires MatchStartEvent but never ChallengeSendEvent — that one only fires for /ttt invite.

Reading a match

Match exposes getId(), getFirstId(), getSecondId(), getFirstName(), getSecondName(), getBet(), isVsBot(), isFinished(), getBoard(), and markOf(UUID) / nameOf(Mark) / idOf(Mark) / playerOf(Mark) to move between a player and their side.

Stats

MethodReturns
getCachedStats(UUID player)Their PlayerStats, or null when not cached
getStats(OfflinePlayer player, Consumer<PlayerStats>)Loads them, then calls you back
getTop(StatColumn column, int limit, Consumer<List<PlayerStats>>)A leaderboard page
api.getStats(player, stats -> getLogger().info(stats.wins() + "W " + stats.losses() + "L " + stats.winRate() + "%"));

getStats calls back straight away, on your thread, when the player is already cached. Otherwise it loads on a background thread and calls back on the main thread. getTop always goes to the database. getCachedStats never blocks and returns null instead.

PlayerStats gives wins(), losses(), draws(), forfeits(), games(), streak(), bestStreak(), earned(), lost(), net(), winRate() and lastPlayed().

StatColumn is WINS, LOSSES, DRAWS, GAMES, STREAK, BEST_STREAK or EARNED.

Economy

MethodReturns
getEconomy()The active EconomyProvider
isBettingEnabled()Whether money is actually moving

isBettingEnabled() is false when bet.enabled is off, when the type is NONE, or when the chosen backend failed to start and fell back.

Events

EventFiresCancellable
ChallengeSendEventA challenge is sentYes
MatchStartEventA match beginsNo
MatchEndEventA match endsNo
@EventHandler public void onChallenge(ChallengeSendEvent event) { if (event.getTarget().hasMetadata("afk")) { event.setCancelled(true); return; } event.setBet(event.getBet() * 2); }

ChallengeSendEvent gives getChallenger(), getTarget(), getBet() and setBet(double), so an add on can change the stake before it is taken.

MatchEndEvent gives getMatch(), getReason(), getWinner(), getLoser() and getPayout().

EndReasonMeans
WINSomeone made three in a row
DRAWThe board filled up
LEFTA player closed the board or disconnected
TIMEOUTA player ran out of turn time
CANCELLEDThe server force ended it

On a draw and on a cancel, getWinner() and getLoser() are null.

Last updated: September 16, 2026 bySenkexin2fc986d