Jump to content

Recommended Posts

Posted

Doesn't seem to have worked.  And it got marked dirty when the frequency is set so it would've notice it there, but I did add it to an override method onGuiClosed() and it doesn't seem to have changed it.

 

Am I not writing to the NBT properly, or am I not writing to the actual tile entity?

Posted

How would I go about that though.  Should I access the container that is the superclass of GuiContainer, since that half of it is server side?  Would changing that tile entity work? (Assuming I make it accessible by the guicontainer)

Posted
  On 5/4/2015 at 4:24 PM, diesieben07 said:

  Quote

See the link... you need to send description packets..

No, this is not the issue here. Description packets go server to client.

Oh... fact...  :P

 

If the action is defined in the button see the part of client>server packet with the enchant button(It's for 1.7.10, maybe work for 1.8... ): http://www.minecraftforge.net/wiki/Tile_Entity_Synchronization

// BSc CIS, hardcore gamer and a big fan of Minecraft.

 

TmzOS ::..

Posted

So I add an override enchantItem() into the Container.  I assume I ned to put

 

this.mc.playerController.sendEnchantPacket(container.windowId, action);

 

Into the GuiContainer.  But how do I access the container to get the windowId from the GuiContainer?

 

 

Edit:  I also tried doing this.wirelessChestEntity.freq(4000); in the onContainerClosed just to force it to do something on the container, and it still only is changed for the duration I'm in the game.  If I save and quit, it still resets to 0.

Posted

Hi

 

These links might help a bit with the background logic behind TileEntities and especially Containers

 

http://greyminecraftcoder.blogspot.com.au/2015/01/tileentity.html

http://greyminecraftcoder.blogspot.com.au/2015/01/gui-containers.html

 

Simple information can be sent from the server container to the client container using the crafters member variable of the container - icrafting.sendProgressBarUpdate() and icrafting.updateProgressBar() - if you are just sending a single number.

 

This tutorial project has a working example for 1.8, almost identical for 1.7.10.

https://github.com/TheGreyGhost/MinecraftByExample/tree/master/src/main/java/minecraftbyexample/mbe31_inventory_furnace

and especially

 

/* Client Synchronization */

// This is where you check if any values have changed and if so send an update to any clients accessing this container
// The container itemstacks are tested in Container.detectAndSendChanges, so we don't need to do that
// We iterate through all of the TileEntity Fields to find any which have changed, and send them.
// You don't have to use fields if you don't wish to; just manually match the ID in sendProgressBarUpdate with the value in
//   updateProgressBar()
// The progress bar values are restricted to shorts.  If you have a larger value (eg int), it's not a good idea to try and split it
//   up into two shorts because the progress bar values are sent independently, and unless you add synchronisation logic at the
//   receiving side, your int value will be wrong until the second short arrives.  Use a custom packet instead.
@Override
public void detectAndSendChanges() {
	super.detectAndSendChanges();

	boolean allFieldsHaveChanged = false;
	boolean fieldHasChanged [] = new boolean[tileInventoryFurnace.getFieldCount()];
	if (cachedFields == null) {
		cachedFields = new int[tileInventoryFurnace.getFieldCount()];
		allFieldsHaveChanged = true;
	}
	for (int i = 0; i < cachedFields.length; ++i) {
		if (allFieldsHaveChanged || cachedFields[i] != tileInventoryFurnace.getField(i)) {
			cachedFields[i] = tileInventoryFurnace.getField(i);
			fieldHasChanged[i] = true;
		}
	}

	// go through the list of crafters (players using this container) and update them if necessary
	for (int i = 0; i < this.crafters.size(); ++i) {
		ICrafting icrafting = (ICrafting)this.crafters.get(i);
		for (int fieldID = 0; fieldID < tileInventoryFurnace.getFieldCount(); ++fieldID) {
			if (fieldHasChanged[fieldID]) {
				// Note that although sendProgressBarUpdate takes 2 ints on a server these are truncated to shorts
				icrafting.sendProgressBarUpdate(this, fieldID, cachedFields[fieldID]);
			}
		}
	}
}

// Called when a progress bar update is received from the server. The two values (id and data) are the same two
// values given to sendProgressBarUpdate.  In this case we are using fields so we just pass them to the tileEntity.
@SideOnly(Side.CLIENT)
@Override
public void updateProgressBar(int id, int data) {
	tileInventoryFurnace.setField(id, data);
}

 

-TGG

 

 

 

Posted

So what I currently have is

 

Entity:

package com.cclloyd.ccmodpack;

import java.util.Arrays;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.inventory.IInventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.nbt.NBTTagList;
import net.minecraft.tileentity.TileEntity;
import net.minecraft.util.ChatComponentText;
import net.minecraft.util.ChatComponentTranslation;
import net.minecraft.util.IChatComponent;

public class WirelessChestEntity extends TileEntity implements IInventory {

/**
 * This is a simple tile entity implementing IInventory that can store 9 item stacks
 */

// Create and initialize the items variable that will store store the items
final int NUMBER_OF_SLOTS = 27;
private ItemStack[] itemStacks = new ItemStack[NUMBER_OF_SLOTS];
private int frequency = 0;
public final static String name = "wirelessChestEntity";

public WirelessChestEntity() {
	this.frequency = 0;
}

public int getFreq() {
	return this.frequency;
}

public String getFreqStr() {
	return Integer.toString(this.frequency);
}

public void setFreq(int freq) {
	this.frequency = freq;
	markDirty();
}

/* The following are some IInventory methods you are required to override */

// Gets the number of slots in the inventory
@Override
public int getSizeInventory() {
	return itemStacks.length;
}

// Gets the stack in the given slot
@Override
public ItemStack getStackInSlot(int slotIndex) {
	return itemStacks[slotIndex];
}

/**
 * Removes some of the units from itemstack in the given slot, and returns as a separate itemstack
	 * @param slotIndex the slot number to remove the items from
 * @param count the number of units to remove
 * @return a new itemstack containing the units removed from the slot
 */
@Override
public ItemStack decrStackSize(int slotIndex, int count) {
	ItemStack itemStackInSlot = getStackInSlot(slotIndex);
	if (itemStackInSlot == null) return null;

	ItemStack itemStackRemoved;
	if (itemStackInSlot.stackSize <= count) {
		itemStackRemoved = itemStackInSlot;
		setInventorySlotContents(slotIndex, null);
	} else {
		itemStackRemoved = itemStackInSlot.splitStack(count);
		if (itemStackInSlot.stackSize == 0) {
			setInventorySlotContents(slotIndex, null);
		}
	}
  markDirty();
	return itemStackRemoved;
}

// overwrites the stack in the given slotIndex with the given stack
@Override
public void setInventorySlotContents(int slotIndex, ItemStack itemstack) {
	itemStacks[slotIndex] = itemstack;
	if (itemstack != null && itemstack.stackSize > getInventoryStackLimit()) {
		itemstack.stackSize = getInventoryStackLimit();
	}
	markDirty();
}

// This is the maximum number if items allowed in each slot
// This only affects things such as hoppers trying to insert items you need to use the container to enforce this for players
// inserting items via the gui
@Override
public int getInventoryStackLimit() {
	return 64;
}

// Return true if the given player is able to use this block. In this case it checks that
// 1) the world tileentity hasn't been replaced in the meantime, and
// 2) the player isn't too far away from the centre of the block
@Override
public boolean isUseableByPlayer(EntityPlayer player) {
	if (this.worldObj.getTileEntity(this.pos) != this) return false;
	final double X_CENTRE_OFFSET = 0.5;
	final double Y_CENTRE_OFFSET = 0.5;
	final double Z_CENTRE_OFFSET = 0.5;
	final double MAXIMUM_DISTANCE_SQ = 8.0 * 8.0;
	return player.getDistanceSq(pos.getX() + X_CENTRE_OFFSET, pos.getY() + Y_CENTRE_OFFSET, pos.getZ() + Z_CENTRE_OFFSET) < MAXIMUM_DISTANCE_SQ;
}

// Return true if the given stack is allowed to go in the given slot.  In this case, we can insert anything.
// This only affects things such as hoppers trying to insert items you need to use the container to enforce this for players
// inserting items via the gui
@Override
public boolean isItemValidForSlot(int slotIndex, ItemStack itemstack) {
	return true;
}

// This is where you save any data that you don't want to lose when the tile entity unloads
// In this case, it saves the itemstacks stored in the container
@Override
public void writeToNBT(NBTTagCompound parentNBTTagCompound)
{
	super.writeToNBT(parentNBTTagCompound); // The super call is required to save and load the tileEntity's location

	// to use an analogy with Java, this code generates an array of hashmaps
	// The itemStack in each slot is converted to an NBTTagCompound, which is effectively a hashmap of key->value pairs such
	//   as slot=1, id=2353, count=1, etc
	// Each of these NBTTagCompound are then inserted into NBTTagList, which is similar to an array.
	parentNBTTagCompound.setInteger("ChestFrequency", this.frequency);

	NBTTagList dataForAllSlots = new NBTTagList();
	for (int i = 0; i < this.itemStacks.length; ++i) {
		if (this.itemStacks[i] != null)	{
			NBTTagCompound dataForThisSlot = new NBTTagCompound();
			dataForThisSlot.setByte("Slot", (byte) i);
			this.itemStacks[i].writeToNBT(dataForThisSlot);
			dataForAllSlots.appendTag(dataForThisSlot);
		}
	}
	parentNBTTagCompound.setTag("Items", dataForAllSlots);


}


// This is where you load the data that you saved in writeToNBT
@Override
public void readFromNBT(NBTTagCompound parentNBTTagCompound)
{
	super.readFromNBT(parentNBTTagCompound); // The super call is required to save and load the tiles location
	final byte NBT_TYPE_COMPOUND = 10;       // See NBTBase.createNewByType() for a listing
	NBTTagList dataForAllSlots = parentNBTTagCompound.getTagList("Items", NBT_TYPE_COMPOUND);

	this.frequency = parentNBTTagCompound.getInteger("ChestFrequency");

	Arrays.fill(itemStacks, null);           // set all slots to empty
	for (int i = 0; i < dataForAllSlots.tagCount(); ++i) {
		NBTTagCompound dataForOneSlot = dataForAllSlots.getCompoundTagAt(i);
		int slotIndex = dataForOneSlot.getByte("Slot") & 255;

		if (slotIndex >= 0 && slotIndex < this.itemStacks.length) {
			this.itemStacks[slotIndex] = ItemStack.loadItemStackFromNBT(dataForOneSlot);
		}
	}


}

// set all slots to empty
@Override
public void clear() {
	Arrays.fill(itemStacks, null);
}

// will add a key for this container to the lang file so we can name it in the GUI
@Override
public String getName() {
	return "container.wirelessChestEntity.name";
}

@Override
public boolean hasCustomName() {
	return false;
}

// standard code to look up what the human-readable name is
@Override
public IChatComponent getDisplayName() {
	return this.hasCustomName() ? new ChatComponentText(this.getName()) : new ChatComponentTranslation(this.getName());
}

// -----------------------------------------------------------------------------------------------------------
// The following methods are not needed for this example but are part of IInventory so they must be implemented

/**
 * This method removes the entire contents of the given slot and returns it.
 * Used by containers such as crafting tables which return any items in their slots when you close the GUI
 * @param slotIndex
 * @return
 */
@Override
public ItemStack getStackInSlotOnClosing(int slotIndex) {
	ItemStack itemStack = getStackInSlot(slotIndex);
	if (itemStack != null) setInventorySlotContents(slotIndex, null);
	return itemStack;
}

@Override
public void openInventory(EntityPlayer player) {}

@Override
public void closeInventory(EntityPlayer player) {}

@Override
public int getField(int id) {
	return 0;
}

@Override
public void setField(int id, int value) {
	if (id == 9000)
			this.frequency = value;
}

@Override
public int getFieldCount() {
	return 0;
}

/*
@Override
public String getGuiId() {
	return CCModpack.MODID + "_" + WirelessChest.name;
}*/
}

 

 

Container:

package com.cclloyd.ccmodpack;

import net.minecraft.entity.player.EntityPlayer;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.inventory.Slot;
import net.minecraft.item.ItemStack;

public class WirelessChestContainer extends Container {

/**
 * The container is used to link the client side gui to the server side inventory and it is where
 * you add the slots to your gui. It can also be used to sync server side data with the client but
 * that will be covered in a later tutorial
 */

// Stores a reference to the tile entity instance for later use
public WirelessChestEntity wirelessChestEntity;


// must assign a slot number to each of the slots used by the GUI.
// For this container, we can see both the tile inventory's slots as well as the player inventory slots and the hotbar.
// Each time we add a Slot to the container, it automatically increases the slotIndex, which means
//  0 - 8 = hotbar slots (which will map to the InventoryPlayer slot numbers 0 - 
//  9 - 35 = player inventory slots (which map to the InventoryPlayer slot numbers 9 - 35)
//  36 - 44 = TileInventory slots, which map to our TileEntity slot numbers 0 - 

private final int HOTBAR_COUNT = 9;
private final int PLAYER_ROWS = 3;
private final int PLAYER_COLUMNS = 9;
private final int PLAYER_SLOTS = PLAYER_COLUMNS * PLAYER_ROWS;
private final int VANILLA_SLOTS = HOTBAR_COUNT + PLAYER_SLOTS;
private final int VANILLA_START = 0;

private final int TE_START = VANILLA_START + VANILLA_SLOTS;
private final int TE_ROWS = 3;
private final int TE_COLUMNS = 9;
private final int TE_SLOTS = TE_ROWS * TE_COLUMNS;


public void setFreq(int frequency) {
	this.wirelessChestEntity.setFreq(frequency);
}

public int getFreq() {
	return this.wirelessChestEntity.getFreq();
}

public String freqStr() {
	return this.wirelessChestEntity.getFreqStr();
}

public WirelessChestContainer(InventoryPlayer invPlayer, WirelessChestEntity wirelessChestEntity) {
	this.wirelessChestEntity = wirelessChestEntity;

	//  Adds all the slots for items
	final int SLOT_X_SPACING = 18;
	final int SLOT_Y_SPACING = 18;

	final int HOTBAR_XPOS = 8;
	final int HOTBAR_YPOS = 164;
	final int PLAYER_XPOS = 8;
	final int PLAYER_YPOS = 106;
	final int TE_XPOS = 8;
	final int TE_YPOS = 48;

	// Add the players hotbar to the gui - the [xpos, ypos] location of each item
	for (int x = 0; x < HOTBAR_COUNT; x++) {
		int slotNumber = x;
		addSlotToContainer(new Slot(invPlayer, slotNumber, HOTBAR_XPOS + SLOT_X_SPACING * x, HOTBAR_YPOS));
	}


	// Add the rest of the players inventory to the gui
	for (int y = 0; y < PLAYER_ROWS; y++) {
		for (int x = 0; x < PLAYER_COLUMNS; x++) {
			int slotNumber = HOTBAR_COUNT + y * PLAYER_COLUMNS + x;
			int xpos = PLAYER_XPOS + x * SLOT_X_SPACING;
			int ypos = PLAYER_YPOS + y * SLOT_Y_SPACING;
			addSlotToContainer(new Slot(invPlayer, slotNumber,  xpos, ypos));
		}
	}


	if (TE_SLOTS != wirelessChestEntity.getSizeInventory()) {
		System.err.println("Mismatched slot count in ContainerBasic(" + TE_SLOTS
											  + ") and TileInventory (" + wirelessChestEntity.getSizeInventory()+")");
	}


	// Add the tile inventory container to the gui
	for (int y = 0; y < TE_ROWS; y++) {
		for (int x = 0; x < TE_COLUMNS; x++) {
			int slotNumber = (y * HOTBAR_COUNT) + x;
			int xpos = TE_XPOS + (x * SLOT_X_SPACING);
			int ypos = TE_YPOS + (y * SLOT_Y_SPACING);
			addSlotToContainer(new Slot(wirelessChestEntity, slotNumber,  xpos, ypos));
		}
	}

}

// Vanilla calls this method every tick to make sure the player is still able to access the inventory, and if not closes the gui
@Override
public boolean canInteractWith(EntityPlayer player)
{
	return wirelessChestEntity.isUseableByPlayer(player);
}

// This is where you specify what happens when a player shift clicks a slot in the gui
//  (when you shift click a slot in the TileEntity Inventory, it moves it to the first available position in the hotbar and/or
//    player inventory.  When you you shift-click a hotbar or player inventory item, it moves it to the first available
//    position in the TileEntity inventory)
// At the very least you must override this and return null or the game will crash when the player shift clicks a slot
// returns null if the source slot is empty, or if none of the the source slot items could be moved
//   otherwise, returns a copy of the source stack
@Override
public ItemStack transferStackInSlot(EntityPlayer player, int sourceSlotIndex)
{
	Slot sourceSlot = (Slot)inventorySlots.get(sourceSlotIndex);
	if (sourceSlot == null || !sourceSlot.getHasStack()) return null;
	ItemStack sourceStack = sourceSlot.getStack();
	ItemStack copyOfSourceStack = sourceStack.copy();

	// Check if the slot clicked is one of the vanilla container slots
	if (sourceSlotIndex >= VANILLA_START && sourceSlotIndex < VANILLA_START + VANILLA_SLOTS) {
		// This is a vanilla container slot so merge the stack into the tile inventory
		if (!mergeItemStack(sourceStack, TE_START, TE_START + TE_SLOTS, false)){
			return null;
		}
	} else if (sourceSlotIndex >= TE_START && sourceSlotIndex < TE_START + TE_SLOTS) {
		// This is a TE slot so merge the stack into the players inventory
		if (!mergeItemStack(sourceStack, VANILLA_START, VANILLA_START + VANILLA_SLOTS, false)) {
			return null;
		}
	} else {
		System.err.print("Invalid slotIndex:" + sourceSlotIndex);
		return null;
	}

	// If stack size == 0 (the entire stack was moved) set slot contents to null
	if (sourceStack.stackSize == 0) {
		sourceSlot.putStack(null);
	} else {
		sourceSlot.onSlotChanged();
	}

	sourceSlot.onPickupFromSlot(player, sourceStack);
	return copyOfSourceStack;
}

// pass the close container message to the tileEntityInventory (not strictly needed for this example)
//  see ContainerChest and TileEntityChest
@Override
public void onContainerClosed(EntityPlayer playerIn)
{
	super.onContainerClosed(playerIn);
	this.wirelessChestEntity.closeInventory(playerIn);
}

@Override
public boolean enchantItem(EntityPlayer player, int action) {
	this.wirelessChestEntity.setFreq(action);
	return super.enchantItem(player, action);
}


}

 

 

GuiContainer:

package com.cclloyd.ccmodpack;

import net.minecraft.client.Minecraft;
import net.minecraft.client.gui.GuiButton;
import net.minecraft.client.gui.inventory.GuiContainer;
import net.minecraft.client.renderer.GlStateManager;
import net.minecraft.entity.player.InventoryPlayer;
import net.minecraft.inventory.Container;
import net.minecraft.util.ResourceLocation;
import net.minecraftforge.fml.relauncher.Side;
import net.minecraftforge.fml.relauncher.SideOnly;

@SideOnly(Side.CLIENT)
public class WirelessChestGuiContainer extends GuiContainer {

/**
 * GuiInventoryBasic is a simple gui that does nothing but draw a background image and a line of text on the screen
 * everything else is handled by the vanilla container code
 */
private static final ResourceLocation texture = new ResourceLocation("ccmodpack", "textures/gui/container/wirelessChest.png");
private WirelessChestEntity wirelessChestEntity;
private WirelessChestContainer container;


public WirelessChestGuiContainer(InventoryPlayer invPlayer, WirelessChestEntity tile) {
	super(new WirelessChestContainer(invPlayer, tile));
	wirelessChestEntity = tile;
	// Set the width and height of the gui.  Should match the size of the texture!
	xSize = 176;
	ySize = 184;
	this.xSize = 176;
	this.ySize = 184;

	this.container = (WirelessChestContainer)this.inventorySlots;
}


public Container getContainer() {
	return null;

}

// draw the background for the GUI - rendered first
@Override
protected void drawGuiContainerBackgroundLayer(float partialTicks, int x, int y) {
	// Bind the image texture of our custom container
	Minecraft.getMinecraft().getTextureManager().bindTexture(texture);
	// Draw the image
	GlStateManager.color(1.0F, 1.0F, 1.0F, 1.0F);
	drawTexturedModalRect(guiLeft, guiTop, 0, 0, xSize, ySize);
}

// draw the foreground for the GUI - rendered after the slots, but before the dragged items and tooltips
// renders relative to the top left corner of the background
@Override
protected void drawGuiContainerForegroundLayer(int mouseX, int mouseY) {
	//final int LABEL_XPOS = this.xSize / 2 - 10;
	//final int LABEL_YPOS = 5;
	//this.guiLeft = (this.width - this.xSize) / 2;
        //this.guiTop = (this.height - this.ySize) / 2;
	//int posX = this.guiLeft;
	//int posY = this.guiTop;
	//int center = this.xSize / 2 + this.guiLeft;
	//fontRendererObj.drawString("0000", this.guiLeft / 2, 4, Color.darkGray.getRGB());

}


@SuppressWarnings("unchecked")
public void initGui() {
	super.initGui();
        this.mc.thePlayer.openContainer = this.inventorySlots;
        this.guiLeft = (this.width - this.xSize) / 2;
        this.guiTop = (this.height - this.ySize) / 2;
	int posX = this.guiLeft;
	int posY = this.guiTop;
	int center = this.xSize / 2 + posX;

	int width1000 = 40;
	int width100 = 33;
	int width10 = 28;
	int width1 = 20;

	int posX1000 = 50;
	int posX100 = 67;
	int posX10 = 36;
	int posX1 = 11;

	int center1000 = center - (width1000 / 2);
	int center100 = center - (width100 / 2);
	int center10 = center - (width10 / 2);
	int center1 = center - (width1 / 2);
	int posY1000 = posY + 4;
	int posY100 = posY + 25;
	int posY10 = posY100;
	int posY1 = posY100;

	this.buttonList.add(new GuiButton(1, center1000 - posX1000, posY1000, width1000, 20, "-1000"));
	this.buttonList.add(new GuiButton(2, center1000 + posX1000, posY1000, width1000, 20, "+1000"));

	this.buttonList.add(new GuiButton(3, center100 - posX100, posY100, width100, 20, "-100"));
	this.buttonList.add(new GuiButton(4, center100 + posX100, posY100, width100, 20, "+100"));

	this.buttonList.add(new GuiButton(5, center10 - posX10, posY10, width10, 20, "-10"));
	this.buttonList.add(new GuiButton(6, center10 + posX10, posY10, width10, 20, "+10"));

	this.buttonList.add(new GuiButton(7, center1 - posX1, posY1, width1, 20, "-1"));
	this.buttonList.add(new GuiButton(8, center1 + posX1, posY1, width1, 20, "+1"));

	this.buttonList.add(new DisabledButton(0, center - (45 / 2), posY1000, 45, 20, wirelessChestEntity.getFreqStr()));
}

@SuppressWarnings("unchecked")
@Override
protected void actionPerformed(GuiButton button) {
	this.guiLeft = (this.width - this.xSize) / 2;
        this.guiTop = (this.height - this.ySize) / 2;
	int posX = this.guiLeft;
	int posY = this.guiTop;
	int center = this.xSize / 2 + posX;
	int posY1000 = posY + 4;


	if (button.id == 1) {
		if (container.getFreq() < 1000)
			container.setFreq(0);
		else
			container.setFreq(container.getFreq() - 1000);

	}
	if (button.id == 2) {
		if (container.getFreq() > 8999)
			container.setFreq(9999);
		else
			container.setFreq(container.getFreq() + 1000);
	}


	this.buttonList.remove(this.buttonList.size() - 1);
	this.buttonList.add(new DisabledButton(0, center - (45 / 2), posY1000, 45, 20, container.freqStr()));

	this.mc.playerController.sendEnchantPacket(this.container.windowId, container.getFreq());
}

@Override
public void onGuiClosed() {
        if (this.mc.thePlayer != null)
            this.inventorySlots.onContainerClosed(this.mc.thePlayer);
    }
}

 

 

 

And yet after I close the map it still doesn't save the frequency.  Only the items.

 

And just an FYI cause it doesn't seem clear, I am using MC 1.8.

Posted

TGG already said how to do it.

You need to send the value of the field using icrafting.sendProgressBarUpdate in Container#detectAndSendChanges,

and override Contaier#updateProgressBar to update the field.

I. Stellarium for Minecraft: Configurable Universe for Minecraft! (WIP)

II. Stellar Sky, Better Star Rendering&Sky Utility mod, had separated from Stellarium.

Posted

If you are trying to send from the client to the server, you will need a custom packet.

For example, in GUIrepair.renameItem()

        this.mc.thePlayer.sendQueue.addToSendQueue(new C17PacketCustomPayload("MC|ItemName", (new PacketBuffer(Unpooled.buffer())).writeString(s)));

which is processed on the server in NetHandlerPlayServer.processVanilla250Packet(C17PacketCustomPayload packetIn)

        else if ("MC|ItemName".equals(packetIn.getChannelName()) && this.playerEntity.openContainer instanceof ContainerRepair)
        {
            ContainerRepair containerrepair = (ContainerRepair)this.playerEntity.openContainer;

            if (packetIn.getBufferData() != null && packetIn.getBufferData().readableBytes() >= 1)
            {
                String s = ChatAllowedCharacters.filterAllowedCharacters(packetIn.getBufferData().readStringFromBuffer(32767));

                if (s.length() <= 30)
                {
                    containerrepair.updateItemName(s);
                }
            }
            else
            {
                containerrepair.updateItemName("");
            }
        }

or for the example of a merchant trade

        else if ("MC|TrSel".equals(packetIn.getChannelName()))
        {
            try
            {
                int i = packetIn.getBufferData().readInt();
                Container container = this.playerEntity.openContainer;

                if (container instanceof ContainerMerchant)
                {
                    ((ContainerMerchant)container).setCurrentRecipeIndex(i);
                }
            }
            catch (Exception exception2)
            {
                logger.error("Couldn\'t select trade", exception2);
            }
        }

I think you will need to create your own custom packet and perform a container check (similar to above) on the EntityPlayerMP that you are given in the message handler.

Here's a working example of network messages that might help

https://github.com/TheGreyGhost/MinecraftByExample/blob/master/src/main/java/minecraftbyexample/mbe60_network_messages/Notes.txt

Also some background info

http://greyminecraftcoder.blogspot.com.au/2015/01/the-client-server-division.html  (and its sub-topics)

 

-TGG

 

 

 

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

    • Short Term Loans Online: A Reliable Source of Fast Cash   If you are experiencing financial difficulties, you don't have to worry about this challenge. This is the quickest and best method for handling financial catastrophes. You can pick short term loans online without reluctance, and you can apply for the payday loan you want online and have it the same day without any issues. With two to four weeks to repay the loan, you may often borrow between $100 and $1000 without having to offer any collateral.   As implied by the title, those with bad credit histories—defaults, arrears, foreclosure, late or missed payments, judgments against you, insolvency or IVA, etc.—are welcome to apply for online short term loans without having to go through any challenging procedures. Interest rates are a bit high in comparison to other loans. A thorough internet search can be used to determine the greatest rate for a financed loan.   You don't have to waste your precious time searching the internet for short term funding payday loans. In just a few minutes, you can apply for the finance you desire by completing a brief online application. The lender will approve the loan once he has verified that you have provided accurate information on this brief form. This loan is carefully deposited into your bank account in the least amount of time. You can utilize the money in a number of ways without running into any problems. Usually, the money can be used to settle debts like credit card balances, overdue bank overdrafts, tuition or school fees for children, energy bills, housing costs, and more.   Loans Lucre makes it simple to apply for short term loans online, so there's no need to drive across town. Additionally, you won't have to wait weeks for a response from us. Additionally, having bad credit shouldn't be a deal-breaker. We evaluate your entire financial history rather than just your FICO score. We approve many debtors who had been rejected by banks.   Once you are approved, Loans Lucre puts your online installment loans directly into your bank account, giving you instant access to your funds. The repayment plan is broken down into simple, reasonably priced monthly installments. Loans Lucre also rejects rollovers. Instead, we help borrowers get back on track when they encounter difficulties with the repayment process. Borrowers who regularly make their payments on time are eligible for lower annual percentage rates (APRs) on their subsequent these loans. That is truly win-win!   You will be communicating with the lender whether you apply for online personal loans through a cash advance broker or directly from the lender. The cost and duration of the transaction will be increased by any third parties you deal with through the direct lender. This will lead to a faulty perception of the "instant approval" of your payday loan, in addition to raising the cost of your transaction. When asking for a payday loan, it is therefore essential that you work with a trustworthy direct lender; a lender with a solid online reputation and satisfied clients is a wise choice.   You can apply for a short term loans online through internet platforms in addition to conventional lenders. A quicker and more convenient application process is frequently provided by these platforms. In the end, it is feasible to get a $500 loan with low credit or no credit at all, but it will need effort and careful evaluation of your financial possibilities. The lender's requirements will always determine approval, so be careful to give accurate information and look into several lenders to determine which one best suit your needs. https://loanslucre.com/  
    • Apply For Fast Cash Loans Online Today To Get Money Right Away   Do you have to deal with your money issues right away? You don't need to go anywhere because you can get fast cash loans online with just a computer and an internet connection. This suggests that you don't need to waste any time applying for these loans. All you have to do is fill out the form accurately and submit it to the lender online. They will check it and determine whether to approve the loan within the specified time frame. The money is moved to your bank account shortly after approval.   The same-day financing loan facility offers the most beneficial cash assistance in quantities ranging from $100 to $1000, with a flexible payback period of 2-4 weeks from the date of acceptance. You can use the borrowed funds to cover your child's tuition or school fees, small vacation expenses, past credit card payments, laundry costs, minor house repairs, your mother's checkups, and other emergencies.   To be qualified for same day funding loans, you must meet specific conditions regardless of your credit score—fair or low. A valid proof of domicile and proof of residence for the last 12 months, a current bank account with an SSN, being employed permanently with a monthly wage of at least $1000, and being at least eighteen years of age are prerequisites. If you satisfy the qualifications, you can apply for same-day payday loans directly without undergoing a credit check if you have bankruptcy, CCJs, IVAs, foreclosure, arrears, or defaults. As a result, getting a loan is fairly easy in the current credit market.   You must complete an application with information about your bank account and job in order to apply for a fast cash loan online from a physical payday lender. You also need to provide the lender with postdated checks that will be deposited on the scheduled repayment date. In return, you get paid right away.   Applicants can apply for same day payday loans at any time, from the comfort of their homes, eliminating the need to travel across town to a payday loan outlet. However, online payday lenders do not frequently provide same-day loans. Instead, payouts are made straight into borrowers' bank accounts via the Automated Clearing House (ACH) system; processing for this method takes at least one business day.   You must think about if you can pay back the loan in full within the allotted time because same day payday loans may have payback periods as little as one week or ten days. If you are unable to pay the full amount due, the lender might accept a token payment from you. The remaining sum will be restructured as a rollover, which is a new loan with fresh interest and administrative costs and the same short payback period. After a few rollovers, a significant number of little payday loans accumulate to the point that debtors still owe more than they originally borrowed, even after making consistent payments for months or years.   You should be ready to submit the required paperwork and supporting proof when applying for a payday loans online same day with bad credit. Usually, lenders will evaluate your present financial state, work status, and loan-repayment capacity. Many lenders specialize in bad credit loans and are willing to take on the risk of lending to those with poor credit, despite the difficulties presented by a low credit score. This implies that you are not automatically denied a loan because of poor credit or no credit at all. https://nuevacash.com/
    • I have removed stevekunglib and it is still crashing again https://pastebin.com/9vE8pji0
    • It looks like an issue with stevekunglib or a mod requiring it
  • Topics

×
×
  • Create New...

Important Information

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