diff --git a/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java b/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java index 8ed4c9171..cc4329c3b 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java +++ b/src/main/java/com/comphenix/protocol/wrappers/EnumWrappers.java @@ -708,6 +708,15 @@ public String toString() { } } + public enum HeightmapType { + WORLD_SURFACE_WG, + WORLD_SURFACE, + OCEAN_FLOOR_WG, + OCEAN_FLOOR, + MOTION_BLOCKING, + MOTION_BLOCKING_NO_LEAVES, + } + private static Class PROTOCOL_CLASS = null; private static Class CLIENT_COMMAND_CLASS = null; private static Class CHAT_VISIBILITY_CLASS = null; @@ -735,6 +744,7 @@ public String toString() { private static Class CLIENT_INTENT_CLASS = null; private static Class TEAM_COLLISION_RULE_CLASS = null; private static Class TEAM_VISIBILITY_CLASS = null; + private static Class HEIGHTMAP_TYPE_CLASS = null; private static boolean INITIALIZING = false; private static boolean INITIALIZED = false; @@ -849,6 +859,10 @@ private static void initialize() { "world.scores.ScoreboardTeamBase$EnumNameTagVisibility" /* Spigot Mapping */, "world.scores.Team$Visibility" /* Mojang Mapping */); + HEIGHTMAP_TYPE_CLASS = MinecraftReflection.getNullableNMS( + "world.level.levelgen.HeightMap$Type" /* Spigot Mapping */, + "world.level.levelgen.Heightmap$Types" /* Mojang Mapping */); + associate(PROTOCOL_CLASS, Protocol.class, getProtocolConverter()); associate(CLIENT_COMMAND_CLASS, ClientCommand.class, getClientCommandConverter()); associate(CHAT_VISIBILITY_CLASS, ChatVisibility.class, getChatVisibilityConverter()); @@ -875,6 +889,7 @@ private static void initialize() { associate(CLIENT_INTENT_CLASS, ClientIntent.class, getClientIntentConverter()); associate(TEAM_COLLISION_RULE_CLASS, TeamCollisionRule.class, getTeamCollisionRuleConverter()); associate(TEAM_VISIBILITY_CLASS, TeamVisibility.class, getTeamVisibilityConverter()); + associate(HEIGHTMAP_TYPE_CLASS, HeightmapType.class, getHeightmapTypeConverter()); if (ENTITY_POSE_CLASS != null) { associate(ENTITY_POSE_CLASS, EntityPose.class, getEntityPoseConverter()); @@ -1059,6 +1074,11 @@ public static Class getTeamVisibilityClass() { return TEAM_VISIBILITY_CLASS; } + public static Class getHeightmapTypeClass() { + initialize(); + return HEIGHTMAP_TYPE_CLASS; + } + // Get the converters public static EquivalentConverter getProtocolConverter() { return new EnumConverter<>(getProtocolClass(), Protocol.class); @@ -1164,6 +1184,10 @@ public static EquivalentConverter getTeamVisibilityConverter() { return new EnumConverter<>(getTeamVisibilityClass(), TeamVisibility.class); } + public static EquivalentConverter getHeightmapTypeConverter() { + return new EnumConverter<>(getHeightmapTypeClass(), HeightmapType.class); + } + /** * @since 1.13+ * @return {@link EnumConverter} or null (if bellow 1.13 / nms EnumPose class cannot be found) diff --git a/src/main/java/com/comphenix/protocol/wrappers/WrappedLevelChunkData.java b/src/main/java/com/comphenix/protocol/wrappers/WrappedLevelChunkData.java index bf81039c6..1daab83b0 100644 --- a/src/main/java/com/comphenix/protocol/wrappers/WrappedLevelChunkData.java +++ b/src/main/java/com/comphenix/protocol/wrappers/WrappedLevelChunkData.java @@ -4,7 +4,9 @@ import java.util.ArrayList; import java.util.BitSet; import java.util.List; +import java.util.Map; +import com.comphenix.protocol.reflect.EquivalentConverter; import org.jetbrains.annotations.Nullable; import com.comphenix.protocol.injector.StructureCache; @@ -41,6 +43,7 @@ public static final class ChunkData extends AbstractWrapper { private static final FieldAccessor BLOCK_ENTITIES_DATA_ACCESSOR; private static final FieldAccessor HEIGHTMAPS_ACCESSOR; + private static final EquivalentConverter> HEIGHTMAPS_CONVERTER; private static final FieldAccessor BUFFER_ACCESSOR; static { @@ -54,9 +57,17 @@ public static final class ChunkData extends AbstractWrapper { BLOCK_ENTITIES_DATA_ACCESSOR = Accessors.getFieldAccessor(reflection.getField(FuzzyFieldContract.newBuilder() .typeExact(List.class) .build())); - HEIGHTMAPS_ACCESSOR = Accessors.getFieldAccessor(reflection.getField(FuzzyFieldContract.newBuilder() - .typeExact(MinecraftReflection.getNBTCompoundClass()) - .build())); + if (MinecraftVersion.v1_21_5.atOrAbove()) { + HEIGHTMAPS_ACCESSOR = Accessors.getFieldAccessor(reflection.getField(FuzzyFieldContract.newBuilder() + .typeExact(Map.class) + .build())); + HEIGHTMAPS_CONVERTER = BukkitConverters.getMapConverter(EnumWrappers.getHeightmapTypeConverter(), Converters.passthrough(long[].class)); + } else { + HEIGHTMAPS_ACCESSOR = Accessors.getFieldAccessor(reflection.getField(FuzzyFieldContract.newBuilder() + .typeExact(MinecraftReflection.getNBTCompoundClass()) + .build())); + HEIGHTMAPS_CONVERTER = null; + } BUFFER_ACCESSOR = Accessors.getFieldAccessor(reflection.getField(FuzzyFieldContract.newBuilder().typeExact(byte[].class).build())); } @@ -68,22 +79,50 @@ public ChunkData(Object handle) { /** * The heightmap of this chunk. + *

+ * Removed in Minecraft 1.21.5. * * @return an NBT-Tag + * @deprecated Use {@link ChunkData#getHeightmaps()} instead. */ + @Deprecated public NbtCompound getHeightmapsTag() { return NbtFactory.fromNMSCompound(HEIGHTMAPS_ACCESSOR.get(handle)); } /** * Sets the heightmap tag of this chunk. + *

+ * Removed in Minecraft 1.21.5. * * @param heightmapsTag the new heightmaps tag. + * @deprecated Use {@link ChunkData#setHeightmaps(Map)} instead. */ + @Deprecated public void setHeightmapsTag(NbtCompound heightmapsTag) { HEIGHTMAPS_ACCESSOR.set(handle, NbtFactory.fromBase(heightmapsTag).getHandle()); } + /** + * The heightmap of this chunk. + * + * @return a map containing the heightmaps + */ + public Map getHeightmaps() { + return HEIGHTMAPS_CONVERTER.getSpecific(HEIGHTMAPS_ACCESSOR.get(handle)); + } + + /** + * Sets the heightmap tag of this chunk. + *

+ * Removed in Minecraft 1.21.5. + * + * @param heightmaps the new heightmaps. + */ + public void setHeightmaps(Map heightmaps) { + HEIGHTMAPS_ACCESSOR.set(handle, HEIGHTMAPS_CONVERTER.getGeneric(heightmaps)); + } + /** * The actual structural data of this chunk as bytes. * @@ -130,12 +169,16 @@ public void setBlockEntityInfo(List blockEntityInfo) { /** * Creates a new wrapper using predefined values. + *

+ * Removed in Minecraft 1.21.5. * * @param heightmapsTag the heightmaps tag * @param buffer the buffer * @param blockEntityInfo a list of wrapped block entities * @return a newly created wrapper + * @deprecated Use {@link ChunkData#fromValues(Map, byte[], List)} instead. */ + @Deprecated public static ChunkData fromValues(NbtCompound heightmapsTag, byte[] buffer, List blockEntityInfo) { ChunkData data = new ChunkData(LEVEL_CHUNK_PACKET_DATA_CONSTRUCTOR.invoke(StructureCache.newNullDataSerializer(), 0, 0)); @@ -145,6 +188,24 @@ public static ChunkData fromValues(NbtCompound heightmapsTag, byte[] buffer, Lis return new ChunkData(data); } + + /** + * Creates a new wrapper using predefined values. + * + * @param heightmaps the heightmaps + * @param buffer the buffer + * @param blockEntityInfo a list of wrapped block entities + * @return a newly created wrapper + */ + public static ChunkData fromValues(Map heightmaps, byte[] buffer, List blockEntityInfo) { + ChunkData data = new ChunkData(LEVEL_CHUNK_PACKET_DATA_CONSTRUCTOR.invoke(StructureCache.newNullDataSerializer(), 0, 0)); + + data.setHeightmaps(heightmaps); + data.setBuffer(buffer); + data.setBlockEntityInfo(blockEntityInfo); + + return new ChunkData(data); + } } /**