Jump to content

[1.16.5] Spawning Entities in ServerWorld (Solved)


izofar

Recommended Posts

Goal

My goal is to replace naturally spawning iron golems with my modded clay golems, but still allowing for players to build their own iron golems. I have the following SubscribeEvent:

Code

@SubscribeEvent
public static void onIronGolemJoinWorld(EntityJoinWorldEvent event) {
		if(event.getEntity() instanceof IronGolemEntity) {
			if(event.getWorld() instanceof ServerWorld) {
				IronGolemEntity entity = (IronGolemEntity) event.getEntity();
				ServerWorld world = (ServerWorld)event.getWorld();
				if(!entity.isPlayerCreated()) {
					ExampleMod.LOGGER.info("Iron Golem Found!");
					ModEntities.CLAY_GOLEM.spawn(world, null, null, entity.blockPosition(), SpawnReason.MOB_SUMMONED, false, false);
					ExampleMod.LOGGER.info("Spawned Clay Golem");
				
				}
			}
			event.setCanceled(true);
			ExampleMod.LOGGER.info("Removed Iron Golem");
		}
	}

Context

I Hope This Isn't a Duplicate Question, I have read the link but still do not understand what I've done wrong. I have read the vanilla code and understand that in order to call the private World#addEntity, I must call ServerWorld#addFreshEntity (true for spawning golems with pumpkins, and silverfish blocks, etc.). Alternatively, spawn eggs call EntityType<?>#spawn, but check that the world parameter is a ServerWorld.

The result of the code above is the same as when I use:

ClayGolemEntity claygolementity = ModEntities.CLAY_GOLEM.create(world);
ExampleMod.LOGGER.info("Created Clay Golem");
claygolementity.moveTo(entity.position());
ExampleMod.LOGGER.info("Moved Clay Golem");
world.addFreshEntity(claygolementity);
ExampleMod.LOGGER.info("Spawned Clay Golem");

Results

My issue is that the following occurs:

(1) using /summon examplemod:iron_golem spawns in a clay golem. Not ideal, but I'm fine with this at the moment.

(2) Constructing Iron Golems constructs and iron golem, as intended

(3) Any naturally spawning golems in villages lags out the game to the point of needing to force quit.

(4) using /summon to spawn an iron golem (with the event.canceled(true) commented out) and then reloading the world lags out as well.

The last print statement is either "Iron Golem Found" as in the first code example, or "Moved Clay Golem" as in the second code example.

I appreciate the help. I haven't yet been able to spawn an entity in the world in code yet.

Edited by izofar
Link to comment
Share on other sites

Reading the javadoc on the event tells you: "Note:  This event may be called before the underlying Chunk is promoted to ChunkStatus#FULL. You will cause chunk loading deadlocks if you don't delay your world interactions."

As such, you should probably keep a queue of entities added along with the world and position you would like it to spawn at. Then, on the next tick in probably WorldTickEvent, check if the chunk is loaded at the position of spawning and if so spawn the entity. Otherwise, recycle into the queue until next tick.

  • Thanks 1
Link to comment
Share on other sites

3 hours ago, ChampionAsh5357 said:

Reading the javadoc on the event tells you: "Note:  This event may be called before the underlying Chunk is promoted to ChunkStatus#FULL. You will cause chunk loading deadlocks if you don't delay your world interactions."

As such, you should probably keep a queue of entities added along with the world and position you would like it to spawn at. Then, on the next tick in probably WorldTickEvent, check if the chunk is loaded at the position of spawning and if so spawn the entity. Otherwise, recycle into the queue until next tick.

Is there an easier way to do this? How would the iron golem have spawned in the first place without chunk deadlocks? Is it easier to modify the villager behavior to spawn the modded entity instead?

Link to comment
Share on other sites

9 hours ago, izofar said:

Is there an easier way to do this? How would the iron golem have spawned in the first place without chunk deadlocks? Is it easier to modify the villager behavior to spawn the modded entity instead?

 

1. Not afaik.

2. The entity is was already added and deferred to load at the correct time already. Follow the event call and you'll see that entities are loaded at a very specific point when processing. Trying to add your own entity at any point in this process would mean you could be loading a chunk that's already loading.

3. No, that is much more difficult.

  • Thanks 1
Link to comment
Share on other sites

20 hours ago, ChampionAsh5357 said:

check if the chunk is loaded at the position of spawning

The Chunk#isLoaded seems to be depreciated, nor is there a ChunkLoader#chunkExists (my research)... what's the new way of doing this? The Chunk#loaded field is private, and the Chunk#getStatus method always returns ChunkStatus.FULL... I can get the chunk with entity.level.getChunk(entity.getBlockPosition()), but what then? Must I use reflection for this? Surely there's a cleaner way.

What was previously isChunkLoaded (which Jabelar said World#isAreaLoaded utilizes) seems to be hasChunksAt, which is marked depreciated. Any guidance on this?

Edited by izofar
Link to comment
Share on other sites

  • izofar changed the title to [1.16.5] Spawning Entities in ServerWorld (Solved)

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.



×
×
  • Create New...

Important Information

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