diff options
Diffstat (limited to 'src/main/java/gregtech/api/objects/blockupdate')
3 files changed, 175 insertions, 0 deletions
diff --git a/src/main/java/gregtech/api/objects/blockupdate/BlockUpdateHandler.java b/src/main/java/gregtech/api/objects/blockupdate/BlockUpdateHandler.java new file mode 100644 index 0000000000..e8f084ea34 --- /dev/null +++ b/src/main/java/gregtech/api/objects/blockupdate/BlockUpdateHandler.java @@ -0,0 +1,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; +} diff --git a/src/main/java/gregtech/api/objects/blockupdate/Cooldown.java b/src/main/java/gregtech/api/objects/blockupdate/Cooldown.java new file mode 100644 index 0000000000..e00fc1c770 --- /dev/null +++ b/src/main/java/gregtech/api/objects/blockupdate/Cooldown.java @@ -0,0 +1,27 @@ +package gregtech.api.objects.blockupdate; + +public class Cooldown { + + public Cooldown(int aLengthInTicks) { + + if (aLengthInTicks <= 0) throw new IllegalArgumentException("length should be a positive non-zero number"); + + this.lengthInTicks = aLengthInTicks; + this.lastTimeStarted = 0; + } + + public void set(long currTickTime) { + lastTimeStarted = currTickTime; + } + + public boolean hasPassed(long currTickTime) { + return currTickTime - lastTimeStarted >= lengthInTicks; + } + + public long getLastTimeStarted() { + return lastTimeStarted; + } + + private long lastTimeStarted; + protected int lengthInTicks; +} diff --git a/src/main/java/gregtech/api/objects/blockupdate/RandomCooldown.java b/src/main/java/gregtech/api/objects/blockupdate/RandomCooldown.java new file mode 100644 index 0000000000..d275c29744 --- /dev/null +++ b/src/main/java/gregtech/api/objects/blockupdate/RandomCooldown.java @@ -0,0 +1,31 @@ +package gregtech.api.objects.blockupdate; + +import static gregtech.api.objects.XSTR.XSTR_INSTANCE; + +public class RandomCooldown extends Cooldown { + + public RandomCooldown(int aMinLengthInTicks, int aMaxLengthInTicks) { + + super(aMinLengthInTicks); + + if (aMinLengthInTicks <= 0) + throw new IllegalArgumentException("min length should be a positive non-zero number"); + if (aMaxLengthInTicks <= 0) + throw new IllegalArgumentException("max length should be a positive non-zero number"); + if (aMinLengthInTicks > aMaxLengthInTicks) + throw new IllegalArgumentException("min length should be less or equal to max length"); + + this.minLengthInTicks = aMinLengthInTicks; + this.maxLengthInTicks = aMaxLengthInTicks; + } + + @Override + public void set(long currTickTime) { + + super.set(currTickTime); + lengthInTicks = minLengthInTicks + XSTR_INSTANCE.nextInt(maxLengthInTicks - minLengthInTicks + 1); + } + + private int minLengthInTicks; + private int maxLengthInTicks; +} |