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
|
package gregtech.api.objects.blockupdate;
import java.util.HashMap;
import net.minecraft.client.Minecraft;
import net.minecraft.client.entity.EntityClientPlayerMP;
import net.minecraft.world.ChunkCoordIntPair;
import net.minecraft.world.World;
import net.minecraft.world.chunk.Chunk;
import appeng.api.util.WorldCoord;
import cpw.mods.fml.common.FMLCommonHandler;
import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import cpw.mods.fml.common.gameevent.TickEvent.ClientTickEvent;
import cpw.mods.fml.common.gameevent.TickEvent.Phase;
import cpw.mods.fml.relauncher.Side;
import cpw.mods.fml.relauncher.SideOnly;
import gregtech.api.enums.TickTime;
// this is a middleware for block updates
// Greg's BaseMetaTileEntity uses World::markBlockForUpdate() to update the texture of a machine
// World::markBlockForUpdate() triggers block updates of all blocks within the same chunk
// this class makes sure chunk updates are perfmormed only once even if several blocks requested update
// (valid obly for requests made using BlockUpdateHandler::enqueueBlockUpdate)
// and introduces a per chunk cooldown to slow the things a bit
// cause too frequent updates are not necessary for visual appearance of a block
@SideOnly(Side.CLIENT)
public class BlockUpdateHandler {
public static final int MIN_UPDATE_COOLDOWN = TickTime.SECOND / 2;
public static final int MAX_UPDATE_COOLDOWN = TickTime.SECOND;
public final static BlockUpdateHandler Instance = new BlockUpdateHandler();
private BlockUpdateHandler() {
blocksToUpdate = new HashMap<ChunkCoordIntPair, WorldCoord>();
cooldowns = new HashMap<ChunkCoordIntPair, RandomCooldown>();
FMLCommonHandler.instance()
.bus()
.register(this);
}
public void enqueueBlockUpdate(World world, WorldCoord pos) {
var player = getPlayer();
if (world != player.worldObj) return;
ResetDataIfPlayerWorldChanged(player);
blocksToUpdate.put(getBlockChunkCoords(world, pos), pos);
}
@SubscribeEvent
public void OnClientTickEvent(ClientTickEvent event) {
if (event.phase != Phase.START) return;
ResetDataIfPlayerWorldChanged(getPlayer());
var it = blocksToUpdate.entrySet()
.iterator();
while (it.hasNext()) {
var entry = it.next();
ChunkCoordIntPair chunkCoords = entry.getKey();
WorldCoord blockCoords = entry.getValue();
RandomCooldown cooldown = cooldowns.get(chunkCoords);
if (cooldown == null) {
cooldown = new RandomCooldown(MIN_UPDATE_COOLDOWN, MAX_UPDATE_COOLDOWN);
cooldowns.put(chunkCoords, cooldown);
}
if (!cooldown.hasPassed(internalTickCounter)) continue;
currWorld.markBlockForUpdate(blockCoords.x, blockCoords.y, blockCoords.z);
cooldown.set(internalTickCounter);
it.remove();
}
++internalTickCounter;
}
private EntityClientPlayerMP getPlayer() {
return Minecraft.getMinecraft().thePlayer;
}
private void ResetDataIfPlayerWorldChanged(EntityClientPlayerMP player) {
if (player == null) return;
World playerWorld = player.worldObj;
if (currWorld != playerWorld) {
blocksToUpdate.clear();
cooldowns.clear();
currWorld = playerWorld;
}
}
private ChunkCoordIntPair getBlockChunkCoords(World world, WorldCoord pos) {
Chunk chunk = world.getChunkFromBlockCoords(pos.x, pos.z);
return chunk.getChunkCoordIntPair();
}
private HashMap<ChunkCoordIntPair, WorldCoord> blocksToUpdate;
private HashMap<ChunkCoordIntPair, RandomCooldown> cooldowns;
private World currWorld = null;
private long internalTickCounter = 0;
}
|