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
|
package gregtech.common;
import static gregtech.common.misc.GlobalVariableStorage.GlobalWirelessComputation;
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;
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
private final long[] computationStored = new long[] { 0, 0 };
private long computationDownloaded = 0;
private int currentIndex = 0;
public Vec3Impl controllerPosition = null;
public long getTotalComputationStored() {
return computationStored[0] + computationStored[1];
}
private long getAvailableComputationStored() {
return getTotalComputationStored() - computationDownloaded;
}
private QuantumDataPacket download(long dataIn, long aTick) {
if (!wirelessEnabled || controllerPosition == null) return new QuantumDataPacket(0L);
// 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;
return new QuantumDataPacket(dataIn);
} else return new QuantumDataPacket(0L);
}
private void update(IGregTechTileEntity entity, long aTick) {
// 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.
// 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;
}
private void setWirelessEnabled(boolean wirelessEnabled) {
this.wirelessEnabled = wirelessEnabled;
}
private void upload(long dataOut, long aTick) {
// Store computation that is uploaded internally
computationStored[currentIndex] += dataOut;
}
public static QuantumDataPacket downloadData(UUID userId, long dataIn, long aTick) {
return getPacketByUserId(userId).download(dataIn, aTick);
}
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;
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);
}
public static WirelessComputationPacket getPacketByUserId(UUID userId) {
UUID team = SpaceProjectManager.getLeader(userId);
if (GlobalWirelessComputation.get(team) == null) {
GlobalWirelessComputation.put(team, new WirelessComputationPacket());
}
return GlobalWirelessComputation.get(team);
}
}
|