Skip to content

Commit

Permalink
Use the proper packet to close the loading screen
Browse files Browse the repository at this point in the history
  • Loading branch information
Tim203 committed Oct 8, 2024
1 parent 36674c6 commit 6b1a9f0
Showing 1 changed file with 26 additions and 9 deletions.
35 changes: 26 additions & 9 deletions src/main/java/org/geysermc/globallinkserver/java/JavaServer.java
Original file line number Diff line number Diff line change
Expand Up @@ -26,11 +26,13 @@

import static org.geysermc.mcprotocollib.protocol.codec.MinecraftCodec.CODEC;

import java.util.BitSet;
import java.util.Collections;
import java.util.OptionalInt;
import net.kyori.adventure.key.Key;
import net.kyori.adventure.text.Component;
import org.cloudburstmc.math.vector.Vector3i;
import org.cloudburstmc.nbt.NbtMap;
import org.geysermc.globallinkserver.config.Config;
import org.geysermc.globallinkserver.link.LinkManager;
import org.geysermc.globallinkserver.player.PlayerManager;
Expand All @@ -50,6 +52,8 @@
import org.geysermc.mcprotocollib.protocol.data.game.command.properties.IntegerProperties;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.GameMode;
import org.geysermc.mcprotocollib.protocol.data.game.entity.player.PlayerSpawnInfo;
import org.geysermc.mcprotocollib.protocol.data.game.level.LightUpdateData;
import org.geysermc.mcprotocollib.protocol.data.game.level.block.BlockEntityInfo;
import org.geysermc.mcprotocollib.protocol.data.game.level.notify.GameEvent;
import org.geysermc.mcprotocollib.protocol.data.status.PlayerInfo;
import org.geysermc.mcprotocollib.protocol.data.status.ServerStatusInfo;
Expand All @@ -59,14 +63,16 @@
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundLoginPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerAbilitiesPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundPlayerPositionPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.entity.player.ClientboundSetHealthPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundGameEventPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundLevelChunkWithLightPacket;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.level.ClientboundSetDefaultSpawnPositionPacket;

public class JavaServer implements org.geysermc.globallinkserver.Server {
private final PlayerManager playerManager;
private final LinkManager linkManager;

private final ClientboundLevelChunkWithLightPacket cachedChunk = cachedChunk();

private final ServerStatusInfo pong = new ServerStatusInfo(
Component.text("Global Link Server"),
new PlayerInfo(1, 0, Collections.emptyList()),
Expand All @@ -91,8 +97,8 @@ public boolean startServer(Config config) {

server.setGlobalFlag(MinecraftConstants.SESSION_SERVICE_KEY, new SessionService());
server.setGlobalFlag(MinecraftConstants.VERIFY_USERS_KEY, true);
server.setGlobalFlag(MinecraftConstants.SERVER_INFO_BUILDER_KEY, (ServerInfoBuilder) session -> pong);
server.setGlobalFlag(MinecraftConstants.SERVER_LOGIN_HANDLER_KEY, (ServerLoginHandler) session -> {
server.setGlobalFlag(MinecraftConstants.SERVER_INFO_BUILDER_KEY, session -> pong);
server.setGlobalFlag(MinecraftConstants.SERVER_LOGIN_HANDLER_KEY, session -> {
session.send(new ClientboundCommandsPacket(
new CommandNode[] {
new CommandNode(
Expand Down Expand Up @@ -151,20 +157,16 @@ public boolean startServer(Config config) {

session.send(new ClientboundPlayerAbilitiesPacket(false, false, true, false, 0f, 0f));

// without this the player will spawn only after waiting 30 seconds
// there are multiple options to fix that,
// but this is the best option as we don't want to send chunk and the player is in spectator anyway
session.send(new ClientboundSetHealthPacket(0, 0, 0));

// this packet is also required to let our player spawn, but the location itself doesn't matter
session.send(new ClientboundSetDefaultSpawnPositionPacket(Vector3i.ZERO, 0));

// we have to listen to the teleport confirm on the PacketHandler to prevent respawn request packet spam,
// so send it after calling ConnectedEvent which adds the PacketHandler as listener
session.send(new ClientboundPlayerPositionPacket(0, 0, 0, 0, 0, 0));

// this packet is required since 1.20.3
// these packet are required since 1.20.3
session.send(new ClientboundGameEventPacket(GameEvent.LEVEL_CHUNKS_LOAD_START, null));
session.send(cachedChunk);

// Manually call the connect event
session.callEvent(new ConnectedEvent(session));
Expand Down Expand Up @@ -192,4 +194,19 @@ public void shutdown() {
server.close();
server = null;
}

private ClientboundLevelChunkWithLightPacket cachedChunk() {
// Based off https://github.com/Nan1t/NanoLimbo/pull/79
byte[] sectionData = new byte[]{0, 0, 0, 0, 0, 0, 1, 0};
var chunkData = new byte[sectionData.length * 16];
var lastIndex = 0;
for (int i = 0; i < 16; i++) {
System.arraycopy(sectionData, 0, chunkData, lastIndex, sectionData.length);
lastIndex += sectionData.length;
}
// new byte[] { 1, 0, 0, 0, 1, 0, 0, 0, 0, 0, 3, -1, -1, 0, 0 } but then decoded
var lightData = new LightUpdateData(new BitSet(), new BitSet(), new BitSet(), BitSet.valueOf(new long[] {262143}), Collections.emptyList(), Collections.emptyList());
var nbt = NbtMap.builder().putCompound("root", NbtMap.builder().putLongArray("MOTION_BLOCKING", new long[37]).build()).build();
return new ClientboundLevelChunkWithLightPacket(0, 0, chunkData, nbt, new BlockEntityInfo[0], lightData);
}
}

0 comments on commit 6b1a9f0

Please sign in to comment.