diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java index 55b004376..46e982f15 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/BatchGenerationEnvironment.java @@ -113,7 +113,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv new ConfigBasedLogger(LogManager.getLogger("LodWorldGen"), () -> Config.Common.Logging.logWorldGenLoadEvent.get()); + #if MC_VER < MC_1_21_5 private static final TicketType DH_SERVER_GEN_TICKET = TicketType.create("dh_server_gen_ticket", Comparator.comparingLong(ChunkPos::toLong)); + #else + private static final TicketType DH_SERVER_GEN_TICKET = new TicketType(/* timeout, 0 = disabled*/0L, /* persist */ false, TicketType.TicketUse.LOADING); + #endif private static final IModChecker MOD_CHECKER = SingletonInjector.INSTANCE.get(IModChecker.class); @@ -878,7 +882,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv chunkLevel = generateUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; #endif + #if MC_VER < MC_1_21_5 level.getChunkSource().distanceManager.addTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); + #else + level.getChunkSource().addTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); + #endif level.getChunkSource().distanceManager.runAllUpdates(level.getChunkSource().chunkMap); // probably not the most optimal to run updates here, but fast enough ChunkHolder holder = level.getChunkSource().chunkMap.getUpdatingChunkIfPresent(pos.toLong()); if (holder == null) @@ -915,7 +923,11 @@ public final class BatchGenerationEnvironment extends AbstractBatchGenerationEnv chunkLevel = chunkWasGeneratedUpToFeatures ? ChunkLevel.byStatus(ChunkStatus.FEATURES) : 33; #endif + #if MC_VER < MC_1_21_5 level.getChunkSource().distanceManager.removeTicket(DH_SERVER_GEN_TICKET, pos, chunkLevel, pos); + #else + level.getChunkSource().removeTicketWithRadius(DH_SERVER_GEN_TICKET, pos, 0); + #endif // mitigate OOM issues in vanilla chunk system: see https://github.com/pop4959/Chunky/pull/383 level.getChunkSource().chunkMap.tick(() -> false); diff --git a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java index 4c8e8fb15..b4d68567b 100644 --- a/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java +++ b/common/src/main/java/com/seibel/distanthorizons/common/wrappers/worldGeneration/mimicObject/ChunkLoader.java @@ -29,6 +29,7 @@ import com.seibel.distanthorizons.core.util.LodUtil; import com.seibel.distanthorizons.core.wrapperInterfaces.chunk.ChunkLightStorage; import java.util.Objects; +import java.util.Optional; import java.util.concurrent.ConcurrentHashMap; @@ -84,6 +85,7 @@ import net.minecraft.world.level.chunk.status.ChunkType; #endif import net.minecraft.world.level.material.Fluid; +import org.jetbrains.annotations.Nullable; public class ChunkLoader @@ -120,7 +122,7 @@ public class ChunkLoader CompoundTag tagLevel = chunkData; #endif - ChunkPos actualPos = new ChunkPos(tagLevel.getInt("xPos"), tagLevel.getInt("zPos")); + ChunkPos actualPos = new ChunkPos(tagGetInt(tagLevel,"xPos"), tagGetInt(tagLevel, "zPos")); if (!Objects.equals(chunkPos, actualPos)) { #if MC_VER >= MC_1_18_2 @@ -174,14 +176,27 @@ public class ChunkLoader #endif - long inhabitedTime = tagLevel.getLong("InhabitedTime"); + long inhabitedTime = tagGetLong(tagLevel, "InhabitedTime"); //================== Read params for making the LevelChunk ================== - UpgradeData upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) - ? new UpgradeData(tagLevel.getCompound(TAG_UPGRADE_DATA)#if MC_VER >= MC_1_17_1 , level #endif ) - : UpgradeData.EMPTY; - boolean isLightOn = tagLevel.getBoolean("isLightOn"); + UpgradeData upgradeData; + #if MC_VER < MC_1_17_1 + upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) + ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA)) + : UpgradeData.EMPTY; + #elif MC_VER < MC_1_21_5 + upgradeData = tagLevel.contains(TAG_UPGRADE_DATA, 10) + ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) + : UpgradeData.EMPTY; + #else + upgradeData = tagLevel.contains(TAG_UPGRADE_DATA) + ? new UpgradeData(tagGetCompoundTag(tagLevel, TAG_UPGRADE_DATA), level) + : UpgradeData.EMPTY; + #endif + + + boolean isLightOn = tagGetBoolean(tagLevel, "isLightOn"); #if MC_VER < MC_1_18_2 ChunkBiomeContainer chunkBiomeContainer = new ChunkBiomeContainer( level.getLevel().registryAccess().registryOrThrow(Registry.BIOME_REGISTRY)#if MC_VER >= MC_1_17_1 , level #endif , @@ -198,17 +213,21 @@ public class ChunkLoader : new ProtoTickList(fluid -> (fluid == null || fluid == Fluids.EMPTY), chunkPos, tagLevel.getList("LiquidsToBeTicked", 9)#if MC_VER >= MC_1_17_1 , level #endif ); #else - #if MC_VER < MC_1_19_4 - LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), - string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos); - LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), - string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); - #else - LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), - (string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos); - LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), - string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); - #endif + #if MC_VER < MC_1_19_4 + LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), + string -> Registry.BLOCK.getOptional(ResourceLocation.tryParse(string)), chunkPos); + LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), + string -> Registry.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); + #elif MC_VER < MC_1_21_4 + LevelChunkTicks blockTicks = LevelChunkTicks.load(tagLevel.getList(BLOCK_TICKS_TAG_18, 10), + (string -> BuiltInRegistries.BLOCK.getOptional(ResourceLocation.tryParse(string))), chunkPos); + LevelChunkTicks fluidTicks = LevelChunkTicks.load(tagLevel.getList(FLUID_TICKS_TAG_18, 10), + string -> BuiltInRegistries.FLUID.getOptional(ResourceLocation.tryParse(string)), chunkPos); + #else + // do we need the ticks for what we're doing? + LevelChunkTicks blockTicks = new LevelChunkTicks<>(); + LevelChunkTicks fluidTicks = new LevelChunkTicks<>(); + #endif #endif LevelChunkSection[] levelChunkSections = readSections(level, chunkPos, tagLevel); @@ -218,7 +237,6 @@ public class ChunkLoader LevelChunk chunk = new LevelChunk((Level) level.getLevel(), chunkPos, chunkBiomeContainer, upgradeData, blockTicks, fluidTicks, inhabitedTime, levelChunkSections, null); #else - LevelChunk chunk = new LevelChunk((Level) level, chunkPos, upgradeData, blockTicks, fluidTicks, inhabitedTime, levelChunkSections, null, blendingData); #endif @@ -252,18 +270,23 @@ public class ChunkLoader biomes.asHolderIdMap(), biomes.holderByNameCodec(), PalettedContainer.Strategy.SECTION_BIOMES, biomes.getOrThrow(Biomes.PLAINS)); #endif #endif + int sectionYIndex = #if MC_VER < MC_1_17_1 16; #else level.getSectionsCount(); #endif LevelChunkSection[] chunkSections = new LevelChunkSection[sectionYIndex]; - boolean isLightOn = chunkData.getBoolean("isLightOn"); - boolean hasSkyLight = level.dimensionType().hasSkyLight(); - ListTag tagSections = chunkData.getList("Sections", 10); - if (tagSections.isEmpty()) tagSections = chunkData.getList("sections", 10); - - for (int j = 0; j < tagSections.size(); ++j) + ListTag tagSections = tagGetListTag(chunkData, "Sections", 10); + if (tagSections == null || tagSections.isEmpty()) { - CompoundTag tagSection = tagSections.getCompound(j); - int sectionYPos = tagSection.getByte("Y"); + tagSections = tagGetListTag(chunkData, "sections", 10); + } + + + if (tagSections != null) + { + for (int j = 0; j < tagSections.size(); ++j) + { + CompoundTag tagSection = tagGetCompoundTag(tagSections, j); + int sectionYPos = tagGetByte(tagSection, "Y"); #if MC_VER < MC_1_18_2 if (tagSection.contains("Palette", 9) && tagSection.contains("BlockStates", 12)) @@ -277,65 +300,89 @@ public class ChunkLoader = levelChunkSection; } #else - int sectionId = level.getSectionIndexFromSectionY(sectionYPos); - if (sectionId >= 0 && sectionId < chunkSections.length) - { - PalettedContainer blockStateContainer; + int sectionId = level.getSectionIndexFromSectionY(sectionYPos); + if (sectionId >= 0 && sectionId < chunkSections.length) + { + PalettedContainer blockStateContainer; #if MC_VER < MC_1_18_2 PalettedContainer biomeContainer; #else - PalettedContainer> biomeContainer; + PalettedContainer> biomeContainer; #endif + + boolean containsBlockStates; + #if MC_VER < MC_1_21_5 + containsBlockStates = tagSection.contains("block_states", 10); + #else + containsBlockStates = tagSection.contains("block_states"); + #endif + + if (containsBlockStates) + { + #if MC_VER < MC_1_20_6 + blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states")) + .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) + .getOrThrow(false, (message) -> logWarningOnce(message)); + #else + blockStateContainer = BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "block_states")) + .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) + .getOrThrow((message) -> logErrorAndReturnException(message)); + #endif + } + else + { + blockStateContainer = new PalettedContainer(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); + } + - blockStateContainer = tagSection.contains("block_states", 10) - ? BLOCK_STATE_CODEC.parse(NbtOps.INSTANCE, tagSection.getCompound("block_states")) - .promotePartial(string -> logBlockDeserializationWarning(chunkPos, sectionYPos, string)) - #if MC_VER < MC_1_20_6 - .getOrThrow(false, (message) -> logWarningOnce(message)) - #else - .getOrThrow((message) -> logErrorAndReturnException(message)) - #endif - : new PalettedContainer(Block.BLOCK_STATE_REGISTRY, Blocks.AIR.defaultBlockState(), PalettedContainer.Strategy.SECTION_STATES); - #if MC_VER < MC_1_18_2 biomeContainer = tagSection.contains("biomes", 10) ? biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")).promotePartial(string -> logErrors(chunkPos, sectionYPos, string)).getOrThrow(false, (message) -> logWarningOnce(message)) : new PalettedContainer(biomes, biomes.getOrThrow(Biomes.PLAINS), PalettedContainer.Strategy.SECTION_BIOMES); #else - - - if (tagSection.contains("biomes", 10)) - { - biomeContainer = - biomeCodec.parse(NbtOps.INSTANCE, tagSection.getCompound("biomes")) - .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) - #if MC_VER < MC_1_20_6 + + + boolean containsBiomes; + #if MC_VER < MC_1_21_5 + containsBiomes = tagSection.contains("biomes", 10); + #else + containsBiomes = tagSection.contains("biomes"); + #endif + + if (containsBiomes) + { + #if MC_VER < MC_1_20_6 + biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes")) + .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) .getOrThrow(false, (message) -> logWarningOnce(message)); - #else - .getOrThrow((message) -> logErrorAndReturnException(message)); - #endif - } - else - { - biomeContainer = new PalettedContainer>(biomes.asHolderIdMap(), + #else + biomeContainer = biomeCodec.parse(NbtOps.INSTANCE, tagGetCompoundTag(tagSection, "biomes")) + .promotePartial(string -> logBiomeDeserializationWarning(chunkPos, sectionYIndex, (String) string)) + .getOrThrow((message) -> logErrorAndReturnException(message)); + #endif + } + else + { + biomeContainer = new PalettedContainer>(biomes.asHolderIdMap(), #if MC_VER < MC_1_21_3 biomes.getHolderOrThrow(Biomes.PLAINS), #else - biomes.getOrThrow(Biomes.PLAINS), + biomes.getOrThrow(Biomes.PLAINS), #endif - PalettedContainer.Strategy.SECTION_BIOMES); - } + PalettedContainer.Strategy.SECTION_BIOMES); + } #endif #if MC_VER < MC_1_20_1 chunkSections[sectionId] = new LevelChunkSection(sectionYPos, blockStateContainer, biomeContainer); #else - chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer); + chunkSections[sectionId] = new LevelChunkSection(blockStateContainer, biomeContainer); #endif - } + } #endif - + + } } return chunkSections; } @@ -345,39 +392,54 @@ public class ChunkLoader #else ChunkType #endif readChunkType(CompoundTag tagLevel) { - ChunkStatus chunkStatus = ChunkStatus.byName(tagLevel.getString("Status")); + ChunkStatus chunkStatus = ChunkStatus.byName(tagGetString(tagLevel,"Status")); if (chunkStatus != null) { return chunkStatus.getChunkType(); } - return - #if MC_VER <= MC_1_20_4 ChunkStatus.ChunkType.PROTOCHUNK; - #else ChunkType.PROTOCHUNK; #endif + #if MC_VER <= MC_1_20_4 + return ChunkStatus.ChunkType.PROTOCHUNK; + #else + return ChunkType.PROTOCHUNK; + #endif } private static void readHeightmaps(LevelChunk chunk, CompoundTag chunkData) { - CompoundTag tagHeightmaps = chunkData.getCompound("Heightmaps"); + CompoundTag tagHeightmaps = tagGetCompoundTag(chunkData, "Heightmaps"); for (Heightmap.Types type : ChunkStatus.FULL.heightmapsAfter()) { String heightmap = type.getSerializationKey(); + #if MC_VER < MC_1_21_5 if (tagHeightmaps.contains(heightmap, 12)) + { chunk.setHeightmap(type, tagHeightmaps.getLongArray(heightmap)); + } + #else + if (tagHeightmaps.contains(heightmap)) + { + Optional optionalHeightmap = tagHeightmaps.getLongArray(heightmap); + if (optionalHeightmap.isPresent()) + { + chunk.setHeightmap(type, optionalHeightmap.get()); + } + } + #endif } Heightmap.primeHeightmaps(chunk, ChunkStatus.FULL.heightmapsAfter()); } private static void readPostPocessings(LevelChunk chunk, CompoundTag chunkData) { - ListTag tagPostProcessings = chunkData.getList("PostProcessing", 9); + ListTag tagPostProcessings = tagGetListTag(chunkData,"PostProcessing", 9); for (int i = 0; i < tagPostProcessings.size(); ++i) { - ListTag listTag3 = tagPostProcessings.getList(i); + ListTag listTag3 = tagGetListTag(tagPostProcessings, i); for (int j = 0; j < listTag3.size(); ++j) { #if MC_VER < MC_1_21_3 chunk.addPackedPostProcess(listTag3.getShort(j), i); #else - chunk.addPackedPostProcess(ShortList.of(listTag3.getShort(j)), i); + chunk.addPackedPostProcess(ShortList.of(tagGetShort(listTag3, j)), i); #endif } } @@ -386,16 +448,38 @@ public class ChunkLoader private static BlendingData readBlendingData(CompoundTag chunkData) { BlendingData blendingData = null; - if (chunkData.contains("blending_data", 10)) + + + boolean containsBlendingData; + #if MC_VER < MC_1_21_5 + containsBlendingData = chunkData.contains("blending_data", 10); + #else + containsBlendingData = chunkData.contains("blending_data"); + #endif + + if (containsBlendingData) { @SuppressWarnings({"unchecked", "rawtypes"}) Dynamic blendingDataTag = new Dynamic(NbtOps.INSTANCE, chunkData.getCompound("blending_data")); - #if MC_VER < MC_1_21_3 - blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logWarningOnce(message)).orElse(null); - #else - blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logWarningOnce(message)).orElse(null)); - #endif + try + { + #if MC_VER < MC_1_21_3 + blendingData = BlendingData.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logWarningOnce(message)).orElse(null); + #else + blendingData = BlendingData.unpack(BlendingData.Packed.CODEC.parse(blendingDataTag).resultOrPartial((message) -> logParsingWarningOnce(message)).orElse(null)); + #endif + } + catch (Exception e) + { + String message = e.getMessage(); + if (message == null || message.trim().isEmpty()) + { + message = "Failed to parse blending data"; + } + + logParsingWarningOnce(message, e); + } } return blendingData; } @@ -472,33 +556,37 @@ public class ChunkLoader // if null all lights = 0 - byte[] blockLightNibbleArray = chunkSectionCompoundTag.getByteArray("BlockLight"); - byte[] skyLightNibbleArray = chunkSectionCompoundTag.getByteArray("SkyLight"); + byte[] blockLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "BlockLight"); + byte[] skyLightNibbleArray = tagGetByteArray(chunkSectionCompoundTag, "SkyLight"); - // if any sky light was found then all lights above will be max brightness - if (skyLightNibbleArray.length != 0) + if (blockLightNibbleArray != null + && skyLightNibbleArray != null) { - foundSkyLight = true; - } - - for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) - { - for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++) + // if any sky light was found then all lights above will be max brightness + if (skyLightNibbleArray.length != 0) { - // chunk sections are also 16 blocks tall - for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++) + foundSkyLight = true; + } + + for (int relX = 0; relX < LodUtil.CHUNK_WIDTH; relX++) + { + for (int relZ = 0; relZ < LodUtil.CHUNK_WIDTH; relZ++) { - int blockPosIndex = relY*16*16 + relZ*16 + relX; - byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex); - byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex); - if (skyLightNibbleArray.length == 0 && foundSkyLight) + // chunk sections are also 16 blocks tall + for (int relY = 0; relY < LodUtil.CHUNK_WIDTH; relY++) { - skyLight = LodUtil.MAX_MC_LIGHT; + int blockPosIndex = relY*16*16 + relZ*16 + relX; + byte blockLight = (blockLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(blockLightNibbleArray, blockPosIndex); + byte skyLight = (skyLightNibbleArray.length == 0) ? 0 : getNibbleAtIndex(skyLightNibbleArray, blockPosIndex); + if (skyLightNibbleArray.length == 0 && foundSkyLight) + { + skyLight = LodUtil.MAX_MC_LIGHT; + } + + int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk); + blockLightStorage.set(relX, y, relZ, blockLight); + skyLightStorage.set(relX, y, relZ, skyLight); } - - int y = relY + (sectionIndex * LodUtil.CHUNK_WIDTH) + ChunkWrapper.getInclusiveMinBuildHeight(chunk); - blockLightStorage.set(relX, y, relZ, blockLight); - skyLightStorage.set(relX, y, relZ, skyLight); } } } @@ -547,9 +635,14 @@ public class ChunkLoader }); } - private static void logWarningOnce(String message) { logWarningOnce(message, null); } - private static void logWarningOnce(String message, Exception e) + private static void logParsingWarningOnce(String message) { logParsingWarningOnce(message, null); } + private static void logParsingWarningOnce(String message, Exception e) { + if (message == null) + { + return; + } + LOGGED_ERROR_MESSAGE_MAP.computeIfAbsent(message, (newMessage) -> { LOGGER.warn("Parsing error: ["+newMessage+"]. " + @@ -576,6 +669,134 @@ public class ChunkLoader + //====================// + // tag helper methods // + //====================// + + // TODO move into separate file (this file is getting long) + // these tag helpers are to simplify tag accessing between MC versions + + /** defaults to "false" if the tag isn't present */ + private static boolean tagGetBoolean(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getBoolean(key); + #else + return tag.getBoolean(key).orElse(false); + #endif + } + + /** defaults to "0" if the tag isn't present */ + private static byte tagGetByte(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getByte(key); + #else + return tag.getByte(key).orElse((byte)0); + #endif + } + + /** defaults to "0" if the tag isn't present */ + private static short tagGetShort(ListTag tag, int index) + { + #if MC_VER < MC_1_21_5 + return tag.getShort(index); + #else + return tag.getShort(index).orElse((short)0); + #endif + } + + /** defaults to "0" if the tag isn't present */ + private static int tagGetInt(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getInt(key); + #else + return tag.getInt(key).orElse(0); + #endif + } + + /** defaults to "0" if the tag isn't present */ + private static long tagGetLong(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getInt(key); + #else + return tag.getLong(key).orElse(0L); + #endif + } + + + + /** defaults to null if the tag isn't present */ + private static String tagGetString(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getString(key); + #else + return tag.getString(key).orElse(null); + #endif + } + + /** defaults to null if the tag isn't present */ + private static byte[] tagGetByteArray(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getByteArray(key); + #else + return tag.getByteArray(key).orElse(null); + #endif + } + + + + /** defaults to null if the tag isn't present */ + @Nullable + private static CompoundTag tagGetCompoundTag(CompoundTag tag, String key) + { + #if MC_VER < MC_1_21_5 + return tag.getCompound(key); + #else + return tag.getCompound(key).orElse(null); + #endif + } + /** defaults to null if the tag isn't present */ + @Nullable + private static CompoundTag tagGetCompoundTag(ListTag tag, int index) + { + #if MC_VER < MC_1_21_5 + return tag.getCompound(index); + #else + return tag.getCompound(index).orElse(null); + #endif + } + + /** + * defaults to null if the tag isn't present + * @param elementType unused after MC 1.21.5 + */ + @Nullable + private static ListTag tagGetListTag(CompoundTag tag, String key, int elementType) + { + #if MC_VER < MC_1_21_5 + return tag.getList(key, elementType); + #else + return tag.getList(key).orElse(null); + #endif + } + + /** defaults to null if the tag isn't present */ + @Nullable + private static ListTag tagGetListTag(ListTag tag, int index) + { + #if MC_VER < MC_1_21_5 + return tag.getList(index); + #else + return tag.getList(index).orElse(null); + #endif + } + + //================// // helper classes //