Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions src/main/java/net/querz/mcaselector/cli/ParamExecutor.java
Original file line number Diff line number Diff line change
Expand Up @@ -129,6 +129,10 @@ public final class ParamExecutor {
.desc("One or a range of section indices to import into the target world during chunk import")
.hasArg()
.get());
options.addOption(Option.builder()
.longOpt("biomes")
.desc("Import only biome data, not blocks or entities")
.get());
options.addOption(Option.builder()
.longOpt("render-height")
.desc("The highest Y level to render in image mode")
Expand Down Expand Up @@ -685,6 +689,11 @@ private void saveSelection(Selection selection, File output) throws RuntimeExcep
}

private List<Range> parseSections(boolean mandatory) throws ParseException {
// If --biomes is set, return empty list (special flag for biomes-only import)
if (line.hasOption("biomes")) {
return new ArrayList<>();
}

if (!line.hasOption("sections")) {
if (mandatory) {
throw new ParseException("missing mandatory sections parameter");
Expand Down
36 changes: 36 additions & 0 deletions src/main/java/net/querz/mcaselector/version/ChunkFilter.java
Original file line number Diff line number Diff line change
Expand Up @@ -106,6 +106,42 @@ interface Merge {

CompoundTag newEmptyChunk(Point2i absoluteLocation, int dataVersion);

// Biomes-only merge for modern Minecraft (1.18+)
default void mergeBiomesOnly(CompoundTag source, CompoundTag destination) {
// In Minecraft 1.18+, biomes are stored in sections
if (source.containsKey("sections") && destination.containsKey("sections")) {
ListTag sourceSections = source.getListTag("sections");
ListTag destSections = destination.getListTag("sections");

if (sourceSections != null && destSections != null) {
// Create map of Y -> Section for fast lookup
java.util.Map<Integer, CompoundTag> destSectionMap = new java.util.HashMap<>();
for (Tag tag : destSections) {
if (tag instanceof CompoundTag section) {
int y = section.getInt("Y");
destSectionMap.put(y, section);
}
}

// Copy biomes from source sections
for (Tag tag : sourceSections) {
if (tag instanceof CompoundTag sourceSection) {
int y = sourceSection.getInt("Y");
CompoundTag destSection = destSectionMap.get(y);

if (destSection != null && sourceSection.containsKey("biomes")) {
// Copy biome palette
Tag biomeData = sourceSection.get("biomes");
if (biomeData != null) {
destSection.put("biomes", biomeData.copy());
}
}
}
}
}
}
}

default ListTag mergeLists(ListTag source, ListTag destination, List<Range> ranges, Function<Tag, Integer> ySupplier, int yOffset) {
ListTag result = new ListTag();
for (Tag dest : destination) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -633,6 +633,12 @@ public static class Merge extends ChunkFilter_21w06a.Merge {

@Override
public void mergeChunks(CompoundTag source, CompoundTag destination, List<Range> ranges, int yOffset) {
// Empty ranges list = biomes-only mode
if (ranges != null && ranges.isEmpty()) {
mergeBiomesOnly(source, destination);
return;
}

mergeCompoundTagLists(source, destination, ranges, yOffset, "sections", c -> ((CompoundTag) c).getInt("Y"));
mergeCompoundTagLists(source, destination, ranges, yOffset, "block_entities", c -> ((CompoundTag) c).getInt("y") >> 4);
mergeCompoundTagLists(source, destination, ranges, yOffset, "block_ticks", c -> ((CompoundTag) c).getInt("y") >> 4);
Expand Down