Redstone Conduits are preventing chunks from being unloaded
LXGaming opened this issue ยท 6 comments
Issue Description:
Redstone Conduits are preventing chunks from being unloaded.
What happens:
EnderIO has checks in place to verify if a chunk is loaded but it lacks checks for if the chunk is queued for unload, when getBlockState
is called it results in the chunk having its unloadQueued
field set to false, This is preventing the chunk from being unloaded.
On a Forge server all Redstone Conduits will prevent chunks from being unloaded.
On a SpongeForge server only Redstone Conduits with a Redstone Sensor Filter will prevent chunks from being unloaded.
What you expected to happen:
EnderIO shouldn't be ticking conduits that are in chunks queued for unload.
Steps to reproduce:
Forge:
- Place a Redstone Conduit.
SpongeForge:
- Place a Redstone Conduit.
- Right click with a Yeta Wrench.
- Insert a Redstone Sensor Filter.
I disconnected from the server and used IntelliJ to set breakpoints so I could see what chunks were still loaded.
Affected Versions (Do not use "latest"):
- EnderIO: 1.12.2-5.1.52
- EnderCore: 1.12.2-0.5.73
- Minecraft: 1.12.2
- Forge: 14.23.5.2847
- SpongeForge? yes and no
- Optifine? no
- Single Player and/or Server? I've only tested this on a Dedicated Server
Your most recent log file where the issue was present:
Redstone Conduit Stacktrace (Forge):
getLoadedChunk:92, ChunkProviderServer (net.minecraft.world.gen)
loadChunk:107, ChunkProviderServer (net.minecraft.world.gen)
loadChunk:101, ChunkProviderServer (net.minecraft.world.gen)
provideChunk:147, ChunkProviderServer (net.minecraft.world.gen)
getChunk:374, World (net.minecraft.world)
getChunk:366, World (net.minecraft.world)
getBlockState:1007, World (net.minecraft.world)
neighborNotifyEvent:212, RedstoneConduitNetwork (crazypants.enderio.conduits.conduit.redstone)
notifyConduitNeighbours:191, RedstoneConduitNetwork (crazypants.enderio.conduits.conduit.redstone)
tickEnd:268, RedstoneConduitNetwork (crazypants.enderio.conduits.conduit.redstone)
onServerTick:57, ServerTickHandler (crazypants.enderio.base.handler)
invoke:-1, ASMEventHandler_124_ServerTickHandler_onServerTick_ServerTickEvent (net.minecraftforge.fml.common.eventhandler)
invoke:90, ASMEventHandler (net.minecraftforge.fml.common.eventhandler)
post:182, EventBus (net.minecraftforge.fml.common.eventhandler)
onPostServerTick:266, FMLCommonHandler (net.minecraftforge.fml.common)
tick:787, MinecraftServer (net.minecraft.server)
run:592, MinecraftServer (net.minecraft.server)
run:748, Thread (java.lang)
Redstone Conduit with Redstone Sensor Filter Stacktrace (SpongeForge):
getLoadedChunk:92, ChunkProviderServer (net.minecraft.world.gen)
redirect$zmg000$impl$ProvideChunkForced:145, ChunkProviderServer (net.minecraft.world.gen)
provideChunk:147, ChunkProviderServer (net.minecraft.world.gen)
getChunk:374, World (net.minecraft.world)
getChunk:366, World (net.minecraft.world)
getBlockState:1970, WorldServer (net.minecraft.world)
apply:15, ComparatorInputSignalFilter (crazypants.enderio.base.filter.redstone)
getNetworkInput:432, InsulatedRedstoneConduit (crazypants.enderio.conduits.conduit.redstone)
updateInputsForSource:114, RedstoneConduitNetwork (crazypants.enderio.conduits.conduit.redstone)
tickEnd:260, RedstoneConduitNetwork (crazypants.enderio.conduits.conduit.redstone)
onServerTick:57, ServerTickHandler (crazypants.enderio.base.handler)
invoke:-1, ASMEventHandler_145_ServerTickHandler_onServerTick_ServerTickEvent (net.minecraftforge.fml.common.eventhandler)
invoke:90, ASMEventHandler (net.minecraftforge.fml.common.eventhandler)
forgeBridge$post:253, EventBus (net.minecraftforge.fml.common.eventhandler)
post:203, EventBus (net.minecraftforge.fml.common.eventhandler)
onPostServerTick:266, FMLCommonHandler (net.minecraftforge.fml.common)
tick:787, MinecraftServer (net.minecraft.server)
run:592, MinecraftServer (net.minecraft.server)
run:748, Thread (java.lang)
seems to be SpongeForge problem bc are server doesn't have any problem with redstone conduits
The code is there in vanilla/Forge, too:
and is documented:
But absolutely nothing but the ChunkProvider accesses that field:
Also, queueUnload() is called:
- When a player logs out; on all chunks within their view distance (even if there are other players there).
- When there are no players logged in at all.
- When the server is stopped.
- When the admin issues a command to unload one or all chunks.
- After the pregen command has generated a chunk.
All of them are "unload if the chunk is idle" events.
I've retested this in a production environment with only Forge, EnderCore, EnderIO and a custom mod to list loadedChunks via commands, I've found that moving away from the chunk so that it's outside the view distance will cause it to get unloaded instantly, However disconnecting while the chunk is still within view distance will keep the chunk loaded even with no other players present on the server.
seems to be SpongeForge problem
Nope, As mentioned above and in the original post I've tested this without SpongeForge being present.
But absolutely nothing but the ChunkProvider accesses that field
Correct but if you check the World::getBlockState
method which EnderIO calls and follow how it loads chunks you will end up at the ChunkProviderServer::getLoadedChunk
which does change the unloadQueued
field, I did provided a Stacktrace in my original post which shows the RedstoneConduitNetwork::tickEnd
method resulting in ChunkProviderServer::getLoadedChunk
getting called.
All of them are "unload if the chunk is idle" events.
Yes but the issue here is that EnderIO is marking the chunk as active when the chunks in question shouldn't be active.
If the chunks are unloaded properly when moving away, this sounds more like a vanilla or Forge bug. There's absolutely no indication that a mod should check that field in addition to world.isBlockLoaded(). There are also plenty of calls to isBlockLoaded() in vanilla code and not a single one does any additional check.
Looking at the order in which notable things are ticked:
-
Scheduled tasks which include packets are processed first, This means that the
CPlayerPacket
which gets sent when the client moves is processed, part of the processing involves updating thePlayerChunkMap
to mark chunks that are non longer within the players view distance as inactive. -
Worlds are ticked and this also include the
ChunkProvider
, it's at this point chunk are unloaded if they have been marked as inactive. -
World Entities and TileEntities are ticked.
-
NetworkSystem is then ticked which handles player disconnections and part of this processing is removing the player from the
PlayerChunkMap
which again will mark chunks as inactive. -
Finally the
RedstoneConduitNetwork
tickEnd
method is called.
This explains why moving away from chunks unloads them correctly as it's happening within the same tick however when a player disconnects the chunks that they were loading are marked as inactive but won't be unloaded until the next tick.
Because the RedstoneConduitNetwork
runs at the end of the server tick any chunks that were marked as inactive due to a player disconnecting are marked as active by EnderIO which then prevents the chunk from being unloaded on the next tick.
I wouldn't call it a Forge or Vanilla bug, Simply put EnderIO is essentially performing TileEntity logic where it shouldn't be performed it, at least not without additional checks in place, no mod should have to check the unloadQueued
field but again you've shifted a ton of logic to be outside the order in which vanilla Minecraft does things and as such you can't expect it to work with zero issues.