Skip to content

Instantly share code, notes, and snippets.

@Exerosis
Created February 20, 2018 13:25
Show Gist options
  • Save Exerosis/7435a03c4521133b2fd27c97f85a1d84 to your computer and use it in GitHub Desktop.
Save Exerosis/7435a03c4521133b2fd27c97f85a1d84 to your computer and use it in GitHub Desktop.
public class TeamsTabList implements TabList {
private static final String BLANK = repeat("s", 16);
private static final String BLANK_P = repeat("p", 16);
//TODO the whole updates vs tablist thing seems ugly... maybe best to do it another way.
private final Set<PlayerInfoData> tabList = new HashSet<>(80);
private final Set<PlayerInfoData> updates = new HashSet<>();
private final Set<Player> players = new HashSet<>();
private final TeamEntry[] entries;
//TODO this certainly doesn't seem ideal... maybe use updates instead somehow?
private final boolean[] set = new boolean[80];
private final Scoreboard board;
public TeamsTabList() {
board = getScoreboardManager().getNewScoreboard();
entries = range(0, 10)
.mapToObj(code -> "§" + code)
.flatMap(code -> range(1, 9).mapToObj(times ->
repeat(code, times)
))
.map(blank -> {
WrappedGameProfile profile = new WrappedGameProfile(randomUUID(), blank);
Team team = board.getTeam(blank);
if (team == null)
team = board.registerNewTeam(blank);
team.setSuffix(BLANK);
team.setPrefix(BLANK_P);
return new TeamEntry(profile, team);
})
.toArray(TeamEntry[]::new);
for (TeamEntry entry : entries)
tabList.add(entry.data);
}
private void sendTabList(Player player, boolean show) {
PacketContainer addPacket = getProtocolManager().createPacket(PLAYER_INFO);
addPacket.getPlayerInfoAction().write(0, show ? ADD_PLAYER : REMOVE_PLAYER);
addPacket.getPlayerInfoDataLists().write(0, new ArrayList<>(tabList));
try {
getProtocolManager().sendServerPacket(player, addPacket, false);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
}
@Override
public TeamsTabList showTo(Player player) {
player.setScoreboard(board);
if (players.add(player))
sendTabList(player, true);
return this;
}
@Override
public TeamsTabList hideTo(Player player) {
//TODO check
if (player.getScoreboard().equals(board))
player.setScoreboard(null);
if (players.remove(player))
sendTabList(player, false);
return this;
}
@Override
public TeamsTabList update() {
PacketContainer packet = getProtocolManager().createPacket(PLAYER_INFO);
packet.getPlayerInfoAction().write(0, ADD_PLAYER);
packet.getPlayerInfoDataLists().write(0, new ArrayList<>(updates));
players.removeIf(player -> {
try {
getProtocolManager().sendServerPacket(player, packet);
} catch (InvocationTargetException e) {
throw new RuntimeException(e);
}
return true;
});
return this;
}
@Override
public TeamEntry entry(int index) {
return entries[max(min(index, 80), 0)];
}
@Override
public Entry entry() {
for (int i = 0; i < 80; i++) {
if (!set[i])
return entry(i);
}
throw new IllegalStateException("There is no more space in this TabList.");
}
//TODO ehhhhhh seems a bit... bad?
class TeamEntry implements Entry {
private final WrappedGameProfile profile;
private final Team team;
private PlayerInfoData data;
public TeamEntry(WrappedGameProfile profile, Team team) {
this.profile = profile;
this.team = team;
queueUpdates(100);
}
@Override
public TeamEntry ping(int ping) {
queueUpdates(ping);
return this;
}
@Override
public TeamEntry skin(WrappedSignedProperty skin) {
Collection<WrappedSignedProperty> textures = profile.getProperties().get("textures");
textures.clear();
textures.add(skin);
queueUpdates(data.getLatency());
return this;
}
@Override
public void text(Object text) {
String value = text.toString();
team.setPrefix(value.substring(0, min(value.length(), 16)));
if (value.length() > 16)
team.setSuffix(value.substring(16, min(value.length(), 32)));
}
private void queueUpdates(int ping) {
data = new PlayerInfoData(profile, ping, NOT_SET, null);
if (!updates.add(data)) {
updates.remove(data);
updates.add(data);
}
if (!tabList.add(data)) {
tabList.remove(data);
tabList.add(data);
}
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment