import { Tab, Tabs } from 'nextra-theme-docs'
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
Explore each integration by cycling through each tab, to find the best fit for your requirements and needs.
<Tabs items={['Apollo API', 'apollo-protos library', 'Manual JSON Object Construction']}>
private final Map<UUID, Team> teamsByTeamId = Maps.newHashMap();
private final Map<UUID, Team> teamsByPlayerUuid = Maps.newHashMap();
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 HashMap<>();
}
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 member) {
Location location = member.getLocation();
return TeamMember.builder()
.playerUuid(member.getUniqueId())
.displayName(Component.text()
.content(member.getName())
.color(NamedTextColor.WHITE)
.build())
.markerColor(Color.WHITE)
.location(ApolloLocation.builder()
.world(location.getWorld().getName())
.x(location.getX())
.y(location.getY())
.z(location.getZ())
.build())
.build();
}
// The refresh method used for updating members locations
public void refresh() {
List<TeamMember> teammates = this.members.values()
.stream().filter(Player::isOnline)
.map(this::createTeamMember)
.collect(Collectors.toList());
this.members.values().forEach(member -> Apollo.getPlayerManager().getPlayer(member.getUniqueId())
.ifPresent(apolloPlayer -> TeamApiExample.this.teamModule.updateTeamMembers(apolloPlayer, teammates)));
}
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();
}
}.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 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
<Tabs items={['Java Presets', 'Minecraft Presets', 'Hex & RGB']}>
The java.awt.Color class statically exposes some colors, although they do not correspond to any existing colors used in Minecraft.
.color(Color.CYAN)The ApolloColors class statically exposes colors that correspond to Bukkit/Spigot's ChatColor enum.
.color(ApolloColors.LIGHT_PURPLE)Custom colors can be created from any RGB values using new Color(int red, int green, int blue), or from any hex color using Color.decode(String hex).
.color(Color.decode("#FF00FF")).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()
)private final Map<UUID, Team> teamsByTeamId = Maps.newHashMap();
private final Map<UUID, Team> teamsByPlayerUuid = Maps.newHashMap();
public TeamProtoExample() {
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 HashMap<>();
}
public void addMember(Player player) {
this.members.put(player.getUniqueId(), player);
TeamProtoExample.this.teamsByPlayerUuid.put(player.getUniqueId(), this);
}
public void removeMember(Player player) {
this.members.remove(player.getUniqueId());
TeamProtoExample.this.teamsByPlayerUuid.remove(player.getUniqueId());
ResetTeamMembersMessage message = ResetTeamMembersMessage.getDefaultInstance();
ProtobufPacketUtil.sendPacket(player, message);
}
private TeamMember createTeamMember(Player member) {
return TeamMember.newBuilder()
.setPlayerUuid(ProtobufUtil.createUuidProto(member.getUniqueId()))
.setAdventureJsonPlayerName(AdventureUtil.toJson(
Component.text()
.content(member.getName())
.color(NamedTextColor.WHITE)
.build()
))
.setMarkerColor(ProtobufUtil.createColorProto(Color.WHITE))
.setLocation(ProtobufUtil.createLocationProto(member.getLocation()))
.build();
}
// The refresh method used for updating members locations
public void refresh() {
List<TeamMember> teammates = this.members.values().stream().filter(Player::isOnline)
.map(this::createTeamMember)
.collect(Collectors.toList());
UpdateTeamMembersMessage message = UpdateTeamMembersMessage.newBuilder()
.addAllMembers(teammates)
.build();
this.members.values().forEach(member -> ProtobufPacketUtil.sendPacket(member, message));
}
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();
}
}private final Map<UUID, Team> teamsByTeamId = Maps.newHashMap();
private final Map<UUID, Team> teamsByPlayerUuid = Maps.newHashMap();
public TeamJsonExample() {
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 HashMap<>();
}
public void addMember(Player player) {
this.members.put(player.getUniqueId(), player);
TeamJsonExample.this.teamsByPlayerUuid.put(player.getUniqueId(), this);
}
public void removeMember(Player player) {
this.members.remove(player.getUniqueId());
TeamJsonExample.this.teamsByPlayerUuid.remove(player.getUniqueId());
JsonObject message = new JsonObject();
message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.team.v1.ResetTeamMembersMessage");
JsonPacketUtil.sendPacket(player, message);
}
private JsonObject createTeamMember(Player member) {
JsonObject message = new JsonObject();
message.add("player_uuid", JsonUtil.createUuidObject(member.getUniqueId()));
message.addProperty("adventure_json_player_name", AdventureUtil.toJson(
Component.text()
.content(member.getName())
.color(NamedTextColor.WHITE)
.build()
));
message.add("marker_color", JsonUtil.createColorObject(Color.WHITE));
message.add("location", JsonUtil.createLocationObject(member.getLocation()));
return message;
}
// The refresh method used for updating members locations
public void refresh() {
JsonArray teammates = this.members.values()
.stream().filter(Player::isOnline)
.map(this::createTeamMember)
.collect(JsonArray::new, JsonArray::add, JsonArray::addAll);
JsonObject message = new JsonObject();
message.addProperty("@type", "type.googleapis.com/lunarclient.apollo.team.v1.UpdateTeamMembersMessage");
message.add("members", teammates);
this.members.values().forEach(member -> JsonPacketUtil.sendPacket(member, message));
}
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();
}
}