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
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
|
package tectech.recipe;
import static com.google.common.math.IntMath.pow;
import static gregtech.api.GregTechAPI.getUnificatedOreDictStack;
import static gregtech.api.enums.Mods.NewHorizonsCoreMod;
import static gregtech.api.util.GTModHandler.getModItem;
import static gregtech.api.util.GTUtility.getPlasmaFuelValueInEUPerLiterFromMaterial;
import static java.lang.Math.min;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;
import net.minecraft.item.ItemStack;
import net.minecraftforge.fluids.FluidStack;
import org.apache.commons.lang3.tuple.Pair;
import gnu.trove.map.TMap;
import gnu.trove.map.hash.TCustomHashMap;
import gnu.trove.strategy.HashingStrategy;
import gregtech.api.enums.Materials;
import gregtech.api.enums.MaterialsUEVplus;
import gregtech.api.enums.OrePrefixes;
import gregtech.api.util.GTOreDictUnificator;
import gtneioreplugin.plugin.block.BlockDimensionDisplay;
import gtneioreplugin.util.GT5OreLayerHelper;
import gtneioreplugin.util.GT5OreSmallHelper;
import tectech.util.FluidStackLong;
import tectech.util.ItemStackLong;
@SuppressWarnings("SpellCheckingInspection")
public class EyeOfHarmonyRecipe {
static final FluidStackLong[] SPECIAL_FLUIDS = new FluidStackLong[] {
new FluidStackLong(MaterialsUEVplus.WhiteDwarfMatter.getMolten(1_152), 1_152),
new FluidStackLong(MaterialsUEVplus.WhiteDwarfMatter.getMolten(1_152), 1_152),
new FluidStackLong(MaterialsUEVplus.WhiteDwarfMatter.getMolten(4_608), 4_608),
new FluidStackLong(MaterialsUEVplus.WhiteDwarfMatter.getMolten(18_432), 18_432),
new FluidStackLong(MaterialsUEVplus.BlackDwarfMatter.getMolten(1_152), 1_152),
new FluidStackLong(MaterialsUEVplus.BlackDwarfMatter.getMolten(4_608), 4_608),
new FluidStackLong(MaterialsUEVplus.BlackDwarfMatter.getMolten(18_432), 18_432),
new FluidStackLong(MaterialsUEVplus.Universium.getMolten(1_152), 1_152),
new FluidStackLong(MaterialsUEVplus.Universium.getMolten(4_608), 4_608),
new FluidStackLong(MaterialsUEVplus.Universium.getMolten(18_432), 18_432) };
HashingStrategy<ItemStack> itemStackHashingStrategy = new HashingStrategy<>() {
private static final long serialVersionUID = -3966004160368229212L;
@Override
public int computeHashCode(ItemStack stack) {
// Not really sure how this works or if it is "unique enough".
int result = stack.getItem()
.hashCode();
result = 31 * result + stack.getItemDamage();
return result;
}
@Override
public boolean equals(ItemStack item1, ItemStack item2) {
return item1.getUnlocalizedName()
.equals(item2.getUnlocalizedName());
}
};
private final TMap<ItemStack, Double> itemStackToProbabilityMap = new TCustomHashMap<>(itemStackHashingStrategy);
private final TMap<ItemStack, Long> itemStackToTrueStackSizeMap = new TCustomHashMap<>(itemStackHashingStrategy);
private final ArrayList<ItemStackLong> outputItems;
private final ArrayList<FluidStackLong> outputFluids;
private final long hydrogenRequirement;
private final long heliumRequirement;
private final long euOutput;
private final long euStartCost;
private final double baseSuccessChance;
private final long spacetimeCasingTierRequired;
private final long miningTimeSeconds;
private final double recipeEnergyEfficiency;
private final ItemStack recipeTriggerItem;
private final long sumOfItems;
private final long rocketTier;
public TMap<ItemStack, Double> getItemStackToProbabilityMap() {
return itemStackToProbabilityMap;
}
public TMap<ItemStack, Long> getItemStackToTrueStackSizeMap() {
return itemStackToTrueStackSizeMap;
}
public double getRecipeEnergyEfficiency() {
return recipeEnergyEfficiency;
}
@SuppressWarnings("FieldCanBeLocal")
private final long standardRecipeEUOutPerTick = 100 * EyeOfHarmonyRecipeStorage.BILLION;
public long getSumOfItems() {
return sumOfItems;
}
public long getRocketTier() {
return rocketTier;
}
public EyeOfHarmonyRecipe(final ArrayList<Pair<Materials, Long>> materialList, final BlockDimensionDisplay block,
final double recipeEnergyEfficiency, final long hydrogenRequirement, final long heliumRequirement,
final long miningTimeSeconds, final long rocketTierOfRecipe, final double baseSuccessChance) {
this.rocketTier = rocketTierOfRecipe;
this.spacetimeCasingTierRequired = min(8, rocketTierOfRecipe);
this.recipeTriggerItem = new ItemStack(block);
this.outputItems = validDustGenerator(materialList);
this.sumOfItems = this.outputItems.stream()
.map(ItemStackLong::getStackSize)
.reduce(0L, Long::sum);
this.outputItems.add(new ItemStackLong(getStoneDustType(block.getDimension()), this.sumOfItems * 3L));
this.outputItems.sort(Comparator.comparingLong(ItemStackLong::getStackSize));
Collections.reverse(this.outputItems);
for (ItemStackLong itemStackLong : outputItems) {
double stackSize = (double) itemStackLong.getStackSize();
double probability = Math.round(100_000 * stackSize / sumOfItems) / 1000.0;
itemStackToProbabilityMap.put(itemStackLong.itemStack, probability);
itemStackToTrueStackSizeMap.put(itemStackLong.itemStack, itemStackLong.stackSize);
}
// End item processing.
// --- Fluid handling ---
ArrayList<FluidStackLong> fluidStackLongArrayList = new ArrayList<>();
int plasmaAmount = (int) ((this.spacetimeCasingTierRequired + 1) * 8_000_000L);
// If DeepDark then it should output all plasmas involved in making exotic catalyst.
if (rocketTier == 9) {
for (Materials material : VALID_PLASMAS) {
fluidStackLongArrayList.add(new FluidStackLong(material.getPlasma(plasmaAmount), plasmaAmount));
}
} else {
// --- Output and process fluids of the recipe.
ArrayList<FluidStack> fluidStackArrayList = new ArrayList<>(validPlasmaGenerator(materialList));
for (FluidStack fluidStack : fluidStackArrayList) {
fluidStack = new FluidStack(fluidStack, plasmaAmount);
fluidStackLongArrayList.add(new FluidStackLong(fluidStack, plasmaAmount));
}
}
// Add a bonus fluid of compressed star matter.
fluidStackLongArrayList.add(
new FluidStackLong(
MaterialsUEVplus.RawStarMatter.getFluid((this.spacetimeCasingTierRequired + 1) * 100_000),
(this.spacetimeCasingTierRequired + 1) * 100_000));
// Tier 0 & 1 - 576 White
// Tier 2 - 2304 White
// Tier 3 - 9216 White
// Tier 4 - 576 Black
// Tier 5 - 2304 Black
// Tier 6 - 9216 Black
// Tier 7 - 576 Universium
// Tier 8 - 2304 Universium
// Tier 9 - 9216 Universium
int spacetimeTier = (int) rocketTierOfRecipe;
if (spacetimeTier == 0 || spacetimeTier == 9) {
spacetimeTier -= 1;
}
fluidStackLongArrayList.add(SPECIAL_FLUIDS[spacetimeTier + 1]);
outputFluids = fluidStackLongArrayList;
// --- End fluid handling ---.
this.hydrogenRequirement = hydrogenRequirement;
this.heliumRequirement = heliumRequirement;
this.baseSuccessChance = baseSuccessChance;
this.miningTimeSeconds = miningTimeSeconds;
this.recipeEnergyEfficiency = recipeEnergyEfficiency;
long plasmaEU = plasmaCostCalculator(outputFluids);
long VM3EU = miningTimeSeconds * pow(2, 19) * 20;
this.euStartCost = (plasmaEU + VM3EU + standardRecipeEUOutPerTick * 20 * miningTimeSeconds);
this.euOutput = (long) (euStartCost * recipeEnergyEfficiency);
}
private ItemStack getStoneDustType(String key) {
ItemStack placeholder = GTOreDictUnificator.get(OrePrefixes.dust, Materials.Stone, 1);
return switch (key) {
case "Ne" -> GTOreDictUnificator.get(OrePrefixes.dust, Materials.Netherrack, 1);
case "ED", "VA", "EA" -> GTOreDictUnificator.get(OrePrefixes.dust, Materials.Endstone, 1);
case "Mo" -> getModItem(NewHorizonsCoreMod.ID, "item.MoonStoneDust", 1, placeholder);
case "De" -> getModItem(NewHorizonsCoreMod.ID, "item.DeimosStoneDust", 1, placeholder);
case "Ma" -> getModItem(NewHorizonsCoreMod.ID, "item.MarsStoneDust", 1, placeholder);
case "Ph" -> getModItem(NewHorizonsCoreMod.ID, "item.PhobosStoneDust", 1, placeholder);
case "As", "KB" -> getModItem(NewHorizonsCoreMod.ID, "item.AsteroidsStoneDust", 1, placeholder);
case "Ca" -> getModItem(NewHorizonsCoreMod.ID, "item.CallistoStoneDust", 1, placeholder);
case "Ce" -> getModItem(NewHorizonsCoreMod.ID, "item.CeresStoneDust", 1, placeholder);
case "Eu" -> getModItem(NewHorizonsCoreMod.ID, "item.EuropaStoneDust", 1, placeholder);
case "Ga" -> getModItem(NewHorizonsCoreMod.ID, "item.GanymedeStoneDust", 1, placeholder);
case "Io" -> getModItem(NewHorizonsCoreMod.ID, "item.IoStoneDust", 1, placeholder);
case "Me" -> getModItem(NewHorizonsCoreMod.ID, "item.MercuryStoneDust", 1, placeholder);
case "Ve" -> getModItem(NewHorizonsCoreMod.ID, "item.VenusStoneDust", 1, placeholder);
case "En" -> getModItem(NewHorizonsCoreMod.ID, "item.EnceladusStoneDust", 1, placeholder);
case "Mi" -> getModItem(NewHorizonsCoreMod.ID, "item.MirandaStoneDust", 1, placeholder);
case "Ob" -> getModItem(NewHorizonsCoreMod.ID, "item.OberonStoneDust", 1, placeholder);
case "Ti" -> getModItem(NewHorizonsCoreMod.ID, "item.TitanStoneDust", 1, placeholder);
case "Pr" -> getModItem(NewHorizonsCoreMod.ID, "item.ProteusStoneDust", 1, placeholder);
case "Tr" -> getModItem(NewHorizonsCoreMod.ID, "item.TritonStoneDust", 1, placeholder);
case "Ha" -> getModItem(NewHorizonsCoreMod.ID, "item.HaumeaStoneDust", 1, placeholder);
case "MM" -> getModItem(NewHorizonsCoreMod.ID, "item.MakeMakeStoneDust", 1, placeholder);
case "Pl" -> getModItem(NewHorizonsCoreMod.ID, "item.PlutoStoneDust", 1, placeholder);
case "BE" -> getModItem(NewHorizonsCoreMod.ID, "item.BarnardaEStoneDust", 1, placeholder);
case "BF" -> getModItem(NewHorizonsCoreMod.ID, "item.BarnardaFStoneDust", 1, placeholder);
case "CB" -> getModItem(NewHorizonsCoreMod.ID, "item.CentauriAStoneDust", 1, placeholder);
case "TE" -> getModItem(NewHorizonsCoreMod.ID, "item.TCetiEStoneDust", 1, placeholder);
case "VB" -> getModItem(NewHorizonsCoreMod.ID, "item.VegaBStoneDust", 1, placeholder);
default -> placeholder;
};
}
public EyeOfHarmonyRecipe(final GT5OreLayerHelper.NormalOreDimensionWrapper normalOreDimensionWrapper,
final GT5OreSmallHelper.SmallOreDimensionWrapper smallOreDimensionWrapper, final BlockDimensionDisplay block,
final double recipeEnergyEfficiency, final long hydrogenRequirement, final long heliumRequirement,
final long miningTimeSeconds, final long spacetimeCasingTierRequired, final double baseSuccessChance) {
// Process recipes output items.
// 6 * 64 = 6 stacks/second for VM tier 3 + Og gas.
this(
processDimension(normalOreDimensionWrapper, smallOreDimensionWrapper, miningTimeSeconds),
block,
recipeEnergyEfficiency,
hydrogenRequirement,
heliumRequirement,
miningTimeSeconds,
spacetimeCasingTierRequired,
baseSuccessChance);
}
// Return clone of list. Deep copy. Maybe a better way to do this?
public ArrayList<ItemStackLong> getOutputItems() {
ArrayList<ItemStackLong> copyOutputList = new ArrayList<>();
for (ItemStackLong itemStackLong : outputItems) {
copyOutputList.add(new ItemStackLong(itemStackLong));
}
return copyOutputList;
}
// Deep copy.
public ArrayList<FluidStackLong> getOutputFluids() {
ArrayList<FluidStackLong> copyOutputList = new ArrayList<>();
for (FluidStackLong fluidStackLong : outputFluids) {
copyOutputList.add(new FluidStackLong(fluidStackLong));
}
return copyOutputList;
}
public long getHydrogenRequirement() {
return hydrogenRequirement;
}
public long getHeliumRequirement() {
return heliumRequirement;
}
public long getEUOutput() {
return euOutput;
}
public long getEUStartCost() {
return euStartCost;
}
public long getRecipeTimeInTicks() {
return miningTimeSeconds * 20;
}
public double getBaseRecipeSuccessChance() {
return baseSuccessChance;
}
public long getSpacetimeCasingTierRequired() {
return spacetimeCasingTierRequired;
}
public ItemStack getRecipeTriggerItem() {
return recipeTriggerItem;
}
private static final double PRIMARY_MULTIPLIER = (0.1 + 1.0 / 9.0); // Byproduct from macerating/washing chance.
private static final double SECONDARY_MULTIPLIER = (1.0 / 9.0); // Thermal centrifuge byproduct chance.
private static final double TERTIARY_MULTIPLIER = (0.1); // Macerating thermal centrifuged byproduct chance.
private static final double QUATERNARY_MULTIPLIER = (0.7); // Mercury/chem bath processing chance.
private static final double[] ORE_MULTIPLIER = { PRIMARY_MULTIPLIER, SECONDARY_MULTIPLIER, TERTIARY_MULTIPLIER,
QUATERNARY_MULTIPLIER };
public static class HashMapHelper extends HashMap<Materials, Double> {
private static final long serialVersionUID = 2297018142561480614L;
void add(Materials material, double value) {
// If key already exists.
if (this.containsKey(material)) {
this.put(material, value + this.get(material));
return;
}
// Otherwise, add value to hashmap entry.
this.put(material, value);
}
}
public static void processHelper(HashMapHelper outputMap, Materials material, double mainMultiplier,
double probability) {
if (material == null) return;
outputMap.add(material.mDirectSmelting, (material.mOreMultiplier * 2) * mainMultiplier * probability);
int index = 0;
for (Materials byProductMaterial : material.mOreByProducts) {
outputMap
.add(byProductMaterial.mDirectSmelting, mainMultiplier * (ORE_MULTIPLIER[index++] * 2) * probability);
}
}
private static ArrayList<Pair<Materials, Long>> processDimension(
GT5OreLayerHelper.NormalOreDimensionWrapper normalOreDimWrapper,
GT5OreSmallHelper.SmallOreDimensionWrapper smallOreDimWrapper, long timeInSeconds) {
HashMapHelper outputMap = new HashMapHelper();
double mainMultiplier = timeInSeconds * 384.0;
if (normalOreDimWrapper != null) {
normalOreDimWrapper.oreVeinToProbabilityInDimension.forEach((veinInfo, probability) -> {
processHelper(outputMap, veinInfo.mPrimaryVeinMaterial, mainMultiplier, probability);
processHelper(outputMap, veinInfo.mSecondaryMaterial, mainMultiplier, probability);
// 8.0 to replicate void miner getDropsVanillaVeins method yields.
processHelper(outputMap, veinInfo.mBetweenMaterial, mainMultiplier / 8.0, probability);
processHelper(outputMap, veinInfo.mSporadicMaterial, mainMultiplier / 8.0, probability);
});
}
// Iterate over small ores in dimension and add them, kinda hacky but works and is close enough.
if (smallOreDimWrapper != null) {
smallOreDimWrapper.oreVeinToProbabilityInDimension.forEach(
(veinInfo,
probability) -> processHelper(outputMap, veinInfo.getOreMaterial(), mainMultiplier, probability));
}
ArrayList<Pair<Materials, Long>> outputList = new ArrayList<>();
outputMap.forEach((material, quantity) -> outputList.add(Pair.of(material, (long) Math.floor(quantity))));
return outputList;
}
private static ArrayList<FluidStack> validPlasmaGenerator(final List<Pair<Materials, Long>> planetList) {
ArrayList<FluidStack> plasmaList = new ArrayList<>();
for (Pair<Materials, Long> pair : planetList) {
if (VALID_PLASMAS.contains(pair.getLeft())) {
plasmaList.add(
pair.getLeft()
.getPlasma(1));
}
}
return plasmaList;
}
private static ArrayList<ItemStackLong> validDustGenerator(final ArrayList<Pair<Materials, Long>> planetList) {
ArrayList<ItemStackLong> dustList = new ArrayList<>();
for (Pair<Materials, Long> pair : planetList) {
ItemStack dust = getUnificatedOreDictStack(
pair.getLeft()
.getDust(1));
if (dust != null) {
dustList.add(new ItemStackLong(dust, pair.getRight()));
}
}
return dustList;
}
private static long plasmaCostCalculator(ArrayList<FluidStackLong> plasmas) {
long total = 0;
for (FluidStackLong plasma : plasmas) {
FluidStack plasmaFluid = plasma.getRegularFluidStack(plasma, 1);
try {
String plasmaName = plasmaFluid.getFluid()
.getUnlocalizedName();
total += plasmaEnergyMap.getOrDefault(plasmaName, 0L) * plasma.amount;
} catch (Exception e) {
e.printStackTrace();
}
}
return (long) (total * getMaxPlasmaTurbineEfficiency());
}
private static double getMaxPlasmaTurbineEfficiency() {
// I hate Shirabon.
return 3.85;
}
private static final List<Materials> VALID_PLASMAS = Stream
.of(
Materials.Helium,
Materials.Iron,
Materials.Calcium,
Materials.Niobium,
Materials.Nitrogen,
Materials.Zinc,
Materials.Silver,
Materials.Titanium,
Materials.Radon,
Materials.Nickel,
Materials.Boron,
Materials.Sulfur,
Materials.Americium,
Materials.Bismuth,
Materials.Oxygen,
Materials.Tin)
.collect(Collectors.toList());
private static final HashMap<String, Long> plasmaEnergyMap = new HashMap<>() {
private static final long serialVersionUID = 7933945171103801933L;
{
VALID_PLASMAS.forEach(
(material -> put(
material.getPlasma(1)
.getFluid()
.getUnlocalizedName(),
(long) (getPlasmaFuelValueInEUPerLiterFromMaterial(material) * getMaxPlasmaTurbineEfficiency()))));
}
};
}
|