Skip to content

Commit abc71c5

Browse files
committed
feat: proper tablist caching, fixes #730
1 parent 8487b98 commit abc71c5

1 file changed

Lines changed: 63 additions & 57 deletions

File tree

type.generic/src/main/java/net/swofty/type/generic/tab/TablistManager.java

Lines changed: 63 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,17 @@
1212
import net.swofty.type.generic.HypixelGenericLoader;
1313
import net.swofty.type.generic.user.HypixelPlayer;
1414

15+
import java.nio.charset.StandardCharsets;
1516
import java.util.*;
16-
import java.util.concurrent.atomic.AtomicReference;
17+
import java.util.concurrent.atomic.AtomicInteger;
1718

1819
public abstract class TablistManager {
19-
private static Map<HypixelPlayer, List<UUID>> tablistEntries = new HashMap<>();
20+
private static final Map<HypixelPlayer, PlayerTabCache> tablistEntries = new HashMap<>();
21+
22+
private static final class PlayerTabCache {
23+
private final List<UUID> tabEntries = new ArrayList<>();
24+
private final Set<String> createdTeams = new HashSet<>();
25+
}
2026

2127
public abstract List<TablistModule> getModules();
2228

@@ -25,89 +31,89 @@ public void deleteTablistEntries(HypixelPlayer player) {
2531
}
2632

2733
public void nullifyCache(HypixelPlayer player) {
28-
if (tablistEntries.containsKey(player) && tablistEntries.get(player) != null) {
29-
player.sendPacket(new PlayerInfoRemovePacket(tablistEntries.get(player)));
30-
tablistEntries.put(player, null);
34+
PlayerTabCache cache = tablistEntries.get(player);
35+
if (cache != null && !cache.tabEntries.isEmpty()) {
36+
player.sendPacket(new PlayerInfoRemovePacket(cache.tabEntries));
37+
cache.tabEntries.clear();
3138
}
3239
}
3340

3441
public void runScheduler(Scheduler scheduler) {
3542
scheduler.scheduleTask(() -> {
3643
HypixelGenericLoader.getLoadedPlayers().forEach(player -> {
37-
if (!tablistEntries.containsKey(player)) {
38-
tablistEntries.put(player, new ArrayList<>());
39-
} else {
40-
if (tablistEntries.get(player) == null) return;
41-
player.sendPacket(new PlayerInfoRemovePacket(tablistEntries.get(player)));
44+
PlayerTabCache cache = tablistEntries.computeIfAbsent(player, ignored -> new PlayerTabCache());
45+
46+
if (!cache.tabEntries.isEmpty()) {
47+
player.sendPacket(new PlayerInfoRemovePacket(cache.tabEntries));
4248
}
43-
tablistEntries.get(player).clear();
49+
cache.tabEntries.clear();
4450

45-
AtomicReference<Map.Entry<String, Integer>> charPrefix = new AtomicReference<>(Map.entry("§", 0));
51+
AtomicInteger slot = new AtomicInteger(0);
4652

4753
getModules().forEach(module -> {
4854
try {
4955
List<TablistModule.TablistEntry> entries = module.getEntries(player);
5056

5157
entries.forEach(entry -> {
58+
int slotIndex = slot.getAndIncrement();
59+
String teamName = getTeamName(slotIndex);
60+
String fakeProfileName = getFakeProfileName(slotIndex);
61+
5262
List<PlayerInfoUpdatePacket.Property> properties = new ArrayList<>();
5363
properties.add(new PlayerInfoUpdatePacket.Property(
54-
"textures",
55-
entry.registry().getTexture(),
56-
entry.registry().getSignature()));
64+
"textures",
65+
entry.registry().getTexture(),
66+
entry.registry().getSignature()));
5767

58-
if (!charPrefix.get().getKey().equals(entry.content())) {
59-
charPrefix.set(Map.entry(entry.content(), charPrefix.get().getValue() + 1));
60-
}
61-
62-
// 0 is AA, 1 is AB, 2 is AC, etc.
63-
// 26 is BA, 27 is BB, 28 is BC, etc.
64-
StringBuilder prefix = new StringBuilder();
65-
int value = charPrefix.get().getValue();
66-
do {
67-
// 'A' has an ASCII value of 65, so adding value % 26 gives us the letter we want.
68-
// We subtract by 1 before the modulus operation because we want 'A' to represent 0, 'B' to represent 1, and so on.
69-
char charToAdd = (char) ('A' + (value - 1) % 26);
70-
prefix.insert(0, charToAdd); // Prepend the character
71-
value = (value - 1) / 26; // Move to the next 'digit'
72-
} while (value > 0);
73-
74-
UUID uuid = UUID.randomUUID();
75-
tablistEntries.get(player).add(uuid);
76-
77-
String randomName = UUID.randomUUID().toString().substring(0, 8);
78-
79-
TeamsPacket teamPacket = new TeamsPacket(prefix.toString(), new TeamsPacket.CreateTeamAction(
80-
Component.text(prefix.toString()),
68+
if (cache.createdTeams.add(teamName)) {
69+
TeamsPacket teamPacket = new TeamsPacket(teamName, new TeamsPacket.CreateTeamAction(
70+
Component.text(teamName),
8171
(byte) 0x01,
8272
TeamsPacket.NameTagVisibility.ALWAYS,
8373
TeamsPacket.CollisionRule.ALWAYS,
8474
NamedTextColor.RED,
85-
Component.text(prefix.toString()),
75+
Component.text(teamName),
8676
Component.empty(),
87-
new ArrayList<>(Collections.singletonList(randomName))
88-
));
77+
new ArrayList<>(Collections.singletonList(fakeProfileName))
78+
));
79+
80+
player.sendPacket(teamPacket);
81+
}
82+
83+
UUID uuid = UUID.nameUUIDFromBytes((player.getUuid().toString() + "#tab#" + slotIndex)
84+
.getBytes(StandardCharsets.UTF_8));
85+
cache.tabEntries.add(uuid);
8986

9087
player.sendPackets(
91-
teamPacket,
92-
new PlayerInfoUpdatePacket(EnumSet.of(
93-
PlayerInfoUpdatePacket.Action.ADD_PLAYER,
94-
PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME,
95-
PlayerInfoUpdatePacket.Action.UPDATE_LISTED
96-
), Collections.singletonList(new PlayerInfoUpdatePacket.Entry(
97-
uuid,
98-
randomName,
99-
properties,
100-
true,
101-
0,
102-
GameMode.CREATIVE,
103-
Component.text(entry.content()),
104-
null,
105-
1, true)))
88+
new PlayerInfoUpdatePacket(EnumSet.of(
89+
PlayerInfoUpdatePacket.Action.ADD_PLAYER,
90+
PlayerInfoUpdatePacket.Action.UPDATE_DISPLAY_NAME,
91+
PlayerInfoUpdatePacket.Action.UPDATE_LISTED
92+
), Collections.singletonList(new PlayerInfoUpdatePacket.Entry(
93+
uuid,
94+
fakeProfileName,
95+
properties,
96+
true,
97+
0,
98+
GameMode.CREATIVE,
99+
Component.text(entry.content()),
100+
null,
101+
1, true)))
106102
);
107103
});
108-
} catch (Exception e) {}
104+
} catch (Exception _) {
105+
}
109106
});
110107
});
111108
}, TaskSchedule.seconds(5), TaskSchedule.seconds(3), ExecutionType.TICK_END);
112109
}
110+
111+
private static String getTeamName(int slotIndex) {
112+
return String.format(Locale.ROOT, "TAB%03d", slotIndex);
113+
}
114+
115+
private static String getFakeProfileName(int slotIndex) {
116+
return "tab" + Integer.toString(slotIndex, 36);
117+
}
118+
113119
}

0 commit comments

Comments
 (0)