Jump to content

Recommended Posts

Posted (edited)

Basically, I'm trying to make a block that has an adjustable light value via GUI. I have the GUI, graphics, and incrementing buttons that can output the int anytime. So far I have a packet that sends that int to the server, then I have to somehow feed it into that specific tileentity instance and write the int the that instance's NBT, which then can be read from the block of that instance, which then sets the value to that int. I have absolutely no clue what to do.

Here's the code that matters. (Yes, I have registered the block and block as a tile entity)

READ COMMENTS IN CODE PLEASE

Block Class:

Spoiler

package its_meow.spaceheater.block.spaceheater;

import java.util.Random;

import its_meow.spaceheater.SpaceHeaterMod;
import its_meow.spaceheater.gui.GUIHeater;
import net.minecraft.block.Block;
import net.minecraft.block.BlockContainer;
import net.minecraft.block.ITileEntityProvider;
import net.minecraft.block.material.Material;
import net.minecraft.block.state.IBlockState;
import net.minecraft.client.Minecraft;
import net.minecraft.client.renderer.block.model.ModelResourceLocation;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.Item;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.EnumFacing;
import net.minecraft.util.EnumHand;
import net.minecraft.util.math.BlockPos;
import net.minecraft.world.World;
import net.minecraftforge.client.model.ModelLoader;
import net.minecraftforge.fml.client.registry.ClientRegistry;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class BlockSpaceHeater extends BlockContainer {

	public BlockSpaceHeater() {
		super(Material.ROCK);
		this.setCreativeTab(SpaceHeaterMod.tab_spaceheater);
		this.setUnlocalizedName("spaceheater");
		this.setRegistryName("spaceheater");
		this.setTickRandomly(true);
	}

@Override
    public boolean onBlockActivated(World worldIn, BlockPos pos, IBlockState state, EntityPlayer playerIn, EnumHand hand, EnumFacing facing, float hitX, float hitY, float hitZ)
    {
        if(!worldIn.isRemote){
        	
        } else {  // I know i did this oddly, I should've just done worldIn.isRemote instead of the weird else
        	TileEntity tileEntity = worldIn.getTileEntity(pos);
        	if(tileEntity instanceof SpaceHeaterTileEntity) {
        		GUIHeater heater = new GUIHeater((SpaceHeaterTileEntity) worldIn.getTileEntity(pos)); //This is how i get the specific tile entity instance fed into the GUI.
        		Minecraft.getMinecraft().displayGuiScreen(heater);//Opens GUI
        	}
        }
		return false;
    }
		
	@Override
	public void updateTick(World worldIn, BlockPos pos, IBlockState state, Random rand) {
		boolean isHeaterOn = true;//Going to hook this to a button later.
		TileEntity tileEntity = worldIn.getTileEntity(pos); //The tile entity of this specific instance
		//int lLevel = ;//Where it's supposed to read NBT and plug into the variable
		if(isHeaterOn){
			this.setLightLevel(/*lLevel*/20F);
		} else {
			this.setLightLevel(0F);
		}
		
		//System.out.println(lLevel);
		
		super.updateTick(worldIn, pos, state, rand);
	}
	
	@SideOnly(Side.CLIENT)
	public void initModel(){
		ModelLoader.setCustomModelResourceLocation(Item.getItemFromBlock(this), 0, new ModelResourceLocation(getRegistryName(), "inventory"));
	}
	
    @Override
    public void breakBlock(World world, BlockPos pos, IBlockState state) {
        super.breakBlock(world, pos, state);
        world.removeTileEntity(pos);

    }



	@Override
	public TileEntity createNewTileEntity(World worldIn, int meta) {
		return new SpaceHeaterTileEntity();
	}

 

GUI Class:

Spoiler

package its_meow.spaceheater.gui;

import its_meow.spaceheater.Ref;
import its_meow.spaceheater.block.spaceheater.BlockSpaceHeater;
import its_meow.spaceheater.block.spaceheater.SpaceHeaterTileEntity;
import its_meow.spaceheater.network.packets.PacketInt;
import its_meow.spaceheater.proxy.CommonProxy;

import java.io.IOException;

import org.lwjgl.opengl.GL11;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.GuiScreen;
import net.minecraft.util.ResourceLocation;
import net.minecraft.world.World;
import static net.minecraft.client.Minecraft.getMinecraft;

public class GUIHeater extends GuiScreen {
	
	final ResourceLocation GUITexture = new ResourceLocation(Ref.MOD_ID, "textures/gui/heater.png");
	int guiWidth = 248;
	int guiHeight = 166;
	
	GuiButton buttonplus;
	GuiButton buttonminus;
	
	final int BUTTONMINUS = 0;
	final int BUTTONPLUS = 1;
	
	private SpaceHeaterTileEntity te;//Initiates tile entity's specific instance variable
	
	public GUIHeater(SpaceHeaterTileEntity te) {
		this.te = te;//Sets te to the imported tile entity
	}
	
	@Override
	public void drawScreen(int mouseX, int mouseY, float partialTicks){
		drawDefaultBackground();
		Minecraft.getMinecraft().renderEngine.bindTexture(GUITexture);
		int centerX = (width / 2) - (guiWidth / 2);
		int centerY = (height / 2) - (guiHeight / 2);
		drawTexturedModalRect(centerX, centerY, 0, 0, guiWidth, guiHeight);
		String str1 = "Heat Level";
		drawCenteredString(fontRendererObj, str1, (width / 2), centerY + 40, 0xFFFFFF);
		GL11.glPushMatrix();
		{
		GL11.glColor4f(1, 1, 1, 1);
		Minecraft.getMinecraft().renderEngine.bindTexture(GUITexture);
		GL11.glPopMatrix();
		}
		super.drawScreen(mouseX, mouseY, partialTicks);
	}
	
	@Override
	public void initGui(){
		buttonList.add(buttonminus = new GuiButton(BUTTONMINUS, (width/2)-150/2, (height)-guiHeight/2, 18, 18, "-"));
		buttonList.add(buttonplus = new GuiButton(BUTTONPLUS, (width/2)+150/2, (height)-guiHeight/2, 18, 18, "+"));

		super.initGui();
	}
	
	private int lightLevel = 11;//This is eventually going to read the NBT for the variable, it currently resets every time you re-open the GUI
	@Override
	protected void actionPerformed(GuiButton button) throws IOException {

		if(button.id == BUTTONPLUS){
			System.out.println("plus");
			lightLevel++;
			if(lightLevel - 11 < 0){
				lightLevel = 11;
			} else if(lightLevel - 11 > 10) {
				lightLevel = 21;
			}
			System.out.println("inGUI-11: " + (lightLevel - 11));
			int displayLightLevel = (lightLevel - 11);
			drawCenteredString(fontRendererObj, Integer.toString(displayLightLevel), (width/2), (height)-guiHeight/2, 0xFFFFFF);
			CommonProxy.packetHandler.INSTANCE.sendToServer(new PacketInt(lightLevel));//Sends the int to the Server, sice GUIs are clientside
		} 
		if(button.id == BUTTONMINUS){
				System.out.println("minus");
				lightLevel--;
				if(lightLevel - 11 < 0){
					lightLevel = 11;
				} else if(lightLevel - 11 > 10) {
					lightLevel = 21;
				}
				System.out.println("inGUI-11: " + (lightLevel - 11));
				int displayLightLevel = (lightLevel - 11);
              	drawCenteredString(fontRendererObj, Integer.toString(displayLightLevel), (width/2), (height)-guiHeight/2, 0xFFFFFF);
				CommonProxy.packetHandler.INSTANCE.sendToServer(new PacketInt(lightLevel));//See above comment
				
		}
		
		super.actionPerformed(button);
	}

	@Override
	protected void keyTyped(char typedChar, int keyCode) throws IOException {
		super.keyTyped(typedChar, keyCode);
	}

	@Override
	public boolean doesGuiPauseGame() {
		return true;
	}

	@Override
	public void onGuiClosed() {
		super.onGuiClosed();
	}
	
	
	
	
	
	
	
	
	
	
	
	
}

 

Tile Entity Class:

Spoiler

package its_meow.spaceheater.block.spaceheater;

import its_meow.spaceheater.gui.GUIHeater;

import javax.annotation.Nullable;

import net.minecraft.block.Block;
import net.minecraft.block.state.IBlockState;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.network.NetworkManager;
import net.minecraft.network.play.server.SPacketUpdateTileEntity;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ITickable;
import net.minecraft.util.math.BlockPos;

public class SpaceHeaterTileEntity extends TileEntity implements ITickable {
	  

		
	    //I have no idea how to use NBT, I tried some tutorials, they're really confusing.
	    @Override
	    public NBTTagCompound getUpdateTag() {
	        // getUpdateTag() is called whenever the chunkdata is sent to the
	        // client. In contrast getUpdatePacket() is called when the tile entity
	        // itself wants to sync to the client. In many cases you want to send
	        // over the same information in getUpdateTag() as in getUpdatePacket().
	    	return writeToNBT(new NBTTagCompound());
	    }

	    @Nullable
	    @Override
	    public SPacketUpdateTileEntity getUpdatePacket() {
	        // Prepare a packet for syncing our TE to the client. Since we only have to sync the stack
	        // and that's all we have we just write our entire NBT here. If you have a complex
	        // tile entity that doesn't need to have all information on the client you can write
	        // a more optimal NBT here.
	        NBTTagCompound nbtTag = new NBTTagCompound();
	        this.writeToNBT(nbtTag);
	        return new SPacketUpdateTileEntity(getPos(), 1, nbtTag);
	    }

	
	    @Override
	    public void readFromNBT(NBTTagCompound compound) {
	        super.readFromNBT(compound);
	    }
	    @Override
	    public NBTTagCompound writeToNBT(NBTTagCompound compound) {
	        super.writeToNBT(compound);
	        
	        
	        
	        
	        
	        
	        return compound;
	    }
	    

		@Override
		public void update() {
	    	BlockPos blockpos = this.getPos();
	    	Block block = this.getBlockType();
	    	if(block instanceof BlockSpaceHeater){
	    		this.world.scheduleBlockUpdate(blockpos, block, 5, 1);//Makes the actual block tick
	    		
	    	}
			
		}
}

 

 

PacketInt Class (w/ Handler):

Spoiler

package its_meow.spaceheater.network.packets;

import io.netty.buffer.ByteBuf;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;

public class PacketInt implements IMessage {
	
	private int theInt;
	
	public PacketInt() {}
	
	public PacketInt(int theInt){
		this.theInt = theInt;
	}
	
	@Override
	public void fromBytes(ByteBuf buf) {
		this.theInt = buf.readInt();
	}

	@Override
	public void toBytes(ByteBuf buf) {
		buf.writeInt(this.theInt);
	}
	
	public static class Handler implements IMessageHandler<PacketInt, IMessage> {

		@Override
		public IMessage onMessage(PacketInt message, MessageContext ctx) {
			
			System.out.println("printed packet: " + message.theInt);
			//This is where I want to write the the specific instance's NBT, but I don't have access to that instance here, how would I get it here? Could I make like a PacketIntTileEntity that sends both? but ByteBuf doesn't have a tileentity type thing. I'm new to packets and all this serverside stuff, I'm used to making mobs and items... I've never made a tile entity, GUI, or advanced block like this one I'm making.
			return null;
		}
		
	
		
	}
	
}

 

 

I have no clue what I want answered but.. SOMETHING?

 

I'm desperate lol

Edited by its_meow
Version for title
Posted
Spoiler
6 minutes ago, diesieben07 said:
  • Don't extend BlockContainer. Override hasTileEntity and createTileEntity.
  • You cannot reference client-only classes such as Minecraft in common code.
  • You must not call setLightLevel after the block was registered. If you need a dynamic light value, override getLightValue(IBlockState, IBlockAccess, BlockPos).
  • The code you have in breakBlock is not needed.
  • Why is your packet called PacketInt?
  • 
    
    
    @Override
    public void update() {
    	BlockPos blockpos = this.getPos();
    	Block block = this.getBlockType();
    	if(block instanceof BlockSpaceHeater){
    		this.world.scheduleBlockUpdate(blockpos, block, 5, 1);//Makes the actual block tick
    	}
    }

     

  • This is a terrible idea. Why are you doing this?

As for the question in the packet handler comment: You need to track which TileEntity the player is looking at on the server, the easiest way is to use Container and GuiContainer with IGuiHandler, as if you wanted to display an inventory. Then the server can track which TE the player is looking at via the Container.

 

1. So the other thing I can do is make it implement ITileEntityProvider, and Override hasTileEntity and return true?

2. It's no longer common code when I do the if !isRemote

3. I don't understand

4. Okay, removed

5. I dunno, it's an int, isn't it?

6. I don't know how I would make the light value set from the tile entity other than that, is there a better way?

 

And where would I use Container and GuiContainer with IGuiHandler?

 

Also, I'm sorry for being a clueless, horrible programmer. This entire area makes no sense to me, I'm doing a mod request because I needed something to do, so... I don't know.

Posted
6 minutes ago, its_meow said:
  Reveal hidden contents

 

1. So the other thing I can do is make it implement ITileEntityProvider, and Override hasTileEntity and return true?

You don't need to implement ITileEntityProvider, those methods are in Block so you just need to override them.

6 minutes ago, its_meow said:

2. It's no longer common code when I do the if !isRemote

Actually it is. Minecraft is a client-only class, which means it only exists on the client. Even if it's only referenced inside an if-statement, it will cause a crash on the server because the code contains a reference to something that doesn't exist at all.

6 minutes ago, its_meow said:

6. I don't know how I would make the light value set from the tile entity other than that, is there a better way?

Override the method getLightValue(IBlockState, IBlockAccess, BlockPos). In there, get the TileEntity and get the light level from it, then return that value. No need for block updates, you just need your TE to store its current light level.

6 minutes ago, its_meow said:

And where would I use Container and GuiContainer with IGuiHandler?

Container is for server-side, GUI is for client-side.

6 minutes ago, its_meow said:

Also, I'm sorry for being a clueless, horrible programmer. This entire area makes no sense to me, I'm doing a mod request because I needed something to do, so... I don't know.

That seems like kind of an unhealthy justification for this? If you don't enjoy it then just... go for a walk or something instead. :P It's supposed to be fun y'know?

Posted
12 minutes ago, Jay Avery said:

You don't need to implement ITileEntityProvider, those methods are in Block so you just need to override them.

Actually it is. Minecraft is a client-only class, which means it only exists on the client. Even if it's only referenced inside an if-statement, it will cause a crash on the server because the code contains a reference to something that doesn't exist at all.

Override the method getLightValue(IBlockState, IBlockAccess, BlockPos). In there, get the TileEntity and get the light level from it, then return that value. No need for block updates, you just need your TE to store its current light level.

Container is for server-side, GUI is for client-side.

That seems like kind of an unhealthy justification for this? If you don't enjoy it then just... go for a walk or something instead. :P It's supposed to be fun y'know?

1. Okay, I figured it out. I was confusing createNewTileEntity with createTileEnity.

2. Then how would I open the GUI?

3. so if I override it, what would the return statement be? would I leave it as super(state, world pos) or make a variable in the tile entity and return that?

4. So I made GUIHeater extend GuiContainer and implement IGuiHandler and it made me add a bunch of methods including drawGuiContainerBackgroundLayer, getServerGuiElement, and getClientGuiElement. Is there something I'm supposed to do with these? I also don't know where to put Container

5. I very much am enjoying this, it just gets frusturating at times when it won't do what you want. GRRR.

I'm having fun though :D

 

Posted

The following is the packet code i use. Note that i have only tested on 1.10.2 but its likely to work with 1.11. Also note its slightly modified to work outside of my mod. You shouldn't need an int for what you want to do, short should work.

 

The Packet Manager thingy, basically the same as SimpleNetworkWrapper except you don't need to specify packet id numbers. Replace "YOURMODSNAME" with a unique name:

package stucuk.square.packets;

import net.minecraftforge.fml.common.network.NetworkRegistry;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
import net.minecraftforge.fml.relauncher.Side;

public class MCPacketSystem {
	private int count = 0;
	private SimpleNetworkWrapper INSTANCE = new MCPacketSystem("YOURMODSNAME");

	public MCPacketSystem(String name)
	{
		INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(name);
	}	
	
	public <REQ extends IMessage, REPLY extends IMessage> void registerPacket(Class<? extends IMessageHandler<REQ, REPLY>> messageHandler, Class<REQ> requestMessageType, Side side)
	{
		INSTANCE.registerMessage(messageHandler, requestMessageType, count, side);
		count++;
	}
	
	public SimpleNetworkWrapper instance()
	{
		return INSTANCE;
	}

	public void inc()
	{
		count++;
	}
}

 

Basic Packet Class (Its used as a base for the actual packets):

package stucuk.square.packets;

import io.netty.buffer.ByteBuf;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.EntityPlayerMP;
import net.minecraftforge.fml.client.FMLClientHandler;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

public class MCBasicPacket implements IMessage {
	
	public void handlePacket(EntityPlayer player, Side side)
	{
		//
	}
	
	@Override
	public void fromBytes(ByteBuf buffer) {
		//
	}

	@Override
	public void toBytes(ByteBuf buffer) {
		//
	}
	
	@SideOnly(Side.CLIENT)
	public void hpc(MessageContext ctx)
	{
		handlePacket(FMLClientHandler.instance().getClient().thePlayer,ctx.side);
	}
	
	public void onMessage(MessageContext ctx) {
		
    	switch (ctx.side)
    	{
        	case CLIENT:
        		hpc(ctx);
        		break;

        	case SERVER:
        		handlePacket(ctx.getServerHandler().playerEntity,ctx.side);
        		break;

        	default:
    	}
	}
    
    public static void sendToServer(IMessage packet)
    {
    	MCPacketSystem.instance().sendToServer(packet);
    }
    
    public static void sendToPlayer(IMessage packet, EntityPlayerMP player)
    {
    	MCPacketSystem.instance().sendTo(packet, player);
    }
}

 

The actual packet class:

package stucuk.square.packets;

import java.io.IOException;

import stucuk.square.interfaces.IGUIPacketHandler;
import io.netty.buffer.ByteBuf;
import net.minecraft.block.Block;
import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.network.PacketBuffer;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.math.BlockPos;
import net.minecraftforge.fml.common.network.simpleimpl.IMessage;
import net.minecraftforge.fml.common.network.simpleimpl.IMessageHandler;
import net.minecraftforge.fml.common.network.simpleimpl.MessageContext;
import net.minecraftforge.fml.relauncher.Side;

public class PacketGUI_ClientToServer extends MCBasicPacket implements IMessage, IMessageHandler<PacketGUI_ClientToServer, IMessage> {

	private int x,y,z;
	private short value;
	private long value64;
	private float valueF;
	private ItemStack valueStack;
	private byte extra;
	private byte datatype;
	
	@Override
	public IMessage onMessage(PacketGUI_ClientToServer message, MessageContext ctx) {
		message.onMessage(ctx);
		return null;
	}
	
	public PacketGUI_ClientToServer(){
		
	}
	
    public PacketGUI_ClientToServer(int x, int y, int z, short value, byte extra){
		this.x     = x;
		this.y     = y;
		this.z     = z;
		this.value = value;
		this.extra = extra;
		this.datatype = 0;
	}
    
    public PacketGUI_ClientToServer(int x, int y, int z, long value64, byte extra){
		this.x     = x;
		this.y     = y;
		this.z     = z;
		this.value64 = value64;
		this.extra = extra;
		this.datatype = 1;
	}
    
    public PacketGUI_ClientToServer(int x, int y, int z, float valueF, byte extra){
		this.x     = x;
		this.y     = y;
		this.z     = z;
		this.valueF = valueF;
		this.extra = extra;
		this.datatype = 2;
	}
    
    public PacketGUI_ClientToServer(int x, int y, int z, ItemStack valueStack, byte extra){
		this.x     = x;
		this.y     = y;
		this.z     = z;
		this.valueStack = valueStack;
		this.extra = extra;
		this.datatype = 3;
	}
	
	@Override
	public void toBytes(ByteBuf buffer) {
		buffer.writeInt(x);
		buffer.writeInt(y);
		buffer.writeInt(z);
		buffer.writeByte(extra);
		
		buffer.writeByte(datatype);
		
		if (this.datatype == 0)
			buffer.writeShort(value);
		else
		if (this.datatype == 1)
			buffer.writeLong(value64);
		else
		if (this.datatype == 2)
			buffer.writeFloat(valueF);
		else
		if (this.datatype == 3)
		{
			PacketBuffer pb = new PacketBuffer(buffer);
			pb.writeItemStackToBuffer(valueStack);
		}
	}
	@Override
	public void fromBytes(ByteBuf buffer) {
		x     = buffer.readInt();
		y     = buffer.readInt();
		z     = buffer.readInt();
		extra = buffer.readByte();
		
		datatype = buffer.readByte();
		
		if (datatype == 0)
			value = buffer.readShort();
		else
		if (datatype == 1)
			value64 = buffer.readLong();
		else
		if (datatype == 2)
			valueF = buffer.readFloat();
		else
		if (datatype == 3)
		{
			PacketBuffer pb = new PacketBuffer(buffer);
			try {
				valueStack = pb.readItemStackFromBuffer();
			} catch (IOException e) {
				e.printStackTrace();
			}
		}
	}

	public void blockHandlePacket(TileEntity te, EntityPlayer player, BlockPos pos, long value, byte extra)
	{
        	((IGUIPacketHandler)te).HandleGUIPacket(player,pos,value,extra);
	}
	
	public void blockHandlePacket(TileEntity te, EntityPlayer player, BlockPos pos, float value, byte extra)
	{
        	((IGUIPacketHandler)te).HandleGUIPacket_Float(player,pos,value,extra);
	}
	
	public void blockHandlePacket(TileEntity te, EntityPlayer player, BlockPos pos, ItemStack value, byte extra)
	{
        	((IGUIPacketHandler)te).HandleGUIPacket_ItemStack(player,pos,value,extra);
	}
	
	@Override
	public void handlePacket(EntityPlayer player, Side side)
	{
		BlockPos pos = new BlockPos(x,y,z);		
		TileEntity te = player.worldObj.getTileEntity(pos);
		
		if (!(te instanceof IGUIPacketHandler))
			return;
        
		switch (this.datatype)
		{
			case (0):
				blockHandlePacket(te, player, pos, value, extra);
				break;
			case (1):
				blockHandlePacket(te, player, pos, value64, extra);
				break;
			case (2):
				blockHandlePacket(te, player, pos, valueF, extra);
				break;
			case (3):
				blockHandlePacket(te, player, pos, valueStack, extra);
				break;
		}
	}
	
	public static void sendShort(int x, int y, int z, short value, byte extra)
	{
		sendToServer(new PacketGUI_ClientToServer(x,y,z,value,extra));
	}
	
	public static void sendShort(int x, int y, int z, short value)
	{
		sendShort(x,y,z,value,(byte)0);
	}
	
	public static void sendLong(int x, int y, int z, long value, byte extra)
	{
		sendToServer(new PacketGUI_ClientToServer(x,y,z,value,extra));
	}
	
	public static void sendLong(int x, int y, int z, long value)
	{
		sendLong(x,y,z,value,(byte)0);
	}
	
	public static void sendFloat(int x, int y, int z, float value, byte extra)
	{
		sendToServer(new PacketGUI_ClientToServer(x,y,z,value,extra));
	}
	
	public static void sendFloat(int x, int y, int z, float value)
	{
		sendFloat(x,y,z,value,(byte)0);
	}
	
	public static void sendItemStack(int x, int y, int z, ItemStack value, byte extra)
	{
		sendToServer(new PacketGUI_ClientToServer(x,y,z,value,extra));
	}
	
	public static void sendItemStack(int x, int y, int z, ItemStack value)
	{
		sendItemStack(x,y,z,value,(byte)0);
	}
}

 

The IGUIPacketHandler needs to be implemented in the TileEntity:

package stucuk.square.interfaces;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.item.ItemStack;
import net.minecraft.util.math.BlockPos;

public interface IGUIPacketHandler {
	public void HandleGUIPacket(EntityPlayer player, BlockPos pos, long value, byte extra);
	public void HandleGUIPacket_Float(EntityPlayer player, BlockPos pos, float value, byte extra);
	public void HandleGUIPacket_ItemStack(EntityPlayer player, BlockPos pos, ItemStack value, byte extra);
}

 

Example code for TileEntity:

public class BaseTileRedstone extends BaseTile implements IGUIPacketHandler {

@Override
	public void HandleGUIPacket(EntityPlayer player, BlockPos pos, long value, byte extra)
	{
		//Do Something! Short and Long values go here!
	}

	@Override
	public void HandleGUIPacket_Float(EntityPlayer player, BlockPos pos, float value, byte extra)
	{

	}

	@Override
	public void HandleGUIPacket_ItemStack(EntityPlayer player, BlockPos pos, ItemStack value, byte extra)
	{
		
	}

}

 

Registering packets:

MCPacketSystem.instance().registerPacket(PacketGUI_ClientToServer.class, PacketGUI_ClientToServer.class, Side.SERVER);

 

Usage in a GUIContainer (x,y,z needs to be the coordinates of the TileEntity):

PacketGUI_ClientToServer.sendShort(x, y, z, value, extra);

 

note that the extra value doesn't need to be passed (defaults to 0), its basically an id which is useful if you need to send more than 1 value to a TileEntity as you can identify what each number sent is for.

Posted
1 minute ago, diesieben07 said:

 

@stucuk Sorry, but I am not sure how your post is supposed to be helpful. Just presenting a solution (and a not-great one at that) and saying "here use this" is not very useful in my opinion. If you want I will elaborate as to why your solution is not great.

People can learn from others code. I know from experience looking at actual code rather than being told the name of certain things is alot easier to understand when you can see the "Big Picture". Everything i posted is self contained clean code.

 

Who wouldn't want to know why their solution isn't good?

Posted (edited)
4 hours ago, diesieben07 said:

True. But without explanation using someone else's code very quickly turns into cargo-culting.

 

Exactly. And that is why it invites people who are new to just copy-paste it and run with it. The aforementioned cargo-culting.

I don't think any of what i posted really needed an explanation, everything uses descriptive function/variable names which should mean self-explanatory code(People can always ask questions if they don't understand something). Cargo-cutting behaviour happens because people are impatient or lazy which will also happen when you tell them about a tutorial, which they will ignore all the descriptive text and go to the code at the bottom of it. So its a catch 22.

 

4 hours ago, diesieben07 said:

Your packet is trying to be "universal", but this leads to very clunky code. You should have one packet dedicated to each purpose, don't try to make a "one size fits all" packet, we have packet types for a reason.

 

I don't see how its bad to group it into a single packet when its just related to a single task. Overall the code is smaller with less duplication than a single packet for each. You would never want a single packet for everything but optimising code is generally a good idea when its applicable to the situation.

 

P.S I won't post further about this as this post is technically off topic and i don't want to derail further (This is a notification of intent rather than a "Please don't post after me").

Edited by stucuk
Posted

Okay everyone. I've managed to get my problems down to two singular problems. First:

How do i get the BlockPos or specific tile entity instance into the GUI class?

Second: how does EntityPlayer::openGui work? also, double semicolons don't seem to work, so I have the statement as playerIn.openGui(SpaceHeaterMod.mod, ? what do i do with this "guiID", worldIn, pos.getX(), pos.getY(), pos.getZ());

 

how do i get a guiID? it says in the comment that it uses Forge's IGuiHandler system. Where can I apply an ID to my GUI? Or have I got the entirely wrong thing?

Posted (edited)
48 minutes ago, its_meow said:

how do i get a guiID?

You make it up. Each Mod handles its own guiID's, which is why you provide the mods instance. Your IGuiHandler basically selects the appropriate Container/GUIContainer based on the guiID you specified.

 

If it makes it any easier you could think of loordgek's code with numbers instead of enums:

public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
        TileEntity tile = world.getTileEntity(new BlockPos(x, y, z)); // Get the Tile Entity!
        switch (ID) { //Which GUI do we want?
            case 0:
                return new ContainerUpgrade(player, (TileGenBase) tile); //We want GUI 0
            case 1:
                return new ContainerFurnaceGen(player, (TileFurnaceGen) tile); //We want GUI 1
        }
        return null; // ID was invalid... return null.
}

 

If you wanted the FurnaceGen GUI you would do:

playerIn.openGui(SpaceHeaterMod.mod, 1 , worldIn, pos.getX(), pos.getY(), pos.getZ());

 

Since your passing the TileEntity to the container, you can use it to get the X/Y/Z coordinates when sending packets from the client to the server. Loordgek's GuiFurnaceGen stores the passed TileEntity in its self.

Edited by stucuk
Posted (edited)

Okay. New main problem. The code works, up until the GuiHandler tries to define the tileEntity.

It picks up the x y z, turns it into a blockpos, and runs

world.getTileEntity(blockpos);

the problem is, by printing that, I see that it returns NULL.. It makes NO sense.

I'm sure it has the right coordinates and blockpos, they both print and I check the coord and it's exactly where my block is, but it won't find it.

 

EDIT: I now notice this may have something to do with the fact that the client is executing this. But, HOW is the server supposed to execute a GUI? I'm lost.

Edited by its_meow
Posted

Are you sure the tile entity is actually being created? If there is no TileEntity being created it will return null when you try and get it.

 

 

The onBlockActivated is called on both client and server, though as diesieben07 sais you want to call it on the server side.

 

public boolean onBlockActivated(World world, BlockPos pos, IBlockState state, EntityPlayer player, EnumHand hand, @Nullable ItemStack heldItem, EnumFacing side, float hitX, float hitY, float hitZ)
{
	if(!world.isRemote)
		player.openGui(SpaceHeaterMod.mod, 1 , world, pos.getX(), pos.getY(), pos.getZ());
    	
	return true;
}

 

If we look at a trimmed down IGuiHandler you can see it specifies a bit for server and client. Forge does all the work at deciding which is called. You just tell it what to open and it then calls getServerGuiElement or getClientElement when needed:

 

public class GuiHander implements IGuiHandler {

    @Override
    public Object getServerGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
        return null; // We return a Server GUI Here (one that extends Container)
    }

    @Override
    public Object getClientGuiElement(int ID, EntityPlayer player, World world, int x, int y, int z) {
        return null; // We return a Client GUI Here (one that extends GUIContainer)
    }
}

 

Posted (edited)

I Figured it out.

deisie, my block has to extend BlockContainer, those methods weren't making the tileEntity for some reason

 

EDIT: I also know each GUI and GUI value are unique now  because when it prints the tilentity it has an @ (randomid)

I just need to adjust some math in my GUI and it should be almost ready

 

I may have just one more issue though if the light value isn't working right

Edited by its_meow
Posted
Just now, diesieben07 said:

Then you are doing something wrong. BlockContainer is old and legacy.

Well then how do I get it to create a tileEntity? because those overidden methods aren't doing anything.

Posted (edited)

im guessing that the following is still the way to do things:

public class SomeClassName extends Block implements ITileEntityProvider {
	@Override
	public TileEntity createNewTileEntity(World worldIn, int meta)
	{
		return new SomeTileEntityClass(someparameters);
	}
}

 

Edited by stucuk
Posted (edited)
6 minutes ago, stucuk said:

im guessing that the following is still the way to do things:


public class SomeClassName extends Block implements ITileEntityProvider {
@Override
	public TileEntity createNewTileEntity(World worldIn, int meta)
	{
		return new SomeTileEntityClass(someparameters);
	}
}

 

Yeah.

Also, I have a similar thing to your packet system, but do I have to register IGuiPacketHandler somewhere? because the packet isn't being recieved by the handler in the tileenity

EDIT:

Okay, it is registered in the Packet file, which is registered as the Handler in the manager, but it's not working... hm

Edited by its_meow
Posted
Just now, diesieben07 said:

No, it is not. Do not implement ITileEntityProvider. Override hasTileEntity and createTileEntity.

I had it like that, and the tile entity was just null.

It looked like this :

@Override
	public boolean hasTileEntity() {
		return true;
	}
	
	@Override
	public TileEntity createTileEntity(World world, IBlockState state) {
		return new TileEntitySpaceHeater();
	}

 

Posted (edited)
Just now, diesieben07 said:

So you completely ignored the deprecation warning on hasTileEntity(). Good for you, don't expect things to work then. Seriously, why do people just not pay attention? There is a giant fucking line through it, does that scream "Please use me, this is the method you want!" to you? Or what? Seriously, I am trying to figure this out.

 

8tBm8nv.png

Yup, checks out. This looks totally fine and totally not like it could cause problems.

That's what it looks like in my block.

you're the one that told me to override it?

Edited by its_meow
Posted
10 minutes ago, its_meow said:

Yeah.

Also, I have a similar thing to your packet system, but do I have to register IGuiPacketHandler somewhere? because the packet isn't being recieved by the handler in the tileenity

Assuming you have the same basic code as i posted for my packets handlepacket bit, In your TileEntity you need to implement it in the implements bit.

 

I.E:

public class BaseTileRedstone extends BaseTile implements IGUIPacketHandler {

	@Override
	public void HandleGUIPacket(EntityPlayer player, BlockPos pos, long value, byte extra)
	{
		//Do Something! Short and Long values go here!
	}

	@Override
	public void HandleGUIPacket_Float(EntityPlayer player, BlockPos pos, float value, byte extra)
	{

	}

	@Override
	public void HandleGUIPacket_ItemStack(EntityPlayer player, BlockPos pos, ItemStack value, byte extra)
	{
		
	}

}

 

Interfaces which the IGUIPacketHandler is, basically lay out stuff a thing should have. When you use the implements bit your stating what interfaces that class supports (Well implements). You can then treat that class as if it was that interface.

 

Basically it allows you to do:

TileEntity te = new MyTileEntity();


if (te instanceof IGUIPacketHandler) //Check its actually implemented the interface
{
	((IGUIPacketHandler)te).HandleGUIPacket(player,pos,1,0); //we can now treat the TileEntity as if it was a IGUIPacketHandler
}

 

 

Posted (edited)
3 minutes ago, diesieben07 said:

Yes, I told you to override hasTileEntity. But that assumed that you apply some common sense and choose the obviously right one, the one that does not have a giant "do not use me" line through it:

 

cwFnSZu.png

I don't have a thing that tells me which one to choose when I override, I just have to type it in, so I had no idea

 

EDIT: Plus, eclipse override/implement method doesn't tell you if it's deprecated. At all.

 

Edited by its_meow
Posted
Just now, stucuk said:

In the guys defensive i never even knew you could get the IDE to generate an override method using the AutoComplete feature. Iv been playing with it since 2014 (And other languages for alot longer).

You have to go in eclipse keybinds and search for Override/Implement and set a shortcut. IDEA i think already has it as a shortcut.

Posted
3 minutes ago, diesieben07 said:

Or at least look at the parent class

Quite.

Apparently I'm a complete and utter jerk and come to this forum just like to make fun of people, be confrontational, and make your personal life miserable.  If you think this is the case, JUST REPORT ME.  Otherwise you're just going to get reported when you reply to my posts and point it out, because odds are, I was trying to be nice.

 

Exception: If you do not understand Java, I WILL NOT HELP YOU and your thread will get locked.

 

DO NOT PM ME WITH PROBLEMS. No help will be given.

Posted
1 minute ago, its_meow said:

You have to go in eclipse keybinds and search for Override/Implement and set a shortcut. IDEA i think already has it as a shortcut.

I use eclipse and never have touched the keybindings. By Autocomplete i mean the CTRL+SPACE thing. I just didn't know you could do it for actual method overrides.

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

    • Version 1.19 - Forge 41.0.63 I want to create a wolf entity that I can ride, so far it seems to be working, but the problem is that when I get on the wolf, I can’t control it. I then discovered that the issue is that the server doesn’t detect that I’m riding the wolf, so I’m struggling with synchronization. However, it seems to not be working properly. As I understand it, the server receives the packet but doesn’t register it correctly. I’m a bit new to Java, and I’ll try to provide all the relevant code and prints *The comments and prints are translated by chatgpt since they were originally in Spanish* Thank you very much in advance No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. No player is mounted, or the passenger is not a player. MountableWolfEntity package com.vals.valscraft.entity; import com.vals.valscraft.network.MountSyncPacket; import com.vals.valscraft.network.NetworkHandler; import net.minecraft.client.Minecraft; import net.minecraft.network.syncher.EntityDataAccessor; import net.minecraft.network.syncher.EntityDataSerializers; import net.minecraft.network.syncher.SynchedEntityData; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.EntityType; import net.minecraft.world.entity.Mob; import net.minecraft.world.entity.ai.attributes.AttributeSupplier; import net.minecraft.world.entity.ai.attributes.Attributes; import net.minecraft.world.entity.animal.Wolf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.entity.Entity; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; import net.minecraft.world.level.Level; import net.minecraft.world.phys.Vec3; import net.minecraftforge.event.TickEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.network.PacketDistributor; public class MountableWolfEntity extends Wolf { private boolean hasSaddle; private static final EntityDataAccessor<Byte> DATA_ID_FLAGS = SynchedEntityData.defineId(MountableWolfEntity.class, EntityDataSerializers.BYTE); public MountableWolfEntity(EntityType<? extends Wolf> type, Level level) { super(type, level); this.hasSaddle = false; } @Override protected void defineSynchedData() { super.defineSynchedData(); this.entityData.define(DATA_ID_FLAGS, (byte)0); } public static AttributeSupplier.Builder createAttributes() { return Wolf.createAttributes() .add(Attributes.MAX_HEALTH, 20.0) .add(Attributes.MOVEMENT_SPEED, 0.3); } @Override public InteractionResult mobInteract(Player player, InteractionHand hand) { ItemStack itemstack = player.getItemInHand(hand); if (itemstack.getItem() == Items.SADDLE && !this.hasSaddle()) { if (!player.isCreative()) { itemstack.shrink(1); } this.setSaddle(true); return InteractionResult.SUCCESS; } else if (!level.isClientSide && this.hasSaddle()) { player.startRiding(this); MountSyncPacket packet = new MountSyncPacket(true); // 'true' means the player is mounted NetworkHandler.CHANNEL.sendToServer(packet); // Ensure the server handles the packet return InteractionResult.SUCCESS; } return InteractionResult.PASS; } @Override public void travel(Vec3 travelVector) { if (this.isVehicle() && this.getControllingPassenger() instanceof Player) { System.out.println("The wolf has a passenger."); System.out.println("The passenger is a player."); Player player = (Player) this.getControllingPassenger(); // Ensure the player is the controller this.setYRot(player.getYRot()); this.yRotO = this.getYRot(); this.setXRot(player.getXRot() * 0.5F); this.setRot(this.getYRot(), this.getXRot()); this.yBodyRot = this.getYRot(); this.yHeadRot = this.yBodyRot; float forward = player.zza; float strafe = player.xxa; if (forward <= 0.0F) { forward *= 0.25F; } this.flyingSpeed = this.getSpeed() * 0.1F; this.setSpeed((float) this.getAttributeValue(Attributes.MOVEMENT_SPEED) * 1.5F); this.setDeltaMovement(new Vec3(strafe, travelVector.y, forward).scale(this.getSpeed())); this.calculateEntityAnimation(this, false); } else { // The wolf does not have a passenger or the passenger is not a player System.out.println("No player is mounted, or the passenger is not a player."); super.travel(travelVector); } } public boolean hasSaddle() { return this.hasSaddle; } public void setSaddle(boolean hasSaddle) { this.hasSaddle = hasSaddle; } @Override protected void dropEquipment() { super.dropEquipment(); if (this.hasSaddle()) { this.spawnAtLocation(Items.SADDLE); this.setSaddle(false); } } @SubscribeEvent public static void onServerTick(TickEvent.ServerTickEvent event) { if (event.phase == TickEvent.Phase.START) { MinecraftServer server = net.minecraftforge.server.ServerLifecycleHooks.getCurrentServer(); if (server != null) { for (ServerPlayer player : server.getPlayerList().getPlayers()) { if (player.isPassenger() && player.getVehicle() instanceof MountableWolfEntity) { MountableWolfEntity wolf = (MountableWolfEntity) player.getVehicle(); System.out.println("Tick: " + player.getName().getString() + " is correctly mounted on " + wolf); } } } } } private boolean lastMountedState = false; @Override public void tick() { super.tick(); if (!this.level.isClientSide) { // Only on the server boolean isMounted = this.isVehicle() && this.getControllingPassenger() instanceof Player; // Only print if the state changed if (isMounted != lastMountedState) { if (isMounted) { Player player = (Player) this.getControllingPassenger(); // Verify the passenger is a player System.out.println("Server: Player " + player.getName().getString() + " is now mounted."); } else { System.out.println("Server: The wolf no longer has a passenger."); } lastMountedState = isMounted; } } } @Override public void addPassenger(Entity passenger) { super.addPassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(true)); } } } @Override public void removePassenger(Entity passenger) { super.removePassenger(passenger); if (passenger instanceof Player) { Player player = (Player) passenger; if (!this.level.isClientSide && player instanceof ServerPlayer) { // Send the packet to the server to indicate the player is no longer mounted NetworkHandler.CHANNEL.send(PacketDistributor.PLAYER.with(() -> (ServerPlayer) player), new MountSyncPacket(false)); } } } @Override public boolean isControlledByLocalInstance() { Entity entity = this.getControllingPassenger(); return entity instanceof Player; } @Override public void positionRider(Entity passenger) { if (this.hasPassenger(passenger)) { double xOffset = Math.cos(Math.toRadians(this.getYRot() + 90)) * 0.4; double zOffset = Math.sin(Math.toRadians(this.getYRot() + 90)) * 0.4; passenger.setPos(this.getX() + xOffset, this.getY() + this.getPassengersRidingOffset() + passenger.getMyRidingOffset(), this.getZ() + zOffset); } } } MountSyncPacket package com.vals.valscraft.network; import com.vals.valscraft.entity.MountableWolfEntity; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.server.level.ServerLevel; import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class MountSyncPacket { private final boolean isMounted; public MountSyncPacket(boolean isMounted) { this.isMounted = isMounted; } public void encode(FriendlyByteBuf buffer) { buffer.writeBoolean(isMounted); } public static MountSyncPacket decode(FriendlyByteBuf buffer) { return new MountSyncPacket(buffer.readBoolean()); } public void handle(NetworkEvent.Context context) { context.enqueueWork(() -> { ServerPlayer player = context.getSender(); // Get the player from the context if (player != null) { // Verifies if the player has dismounted if (!isMounted) { Entity vehicle = player.getVehicle(); if (vehicle instanceof MountableWolfEntity wolf) { // Logic to remove the player as a passenger wolf.removePassenger(player); System.out.println("Server: Player " + player.getName().getString() + " is no longer mounted."); } } } }); context.setPacketHandled(true); // Marks the packet as handled } } networkHandler package com.vals.valscraft.network; import com.vals.valscraft.valscraft; import net.minecraft.resources.ResourceLocation; import net.minecraftforge.network.NetworkRegistry; import net.minecraftforge.network.simple.SimpleChannel; import net.minecraftforge.network.NetworkEvent; import java.util.function.Supplier; public class NetworkHandler { private static final String PROTOCOL_VERSION = "1"; public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel( new ResourceLocation(valscraft.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals, PROTOCOL_VERSION::equals ); public static void init() { int packetId = 0; // Register the mount synchronization packet CHANNEL.registerMessage( packetId++, MountSyncPacket.class, MountSyncPacket::encode, MountSyncPacket::decode, (msg, context) -> msg.handle(context.get()) // Get the context with context.get() ); } }  
    • Do you use features of inventory profiles next (ipnext) or is there a change without it?
    • Remove rubidium - you are already using embeddium, which is a fork of rubidium
  • Topics

  • Who's Online (See full list)

×
×
  • Create New...

Important Information

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