0

如果您在键盘 GUI 中键入的代码是正确的,我正在尝试使用 setBlock 命令来放置我的键盘的活动(发出红石电源)版本。我即将向您展示的代码在客户端(单人游戏)端完美运行,但在服务器(多人游戏)端却没有。继承人的代码:

BlockKeypad 'onBlockActivated' 代码:

public boolean onBlockActivated(World par1World, int par2, int par3, int par4, EntityPlayer par5EntityPlayer, int par6, float par7, float par8, float par9){
this.playerObj = par5EntityPlayer;
this.lastKeypadX = par2;
this.lastKeypadY = par3;
this.lastKeypadZ = par4;

if(par1World instanceof WorldServer){
    this.worldServerObj = par1World;
    TileEntityKeypad TEK = (TileEntityKeypad) par1World.getBlockTileEntity(par2, par3, par4);
    System.out.println(TEK.getKeypadCode() + " | Code from TileEntity");

    this.openCode = TEK.getKeypadCode();
    if(TEK.getKeypadCode() == 0){
        par5EntityPlayer.openGui(mod_SecurityCraft.instance, 1, par1World, par2, par3, par4);
    }else{
        par5EntityPlayer.openGui(mod_SecurityCraft.instance, 0, par1World, par2, par3, par4);
    }

    return true;
}else{
    this.worldObj = par1World;
       //Rest of client code here


    return true;
}           

}

Gui键盘代码:

private void checkCode(String par1String) {
int code = 0;
try{
    code = Integer.parseInt(par1String);
}catch(Exception e){
    e.printStackTrace();
}

System.out.println(BlockKeypad.openCode + " | GUI");
if(code == BlockKeypad.openCode){           
new ScheduleUpdate(3, BlockKeypad.worldServerObj, BlockKeypad.lastKeypadX,BlockKeypad.lastKeypadY, BlockKeypad.lastKeypadZ, BlockKeypad.openCode, this.keypadInventory);
    BlockKeypad.playerObj.closeScreen();
            }

}

ScheduleUpdate 类:

public class ScheduleUpdate{
Timer timer;
private int xCoord;
private int yCoord;
private int zCoord;
private int metadata;
private int passcode;
private TileEntityKeypad TEK;
public ScheduleUpdate(int seconds, World par2World, int par3, int par4, int par5, int par6, TileEntityKeypad keypadInventory){
    timer = new Timer();
    timer.schedule(new RemindTask(), seconds*1000); //TODO 60
    xCoord = par3;
    yCoord = par4;
    zCoord = par5;
    passcode = par6;
    TEK = keypadInventory;
    //BlockKeypad.shouldCheckMeta = false;

    metadata = par2World.getBlockMetadata(par3, par4 , par5);
    System.out.println(metadata + " | metadata");
    par2World.setBlock(par3, par4, par5, mod_SecurityCraft.KeypadActive.blockID, metadata, 3);
    par2World.notifyBlocksOfNeighborChange(par3, par4 , par5, mod_SecurityCraft.KeypadActive.blockID);

}
class RemindTask extends TimerTask{

    public void run(){
        BlockKeypad.worldObj.setBlock(xCoord, yCoord, zCoord, mod_SecurityCraft.Keypad.blockID, metadata, 3);
        BlockKeypad.worldObj.notifyBlocksOfNeighborChange(xCoord, yCoord, zCoord, mod_SecurityCraft.Keypad.blockID);

        ((TileEntityKeypad) BlockKeypad.worldObj.getBlockTileEntity(xCoord, yCoord, zCoord)).setKeypadCode(passcode);


        timer.cancel();
    }
}

}

如果我使用我现在拥有的这段代码,由于某种原因,当我创建一个新的 ScheduleUpdate 对象(在 GuiKeypad 代码中)时,它会在 BlockKeypad.worldServerObj 上给我一个 NullPointerException。如果我用 BlockKeypad.worldObj (我的客户端 World 对象)切换它,它看起来像是放置了块,但是如果我更新新块(右键单击它,在它旁边放置一个块等),它就会消失. 所以我猜我必须使用worldServerObj,但同样,每当我尝试使用它时它都会抛出NullPointerException,即使我在GUI打开之前设置为服务器的World对象。

我为 System.out.println() 制作了一个项目,这是我在 BlockKeypad 类中制作的两个世界对象。

当我右键单击它时,它会在控制台(客户端)中打印:

net.minecraft.multiplayer.WorldClient()
null

在服务器控制台中:

null
net.minecraft.multiplayer.WorldServer()

有谁知道怎么了?我将非常感谢任何帮助,因为这是唯一阻止我发布我的 mod 的多人兼容版本的事情。谢谢!

4

1 回答 1

1

简短的回答是,您已将您的 mod 编码为仅单人模式,这意味着只有在客户端代码和服务器代码在相同的运行时环境中执行并且可以轻松地将对象引用和值传回时,它才能正确运行,并且向前。您的客户端报告 WorldServer 对象为空的原因是因为它在连接到专用服务器时实际上无权访问任何 WorldServer 对象(在 SSP 中,客户端正在运行集成服务器,因此它可以访问它) . 服务器无权访问 WorldClient 对象的原因也是如此。

基本上,您需要为客户端实现客户端/服务器数据包处理程序,以发送服务器所需的自定义数据,以确定播放器是否输入了正确的键盘条目并采取适当的操作。这是通过在玩家完成输入密钥代码并提交时从客户端调度 Packet250CustomPayload 实例来完成的。Packet250CustomPayload 由一个 Object[] 组成,它可以包含处理请求所需的任何对象类型。为了您的利益,我希望您使用 Minecraft Forge 作为模组加载机制,因为这是让您的模组同时适用于 SSP 和 SMP 的最简单方法。

这是 Minecraft 中数据包处理教程的链接:http: //www.minecraftforge.net/wiki/Packet_Handling

这是 Treecapitator 源代码的另一个链接(这是我的代码,请随意使用它来学习如何应用数据包处理概念):https ://github.com/bspkrs/Treecapitator

此外,Treecapitator 数据包处理代码使用我所需的依赖模块 bspkrsCore 中的一个类,该类有助于构建数据包(我无法发布第三个 URL,因为我没有信誉点):[mygithubURL]/bspkrsCore/blob/master/src/bspkrs /fml/util/ForgePacketHelper.java

其他提示:
~ 不要检查 World 对象是否属于特定对象类型,而是使用 world.isRemote()。当 isRemote() 为真时,您应该运行特定于客户端的代码,而当它为假时,您应该运行特定于服务器的代码。
〜不要使用单独的线程来修改世界......您应该注册一个新的滴答处理程序以避免并发修改异常。

于 2013-09-25T16:12:29.970 回答