aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/gregtech/api/objects/blockupdate/BlockUpdateHandler.java
blob: e8f084ea343370e931270f8675851dfd5d320138 (plain)
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;
}