Skip to content

Commit

Permalink
Merge pull request #62 from Querz/iterators
Browse files Browse the repository at this point in the history
Iterators
  • Loading branch information
Querz committed Apr 29, 2021
2 parents 25e79ed + 11bed35 commit ed91e16
Show file tree
Hide file tree
Showing 3 changed files with 113 additions and 25 deletions.
43 changes: 23 additions & 20 deletions src/main/java/net/querz/mca/Chunk.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,13 @@
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;
import java.util.TreeMap;

import static net.querz.mca.LoadFlags.*;

public class Chunk {
public class Chunk implements Iterable<Section> {

public static final int DEFAULT_DATA_VERSION = 2567;

Expand All @@ -31,7 +35,7 @@ public class Chunk {
private int[] biomes;
private CompoundTag heightMaps;
private CompoundTag carvingMasks;
private Section[] sections = new Section[16]; //always initialized with size = 16 for fast access
private Map<Integer, Section> sections = new TreeMap<>();
private ListTag<CompoundTag> entities;
private ListTag<CompoundTag> tileEntities;
private ListTag<CompoundTag> tileTicks;
Expand Down Expand Up @@ -112,15 +116,9 @@ private void initReferences(long loadFlags) {
}
if ((loadFlags & (BLOCK_LIGHTS|BLOCK_STATES|SKY_LIGHT)) != 0 && level.containsKey("Sections")) {
for (CompoundTag section : level.getListTag("Sections").asCompoundTagList()) {
int sectionIndex = section.getByte("Y");
if (sectionIndex > 15 || sectionIndex < 0) {
continue;
}
int sectionIndex = section.getNumber("Y").byteValue();
Section newSection = new Section(section, dataVersion, loadFlags);
if (newSection.isEmpty()) {
continue;
}
sections[sectionIndex] = newSection;
sections.put(sectionIndex, newSection);
}
}

Expand Down Expand Up @@ -285,7 +283,7 @@ int getBiomeIndex(int biomeX, int biomeY, int biomeZ) {
}

public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
Section section = sections[MCAUtil.blockToChunk(blockY)];
Section section = sections.get(MCAUtil.blockToChunk(blockY));
if (section == null) {
return null;
}
Expand All @@ -306,9 +304,9 @@ public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
public void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) {
checkRaw();
int sectionIndex = MCAUtil.blockToChunk(blockY);
Section section = sections[sectionIndex];
Section section = sections.get(sectionIndex);
if (section == null) {
section = sections[sectionIndex] = Section.newSection();
sections.put(sectionIndex, section = Section.newSection());
}
section.setBlockStateAt(blockX, blockY, blockZ, state, cleanup);
}
Expand All @@ -328,7 +326,7 @@ public int getDataVersion() {
public void setDataVersion(int dataVersion) {
checkRaw();
this.dataVersion = dataVersion;
for (Section section : sections) {
for (Section section : sections.values()) {
if (section != null) {
section.dataVersion = dataVersion;
}
Expand Down Expand Up @@ -373,7 +371,7 @@ public void setStatus(String status) {
* @return The Section.
*/
public Section getSection(int sectionY) {
return sections[sectionY];
return sections.get(sectionY);
}

/**
Expand All @@ -383,7 +381,7 @@ public Section getSection(int sectionY) {
*/
public void setSection(int sectionY, Section section) {
checkRaw();
sections[sectionY] = section;
sections.put(sectionY, section);
}

/**
Expand Down Expand Up @@ -623,7 +621,7 @@ int getBlockIndex(int blockX, int blockZ) {

public void cleanupPalettesAndBlockStates() {
checkRaw();
for (Section section : sections) {
for (Section section : sections.values()) {
if (section != null) {
section.cleanupPaletteAndBlockStates();
}
Expand Down Expand Up @@ -712,12 +710,17 @@ public CompoundTag updateHandle(int xPos, int zPos) {
level.put("Structures", structures);
}
ListTag<CompoundTag> sections = new ListTag<>(CompoundTag.class);
for (int i = 0; i < this.sections.length; i++) {
if (this.sections[i] != null) {
sections.add(this.sections[i].updateHandle(i));
for (Section section : this.sections.values()) {
if (section != null) {
sections.add(section.updateHandle());
}
}
level.put("Sections", sections);
return data;
}

@Override
public Iterator<Section> iterator() {
return sections.values().iterator();
}
}
12 changes: 11 additions & 1 deletion src/main/java/net/querz/mca/MCAFile.java
Original file line number Diff line number Diff line change
@@ -1,10 +1,15 @@
package net.querz.mca;

import net.querz.nbt.tag.CompoundTag;
import net.querz.nbt.tag.Tag;

import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Map;

public class MCAFile {
public class MCAFile implements Iterable<Chunk> {

/**
* The default chunk data version used when no custom version is supplied.
Expand Down Expand Up @@ -292,4 +297,9 @@ public void cleanupPalettesAndBlockStates() {
}
}
}

@Override
public Iterator<Chunk> iterator() {
return Arrays.stream(chunks).iterator();
}
}
83 changes: 79 additions & 4 deletions src/main/java/net/querz/mca/Section.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,19 @@
import net.querz.nbt.tag.LongArrayTag;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;

public class Section {
public class Section implements Comparable<Section> {

private CompoundTag data;
private Map<String, List<PaletteIndex>> valueIndexedPalette = new HashMap<>();
private ListTag<CompoundTag> palette;
private byte[] blockLight;
private long[] blockStates;
private byte[] skyLight;
private int height;
int dataVersion;

public Section(CompoundTag sectionRoot, int dataVersion) {
Expand All @@ -27,6 +29,8 @@ public Section(CompoundTag sectionRoot, int dataVersion) {
public Section(CompoundTag sectionRoot, int dataVersion, long loadFlags) {
data = sectionRoot;
this.dataVersion = dataVersion;
height = sectionRoot.getNumber("Y").byteValue();

ListTag<?> rawPalette = sectionRoot.getListTag("Palette");
if (rawPalette == null) {
return;
Expand Down Expand Up @@ -85,6 +89,14 @@ PaletteIndex getValueIndexedPalette(CompoundTag data) {
return null;
}

@Override
public int compareTo(Section o) {
if (o == null) {
return -1;
}
return Integer.compare(height, o.height);
}

private static class PaletteIndex {

CompoundTag data;
Expand All @@ -104,6 +116,17 @@ public boolean isEmpty() {
return data == null;
}

/**
* @return the Y value of this section.
* */
public int getHeight() {
return height;
}

public void setHeight(int height) {
this.height = height;
}

/**
* Fetches a block state based on a block location from this section.
* The coordinates represent the location of the block inside of this Section.
Expand All @@ -113,7 +136,10 @@ public boolean isEmpty() {
* @return The block state data of this block.
*/
public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
int index = getBlockIndex(blockX, blockY, blockZ);
return getBlockStateAt(getBlockIndex(blockX, blockY, blockZ));
}

private CompoundTag getBlockStateAt(int index) {
int paletteIndex = getPaletteIndex(index);
return palette.get(paletteIndex);
}
Expand Down Expand Up @@ -239,8 +265,10 @@ static long bitRange(long value, int from, int to) {
* Recalculating the Palette should only be executed once right before saving the Section to file.
*/
public void cleanupPaletteAndBlockStates() {
Map<Integer, Integer> oldToNewMapping = cleanupPalette();
adjustBlockStateBits(oldToNewMapping, blockStates);
if (blockStates != null) {
Map<Integer, Integer> oldToNewMapping = cleanupPalette();
adjustBlockStateBits(oldToNewMapping, blockStates);
}
}

private Map<Integer, Integer> cleanupPalette() {
Expand Down Expand Up @@ -395,4 +423,51 @@ public CompoundTag updateHandle(int y) {
}
return data;
}

public CompoundTag updateHandle() {
return updateHandle(height);
}

/**
* Creates an iterable that iterates over all blocks in this section, in order of their indices.
* An index can be calculated using the following formula:
* <pre>
* {@code
* index = (blockY & 0xF) * 256 + (blockZ & 0xF) * 16 + (blockX & 0xF);
* }
* </pre>
* The CompoundTags are references to this Section's Palette and should only be modified if the intention is to
* modify ALL blocks of the same type in this Section at the same time.
* */
public Iterable<CompoundTag> blocksStates() {
return new BlockIterator(this);
}

private static class BlockIterator implements Iterable<CompoundTag>, Iterator<CompoundTag> {

private Section section;
private int currentIndex;

public BlockIterator(Section section) {
this.section = section;
currentIndex = 0;
}

@Override
public boolean hasNext() {
return currentIndex < 4096;
}

@Override
public CompoundTag next() {
CompoundTag blockState = section.getBlockStateAt(currentIndex);
currentIndex++;
return blockState;
}

@Override
public Iterator<CompoundTag> iterator() {
return this;
}
}
}

0 comments on commit ed91e16

Please sign in to comment.