Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Wireless data refactor & fixes #3264

Merged
merged 7 commits into from
Sep 23, 2024
Merged
76 changes: 30 additions & 46 deletions src/main/java/gregtech/common/WirelessComputationPacket.java
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,6 @@

import java.util.UUID;

import com.gtnewhorizon.structurelib.util.Vec3Impl;

import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
import gregtech.common.misc.spaceprojects.SpaceProjectManager;
import tectech.mechanics.dataTransport.QuantumDataPacket;
Expand All @@ -15,68 +13,69 @@ public class WirelessComputationPacket {
public boolean wirelessEnabled = false;

// The main idea: 'Clearing' the computation net advances the index and sets the computation stored
// for this index to zero. Uploading is always done to the current index, but data can be downloaded from
// both indices
// for this index to zero. Uploading is always done to the current index, downloading is always done from the
// other index. This is essentially just a double buffered computation storage. The reason for this is that
// every upload needs to be done before every download happens.
private final long[] computationStored = new long[] { 0, 0 };
private long computationDownloaded = 0;
private int currentIndex = 0;
private long lastUpdateTick = -1;

public Vec3Impl controllerPosition = null;
private int uploadIndex() {
return currentIndex;
}

public long getTotalComputationStored() {
return computationStored[0] + computationStored[1];
private int downloadIndex() {
return (currentIndex + 1) % 2;
}

private long getAvailableComputationStored() {
return getTotalComputationStored() - computationDownloaded;
public long getAvailableComputationStored() {
return computationStored[downloadIndex()];
}

private QuantumDataPacket download(long dataIn, long aTick) {
if (!wirelessEnabled || controllerPosition == null) return new QuantumDataPacket(0L);
if (!wirelessEnabled) return new QuantumDataPacket(0L);

// If the net hasn't been updated yet this tick, make sure to do so
if (lastUpdateTick < aTick) {
this.update();
lastUpdateTick = aTick;
}

// If we have enough computation 'stored', download it
// Note that this means that if you do not have enough computation to go to all
// destinations, it won't be distributed equally. This is fine.
// This also means that if you don't have enough computation for a hatch, it will not receive any computation
// at all. This is also fine.
if (getAvailableComputationStored() >= dataIn) {
computationDownloaded += dataIn;
computationStored[downloadIndex()] -= dataIn;
return new QuantumDataPacket(dataIn);
} else return new QuantumDataPacket(0L);
}

private void update(IGregTechTileEntity entity, long aTick) {
private void update() {
// The reason we want this complex index cycling system is because hatches may upload and download computation
// in the same tick as the currently stored computation is cleared. To avoid interruptions, we want to
// try to double buffer these updates. This means that we keep two computation values around, and every update
// we only clear one of them. Only the most recent entry can be used for uploading computation, but we allow
// downloading computation from both the current and the previous index.
// we only clear one of them.

// Remove downloaded computation previous index (which is also the next index since there are only two),
// then remove the leftover from current index.
int nextIndex = (currentIndex + 1) % 2;
long availableInPrevious = computationStored[nextIndex];
// Clear stored computation for the next index, since we don't want to allow players to accumulate
// computation in their wireless network indefinitely. This would allow for cheesing research by passively
// banking computation and then setting the input hatch to a high value when the computation is needed.
computationStored[nextIndex] = 0;
if (computationDownloaded > availableInPrevious) {
long toDrainFromCurrent = computationDownloaded - availableInPrevious;
computationStored[currentIndex] -= toDrainFromCurrent;
}
// Reset our current tally of downloaded computation
computationDownloaded = 0;
// Now advance the current index to the next index
currentIndex = nextIndex;
computationStored[downloadIndex()] = 0;
currentIndex = (currentIndex + 1) % 2;
}

private void setWirelessEnabled(boolean wirelessEnabled) {
this.wirelessEnabled = wirelessEnabled;
}

private void upload(long dataOut, long aTick) {
// If the net hasn't been updated yet this tick, make sure to do so
if (lastUpdateTick < aTick) {
this.update();
lastUpdateTick = aTick;
}
// Store computation that is uploaded internally
computationStored[currentIndex] += dataOut;
computationStored[uploadIndex()] += dataOut;
}

public static QuantumDataPacket downloadData(UUID userId, long dataIn, long aTick) {
Expand All @@ -87,26 +86,11 @@ public static void uploadData(UUID userId, long dataOut, long aTick) {
getPacketByUserId(userId).upload(dataOut, aTick);
}

public static void updatePacket(IGregTechTileEntity entity, long aTick) {
getPacketByUserId(entity.getOwnerUuid()).update(entity, aTick);
}

public static boolean enableWirelessNetWork(IGregTechTileEntity entity) {
var packet = getPacketByUserId(entity.getOwnerUuid());
Vec3Impl pos = new Vec3Impl(entity.getXCoord(), entity.getYCoord(), entity.getZCoord());
if (packet.wirelessEnabled && packet.controllerPosition != null
&& pos.compareTo(packet.controllerPosition) != 0) return false;
public static void enableWirelessNetWork(IGregTechTileEntity entity) {
getPacketByUserId(entity.getOwnerUuid()).setWirelessEnabled(true);
if (packet.controllerPosition == null) {
packet.controllerPosition = new Vec3Impl(entity.getXCoord(), entity.getYCoord(), entity.getZCoord());
}
return true;
}

public static void disableWirelessNetWork(IGregTechTileEntity entity) {
var packet = getPacketByUserId(entity.getOwnerUuid());
Vec3Impl pos = new Vec3Impl(entity.getXCoord(), entity.getYCoord(), entity.getZCoord());
if (packet.controllerPosition != null && packet.controllerPosition.compareTo(pos) != 0) return;
getPacketByUserId(entity.getOwnerUuid()).setWirelessEnabled(false);
}

Expand Down
25 changes: 18 additions & 7 deletions src/main/java/gregtech/common/WirelessDataStore.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,28 @@

public class WirelessDataStore {

private final ArrayList<ItemStack> dataSticks = new ArrayList<>();
public static final long UPLOAD_TICK = 200;
public static final long DOWNLOAD_TICK = UPLOAD_TICK + 1;

public void clearData() {
dataSticks.clear();
}
private long lastUploadTick = -1;
private long lastDownloadTick = -1;
private final ArrayList<ItemStack> uploadedSticks = new ArrayList<>();
private final ArrayList<ItemStack> dataSticks = new ArrayList<>();

public void uploadData(List<ItemStack> sticks) {
dataSticks.addAll(sticks);
public void uploadData(List<ItemStack> sticks, long tick) {
if (lastUploadTick < tick) {
uploadedSticks.clear();
lastUploadTick = tick;
}
uploadedSticks.addAll(sticks);
}

public List<ItemStack> downloadData() {
public List<ItemStack> downloadData(long tick) {
if (lastDownloadTick < tick) {
dataSticks.clear();
dataSticks.addAll(uploadedSticks);
lastDownloadTick = tick;
}
return dataSticks;
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,10 @@ public boolean canConnectData(ForgeDirection side) {
return isOutputFacing(side);
}

public void providePacket(QuantumDataPacket packet) {
this.q = packet;
}

@Override
public void moveAround(IGregTechTileEntity aBaseMetaTileEntity) {
IConnectsToDataPipe current = this, source = this, next;
Expand Down
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
package tectech.thing.metaTileEntity.hatch;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraftforge.common.util.ForgeDirection;

import gregtech.api.interfaces.ITexture;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
import gregtech.api.metatileentity.MetaTileEntity;
import gregtech.common.WirelessComputationPacket;
import tectech.mechanics.dataTransport.QuantumDataPacket;

public class MTEHatchWirelessComputationOutput extends MTEHatchDataOutput {

private int clearDelay = 0;

public MTEHatchWirelessComputationOutput(int aID, String aName, String aNameRegional, int aTier) {
super(aID, aName, aNameRegional, aTier);

Expand Down Expand Up @@ -39,12 +43,36 @@ public boolean canConnectData(ForgeDirection side) {
return false;
}

@Override
public void loadNBTData(NBTTagCompound aNBT) {
super.loadNBTData(aNBT);
if (aNBT.hasKey("clearDelay")) {
this.clearDelay = aNBT.getInteger("clearDelay");
}
}

@Override
public void saveNBTData(NBTTagCompound aNBT) {
super.saveNBTData(aNBT);
aNBT.setInteger("clearDelay", this.clearDelay);
}

@Override
public void providePacket(QuantumDataPacket packet) {
super.providePacket(packet);
// Keep providing to wireless net for 21 ticks, because after this time a new packet from the computer should
// have arrived
this.clearDelay = 21;
}

@Override
public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
super.onPreTick(aBaseMetaTileEntity, aTick);
if (aBaseMetaTileEntity.isServerSide() && q != null) {
WirelessComputationPacket.uploadData(aBaseMetaTileEntity.getOwnerUuid(), q.getContent(), aTick);
q = null;
if (clearDelay-- == 0) {
q = null;
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@

import org.apache.commons.lang3.reflect.FieldUtils;

import com.google.common.collect.ImmutableList;

import gregtech.api.enums.Dyes;
import gregtech.api.interfaces.ITexture;
import gregtech.api.interfaces.tileentity.IGregTechTileEntity;
Expand All @@ -32,6 +34,8 @@ public class MTEHatchWirelessDataItemsInput extends MTEHatchDataAccess {

private String clientLocale = "en_US";

private List<ItemStack> dataItems = null;

public MTEHatchWirelessDataItemsInput(int aID, String aName, String aNameRegional, int aTier) {
super(aID, aName, aNameRegional, aTier);
TTUtility.setTier(aTier, this);
Expand Down Expand Up @@ -118,14 +122,25 @@ public String[] getDescription() {

@Override
public List<ItemStack> getInventoryItems(Predicate<ItemStack> filter) {
WirelessDataStore wirelessData = WirelessDataStore
.getWirelessDataSticks(getBaseMetaTileEntity().getOwnerUuid());
return wirelessData.downloadData()
.stream()
if (this.dataItems == null) return ImmutableList.of();
return this.dataItems.stream()
.filter(stack -> stack != null && filter.test(stack))
.collect(Collectors.toList());
}

@Override
public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
if (aBaseMetaTileEntity.isServerSide()) {
// Upload data packet and mark it as uploaded, so it will not be uploaded again
// until the data bank resets the wireless network
if (aTick % WirelessDataStore.DOWNLOAD_TICK == 0) {
WirelessDataStore wirelessDataStore = WirelessDataStore
.getWirelessDataSticks(getBaseMetaTileEntity().getOwnerUuid());
this.dataItems = wirelessDataStore.downloadData(aTick);
}
}
}

@Override
public boolean isGivingInformation() {
return true;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,6 @@ public class MTEHatchWirelessDataItemsOutput extends MTEHatch {

public InventoryDataPacket dataPacket = null;

public boolean uploadedSinceReset = false;

public MTEHatchWirelessDataItemsOutput(int aID, String aName, String aNameRegional, int aTier) {
super(
aID,
Expand Down Expand Up @@ -94,7 +92,6 @@ public void saveNBTData(NBTTagCompound aNBT) {
if (dataPacket != null) {
aNBT.setTag("eDATA", dataPacket.toNbt());
}
aNBT.setBoolean("uploadedSinceReset", uploadedSinceReset);
}

@Override
Expand All @@ -103,21 +100,17 @@ public void loadNBTData(NBTTagCompound aNBT) {
if (aNBT.hasKey("eDATA")) {
dataPacket = new InventoryDataPacket(aNBT.getCompoundTag("eDATA"));
}
if (aNBT.hasKey("uploadedSinceReset")) {
uploadedSinceReset = aNBT.getBoolean("uploadedSinceReset");
}
}

@Override
public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
if (aBaseMetaTileEntity.isServerSide()) {
// Upload data packet and mark it as uploaded, so it will not be uploaded again
// until the data bank resets the wireless network
if (dataPacket != null && !uploadedSinceReset) {
if (dataPacket != null && (aTick % WirelessDataStore.UPLOAD_TICK) == 0) {
WirelessDataStore wirelessDataStore = WirelessDataStore
.getWirelessDataSticks(getBaseMetaTileEntity().getOwnerUuid());
wirelessDataStore.uploadData(Arrays.asList(dataPacket.getContent()));
uploadedSinceReset = true;
wirelessDataStore.uploadData(Arrays.asList(dataPacket.getContent()), aTick);
}
}
}
Expand Down
18 changes: 0 additions & 18 deletions src/main/java/tectech/thing/metaTileEntity/multi/MTEDataBank.java
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@
import gregtech.api.util.IGTHatchAdder;
import gregtech.api.util.MultiblockTooltipBuilder;
import gregtech.common.WirelessComputationPacket;
import gregtech.common.WirelessDataStore;
import tectech.Reference;
import tectech.mechanics.dataTransport.InventoryDataPacket;
import tectech.recipe.TTRecipeAdder;
Expand Down Expand Up @@ -248,23 +247,6 @@ public final boolean addDataBankHatchToMachineList(IGregTechTileEntity aTileEnti
return false;
}

@Override
public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
super.onPreTick(aBaseMetaTileEntity, aTick);
// Every 200 ticks, clear wireless data store so hatches need to provide their data again in
// their onPostTick() call. This also happens every 200 ticks
if (mMachine && aBaseMetaTileEntity.isActive() && wirelessModeEnabled && aTick % 200 == 0) {
WirelessDataStore wirelessStore = WirelessDataStore
.getWirelessDataSticks(aBaseMetaTileEntity.getOwnerUuid());
wirelessStore.clearData();

// After reset, clear uploadedSinceReset of all connected hatches
for (MTEHatchWirelessDataItemsOutput hatch : eWirelessStacksDataOutputs) {
hatch.uploadedSinceReset = false;
}
}
}

@Override
public void onScrewdriverRightClick(ForgeDirection side, EntityPlayer aPlayer, float aX, float aY, float aZ) {
if (getBaseMetaTileEntity().isServerSide()) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -234,14 +234,6 @@ public void loadNBTData(NBTTagCompound aNBT) {
}
}

@Override
public void onPreTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
super.onPreTick(aBaseMetaTileEntity, aTick);
if (aBaseMetaTileEntity.isServerSide() && wirelessModeEnabled && aTick % 20 == 0) {
WirelessComputationPacket.updatePacket(aBaseMetaTileEntity, aTick);
}
}

@Override
public void onPostTick(IGregTechTileEntity aBaseMetaTileEntity, long aTick) {
super.onPostTick(aBaseMetaTileEntity, aTick);
Expand Down Expand Up @@ -346,7 +338,7 @@ public void outputAfterRecipe_EM() {
}

for (MTEHatchDataOutput o : eOutputData) {
o.q = pack;
o.providePacket(pack);
}
}
}
Expand Down Expand Up @@ -570,7 +562,7 @@ public String[] getInfoData() {
data.add("Wireless mode: " + EnumChatFormatting.GREEN + "enabled");
data.add(
"Total wireless computation available: " + EnumChatFormatting.YELLOW
+ wirelessComputationPacket.getTotalComputationStored());
+ wirelessComputationPacket.getAvailableComputationStored());
} else {
data.add("Wireless mode: " + EnumChatFormatting.RED + "disabled");
}
Expand Down