Skip to content

Commit ed91e16

Browse files
authored
Merge pull request #62 from Querz/iterators
Iterators
2 parents 25e79ed + 11bed35 commit ed91e16

File tree

3 files changed

+113
-25
lines changed

3 files changed

+113
-25
lines changed

src/main/java/net/querz/mca/Chunk.java

+23-20
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,13 @@
1212
import java.io.IOException;
1313
import java.io.RandomAccessFile;
1414
import java.util.Arrays;
15+
import java.util.Iterator;
16+
import java.util.Map;
17+
import java.util.TreeMap;
18+
1519
import static net.querz.mca.LoadFlags.*;
1620

17-
public class Chunk {
21+
public class Chunk implements Iterable<Section> {
1822

1923
public static final int DEFAULT_DATA_VERSION = 2567;
2024

@@ -31,7 +35,7 @@ public class Chunk {
3135
private int[] biomes;
3236
private CompoundTag heightMaps;
3337
private CompoundTag carvingMasks;
34-
private Section[] sections = new Section[16]; //always initialized with size = 16 for fast access
38+
private Map<Integer, Section> sections = new TreeMap<>();
3539
private ListTag<CompoundTag> entities;
3640
private ListTag<CompoundTag> tileEntities;
3741
private ListTag<CompoundTag> tileTicks;
@@ -112,15 +116,9 @@ private void initReferences(long loadFlags) {
112116
}
113117
if ((loadFlags & (BLOCK_LIGHTS|BLOCK_STATES|SKY_LIGHT)) != 0 && level.containsKey("Sections")) {
114118
for (CompoundTag section : level.getListTag("Sections").asCompoundTagList()) {
115-
int sectionIndex = section.getByte("Y");
116-
if (sectionIndex > 15 || sectionIndex < 0) {
117-
continue;
118-
}
119+
int sectionIndex = section.getNumber("Y").byteValue();
119120
Section newSection = new Section(section, dataVersion, loadFlags);
120-
if (newSection.isEmpty()) {
121-
continue;
122-
}
123-
sections[sectionIndex] = newSection;
121+
sections.put(sectionIndex, newSection);
124122
}
125123
}
126124

@@ -285,7 +283,7 @@ int getBiomeIndex(int biomeX, int biomeY, int biomeZ) {
285283
}
286284

287285
public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
288-
Section section = sections[MCAUtil.blockToChunk(blockY)];
286+
Section section = sections.get(MCAUtil.blockToChunk(blockY));
289287
if (section == null) {
290288
return null;
291289
}
@@ -306,9 +304,9 @@ public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
306304
public void setBlockStateAt(int blockX, int blockY, int blockZ, CompoundTag state, boolean cleanup) {
307305
checkRaw();
308306
int sectionIndex = MCAUtil.blockToChunk(blockY);
309-
Section section = sections[sectionIndex];
307+
Section section = sections.get(sectionIndex);
310308
if (section == null) {
311-
section = sections[sectionIndex] = Section.newSection();
309+
sections.put(sectionIndex, section = Section.newSection());
312310
}
313311
section.setBlockStateAt(blockX, blockY, blockZ, state, cleanup);
314312
}
@@ -328,7 +326,7 @@ public int getDataVersion() {
328326
public void setDataVersion(int dataVersion) {
329327
checkRaw();
330328
this.dataVersion = dataVersion;
331-
for (Section section : sections) {
329+
for (Section section : sections.values()) {
332330
if (section != null) {
333331
section.dataVersion = dataVersion;
334332
}
@@ -373,7 +371,7 @@ public void setStatus(String status) {
373371
* @return The Section.
374372
*/
375373
public Section getSection(int sectionY) {
376-
return sections[sectionY];
374+
return sections.get(sectionY);
377375
}
378376

379377
/**
@@ -383,7 +381,7 @@ public Section getSection(int sectionY) {
383381
*/
384382
public void setSection(int sectionY, Section section) {
385383
checkRaw();
386-
sections[sectionY] = section;
384+
sections.put(sectionY, section);
387385
}
388386

389387
/**
@@ -623,7 +621,7 @@ int getBlockIndex(int blockX, int blockZ) {
623621

624622
public void cleanupPalettesAndBlockStates() {
625623
checkRaw();
626-
for (Section section : sections) {
624+
for (Section section : sections.values()) {
627625
if (section != null) {
628626
section.cleanupPaletteAndBlockStates();
629627
}
@@ -712,12 +710,17 @@ public CompoundTag updateHandle(int xPos, int zPos) {
712710
level.put("Structures", structures);
713711
}
714712
ListTag<CompoundTag> sections = new ListTag<>(CompoundTag.class);
715-
for (int i = 0; i < this.sections.length; i++) {
716-
if (this.sections[i] != null) {
717-
sections.add(this.sections[i].updateHandle(i));
713+
for (Section section : this.sections.values()) {
714+
if (section != null) {
715+
sections.add(section.updateHandle());
718716
}
719717
}
720718
level.put("Sections", sections);
721719
return data;
722720
}
721+
722+
@Override
723+
public Iterator<Section> iterator() {
724+
return sections.values().iterator();
725+
}
723726
}

src/main/java/net/querz/mca/MCAFile.java

+11-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,15 @@
11
package net.querz.mca;
22

33
import net.querz.nbt.tag.CompoundTag;
4+
import net.querz.nbt.tag.Tag;
5+
46
import java.io.IOException;
57
import java.io.RandomAccessFile;
8+
import java.util.Arrays;
9+
import java.util.Iterator;
10+
import java.util.Map;
611

7-
public class MCAFile {
12+
public class MCAFile implements Iterable<Chunk> {
813

914
/**
1015
* The default chunk data version used when no custom version is supplied.
@@ -292,4 +297,9 @@ public void cleanupPalettesAndBlockStates() {
292297
}
293298
}
294299
}
300+
301+
@Override
302+
public Iterator<Chunk> iterator() {
303+
return Arrays.stream(chunks).iterator();
304+
}
295305
}

src/main/java/net/querz/mca/Section.java

+79-4
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,19 @@
77
import net.querz.nbt.tag.LongArrayTag;
88
import java.util.ArrayList;
99
import java.util.HashMap;
10+
import java.util.Iterator;
1011
import java.util.List;
1112
import java.util.Map;
1213

13-
public class Section {
14+
public class Section implements Comparable<Section> {
1415

1516
private CompoundTag data;
1617
private Map<String, List<PaletteIndex>> valueIndexedPalette = new HashMap<>();
1718
private ListTag<CompoundTag> palette;
1819
private byte[] blockLight;
1920
private long[] blockStates;
2021
private byte[] skyLight;
22+
private int height;
2123
int dataVersion;
2224

2325
public Section(CompoundTag sectionRoot, int dataVersion) {
@@ -27,6 +29,8 @@ public Section(CompoundTag sectionRoot, int dataVersion) {
2729
public Section(CompoundTag sectionRoot, int dataVersion, long loadFlags) {
2830
data = sectionRoot;
2931
this.dataVersion = dataVersion;
32+
height = sectionRoot.getNumber("Y").byteValue();
33+
3034
ListTag<?> rawPalette = sectionRoot.getListTag("Palette");
3135
if (rawPalette == null) {
3236
return;
@@ -85,6 +89,14 @@ PaletteIndex getValueIndexedPalette(CompoundTag data) {
8589
return null;
8690
}
8791

92+
@Override
93+
public int compareTo(Section o) {
94+
if (o == null) {
95+
return -1;
96+
}
97+
return Integer.compare(height, o.height);
98+
}
99+
88100
private static class PaletteIndex {
89101

90102
CompoundTag data;
@@ -104,6 +116,17 @@ public boolean isEmpty() {
104116
return data == null;
105117
}
106118

119+
/**
120+
* @return the Y value of this section.
121+
* */
122+
public int getHeight() {
123+
return height;
124+
}
125+
126+
public void setHeight(int height) {
127+
this.height = height;
128+
}
129+
107130
/**
108131
* Fetches a block state based on a block location from this section.
109132
* The coordinates represent the location of the block inside of this Section.
@@ -113,7 +136,10 @@ public boolean isEmpty() {
113136
* @return The block state data of this block.
114137
*/
115138
public CompoundTag getBlockStateAt(int blockX, int blockY, int blockZ) {
116-
int index = getBlockIndex(blockX, blockY, blockZ);
139+
return getBlockStateAt(getBlockIndex(blockX, blockY, blockZ));
140+
}
141+
142+
private CompoundTag getBlockStateAt(int index) {
117143
int paletteIndex = getPaletteIndex(index);
118144
return palette.get(paletteIndex);
119145
}
@@ -239,8 +265,10 @@ static long bitRange(long value, int from, int to) {
239265
* Recalculating the Palette should only be executed once right before saving the Section to file.
240266
*/
241267
public void cleanupPaletteAndBlockStates() {
242-
Map<Integer, Integer> oldToNewMapping = cleanupPalette();
243-
adjustBlockStateBits(oldToNewMapping, blockStates);
268+
if (blockStates != null) {
269+
Map<Integer, Integer> oldToNewMapping = cleanupPalette();
270+
adjustBlockStateBits(oldToNewMapping, blockStates);
271+
}
244272
}
245273

246274
private Map<Integer, Integer> cleanupPalette() {
@@ -395,4 +423,51 @@ public CompoundTag updateHandle(int y) {
395423
}
396424
return data;
397425
}
426+
427+
public CompoundTag updateHandle() {
428+
return updateHandle(height);
429+
}
430+
431+
/**
432+
* Creates an iterable that iterates over all blocks in this section, in order of their indices.
433+
* An index can be calculated using the following formula:
434+
* <pre>
435+
* {@code
436+
* index = (blockY & 0xF) * 256 + (blockZ & 0xF) * 16 + (blockX & 0xF);
437+
* }
438+
* </pre>
439+
* The CompoundTags are references to this Section's Palette and should only be modified if the intention is to
440+
* modify ALL blocks of the same type in this Section at the same time.
441+
* */
442+
public Iterable<CompoundTag> blocksStates() {
443+
return new BlockIterator(this);
444+
}
445+
446+
private static class BlockIterator implements Iterable<CompoundTag>, Iterator<CompoundTag> {
447+
448+
private Section section;
449+
private int currentIndex;
450+
451+
public BlockIterator(Section section) {
452+
this.section = section;
453+
currentIndex = 0;
454+
}
455+
456+
@Override
457+
public boolean hasNext() {
458+
return currentIndex < 4096;
459+
}
460+
461+
@Override
462+
public CompoundTag next() {
463+
CompoundTag blockState = section.getBlockStateAt(currentIndex);
464+
currentIndex++;
465+
return blockState;
466+
}
467+
468+
@Override
469+
public Iterator<CompoundTag> iterator() {
470+
return this;
471+
}
472+
}
398473
}

0 commit comments

Comments
 (0)