Skip to content

Chunks forced by other mods or /forceload are removed every tick #36

@Smalldero

Description

@Smalldero

When another mod or the built‑in /forceload command forces chunks to load via setChunkForced method, this mod immediately un‑forces them on every game tick—effectively overriding all external chunk‑loading sources.

Reproduction Steps

  1. Force-load a chunk using /forceload add ~ ~
  2. Verify the chunk is loaded with /forceload query ~ ~
  3. Move to another chunk and create the chunk loaded minecart from this mod
  4. Return to the original forced chunk and run /forceload query ~ ~ → the chunk is no longer loaded

Expected Behavior

The mod should only remove chunks that it forced itself - leaving chunks loaded by other mods or by /forceload intact.

Fix for version 1.21.5

Add the following to the ScriptsChunkLoadersMod Class:

+ public static final ChunkTicketType CUSTOM_TICKETTYPE =  Registry.register(Registries.TICKET_TYPE, ScriptsChunkLoadersMod.MODID, new ChunkTicketType(0L, true, ChunkTicketType.Use.LOADING_AND_SIMULATION));

Then change the following in the ChunkLoaderManager Class:

private void updateChunkLoaders(ServerWorld world) {
      var currentChunks = calculateLoadedChunks(world);

      // TODO: This can probably be optimized. We're looping over the same range twice since there usually is an
      //  overlap between the current chunks and the loaded chunks.

      final LongSet loadedChunks = world.getForcedChunks();

      currentChunks.forEach(chunkPos -> {
          long longPos = chunkPos.toLong();

          if (!loadedChunks.contains(longPos)) {
              // Load chunk
-             world.setChunkForced(chunkPos.x, chunkPos.z, true);
+            var ticket = new ChunkTicket(ScriptsChunkLoadersMod.CUSTOM_TICKETTYPE, ServerChunkLoadingManager.FORCED_CHUNK_LEVEL);
+            world.getChunkManager().addTicket(ticket, chunkPos);
          }
      });

      loadedChunks.forEach(longPos -> {
          var chunkPos = new ChunkPos(longPos);
          if (!currentChunks.contains(chunkPos)) {
              // Unload chunk
-             world.setChunkForced(chunkPos.x, chunkPos.z, false);
+            world.getChunkManager().removeTicket(ScriptsChunkLoadersMod.CUSTOM_TICKETTYPE, chunkPos, 2);
          }
      });
  }

All chunks loaded by this mod are now registered under the custom ChunkTicketType. When these chunks are unloaded, they are only removed from that ChunkTicketType and all other loaded chunks remain untouched.

Version 1.21.9

The following changes in the 1.21.9 version of the game in the ScriptsChunkLoadersMod Class:

- public static final ChunkTicketType CUSTOM_TICKETTYPE =  Registry.register(Registries.TICKET_TYPE, ScriptsChunkLoadersMod.MODID, new ChunkTicketType(0L, true, ChunkTicketType.Use.LOADING_AND_SIMULATION));
+ public static final ChunkTicketType CUSTOM_TICKETTYPE =  Registry.register(Registries.TICKET_TYPE, ScriptsChunkLoadersMod.MODID, new ChunkTicketType(ChunkTicketType.NO_EXPIRATION, ChunkTicketType.SERIALIZE | ChunkTicketType.FOR_LOADING | ChunkTicketType.FOR_SIMULATION | ChunkTicketType.RESETS_IDLE_TIMEOUT));

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions