Reputation: 3
Im trying to use the setBlock command to place the active (giving out redstone power) version of my keypad if the code you type in the keypad GUI is correct. The code im about to show you works flawlessly on the client (Singleplayer) side, but not on the server (Multiplayer) side. Heres the code:
BlockKeypad 'onBlockActivated' code:
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;
}
}
GuiKeypad code:
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 class:
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();
}
}
}
If i use this code i have now, for some reason, it gives me a NullPointerException on BlockKeypad.worldServerObj when i create a new ScheduleUpdate object (in the GuiKeypad code). If i switch that with BlockKeypad.worldObj (my client side World object), it looks like it places the block, but if i update the new block (right-clicking it, placing a block next to it, etc. ), it disappears. So im guessing i have to use the worldServerObj, but again, it throws a NullPointerException whenever i try and use that, even though im setting to the server's World object before the GUI even opens.
I made a item to System.out.println() the two world objects i made in the BlockKeypad class.
When i right-click it, it prints this in the console (client):
net.minecraft.multiplayer.WorldClient()
null
In the server console:
null
net.minecraft.multiplayer.WorldServer()
Anyone know whats wrong? I would greatly appreciate any help at all, as this is the only thing holding me back from releasing the multiplayer-compatible version of my mod. Thanks!
Upvotes: 0
Views: 3287
Reputation: 387
The short answer is that you've coded your mod to be single-player only, meaning that it will only operate correctly if the client code and the server code are executing from the same runtime environment and can easily pass object references and values back and forth. The reason your client is reporting that the WorldServer object is null is because it doesn't actually have access to any WorldServer objects when connected to a dedicated server (in SSP the client is running the integrated server, so it DOES have access to it). The same is true for why the server doesn't have access to the WorldClient object.
Basically you need to implement client/server packet handlers for the client to send the custom data needed by the server to determine if the player has entered the correct keypad entry and take the appropriate action. This is done by dispatching an instance of Packet250CustomPayload from the client when a player has finished entering a keycode and submitted it. Packet250CustomPayload consists of an Object[] that can contain any object types you need to process the request. For your sake I hope you are using Minecraft Forge as the mod loading mechanism as that's the easiest way to make your mod work for both SSP and SMP.
Here is a link to a tutorial on packet handling in Minecraft: http://www.minecraftforge.net/wiki/Packet_Handling
Here is another link to the source of Treecapitator (it's my code, so feel free to use it to learn how to apply packet handling concepts): https://github.com/bspkrs/Treecapitator
Additionally, Treecapitator packet handling code uses a class from my required dependency mod bspkrsCore that helps with constructing packets (I can't post the third URL as I have no reputation points): [mygithubURL]/bspkrsCore/blob/master/src/bspkrs/fml/util/ForgePacketHelper.java
Other tips:
~ instead of checking if the World object is of a specific object type, use world.isRemote(). When isRemote() is true you should run your client-specific code and when it's false you should run your server-specific code.
~ don't use a separate thread to modify the world... you should instead register a new tick handler to avoid concurrent modification exceptions.
Upvotes: 1