Minecraft Forge EntityJoinWorldEvent返回错误的位置!错误 [英] Minecraft Forge EntityJoinWorldEvent returns Wrong Location! Error

查看:206
本文介绍了Minecraft Forge EntityJoinWorldEvent返回错误的位置!错误的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

在本地开发环境中的Eclipse(Mars.1版本(4.5.1))中使用Forge 1.8.9.

Using Forge 1.8.9 in Eclipse (Mars.1 Release (4.5.1)) in local development environment.

我试图在玩家每次加入或重新加入世界时设定其位置.它总是在第一次运行(例如运行并加入世界.请参阅第一个屏幕截图).

I'm trying to set a player's location every time they join or re-join a world. It always works the first time (e.g. run and join the world. See first screen shot).

在世界各地移动了一点,然后退出该世界并返回(在关闭MC的同一会话中退出),该世界未能出现在控制台中.该位置与全部正常"登录名中的位置相同.另外还有错误的位置!错误.

After moving around the world a little bit, then logging out of that world and going back in (same session w/out closing down MC), the world fails to appear and in the Console. The location is the same location as in the "all OK" login. Plus there is a Wrong Location! Error.

控制台中的错误在这里:

The error from the console is here:

 [05:47:53] [Server thread/INFO]: Player992 joined the game
 [05:47:53] [Server thread/WARN]: Wrong location! (9, 9) should be (9, 6),  EntityPlayerMP['Player992'/2371, l='world', x=145.00, y=73.00, z=145.00]
 [05:48:18] [Server thread/INFO]: Saving and pausing game...
 [05:48:18] [Server thread/INFO]: Saving chunks for level 'world'/Overworld
 [05:48:18] [Server thread/INFO]: Saving chunks for level 'world'/Nether
 [05:48:18] [Server thread/INFO]: Saving chunks for level 'world'/The End

我尝试了一些变体,包括 Minecraft Forge:为setLocationAndAngles使用正确的Join Game侦听器,但没有骰子(行为不同).

I've tried a few variations of this, including Minecraft Forge: Using correct Join Game listener for setLocationAndAngles but no dice (different behaviour).

忽略所有不相关的导入".它们是我多次尝试的产物.

Ignore all the 'imports' that aren't relevant. They are artifacts of my multiple attempts.

import net.minecraft.util.ChatComponentText;
import net.minecraft.util.EnumChatFormatting;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.util.EnumChatFormatting;
import net.minecraftforge.event.entity.EntityJoinWorldEvent;
import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.fml.common.gameevent.PlayerEvent.PlayerLoggedInEvent;
//import cpw.mods.fml.common.eventhandler.SubscribeEvent;
import net.minecraftforge.client.event.RenderWorldEvent;
import net.minecraftforge.event.world.WorldEvent;
public class JoinGameLocation {

    @SubscribeEvent
    public void onEntityJoinWorld(EntityJoinWorldEvent event) {
        if (event.entity != null && event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
        event.entity.setLocationAndAngles(145, 73, 145, 0, 0);
        }
    }

}

我已经阅读了有关错误位置"错误的内容,但是由于我可以第一次出现在该位置,所以似乎有些不对劲,所以就好像我没有出现在街区中一样.我尝试创建一个短暂的延迟(1-3s),但是仍然会发生错误.

I've done some reading on the Wrong Location error, but something doesn't seem right, given that I can appear in that location the first time around, so it is not like I am appearing inside a block. I've tried creating a short delay (1-3s), but the error still occurs.

推荐答案

位置错误!"用于将实体添加到不应从其坐标进入的块中时使用.

"Wrong location!" is used when an entity is added to a chunk that it shouldn't be in from its coordinates.

在此处(World.java)中触发事件的地方(实际上,还有其他几个地方,但这是玩家在其他实体中使用的地方):

Here's where (in World.java) the event is fired (well, actually, there are a few other places, but this is the one used by players among other entities):

/**
 * Called when an entity is spawned in the world. This includes players.
 */
public boolean spawnEntityInWorld(Entity p_72838_1_)
{
    // do not drop any items while restoring blocksnapshots. Prevents dupes
    if (!this.isRemote && (p_72838_1_ == null || (p_72838_1_ instanceof net.minecraft.entity.item.EntityItem && this.restoringBlockSnapshots))) return false;

    int i = MathHelper.floor_double(p_72838_1_.posX / 16.0D);
    int j = MathHelper.floor_double(p_72838_1_.posZ / 16.0D);
    boolean flag = p_72838_1_.forceSpawn;

    if (p_72838_1_ instanceof EntityPlayer)
    {
        flag = true;
    }

    if (!flag && !this.isChunkLoaded(i, j, true))
    {
        return false;
    }
    else
    {
        if (p_72838_1_ instanceof EntityPlayer)
        {
            EntityPlayer entityplayer = (EntityPlayer)p_72838_1_;
            this.playerEntities.add(entityplayer);
            this.updateAllPlayersSleepingFlag();
        }

        if (net.minecraftforge.common.MinecraftForge.EVENT_BUS.post(new net.minecraftforge.event.entity.EntityJoinWorldEvent(p_72838_1_, this)) && !flag) return false;

        this.getChunkFromChunkCoords(i, j).addEntity(p_72838_1_);
        this.loadedEntityList.add(p_72838_1_);
        this.onEntityAdded(p_72838_1_);
        return true;
    }
}

请注意,更新播放器的位置后,ij(块坐标)不会更改.因此,当调用Chunk.addEntity(见下文)时,事情就不起作用了:

Note that i and j (chunk coordinates) aren't changed after updating the player's location. So when Chunk.addEntity (see below) is called, things don't work:

/**
 * Adds an entity to the chunk. Args: entity
 */
public void addEntity(Entity entityIn)
{
    this.hasEntities = true;
    int i = MathHelper.floor_double(entityIn.posX / 16.0D);
    int j = MathHelper.floor_double(entityIn.posZ / 16.0D);

    if (i != this.xPosition || j != this.zPosition)
    {
        logger.warn("Wrong location! (" + i + ", " + j + ") should be (" + this.xPosition + ", " + this.zPosition + "), " + entityIn, new Object[] {entityIn});
        entityIn.setDead();
    }

    // ... rest of the method
}

这杀死了玩家.

我不完全确定为什么它第一次起作用.只要您以与要传送的块相同的身份登录,它便会起作用,因此,如果您在错误的位置后注销,则下次将成功登录.

I'm not entirely sure why it's working the first time. It'll work whenever you log in in the same chunk as the one you'd be teleported to, so if you log out after you're in the wrong location, you'll log in successfully the next time.

在进行修复之前,还有一些其他注意事项:

Before I get to a fix, here's a few other things to note:

  • 您不需要对instanceof进行空检查-null永远不会通过instanceof测试.
  • (至少根据CommandTeleport的说法),您需要使用EntityPlayerMP.playerNetServerHandler.setPlayerLocation来不同地传送EntityPlayerMP.
  • You don't need to do a null check with instanceof - null will never pass an instanceof test.
  • (At least according to CommandTeleport), you need to teleport EntityPlayerMPs differently, using EntityPlayerMP.playerNetServerHandler.setPlayerLocation.

要解决此问题,您需要将隐形传送延迟1刻.我不确定这是什么规范的伪造方法,但是类似的东西应该可以工作:

To fix it, you'll need to delay the teleportation by 1 tick. I'm not sure quite what the canonical forge method for that is, but something like this should work:

List<Entity> playersToTeleport = new ArrayList<Entity>();

@SubscribeEvent
public void onEntityJoinWorld(EntityJoinWorldEvent event) {
    if (event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
        playersToTeleport.add(event.entity);
    }
}

@SubscribeEvent
public void teleportEntiesOnWorldTick(TickEvent.WorldTickEvent event) {
// Make sure that this is the type of tick we want.
if (event.phase == TickEvent.Phase.START && event.type == TickEvent.Type.WORLD) {
        for (Entity entity : playersToTeleport) {
            if (entity.worldObj == event.world) {
                if (entity instanceof EntityPlayerMP) {
                    ((EntityPlayerMP) entity).playerNetServerHandler.setPlayerLocation(145, 73, 145, 0, 0);
                } else {
                    entity.setLocationAndAngles(145, 73, 145, 0, 0);
                }
            }
        }
        playersToTeleport.clear();
    }
}

如果您需要更改播放器的位置,而不是总是转到这些特定坐标,则这是一种方法:

If you need to be able to change the position the player will be at rather than always going to those specific coordinates, here's one way of doing so:

@SubscribeEvent
public void onEntityJoinWorld(EntityJoinWorldEvent event) {
    if (event.entity instanceof EntityPlayer && !event.entity.worldObj.isRemote) {
        queueTeleportNextTick(event.entity, Math.random() * 200 - 100, 73,
                Math.random() * 200 - 100, 0, 0);
    }
}

/**
 * List of teleports to perform next tick.
 */
private List<TeleportInfo> queuedTeleports = new ArrayList<TeleportInfo>();

/**
 * Stores information about a future teleport.
 */
private static class TeleportInfo {
    public TeleportInfo(Entity entity, double x, double y, double z,
            float yaw, float pitch) {
        this.entity = entity;
        this.x = x;
        this.y = y;
        this.z = z;
        this.yaw = yaw;
        this.pitch = pitch;
    }

    public final Entity entity;
    public final double x;
    public final double y;
    public final double z;
    public final float yaw;
    public final float pitch;
}

/**
 * Teleport the given entity to the given coordinates on the next game tick.
 */
public void queueTeleportNextTick(Entity entity, double x, double y,
        double z, float yaw, float pitch) {
    System.out.printf("Preparing to teleport %s to %f, %f, %f%n", entity, x, y, z);
    queuedTeleports.add(new TeleportInfo(entity, x, y, z, yaw, pitch));
}

@SubscribeEvent
public void teleportEntiesOnWorldTick(TickEvent.WorldTickEvent event) {
    // Make sure that this is the type of tick we want.
    if (event.phase == TickEvent.Phase.START && event.type == TickEvent.Type.WORLD) {
        // Perform each teleport
        Iterator<TeleportInfo> itr = queuedTeleports.iterator();
        while (itr.hasNext()) {
            TeleportInfo info = itr.next();
            if (info.entity.worldObj == event.world) {
                System.out.printf("Teleporting %s to %f, %f, %f%n", info.entity, info.x, info.y, info.z);
                if (info.entity instanceof EntityPlayerMP) {
                    // EntityPlayerMPs are handled somewhat differently.
                    ((EntityPlayerMP) info.entity).playerNetServerHandler
                            .setPlayerLocation(info.x, info.y, info.z,
                                    info.pitch, info.yaw);
                } else {
                    info.entity.setLocationAndAngles(info.x, info.y, info.z,
                            info.pitch, info.yaw);
                }
                itr.remove();
            }
        }
    }
}

此外,请注意,要使用TickEvent,您需要注册到与EntityJoinWorldEvent一起使用的单独的总线,因此要完全注册此处使用的事件,请执行以下操作:

Also, note that to use TickEvent, you need to register to a separate bus than you'd use with EntityJoinWorldEvent, so to fully register the events used here, you'd do this:

MinecraftForge.EVENT_BUS.register(this);
FMLCommonHandler.instance().bus().register(this);

这篇关于Minecraft Forge EntityJoinWorldEvent返回错误的位置!错误的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆