aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/common/UndergroundOil.java
diff options
context:
space:
mode:
authorNotAPenguin <michiel.vandeginste@gmail.com>2024-09-02 23:17:17 +0200
committerGitHub <noreply@github.com>2024-09-02 23:17:17 +0200
commit1b820de08a05070909a267e17f033fcf58ac8710 (patch)
tree02831a025986a06b20f87e5bcc69d1e0c639a342 /src/main/java/gregtech/common/UndergroundOil.java
parentafd3fd92b6a6ab9ab0d0dc3214e6bc8ff7a86c9b (diff)
downloadGT5-Unofficial-1b820de08a05070909a267e17f033fcf58ac8710.tar.gz
GT5-Unofficial-1b820de08a05070909a267e17f033fcf58ac8710.tar.bz2
GT5-Unofficial-1b820de08a05070909a267e17f033fcf58ac8710.zip
The Great Renaming (#3014)
* move kekztech to a single root dir * move detrav to a single root dir * move gtnh-lanthanides to a single root dir * move tectech and delete some gross reflection in gt++ * remove more reflection inside gt5u * delete more reflection in gt++ * fix imports * move bartworks and bwcrossmod * fix proxies * move galactigreg and ggfab * move gtneioreplugin * try to fix gt++ bee loader * apply the rename rules to BW * apply rename rules to bwcrossmod * apply rename rules to detrav scanner mod * apply rename rules to galacticgreg * apply rename rules to ggfab * apply rename rules to goodgenerator * apply rename rules to gtnh-lanthanides * apply rename rules to gt++ * apply rename rules to kekztech * apply rename rules to kubatech * apply rename rules to tectech * apply rename rules to gt apply the rename rules to gt * fix tt import * fix mui hopefully * fix coremod except intergalactic * rename assline recipe class * fix a class name i stumbled on * rename StructureUtility to GTStructureUtility to prevent conflict with structurelib * temporary rename of GTTooltipDataCache to old name * fix gt client/server proxy names
Diffstat (limited to 'src/main/java/gregtech/common/UndergroundOil.java')
-rw-r--r--src/main/java/gregtech/common/UndergroundOil.java339
1 files changed, 339 insertions, 0 deletions
diff --git a/src/main/java/gregtech/common/UndergroundOil.java b/src/main/java/gregtech/common/UndergroundOil.java
new file mode 100644
index 0000000000..e5da237288
--- /dev/null
+++ b/src/main/java/gregtech/common/UndergroundOil.java
@@ -0,0 +1,339 @@
+package gregtech.common;
+
+import static gregtech.api.objects.XSTR.XSTR_INSTANCE;
+
+import java.io.DataInput;
+import java.io.DataOutput;
+import java.io.IOException;
+import java.util.Objects;
+import java.util.WeakHashMap;
+
+import javax.annotation.Nullable;
+import javax.annotation.ParametersAreNonnullByDefault;
+
+import net.minecraft.world.World;
+import net.minecraft.world.chunk.Chunk;
+import net.minecraftforge.event.world.ChunkDataEvent;
+import net.minecraftforge.fluids.Fluid;
+import net.minecraftforge.fluids.FluidStack;
+
+import org.apache.commons.lang3.tuple.Pair;
+
+import gregtech.GTMod;
+import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
+import gregtech.api.objects.GTUODimension;
+import gregtech.api.objects.GTUOFluid;
+import gregtech.api.objects.XSTR;
+import gregtech.api.util.GTChunkAssociatedData;
+
+/**
+ * Created by Tec on 29.04.2017.
+ */
+public class UndergroundOil {
+
+ public static final short DIVIDER = 5000;
+ private static final GT_UndergroundOilStore STORAGE = new GT_UndergroundOilStore();
+ private static final ChunkData NIL_FLUID_STACK = new ChunkData(-1, null, null, false);
+
+ /**
+ * Effectively just call {@code undergroundOil(te, -1)} for you
+ *
+ * @see #undergroundOil(World, int, int, float)
+ */
+ public static FluidStack undergroundOilReadInformation(IGregTechTileEntity te) {
+ return undergroundOil(
+ te.getWorld()
+ .getChunkFromBlockCoords(te.getXCoord(), te.getZCoord()),
+ -1);
+ }
+
+ /**
+ * Effectively just call {@code undergroundOil(chunk, -1)} for you
+ *
+ * @see #undergroundOil(World, int, int, float)
+ */
+ public static FluidStack undergroundOilReadInformation(Chunk chunk) {
+ return undergroundOil(chunk, -1);
+ }
+
+ /** @see #undergroundOil(World, int, int, float) */
+ public static FluidStack undergroundOil(IGregTechTileEntity te, float readOrDrainCoefficient) {
+ return undergroundOil(
+ te.getWorld()
+ .getChunkFromBlockCoords(te.getXCoord(), te.getZCoord()),
+ readOrDrainCoefficient);
+ }
+
+ // Returns whole content for information purposes -> when drainSpeedCoefficient < 0
+ // Else returns extracted fluidStack if amount > 0, or null otherwise
+ /** @see #undergroundOil(World, int, int, float) */
+ public static FluidStack undergroundOil(Chunk chunk, float readOrDrainCoefficient) {
+ return undergroundOil(chunk.worldObj, chunk.xPosition, chunk.zPosition, readOrDrainCoefficient);
+ }
+
+ /**
+ * Pump fluid or read info.
+ *
+ * @param w a remote World. For a WorldClient it will always tell you null
+ * @param chunkX chunk coordinate X, i.e. blockX >> 4
+ * @param chunkZ chunk coordinate Z, i.e. blockZ >> 4
+ * @param readOrDrainCoefficient how fast to pump. The higher the faster. use negative to read expected current
+ * output
+ * @return null if nothing here, or depleted already, or a client side world
+ */
+ public static FluidStack undergroundOil(World w, int chunkX, int chunkZ, float readOrDrainCoefficient) {
+ if (w.isRemote) return null; // troublemakers go away
+ ChunkData chunkData = STORAGE.get(w, chunkX, chunkZ);
+ if (chunkData.getVein() == null || chunkData.getFluid() == null) // nothing here...
+ return null;
+ // do stuff on it if needed
+ FluidStack fluidInChunk = new FluidStack(chunkData.getFluid(), 0);
+ if (readOrDrainCoefficient >= 0) {
+ int fluidExtracted = (int) Math.floor(chunkData.getAmount() * (double) readOrDrainCoefficient / DIVIDER);
+ double averageDecrease = chunkData.getVein().DecreasePerOperationAmount * (double) readOrDrainCoefficient;
+ int decrease = (int) Math.ceil(averageDecrease);
+ if (fluidExtracted <= 0 || chunkData.amount <= decrease) { // decrease - here it is max value of extraction
+ // for easy check
+ chunkData.setAmount(0);
+ } else {
+ fluidInChunk.amount = fluidExtracted; // give appropriate amount
+ if (XSTR_INSTANCE.nextFloat() < (decrease - averageDecrease)) decrease--; // use XSTR_INSTANCE to
+ // "subtract double from int"
+ // ex.
+ // averageDecrease=3.9
+ // decrease= ceil from 3.9 = 4
+ // decrease-averageDecrease=0.1 -> chance to subtract 1
+ // if XSTR_INSTANCE is < chance then subtract 1
+ chunkData.changeAmount(-decrease); // diminish amount, "randomly" adjusted to double value
+ // (averageDecrease)
+ }
+ } else { // just get info
+ if (chunkData.amount <= DIVIDER) {
+ chunkData.setAmount(0);
+ } else {
+ // get the expected current output
+ fluidInChunk.amount = (int) Math
+ .floor(chunkData.getAmount() * (double) -readOrDrainCoefficient / DIVIDER);
+ }
+ }
+ return fluidInChunk;
+ }
+
+ /**
+ * Get the deposit as if it is never exploited
+ *
+ * @return UO fluid kind and amount, or null if nothing here.
+ */
+ public static Pair<GTUOFluid, Integer> getPristineAmount(World world, int chunkX, int chunkZ) {
+ int dimensionId = world.provider.dimensionId;
+ GTUODimension dimension = GTMod.gregtechproxy.mUndergroundOil.GetDimension(dimensionId);
+ if (dimension == null) return null;
+ // prepare RNG
+ final XSTR tVeinRNG = new XSTR(world.getSeed() + dimensionId * 2L + (chunkX >> 3) + 8267L * (chunkZ >> 3));
+ GTUOFluid uoFluid = dimension.getRandomFluid(tVeinRNG);
+ // nothing here :(
+ if (uoFluid == null || uoFluid.getFluid() == null) return null;
+ // offset each chunk's fluid amount by +-25%
+ // discard random values not for current chunk
+ int veinAverage = uoFluid.getRandomAmount(tVeinRNG);
+ for (int i = 0; i < (((chunkX & 0x7) << 3) | chunkZ & 0x7); i++) {
+ tVeinRNG.next(24);
+ }
+ int amount = (int) ((float) veinAverage * (0.75f + (tVeinRNG.nextFloat() / 2f)));
+ return Pair.of(uoFluid, amount);
+ }
+
+ static void migrate(ChunkDataEvent.Load e) {
+ if (e.getData()
+ .hasKey("GTOIL")
+ && e.getData()
+ .hasKey("GTOILFLUID")) {
+ ChunkData chunkData = STORAGE.get(e.getChunk());
+ Fluid fluid = chunkData.getFluid();
+ if (fluid != null && fluid.getID() == e.getData()
+ .getInteger("GTOILFLUID")) chunkData.setAmount(
+ Math.min(
+ chunkData.getAmount(),
+ e.getData()
+ .getInteger("GTOIL")));
+ }
+ }
+
+ /**
+ * Revamped UO store.
+ * <p>
+ * Primary functionality:
+ *
+ * <ul>
+ * <li>Decouple data storage with chunk, making it possible to pump oil from unloaded chunks</li>
+ * <li>Regen detection. If fluid generation config is changed, chunk fluid will be regenerated.</li>
+ * </ul>
+ *
+ * <h2>Serialized form</h2>
+ * <p>
+ * Since the exact file layout is controlled by the super class, here we only concern how each chunk's data is
+ * written.
+ * <h3>Form A: Empty Chunk</h3>
+ * <ol>
+ * <li>4 bytes of 0</li>
+ * </ol>
+ *
+ * <h3>Form B: Normal Chunk</h3>
+ * <ol>
+ * <li>4 bytes unsigned integer. Vein Hash.</li>
+ * <li>UTF string. Vein Key.</li>
+ * <li>4 bytes signed integer. Fluid amount.</li>
+ * </ol>
+ *
+ * @author glease
+ */
+ @ParametersAreNonnullByDefault
+ private static class GT_UndergroundOilStore extends GTChunkAssociatedData<ChunkData> {
+
+ private static final WeakHashMap<GTUOFluid, Integer> hashes = new WeakHashMap<>();
+
+ private GT_UndergroundOilStore() {
+ super("UO", UndergroundOil.ChunkData.class, 64, (byte) 0, false);
+ }
+
+ @Override
+ protected void writeElement(DataOutput output, ChunkData element, World world, int chunkX, int chunkZ)
+ throws IOException {
+ /* see class javadoc for explanation */
+ output.writeInt(element.getVeinHash());
+ if (element.getVeinKey() == null) return;
+ output.writeUTF(element.getVeinKey());
+ if (element.getAmount() > 0 && element.getFluid() != null) {
+ output.writeInt(element.getAmount());
+ } else {
+ output.writeInt(-1);
+ }
+ }
+
+ @Override
+ protected UndergroundOil.ChunkData readElement(DataInput input, int version, World world, int chunkX,
+ int chunkZ) throws IOException {
+ /* see class javadoc for explanation */
+ if (version != 0) throw new IOException("Region file corrupted");
+ UndergroundOil.ChunkData pristine = createElement(world, chunkX, chunkZ);
+ int hash = input.readInt();
+ String veinKey = hash != 0 ? input.readUTF() : null;
+ int amount = hash != 0 ? input.readInt() : -1;
+ if (hash != pristine.veinHash || !Objects.equals(veinKey, pristine.getVeinKey())) {
+ // vein config changed. use regen-ed data.
+ return pristine;
+ }
+ if (hash == 0) return NIL_FLUID_STACK;
+ return new UndergroundOil.ChunkData(
+ amount,
+ GTMod.gregtechproxy.mUndergroundOil.GetDimension(world.provider.dimensionId)
+ .getUOFluid(veinKey),
+ veinKey);
+ }
+
+ @Override
+ protected UndergroundOil.ChunkData createElement(World world, int chunkX, int chunkZ) {
+ Pair<GTUOFluid, Integer> pristine = getPristineAmount(world, chunkX, chunkZ);
+ if (pristine == null) return NIL_FLUID_STACK;
+ int dimensionId = world.provider.dimensionId;
+ GTUODimension dimension = GTMod.gregtechproxy.mUndergroundOil.GetDimension(dimensionId);
+ return new UndergroundOil.ChunkData(
+ pristine.getRight(),
+ pristine.getLeft(),
+ dimension.getUOFluidKey(pristine.getLeft()),
+ false);
+ }
+
+ private static int hash(@Nullable GTUOFluid fluid) {
+ if (fluid == null) return 0;
+ int result = fluid.Registry.hashCode();
+ result = 31 * result + fluid.MaxAmount;
+ result = 31 * result + fluid.MinAmount;
+ result = 31 * result + fluid.Chance;
+ result = 31 * result + fluid.DecreasePerOperationAmount;
+ return result == 0 ? 1 : result;
+ }
+ }
+
+ /**
+ * Represent the amount of fluid in a given chunk.
+ */
+ private static final class ChunkData implements GTChunkAssociatedData.IData {
+
+ private final Fluid fluid;
+
+ @Nullable
+ private final GTUOFluid vein;
+
+ private final String veinKey;
+ private final int veinHash;
+ private int amount;
+ private boolean dirty;
+
+ private ChunkData(int amount, GTUOFluid veinKey, String veinID) {
+ this(amount, veinKey, veinID, true);
+ }
+
+ private ChunkData(int amount, @Nullable GTUOFluid vein, @Nullable String veinKey, boolean dirty) {
+ this.amount = amount;
+ this.vein = vein;
+ this.dirty = dirty;
+ if (vein == null) {
+ fluid = null;
+ this.veinKey = null;
+ veinHash = 0;
+ } else {
+ fluid = vein.getFluid();
+ this.veinKey = veinKey;
+ veinHash = GT_UndergroundOilStore.hashes.computeIfAbsent(vein, GT_UndergroundOilStore::hash);
+ }
+ }
+
+ /**
+ * The current fluid type. {@code null} if vein is generated to be empty.
+ */
+ @Nullable
+ public Fluid getFluid() {
+ return fluid;
+ }
+
+ /**
+ * Current fluid amount. Might be 0 if empty. Cannot be negative
+ */
+ public int getAmount() {
+ return amount;
+ }
+
+ public void setAmount(int amount) {
+ if (this.amount != amount) dirty = true;
+ this.amount = Math.max(0, amount);
+ }
+
+ public void changeAmount(int delta) {
+ if (delta != 0) dirty = true;
+ this.amount = Math.max(amount + delta, 0);
+ }
+
+ @Nullable
+ public GTUOFluid getVein() {
+ return vein;
+ }
+
+ /**
+ * The vein ID. Might be null if generated to be empty.
+ */
+ @Nullable
+ public String getVeinKey() {
+ return veinKey;
+ }
+
+ public int getVeinHash() {
+ return veinHash;
+ }
+
+ @Override
+ public boolean isSameAsDefault() {
+ return !dirty;
+ }
+ }
+}