Jump to content

[1.19.2] ForgeChunkManager to force chunks around a moving entity


Recommended Posts

Posted

I recently read up about ForgeChunkManager and how it can be used to keep particular chunks loaded. Namely that you submit 'tickets' for each forced chunk which are tagged by UUID, BlockPos or Entity.

However, I want to keep the chunks around particular non-player entities loaded - do I have to check the position on every tick for every one of these entities in order to change its associated ticket? (ie. remove the old one and create a new one) That doesn't seem very efficient to me.

Is there a more built-in way to automatically keep the chunk around an entity loaded?

Posted
  On 11/11/2022 at 8:44 AM, SoLegendary said:

Is there a more built-in way to automatically keep the chunk around an entity loaded?

Expand  

I will note you answered the question yourself:

  On 11/11/2022 at 8:44 AM, SoLegendary said:

Namely that you submit 'tickets' for each forced chunk which are tagged by UUID, BlockPos or Entity.

Expand  

The entity is an Entity, it does not have to be a Player.

Posted (edited)

@ChampionAsh5357 I should have been a bit more specific with my question.

The method to force a chunk for an entity is:

forceChunk(ServerLevel level, String modId, Entity owner, int chunkX, int chunkZ, boolean add, boolean ticking)

But the fact it accepts a chunkX and chunkZ kind of implies that it keeps only the chunk that is passed loaded and does not move. Does the forced automatically chunk change as the entity moves or do I have to check myself if the entity moved into a new chunk each tick?

EDIT: I'm trying to force a chunk with my entities here but it doesn't seem to work (I lose access to them via level.getEntity once my player's out of range):
 

    @SubscribeEvent
    public static void onEntityJoin(EntityJoinLevelEvent evt) {
        Entity entity = evt.getEntity();
        if (entity instanceof Unit && !evt.getLevel().isClientSide) {
            ChunkAccess chunk = evt.getLevel().getChunk(entity.getOnPos());
            ForgeChunkManager.forceChunk((ServerLevel) evt.getLevel(), ReignOfNether.MOD_ID, entity, chunk.getPos().x, chunk.getPos().z, true, true);
        }
    }

 

Edited by SoLegendary
Posted
  On 11/12/2022 at 2:33 AM, SoLegendary said:

Does the forced automatically chunk change as the entity moves or do I have to check myself if the entity moved into a new chunk each tick?

Expand  

You would have to remove the previous ticket and then add a new one each time the entity steps into a new chunk.

  On 11/12/2022 at 2:33 AM, SoLegendary said:

EDIT: I'm trying to force a chunk with my entities here but it doesn't seem to work (I lose access to them via level.getEntity once my player's out of range):

Expand  

I believe the chunk has to be ticking to grab the associated entity, or you need to refer to them by the entity uuid, assuming the entity isn't unloaded when the chunk is.

 

Why are you trying to force a chunk to remain loaded by the way? You can usually do most logic without having to do so.

Posted (edited)
  On 11/12/2022 at 8:41 PM, ChampionAsh5357 said:

Why are you trying to force a chunk to remain loaded by the way? You can usually do most logic without having to do so.

Expand  

I'm creating an RTS mod with a top-down camera view. This means that the player has to be able to pan their camera far away and still retain selection of units (eg. sending an army across the map to an opponent's base). 'Panning the camera' simply means moving their player entity in spectator mode.

However, unit commands rely on the entity and its chunk still being loaded, watch what happens in my mod when I move the camera too far (ignore the weird villager rendering bug):

https://i.imgur.com/kFguQBF.mp4

This happens because I retain selection with this code:

    @SubscribeEvent
    public static void onRenderLivingEntity(RenderLivingEvent.Pre<? extends LivingEntity, ? extends Model> evt) {

        ArrayList<LivingEntity> units = UnitClientEvents.getSelectedUnits();

        units.sort(Comparator.comparing(HudClientEvents::getSimpleEntityName));

        if (units.size() <= 0)
            hudSelectedEntity = null;
        else if (hudSelectedEntity == null || units.size() == 1 || !units.contains(hudSelectedEntity))
            hudSelectedEntity = units.get(0);
    }

In UnitClientEvents I maintain a list of my unit Ids with EntityLeaveLevelEvent and EntityJoinLevelEvent and moving out of render range appears to remove them from this list until I move back into render range:

    @SubscribeEvent
    public static void onEntityLeave(EntityLeaveLevelEvent evt) {
        Entity entity = evt.getEntity();
        if (entity instanceof Unit unit && evt.getLevel().isClientSide)
            allUnitIds.removeIf(e -> e == entity.getId());
    }
    @SubscribeEvent
    public static void onEntityJoin(EntityJoinLevelEvent evt) {
        Entity entity = evt.getEntity();
        if (entity instanceof Unit unit && evt.getLevel().isClientSide)
            allUnitIds.add(entity.getId());
    }

I assumed that forcing a chunk would also render the entities too but that doesn't seem to be the case, either because forced chunks don't care about rendering and/or the 'forcing' doesn't care about the client at all.

EDIT: I found this post that references rendering faraway chunks clientside in 1.12 but is there a 1.19.2 equivalent of these classes?

 

Edited by SoLegendary
Posted
  On 11/12/2022 at 11:40 PM, SoLegendary said:

I assumed that forcing a chunk would also render the entities too but that doesn't seem to be the case, either because forced chunks don't care about rendering and/or the 'forcing' doesn't care about the client at all.

Expand  

Forcing is a server side thing which tells it to tick. Client side rendering is controlled by the chunk render distance in the options settings. Typically that has a hardcoded max on that since the game is not optimized for what you are doing.

In my opinion, it would be better to create a pseudo-level which you control such that you can do your own custom rendering, logic, and serialization so you can apply optimizations without needing to do ridiculous workarounds. It additionally has an added benefit of being independent of the main game, so you could have many different RTSes per world.

But if you want to keep going down this path, you just need to render and optimize multiple chunks on screen and make sure your force logic is functioning properly. Though you can probably get away without forcing the chunk by just keeping track of how much time has passed and executing all the logic at once or having the logic apply on the world capability in a limited capacity such that when the chunk loads back in, you can apply the transforms immediately.

Posted
  On 11/17/2022 at 4:00 AM, ChampionAsh5357 said:

Forcing is a server side thing which tells it to tick. Client side rendering is controlled by the chunk render distance in the options settings. Typically that has a hardcoded max on that since the game is not optimized for what you are doing.

In my opinion, it would be better to create a pseudo-level which you control such that you can do your own custom rendering, logic, and serialization so you can apply optimizations without needing to do ridiculous workarounds. It additionally has an added benefit of being independent of the main game, so you could have many different RTSes per world.

But if you want to keep going down this path, you just need to render and optimize multiple chunks on screen and make sure your force logic is functioning properly. Though you can probably get away without forcing the chunk by just keeping track of how much time has passed and executing all the logic at once or having the logic apply on the world capability in a limited capacity such that when the chunk loads back in, you can apply the transforms immediately.

Expand  

I intend for this game mode in my mod to be fully compatible with regular vanilla players so I don't want to make separate virtual levels at all.

Is it possible to replicate the same logic that ClientPlayers have to have the chunks around them be rendered and have it apply to my Unit entities as well? I'm sure that if I can do that along with Serverside chunk forcing, I can get this to work as intended. I could even lower their effective chunk render distance to be 1 since all I really need is the chunk they're currently standing on.

Do you know the class where that kind of logic is handled?

Posted
  On 11/17/2022 at 7:13 AM, SoLegendary said:

Is it possible to replicate the same logic that ClientPlayers have to have the chunks around them be rendered and have it apply to my Unit entities as well?

Expand  

Potentially? Though you will probably have to build and render the chunk cache yourself since I believe it does a hardcoded check for player distance (e.g. `ChunkRenderDispatcher`).

Posted

Ok so after banging my head against chunk and entity rendering code for a day I just thought: "wait, what if I just kept the entity reference after it leaves the ClientLevel in EntityLeaveLevelEvent?"

So that's what I did, and apparently it worked, I can now retain selection of my entities and issue them commands after moving the player far off, even beyond chunk rendering distance without forcing chunks.

Though this method does it have its downsides:

  1. I can't update clientside data for the entity while its outside of view (eg. health and position).
  2. I have no reliable way to detect when an entity actually properly leaves the level (ie. by dying or changing dimensions).

I'm assuming this method works because the server is still tracking all of these entities regardless of the player's distance, so maybe I can sync the data from the server?

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.
Note: Your post will require moderator approval before it will be visible.

Guest
Unfortunately, your content contains terms that we do not allow. Please edit your content to remove the highlighted words below.
Reply to this topic...

×   Pasted as rich text.   Restore formatting

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Announcements



×
×
  • Create New...

Important Information

By using this site, you agree to our Terms of Use.