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
|
package gregtech.api.threads;
import gregtech.GT_Mod;
import gregtech.api.GregTech_API;
import gregtech.api.interfaces.tileentity.IMachineBlockUpdateable;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.world.ChunkPosition;
import net.minecraft.world.World;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
public class GT_Runnable_MachineBlockUpdate implements Runnable {
//used by runner thread
private final int x, y, z;
private final World world;
private final Set<ChunkPosition> visited = new HashSet<>(80);
//Threading
private static final ThreadFactory THREAD_FACTORY = r -> {
Thread thread = new Thread(r);
thread.setName("GT_MachineBlockUpdate");
return thread;
};
private static ExecutorService EXECUTOR_SERVICE;
//This class should never be initiated outside of this class!
private GT_Runnable_MachineBlockUpdate(World aWorld, int aX, int aY, int aZ) {
this.world = aWorld;
this.x = aX;
this.y = aY;
this.z = aZ;
}
public static boolean isEnabled() {
return isEnabled;
}
public static void setEnabled() {
GT_Runnable_MachineBlockUpdate.isEnabled = true;
}
public static void setDisabled() {
GT_Runnable_MachineBlockUpdate.isEnabled = true;
}
public static void setEnabled(boolean isEnabled) {
GT_Runnable_MachineBlockUpdate.isEnabled = isEnabled;
}
private static boolean isEnabled = true;
public static void setMachineUpdateValues(World aWorld, int aX, int aY, int aZ) {
if (isEnabled)
EXECUTOR_SERVICE.submit(new GT_Runnable_MachineBlockUpdate(aWorld, aX, aY, aZ));
}
public static void initExecutorService() {
EXECUTOR_SERVICE = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(), THREAD_FACTORY);
//Executors.newSingleThreadExecutor(THREAD_FACTORY);
//Executors.newCachedThreadPool(THREAD_FACTORY);
//Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors(),THREAD_FACTORY);
}
public static void shutdownExecutorService() {
try {
GT_Mod.GT_FML_LOGGER.info("Shutting down Machine block update executor service");
EXECUTOR_SERVICE.shutdown(); // Disable new tasks from being submitted
// Wait a while for existing tasks to terminate
if (!EXECUTOR_SERVICE.awaitTermination(60, TimeUnit.SECONDS)) {
EXECUTOR_SERVICE.shutdownNow(); // Cancel currently executing tasks
// Wait a while for tasks to respond to being cancelled
if (!EXECUTOR_SERVICE.awaitTermination(60, TimeUnit.SECONDS)) {
GT_Mod.GT_FML_LOGGER.error("Well this didn't terminated well... GT_Runnable_MachineBlockUpdate.shutdownExecutorService");
}
}
} catch (InterruptedException ie) {
GT_Mod.GT_FML_LOGGER.error("Well this interruption got interrupted...", ie);
// (Re-)Cancel if current thread also interrupted
EXECUTOR_SERVICE.shutdownNow();
// Preserve interrupt status
Thread.currentThread().interrupt();
}catch (Exception e){
GT_Mod.GT_FML_LOGGER.error("Well this didn't terminated well...",e);
// (Re-)Cancel in case
EXECUTOR_SERVICE.shutdownNow();
}finally {
GT_Mod.GT_FML_LOGGER.info("Leaving... GT_Runnable_MachineBlockUpdate.shutdownExecutorService");
}
}
private boolean shouldRecurse(TileEntity aTileEntity, int aX, int aY, int aZ) {
//no check on IGregTechTileEntity as it should call the underlying meta tile isMachineBlockUpdateRecursive
//if (aTileEntity instanceof IGregTechTileEntity) {
// return ((IGregTechTileEntity) aTileEntity).isMachineBlockUpdateRecursive();
//}
return (aTileEntity instanceof IMachineBlockUpdateable &&
((IMachineBlockUpdateable) aTileEntity).isMachineBlockUpdateRecursive()) ||
GregTech_API.isMachineBlock(world.getBlock(aX, aY, aZ), world.getBlockMetadata(aX, aY, aZ));
}
private void causeUpdate(TileEntity tileEntity) {
//no check for IGregTechTileEntity as it should call the underlying meta tile onMachineBlockUpdate
if (tileEntity instanceof IMachineBlockUpdateable) {
((IMachineBlockUpdateable) tileEntity).onMachineBlockUpdate();
}
}
private void stepToUpdateMachine(int aX, int aY, int aZ) {
if (!visited.add(new ChunkPosition(aX, aY, aZ)))
return;
TileEntity tTileEntity = world.getTileEntity(aX, aY, aZ);
causeUpdate(tTileEntity);
if (visited.size() < 5 || shouldRecurse(tTileEntity, aX, aY, aZ)) {
stepToUpdateMachine(aX + 1, aY, aZ);
stepToUpdateMachine(aX - 1, aY, aZ);
stepToUpdateMachine(aX, aY + 1, aZ);
stepToUpdateMachine(aX, aY - 1, aZ);
stepToUpdateMachine(aX, aY, aZ + 1);
stepToUpdateMachine(aX, aY, aZ - 1);
}
}
@Override
public void run() {
try {
stepToUpdateMachine(x, y, z);
} catch (Exception e) {
GT_Mod.GT_FML_LOGGER.error("Well this update was broken... " + new Coordinates(x, y, z, world), e);
}
}
public static class Coordinates {
public final int mX;
public final int mY;
public final int mZ;
public final World mWorld;
public Coordinates(int mX, int mY, int mZ, World mWorld) {
this.mX = mX;
this.mY = mY;
this.mZ = mZ;
this.mWorld = mWorld;
}
@Override
public String toString() {
return "Coordinates{" +
"mX=" + mX +
", mY=" + mY +
", mZ=" + mZ +
", mWorld=" + mWorld.getProviderName() + " @dimId " + mWorld.provider.dimensionId +
'}';
}
}
}
|