From 93b6376b389d29f16e2e24729c305431913df0e8 Mon Sep 17 00:00:00 2001 From: Gero Date: Wed, 29 Mar 2023 09:21:01 +0200 Subject: [PATCH] Remove registry decoding (#979) --- .../backend/VelocityServerConnection.java | 8 +- .../client/ClientPlaySessionHandler.java | 2 +- .../connection/registry/DimensionData.java | 388 ------------------ .../registry/DimensionRegistry.java | 128 ------ .../proxy/protocol/packet/JoinGame.java | 105 ++--- .../proxy/protocol/packet/Respawn.java | 11 +- 6 files changed, 33 insertions(+), 609 deletions(-) delete mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionData.java delete mode 100644 proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionRegistry.java diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java index 22c1dd821..a2300b978 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/backend/VelocityServerConnection.java @@ -35,7 +35,6 @@ import com.velocitypowered.proxy.connection.ConnectionTypes; import com.velocitypowered.proxy.connection.MinecraftConnection; import com.velocitypowered.proxy.connection.MinecraftConnectionAssociation; import com.velocitypowered.proxy.connection.client.ConnectedPlayer; -import com.velocitypowered.proxy.connection.registry.DimensionRegistry; import com.velocitypowered.proxy.connection.util.ConnectionRequestResults.Impl; import com.velocitypowered.proxy.protocol.StateRegistry; import com.velocitypowered.proxy.protocol.packet.Handshake; @@ -52,6 +51,7 @@ import java.util.Map; import java.util.Optional; import java.util.concurrent.CompletableFuture; import java.util.function.UnaryOperator; +import net.kyori.adventure.nbt.CompoundBinaryTag; import org.checkerframework.checker.nullness.qual.MonotonicNonNull; import org.checkerframework.checker.nullness.qual.Nullable; @@ -69,7 +69,7 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, private boolean gracefulDisconnect = false; private BackendConnectionPhase connectionPhase = BackendConnectionPhases.UNKNOWN; private final Map pendingPings = new HashMap<>(); - private @MonotonicNonNull DimensionRegistry activeDimensionRegistry; + private @MonotonicNonNull CompoundBinaryTag activeDimensionRegistry; /** * Initializes a new server connection. @@ -344,11 +344,11 @@ public class VelocityServerConnection implements MinecraftConnectionAssociation, return hasCompletedJoin; } - public DimensionRegistry getActiveDimensionRegistry() { + public CompoundBinaryTag getActiveDimensionRegistry() { return activeDimensionRegistry; } - public void setActiveDimensionRegistry(DimensionRegistry activeDimensionRegistry) { + public void setActiveDimensionRegistry(CompoundBinaryTag activeDimensionRegistry) { this.activeDimensionRegistry = activeDimensionRegistry; } } diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java index 82f6706d7..bc041d8ab 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/connection/client/ClientPlaySessionHandler.java @@ -473,7 +473,7 @@ public class ClientPlaySessionHandler implements MinecraftSessionHandler { } } - destination.setActiveDimensionRegistry(joinGame.getDimensionRegistry()); // 1.16 + destination.setActiveDimensionRegistry(joinGame.getRegistry()); // 1.16 // Remove previous boss bars. These don't get cleared when sending JoinGame, thus the need to // track them. diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionData.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionData.java deleted file mode 100644 index 1a484abc0..000000000 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionData.java +++ /dev/null @@ -1,388 +0,0 @@ -/* - * Copyright (C) 2020-2023 Velocity Contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.velocitypowered.proxy.connection.registry; - -import com.google.common.base.Preconditions; -import com.velocitypowered.api.network.ProtocolVersion; -import net.kyori.adventure.nbt.CompoundBinaryTag; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Represents a dimension sent to the client by the server. - */ -public final class DimensionData { - - private static final String UNKNOWN_DIMENSION_ID = "velocity:unknown_dimension"; - - private final String registryIdentifier; - private final @Nullable Integer dimensionId; - private final boolean isNatural; - private final float ambientLight; - private final boolean isShrunk; - private final boolean isUltrawarm; - private final boolean hasCeiling; - private final boolean hasSkylight; - private final boolean isPiglinSafe; - private final boolean doBedsWork; - private final boolean doRespawnAnchorsWork; - private final boolean hasRaids; - private final int logicalHeight; - private final String burningBehaviourIdentifier; - private final @Nullable Long fixedTime; - private final @Nullable Boolean createDragonFight; - private final @Nullable Double coordinateScale; - private final @Nullable String effects; - private final @Nullable Integer minY; // Required and added by 1.17 - private final @Nullable Integer height; // Required and added by 1.17 - private final @Nullable Integer monsterSpawnBlockLightLimit; // Required and added by 1.19 - private final @Nullable Integer monsterSpawnLightLevel; // Required and added by 1.19 - - /** - * Initializes a new {@link DimensionData} instance. - * - * @param registryIdentifier the identifier for the dimension from the registry. - * @param dimensionId the dimension ID contained in the registry (the "id" tag) - * @param isNatural indicates if the dimension use natural world generation - * (e.g. overworld) - * @param ambientLight the light level the client sees without external lighting - * @param isShrunk indicates if the world is shrunk, aka not the full 256 - * blocks (e.g. nether) - * @param isUltrawarm internal dimension warmth flag - * @param hasCeiling indicates if the dimension has a ceiling layer - * @param hasSkylight indicates if the dimension should display the sun - * @param isPiglinSafe indicates if piglins should naturally zombify in this - * dimension - * @param doBedsWork indicates if players should be able to sleep in beds in this - * dimension - * @param doRespawnAnchorsWork indicates if player respawn points can be used in this - * dimension - * @param hasRaids indicates if raids can be spawned in the dimension - * @param logicalHeight the natural max height for the given dimension - * @param burningBehaviourIdentifier the identifier for how burning blocks work in the dimension - * @param fixedTime optional. If set to any game daytime value will deactivate - * time cycle - * @param createDragonFight optional. Internal flag used in the end dimension - * @param coordinateScale optional, unknown purpose - * @param effects optional, unknown purpose - * @param minY the world effective lowest build-level - * @param height the world height above zero - * @param monsterSpawnBlockLightLimit an integer controlling the block light needed to prevent - * monster spawns. - * @param monsterSpawnLightLevel an int provider which is evaluated to find a value to - * compare the current overall brightness with to determine if - * a monster should be allowed to spawn. - */ - public DimensionData(String registryIdentifier, - @Nullable Integer dimensionId, - boolean isNatural, - float ambientLight, boolean isShrunk, boolean isUltrawarm, - boolean hasCeiling, boolean hasSkylight, - boolean isPiglinSafe, boolean doBedsWork, - boolean doRespawnAnchorsWork, boolean hasRaids, - int logicalHeight, String burningBehaviourIdentifier, - @Nullable Long fixedTime, @Nullable Boolean createDragonFight, - @Nullable Double coordinateScale, - @Nullable String effects, - @Nullable Integer minY, @Nullable Integer height, - @Nullable Integer monsterSpawnBlockLightLimit, - @Nullable Integer monsterSpawnLightLevel) { - this.monsterSpawnBlockLightLimit = monsterSpawnBlockLightLimit; - this.monsterSpawnLightLevel = monsterSpawnLightLevel; - Preconditions.checkNotNull( - registryIdentifier, "registryIdentifier cannot be null"); - Preconditions.checkArgument(registryIdentifier.length() > 0, - "registryIdentifier cannot be empty"); - Preconditions.checkArgument(logicalHeight >= 0, "localHeight must be >= 0"); - Preconditions.checkNotNull( - burningBehaviourIdentifier, "burningBehaviourIdentifier cannot be null"); - Preconditions.checkArgument(burningBehaviourIdentifier.length() > 0, - "burningBehaviourIdentifier cannot be empty"); - this.registryIdentifier = registryIdentifier; - this.dimensionId = dimensionId; - this.isNatural = isNatural; - this.ambientLight = ambientLight; - this.isShrunk = isShrunk; - this.isUltrawarm = isUltrawarm; - this.hasCeiling = hasCeiling; - this.hasSkylight = hasSkylight; - this.isPiglinSafe = isPiglinSafe; - this.doBedsWork = doBedsWork; - this.doRespawnAnchorsWork = doRespawnAnchorsWork; - this.hasRaids = hasRaids; - this.logicalHeight = logicalHeight; - this.burningBehaviourIdentifier = burningBehaviourIdentifier; - this.fixedTime = fixedTime; - this.createDragonFight = createDragonFight; - this.coordinateScale = coordinateScale; - this.effects = effects; - this.minY = minY; - this.height = height; - } - - public String getRegistryIdentifier() { - return registryIdentifier; - } - - public @Nullable Integer getDimensionId() { - return dimensionId; - } - - public boolean isNatural() { - return isNatural; - } - - public float getAmbientLight() { - return ambientLight; - } - - public boolean isShrunk() { - return isShrunk; - } - - public boolean isUltrawarm() { - return isUltrawarm; - } - - public boolean hasCeiling() { - return hasCeiling; - } - - public boolean hasSkylight() { - return hasSkylight; - } - - public boolean isPiglinSafe() { - return isPiglinSafe; - } - - public boolean doBedsWork() { - return doBedsWork; - } - - public boolean doRespawnAnchorsWork() { - return doRespawnAnchorsWork; - } - - public boolean hasRaids() { - return hasRaids; - } - - public int getLogicalHeight() { - return logicalHeight; - } - - public String getBurningBehaviourIdentifier() { - return burningBehaviourIdentifier; - } - - public @Nullable Long getFixedTime() { - return fixedTime; - } - - public @Nullable Boolean getCreateDragonFight() { - return createDragonFight; - } - - public @Nullable Double getCoordinateScale() { - return coordinateScale; - } - - public @Nullable Integer getMinY() { - return minY; - } - - public @Nullable Integer getHeight() { - return height; - } - - /** - * Returns a fresh {@link DimensionData} with the specified {@code registryIdentifier} and - * {@code dimensionId}. - * - * @param registryIdentifier the identifier for the dimension from the registry - * @param dimensionId optional, dimension ID - * @return a new {@link DimensionData} - */ - public DimensionData annotateWith(String registryIdentifier, - @Nullable Integer dimensionId) { - return new DimensionData(registryIdentifier, dimensionId, isNatural, ambientLight, isShrunk, - isUltrawarm, hasCeiling, hasSkylight, isPiglinSafe, doBedsWork, doRespawnAnchorsWork, - hasRaids, logicalHeight, burningBehaviourIdentifier, fixedTime, createDragonFight, - coordinateScale, effects, minY, height, monsterSpawnBlockLightLimit, - monsterSpawnLightLevel); - } - - public boolean isUnannotated() { - return this.registryIdentifier.equalsIgnoreCase(UNKNOWN_DIMENSION_ID); - } - - /** - * Parses a given CompoundTag to a DimensionData instance. Assumes the data only contains - * dimension details. - * - * @param details the compound from the registry to read - * @param version the protocol version - * @return game dimension data - */ - public static DimensionData decodeBaseCompoundTag(CompoundBinaryTag details, - ProtocolVersion version) { - boolean isNatural = details.getBoolean("natural"); - float ambientLight = details.getFloat("ambient_light"); - boolean isShrunk = details.getBoolean("shrunk"); - boolean isUltrawarm = details.getBoolean("ultrawarm"); - boolean hasCeiling = details.getBoolean("has_ceiling"); - boolean hasSkylight = details.getBoolean("has_skylight"); - boolean isPiglinSafe = details.getBoolean("piglin_safe"); - boolean doBedsWork = details.getBoolean("bed_works"); - boolean doRespawnAnchorsWork = details.getBoolean("respawn_anchor_works"); - boolean hasRaids = details.getBoolean("has_raids"); - int logicalHeight = details.getInt("logical_height"); - String burningBehaviourIdentifier = details.getString("infiniburn"); - Long fixedTime = details.keySet().contains("fixed_time") - ? details.getLong("fixed_time") : null; - Boolean hasEnderdragonFight = details.keySet().contains("has_enderdragon_fight") - ? details.getBoolean("has_enderdragon_fight") : null; - Double coordinateScale = details.keySet().contains("coordinate_scale") - ? details.getDouble("coordinate_scale") : null; - String effects = details.keySet().contains("effects") ? details.getString("effects") - : null; - Integer minY = details.keySet().contains("min_y") ? details.getInt("min_y") : null; - Integer height = details.keySet().contains("height") ? details.getInt("height") : null; - Integer monsterSpawnBlockLightLimit = - details.keySet().contains("monster_spawn_block_light_limit") - ? details.getInt("monster_spawn_block_light_limit") : null; - Integer monsterSpawnLightLevel = - details.keySet().contains("monster_spawn_light_level") ? details.getInt( - "monster_spawn_block_light_limit") : - null; - if (version.compareTo(ProtocolVersion.MINECRAFT_1_17) >= 0) { - Preconditions.checkNotNull(height, - "DimensionData requires 'height' to be present for this version"); - Preconditions.checkNotNull(minY, - "DimensionData requires 'minY' to be present for this version"); - } - if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) { - Preconditions.checkNotNull(monsterSpawnBlockLightLimit, - "DimensionData requires 'monster_spawn_block_light_limit' to be present" - + " for this version."); - Preconditions.checkNotNull(monsterSpawnLightLevel, - "DimensionData requires 'monster_spawn_light_level' to be present" - + " for this version."); - } - return new DimensionData( - UNKNOWN_DIMENSION_ID, null, isNatural, ambientLight, isShrunk, - isUltrawarm, hasCeiling, hasSkylight, isPiglinSafe, doBedsWork, doRespawnAnchorsWork, - hasRaids, logicalHeight, burningBehaviourIdentifier, fixedTime, hasEnderdragonFight, - coordinateScale, effects, minY, height, monsterSpawnBlockLightLimit, - monsterSpawnLightLevel); - } - - /** - * Parses a given CompoundTag to a DimensionData instance. Assumes the data is part of a dimension - * registry. - * - * @param dimTag the compound from the registry to read - * @param version the protocol version - * @return game dimension data - */ - public static DimensionData decodeRegistryEntry(CompoundBinaryTag dimTag, - ProtocolVersion version) { - String registryIdentifier = dimTag.getString("name"); - CompoundBinaryTag details; - Integer dimensionId = null; - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { - dimensionId = dimTag.getInt("id"); - details = dimTag.getCompound("element"); - } else { - details = dimTag; - } - - DimensionData deserializedDetails = decodeBaseCompoundTag(details, version); - return deserializedDetails.annotateWith(registryIdentifier, dimensionId); - } - - /** - * Encodes the Dimension data as CompoundTag. - * - * @param version the version to serialize as - * @return compound containing the dimension data - */ - public CompoundBinaryTag encodeAsCompoundTag(ProtocolVersion version) { - CompoundBinaryTag details = serializeDimensionDetails(); - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { - if (dimensionId == null) { - throw new IllegalStateException("Tried to serialize a 1.16.2+ dimension registry entry " - + "without an ID"); - } - - return CompoundBinaryTag.builder() - .putString("name", registryIdentifier) - .putInt("id", dimensionId) - .put("element", details) - .build(); - } else { - return details.putString("name", registryIdentifier); - } - } - - /** - * Serializes details of this dimension. - * - * @return serialized details of this dimension - */ - public CompoundBinaryTag serializeDimensionDetails() { - CompoundBinaryTag.Builder ret = CompoundBinaryTag.builder(); - ret.putBoolean("natural", isNatural); - ret.putFloat("ambient_light", ambientLight); - ret.putBoolean("shrunk", isShrunk); - ret.putBoolean("ultrawarm", isUltrawarm); - ret.putBoolean("has_ceiling", hasCeiling); - ret.putBoolean("has_skylight", hasSkylight); - ret.putBoolean("piglin_safe", isPiglinSafe); - ret.putBoolean("bed_works", doBedsWork); - ret.putBoolean("respawn_anchor_works", doRespawnAnchorsWork); - ret.putBoolean("has_raids", hasRaids); - ret.putInt("logical_height", logicalHeight); - ret.putString("infiniburn", burningBehaviourIdentifier); - if (fixedTime != null) { - ret.putLong("fixed_time", fixedTime); - } - if (createDragonFight != null) { - ret.putBoolean("has_enderdragon_fight", createDragonFight); - } - if (coordinateScale != null) { - ret.putDouble("coordinate_scale", coordinateScale); - } - if (effects != null) { - ret.putString("effects", effects); - } - if (minY != null) { - ret.putInt("min_y", minY); - } - if (height != null) { - ret.putInt("height", height); - } - if (monsterSpawnBlockLightLimit != null) { - ret.putInt("monster_spawn_block_light_limit", monsterSpawnBlockLightLimit); - } - if (monsterSpawnLightLevel != null) { - ret.putInt("monster_spawn_light_level", monsterSpawnLightLevel); - } - return ret.build(); - } -} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionRegistry.java b/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionRegistry.java deleted file mode 100644 index 29a6b8f97..000000000 --- a/proxy/src/main/java/com/velocitypowered/proxy/connection/registry/DimensionRegistry.java +++ /dev/null @@ -1,128 +0,0 @@ -/* - * Copyright (C) 2020-2023 Velocity Contributors - * - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation, either version 3 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program. If not, see . - */ - -package com.velocitypowered.proxy.connection.registry; - -import com.google.common.base.Preconditions; -import com.google.common.collect.ImmutableSet; -import com.google.common.collect.Maps; -import com.velocitypowered.api.network.ProtocolVersion; -import java.util.Map; -import java.util.Set; -import net.kyori.adventure.nbt.BinaryTag; -import net.kyori.adventure.nbt.BinaryTagTypes; -import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.kyori.adventure.nbt.ListBinaryTag; -import org.checkerframework.checker.nullness.qual.Nullable; - -/** - * Represents a registry of dimensions sent to the client by the server. - */ -public final class DimensionRegistry { - - private final Map registeredDimensions; - private final ImmutableSet levelNames; - - /** - * Initializes a new {@link DimensionRegistry} instance. This registry is required for 1.16+ - * clients/servers to communicate, it constrains the dimension types and names the client can be - * sent in a Respawn action (dimension change). This WILL raise an IllegalArgumentException if the - * following is not met: - At least one valid DimensionData instance is provided - At least one - * valid world name is provided - * - * @param registeredDimensions a populated {@link ImmutableSet} containing dimension data types - * @param levelNames a populated {@link ImmutableSet} of the level (world) names the - * server offers - */ - public DimensionRegistry(ImmutableSet registeredDimensions, - ImmutableSet levelNames) { - Preconditions.checkNotNull(registeredDimensions, - "registeredDimensions cannot be null"); - Preconditions.checkNotNull(levelNames, - "levelNames cannot be null"); - Preconditions.checkArgument(registeredDimensions.size() > 0, - "registeredDimensions needs to be populated"); - Preconditions.checkArgument(levelNames.size() > 0, - "levelNames needs to populated"); - this.registeredDimensions = Maps.uniqueIndex( - registeredDimensions, DimensionData::getRegistryIdentifier); - this.levelNames = levelNames; - } - - public Map getRegisteredDimensions() { - return registeredDimensions; - } - - public Set getLevelNames() { - return levelNames; - } - - /** - * Returns the internal dimension data type as used by the game. - * - * @param dimensionIdentifier how the dimension is identified by the connection - * @return game dimension data or null if not registered - */ - public @Nullable DimensionData getDimensionData(String dimensionIdentifier) { - return registeredDimensions.get(dimensionIdentifier); - } - - /** - * Checks a {@link DimensionInfo} against this registry. - * - * @param toValidate the {@link DimensionInfo} to validate - * @return true: the dimension information is valid for this registry - */ - public boolean isValidFor(DimensionInfo toValidate) { - if (toValidate == null) { - return false; - } - return registeredDimensions.containsKey(toValidate.getRegistryIdentifier()) - && levelNames.contains(toValidate.getLevelName()); - } - - /** - * Encodes the stored Dimension registry as CompoundTag. - * - * @return the CompoundTag containing identifier:type mappings - */ - public ListBinaryTag encodeRegistry(ProtocolVersion version) { - ListBinaryTag.Builder listBuilder = ListBinaryTag - .builder(BinaryTagTypes.COMPOUND); - for (DimensionData iter : registeredDimensions.values()) { - listBuilder.add(iter.encodeAsCompoundTag(version)); - } - return listBuilder.build(); - } - - /** - * Decodes a CompoundTag storing a dimension registry. - * - * @param toParse CompoundTag containing a dimension registry - */ - public static ImmutableSet fromGameData(ListBinaryTag toParse, - ProtocolVersion version) { - Preconditions.checkNotNull(toParse, "ListTag cannot be null"); - ImmutableSet.Builder mappings = ImmutableSet.builder(); - for (BinaryTag iter : toParse) { - if (iter instanceof CompoundBinaryTag) { - mappings.add(DimensionData.decodeRegistryEntry((CompoundBinaryTag) iter, version)); - } - } - return mappings.build(); - } -} diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java index 85a61ef4f..90320f948 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/JoinGame.java @@ -20,16 +20,12 @@ package com.velocitypowered.proxy.protocol.packet; import com.google.common.collect.ImmutableSet; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import com.velocitypowered.proxy.connection.registry.DimensionData; import com.velocitypowered.proxy.connection.registry.DimensionInfo; -import com.velocitypowered.proxy.connection.registry.DimensionRegistry; import com.velocitypowered.proxy.protocol.*; import io.netty.buffer.ByteBuf; import it.unimi.dsi.fastutil.Pair; import net.kyori.adventure.nbt.BinaryTagIO; -import net.kyori.adventure.nbt.BinaryTagTypes; import net.kyori.adventure.nbt.CompoundBinaryTag; -import net.kyori.adventure.nbt.ListBinaryTag; import org.checkerframework.checker.nullness.qual.Nullable; public class JoinGame implements MinecraftPacket { @@ -46,15 +42,13 @@ public class JoinGame implements MinecraftPacket { private int viewDistance; // 1.14+ private boolean reducedDebugInfo; private boolean showRespawnScreen; - private DimensionRegistry dimensionRegistry; // 1.16+ + private ImmutableSet levelNames; // 1.16+ + private CompoundBinaryTag registry; // 1.16+ private DimensionInfo dimensionInfo; // 1.16+ - private DimensionData currentDimensionData; // 1.16.2+ + private CompoundBinaryTag currentDimensionData; // 1.16.2+ private short previousGamemode; // 1.16+ - private CompoundBinaryTag biomeRegistry; // 1.16.2+ private int simulationDistance; // 1.18+ - private @Nullable Pair lastDeathPosition; - private CompoundBinaryTag chatTypeRegistry; // placeholder, 1.19+ - private @Nullable CompoundBinaryTag originalRegistryContainerTag; + private @Nullable Pair lastDeathPosition; // 1.19+ public int getEntityId() { return entityId; @@ -132,14 +126,6 @@ public class JoinGame implements MinecraftPacket { this.dimensionInfo = dimensionInfo; } - public DimensionRegistry getDimensionRegistry() { - return dimensionRegistry; - } - - public void setDimensionRegistry(DimensionRegistry dimensionRegistry) { - this.dimensionRegistry = dimensionRegistry; - } - public short getPreviousGamemode() { return previousGamemode; } @@ -156,15 +142,7 @@ public class JoinGame implements MinecraftPacket { this.isHardcore = isHardcore; } - public CompoundBinaryTag getBiomeRegistry() { - return biomeRegistry; - } - - public void setBiomeRegistry(CompoundBinaryTag biomeRegistry) { - this.biomeRegistry = biomeRegistry; - } - - public DimensionData getCurrentDimensionData() { + public CompoundBinaryTag getCurrentDimensionData() { return currentDimensionData; } @@ -184,12 +162,8 @@ public class JoinGame implements MinecraftPacket { this.lastDeathPosition = lastDeathPosition; } - public CompoundBinaryTag getChatTypeRegistry() { - return chatTypeRegistry; - } - - public void setChatTypeRegistry(CompoundBinaryTag chatTypeRegistry) { - this.chatTypeRegistry = chatTypeRegistry; + public CompoundBinaryTag getRegistry() { + return registry; } @Override @@ -200,12 +174,16 @@ public class JoinGame implements MinecraftPacket { + ", dimension=" + dimension + ", partialHashedSeed=" + partialHashedSeed + ", difficulty=" + difficulty + + ", isHardcore=" + isHardcore + ", maxPlayers=" + maxPlayers + ", levelType='" + levelType + '\'' + ", viewDistance=" + viewDistance + ", reducedDebugInfo=" + reducedDebugInfo - + ", dimensionRegistry='" + dimensionRegistry + '\'' + + ", showRespawnScreen=" + showRespawnScreen + + ", levelNames=" + levelNames + + ", registry='" + registry + '\'' + ", dimensionInfo='" + dimensionInfo + '\'' + + ", currentDimensionData='" + currentDimensionData + '\'' + ", previousGamemode=" + previousGamemode + ", simulationDistance=" + simulationDistance + ", lastDeathPosition='" + lastDeathPosition + '\'' @@ -263,39 +241,16 @@ public class JoinGame implements MinecraftPacket { this.isHardcore = (this.gamemode & 0x08) != 0; this.gamemode &= ~0x08; } - this.previousGamemode = buf.readByte(); - ImmutableSet levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf)); - - CompoundBinaryTag registryContainer = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER); - ListBinaryTag dimensionRegistryContainer; - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { - dimensionRegistryContainer = registryContainer.getCompound("minecraft:dimension_type") - .getList("value", BinaryTagTypes.COMPOUND); - this.biomeRegistry = registryContainer.getCompound("minecraft:worldgen/biome"); - if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) { - this.chatTypeRegistry = registryContainer.getCompound("minecraft:chat_type"); - } else { - this.chatTypeRegistry = CompoundBinaryTag.empty(); - } - } else { - dimensionRegistryContainer = registryContainer.getList("dimension", - BinaryTagTypes.COMPOUND); - } - ImmutableSet readData = - DimensionRegistry.fromGameData(dimensionRegistryContainer, version); - this.dimensionRegistry = new DimensionRegistry(readData, levelNames); - this.originalRegistryContainerTag = registryContainer; - + this.levelNames = ImmutableSet.copyOf(ProtocolUtils.readStringArray(buf)); + this.registry = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER); String dimensionIdentifier; String levelName = null; if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0 && version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) { - CompoundBinaryTag currentDimDataTag = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER); + this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, JOINGAME_READER); dimensionIdentifier = ProtocolUtils.readString(buf); - this.currentDimensionData = DimensionData.decodeBaseCompoundTag(currentDimDataTag, version) - .annotateWith(dimensionIdentifier, null); } else { dimensionIdentifier = ProtocolUtils.readString(buf); levelName = ProtocolUtils.readString(buf); @@ -315,9 +270,11 @@ public class JoinGame implements MinecraftPacket { this.reducedDebugInfo = buf.readBoolean(); this.showRespawnScreen = buf.readBoolean(); + boolean isDebug = buf.readBoolean(); boolean isFlat = buf.readBoolean(); this.dimensionInfo = new DimensionInfo(dimensionIdentifier, levelName, isFlat, isDebug); + // optional death location if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0 && buf.readBoolean()) { this.lastDeathPosition = Pair.of(ProtocolUtils.readString(buf), buf.readLong()); @@ -379,40 +336,25 @@ public class JoinGame implements MinecraftPacket { buf.writeByte(isHardcore ? gamemode | 0x8 : gamemode); } buf.writeByte(previousGamemode); - ProtocolUtils.writeStringArray(buf, dimensionRegistry.getLevelNames().toArray(new String[0])); - if (this.originalRegistryContainerTag != null) { - ProtocolUtils.writeCompoundTag(buf, this.originalRegistryContainerTag); - } else { - CompoundBinaryTag.Builder registryContainer = CompoundBinaryTag.builder(); - ListBinaryTag encodedDimensionRegistry = dimensionRegistry.encodeRegistry(version); - if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { - CompoundBinaryTag.Builder dimensionRegistryEntry = CompoundBinaryTag.builder(); - dimensionRegistryEntry.putString("type", "minecraft:dimension_type"); - dimensionRegistryEntry.put("value", encodedDimensionRegistry); - registryContainer.put("minecraft:dimension_type", dimensionRegistryEntry.build()); - registryContainer.put("minecraft:worldgen/biome", biomeRegistry); - if (version.compareTo(ProtocolVersion.MINECRAFT_1_19) >= 0) { - registryContainer.put("minecraft:chat_type", chatTypeRegistry); - } - } else { - registryContainer.put("dimension", encodedDimensionRegistry); - } - ProtocolUtils.writeCompoundTag(buf, registryContainer.build()); - } + + ProtocolUtils.writeStringArray(buf, levelNames.toArray(String[]::new)); + ProtocolUtils.writeCompoundTag(buf, this.registry); if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0 && version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) { - ProtocolUtils.writeCompoundTag(buf, currentDimensionData.serializeDimensionDetails()); + ProtocolUtils.writeCompoundTag(buf, currentDimensionData); ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier()); } else { ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier()); ProtocolUtils.writeString(buf, dimensionInfo.getLevelName()); } + buf.writeLong(partialHashedSeed); if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0) { ProtocolUtils.writeVarInt(buf, maxPlayers); } else { buf.writeByte(maxPlayers); } + ProtocolUtils.writeVarInt(buf, viewDistance); if (version.compareTo(ProtocolVersion.MINECRAFT_1_18) >= 0) { ProtocolUtils.writeVarInt(buf, simulationDistance); @@ -420,6 +362,7 @@ public class JoinGame implements MinecraftPacket { buf.writeBoolean(reducedDebugInfo); buf.writeBoolean(showRespawnScreen); + buf.writeBoolean(dimensionInfo.isDebugType()); buf.writeBoolean(dimensionInfo.isFlat()); diff --git a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Respawn.java b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Respawn.java index d75de12b2..11d543c89 100644 --- a/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Respawn.java +++ b/proxy/src/main/java/com/velocitypowered/proxy/protocol/packet/Respawn.java @@ -19,7 +19,6 @@ package com.velocitypowered.proxy.protocol.packet; import com.velocitypowered.api.network.ProtocolVersion; import com.velocitypowered.proxy.connection.MinecraftSessionHandler; -import com.velocitypowered.proxy.connection.registry.DimensionData; import com.velocitypowered.proxy.connection.registry.DimensionInfo; import com.velocitypowered.proxy.protocol.MinecraftPacket; import com.velocitypowered.proxy.protocol.ProtocolUtils; @@ -39,7 +38,7 @@ public class Respawn implements MinecraftPacket { private byte dataToKeep; // 1.16+ private DimensionInfo dimensionInfo; // 1.16-1.16.1 private short previousGamemode; // 1.16+ - private DimensionData currentDimensionData; // 1.16.2+ + private CompoundBinaryTag currentDimensionData; // 1.16.2+ private @Nullable Pair lastDeathPosition; // 1.19+ public Respawn() { @@ -47,7 +46,7 @@ public class Respawn implements MinecraftPacket { public Respawn(int dimension, long partialHashedSeed, short difficulty, short gamemode, String levelType, byte dataToKeep, DimensionInfo dimensionInfo, - short previousGamemode, DimensionData currentDimensionData, + short previousGamemode, CompoundBinaryTag currentDimensionData, @Nullable Pair lastDeathPosition) { this.dimension = dimension; this.partialHashedSeed = partialHashedSeed; @@ -155,10 +154,8 @@ public class Respawn implements MinecraftPacket { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0 && version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) { - CompoundBinaryTag dimDataTag = ProtocolUtils.readCompoundTag(buf, BinaryTagIO.reader()); + this.currentDimensionData = ProtocolUtils.readCompoundTag(buf, BinaryTagIO.reader()); dimensionIdentifier = ProtocolUtils.readString(buf); - this.currentDimensionData = DimensionData.decodeBaseCompoundTag(dimDataTag, version) - .annotateWith(dimensionIdentifier, null); } else { dimensionIdentifier = ProtocolUtils.readString(buf); levelName = ProtocolUtils.readString(buf); @@ -198,7 +195,7 @@ public class Respawn implements MinecraftPacket { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16) >= 0) { if (version.compareTo(ProtocolVersion.MINECRAFT_1_16_2) >= 0 && version.compareTo(ProtocolVersion.MINECRAFT_1_19) < 0) { - ProtocolUtils.writeCompoundTag(buf, currentDimensionData.serializeDimensionDetails()); + ProtocolUtils.writeCompoundTag(buf, currentDimensionData); ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier()); } else { ProtocolUtils.writeString(buf, dimensionInfo.getRegistryIdentifier());