Alex's Caves

Alex's Caves

5M Downloads

Failed Nuclear Explosion created permanently loaded chunks

SwiftSniffer opened this issue ยท 2 comments

commented

Following the detonation of a Nuclear Bomb, and due to messing with its power setting and the fact that it loaded a huge amount of entities and what not (I'll skip the details), this caused the world to crash.

Upon reloading, the explosion did nothing (except a small tnt explosion), and ever since then, all chunks within the bomb radius are permanently loaded.

Removing chunks with the /forceload command did nothing, because apparently no chunks are permanently loaded.
Removing the mod did nothing.

Is there a way to fix that? It hammers the performance of my world. And I can't just delete the world, nor can I do anything about the content of those loaded chunks.

commented

I haven't used force loaded chunks yet, but won't this (once the unload is called) try to remove non-ticking force loaded chunks?

Shouldn't they be ticking though (since this is what you set them to)?
Meaning, on removal shouldn't the second parameter still be true?
(Since your initial call added the chunks to the tickingChunks map)

@Override
public void remove(Entity.RemovalReason removalReason) {
if (!level().isClientSide && loadingChunks) {
loadingChunks = false;
loadChunksAround(false);
}
super.remove(removalReason);
}

private void loadChunksAround(boolean load) {
if (this.level() instanceof ServerLevel serverLevel) {
ChunkPos chunkPos = new ChunkPos(this.blockPosition());
int dist = Math.max(getChunksAffected(), serverLevel.getServer().getPlayerList().getViewDistance() / 2);
for (int i = -dist; i <= dist; i++) {
for (int j = -dist; j <= dist; j++) {
ForgeChunkManager.forceChunk(serverLevel, AlexsCaves.MODID, this, chunkPos.x + i, chunkPos.z + j, load, load);
}
}
}
}

        private Map<TicketOwner<T>, LongSet> getTickets(boolean ticking)
        {
            return ticking ? tickingChunks : chunks;
        }

        /**
         * @return {@code true} if the state changed.
         */
        private boolean remove(TicketOwner<T> owner, long chunk, boolean ticking)
        {
            Map<TicketOwner<T>, LongSet> tickets = getTickets(ticking);
            if (tickets.containsKey(owner))
            {
                LongSet ticketChunks = tickets.get(owner);
                if (ticketChunks.remove(chunk))
                {
                    if (ticketChunks.isEmpty())
                        tickets.remove(owner);
                    return true;
                }
            }
            return false;
        }

Additionally you could also set a callback if I understand it correctly

    /**
     * Sets the forced chunk loading validation callback for the given mod. This allows for validating and removing no longer valid tickets on level load.
     *
     * @apiNote This method should be called from a {@link net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent} using one of the {@link
     * net.minecraftforge.fml.event.lifecycle.ParallelDispatchEvent} enqueueWork methods.
     */
    public static void setForcedChunkLoadingCallback(String modId, LoadingValidationCallback callback)
    {
        if (ModList.get().isLoaded(modId))
            callbacks.put(modId, callback);
        else
            LOGGER.warn("A mod attempted to set the forced chunk validation loading callback for an unloaded mod of id: {}", modId);
    }

which is called here:

    /**
     * Reinstates forge's forced chunks when vanilla initially loads a level and reinstates their forced chunks. This method also will validate all of forge's forced
     * chunks using and registered {@link LoadingValidationCallback}.
     *
     * @apiNote Internal
     */
    public static void reinstatePersistentChunks(ServerLevel level, ForcedChunksSavedData saveData)

where you can make sure that tickets (force loaded chunks) are removed

commented

The issue is still ongoing.

To give you a great example to test out:
Make a large field of planted wheat seed. Detonate a nuke in the middle of it. Cover the hole with farmland and new seeds.

Now, teleport a thousand blocks away, boost the gamerule randomtickspeed to 3000, wait 10 seconds, then put the gamerule back to 3. Then, come back to the coordinates of the nuke hole.

You will see that the wheat where the hole was has grown, while the wheat elsewhere didn't.

This will prove that a Nuclear Bomb does load chunks even after detonating. Which is a big issue.