]> git.lizzy.rs Git - BoundingBoxOutlineReloaded.git/blob - src/main/java/com/irtimaled/bbor/client/interop/NBTStructureLoader.java
Setup for 1.15.2-Fabric
[BoundingBoxOutlineReloaded.git] / src / main / java / com / irtimaled / bbor / client / interop / NBTStructureLoader.java
1 package com.irtimaled.bbor.client.interop;
2
3 import com.irtimaled.bbor.common.EventBus;
4 import com.irtimaled.bbor.common.ReflectionHelper;
5 import com.irtimaled.bbor.common.events.StructuresLoaded;
6 import com.irtimaled.bbor.common.models.DimensionId;
7 import net.minecraft.nbt.CompoundTag;
8 import net.minecraft.nbt.ListTag;
9 import net.minecraft.structure.StructureManager;
10 import net.minecraft.structure.StructurePiece;
11 import net.minecraft.structure.StructureStart;
12 import net.minecraft.util.math.BlockBox;
13 import net.minecraft.util.math.ChunkPos;
14 import net.minecraft.world.FeatureUpdater;
15 import net.minecraft.world.IWorld;
16 import net.minecraft.world.PersistentStateManager;
17 import net.minecraft.world.WorldSaveHandler;
18 import net.minecraft.world.biome.Biome;
19 import net.minecraft.world.dimension.DimensionType;
20 import net.minecraft.world.gen.chunk.ChunkGenerator;
21 import net.minecraft.world.storage.RegionBasedStorage;
22
23 import java.io.File;
24 import java.io.IOException;
25 import java.util.*;
26 import java.util.function.Function;
27
28 class NBTStructureLoader {
29     private final DimensionId dimensionId;
30     private final Set<String> loadedChunks = new HashSet<>();
31
32     private FeatureUpdater legacyStructureDataUtil = null;
33     private WorldSaveHandler saveHandler = null;
34     private File chunkSaveLocation = null;
35     private ChunkLoader chunkLoader;
36
37     NBTStructureLoader(DimensionId dimensionId, WorldSaveHandler saveHandler, File worldDirectory) {
38         this.dimensionId = dimensionId;
39         this.configure(saveHandler, worldDirectory);
40     }
41
42     void clear() {
43         this.legacyStructureDataUtil = null;
44         this.saveHandler = null;
45         this.chunkSaveLocation = null;
46         this.loadedChunks.clear();
47
48         if (this.chunkLoader == null) return;
49         try {
50             this.chunkLoader.close();
51         } catch (IOException ignored) {
52         }
53         this.chunkLoader = null;
54     }
55
56     void configure(WorldSaveHandler saveHandler, File worldDirectory) {
57         this.saveHandler = saveHandler;
58         if (worldDirectory != null) {
59             this.chunkSaveLocation = new File(dimensionId.getDimensionType().getSaveDirectory(worldDirectory), "region");
60             this.chunkLoader = new ChunkLoader(this.chunkSaveLocation);
61         }
62     }
63
64     private FeatureUpdater getLegacyStructureDataUtil() {
65         if (this.legacyStructureDataUtil == null) {
66             File dataFolder = new File(DimensionType.OVERWORLD.getSaveDirectory(this.saveHandler.getWorldDir()), "data");
67             this.legacyStructureDataUtil = FeatureUpdater.create(dimensionId.getDimensionType(),
68                     new PersistentStateManager(dataFolder, this.saveHandler.getDataFixer()));
69         }
70         return this.legacyStructureDataUtil;
71     }
72
73     private CompoundTag loadStructureStarts(int chunkX, int chunkZ) {
74         try {
75             CompoundTag compound = this.chunkLoader.readChunk(chunkX, chunkZ);
76             if (compound == null) return null;
77             int dataVersion = compound.contains("DataVersion", 99) ? compound.getInt("DataVersion") : -1;
78             if (dataVersion < 1493) {
79                 if (compound.getCompound("Level").getBoolean("hasLegacyStructureData")) {
80                     compound = getLegacyStructureDataUtil().getUpdatedReferences(compound);
81                 }
82             }
83             return compound.getCompound("Level").getCompound("Structures").getCompound("Starts");
84         } catch (IOException ignored) {
85         }
86         return null;
87     }
88
89     void loadStructures(int chunkX, int chunkZ) {
90         if (saveHandler == null) return;
91
92         if (!loadedChunks.add(String.format("%s,%s", chunkX, chunkZ))) return;
93
94         CompoundTag structureStarts = loadStructureStarts(chunkX, chunkZ);
95         if (structureStarts == null || structureStarts.getSize() == 0) return;
96
97         Map<String, StructureStart> structureStartMap = new HashMap<>();
98         for (String key : structureStarts.getKeys()) {
99             CompoundTag compound = structureStarts.getCompound(key);
100             if (compound.contains("BB")) {
101                 structureStartMap.put(key, new SimpleStructureStart(compound));
102             }
103         }
104
105         EventBus.publish(new StructuresLoaded(structureStartMap, dimensionId));
106     }
107
108     private static class SimpleStructureStart extends StructureStart {
109         SimpleStructureStart(CompoundTag compound) {
110             super(null,
111                     0,
112                     0,
113                     new BlockBox(compound.getIntArray("BB")),
114                     0,
115                     0);
116
117             ListTag children = compound.getList("Children", 10);
118             for (int index = 0; index < children.size(); ++index) {
119                 CompoundTag child = children.getCompound(index);
120                 if (child.contains("BB")) this.children.add(new SimpleStructurePiece(child));
121             }
122         }
123
124         @Override
125         public void initialize(ChunkGenerator<?> chunkGenerator, StructureManager structureManager, int i, int i1, Biome biome) {
126
127         }
128     }
129
130     private static class SimpleStructurePiece extends StructurePiece {
131         SimpleStructurePiece(CompoundTag compound) {
132             super(null, compound);
133         }
134
135         @Override
136         protected void toNbt(CompoundTag compoundTag) {
137
138         }
139
140         @Override
141         public boolean generate(IWorld iWorld, ChunkGenerator<?> chunkGenerator, Random random, BlockBox blockBox, ChunkPos chunkPos) {
142             return false;
143         }
144     }
145
146     private static class ChunkLoader {
147         private static final Function<File, RegionBasedStorage> creator =
148                 ReflectionHelper.getPrivateInstanceBuilder(RegionBasedStorage.class, File.class);
149
150         private final RegionBasedStorage regionFileCache;
151
152         public ChunkLoader(File file) {
153             this.regionFileCache = creator.apply(file);
154         }
155
156         public CompoundTag readChunk(int chunkX, int chunkZ) throws IOException {
157             if (regionFileCache == null) return null;
158             return regionFileCache.getTagAt(new ChunkPos(chunkX, chunkZ));
159         }
160
161         public void close() throws IOException {
162             if (regionFileCache == null) return;
163             regionFileCache.close();
164         }
165     }
166 }