1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
|
package bartworks.API;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.lazy;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAdder;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlockAnyMeta;
import static com.gtnewhorizon.structurelib.structure.StructureUtility.ofBlocksTiered;
import java.util.ArrayList;
import java.util.List;
import java.util.PriorityQueue;
import java.util.function.BiConsumer;
import java.util.function.Function;
import java.util.stream.Collectors;
import net.minecraft.block.Block;
import org.apache.commons.lang3.tuple.Pair;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.LinkedHashMultimap;
import com.google.common.collect.SetMultimap;
import com.google.common.collect.Table;
import com.gtnewhorizon.structurelib.structure.IStructureElement;
import bartworks.common.loaders.ItemRegistry;
import cpw.mods.fml.common.Loader;
import cpw.mods.fml.common.LoaderState;
/**
* API for bartworks borosilicate glass.
* <p>
* You might have noticed this API does not expose any Block instance, but only IStructureElements. This is in case we
* add more glass blocks later, and we run out of meta id for only one block.
* <p>
* IStructureElements returned from this class <b>SHOULD NOT</b> have its methods called before post init, or else you
* might end up with wrong autoplace hints.
*/
public class BorosilicateGlass {
private static List<Pair<Block, Integer>> representatives;
private static SetMultimap<Byte, Pair<Block, Integer>> allLevels;
private static final Table<Block, Integer, Byte> allLevelsReverse = HashBasedTable.create();
private static boolean isValidTier(int tier) {
return tier > 0 && tier <= Byte.MAX_VALUE;
}
public static Block getGlassBlock() {
return ItemRegistry.bw_realglas;
}
public static Block getGlassBlock2() {
return ItemRegistry.bw_realglas2;
}
private static void doRegister(byte level, Block block, int meta,
SetMultimap<Byte, Pair<Block, Integer>> allLevels) {
allLevels.put(level, Pair.of(block, meta));
allLevelsReverse.put(block, meta, level);
}
private static SetMultimap<Byte, Pair<Block, Integer>> getAllLevels() {
if (allLevels == null) {
SetMultimap<Byte, Pair<Block, Integer>> ret = LinkedHashMultimap.create();
Block block = getGlassBlock();
doRegister((byte) 3, block, 0, ret);
doRegister((byte) 4, block, 1, ret);
doRegister((byte) 5, block, 12, ret);
doRegister((byte) 5, block, 2, ret);
doRegister((byte) 6, block, 3, ret);
doRegister((byte) 7, block, 4, ret);
doRegister((byte) 8, block, 5, ret);
for (int i = 6; i < 12; i++) {
doRegister((byte) 3, block, i, ret);
}
doRegister((byte) 9, block, 13, ret);
doRegister((byte) 10, block, 14, ret);
doRegister((byte) 11, block, 15, ret);
block = getGlassBlock2();
doRegister((byte) 12, block, 0, ret);
allLevels = ret;
}
return allLevels;
}
private static List<Pair<Block, Integer>> getRepresentatives() {
if (representatives == null) {
SetMultimap<Byte, Pair<Block, Integer>> allLevels = getAllLevels();
ArrayList<Pair<Block, Integer>> ret = new ArrayList<>();
for (Byte level : new PriorityQueue<>(allLevels.keySet())) {
ret.add(
allLevels.get(level)
.iterator()
.next());
}
representatives = ret;
}
return representatives;
}
private static Byte checkWithinBound(byte val, byte lo, byte hi) {
return val > hi || val < lo ? null : val;
}
/**
* ONLY registers borosilicate glass. Without this, {@link #getTier} won't work properly in environments that don't
* have the coremod.
*/
public static void registerBorosilicateGlass() {
getAllLevels();
}
/**
* Register a new block as valid borosilicate glass with given tier (even if it doesn't contain boron at all)
*
* Does not support matching by more complex stuff like tile entity!
*
* Can only be called at INIT stage.
*/
public static void registerGlass(Block block, int meta, byte tier) {
if (Loader.instance()
.hasReachedState(LoaderState.POSTINITIALIZATION)) throw new IllegalStateException("register too late!");
if (!Loader.instance()
.hasReachedState(LoaderState.INITIALIZATION)) throw new IllegalStateException("register too early!");
if (!isValidTier(tier)) throw new IllegalArgumentException("not a valid tier: " + tier);
doRegister(tier, block, meta, getAllLevels());
}
/**
* Check if there is at least one type of boroglass in that tier.
*/
public static boolean hasGlassInTier(int tier) {
return getAllLevels().containsKey((byte) tier);
}
/**
* Get a structure element for a certain tier of <b>borosilicate</b> glass. DOES NOT accept other glass like
* reinforced glass, magic mirror, vanilla glass, etc. unless these glass are explicitly registered as a
* borosilicate glass.
* <p>
* Use this if you just want boroglass here and doesn't care what tier it is.
*/
public static <T> IStructureElement<T> ofBoroGlass(int tier) {
if (!hasGlassInTier(tier)) throw new IllegalArgumentException();
return lazy(t -> {
Pair<Block, Integer> pair = getRepresentatives().get(tier - 3);
return ofBlockAdder((t1, block1, meta) -> getTier(block1, meta) == tier, pair.getKey(), pair.getValue());
});
}
/**
* Get a structure element for any kind of <b>borosilicate</b> glass. DOES NOT accept other glass like reinforced
* glass, magic mirror, vanilla glass, etc. unless these glass are explicitly registered as a borosilicate glass.
* <p>
* Use this if you just want boroglass here and doesn't care what tier it is.
*/
public static <T> IStructureElement<T> ofBoroGlassAnyTier() {
return lazy(t -> ofBlockAnyMeta(getGlassBlock()));
}
/**
* Get a structure element for <b>borosilicate</b> glass. DOES NOT accept other glass like reinforced glass, magic
* mirror, vanilla glass, etc. unless these glass are explicitly registered as a borosilicate glass.
* <p>
* This assumes you want all glass used to be of the same tier.
* <p>
* NOTE: This will accept the basic boron glass (HV tier) as well. You might not want this. Use the other overload
* to filter this out.
*
* @param initialValue the value set before structure check started
*/
public static <T> IStructureElement<T> ofBoroGlass(byte initialValue, BiConsumer<T, Byte> setter,
Function<T, Byte> getter) {
return lazy(
t -> ofBlocksTiered(BorosilicateGlass::getTier, getRepresentatives(), initialValue, setter, getter));
}
/**
* Get a structure element for <b>borosilicate</b> glass. DOES NOT accept other glass like reinforced glass, magic
* mirror, vanilla glass, etc. unless these glass are explicitly registered as a borosilicate glass.
*
* @param initialValue the value set before structure check started
* @param minTier minimal accepted tier. inclusive. must be greater than 0.
* @param maxTier maximal accepted tier. inclusive.
*/
public static <T> IStructureElement<T> ofBoroGlass(byte initialValue, byte minTier, byte maxTier,
BiConsumer<T, Byte> setter, Function<T, Byte> getter) {
if (minTier > maxTier || minTier < 0) throw new IllegalArgumentException();
return lazy(
t -> ofBlocksTiered(
(block1, meta) -> checkWithinBound(getTier(block1, meta), minTier, maxTier),
getRepresentatives().stream()
.skip(Math.max(minTier - 3, 0))
.limit(maxTier - minTier + 1)
.collect(Collectors.toList()),
initialValue,
setter,
getter));
}
/**
* Get the tier of this <b>borosilicate</b> glass. DOES NOT consider other glass like reinforced glass, magic
* mirror, vanilla glass, etc. unless these glass are explicitly registered as a borosilicate glass.
*
* @return glass tier, or -1 if is not a borosilicate glass
*/
public static byte getTier(Block block, int meta) {
Byte ret = allLevelsReverse.get(block, meta);
return ret == null ? -1 : ret;
}
}
|