/*
* spotless:off
* KubaTech - Gregtech Addon
* Copyright (C) 2022 - 2024 kuba6000
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 3 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library. If not, see .
* spotless:on
*/
package kubatech.test;
import static gregtech.api.util.GT_RecipeBuilder.MINUTES;
import static gregtech.api.util.GT_RecipeBuilder.SECONDS;
import static kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse.EIG_BALANCE_IC2_ACCELERATOR_TIER;
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.fail;
import java.io.File;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Map;
import net.minecraft.block.Block;
import net.minecraft.init.Blocks;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.server.MinecraftServer;
import net.minecraft.util.ChatComponentText;
import net.minecraft.world.MinecraftException;
import net.minecraft.world.World;
import net.minecraft.world.WorldProvider;
import net.minecraft.world.WorldProviderSurface;
import net.minecraft.world.WorldServer;
import net.minecraft.world.WorldSettings;
import net.minecraft.world.WorldType;
import net.minecraft.world.chunk.storage.IChunkLoader;
import net.minecraft.world.storage.IPlayerFileData;
import net.minecraft.world.storage.ISaveHandler;
import net.minecraft.world.storage.WorldInfo;
import net.minecraftforge.common.DimensionManager;
import org.junit.jupiter.api.Test;
import com.gtnewhorizon.gtnhlib.util.map.ItemStackMap;
import gregtech.api.GregTech_API;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
import gregtech.common.blocks.GT_Item_Machines;
import ic2.api.crops.CropCard;
import ic2.api.crops.Crops;
import ic2.core.Ic2Items;
import ic2.core.crop.TileEntityCrop;
import kubatech.tileentity.gregtech.multiblock.GT_MetaTileEntity_ExtremeIndustrialGreenhouse;
public class EIGTests {
private static final int EIG_CONTROLLER_METADATA = 12_792;
private static final int NUMBER_OF_CROPS_PER_TEST = 90;
private static final int NUMBER_OF_TESTS_TO_DO = 30;
static World myWorld;
public EIGTests() {
if (!DimensionManager.isDimensionRegistered(256)) {
DimensionManager.registerProviderType(256, WorldProviderSurface.class, false);
DimensionManager.registerDimension(256, 256);
}
if (myWorld == null) {
myWorld = new WorldServer(MinecraftServer.getServer(), new ISaveHandler() {
@Override
public WorldInfo loadWorldInfo() {
return null;
}
@Override
public void checkSessionLock() throws MinecraftException {
}
@Override
public IChunkLoader getChunkLoader(WorldProvider p_75763_1_) {
return null;
}
@Override
public void saveWorldInfoWithPlayer(WorldInfo p_75755_1_, NBTTagCompound p_75755_2_) {
}
@Override
public void saveWorldInfo(WorldInfo p_75761_1_) {
}
@Override
public IPlayerFileData getSaveHandler() {
return null;
}
@Override
public void flush() {
}
@Override
public File getWorldDirectory() {
return null;
}
@Override
public File getMapFileFromName(String p_75758_1_) {
return null;
}
@Override
public String getWorldDirectoryName() {
return "dummy";
}
},
"DummyTestWorld",
256,
new WorldSettings(256, WorldSettings.GameType.SURVIVAL, false, false, WorldType.DEFAULT),
MinecraftServer.getServer().theProfiler) {
@Override
public File getChunkSaveLocation() {
return new File("ignoreme");
}
@Override
public int getBlockLightValue(int p_72957_1_, int p_72957_2_, int p_72957_3_) {
return 4;
}
};
}
}
private static int leftOverTicksFromRealRun = 0;
ItemStackMap getRealDrops(TileEntityCrop cropTile, CropCard cc, int growth, int gain, int resistance) {
cropTile.setCrop(cc);
cropTile.setGrowth((byte) growth);
cropTile.setGain((byte) gain);
cropTile.setResistance((byte) resistance);
cropTile.tick();
ItemStackMap expected = new ItemStackMap<>();
// run for 30 minutes
for (int k = 0; k < NUMBER_OF_CROPS_PER_TEST; k++) {
cropTile.ticker = 1;
cropTile.setSize((byte) cc.maxSize());
cropTile.setSize(cc.getSizeAfterHarvest(cropTile));
cropTile.growthPoints = 0;
int lastHarvestedAt = 0;
int i;
for (i = 0; i < (30 * MINUTES) * (1 << EIG_BALANCE_IC2_ACCELERATOR_TIER);) {
i += TileEntityCrop.tickRate;
cropTile.tick();
if (!cc.canGrow(cropTile)) {
lastHarvestedAt = i;
ItemStack[] stacks = cropTile.harvest_automated(false);
for (ItemStack stack : stacks) {
expected.merge(stack, stack.stackSize, Integer::sum);
}
}
}
leftOverTicksFromRealRun += i - lastHarvestedAt;
}
return expected;
}
ItemStackMap getEIGDrops(GT_MetaTileEntity_ExtremeIndustrialGreenhouse EIG, ItemStack stack) {
ItemStackMap generated = new ItemStackMap<>();
int imax = (30 * MINUTES) / (5 * SECONDS);
double ticks_to_ignore_per_operation = Math
.ceil((double) leftOverTicksFromRealRun / (NUMBER_OF_CROPS_PER_TEST * imax));
for (int j = 0; j < NUMBER_OF_CROPS_PER_TEST; j++) {
GT_MetaTileEntity_ExtremeIndustrialGreenhouse.GreenHouseSlot slot = new GT_MetaTileEntity_ExtremeIndustrialGreenhouse.GreenHouseSlot(
EIG,
stack.copy(),
true,
false);
if (slot.isValid) {
for (int i = 0; i < imax; i++) {
int ticks_to_ignore = (int) Math.min(ticks_to_ignore_per_operation, leftOverTicksFromRealRun);
leftOverTicksFromRealRun -= ticks_to_ignore;
for (ItemStack ic2Drop : slot.getIC2Drops(
EIG,
(5 * SECONDS * (1 << EIG_BALANCE_IC2_ACCELERATOR_TIER)) - (double) ticks_to_ignore)) {
generated.merge(ic2Drop, ic2Drop.stackSize, Integer::sum);
}
}
}
}
return generated;
}
@Test
void EIGDrops() {
myWorld.setBlock(10, 80, 0, Blocks.farmland, 0, 0);
myWorld.setBlock(10, 81, 0, Block.getBlockFromItem(Ic2Items.crop.getItem()), 0, 0);
CropCard cc = Crops.instance.getCropCard("gregtech", "Indigo");
TileEntityCrop cropTile = (TileEntityCrop) myWorld.getTileEntity(10, 81, 0);
ItemStack ccStack = cropTile.generateSeeds(cc, (byte) 10, (byte) 10, (byte) 10, (byte) 1);
for (int i = 0; i < TileEntityCrop.tickRate; i++) {
cropTile.waterStorage = 200;
cropTile.updateEntity();
}
GT_Item_Machines itemMachines = (GT_Item_Machines) Item.getItemFromBlock(GregTech_API.sBlockMachines);
itemMachines.placeBlockAt(
new ItemStack(itemMachines, 1, EIG_CONTROLLER_METADATA),
null,
myWorld,
0,
81,
0,
2,
0,
0,
0,
EIG_CONTROLLER_METADATA);
IGregTechTileEntity te = (IGregTechTileEntity) myWorld.getTileEntity(0, 81, 0);
GT_MetaTileEntity_ExtremeIndustrialGreenhouse EIG = (GT_MetaTileEntity_ExtremeIndustrialGreenhouse) te
.getMetaTileEntity();
int[] abc = new int[] { 0, -2, 3 };
int[] xyz = new int[] { 0, 0, 0 };
EIG.getExtendedFacing()
.getWorldOffset(abc, xyz);
xyz[0] += te.getXCoord();
xyz[1] += te.getYCoord();
xyz[2] += te.getZCoord();
myWorld.setBlock(xyz[0], xyz[1] - 2, xyz[2], GregTech_API.sBlockCasings4, 1, 0);
myWorld.setBlock(xyz[0], xyz[1] - 1, xyz[2], Blocks.farmland, 0, 0);
ItemStack stackToTest = null;
for (int n = 0; n < 5; n++) {
int[] x = new int[NUMBER_OF_TESTS_TO_DO];
int[] y = new int[NUMBER_OF_TESTS_TO_DO];
// MinecraftServer.getServer()
// .addChatMessage(new ChatComponentText("[EIGTest results]"));
for (int i = 0; i < NUMBER_OF_TESTS_TO_DO; i++) {
leftOverTicksFromRealRun = 0;
ItemStackMap expected = getRealDrops(cropTile, cc, 10, 10, 10);
ItemStackMap generated = getEIGDrops(EIG, ccStack);
// MinecraftServer.getServer()
// .addChatMessage(new ChatComponentText("[TEST" + i + "]Real crop drops:"));
// for (Map.Entry entry : expected.entrySet()) {
// MinecraftServer.getServer()
// .addChatMessage(new ChatComponentText("- " + entry.getKey().getDisplayName() + " x" +
// entry.getValue()));
// }
// MinecraftServer.getServer()
// .addChatMessage(new ChatComponentText("[TEST" + i + "]EIG crop drops:"));
// for (Map.Entry entry : generated.entrySet()) {
// MinecraftServer.getServer()
// .addChatMessage(new ChatComponentText("- " + entry.getKey().getDisplayName() + " x" +
// entry.getValue()));
// }
// we are only comparing one item from drops
if (stackToTest == null) {
stackToTest = expected.entrySet()
.stream()
.max(Comparator.comparingInt(Map.Entry::getValue))
.get()
.getKey();
}
int expectedValue = expected.getOrDefault(stackToTest, 0);
int generatedValue = generated.getOrDefault(stackToTest, 0);
x[i] = expectedValue;
y[i] = generatedValue;
}
double real_average = Arrays.stream(x)
.average()
.getAsDouble();
double eig_average = Arrays.stream(y)
.average()
.getAsDouble();
double real_variance = 0d;
double a = 0d;
for (int i : x) {
a += (i - real_average) * (i - real_average);
}
a /= NUMBER_OF_TESTS_TO_DO;
real_variance = a;
double eig_variance = 0d;
a = 0d;
for (int i : y) {
a += (i - eig_average) * (i - eig_average);
}
a /= NUMBER_OF_TESTS_TO_DO;
eig_variance = a;
double u = (real_average - eig_average)
/ Math.sqrt((real_variance / NUMBER_OF_TESTS_TO_DO) + (eig_variance / NUMBER_OF_TESTS_TO_DO));
MinecraftServer.getServer()
.addChatMessage(
new ChatComponentText(
"real average = " + Math
.round(real_average) + " eig average = " + Math.round(eig_average) + " u = " + u));
double test_critical_value = 1.959964d;
boolean passed = Math.abs(u) < test_critical_value;
boolean instafail = Math.abs(u) > test_critical_value * 2;
if (passed) return;
assertFalse(instafail);
}
fail();
}
}