diff options
author | iamblackornot <nkzshinnik@gmail.com> | 2023-10-21 13:16:22 +0300 |
---|---|---|
committer | GitHub <noreply@github.com> | 2023-10-21 12:16:22 +0200 |
commit | a2e23af5cbd85d085ce2003402560aad4bb87a52 (patch) | |
tree | 7872d1db1774161833b8d3bd73a293b86417c3b7 /src | |
parent | 2466d880d95a0584f5beb7a205070b0e3fc47549 (diff) | |
download | GT5-Unofficial-a2e23af5cbd85d085ce2003402560aad4bb87a52.tar.gz GT5-Unofficial-a2e23af5cbd85d085ce2003402560aad4bb87a52.tar.bz2 GT5-Unofficial-a2e23af5cbd85d085ce2003402560aad4bb87a52.zip |
A new approach for block updates in BaseMetaTileEntity (#2342)
* - added 0,5s cooldown on BaseMetaTileEntity texture render update
* - changed to RandomCooldown to make visual representation of the target object more relevant to its state
* - implemented a BlockUpdateHandler, making the update cooldowns chunk-based
- left commented out debug code
* - now BaseMetaTileEntity tracks last time a texture update was issued and skips update if parent chunk was already updated since last update issue
* - reworked BlockUpdateHandler to a singleton doing update work on client tick, this way update logic is fully encapsulated and gets rid of some comparisons needed to sync updates
* - fixed a bug with crash on quitting the game
- forgot to add moved sources
- cleaned up debug code
- added description commentary
* - updated buildscript
* - switched to internal tick counter, cause server time is unreliable and crashes client https://github.com/GTNewHorizons/GT-New-Horizons-Modpack/issues/14742
- removed subclass aliases
- switched to XSTR instead of java's Random
- IllegalArugmentException instead of InvalidParameterException
- added client side config option to enable/disable this feature (by default is off)
---------
Co-authored-by: iamblackornot <nkzshinnnik@gmail.com>
Diffstat (limited to 'src')
6 files changed, 188 insertions, 2 deletions
diff --git a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java index a7236e164d..8755bacf7f 100644 --- a/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java +++ b/src/main/java/gregtech/api/metatileentity/BaseMetaTileEntity.java @@ -72,6 +72,7 @@ import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_BasicMachin import gregtech.api.metatileentity.implementations.GT_MetaTileEntity_Hatch; import gregtech.api.net.GT_Packet_TileEntity; import gregtech.api.objects.GT_ItemStack; +import gregtech.api.objects.blockupdate.BlockUpdateHandler; import gregtech.api.util.GT_CoverBehaviorBase; import gregtech.api.util.GT_Log; import gregtech.api.util.GT_ModHandler; @@ -333,8 +334,11 @@ public class BaseMetaTileEntity extends CommonMetaTileEntity } if (mNeedsUpdate) { - worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); - // worldObj.func_147479_m(xCoord, yCoord, zCoord); + if (GT_Mod.gregtechproxy.mUseBlockUpdateHandler) { + BlockUpdateHandler.Instance.enqueueBlockUpdate(worldObj, getLocation()); + } else { + worldObj.markBlockForUpdate(xCoord, yCoord, zCoord); + } mNeedsUpdate = false; } } 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; +} diff --git a/src/main/java/gregtech/common/GT_Proxy.java b/src/main/java/gregtech/common/GT_Proxy.java index ffa6d617b8..8897bfb6e4 100644 --- a/src/main/java/gregtech/common/GT_Proxy.java +++ b/src/main/java/gregtech/common/GT_Proxy.java @@ -658,6 +658,11 @@ public abstract class GT_Proxy implements IGT_Mod, IGuiHandler, IFuelHandler, IG public boolean mRenderPollutionFog = true; /** + * This enables BaseMetaTileEntity block updates handled by BlockUpdateHandler + */ + public boolean mUseBlockUpdateHandler = false; + + /** * This makes cover tabs visible on GregTech machines */ public boolean mCoverTabsVisible = true; diff --git a/src/main/java/gregtech/loaders/preload/GT_PreLoad.java b/src/main/java/gregtech/loaders/preload/GT_PreLoad.java index 730aba52a0..749cb06eda 100644 --- a/src/main/java/gregtech/loaders/preload/GT_PreLoad.java +++ b/src/main/java/gregtech/loaders/preload/GT_PreLoad.java @@ -835,6 +835,8 @@ public class GT_PreLoad { .get("render", "RenderItemDurabilityBar", true); GT_Mod.gregtechproxy.mRenderItemChargeBar = GregTech_API.sClientDataFile .get("render", "RenderItemChargeBar", true); + GT_Mod.gregtechproxy.mUseBlockUpdateHandler = GregTech_API.sClientDataFile + .get("render", "UseBlockUpdateHandler", false); GT_Mod.gregtechproxy.mCoverTabsVisible = GregTech_API.sClientDataFile .get("interface", "DisplayCoverTabs", true); |