Team Module
Overview
The team module will allow you to interact with the Team View mod in Lunar Client.
- Interact with the Team View mod
- Create, delete and update teams
- Enables displaying a marker above the head of teammates
- Set custom team marker color

Integration
Sample Code
Explore each integration by cycling through each tab, to find the best fit for your requirements and needs.
private final Map<UUID, Team> teamsByTeamId = new ConcurrentHashMap<>();
private final Map<UUID, Team> teamsByPlayerUuid = new ConcurrentHashMap<>();
public TeamApiExample() {
if (ServerUtil.isFolia()) {
this.runFoliaTeamUpdateTask();
} else {
this.runBukkitTeamUpdateTask();
}
Bukkit.getPluginManager().registerEvents(this, ApolloExamplePlugin.getInstance());
}
@EventHandler
private void onPlayerQuit(PlayerQuitEvent event) {
Player player = event.getPlayer();
this.getByPlayerUuid(player.getUniqueId()).ifPresent(team -> {
team.removeMember(player);
});
}
public Optional<Team> getByPlayerUuid(UUID playerUuid) {
return Optional.ofNullable(this.teamsByPlayerUuid.get(playerUuid));
}
public Optional<Team> getByTeamId(UUID teamId) {
return Optional.ofNullable(this.teamsByTeamId.get(teamId));
}
public Team createTeam() {
Team team = new Team();
this.teamsByTeamId.put(team.getTeamId(), team);
return team;
}
public void deleteTeam(UUID teamId) {
Team team = this.teamsByTeamId.remove(teamId);
if (team != null) {
team.getMembers().forEach(team::removeMember);
}
}
private void runBukkitTeamUpdateTask() {
Bukkit.getScheduler().runTaskTimerAsynchronously(ApolloExamplePlugin.getInstance(), () -> {
this.teamsByTeamId.values().forEach(Team::refresh);
}, 1L, 1L);
}
private void runFoliaTeamUpdateTask() {
Bukkit.getAsyncScheduler().runAtFixedRate(ApolloExamplePlugin.getInstance(), task -> {
this.teamsByTeamId.values().forEach(Team::refresh);
}, 50L, 50L, TimeUnit.MILLISECONDS);
}
public class Team {
private final UUID teamId;
private final Map<UUID, Player> members;
public Team() {
this.teamId = UUID.randomUUID();
this.members = new ConcurrentHashMap<>();
}
public void addMember(Player player) {
this.members.put(player.getUniqueId(), player);
TeamApiExample.this.teamsByPlayerUuid.put(player.getUniqueId(), this);
}
public void removeMember(Player player) {
this.members.remove(player.getUniqueId());
TeamApiExample.this.teamsByPlayerUuid.remove(player.getUniqueId());
Apollo.getPlayerManager().getPlayer(player.getUniqueId())
.ifPresent(TeamApiExample.this.teamModule::resetTeamMembers);
}
private TeamMember createTeamMember(Player player, boolean withinPlayerTrackingRange) {
TeamMember.TeamMemberBuilder builder = TeamMember.builder()
.playerUuid(player.getUniqueId())
.markerColor(Color.WHITE);
if (!withinPlayerTrackingRange) {
Location location = player.getLocation();
builder.location(ApolloLocation.builder()
.world(location.getWorld().getName())
.x(location.getX())
.y(location.getY())
.z(location.getZ())
.build());
builder.displayName(Component.text()
.content(player.getName())
.color(NamedTextColor.WHITE)
.build());
}
return builder.build();
}
public void refresh() {
for (Player viewer : this.members.values()) {
Optional<ApolloPlayer> apolloPlayerOpt = Apollo.getPlayerManager().getPlayer(viewer.getUniqueId());
if (!apolloPlayerOpt.isPresent()) {
continue;
}
List<TeamMember> teammates = new ArrayList<>();
for (Player member : this.members.values()) {
if (viewer == member) {
continue;
}
if (!viewer.canSee(member)) {
continue;
}
if (!viewer.getWorld().getName().equals(member.getWorld().getName())) {
continue;
}
boolean withinPlayerTrackingRange = this.isWithinPlayerTrackingRange(viewer, member);
teammates.add(this.createTeamMember(member, withinPlayerTrackingRange));
}
apolloPlayerOpt.ifPresent(apolloPlayer -> {
TeamApiExample.this.teamModule.updateTeamMembers(apolloPlayer, teammates);
});
}
}
/**
* <p>Check if player is within 48 blocks. Ideally, this could be checked directly
* through the server's internal entity tracker for exact tracking behavior,
* but that is not exposed in the Bukkit API.</p>
*
* @param viewer the viewer
* @param member the member
* @return whether within player tracking range
*/
private boolean isWithinPlayerTrackingRange(Player viewer, Player member) {
double maxDistance = 48;
double dx = viewer.getLocation().getX() - member.getLocation().getX();
double dz = viewer.getLocation().getZ() - member.getLocation().getZ();
return (dx * dx + dz * dz) <= (maxDistance * maxDistance);
}
public UUID getTeamId() {
return this.teamId;
}
public Collection<Player> getMembers() {
return this.members.values();
}
@Override
public boolean equals(Object other) {
if (this == other) {
return true;
}
if (other == null || other.getClass() != this.getClass()) {
return false;
}
Team team = (Team) other;
return this.teamId.equals(team.getTeamId());
}
@Override
public int hashCode() {
return this.teamId.hashCode();
}
}TeamMember Options
.playerUuid(java.util.UUID) member UUID.
.playerUuid(UUID).displayName(Component) is the display name that will be shown whenever the observer is outside view distance, but hovers over the player marker. See the chat components (opens in a new tab) page for more.
.displayName(Component.text()
.content(member.getName())
.color(NamedTextColor.WHITE)
.build()).markerColor(java.awt.Color) is how you dictate the color of the marker. See the colors page for more.
Color Types
The java.awt.Color class statically exposes some colors, although they do not correspond to any existing colors used in Minecraft.
.color(Color.CYAN).location(ApolloLocation) is using the ApolloLocation builder to create the location. See the locations page for more.
.location(ApolloLocation.builder()
.world("world")
.x(5)
.y(100)
.z(0)
.build()
)