{"id":49078203,"url":"https://github.com/ez-plugins/teams-api","last_synced_at":"2026-05-27T14:08:12.682Z","repository":{"id":352595781,"uuid":"1215783635","full_name":"ez-plugins/teams-api","owner":"ez-plugins","description":"The universal bridge between Minecraft team plugins and everything else.","archived":false,"fork":false,"pushed_at":"2026-05-13T23:13:00.000Z","size":8543,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-14T01:35:35.304Z","etag":null,"topics":["factions","factions-api","factions-plugin","java-21","minecraft"],"latest_commit_sha":null,"homepage":"https://ez-plugins.github.io/teams-api/","language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ez-plugins.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":"AGENTS.md","dco":null,"cla":null}},"created_at":"2026-04-20T08:51:38.000Z","updated_at":"2026-05-13T23:13:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/ez-plugins/teams-api","commit_stats":null,"previous_names":["ez-plugins/teams-api"],"tags_count":9,"template":false,"template_full_name":null,"purl":"pkg:github/ez-plugins/teams-api","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ez-plugins%2Fteams-api","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ez-plugins%2Fteams-api/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ez-plugins%2Fteams-api/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ez-plugins%2Fteams-api/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ez-plugins","download_url":"https://codeload.github.com/ez-plugins/teams-api/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ez-plugins%2Fteams-api/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33160167,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-17T22:39:12.733Z","status":"ssl_error","status_checked_at":"2026-05-17T22:39:10.741Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["factions","factions-api","factions-plugin","java-21","minecraft"],"created_at":"2026-04-20T11:00:31.611Z","updated_at":"2026-05-27T14:08:12.668Z","avatar_url":"https://github.com/ez-plugins.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# TeamsAPI\r\n\r\n[![CI](https://github.com/ez-plugins/teams-api/actions/workflows/ci.yml/badge.svg)](https://github.com/ez-plugins/teams-api/actions)\r\n[![codecov](https://codecov.io/gh/ez-plugins/teams-api/branch/main/graph/badge.svg)](https://codecov.io/gh/ez-plugins/teams-api)\r\n[![License](https://img.shields.io/github/license/ez-plugins/teams-api)](LICENSE)\r\n[![Jitpack](https://jitpack.io/v/ez-plugins/teams-api.svg)](https://jitpack.io/#ez-plugins/teams-api)\r\n\r\nTeamsAPI is a universal bridge plugin for Minecraft servers. Inspired by\r\n[Vault](https://github.com/MilkBowl/VaultAPI), it defines a clean, stable interface\r\nfor team operations so any plugin that needs team data can work with any compatible\r\nteam plugin without coupling them together.\r\n\r\n## How It Works\r\n\r\n```text\r\nYour Plugin (consumer)  -\u003e  TeamsAPI (bridge)  -\u003e  Team Plugin (provider)\r\n```\r\n\r\n- **Providers** (e.g. faction, clan, guild plugins) implement `TeamsService` and\r\n  register with TeamsAPI during `onEnable()`.\r\n- **Consumers** (any plugin that needs team data) call `TeamsAPI.getService()` and\r\n  use the returned `TeamsService` without knowing which team plugin is installed.\r\n- **Server owners** install `TeamsAPI.jar` alongside any single compatible team plugin.\r\n\r\n## Download\r\n\r\n[GitHub Releases](https://github.com/ez-plugins/teams-api/releases) |\r\n[Modrinth](https://modrinth.com/plugin) | [Hangar](https://hangar.papermc.io/EzPlugins)\r\n\r\n## For Developers\r\n\r\n### Add the dependency\r\n\r\n**Maven** (via [Jitpack](https://jitpack.io/#ez-plugins/teams-api)):\r\n\r\n```xml\r\n\u003crepositories\u003e\r\n    \u003crepository\u003e\r\n        \u003cid\u003ejitpack.io\u003c/id\u003e\r\n        \u003curl\u003ehttps://jitpack.io\u003c/url\u003e\r\n    \u003c/repository\u003e\r\n\u003c/repositories\u003e\r\n\r\n\u003cdependency\u003e\r\n    \u003cgroupId\u003ecom.github.ez-plugins\u003c/groupId\u003e\r\n    \u003cartifactId\u003eteams-api\u003c/artifactId\u003e\r\n    \u003cversion\u003e2.3.0\u003c/version\u003e\r\n    \u003cscope\u003eprovided\u003c/scope\u003e\r\n\u003c/dependency\u003e\r\n```\r\n\r\n**Gradle**:\r\n\r\n```groovy\r\nrepositories {\r\n    maven { url 'https://jitpack.io' }\r\n}\r\ndependencies {\r\n    compileOnly 'com.github.ez-plugins:teams-api:2.3.0'\r\n}\r\n```\r\n\r\n### Consumer usage\r\n\r\n```java\r\n// In onEnable() or lazily:\r\nif (!TeamsAPI.isAvailable()) {\r\n    getLogger().warning(\"No team plugin found. Team features disabled.\");\r\n    return;\r\n}\r\n\r\n// Anywhere team data is needed:\r\nTeamsService teams = TeamsAPI.getService();\r\nOptional\u003cTeam\u003e team = teams.getPlayerTeam(player.getUniqueId());\r\nteam.ifPresent(t -\u003e player.sendMessage(\"Team: \" + t.getDisplayName()));\r\n```\r\n\r\n### Provider registration\r\n\r\n```java\r\nprivate MyTeamsService teamsService;\r\n\r\n@Override\r\npublic void onEnable() {\r\n    teamsService = new MyTeamsService(this);\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n}\r\n```\r\n\r\n### Invite service (optional)\r\n\r\nIf the active team plugin supports invitations, a `TeamsInviteService` is available:\r\n\r\n```java\r\nif (TeamsAPI.isInviteAvailable()) {\r\n    TeamsInviteService invites = TeamsAPI.getInviteService();\r\n    invites.invitePlayer(teamId, sender.getUniqueId(), target.getUniqueId());\r\n}\r\n```\r\n\r\nProviders that support invitations register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerInviteProvider(this, inviteService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterInviteProvider(inviteService);\r\n}\r\n```\r\n\r\n### Warp service (optional)\r\n\r\nIf the active team plugin supports named warps, a `TeamsWarpService` is available:\r\n\r\n```java\r\nif (TeamsAPI.isWarpAvailable()) {\r\n    TeamsWarpService warps = TeamsAPI.getWarpService();\r\n    warps.getWarp(teamId, \"home\").ifPresent(w -\u003e player.teleport(w.getLocation()));\r\n}\r\n```\r\n\r\nProviders that support warps register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerWarpProvider(this, warpService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterWarpProvider(warpService);\r\n}\r\n```\r\n\r\n### Team chest service (optional)\r\n\r\nIf the active team plugin supports team chest operations, a `TeamsChestService`\r\nis available:\r\n\r\n```java\r\nif (TeamsAPI.isChestAvailable()) {\r\n    TeamsChestService chests = TeamsAPI.getChestService();\r\n    Collection\u003cString\u003e chestIds = chests.getChestIds(teamId);\r\n    Collection\u003cItemStack\u003e defaultContents = chests.getContents(teamId);\r\n    Collection\u003cItemStack\u003e vaultContents = chests.getContents(teamId, \"vault\");\n    boolean replaced = chests.setContents(teamId, \"vault\", vaultContents);\n}\n```\n\r\nProviders that support team chests register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerChestProvider(this, chestService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterChestProvider(chestService);\r\n}\r\n```\r\n\r\n### Claim service (optional)\r\n\r\nIf the active team plugin supports chunk claims, a `TeamsClaimService` is available:\r\n\r\n```java\r\nif (TeamsAPI.isClaimAvailable()) {\r\n    TeamsClaimService claims = TeamsAPI.getClaimService();\r\n    Chunk chunk = player.getLocation().getChunk();\r\n    boolean claimed = claims.claimChunk(\r\n        teamId, player.getUniqueId(),\r\n        chunk.getWorld().getName(), chunk.getX(), chunk.getZ()\r\n    );\r\n}\r\n```\r\n\r\nTerritory type checks are also available for SafeZone/WarZone-aware providers:\r\n\r\n```java\r\nClaimTerritoryType territory = claims.getTerritoryTypeAt(\r\n    chunk.getWorld().getName(), chunk.getX(), chunk.getZ()\r\n);\r\nif (territory == ClaimTerritoryType.SAFE_ZONE) {\r\n    player.sendMessage(\"You are in SafeZone.\");\r\n}\r\n```\r\n\r\nProviders that support claims register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerClaimProvider(this, claimService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterClaimProvider(claimService);\r\n}\r\n```\r\n\r\n### Power service (optional)\r\n\r\nIf the active team plugin exposes power values, a `TeamsPowerService` is available:\r\n\r\n```java\r\nif (TeamsAPI.isPowerAvailable()) {\r\n    TeamsPowerService power = TeamsAPI.getPowerService();\r\n    double current = power.getTeamPower(teamId);\r\n    double max = power.getTeamMaxPower(teamId);\r\n    player.sendMessage(\"Team power: \" + current + \" / \" + max);\r\n}\r\n```\r\n\r\n### Power history service (optional)\r\n\r\nIf the active team plugin exposes power history, a `TeamsPowerHistoryService`\r\nis available:\r\n\r\n```java\r\nif (TeamsAPI.isPowerHistoryAvailable()) {\r\n    TeamsPowerHistoryService history = TeamsAPI.getPowerHistoryService();\r\n    Collection\u003cTeamPowerHistoryEntry\u003e recent =\r\n        history.getPlayerPowerHistory(player.getUniqueId(), 25);\r\n}\r\n```\r\n\r\nProviders that expose power history register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerPowerHistoryProvider(this, powerHistoryService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterPowerHistoryProvider(powerHistoryService);\r\n}\r\n```\r\n\r\nProviders that expose power register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerPowerProvider(this, powerService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterPowerProvider(powerService);\r\n}\r\n```\r\n\r\n### Relation service (optional)\r\n\r\nIf the active team plugin supports inter-team diplomacy, a `TeamsRelationService` is\r\navailable. Relations are directional — team A can declare `ALLY` toward team B\r\nindependently of what team B declares toward team A.\r\n\r\n```java\r\nif (TeamsAPI.isRelationAvailable()) {\r\n    TeamsRelationService relations = TeamsAPI.getRelationService();\r\n\r\n    // Declare an alliance\r\n    relations.setRelation(myTeamId, theirTeamId, TeamRelation.ALLY, player.getUniqueId());\r\n\r\n    // Query the current relation\r\n    TeamRelation rel = relations.getRelation(myTeamId, theirTeamId);\r\n    player.sendMessage(\"Relation: \" + rel.getDisplayName());\r\n\r\n    // Convenience helpers (mutual check)\r\n    if (relations.areAllies(myTeamId, theirTeamId)) {\r\n        player.sendMessage(\"You are mutual allies!\");\r\n    }\r\n}\r\n```\r\n\r\nProviders that support relations register the service alongside `TeamsService`:\r\n\r\n```java\r\n@Override\r\npublic void onEnable() {\r\n    TeamsAPI.registerProvider(this, teamsService);\r\n    TeamsAPI.registerRelationProvider(this, relationService);\r\n}\r\n\r\n@Override\r\npublic void onDisable() {\r\n    TeamsAPI.unregisterProvider(teamsService);\r\n    TeamsAPI.unregisterRelationProvider(relationService);\r\n}\r\n```\r\n\r\n`TeamRelation` values (lowest → highest hostility): `MEMBER`, `ALLY`, `TRUCE`, `NEUTRAL`, `ENEMY`.\r\n\r\nNote: `TeamRelation` now includes an optional classification layer via the\r\n`RelationNature` enum (`FRIENDLY`, `NEUTRAL`, `HOSTILE`). Each relation constant\r\nexposes `getDefaultNature()` and `getNature()`; server or provider code may call\r\n`setNatureOverride(RelationNature)` during initialisation to re-classify relations\r\n(for example treating `TRUCE` as `NEUTRAL`). `isFriendly()` and `isHostile()` are\r\nkept unchanged for backwards compatibility.\r\n\r\n**Optional power shop**\r\n\r\n\u003e **Vault (optional):** `plugin.yml` declares `softdepend: [Vault]`. When Vault is\r\n\u003e installed the built-in power shop (`/teamsapi power buy`) can charge players.\r\n\u003e TeamsAPI loads normally without Vault; the shop is simply disabled.\r\n\r\n**TeamsAPI extensions**\r\n\r\n\u003e **Extensions:** TeamsAPI ships official extension JARs by default and provisions\r\n\u003e them into `plugins/TeamsAPI/extensions/` on startup. You can also download extension\r\n\u003e JARs from GitHub Releases/Modrinth, install via `/teamsapi install \u003cextension\u003e`, and\r\n\u003e load without restart using `/teamsapi load \u003cfile\u003e.jar`.\r\n\r\nAny plugin can register a `TeamsSubcommand` via `TeamsAPI.registerSubcommand()`. Team\r\nplugins call `TeamsAPI.getSubcommands()` in their own command executor to dispatch them,\r\nallowing third-party plugins to extend the team plugin's command tree without any direct\r\ncoupling between plugins.\r\n\r\nExtend `AbstractTeamsSubcommand` (recommended) or implement `TeamsSubcommand` directly:\r\n\r\n```java\r\npublic class StatsSubcommand extends AbstractTeamsSubcommand {\r\n    public StatsSubcommand() {\r\n        super(\"stats\", \"Show faction statistics.\", \"myfactions.stats\");\r\n    }\r\n\r\n    @Override\r\n    public boolean execute(CommandSender sender, String[] args) {\r\n        // handle the command\r\n        return true; // return false to trigger the usage hint\r\n    }\r\n}\r\n\r\n// In onEnable:\r\nTeamsAPI.registerSubcommand(this, new StatsSubcommand());\r\n\r\n// In onDisable:\r\nTeamsAPI.unregisterSubcommand(statsSubcommand);\r\n```\r\n\r\nTeam plugins dispatch registered subcommands inside their own command executor:\r\n\r\n```java\r\nfor (TeamsSubcommand sub : TeamsAPI.getSubcommands()) {\r\n    if (sub.getName().equalsIgnoreCase(args[0])) {\r\n        String perm = sub.getPermission();\r\n        if (perm != null \u0026\u0026 !sender.hasPermission(perm)) {\r\n            sender.sendMessage(\"You do not have permission.\");\r\n            return true;\r\n        }\r\n        if (!sub.execute(sender, args)) {\r\n            sender.sendMessage(\"Usage: \" + sub.getUsage());\r\n        }\r\n        return true;\r\n    }\r\n}\r\n```\r\n\r\n| Method | Returns | Description |\r\n|--------|---------|-------------|\r\n| `getName()` | `String` | Matched case-insensitively against `args[0]` |\r\n| `getDescription()` | `String` | Optional description for help output |\r\n| `getPermission()` | `String` | Required permission, or `null` for no check |\r\n| `execute(sender, args)` | `boolean` | Called when dispatched; return `false` to show usage |\r\n| `getUsage()` | `String` | Usage hint sent when `execute` returns `false` |\r\n| `tabComplete(sender, args)` | `List\u003cString\u003e` | Tab-completion suggestions; default: empty list |\r\n\r\n### Events\r\n\r\nProvider events extend `TeamEvent`. Core events are cancellable:\r\n\r\n```java\r\n@EventHandler\r\npublic void onTeamJoin(TeamJoinEvent event) {\r\n    if (event.getTeam().getSize() \u003e= 10) {\r\n        event.setCancelled(true);\r\n    }\r\n}\r\n\r\n@EventHandler\r\npublic void onWarpSet(TeamWarpSetEvent event) {\r\n    // Cancel to prevent the warp from being saved\r\n}\r\n\r\n@EventHandler\r\npublic void onClaim(TeamClaimEvent event) {\r\n    // Cancel to block the claim\r\n}\r\n\r\n@EventHandler\r\npublic void onUnclaim(TeamUnclaimEvent event) {\r\n    // Cancel to block the unclaim\r\n}\r\n```\r\n\r\nFor the complete API reference, see [docs/api.md](docs/api.md).\r\nFor integration examples, see [docs/developer-guide.md](docs/developer-guide.md).\r\n\r\n## Proxy Support\r\n\r\nTeamsAPI includes bridge plugins for both major proxy platforms:\r\n\r\n| Proxy | Plugin | Guide |\r\n|-------|--------|-------|\r\n| Velocity | `teams-api-velocity` | [Velocity Guide](docs/velocity.md) |\r\n| BungeeCord / Waterfall | `teams-api-bungeecord` | [BungeeCord Guide](docs/bungeecord.md) |\r\n\r\nBoth bridges expose an async API (`CompletableFuture\u003cT\u003e`) so proxy-side plugins can\r\nquery team data from backend servers without direct coupling.\r\n\r\n### Multi-proxy (Redis)\r\n\r\nBoth bridge plugins support **multi-proxy networks** via Redis Pub/Sub. When Redis is\r\nenabled in `config.yml`, queries that cannot be fulfilled by a local player are\r\nautomatically forwarded to another proxy in the network. All proxies must share the\r\nsame Redis instance.\r\n\r\n```yaml\r\n# plugins/teamsapi/config.yml\r\nredis:\r\n  enabled: true\r\n  host: \"your-redis-host\"\r\n  port: 6379\r\n  prefix: \"teamsapi:\"\r\n```\r\n\r\nSee the [Velocity Guide](docs/velocity.md) or [BungeeCord Guide](docs/bungeecord.md)\r\nfor the full configuration reference.\r\n\r\n## Compatibility\r\n\r\n| Requirement | Version |\r\n|-------------|---------|\r\n| Java | 17+ (25 recommended) |\r\n| Server software | Paper / Spigot / Purpur / Folia 1.16+ |\r\n| Build tool | Maven 3.8+ or Gradle 8+ |\r\n\r\n## Build from Source\r\n\r\n```bash\r\n# Compile\r\nmvn -q -DskipTests compile\r\n\r\n# Run tests\r\nmvn -q -pl teams-api test\r\n\r\n# Build server JAR\r\nmvn -q -DskipTests package\r\n```\r\n\r\n## Project Modules\r\n\r\n| Module | Description |\r\n|--------|-------------|\r\n| `teams-api/` | Public API: interfaces, models, and events. Depend on this. |\r\n| `teams-api-plugin/` | Bukkit plugin packaging. Server owners install this JAR. |\r\n| `teams-api-extension-betterteams/` | BetterTeams provider extension (installable bridge module). |\r\n| `teams-api-extension-towny/` | Towny provider extension (installable bridge module). |\r\n| `teams-api-extension-kingdomsx/` | KingdomsX provider extension (installable bridge module). |\r\n| `teams-api-velocity/` | Velocity proxy plugin. Bridges team queries to backend servers. Supports Redis for multi-proxy setups. |\r\n| `teams-api-bungeecord/` | BungeeCord / Waterfall proxy plugin. Mirrors the Velocity bridge. Supports Redis for multi-proxy setups. |\r\n\r\n## Contributing\r\n\r\n1. `mvn -q -DskipTests compile` must succeed.\r\n2. `mvn -q -pl teams-api test` all tests must pass.\r\n3. `mvn -q -pl teams-api checkstyle:check` zero violations.\r\n4. Add tests for non-trivial logic changes.\r\n5. Update Javadoc whenever a public API changes.\r\n\r\nSee [AGENTS.md](AGENTS.md) for full coding standards.\r\n\r\n## License\r\n\r\nMIT — see [LICENSE](LICENSE).\r\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fez-plugins%2Fteams-api","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fez-plugins%2Fteams-api","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fez-plugins%2Fteams-api/lists"}