Jump to content

[1.16.5] Make GUI for a block


Aonodensetsu

Recommended Posts

I followed a tutorial (albeit I think it was using MCP mappings because some methods it overwrote simply didn't exist for me so I tried to guess which is which sometimes) for adding a GUI to a block. I had the made the block prior so that in itself was working, so I went on as usual to add a GUI to it. I think I might have guessed wrong somewhere, as the GUI doesn't show up at all - but the game doesn't crash and Eclipse doesn't show any errors.

Spoiler

TileEntityRegistryHandler.java, which should register the TileEntity to the Block.




public class TileEntityRegistryHandler {
	public static ContainerType<ContainerGravityCore> GravityContainer;
	
	public static final DeferredRegister<TileEntityType<?>> TILE_ENTITIES = DeferredRegister.create(ForgeRegistries.TILE_ENTITIES, SMModContainer.MODID);

	public static final RegistryObject<TileEntityType<TileEntityGravityCore>> GRAVITY_CORE = TILE_ENTITIES.register("gravity_core", () ->
		TileEntityType.Builder.of(TileEntityGravityCore::new, BlockRegistryHandler.GRAVITY_CORE.get()).build(null)
	);
	
	public static void init(IEventBus bus) {
		TILE_ENTITIES.register(bus);
	}
}

 

Spoiler

BlockGravityCore.java, which is the Block I made - here, only part of the file that I modified to add TileEntity.




@Override
	public TileEntity createTileEntity(BlockState state, IBlockReader world) {
		return new TileEntityGravityCore();
	}
	
	@Override
	public boolean hasTileEntity(BlockState state) {
		return true;
	}
	
	@SuppressWarnings("deprecation")
	@Override
	public ActionResultType use(BlockState block, World world, BlockPos coord, PlayerEntity player, Hand hand, BlockRayTraceResult ray) {
		if (world.isClientSide) { return ActionResultType.SUCCESS; }
		INamedContainerProvider namedcontainer = block.getMenuProvider(world, coord);
		if (namedcontainer != null) {
			if (!(player instanceof PlayerEntity)) { return ActionResultType.FAIL; }
			ServerPlayerEntity serverplayer = (ServerPlayerEntity) player;
			NetworkHooks.openGui(serverplayer, namedcontainer);
		}
		return ActionResultType.SUCCESS;
	}
	
	@Override
	public void destroy(IWorld world, BlockPos coord, BlockState block) {
		TileEntity tile = world.getBlockEntity(coord);
		if (tile instanceof TileEntityGravityCore) {
			TileEntityGravityCore tileentity = (TileEntityGravityCore) tile;
			tileentity.dropAll(world, coord);
		}
		super.destroy(world, coord, block);
	}

 

Spoiler

TileEntityGravityCore.java - which should be the TileEntity for the Block.




public class TileEntityGravityCore extends TileEntity implements INamedContainerProvider {
	public static TileEntityType<TileEntityGravityCore> TILE_GRAVITY;
	private final ContentsGravityCore contents;
	public static final int SLOT_SIZE = 27;

	public TileEntityGravityCore() {
		super(TILE_GRAVITY);
		contents = ContentsGravityCore.createForTileEntity(27, this::canPlayerAccessInventory, this::setChanged);
	}

	@Override
	public Container createMenu(int id, PlayerInventory playerinventory, PlayerEntity player) {
		return ContainerGravityCore.createContainerServerSide(id, playerinventory, contents);
	}

	@Override
	public ITextComponent getDisplayName() {
		return new TranslationTextComponent("container.starminer.gravitygui");
	}
	
	@Override
	public CompoundNBT save(CompoundNBT nbt) {
		super.save(nbt);
		CompoundNBT inventory = contents.serializeNBT();
		nbt.put("contents", inventory);
		return nbt;
	}
	
	@Override
	public void load(BlockState block, CompoundNBT nbt) {
		super.load(block, nbt);
		CompoundNBT inventory = nbt.getCompound("contents");
		contents.deserializeNBT(inventory);
		if (contents.getContainerSize() != SLOT_SIZE) { throw new IllegalArgumentException("Corrupted NBT"); }
	}
	
	@Override
	public SUpdateTileEntityPacket getUpdatePacket() {
		CompoundNBT nbt = new CompoundNBT();
		return new SUpdateTileEntityPacket(worldPosition, 42, nbt);
	}
	
	@Override
	public void onDataPacket(NetworkManager net, SUpdateTileEntityPacket pkt) {
		BlockState block = level.getBlockState(worldPosition);
		read(block, pkt.getTag());
	}
	
	@Override
	public CompoundNBT getUpdateTag() {
		CompoundNBT nbt = new CompoundNBT();
		write(nbt);
		return nbt;
	}
	
	@Override
	public void handleUpdateTag(BlockState block, CompoundNBT tag) {
		this.read(block, tag);
	}
	
	public void dropAll(IWorld world, BlockPos coord) {
		InventoryHelper.dropContents(level, coord, contents);
	}
	
	private void write(CompoundNBT nbt) {}

	private void read(BlockState block, CompoundNBT tag) {}

	public boolean canPlayerAccessInventory(PlayerEntity player) {
		if (this.level.getBlockEntity(this.worldPosition) != this) { return false; }
		return player.blockPosition().distSqr(new Vector3i(this.worldPosition.getX() + 0.5, this.worldPosition.getY() + 0.5, this.worldPosition.getZ() + 0.5)) < 64;
	}
}

 

Spoiler

ContentsGravityCore.java, which should store the contents of the Inventory as far as I'm aware.




public class ContentsGravityCore implements IInventory {
	private ItemStackHandler contents;

	public static ContentsGravityCore createForTileEntity(int size, Predicate<PlayerEntity> canAccess, Notify changed) { 
		return new ContentsGravityCore(size, canAccess, changed); 
	}
	
	public static ContentsGravityCore createForClientContainer(int size) {
		return new ContentsGravityCore(size);
	}

	public CompoundNBT serializeNBT() { 
		return contents.serializeNBT(); 
	}
	
	public void deserializeNBT(CompoundNBT nbt) {
		contents.deserializeNBT(nbt);
	}
	
	public void lambdaCanPlayerAccessInventory(Predicate<PlayerEntity> player) {
		this.lambdaCanPlayerAccessInventory = player;
	}
	
	public void lambdaMarkDirty(Notify dirty) {
		this.lambdaSetChangedNotification = dirty;
	}
	
	public void lambdaOpenInventoryNotification(Notify open) {
		this.lambdaOpenInventoryNotification = open;
	}
	
	public void lambdaCloseInventoryNotification(Notify close) {
		this.lambdaCloseInventoryNotification = close;
	}
	
	public boolean isUsable(PlayerEntity player) {
		return lambdaCanPlayerAccessInventory.test(player);
	}
	
	public boolean isItemValidForSlot(int id, ItemStack item) {
		return contents.isItemValid(id, item);
	}
	
	@FunctionalInterface
	public interface Notify {
		void invoke();
	}
	
	public void openInventory(PlayerEntity player) {
		lambdaOpenInventoryNotification.invoke();
	}
	
	public void closeInventory(PlayerEntity player) {
		lambdaCloseInventoryNotification.invoke();
	}
	
	public boolean isEmpty() {
		for (int i = 0; i < contents.getSlots(); i++) {
			if (!contents.getStackInSlot(i).isEmpty()) { return false; }
		}
		return true;
	}
	
	private ContentsGravityCore(int size) {
		this.contents = new ItemStackHandler(size);
	}
	
	private ContentsGravityCore(int size, Predicate<PlayerEntity> player, Notify dirty) {
		this.contents = new ItemStackHandler(size);
		this.lambdaCanPlayerAccessInventory = player;
		this.lambdaSetChangedNotification = dirty;
	}

	private Predicate<PlayerEntity> lambdaCanPlayerAccessInventory = x-> true;
	
	private Notify lambdaSetChangedNotification = ()->{};
	
	private Notify lambdaOpenInventoryNotification = ()->{};
	
	private Notify lambdaCloseInventoryNotification = ()->{};

	@Override
	public void clearContent() {
		for (int i = 0; i < contents.getSlots(); i++) {
			removeFromSlot(i);
		}
	}
	
	@Override
	public int getContainerSize() { 
		return contents.getSlots();  
	}
	
	@Override
	public ItemStack getItem(int id) { 
		return contents.getStackInSlot(id); 
	}
	
	@Override
	public ItemStack removeItem(int id, int count) { 
		return contents.extractItem(id, count, false); 
	}
	
	public ItemStack removeFromSlot(int id) {
		return removeItem(id, contents.getSlotLimit(id));
	}
	
	@Override
	public ItemStack removeItemNoUpdate(int id) { return null; }
	
	@Override
	public void setItem(int id, ItemStack item) { 
		contents.setStackInSlot(id, item); 
	}
	
	@Override
	public void setChanged() { 
		lambdaSetChangedNotification.invoke(); 
	}
	
	@Override
	public boolean stillValid(PlayerEntity player) { return false; }
}

 

Spoiler

ContainerGravityCore.java, which makes the slots of the inventory - again, as far as I'm aware.




public class ContainerGravityCore extends Container {
	private static final Logger LOGGER = LogManager.getLogger();
	private ContentsGravityCore contents;
	
	private static final int HOTBAR_SLOTS = 9;
	private static final int PLAYER_ROWS = 3;
	private static final int PLAYER_ROW_SIZE = 9;
	private static final int PLAYER_SLOTS = PLAYER_ROW_SIZE * PLAYER_ROWS;
	private static final int VANILLA_INVENTORY = PLAYER_SLOTS + HOTBAR_SLOTS;
	private static final int VANILLA_FIRST_SLOT = 0;
	private static final int MOD_FIRST_SLOT = VANILLA_FIRST_SLOT + VANILLA_INVENTORY;
	private static final int MOD_INVENTORY = TileEntityGravityCore.SLOT_SIZE;
	
	private static final int MOD_INVENTORY_POS = 20;
	public static final int VANILLA_INVENTORY_POS = 113;
	
	public static ContainerGravityCore createContainerServerSide(int id, PlayerInventory playerinventory, ContentsGravityCore contents) {
		return new ContainerGravityCore(id, playerinventory, contents);
	}

	public static ContainerGravityCore createContainerClientSide(int id, PlayerInventory playerinventory, PacketBuffer extra) {
		ContentsGravityCore contents = ContentsGravityCore.createForClientContainer(TileEntityGravityCore.SLOT_SIZE);
		return new ContainerGravityCore(id, playerinventory, contents);
	}
	
	private ContainerGravityCore(int id, PlayerInventory playerinventory, ContentsGravityCore contents) {
		super(TileEntityRegistryHandler.GravityContainer, id);
		if (TileEntityRegistryHandler.GravityContainer == null) { throw new IllegalStateException("Must initialize before constructing!"); }
		PlayerInvWrapper forgeinv = new PlayerInvWrapper(playerinventory);
		this.contents = contents;
		final int X_SPACING = 18;
		final int Y_SPACING = 18;
		final int HOTBAR_POS_X = 8;
		final int HOTBAR_POS_Y = 109;
		for (int i = 0; i < HOTBAR_SLOTS; i++) {
			addSlot(new SlotItemHandler(forgeinv, i, HOTBAR_POS_X + X_SPACING * i, HOTBAR_POS_Y));
		}
		final int PLAYER_X_POS = 8;
		for (int i = 0; i < PLAYER_ROWS; i++) {
			for (int j = 0; j < PLAYER_ROW_SIZE; j++) {
				addSlot(new SlotItemHandler(forgeinv, HOTBAR_SLOTS + i * PLAYER_ROWS + j, PLAYER_X_POS + i * X_SPACING, VANILLA_INVENTORY_POS + i * Y_SPACING));
			}
		}
		
		if (MOD_INVENTORY != contents.getContainerSize()) { LOGGER.warn("Mismatched slot count" + MOD_INVENTORY + "vs" + contents.getContainerSize()); }
		
		final int MOD_INV_X = 8;
		for (int i = 0; i < MOD_INVENTORY / PLAYER_ROW_SIZE; i++) {
			for (int j = 0; j < MOD_INVENTORY / PLAYER_ROWS; j++) {
				addSlot(new Slot(contents, i * PLAYER_ROWS + j, MOD_INV_X + X_SPACING * j, MOD_INVENTORY_POS + Y_SPACING * i));
			}
		}
	}
	
	public boolean canInteractWith(PlayerEntity player) {
		return contents.isUsable(player);
	}
	
	public ItemStack transferStackInSlot(PlayerEntity player, int slot) {
		Slot src = this.slots.get(slot);
		if (src == null || !src.hasItem()) { return ItemStack.EMPTY; }
		ItemStack srcstack = src.getItem();
		ItemStack copy = srcstack.copy();
		if (slot >= VANILLA_FIRST_SLOT && slot < VANILLA_FIRST_SLOT + VANILLA_INVENTORY) {
			if (!moveItemStackTo(srcstack, MOD_FIRST_SLOT, MOD_FIRST_SLOT + MOD_INVENTORY, false)) {
				return ItemStack.EMPTY;
			} 
		} else if (slot >= MOD_FIRST_SLOT && slot < MOD_FIRST_SLOT + MOD_INVENTORY) {
			if (!moveItemStackTo(srcstack, VANILLA_FIRST_SLOT, VANILLA_FIRST_SLOT + VANILLA_INVENTORY, false)) {
				return ItemStack.EMPTY;
			}
		} else {
			LOGGER.warn("Invalid slot index" + slot);
			return ItemStack.EMPTY;
		}
		if (srcstack.getCount() == 0) {
			src.set(ItemStack.EMPTY);
		} else {
			src.setChanged();
		}
		src.onTake(player, srcstack);
		return copy;
	}
	
	@Override
	public boolean stillValid(PlayerEntity p_75145_1_) {
		return false;
	}
}

 

I have the TileEntityRegistryHandler called from the main mod file to register the Bus (I checked and it does get called), so the TileEntity itself should be getting registered.

Edited by Aonodensetsu
Link to comment
Share on other sites

  • Aonodensetsu changed the title to [1.16.5] Make GUI for a block

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



×
×
  • Create New...

Important Information

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