-
-
Notifications
You must be signed in to change notification settings - Fork 294
/
TabListRemover.java
158 lines (127 loc) · 4.85 KB
/
TabListRemover.java
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
package net.citizensnpcs.npc.skin;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;
import org.bukkit.Bukkit;
import org.bukkit.entity.Player;
import com.google.common.base.Preconditions;
import net.citizensnpcs.Settings.Setting;
import net.citizensnpcs.api.CitizensAPI;
import net.citizensnpcs.util.NMS;
/**
* Sends remove packets in batch per player.
*
* <p>
* Collects entities to remove and sends them all to the player in a single packet.
* </p>
*/
public class TabListRemover {
private final Map<UUID, PlayerEntry> pending = new HashMap<UUID, PlayerEntry>(Bukkit.getMaxPlayers() / 2);
TabListRemover() {
Bukkit.getScheduler().runTaskTimer(CitizensAPI.getPlugin(), new Sender(), 2, 2);
}
/**
* Cancel packets pending to be sent to the specified player.
*
* @param player
* The player.
*/
public void cancelPackets(Player player) {
Preconditions.checkNotNull(player);
PlayerEntry entry = pending.remove(player.getUniqueId());
if (entry == null)
return;
for (SkinnableEntity entity : entry.toRemove) {
entity.getSkinTracker().notifyRemovePacketCancelled(player.getUniqueId());
}
}
/**
* Cancel packets pending to be sent to the specified player for the specified skinnable entity.
*
* @param player
* The player.
* @param skinnable
* The skinnable entity.
*/
public void cancelPackets(Player player, SkinnableEntity skinnable) {
Preconditions.checkNotNull(player);
Preconditions.checkNotNull(skinnable);
PlayerEntry entry = pending.get(player.getUniqueId());
if (entry == null)
return;
if (entry.toRemove.remove(skinnable)) {
skinnable.getSkinTracker().notifyRemovePacketCancelled(player.getUniqueId());
}
if (entry.toRemove.isEmpty()) {
pending.remove(player.getUniqueId());
}
}
private PlayerEntry getEntry(Player player) {
PlayerEntry entry = pending.get(player.getUniqueId());
if (entry == null) {
entry = new PlayerEntry(player);
pending.put(player.getUniqueId(), entry);
}
return entry;
}
/**
* Send a remove packet to the specified player for the specified skinnable entity.
*
* @param player
* The player to send the packet to.
* @param entity
* The entity to remove.
*/
public void sendPacket(Player player, SkinnableEntity entity) {
Preconditions.checkNotNull(player);
Preconditions.checkNotNull(entity);
PlayerEntry entry = getEntry(player);
entry.toRemove.add(entity);
}
private class PlayerEntry {
Player player;
Set<SkinnableEntity> toRemove = new HashSet<SkinnableEntity>(25);
PlayerEntry(Player player) {
this.player = player;
}
}
private class Sender implements Runnable {
@Override
public void run() {
int maxPacketEntries = Setting.MAX_PACKET_ENTRIES.asInt();
Iterator<Map.Entry<UUID, PlayerEntry>> entryIterator = pending.entrySet().iterator();
while (entryIterator.hasNext()) {
Map.Entry<UUID, PlayerEntry> mapEntry = entryIterator.next();
PlayerEntry entry = mapEntry.getValue();
int listSize = Math.min(maxPacketEntries, entry.toRemove.size());
boolean sendAll = listSize == entry.toRemove.size();
List<SkinnableEntity> skinnableList = new ArrayList<SkinnableEntity>(listSize);
int i = 0;
Iterator<SkinnableEntity> skinIterator = entry.toRemove.iterator();
while (skinIterator.hasNext()) {
if (i >= maxPacketEntries)
break;
SkinnableEntity skinnable = skinIterator.next();
skinnableList.add(skinnable);
skinIterator.remove();
i++;
}
if (entry.player.isOnline()) {
NMS.sendTabListRemove(entry.player, skinnableList);
}
// notify skin trackers that a remove packet has been sent to a player
for (SkinnableEntity entity : skinnableList) {
entity.getSkinTracker().notifyRemovePacketSent(entry.player.getUniqueId());
}
if (sendAll) {
entryIterator.remove();
}
}
}
}
}