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
Tested on 1.21.1
  • Loading branch information
Tim203 committed Oct 8, 2024
1 parent 36674c6 commit e5e5e88
Showing 1 changed file with 31 additions and 31 deletions.
62 changes: 31 additions & 31 deletions src/main/java/org/geysermc/globallinkserver/java/JavaServer.java
Original file line number Diff line number Diff line change
@@ -1,36 +1,20 @@
/*
* Copyright (c) 2021-2024 GeyserMC
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in all
* copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*
* @author GeyserMC
* Licensed under the MIT license
* @link https://github.com/GeyserMC/GlobalLinkServer
*/
package org.geysermc.globallinkserver.java;

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

import java.util.BitSet;
import java.util.Collections;
import java.util.List;
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 @@ -43,30 +27,32 @@
import org.geysermc.mcprotocollib.network.tcp.TcpServer;
import org.geysermc.mcprotocollib.protocol.MinecraftConstants;
import org.geysermc.mcprotocollib.protocol.MinecraftProtocol;
import org.geysermc.mcprotocollib.protocol.ServerLoginHandler;
import org.geysermc.mcprotocollib.protocol.data.game.command.CommandNode;
import org.geysermc.mcprotocollib.protocol.data.game.command.CommandParser;
import org.geysermc.mcprotocollib.protocol.data.game.command.CommandType;
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;
import org.geysermc.mcprotocollib.protocol.data.status.VersionInfo;
import org.geysermc.mcprotocollib.protocol.data.status.handler.ServerInfoBuilder;
import org.geysermc.mcprotocollib.protocol.packet.ingame.clientbound.ClientboundCommandsPacket;
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 +77,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 +137,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 packets 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 +174,22 @@ public void shutdown() {
server.close();
server = null;
}

private ClientboundLevelChunkWithLightPacket cachedChunk() {
// 8 bytes for every section:
// short - block count
// for both blocks and biomes:
// byte - bits per entry
// varint(1) - block ID (0, air)
// varint(1) - data length
// times 16 for the 16 chunk sections that the end biome has
byte[] chunkData = new byte[8 * 16];

// just setting everything to empty seems to do the trick
var lightData =
new LightUpdateData(new BitSet(), new BitSet(), new BitSet(), new BitSet(), List.of(), List.of());
// same applies for the heightmaps
return new ClientboundLevelChunkWithLightPacket(
0, 0, chunkData, NbtMap.EMPTY, new BlockEntityInfo[0], lightData);
}
}

0 comments on commit e5e5e88

Please sign in to comment.