𝐀𝐝𝐦𝐢𝐧𝐢𝐬𝐭𝐫𝐚𝐭𝐨𝐫𝐬
- Jan
- 26
- 3
𝐃𝐄𝐕𝐄𝐋𝐎𝐏𝐄𝐑 & 𝐀𝐃𝐌𝐈𝐍
𝐅𝐨𝐮𝐧𝐝𝐞𝐫
𝐌𝐞𝐦𝐛𝐞𝐫
DonutTeams
Team management plugin for Minecraft
Paper/Spigot 1.21+ • Java 21
Team management plugin for Minecraft
Paper/Spigot 1.21+ • Java 21
Installation
Requirements:
- Paper/Spigot 1.21+
- Java 21 or higher
- License key from Discord
Setup:
1. Download
DonutTeams.jar2. Place in
plugins/ folder3. Start server (generates
config.yml)4. Get license from discord.gg/r6XJyfzhdT
5. Edit
plugins/DonutTeams/config.yml:
Code:
License: "your-key-here"
Commands
Player Commands
| Command | Description |
|---|---|
/team create <name> | Create a team |
/team disband | Disband your team |
/team invite <player> | Invite a player |
/team join <team> | Accept invitation |
/team leave | Leave your team |
/team kick <player> | Kick a member |
/team info | Open team GUI |
/team home | Teleport to team home |
/team sethome | Set team home |
/team delhome | Delete team home |
/team chat | Toggle team chat |
/team c | Team chat alias |
/team pvp | Toggle friendly fire |
/team rename <name> | Rename team |
Admin Commands
| Command | Description |
|---|---|
/dteam reload | Reload configuration |
/dteam delete <team> | Delete any team |
/dteam list [all] | List teams |
/dteam info <team> | View team details |
/dteam forcejoin <player> <team> | Force player to team |
/dteam tphome <team> | TP to team home |
/dteam blacklist add <name> | Blacklist team name |
/dteam blacklist remove <name> | Remove from blacklist |
/dteam blacklist list | List blacklisted names |
/dteam migrate <source-dest> | Migrate databases |
/dteam switchstorage <type> | Switch storage type |
Permissions
Player:
donutteams.*- All player commandsdonutteams.createdonutteams.disbanddonutteams.invitedonutteams.joindonutteams.leavedonutteams.kickdonutteams.infodonutteams.homedonutteams.sethomedonutteams.chatdonutteams.rename
Admin:
donutteams.admin.*- All admin commandsdonutteams.admin.reloaddonutteams.admin.deletedonutteams.admin.listdonutteams.admin.infodonutteams.admin.forcejoindonutteams.admin.blacklistdonutteams.admin.migrate
Configuration
Database
Code:
database:
type: SQLITE # or MYSQL
mysql:
host: localhost
port: 3306
database: donutteams
username: root
password: password
pool-size: 10
Teams
Code:
settings:
invite-expiry-seconds: 30
team-limit: 50 # Max members per team
features:
home:
enabled: true
pvp:
enabled: true
teleport:
delay-seconds: 5
sound:
enabled: true
rename:
cooldown-minutes: 30
enabled: true
Performance
Code:
settings:
performance:
refresh-cooldown-seconds: 3
tab-complete-cooldown-ms: 500
skull-cache:
max-size: 500
expire-after-minutes: 15
Developer API
DonutTeams provides a complete API for plugin developers.
Setup
Step 1: Add JAR to project
Create
libs/ folder, add DonutTeams.jarStep 2: build.gradle
Code:
dependencies {
compileOnly files('libs/DonutTeams.jar')
}
Step 3: plugin.yml
YAML:
depend: [DonutTeams]
Step 4: Get API instance
Java:
import og.shyamstudio.donutteams.api.DonutTeamsAPI;
// In onEnable()
if (!Bukkit.getPluginManager().isPluginEnabled("DonutTeams")) {
getLogger().severe("DonutTeams not found!");
getServer().getPluginManager().disablePlugin(this);
return;
}
DonutTeamsAPI api = DonutTeamsAPI.getInstance();
getLogger().info("DonutTeams API ready!");
Basic Usage
Check if player is in a team:
Java:
DonutTeamsAPI api = DonutTeamsAPI.getInstance();
if (api.isInTeam(player.getUniqueId())) {
player.sendMessage("You're in a team!");
// Get team name
String teamName = api.getPlayerTeamName(player.getUniqueId());
player.sendMessage("Team: " + teamName);
}
Check if two players are teammates:
Java:
UUID player1 = ...;
UUID player2 = ...;
if (api.areTeammates(player1, player2)) {
// They're in the same team
}
Get team information:
Java:
import og.shyamstudio.donutteams.entity.TeamEntity;
import og.shyamstudio.donutteams.entity.member.TeamMember;
TeamEntity team = api.getTeam("TeamName");
if (team != null) {
// Get members
List<TeamMember> members = team.getMembers();
// Get leader
TeamMember leader = api.getTeamLeader("TeamName");
// Get home location
Location home = api.getTeamHome("TeamName");
// Check friendly fire
boolean ff = api.isFriendlyFireEnabled("TeamName");
}
Async Operations
Most write operations are async for performance. Always handle them properly:
Creating a team:
Java:
api.createTeam("MyTeam", leaderPlayer).thenAccept(success -> {
if (success) {
// Run on main thread for Bukkit operations
Bukkit.getScheduler().runTask(plugin, () -> {
leaderPlayer.sendMessage("§aTeam created!");
});
} else {
Bukkit.getScheduler().runTask(plugin, () -> {
leaderPlayer.sendMessage("§cFailed - you may already be in a team");
});
}
}).exceptionally(ex -> {
plugin.getLogger().severe("Error: " + ex.getMessage());
return null;
});
Adding a player to a team:
Java:
api.addPlayerToTeam("TeamName", targetPlayer).thenAccept(success -> {
Bukkit.getScheduler().runTask(plugin, () -> {
if (success) {
targetPlayer.sendMessage("§aYou joined the team!");
} else {
targetPlayer.sendMessage("§cCouldn't join team");
}
});
});
Removing a player:
Java:
api.removePlayerFromTeam(playerUUID).thenAccept(success -> {
if (success) {
plugin.getLogger().info("Player removed from team");
}
});
Disbanding a team:
Java:
api.disbandTeam("TeamName").thenAccept(success -> {
if (success) {
plugin.getLogger().info("Team disbanded");
}
});
Permission System
Team members have granular permissions. Available permissions:
TeamPermission enum:
DELETE- Disband teamMANAGE- Kick members, edit permissionsHOME- Use team homeSET_HOME- Set team homePVP- Toggle friendly fireSPEAK- Use team chatINVITE- Invite players
Check permission:
Java:
import og.shyamstudio.donutteams.entity.permission.TeamPermission;
boolean canInvite = api.hasPermission(playerUUID, TeamPermission.INVITE);
boolean isLeader = api.hasPermission(playerUUID, TeamPermission.DELETE);
Grant permission:
Java:
api.grantPermission(playerUUID, TeamPermission.MANAGE).thenAccept(success -> {
if (success) {
plugin.getLogger().info("Permission granted");
}
});
Revoke permission:
Java:
api.revokePermission(playerUUID, TeamPermission.INVITE).thenAccept(success -> {
if (success) {
plugin.getLogger().info("Permission revoked");
}
});
Events
Listen to team events in your plugin:
Java:
import og.shyamstudio.donutteams.api.events.*;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
public class TeamListener implements Listener {
@EventHandler
public void onTeamCreate(TeamCreateEvent event) {
TeamEntity team = event.getTeam();
Player leader = event.getLeader();
Bukkit.broadcastMessage(
"§6" + leader.getName() + " §ecreated team §b" + team.getName()
);
}
@EventHandler
public void onPlayerJoinTeam(TeamPlayerJoinEvent event) {
String teamName = event.getTeamName();
Player player = event.getPlayer();
player.sendMessage("§aWelcome to " + teamName + "!");
}
@EventHandler
public void onPlayerLeaveTeam(TeamPlayerLeaveEvent event) {
String teamName = event.getTeamName();
Player player = event.getPlayer();
player.sendMessage("§7You left " + teamName);
}
@EventHandler
public void onTeamDisband(TeamDisbandEvent event) {
// This event is CANCELLABLE
if (someCondition) {
event.setCancelled(true);
}
TeamEntity team = event.getTeam();
String reason = event.getReason(); // Optional
}
@EventHandler
public void onPermissionChange(TeamPermissionChangeEvent event) {
TeamMember member = event.getMember();
TeamPermission permission = event.getPermission();
boolean granted = event.isGranted();
plugin.getLogger().info(
member.getName() + " - " +
permission + ": " + granted
);
}
}
// Don't forget to register in onEnable():
getServer().getPluginManager().registerEvents(new TeamListener(), this);
Advanced: Direct Entity Access
For advanced use cases, you can work directly with TeamEntity and TeamMember:
Java:
import og.shyamstudio.donutteams.entity.TeamEntity;
import og.shyamstudio.donutteams.entity.member.TeamMember;
// Get team entity
TeamEntity team = api.getTeam("TeamName");
if (team != null) {
// Direct member access
for (TeamMember member : team.getMembers()) {
UUID uuid = member.getUniqueId();
String name = member.getName();
boolean online = member.isOnline();
Player bukkitPlayer = member.getBukkitPlayer(); // may be null
// Check permissions
if (member.hasPermission(TeamPermission.DELETE)) {
// This is the leader
}
}
// Check if specific player is in team
boolean hasMember = team.hasMember(playerUUID);
// Get creation time
Instant createdAt = team.getCreatedAt();
}
Async team loading:
Java:
// Recommended for better performance
api.getTeamAsync("TeamName").thenAccept(team -> {
if (team != null) {
// Process team data
}
});
// Same for members
api.getTeamMemberAsync(playerUUID).thenAccept(member -> {
if (member != null) {
String teamName = member.getTeamName();
// Process member data
}
});
Real-World Examples
Example 1: Economy integration
Java:
// Give bonus money to team members when leader earns money
@EventHandler
public void onPlayerEarn(PlayerEarnMoneyEvent event) {
Player leader = event.getPlayer();
double amount = event.getAmount();
String teamName = api.getPlayerTeamName(leader.getUniqueId());
if (teamName != null) {
List<Player> onlineMembers = api.getOnlineTeamMembers(teamName);
double bonus = amount * 0.1; // 10% bonus
for (Player member : onlineMembers) {
if (!member.equals(leader)) {
economy.depositPlayer(member, bonus);
member.sendMessage("§a+$" + bonus + " team bonus!");
}
}
}
}
Example 2: Prevent PvP between teammates
Java:
@EventHandler
public void onPvP(EntityDamageByEntityEvent event) {
if (!(event.getEntity() instanceof Player victim)) return;
if (!(event.getDamager() instanceof Player attacker)) return;
if (api.areTeammates(victim.getUniqueId(), attacker.getUniqueId())) {
event.setCancelled(true);
attacker.sendMessage("§cYou can't hurt your teammate!");
}
}
Example 3: Team-wide teleportation
Java:
public void teleportTeamToLocation(String teamName, Location destination) {
List<Player> onlineMembers = api.getOnlineTeamMembers(teamName);
for (Player player : onlineMembers) {
player.teleportAsync(destination).thenAccept(success -> {
if (success) {
player.sendMessage("§aTeam teleported!");
}
});
}
}
Example 4: Team-based permissions
Java:
// Give special permission to team leaders
public boolean canUseAdmin(Player player) {
return api.hasPermission(player.getUniqueId(), TeamPermission.DELETE);
}
// Give special permission to team managers
public boolean canManageRegion(Player player) {
return api.hasPermission(player.getUniqueId(), TeamPermission.MANAGE);
}
Best Practices
- Always use async methods (
getTeamAsync,createTeam, etc.) for better performance - Check
DonutTeamsAPI.isAvailable()before getting instance - Use
Bukkit.getScheduler().runTask()inside.thenAccept()for Bukkit API calls - Cache results if you need them multiple times in short period
- Use events instead of polling for team changes
- Handle exceptions in
.exceptionally()blocks
PlaceholderAPI
Placeholder:
%team_name%- Player's team name (returns "N/A" if not in team)
Support
Discord: discord.gg/r6XJyfzhdT
When reporting issues provide:
- Server version
- Java version
- Full console error
DonutTeams • by Ravi_Rai • ShyamStudio
Last edited: