Passed
Branch dev (d24a17)
by Etienne
01:34
created

convertLitematicToNbt(NbtCompound,String)   B

Complexity

Conditions 8

Size

Total Lines 70
Code Lines 27

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
dl 0
loc 70
rs 7.3333
c 1
b 0
f 0
eloc 27
cc 8

How to fix   Long Method   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
package de.kleiner3.lasertag.common.util;
2
3
import net.minecraft.nbt.*;
4
5
/**
6
 * Util class for NbtCompound operations
7
 *
8
 * @author Étienne Muser
9
 */
10
public class NbtUtil {
11
    /**
12
     * Converts a NbtCompound deserialized from a .litematic file and converts it into a NbtCompound with the format of a .nbt file
13
     * @param litematic
14
     * @param mainRegionName
15
     * @return
16
     */
17
    public static NbtCompound convertLitematicToNbt(NbtCompound litematic, String mainRegionName) {
18
        // Create new nbt compound
19
        var nbt = new NbtCompound();
20
21
        // Get the regions element
22
        var regionsElement = litematic.get("Regions");
23
24
        // If the regions element is not a nbt compound
25
        if (!(regionsElement instanceof NbtCompound)) {
26
            return null;
27
        }
28
29
        // Cast
30
        var regionsCompound = (NbtCompound)regionsElement;
31
32
        // Get the main region element
33
        var mainRegionElement = regionsCompound.get(mainRegionName);
34
35
        // If the main region element is not a nbt compound
36
        if (!(mainRegionElement instanceof NbtCompound)) {
37
            return null;
38
        }
39
40
        // Cast
41
        var mainRegionCompound = (NbtCompound)mainRegionElement;
42
43
        // Add size nbt list
44
        if (!addSize(nbt, mainRegionCompound)) {
45
            return null;
46
        }
47
48
        // Add entities list
49
        if (!addEntities(nbt, mainRegionCompound)) {
50
            return null;
51
        }
52
53
        // Get size element
54
        var sizeElement = mainRegionCompound.get("Size");
55
56
        // Check
57
        if (!(sizeElement instanceof NbtCompound)) {
58
            return null;
59
        }
60
61
        // Cast
62
        var sizeCompound = (NbtCompound)sizeElement;
63
64
        // Get the palette
65
        var paletteElement = mainRegionCompound.get("BlockStatePalette");
66
67
        // Check
68
        if (!(paletteElement instanceof NbtList)) {
69
            return null;
70
        }
71
72
        // Cast
73
        var paletteList = (NbtList)paletteElement;
74
75
        // Add blocks list
76
        if (!addBlockList(nbt, mainRegionCompound, sizeCompound, paletteList)) {
77
            return null;
78
        }
79
80
        // Add palette list
81
        nbt.put("palette", paletteElement);
82
83
        // Add data version int
84
        nbt.put("DataVersion", litematic.get("MinecraftDataVersion"));
85
86
        return nbt;
87
    }
88
89
    //region convertLitematicToNbt helper
90
91
    private static boolean addSize(NbtCompound nbt, NbtCompound litematicMainRegion) {
92
        // Get size element
93
        var sizeElement = litematicMainRegion.get("Size");
94
95
        // If is not nbt compound
96
        if (!(sizeElement instanceof NbtCompound)) {
97
            return false;
98
        }
99
100
        // Cast
101
        var sizeCompound = (NbtCompound)sizeElement;
102
103
        // Convert to list
104
        var sizeList = xyzCompoundToList(sizeCompound);
105
106
        // Put
107
        nbt.put("size", sizeList);
108
109
        return true;
110
    }
111
112
    private static boolean addEntities(NbtCompound nbt, NbtCompound litematicMainRegion) {
113
        // Get the entities element
114
        var entitiesElement = litematicMainRegion.get("Entities");
115
116
        // If is not nbt list
117
        if (!(entitiesElement instanceof NbtList)) {
118
            return false;
119
        }
120
121
        // Cast
122
        var entitiesList = (NbtList)entitiesElement;
123
124
        // Create new list
125
        var list = new NbtList();
126
127
        // For every entity
128
        for (var entity : entitiesList) {
129
            // If is not nbtCompound
130
            if (!(entity instanceof NbtCompound)) {
131
                return false;
132
            }
133
134
            // Cast
135
            var entityCompound = (NbtCompound)entity;
136
137
            // Add to list
138
            if (!addEntityToList(list, entityCompound)) {
139
                return false;
140
            }
141
        }
142
143
        // Put
144
        nbt.put("entities", list);
145
146
        return true;
147
    }
148
149
    private static boolean addEntityToList(NbtList list, NbtCompound litematicEntity) {
150
        // Get pos of entity
151
        var posElement = litematicEntity.get("Pos");
152
153
        // If pos is not nbt list
154
        if (!(posElement instanceof NbtList)) {
155
            return false;
156
        }
157
158
        // Cast
159
        var posList = (NbtList)posElement;
160
161
        // Create new entity
162
        var entity = new NbtCompound();
163
164
        // Add pos to entity
165
        entity.put("pos", posList);
166
167
        // Remove pos from litematica entity
168
        litematicEntity.remove("Pos");
169
170
        // Add nbt to entity
171
        entity.put("nbt", litematicEntity);
172
173
        // Add entity to list
174
        list.add(entity);
175
176
        return true;
177
    }
178
179
    private static boolean addBlockList(NbtCompound nbt, NbtCompound litematicMainRegion, NbtCompound size, NbtList palette) {
180
        // Create block list
181
        var list = new NbtList();
182
183
        // Get size
184
        var sizeX = ((NbtInt)size.get("x")).intValue();
185
        var sizeY = ((NbtInt)size.get("y")).intValue();
186
        var sizeZ = ((NbtInt)size.get("z")).intValue();
187
188
        // Get block state array element
189
        var blockStateArrayElement = litematicMainRegion.get("BlockStates");
190
191
        // If is not long array
192
        if (!(blockStateArrayElement instanceof NbtLongArray)) {
193
            return false;
194
        }
195
196
        // Cast
197
        var blockStateArray = (NbtLongArray)blockStateArrayElement;
198
199
        // Calculate number of bits
200
        var bits = Math.max(2, Integer.SIZE - Integer.numberOfLeadingZeros(palette.size() - 1));
201
202
        // Calculate max entry value
203
        var maxEntryValue = (1L << bits) - 1L;
204
205
        // Iterate over every possible block
206
        for (long x = 0; x < sizeX; x++) {
207
            for (long y = 0; y < sizeY; y++) {
208
                for (long z = 0; z < sizeZ; z++) {
209
                    // Get index in array
210
                    var index = (y * sizeX * sizeZ) + (z * sizeX) + x;
211
212
                    // Get the block state index in the palette
213
                    var paletteIndex = getBlockAt(blockStateArray, index, bits, maxEntryValue);
214
215
                    // Create block nbt compound
216
                    var block = new NbtCompound();
217
218
                    // Create pos list
219
                    var pos = new NbtList();
220
                    pos.add(NbtInt.of((int) x));
221
                    pos.add(NbtInt.of((int) y));
222
                    pos.add(NbtInt.of((int) z));
223
224
                    // Add pos to block
225
                    block.put("pos", pos);
226
227
                    // Add state to block
228
                    block.put("state", NbtInt.of(paletteIndex));
229
230
                    // Add block to list
231
                    list.add(block);
232
                }
233
            }
234
        }
235
236
        // Add block list to nbt
237
        nbt.put("blocks", list);
238
239
        return true;
240
    }
241
242
    private static int getBlockAt(NbtLongArray array, long index, int bitsPerEntry, long maxEntryValue) {
243
        var startOffset = index * (long) bitsPerEntry;
244
        var startArrIndex = (int) (startOffset >> 6); // startOffset / 64
245
        var endArrIndex = (int) (((index + 1L) * (long) bitsPerEntry - 1L) >> 6);
246
        var startBitOffset = (int) (startOffset & 0x3F); // startOffset % 64
247
248
        var valAtStartIndex = array.get(startArrIndex).longValue();
249
250
        if (startArrIndex == endArrIndex)
251
        {
252
            return (int) (valAtStartIndex >>> startBitOffset & maxEntryValue);
253
        }
254
        else
255
        {
256
            var valAtEndIndex = array.get(endArrIndex).longValue();
257
258
            var endOffset = 64 - startBitOffset;
259
            return (int) ((valAtStartIndex >>> startBitOffset | valAtEndIndex << endOffset) & maxEntryValue);
260
        }
261
    }
262
263
    //endregion
264
265
    public static NbtList xyzCompoundToList(NbtCompound compound) {
266
        // Create list
267
        var list = new NbtList();
268
269
        // Add to list
270
        list.add(0, compound.get("x"));
271
        list.add(1, compound.get("y"));
272
        list.add(2, compound.get("z"));
273
274
        return list;
275
    }
276
}
277