Skip to content

Commit e181a4e

Browse files
committed
added y0 loading screen
1 parent 82704f2 commit e181a4e

File tree

10 files changed

+124
-17
lines changed

10 files changed

+124
-17
lines changed

src/main/java/net/potato/tuff/TuffX.java

Lines changed: 122 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,8 @@
3030
import java.util.concurrent.ConcurrentHashMap;
3131
import java.util.concurrent.ConcurrentLinkedQueue;
3232

33+
import java.util.logging.Level;
34+
3335
public class TuffX extends JavaPlugin implements Listener, PluginMessageListener {
3436

3537
public static final String CHANNEL = "eagler:below_y0";
@@ -38,8 +40,17 @@ public class TuffX extends JavaPlugin implements Listener, PluginMessageListener
3840
private static final int CHUNKS_PER_TICK = 2;
3941

4042
private final Map<UUID, Queue<Vector>> requestQueue = new ConcurrentHashMap<>();
43+
private final Map<UUID, Set<Vector>> currentlyQueued = new ConcurrentHashMap<>();
44+
45+
private final Map<UUID, Boolean> initialLoadingPlayers = new ConcurrentHashMap<>();
46+
private final Map<UUID, Integer> initialChunksToProcess = new ConcurrentHashMap<>();
47+
4148
private BukkitTask processorTask;
4249

50+
private void logDebug(String message) {
51+
getLogger().log(Level.INFO, "[TuffX-Debug] " + message);
52+
}
53+
4354
@Override
4455
public void onEnable() {
4556
getServer().getMessenger().registerOutgoingPluginChannel(this, CHANNEL);
@@ -75,39 +86,84 @@ public void onPluginMessageReceived(String channel, Player player, byte[] messag
7586
}
7687

7788
private void handleIncomingPacket(Player player, Location loc, String action, int chunkX, int chunkZ) {
89+
UUID playerId = player.getUniqueId();
7890
switch (action.toLowerCase()) {
7991
case "request_chunk":
80-
Queue<Vector> queue = requestQueue.computeIfAbsent(player.getUniqueId(), k -> new ConcurrentLinkedQueue<>());
81-
queue.add(new Vector(chunkX, 0, chunkZ));
92+
Vector chunkVec = new Vector(chunkX, 0, chunkZ);
93+
Set<Vector> queuedSet = currentlyQueued.computeIfAbsent(playerId, k -> ConcurrentHashMap.newKeySet());
94+
95+
if (queuedSet.add(chunkVec)) {
96+
requestQueue.computeIfAbsent(playerId, k -> new ConcurrentLinkedQueue<>()).add(chunkVec);
97+
98+
if (initialLoadingPlayers.getOrDefault(playerId, false)) {
99+
initialChunksToProcess.merge(playerId, 1, Integer::sum);
100+
logDebug("Player " + player.getName() + " needs chunk " + chunkX + "," + chunkZ + ". Total initial chunks to process: " + initialChunksToProcess.get(playerId));
101+
}
102+
}
82103
break;
83104
case "ready":
84-
String welcome = "§bWelcome, §e" + player.getName() + "§b!";
85-
byte[] payload = createWelcomePayload(welcome, getServer().getOnlinePlayers().size());
86-
if (payload != null) player.sendPluginMessage(this, CHANNEL, payload);
105+
logDebug("Player " + player.getName() + " sent READY packet. Starting initial load sequence.");
106+
107+
initialLoadingPlayers.put(playerId, true);
108+
initialChunksToProcess.put(playerId, 0);
109+
110+
new BukkitRunnable() {
111+
@Override
112+
public void run() {
113+
if (initialLoadingPlayers.containsKey(playerId)) {
114+
initialLoadingPlayers.put(playerId, false); // Lock the state.
115+
logDebug("Player " + player.getName() + " initial chunk requests locked in at " + initialChunksToProcess.getOrDefault(playerId, 0) + " chunks.");
116+
117+
if (initialChunksToProcess.getOrDefault(playerId, 0) == 0) {
118+
checkIfInitialLoadComplete(player);
119+
}
120+
}
121+
}
122+
}.runTaskLater(this, 5L);
123+
124+
player.sendPluginMessage(this, CHANNEL, createBelowY0StatusPayload(true));
87125
break;
88126
case "use_on_block":
89127
new BukkitRunnable() {
90128
@Override
91129
public void run() {
92-
Block block = loc.getBlock();
93-
ItemStack item = player.getInventory().getItemInMainHand();
94-
getServer().getPluginManager().callEvent(new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, block, block.getFace(player.getLocation().getBlock())));
130+
Block block = loc.getBlock();
131+
ItemStack item = player.getInventory().getItemInMainHand();
132+
getServer().getPluginManager().callEvent(new PlayerInteractEvent(player, Action.RIGHT_CLICK_BLOCK, item, block, block.getFace(player.getLocation().getBlock())));
95133
}
96134
}.runTask(this);
97135
break;
98136
}
99137
}
138+
139+
private byte[] createBelowY0StatusPayload(boolean status) {
140+
try (ByteArrayOutputStream bout = new ByteArrayOutputStream(); DataOutputStream out = new DataOutputStream(bout)) {
141+
out.writeUTF("belowy0_status");
142+
out.writeBoolean(status);
143+
return bout.toByteArray();
144+
} catch (IOException e) { return null; }
145+
}
100146

101147
private void startProcessorTask() {
102148
this.processorTask = new BukkitRunnable() {
103149
@Override
104150
public void run() {
105-
for (Map.Entry<UUID, Queue<Vector>> entry : requestQueue.entrySet()) {
106-
Player player = getServer().getPlayer(entry.getKey());
107-
Queue<Vector> queue = entry.getValue();
151+
for (UUID playerUUID : new HashSet<>(requestQueue.keySet())) {
152+
Player player = getServer().getPlayer(playerUUID);
153+
Queue<Vector> queue = requestQueue.get(playerUUID);
108154

109-
if (player == null || !player.isOnline() || queue.isEmpty()) continue;
155+
if (player == null || !player.isOnline()) {
156+
requestQueue.remove(playerUUID);
157+
initialLoadingPlayers.remove(playerUUID);
158+
initialChunksToProcess.remove(playerUUID);
159+
currentlyQueued.remove(playerUUID);
160+
continue;
161+
}
110162

163+
if (queue == null || queue.isEmpty()) {
164+
continue;
165+
}
166+
111167
for (int i = 0; i < CHUNKS_PER_TICK && !queue.isEmpty(); i++) {
112168
Vector vec = queue.poll();
113169
if (vec != null) {
@@ -129,16 +185,17 @@ public void run() {
129185
private void processAndSendChunk(final Player player, final Chunk chunk) {
130186
if (chunk == null || !player.isOnline()) return;
131187

132-
final Map<BlockData, int[]> conversionCache = new HashMap<>();
188+
final Vector chunkVec = new Vector(chunk.getX(), 0, chunk.getZ());
189+
logDebug("Processing chunk " + chunk.getX() + "," + chunk.getZ() + " for " + player.getName());
133190

134191
new BukkitRunnable() {
135192
@Override
136193
public void run() {
137194
final ChunkSnapshot snapshot = chunk.getChunkSnapshot(true, false, false);
195+
final Map<BlockData, int[]> conversionCache = new HashMap<>();
138196

139197
for (int sectionY = -4; sectionY < 0; sectionY++) {
140-
if (!player.isOnline()) break;
141-
198+
if (!player.isOnline()) break;
142199
try {
143200
byte[] payload = createSectionPayload(snapshot, chunk.getX(), chunk.getZ(), sectionY, conversionCache);
144201
if (payload != null) {
@@ -148,13 +205,61 @@ public void run() {
148205
getLogger().severe("Payload creation failed for " + chunk.getX() + "," + chunk.getZ() + ": " + e.getMessage());
149206
}
150207
}
208+
209+
new BukkitRunnable() {
210+
@Override
211+
public void run() {
212+
if (!player.isOnline()) return;
213+
214+
Set<Vector> queuedSet = currentlyQueued.get(player.getUniqueId());
215+
if (queuedSet != null) {
216+
queuedSet.remove(chunkVec);
217+
}
218+
checkIfInitialLoadComplete(player);
219+
}
220+
}.runTask(TuffX.this);
151221
}
152222
}.runTaskAsynchronously(this);
153223
}
154-
224+
225+
private void checkIfInitialLoadComplete(Player player) {
226+
UUID playerId = player.getUniqueId();
227+
228+
if (initialChunksToProcess.containsKey(playerId)) {
229+
int remaining = initialChunksToProcess.compute(playerId, (k, v) -> (v == null) ? -1 : v - 1);
230+
231+
logDebug("Player " + player.getName() + " finished a chunk. Remaining initial chunks: " + remaining);
232+
233+
if (remaining <= 0) {
234+
initialLoadingPlayers.remove(playerId);
235+
initialChunksToProcess.remove(playerId);
236+
237+
player.sendPluginMessage(this, CHANNEL, createLoadFinishedPayload());
238+
logDebug("INITIAL LOAD COMPLETE for " + player.getName() + ". Sent finished packet.");
239+
}
240+
}
241+
}
242+
243+
private byte[] createLoadFinishedPayload() {
244+
try (ByteArrayOutputStream bout = new ByteArrayOutputStream();
245+
DataOutputStream out = new DataOutputStream(bout)) {
246+
247+
out.writeUTF("y0_load_finished");
248+
249+
return bout.toByteArray();
250+
} catch (IOException e) {
251+
getLogger().severe("Failed to create the y0_load_finished payload!");
252+
return null;
253+
}
254+
}
255+
155256
@EventHandler
156257
public void onPlayerQuit(PlayerQuitEvent event) {
157-
requestQueue.remove(event.getPlayer().getUniqueId());
258+
UUID playerId = event.getPlayer().getUniqueId();
259+
requestQueue.remove(playerId);
260+
initialLoadingPlayers.remove(playerId);
261+
currentlyQueued.remove(playerId);
262+
initialChunksToProcess.remove(playerId);
158263
}
159264

160265
private byte[] createWelcomePayload(String message, int someNumber) {

target/TuffX.jar

4.14 KB
Binary file not shown.
104 Bytes
Binary file not shown.
-387 Bytes
Binary file not shown.
205 Bytes
Binary file not shown.
1.34 KB
Binary file not shown.
2.64 KB
Binary file not shown.
4.05 KB
Binary file not shown.

target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
net\potato\tuff\TuffX$2.class
22
net\potato\tuff\TuffX$1.class
3+
net\potato\tuff\TuffX$4.class
34
net\potato\tuff\TuffX.class
45
net\potato\tuff\TuffX$3.class
56
net\potato\tuff\ViaBlockIds$1.class
7+
net\potato\tuff\TuffX$4$1.class
68
net\potato\tuff\ViaBlockIds.class
79
net\potato\tuff\ChunkSectionKey.class
810
net\potato\tuff\LegacyBlockIds.class

target/original-TuffX.jar

4.11 KB
Binary file not shown.

0 commit comments

Comments
 (0)