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
|
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;
}
/**
* If the thread is idle, sets new values and remove the idle flag, otherwise, queue the cooridinates.
*/
public static void setMachineUpdateValues(World aWorld, int aX, int aY, int aZ) {
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 {
EXECUTOR_SERVICE.awaitTermination(60, TimeUnit.SECONDS);
} catch (InterruptedException e) {
GT_Mod.GT_FML_LOGGER.error("Well this interruption got interrupted...", e);
}
//terminates executor permanently
EXECUTOR_SERVICE.shutdownNow();
}
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 +
'}';
}
}
}
|