CubicChunks

CubicChunks

840k Downloads

Entities becames invisible after TP.

Foghrye4 opened this issue ยท 12 comments

commented

Result - invisible mobs. Nasty.
How to repeat:

  1. Set chunk garbage collector interval to ridiculously high value.
  2. TP to point far from spawn.
  3. Add some mobs.
  4. Die.
  5. Respawn.
  6. TP back to mobs.

TP back and forth does not produce bug.

commented
    @Inject(method = "tick", at = @At(value = "RETURN"))
    public void onTick(CallbackInfo ci) {
        for (Entity entity : this.loadedEntityList) {
            if (!entity.addedToChunk)
                continue;
            int entityBlockPosX = entity.chunkCoordX;
            int entityBlockPosY = entity.chunkCoordY;
            int entityBlockPosZ = entity.chunkCoordZ;
            CubePos cpos = new CubePos(entityBlockPosX, entityBlockPosY, entityBlockPosZ);
            if (!this.getCubeCache().getCube(cpos).getEntityContainer().getEntities().contains(entity)) {
                throw new IllegalStateException("Entity does not contained in his cube");
            }
        }
    }

This code injected to WorldClient throw exception.
In contrary this code:

public class BlankEntityContainer extends EntityContainer {
    @Override
    public void addEntity(Entity entity) {
        throw new IllegalStateException("Attempt to add entity to blank cube.");
    }

Show nothing despite presence of an invisible mobs.

commented

Probably because this injection ribs before mc moves entities between chunks

commented

I launched such debug code to understand what is going on:

	public void checkEntities(Entity cse) {
		List<Entity> entityList = cse.world.getEntitiesWithinAABBExcludingEntity(cse, new AxisAlignedBB(cse.posX - 6, cse.posY, cse.posZ - 6, cse.posX + 6, cse.posY + 2, cse.posZ + 6));
		IntList ids = new IntArrayList();
		for (Entity entity : entityList) {
			ids.add(entity.getEntityId());
		}
		QuickSaveQuickLoadMod.network.sendEntityInfoToPlayer(cse, ids.toIntArray());
	}

	public void checkEntitiesClient(EntityPlayerSP player, int[] ids) {
		World world = player.world;
		ICubicWorld cw = (ICubicWorld) player.world;
		QuickSaveQuickLoadMod.log.info("Checking entities by server ID");
		for(int id:ids){
			Entity entity = world.getEntityByID(id);
			QuickSaveQuickLoadMod.log.info("id = " + id);
			QuickSaveQuickLoadMod.log.info(entity);
			if(entity == null)
				continue;
			QuickSaveQuickLoadMod.log.info("Added to chunk = " + entity.addedToChunk);
			QuickSaveQuickLoadMod.log.info("Is dead = " + entity.isDead);
			int entityBlockPosX = entity.chunkCoordX;
			int entityBlockPosY = entity.chunkCoordY;
			int entityBlockPosZ = entity.chunkCoordZ;
			CubePos cpos = new CubePos(entityBlockPosX, entityBlockPosY, entityBlockPosZ);
			if (!cw.getCubeCache().getCube(cpos).getEntityContainer().getEntities().contains(entity))
				QuickSaveQuickLoadMod.log.info("Not in cube");
			else
				QuickSaveQuickLoadMod.log.info("Is in correct cube");
			
			if(!entity.addedToChunk) {
				world.updateEntityWithOptionalForce(entity, true);
				QuickSaveQuickLoadMod.log.info("After force update addedToChunk= " + entity.addedToChunk);
			}
		}
	}

Output:

[19:26:09] [Netty Local Client IO #0/INFO] [quicksave_quickload]: EntityCaveSpiderLeveled['Cave Spider'/9431, l='MpServer', x=2202.62, y=-159.00, z=2938.30]
[19:26:09] [Netty Local Client IO #0/INFO] [quicksave_quickload]: Added to chunk = false
[19:26:09] [Netty Local Client IO #0/INFO] [quicksave_quickload]: Is dead = false
[19:26:09] [Netty Local Client IO #0/INFO] [quicksave_quickload]: Not in cube
[19:26:09] [Netty Local Client IO #0/INFO] [quicksave_quickload]: After force update addedToChunk= true

Video how they act after forced update: https://youtu.be/-SvCQadwqbo

commented

It seems that at client side invisible entity contained in entitiesById, but not in loadedEntityList. Either process of spawning was interrupted between those two points, or entity was removed from loadedEntityList.

commented

The most worrying part for me is the netty thread here... That doesn't look right

commented

Ah, thats unrelated. Its just because I'm using network to send array of ids to client.

commented

Well then. I don't really have the time to debug it myself now. You should really try to find a way to compare it against vanilla.

commented

That's what I do. I'm updating this issue just in hope you or someone else could've scream: "Hey, I know why this is happening!" after reading all of this before I do.

In all possible cases when entity removed from entity loaded list is when they are either dead or set to be dead.

entitySpawnQueue overloaded.

commented

It's seems that before player click "respawn" Minecraft constantly call EntityTracker.untrack(player) every tick.


Unrelated to bug.


It seems that if entity is trying to be spawned by network handler in client world in unloaded cube, spawn of that entity scheduled next tick. Next tick it will be removed from entity spawn queue even if it fails to be spawned again. This could be a source of a problem.


No, it is not.


Despite a fact that entity successfully spawned client-side it is still not rendered.


    @Inject(method = "renderEntities", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/BlockPos$PooledMutableBlockPos;retain()Lnet/minecraft/util/math/BlockPos$PooledMutableBlockPos;"), cancellable = true)
    public void debugRenderEntities(Entity renderViewEntity, ICamera camera, float partialTicks, CallbackInfo ci){
        for(Entity entity:this.world.loadedEntityList) {
            if(entity != Minecraft.getMinecraft().getRenderViewEntity())
            this.renderManager.renderEntityStatic(entity, partialTicks, false);
            if(entity instanceof EntityHusk)
                System.out.println("rendering husk");
        }
    }

[21:24:30] [Server thread/INFO]: [Player330: Teleported Player330 to 1000.5, 10.0, 0.5]
[21:24:30] [main/INFO]: [CHAT] Teleported Player330 to 1000.5, 10.0, 0.5
[21:24:30] [Server thread/INFO] [STDOUT]: [cubicchunks.entity.CubicEntityTrackerEntry:updatePlayerEntity:74]: EntityHusk['Husk'/26854, l='New World', x=1002.23, y=0.00, z=-5.44]
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.multiplayer.WorldClient:handler$handleSpawnEntity$zca000:709]: Attempt to spawn husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.multiplayer.WorldClient:handler$handleSpawnEntity$zca000:709]: Attempt to spawn husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.multiplayer.WorldClient:handler$handleSpawnEntity$zca000:713]: Success
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.renderer.RenderGlobal:handler$debugRenderEntities$zcb000:2766]: rendering husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.renderer.RenderGlobal:handler$debugRenderEntities$zcb000:2766]: rendering husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.renderer.RenderGlobal:handler$debugRenderEntities$zcb000:2766]: rendering husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.renderer.RenderGlobal:handler$debugRenderEntities$zcb000:2766]: rendering husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.renderer.RenderGlobal:handler$debugRenderEntities$zcb000:2766]: rendering husk
[21:24:30] [main/INFO] [STDOUT]: [net.minecraft.client.renderer.RenderGlobal:handler$debugRenderEntities$zcb000:2766]: rendering husk
[21:24:35] [Server thread/INFO]: Saving and pausing game...

Output of this brutal debug code shows that entity first added to client-side loaded entities list and in a few ticks removed from it.


Entity removed via network SPacketDestroyEntities

commented

I'm stuck. Hooking on .setDead() shows that .setDead() called once before TP and entity spawn on client side. Hooking on .onEntityRemoved() shows that it is removed because it is dead.

commented

In general you can get much more information about what is going on by printing stack trace in debug logging, easiest way is this:
new Error().printStackTrace();

commented

I used

        for(StackTrace st:Thread.currentThread().getStackTrace()){
            System.out.println(st);
        }