Jump to content

[1.10.2] "Player moved wrongly" preventing teleportation


IceMetalPunk

Recommended Posts

I have a block which, when collided with, checks for a certain item in the player's hand. If found, it uses the item's data tags to get a coordinate, and then teleports the player there.

 

This *almost* works. Except when the teleportation occurs, I get a server warning in the console saying "[Playername] moved wrongly!" and end up getting teleported right back next to the block instead of the proper coordinates. I tried looking into the EntityEnderPearl code to see how that handles teleportation, and it seems to just use EntityPlayerMP#setPositionAndUpdate...but that's what I'm using and the server is complaining about it.

 

I've found online other people who've had this trouble, but the solutions were for older versions of Forge which no longer apply; how do I teleport the player properly without it complaining and rubber-banding them?

 

Here's the code in question:

 

]@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	if (entity instanceof EntityPlayerMP && !entity.worldObj.isRemote) {
		EntityPlayer player = (EntityPlayer) entity;
		ItemStack mainItem = player.getHeldItemMainhand();
		ItemStack offItem = player.getHeldItemOffhand();
		if (mainItem != null && mainItem.getItem() == Amethystic.items.PORTKEY && mainItem.hasTagCompound()) {
			NBTTagCompound tag = mainItem.getTagCompound();
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			mainItem.damageItem(1, player);
			player.setPositionAndUpdate(x, y, z);
			player.setFire(1);
		}
		else if (offItem != null && offItem.getItem() == Amethystic.items.PORTKEY && offItem.hasTagCompound()) {

			NBTTagCompound tag = offItem.getTagCompound();
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			offItem.damageItem(1, player);
			player.setPositionAndUpdate(x, y, z);
			EntityEnderPearl p;
			player.setFire(1);
		}
	}
}

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

EntityPlayerMP does override

Entity#setPositionAndUpdate()

, so try changing this

EntityPlayer player = (EntityPlayer) entity;

to this

EntityPlayerMP player = (EntityPlayerMP) entity;

 

Currently you are actually calling

Entity#setPositionAndUpdate()

rather than

EntityPlayerMP#setPositionAndUpdate()

. This is becasuee the field player is of the type EntityPlayer, not EntityPlayerMP; EntityPlayer does not override

setPositionAndUpdate()

and neither does EntityLivingBase, so

Entity#setPositionAndUpdate()

is called.

 

Link to comment
Share on other sites

Its sound like a client server sync issue to me. After looking at your code you are call it both on the client and server which causes sync issue. Try wrapping your block with if(!world.isRemove) { ... } and try again. This will call that line of code on the server only.

Link to comment
Share on other sites

The entire method is wrapped in a conditional that checks if

!entity.worldObj.isRemote

....the whole thing runs only on the server.

 

A bit of file searching shows this warning occurs under the following conditions:

 

1) The player is not in creative or spectator mode.

2) The player is not sleeping.

3) The player has not just switched dimensions.

4) The server update packet shows the player is more than 0.25 blocks away from the player's last known location.

 

Which, of course, is the current situation when teleporting. But I don't understand why, then, it doesn't trigger the warning when using an Ender Pearl, since the EntityEnderPearl uses the same method to teleport the player on the server just as I'm doing...

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

Ok I figured it out. You need to call it in both the client and server. That means remove the if(!world.isRemove) {} then that error will stop.

 

Here is my example.

@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	super.onEntityCollidedWithBlock(world, pos, state, entity);
	if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	}
}

@Override
public void onEntityWalk(World world, BlockPos pos, Entity entity) {
	// TODO Auto-generated method stub
	super.onEntityWalk(world, pos, entity);


	//if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	//}

}

 

However, I ran into a weird problem with the onEntityCollidedWithBlock event. It was firing so I used the onEntityWalk even and it worked.

Link to comment
Share on other sites

Ok I figured it out. You need to call it in both the client and server. That means remove the if(!world.isRemove) {} then that error will stop.

 

Here is my example.

@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	super.onEntityCollidedWithBlock(world, pos, state, entity);
	if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	}
}

@Override
public void onEntityWalk(World world, BlockPos pos, Entity entity) {
	// TODO Auto-generated method stub
	super.onEntityWalk(world, pos, entity);


	//if(!world.isRemote) {
		if(entity instanceof EntityPlayer) {
			EntityPlayer player = (EntityPlayer) entity;

			BlockPos npos = pos.add(25, 1.0, 0);

			player.velocityChanged = true;

			player.setPositionAndUpdate(npos.getX(), npos.getY(), npos.getZ());
		}
	//}

}

 

However, I ran into a weird problem with the onEntityCollidedWithBlock event. It was firing so I used the onEntityWalk even and it worked.

If I use onEntityWalk, the method is never called; keep in mind this is a fire-based block with no collision box.

 

Using onEntityCollidedWithBlock, but moving the isRemote check around just the damageItem lines (which is required or else there's weird damage desync problems with the item) and not around the teleportation line, still gives the warning/rubber banding...

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

That might be your problem. I'm currently using version 12.18.2.2107 which is the version that I did my testing with. I did receive the error message but I wasn't rubber banning back to the same location with the test example I created. I think it could be a forge bug cause the issue. Try updating to the latest version of forge and I think it should because when I compared your code to my code they look almost identical for the exception you are store your location an items nbt and my was hard-coded. I think its a forge bug so updating forge should fix the issue.

Link to comment
Share on other sites

Look at

CommandTeleport

on how to do teleportation properly. It most certainly should not be happening client-side at all.

Thanks for the info and I agree that teleportation should not be happening on the client.

 

Look at the setPlayerLocation method, its the one that changes the player location.

Link to comment
Share on other sites

Look at

CommandTeleport

on how to do teleportation properly. It most certainly should not be happening client-side at all.

 

It seems like all that command does is call EntityPlayerMP's connection.setPlayerLocation() for the teleport. So I tried using that, and I still get the "Player Moved Wrongly" warning and rubber-banding...

 

Here's the current code:

 

	protected void teleport(EntityPlayerMP player, BlockPos destination) {
	teleport(player, destination.getX(), destination.getY(), destination.getZ());
}

protected void teleport(EntityPlayerMP player, int x, int y, int z) {
	player.connection.setPlayerLocation(x, y, z, player.rotationYaw, player.rotationPitch);
}

// Teleport the player when they walk through the flames with a linked
// portkey
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	if (entity instanceof EntityPlayerMP && !entity.worldObj.isRemote) {
		EntityPlayerMP player = (EntityPlayerMP) entity;
		ItemStack mainItem = player.getHeldItemMainhand();
		ItemStack offItem = player.getHeldItemOffhand();

		NBTTagCompound tag = null;
		if (mainItem != null && mainItem.getItem() == Amethystic.items.PORTKEY && mainItem.hasTagCompound()) {
			tag = mainItem.getTagCompound();
			mainItem.damageItem(1, player);
		}
		else if (offItem != null && offItem.getItem() == Amethystic.items.PORTKEY && offItem.hasTagCompound()) {
			tag = offItem.getTagCompound();
			offItem.damageItem(1, player);
		}

		if (tag != null) {
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			player.velocityChanged = true;
			teleport(player, x, y, z);
			player.setFire(1);
		}
	}
}

 

Next I'll try using the latest version of Forge and see if that helps, but for now, I'm doing exactly what the teleport command does but it's still complaining.

Whatever Minecraft needs, it is most likely not yet another tool tier.

Link to comment
Share on other sites

  • 6 months later...
On 10/18/2016 at 0:21 AM, IceMetalPunk said:

 

It seems like all that command does is call EntityPlayerMP's connection.setPlayerLocation() for the teleport. So I tried using that, and I still get the "Player Moved Wrongly" warning and rubber-banding...

 

Here's the current code:

 

 


	protected void teleport(EntityPlayerMP player, BlockPos destination) {
	teleport(player, destination.getX(), destination.getY(), destination.getZ());
}

protected void teleport(EntityPlayerMP player, int x, int y, int z) {
	player.connection.setPlayerLocation(x, y, z, player.rotationYaw, player.rotationPitch);
}

// Teleport the player when they walk through the flames with a linked
// portkey
@Override
public void onEntityCollidedWithBlock(World world, BlockPos pos, IBlockState state, Entity entity) {
	if (entity instanceof EntityPlayerMP && !entity.worldObj.isRemote) {
		EntityPlayerMP player = (EntityPlayerMP) entity;
		ItemStack mainItem = player.getHeldItemMainhand();
		ItemStack offItem = player.getHeldItemOffhand();

		NBTTagCompound tag = null;
		if (mainItem != null && mainItem.getItem() == Amethystic.items.PORTKEY && mainItem.hasTagCompound()) {
			tag = mainItem.getTagCompound();
			mainItem.damageItem(1, player);
		}
		else if (offItem != null && offItem.getItem() == Amethystic.items.PORTKEY && offItem.hasTagCompound()) {
			tag = offItem.getTagCompound();
			offItem.damageItem(1, player);
		}

		if (tag != null) {
			int x = tag.getInteger("linkX"), y = tag.getInteger("linkY"), z = tag.getInteger("linkZ");
			player.velocityChanged = true;
			teleport(player, x, y, z);
			player.setFire(1);
		}
	}
}
 

 

 

Next I'll try using the latest version of Forge and see if that helps, but for now, I'm doing exactly what the teleport command does but it's still complaining.

 
 

 

 

I've tried the basically same thing, taken straight from the command, in multiple game versions, and the results I get a very, very weird.  I implemented my TP in an abstract base class, and had four classes that inherited it (for short vs. long range, and one-way vs. two-way teleporters).  All inherited directly, no changes.  It works perfectly 100% of the time for both one-way teleporters but not the two-way (always the error if in survival, even with cheats on, works if used in creative). 

 

So, this way can work, sometimes, but why it sometimes doesn't is a mystery that needs some explaining (and probably a fix) -- will anyone else answer this?

Edited by JaredBGreat

Developer of Doomlike Dungeons.

Link to comment
Share on other sites

  • 4 months later...

Apologies for the minor necro, but I have some information to add to this thread which I figured might be useful...

 

I hit this same problem today while porting PneumaticCraft's air cannon to 1.12 - one of the air cannon's modes allows players to be launched into the air.  Worked fine if I triggered the cannon via a button, but I got the "player moved wrongly!" message when triggering with a pressure plate.  The reason for this is that the pressure plate's redstone signal (and the resulting actions) is directly triggered by entity movement, so EntityPlayerMP#setPositionAndUpdate() effectively ends up getting called from within Entity#move().  This is sufficient to trigger the server's move validation checks, since the player has moved further than expected.

 

I got around it with a bit of a gross hack: using reflection to set EntityMP's private invulnerableDimensionChange field to true right before calling setPositionAndUpdate() - the server validation code will be ignored if this field is true.  This at least has the nice side effect of being automatically switched off pretty much straight away; as soon as the server receives a CPacketConfirmTeleport packet, which happens as soon as the client gets the SPacketPlayerPosLook packet.

 

It's not pretty, but it works.

  • Like 1
Link to comment
Share on other sites

On 10/15/2016 at 8:27 PM, Leviathan143 said:

EntityPlayerMP does override


Entity#setPositionAndUpdate()
 

, so try changing this

 


EntityPlayer player = (EntityPlayer) entity;
 

 

to this

 


EntityPlayerMP player = (EntityPlayerMP) entity;
 

 

 

Currently you are actually calling


Entity#setPositionAndUpdate()
 

rather than


EntityPlayerMP#setPositionAndUpdate()
 

. This is becasuee the field player is of the type EntityPlayer, not EntityPlayerMP; EntityPlayer does not override


setPositionAndUpdate()
 

and neither does EntityLivingBase, so


Entity#setPositionAndUpdate()
 

is called.

 

This doesn't sound right to me. Isn't the whole point of virtual methods that you don't have to worry about this?

Link to comment
Share on other sites

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • They were already updated, and just to double check I even did a cleanup and fresh update from that same page. I'm quite sure drivers are not the problem here. 
    • i tried downloading the drivers but it says no AMD graphics hardware has been detected    
    • Update your AMD/ATI drivers - get the drivers from their website - do not update via system  
    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
  • Topics

×
×
  • Create New...

Important Information

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