Posted May 11, 201312 yr Hey everyone, I've made a new power supplying block. When I began, I made it behave like a button by overriding onBlockActivated and managing the power duration with a combination of the block metadata and an overridden updateTick. It worked perfectly. I placed the new block, added some redstone wires next to it, right clicked, and the redstone wire lit up for the proper number of ticks. So, I was happy with that. Now I needed to change the trigger from a right click to a chat event. The idea is to have a power supply that activates when a keyword is said within a specific range of it. This sounds like a job for a tile entity. I try to develop incrementally (as I'm learning to mod as I go, and don't want to commit to some code until I know it works) Eventually, I want a gui like the sign to set the password when the block is placed, but for now, I'm just hardcoding the password to see if I can get it to work. Here is my tile entity: public class TileEntityPasswordBlock extends TileEntity { public String password = "Testing"; public void writeToNBT(NBTTagCompound par1NBTTagCompound) { super.writeToNBT(par1NBTTagCompound); par1NBTTagCompound.setString("Password", this.password); } public void readFromNBT(NBTTagCompound par1NBTTagCompound) { super.readFromNBT(par1NBTTagCompound); this.password = par1NBTTagCompound.getString("Password"); if (this.password.length() > 15) { this.password = this.password.substring(0, 15); } } public Packet getDescriptionPacket() { NBTTagCompound nbtTag = new NBTTagCompound(); this.writeToNBT(nbtTag); return new Packet132TileEntityData(this.xCoord, this.yCoord, this.zCoord, 1, nbtTag); } public void onDataPacket(INetworkManager net, Packet132TileEntityData packet) { readFromNBT(packet.customParam1); } public void checkChatForPassword(String chat) { if (this.worldObj != null) { this.blockType = this.getBlockType(); if (this.blockType != null && this.blockType instanceof PasswordBlock) { ((PasswordBlock)this.blockType).passwordDetected(this.worldObj, this.xCoord, this.yCoord, this.zCoord); } } } } Note that I'm not bothering to check that chat message for the password yet. For now, I just want it to light up when anything is said in chat. My password block extends BlockContainer and overrides createNewTileEntity, and I've added a method to trigger the redstone that is called by the tile entity: @Override public TileEntity createNewTileEntity(World world) { return new TileEntityPasswordBlock(); } @SideOnly(Side.CLIENT) public void passwordDetected(World world, int x, int y, int z) { int i = world.getBlockMetadata(x, y, z); world.setBlockMetadataWithNotify(x, y, z, 10, 0); if (i == 0) { world.notifyBlocksOfNeighborChange(x, y, z, this.blockID); } world.scheduleBlockUpdate(x, y, z, this.blockID, 0); } Now I just need to call checkChatForPassword on every TileEntityPasswordBlock and pass in the chat. I've already created a ServerChatEvent handler that intercepts chat, loops through players and delivers the chat to only those players within a given distance of the sender. I thought that this would be the ideal place to loop through my tile entities and and pass the current chat to their checkChatForPassword. Unfortunately, 1) I could not find how to list the tile entites, and 2) the PasswordBlocks' passwordDetected is ClientOnly, and the ServerChatEvent works on the server thread. Even if I did hook it up, it wouldn't work because it need to be on the client thread. How can I achieve this? I'm running low on ideas here, and would appreciate anything you guys could offer. Thanks! - Scott (This is my second try at posting this... the first doesn't look to have worked. If I notice two copies of this thread, I'll be sure to delete one.)
May 11, 201312 yr Author After some more thinking, I realize that when going from client to server (or vise versa) you need to work in packets. That being said, I still have no idea as to how to go about this. Any suggestions?
May 11, 201312 yr You need a packet handler; the Forge tutorials have one such tutorial. Basically, from the "source" you need to send a 132TileEntityData packet, and your packetHandler needs to act accordingly. Here is how I do it (this is a GUI controlling a TE variable, but the principle is the same). Also note you need to make your mod "listen" to a channel at the top of your main mod class, like this: channels={"RotaryCraftData"}, packetHandler = PacketHandler.class) GUI: public void sendPacket(int a) { ByteArrayOutputStream bos = new ByteArrayOutputStream(20); // 5 ints DataOutputStream outputStream = new DataOutputStream(bos); try { //ModLoader.getMinecraftInstance().thePlayer.addChatMessage(String.valueOf(drops)); outputStream.writeInt(a); if (a == 19) outputStream.writeInt(omega); if (a == 20) outputStream.writeInt(torque); outputStream.writeInt(coil.xCoord); outputStream.writeInt(coil.yCoord); outputStream.writeInt(coil.zCoord); } catch (Exception ex) { ex.printStackTrace(); } Packet250CustomPayload packet = new Packet250CustomPayload(); packet.channel = "RotaryCraftData"; packet.data = bos.toByteArray(); packet.length = bos.size(); Side side = FMLCommonHandler.instance().getEffectiveSide(); if (side == Side.SERVER) { // We are on the server side. EntityPlayerMP player2 = (EntityPlayerMP) player; } else if (side == Side.CLIENT) { // We are on the client side. EntityClientPlayerMP player2 = (EntityClientPlayerMP) player; PacketDispatcher.sendPacketToServer(packet); } else { // We are on the Bukkit server. } } Corresponding sections of the packetHandler: [...] private TileEntityAdvancedGear adv; private TileEntityAdvancedGear clientadv; @Override public void onPacketData(INetworkManager manager, Packet250CustomPayload packet, Player player) { ep = (EntityPlayer) player; if (packet.channel.equals("RotaryCraftData")) { this.handleData(packet); } } private void handleData(Packet250CustomPayload packet) { DataInputStream inputStream = new DataInputStream(new ByteArrayInputStream(packet.data)); int control; boolean drops; int len; int[] data; long longdata = 0; int x,y,z; boolean readinglong = false; //System.out.print(packet.length); try { control = inputStream.readInt(); pack = EnumPackets.getEnum(control); len = pack.getNumberDataInts(); data = new int[len]; readinglong = pack.isLongPacket(); if (!readinglong) { for (int i = 0; i < len; i++) data[i] = inputStream.readInt(); } else longdata = inputStream.readLong(); x = inputStream.readInt(); y = inputStream.readInt(); z = inputStream.readInt(); } catch (IOException e) { e.printStackTrace(); return; } World world = ModLoader.getMinecraftInstance().theWorld; Minecraft m = Minecraft.getMinecraft(); WorldServer ws = m.getIntegratedServer().worldServerForDimension(m.thePlayer.dimension); switch (pack) { [...] case COIL: adv = (TileEntityAdvancedGear)ws.getBlockTileEntity(x, y, z); clientadv = (TileEntityAdvancedGear)world.getBlockTileEntity(x, y, z); if (control == 19) { adv.releaseOmega = data[0]; clientadv.releaseOmega = data[0]; } if (control == 20) { adv.releaseTorque = data[0]; clientadv.releaseTorque = data[0]; } break; [...] } } Follow my mod(s) here: http://www.minecraftforum.net/topic/1969694-
May 12, 201312 yr Author Hey Reika, Thanks for your help. Between your post and a tutorial I found about packets, I was able to create and send the packet I need. Everything is flowing properly now, but I still can't get the chat to trigger the redstone power. I've managed to track it down to my packet not referencing the world that has my block's metadata. right now, I have two ways of triggering my block's power. I can right click it, or I can type a chat message. Right clicking it works, chatting doesn't. I printed the world.toString() for both, and on the one that works has a worldserver id, while the one that doesn't (from my chat) uses a world id. So I need my packet to get a reference to the current world server that the tile is in... regardless of whether I'm playing in SSP or SMP. I've tried a ton of stuff, but nothing seems to work. Any ideas?
May 12, 201312 yr Did you try the method I use in the packetHandler (where I get both world and ws)? Follow my mod(s) here: http://www.minecraftforum.net/topic/1969694-
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.