Jump to content

OuiOuiCroissant

Members
  • Posts

    13
  • Joined

  • Last visited

Posts posted by OuiOuiCroissant

  1. It's still giving me those same 3 errors on the underlined bits:

    INSTANCE.registerMessage(id++, SetKingPacket.class, SetKingPacket::encode, SetKingPacket::decode, SetKingPacket.Handler::handle);

    "The type SetKingPacket does not define encode(MSG, PacketBuffer) that is applicable here"

    "The type of decode(PacketBuffer) from the type SetKingPacket is SetKingPacket, this is incompatible with the descriptor's return type: MSG"

    "The type SetKingPacket.Handler does not define handle(MSG, Supplier<NetworkEvent.Context>) that is applicable here"

     

    SetKingPacket.encode() is a static void method, but SimpleChannel.registerMessage() wants a BiConsumer<MSG,PacketBuffer> in that parameter. How would encode ever work?

     

    Handler:

    package com.siegemod.packets;
    
    import com.siegemod.SiegeMod;
    
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.fml.network.NetworkRegistry;
    import net.minecraftforge.fml.network.simple.SimpleChannel;
    
    public class SiegePacketHandler {
    
    	private static final String PROTOCOL_VERSION = "1";
    	public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(new ResourceLocation(SiegeMod.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals,
    			PROTOCOL_VERSION::equals);
    
    	private static int id;
    
    	public static void registerPackets() {
    		INSTANCE.registerMessage(id++, SetKingPacket.class, SetKingPacket::encode, SetKingPacket::decode, SetKingPacket.Handler::handle);
    	}
    }
    
    /*
    // Sending to one player
    INSTANCE.send(PacketDistributor.PLAYER.with(playerMP),new MyMessage());
    
    // Send to all players tracking this chunk
    INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(chunk),new MyMessage());
    
    // Sending to all connected players
    INSTANCE.send(PacketDistributor.ALL.noArg(),new MyMessage());
    */

    Packet:

    package com.siegemod.packets;
    
    import com.google.common.base.Supplier;
    
    import net.minecraft.entity.player.ServerPlayerEntity;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.fml.network.NetworkEvent;
    
    public class SetKingPacket {
    
    	private final int data;
    
    	public SetKingPacket(int dataIn) {
    		this.data = dataIn;
    	}
    
    	public static void encode(SetKingPacket msg, PacketBuffer buf) {
    		buf.writeInt(msg.data);
    	}
    
    	public static SetKingPacket decode(PacketBuffer buf) {
    		int data = buf.readInt();
    
    		return new SetKingPacket(data);
    	}
    
    	public static class Handler {
    
    		public static void handle(SetKingPacket msg, Supplier<NetworkEvent.Context> ctx) {
    			ctx.get().enqueueWork(() -> {
    				// Work that needs to be threadsafe (most work)
    				ServerPlayerEntity sender = ctx.get().getSender(); // the client that sent this packet
    				// do stuff
    			});
    			ctx.get().setPacketHandled(true);
    		}
    	}
    }

     

     

  2. That makes sense. I'm still getting errors on the last 3 parameters of INSTANCE.registerMessage() in my packet handler. Is there a new way to register packets in 1.15.2?

    Quote

    The method registerMessage(int, Class<MSG>, BiConsumer<MSG,PacketBuffer>, Function<PacketBuffer,MSG>, BiConsumer<MSG,Supplier<NetworkEvent.Context>>) in the type SimpleChannel is not applicable for the arguments (int, Class<SetKingPacket>, SetKingPacket::encode, SetKingPacket::new, SetKingPacket.Handler::handle)

     

    My Packet:

    package com.siegemod.packets;
    
    import com.google.common.base.Supplier;
    
    import net.minecraft.entity.player.ServerPlayerEntity;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.fml.network.NetworkEvent;
    
    public class SetKingPacket {
    
    	private final int data;
    
    	public SetKingPacket(int dataIn) {
    		this.data = dataIn;
    	}
    
    	public static void encode(SetKingPacket msg, PacketBuffer buf) {
    		buf.writeInt(msg.data);
    	}
    
    	public static SetKingPacket decode(PacketBuffer buf) {
    		int data = buf.readInt();
    
    		return new SetKingPacket(data);
    	}
    
    	public static class Handler {
    
    		public static void handle(SetKingPacket msg, Supplier<NetworkEvent.Context> ctx) {
    			ctx.get().enqueueWork(() -> {
    				// Work that needs to be threadsafe (most work)
    				ServerPlayerEntity sender = ctx.get().getSender(); // the client that sent this packet
    				// do stuff
    			});
    			ctx.get().setPacketHandled(true);
    		}
    	}
    }

     

    My Packet Handler:

    package com.siegemod.packets;
    
    import com.siegemod.SiegeMod;
    
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.fml.network.NetworkRegistry;
    import net.minecraftforge.fml.network.simple.SimpleChannel;
    
    public final class SiegePacketHandler {
    
    	private static final String PROTOCOL_VERSION = "1";
    	public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(new ResourceLocation(SiegeMod.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals,
    			PROTOCOL_VERSION::equals);
    
    	private static int id;
    
    	public static void register() {
    		INSTANCE.registerMessage(id++, SetKingPacket.class, SetKingPacket::encode, SetKingPacket::new, SetKingPacket.Handler::handle);
    	}
    }
    
    /*
    // Sending to one player
    INSTANCE.send(PacketDistributor.PLAYER.with(playerMP),new MyMessage());
    
    // Send to all players tracking this chunk
    INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(chunk),new MyMessage());
    
    // Sending to all connected players
    INSTANCE.send(PacketDistributor.ALL.noArg(),new MyMessage());
    */

     

  3. I just learned how to do packets for the first time by following the forge documentation, but it only got me so far. I don't understand what SimpleChannel.registerMessages() should take as parameters.

    In a lot of examples and tutorials they give it static void methods from the message class, but it won't accept those in my code. It "is not applicable for the arguments". I see people implementing IMessage into their packet class, but there is no IMessage interface! Has it been replaced with MSG? Do I have to create it?

     

    If you know a lot about packets, can you tell me what I'm doing wrong?

     

    My Packet Handler:

    package com.siegemod.util;
    
    import com.siegemod.SiegeMod;
    import com.siegemod.packets.SetKingPacket;
    
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.fml.network.NetworkRegistry;
    import net.minecraftforge.fml.network.simple.SimpleChannel;
    
    public class SiegePacketHandler {
    
    	private static final String PROTOCOL_VERSION = "1";
    	public static final SimpleChannel INSTANCE = NetworkRegistry.newSimpleChannel(new ResourceLocation(SiegeMod.MODID, "main"), () -> PROTOCOL_VERSION, PROTOCOL_VERSION::equals,
    			PROTOCOL_VERSION::equals);
    
    	private static int id;
    
    	public static void registerPackets() {
    		INSTANCE.registerMessage(id++, SetKingPacket.class, SetKingPacket::encode, SetKingPacket::decode, SetKingPacket::handle);
    	}
    }
    
    /*
    // Sending to one player
    INSTANCE.send(PacketDistributor.PLAYER.with(playerMP),new MyMessage());
    
    // Send to all players tracking this chunk
    INSTANCE.send(PacketDistributor.TRACKING_CHUNK.with(chunk),new MyMessage());
    
    // Sending to all connected players
    INSTANCE.send(PacketDistributor.ALL.noArg(),new MyMessage());
    */

     

    My Message:

    package com.siegemod.packets;
    
    import java.nio.ByteBuffer;
    
    import org.lwjgl.system.windows.MSG;
    
    import com.google.common.base.Supplier;
    
    import net.minecraft.entity.player.ServerPlayerEntity;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.fml.network.NetworkEvent;
    
    public class SetKingPacket extends MSG {
    
    	private String kingUUID;
    
    	public SetKingPacket(ByteBuffer buffer) {
    		super(buffer);
    	}
    
    	public static void encode(SetKingPacket msg, PacketBuffer buf) {
    		buf.writeString(msg.kingUUID);
    	}
    
    	public static void decode(PacketBuffer buf, SetKingPacket msg) {
    		msg.kingUUID = buf.readString();
    	}
    
    	public static void handle(SetKingPacket msg, Supplier<NetworkEvent.Context> ctx) {
    		ctx.get().enqueueWork(() -> {
    			// Work that needs to be threadsafe (most work)
    			ServerPlayerEntity sender = ctx.get().getSender(); // the client that sent this packet
    			// do stuff
    		});
    		ctx.get().setPacketHandled(true);
    	}
    }

     

  4. Like so?

    Spoiler

        @Override
        public final boolean processInteract(PlayerEntity player, Hand hand) {
            if (hand == Hand.MAIN_HAND && player instanceof ServerPlayerEntity && !world.isRemote) {
                if (this.hasKing() && this.isKing(player)) {
                    SiegeEntity peasant = this;
                    NetworkHooks.openGui((ServerPlayerEntity) player, this.containerProvider, new Consumer<PacketBuffer>() {
                        @Override
                        public void accept(PacketBuffer buffer) {
                            buffer.writeInt(peasant.getEntityId());
                        }
                    });

                    return true;
                } else if (!this.hasKing()) {
                    return super.processInteract(player, hand);
                }
            }
            return super.processInteract(player, hand);
        }

  5. Something I implement? As in I implement an interface? Or do you mean I create a new instance of PacketBuffer like so:

    ContainerProvider:

    Spoiler

        public class SiegeContainerProvider implements INamedContainerProvider {

            private final SiegeEntity peasant;

            public SiegeContainerProvider(SiegeEntity peasantIn) {
                this.peasant = peasantIn;
            }

            @Override
            public Container createMenu(int containerId, PlayerInventory playerInv, PlayerEntity player) {
                PacketBuffer containerPacket = new PacketBuffer(Unpooled.buffer());
                containerPacket.writeInt(peasant.getEntityId());
                return new PeasantContainer(containerId, playerInv, containerPacket);
            }

            @Override
            public ITextComponent getDisplayName() {
                return peasant.getDisplayName();
            }
        }

    Here are my other classes as they currently are:

    EntityClass:

    Spoiler

    package com.siegemod.entities;

    import java.util.UUID;

    import com.siegemod.container.PeasantContainer;
    import com.siegemod.container.PeasantInventory;

    import io.netty.buffer.Unpooled;
    import net.minecraft.entity.AgeableEntity;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityType;
    import net.minecraft.entity.ILivingEntityData;
    import net.minecraft.entity.SharedMonsterAttributes;
    import net.minecraft.entity.SpawnReason;
    import net.minecraft.entity.ai.goal.HurtByTargetGoal;
    import net.minecraft.entity.ai.goal.LookAtGoal;
    import net.minecraft.entity.ai.goal.LookRandomlyGoal;
    import net.minecraft.entity.ai.goal.MoveThroughVillageGoal;
    import net.minecraft.entity.ai.goal.MoveTowardsTargetGoal;
    import net.minecraft.entity.ai.goal.MoveTowardsVillageGoal;
    import net.minecraft.entity.ai.goal.SwimGoal;
    import net.minecraft.entity.merchant.villager.AbstractVillagerEntity;
    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.entity.player.ServerPlayerEntity;
    import net.minecraft.inventory.Inventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.INamedContainerProvider;
    import net.minecraft.item.ItemStack;
    import net.minecraft.item.MerchantOffer;
    import net.minecraft.nbt.CompoundNBT;
    import net.minecraft.nbt.ListNBT;
    import net.minecraft.network.PacketBuffer;
    import net.minecraft.pathfinding.GroundPathNavigator;
    import net.minecraft.util.Hand;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.util.text.ITextComponent;
    import net.minecraft.world.DifficultyInstance;
    import net.minecraft.world.IWorld;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.network.NetworkHooks;

    public abstract class SiegeEntity extends AbstractVillagerEntity {

        protected final double walkSpeed = 0.4D;
        // Convert to ItemHandler
        private final PeasantInventory peasantInventory;
        private final SiegeContainerProvider containerProvider;

        // 0 = wander, 1 = follow, 2 = locked follow, 3 = guard, 4 = locked guard.
        protected double stance = 0;
        // The main controller of this peasant
        protected UUID kingUniqueID;
        // Allowed to control this peasant and access inventory
        protected UUID[] royalFamily;
        // Will not attack/be attacked by the soldiers of people on this list
        protected UUID[] allies;

        protected BlockPos destination;
        protected ItemStack targetItem;

        public SiegeEntity(EntityType<? extends AbstractVillagerEntity> entityType, World worldIn, PlayerEntity kingIn) {
            super(entityType, worldIn);
            this.peasantInventory = new PeasantInventory(new Inventory(16), this);
            this.containerProvider = new SiegeContainerProvider(this);
            if (kingIn != null)
                this.kingUniqueID = kingIn.getUniqueID();

            ((GroundPathNavigator) this.getNavigator()).setBreakDoors(true);
            this.getNavigator().setCanSwim(true);
            this.setCanPickUpLoot(true);
        }

        @Override
        public ILivingEntityData onInitialSpawn(IWorld worldIn, DifficultyInstance difficultyIn, SpawnReason reason, ILivingEntityData spawnDataIn, CompoundNBT dataTag) {
            if (!world.isRemote && reason == SpawnReason.COMMAND)
                this.setKing(world.getClosestPlayer(this, 999).getUniqueID());
            if (this.rand.nextInt(10) == 0)
                this.setLeftHanded(true);
            return super.onInitialSpawn(worldIn, difficultyIn, reason, spawnDataIn, dataTag);
        }

        @Override
        protected void registerGoals() {
            super.registerGoals();
            this.goalSelector.addGoal(0, new SwimGoal(this));
            // We're going to need a custom avoid entity goal
            // We're going to need a custom choose target goal 
            // We're going to need a custom "wander near player bed while unclaimed but eventually wander away and despawn" goal
            this.goalSelector.addGoal(2, new MoveTowardsTargetGoal(this, this.walkSpeed, 32.0F));
            this.goalSelector.addGoal(2, new MoveTowardsVillageGoal(this, this.walkSpeed));
            this.goalSelector.addGoal(3, new MoveThroughVillageGoal(this, this.walkSpeed, false, 4, () -> {
                return false;
            }));
            this.goalSelector.addGoal(7, new LookAtGoal(this, PlayerEntity.class, 6.0F));
            this.goalSelector.addGoal(8, new LookRandomlyGoal(this));

            this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
        }

        @Override
        protected void registerAttributes() {
            super.registerAttributes();
            this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0D);
            this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(64.0D);
            this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(this.walkSpeed);

            this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(1.0D);

            this.getAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(0.0D);
            this.getAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).setBaseValue(0.0D);
            this.getAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(10.0F);
        }

        @Override
        public boolean attackEntityAsMob(Entity entityIn) {
            this.swingArm(getActiveHand());
            return super.attackEntityAsMob(entityIn);
        }

        public void livingTick() {
            this.updateArmSwingProgress();
            super.livingTick();
        }

        public void writeAdditional(CompoundNBT compound) {
            super.writeAdditional(compound);
            ListNBT listnbt = new ListNBT();
            for (int i = 0; i < this.peasantInventory.getSlots(); ++i) {
                ItemStack itemstack = this.peasantInventory.getStackInSlot(i);
                if (!itemstack.isEmpty()) {
                    listnbt.add(itemstack.write(new CompoundNBT()));
                }
            }
            compound.put("PeasantInventory", listnbt);

            if (this.kingUniqueID != null)
                compound.putUniqueId("KingId", this.kingUniqueID);
        }

        public void readAdditional(CompoundNBT compound) {
            super.readAdditional(compound);

            ListNBT listnbt = compound.getList("PeasantInventory", 10);
            for (int i = 0; i < listnbt.size(); ++i) {
                ItemStack itemstack = ItemStack.read(listnbt.getCompound(i));
                if (!itemstack.isEmpty()) {
                    this.peasantInventory.insertItem(i, itemstack, false);
                }
            }

            if (this.kingUniqueID == null && compound.hasUniqueId("KingId")) {
                this.setKing(compound.getUniqueId("KingId"));
            }
        }

        public PlayerEntity getKing() {
            return world.getPlayerByUuid(this.kingUniqueID);
        }

        public void setKing(UUID playerUUIDIn) {
            this.kingUniqueID = playerUUIDIn;
        }

        @Override
        public final boolean processInteract(PlayerEntity player, Hand hand) {
            if (hand == Hand.MAIN_HAND && !world.isRemote) {
                if (player.getUniqueID() == this.kingUniqueID && player instanceof ServerPlayerEntity && !world.isRemote) {
                    NetworkHooks.openGui((ServerPlayerEntity) player, this.containerProvider);
                    return true;
                }
            }
            return super.processInteract(player, hand);
        }

        public PeasantInventory getPeasantInventory() {
            return peasantInventory;
        }
        /*
        public DyeColor getPrimaryColor() {
            return DyeColor.byId(this.dataManager.get(COLLAR_COLOR));
        }
        
        public void setSecondaryColor(DyeColor collarcolor) {
            this.dataManager.set(COLLAR_COLOR, collarcolor.getId());
        }*/

        @Override
        public AgeableEntity createChild(AgeableEntity ageable) {
            return null;
        }

        @Override
        protected void onVillagerTrade(MerchantOffer offer) {
        }

        @Override
        protected void populateTradeData() {
        }

    }

    Container Factory:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.container.PeasantContainer;

    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.fml.network.IContainerFactory;

    public class SiegeContainerFactory implements IContainerFactory<Container> {

        @Override
        public Container create(int windowId, PlayerInventory inv, PacketBuffer data) {
            return new PeasantContainer(windowId, inv, data);
        }

    }

    Screen Factory:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.container.PeasantScreen;

    import net.minecraft.client.gui.ScreenManager.IScreenFactory;
    import net.minecraft.client.gui.screen.inventory.ContainerScreen;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.util.text.ITextComponent;

    public class SiegeScreenFactory implements IScreenFactory<Container, ContainerScreen<Container>> {

        @Override
        public ContainerScreen<Container> create(Container container, PlayerInventory inv, ITextComponent ITextComponent) {
            return new PeasantScreen(container, inv, ITextComponent);
        }

    }

    Container:

    Spoiler

    package com.siegemod.container;

    import com.mojang.datafixers.util.Pair;
    import com.siegemod.entities.SiegeEntity;

    import net.minecraft.enchantment.EnchantmentHelper;
    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.EquipmentSlotType;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.PlayerContainer;
    import net.minecraft.inventory.container.Slot;
    import net.minecraft.item.ItemStack;
    import net.minecraft.network.PacketBuffer;
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.api.distmarker.OnlyIn;

    public class PeasantContainer extends Container {

        public SiegeEntity peasant;
        public IInventory peasantInventory;

        public static final EquipmentSlotType[] VALID_EQUIPMENT_SLOTS = new EquipmentSlotType[] { EquipmentSlotType.HEAD, EquipmentSlotType.CHEST, EquipmentSlotType.LEGS, EquipmentSlotType.FEET };
        private static final ResourceLocation[] ARMOR_SLOT_TEXTURES = new ResourceLocation[] { PlayerContainer.EMPTY_ARMOR_SLOT_BOOTS, PlayerContainer.EMPTY_ARMOR_SLOT_LEGGINGS,
                PlayerContainer.EMPTY_ARMOR_SLOT_CHESTPLATE, PlayerContainer.EMPTY_ARMOR_SLOT_HELMET };

        public PeasantContainer(int containerId, PlayerInventory playerInv, PacketBuffer containerBuffer) {
            super(SiegeContainerTypes.PEASANT_CONTAINER.get(), containerId);
            this.peasant = (SiegeEntity) playerInv.player.world.getEntityByID(containerBuffer.readInt());
            this.peasantInventory = peasant.getPeasantInventory().getInv();
            this.peasantInventory.openInventory(playerInv.player);

            // MainHand 0
            this.addSlot(new Slot(this.peasantInventory, 0, 32, 62) {

                @Override
                public void onSlotChanged() {
                    super.onSlotChanged();
                    peasant.getPeasantInventory().markDirty();
                }
            });

            //Armor 1-4
            for (int row = 0; row < 4; row++) {
                final EquipmentSlotType equipmentslottype = VALID_EQUIPMENT_SLOTS[row];
                this.addSlot(new Slot(this.peasantInventory, row + 1, 8, 8 + row * 18) {

                    @Override
                    public void onSlotChanged() {
                        super.onSlotChanged();
                        peasant.getPeasantInventory().markDirty();
                    }

                    @Override
                    public int getSlotStackLimit() {
                        return 1;
                    }

                    @Override
                    public boolean isItemValid(ItemStack stack) {
                        return stack.canEquip(equipmentslottype, peasant);
                    }

                    @Override
                    public boolean canTakeStack(PlayerEntity playerIn) {
                        ItemStack itemstack = this.getStack();
                        return !itemstack.isEmpty() && !playerIn.isCreative() && EnchantmentHelper.hasBindingCurse(itemstack) ? false : super.canTakeStack(playerIn);
                    }

                    @OnlyIn(Dist.CLIENT)
                    public Pair<ResourceLocation, ResourceLocation> func_225517_c_() {
                        return Pair.of(PlayerContainer.LOCATION_BLOCKS_TEXTURE, ARMOR_SLOT_TEXTURES[equipmentslottype.getIndex()]);
                    }
                });
            }

            // OffHand 5
            this.addSlot(new Slot(this.peasantInventory, 5, 56, 62) {

                @Override
                public void onSlotChanged() {
                    super.onSlotChanged();
                    peasant.getPeasantInventory().markDirty();
                }

                @OnlyIn(Dist.CLIENT)
                public Pair<ResourceLocation, ResourceLocation> func_225517_c_() {
                    return Pair.of(PlayerContainer.LOCATION_BLOCKS_TEXTURE, PlayerContainer.EMPTY_ARMOR_SLOT_SHIELD);
                }
            });

            // Main Inventory 6-15
            final int invXPos = 80;
            final int invYPos = 8;
            final int height = 2;
            final int length = 5;
            for (int row = 0; row < height; row++)
                for (int column = 0; column < length; column++)
                    this.addSlot(new Slot(this.peasantInventory, (row * length) + column + 6, invXPos + column * 18, invYPos + row * 18));

            // Player Main Inventory
            for (int row = 0; row < 3; ++row)
                for (int column = 0; column < 9; ++column)
                    this.addSlot(new Slot(playerInv, column + row * 9 + 9, 8 + column * 18, 102 + row * 18 + -18));

            // Player Hotbar
            for (int row = 0; row < 9; ++row) {
                this.addSlot(new Slot(playerInv, row, 8 + row * 18, 142));
            }
        }

        @Override
        public boolean canInteractWith(PlayerEntity playerIn) {
            return peasant != null && ((playerIn == peasant.getKing() && playerIn.getDistance(peasant) <= PlayerEntity.REACH_DISTANCE.getDefaultValue() + 1) || playerIn.isCreative());
        }

        @Override
        public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
            ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = this.inventorySlots.get(index);
            if (slot != null && slot.getHasStack()) {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
                if (index < this.peasantInventory.getSizeInventory()) {
                    if (!this.mergeItemStack(itemstack1, this.peasantInventory.getSizeInventory(), this.inventorySlots.size(), true)) {
                        return ItemStack.EMPTY;
                    }
                } else if (!this.mergeItemStack(itemstack1, 1, this.peasantInventory.getSizeInventory(), false)) {
                    return ItemStack.EMPTY;
                }
                if (itemstack1.isEmpty()) {
                    slot.putStack(ItemStack.EMPTY);
                } else {
                    slot.onSlotChanged();
                }
            }
            return itemstack;
        }

        public SiegeEntity getPeasant() {
            return this.peasant;
        }
    }

  6. I just meant a static field to pass into NetworkHooks.openGui(ServerPlayerEntity, INamedContainerProvider, Consumer<PacketBuffer>) like so:

    Spoiler

    public static final PacketBuffer CONTAINER_PACKET = new PacketBuffer(Unpooled.buffer());

     

    So far my container factory looks like:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.container.PeasantContainer;

    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.fml.network.IContainerFactory;

    public class SiegeContainerFactory implements IContainerFactory<Container> {

        @Override
        public Container create(int windowId, PlayerInventory inv, PacketBuffer data) {
            System.out.println("IContainerFactory#CREATE WAS RUN");
            return new PeasantContainer(windowId, inv, data);
        }
    }

    And I made a screen factory:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.container.PeasantScreen;

    import net.minecraft.client.gui.ScreenManager.IScreenFactory;
    import net.minecraft.client.gui.screen.inventory.ContainerScreen;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.util.text.ITextComponent;

    public class SiegeScreenFactory implements IScreenFactory<Container, ContainerScreen<Container>> {

        @Override
        public ContainerScreen<Container> create(Container container, PlayerInventory inv, ITextComponent ITextComponent) {
            System.out.println("ScreenFactory#CREATE WAS RUN");
            return new PeasantScreen(container, inv, ITextComponent);
        }
    }

    Will both of these create() methods be run if I run NetworkHooks.openGui(ServerPlayerEntity, INamedContainerProvider, Consumer<PacketBuffer>) on the server side?

     

    Thank you so much for your patience and help.

  7. IContainerFactory doesn't have a PacketBuffer field, it only exists as a parameter in its create() method. Where does an instance of PacketBuffer come from? Or should I create my own static instance in my container factory?

     

    Implementing IContainerFactory on my container factory has me implement a create() method:

    Spoiler

        @Override
        public Container create(int windowId, PlayerInventory inv, PacketBuffer data) {
            return null;
        }
    }

    But I cannot make a static instance of my container, right? And create() is not a static method so I can't call it from somewhere else. I have nothing to pass into widowId or playerInv from here either.

    Spoiler

    package com.siegemod.container;

    import com.siegemod.SiegeMod;

    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.ContainerType;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.common.extensions.IForgeContainerType;
    import net.minecraftforge.fml.RegistryObject;
    import net.minecraftforge.fml.network.IContainerFactory;
    import net.minecraftforge.registries.DeferredRegister;
    import net.minecraftforge.registries.ForgeRegistries;

    public class SiegeContainerTypes implements IContainerFactory<Container> {

        public static final DeferredRegister<ContainerType<?>> CONTAINER_TYPES = new DeferredRegister<>(ForgeRegistries.CONTAINERS, SiegeMod.MODID);

        public static final RegistryObject<ContainerType<PeasantContainer>> PEASANT_CONTAINER = CONTAINER_TYPES.register(SiegeMod.MODID, () -> {
            return IForgeContainerType.create(PeasantContainer::new);
        });

        @Override
        public Container create(int windowId, PlayerInventory inv, PacketBuffer data) {
            return null;
        }
    }

     

  8. Update!

    I have discovered that I MUST use the required constructor:

    Spoiler

    public PeasantContainer(int containerId, PlayerInventory playerInv, PacketBuffer containerBuffer) {

    However, I need both the Screen and Container classes to identify the entity they belong to.

     

    I bet I can pass getEntityID through the PacketBuffer parameter of Container class. Do I make a new PacketBuffer in the createMenu method and give it Unpooled.buffer()?

    Spoiler

            @Override
            public Container createMenu(int containerId, PlayerInventory playerInv, PlayerEntity player) {
                return new PeasantContainer(containerId, playerInv, new PacketBuffer(Unpooled.buffer().writeInt(PEASANT.getEntityId())));
            }

    When I read it in the Container class it throws an IndexOutOfBoundsException. I will need to read up on how PacketBuffer works. I will update if I figure it out.

    Spoiler

        public PeasantContainer(int containerId, PlayerInventory playerInv, PacketBuffer containerBuffer) {
            super(SiegeContainerTypes.PEASANT_CONTAINER.get(), containerId);
            this.peasant = (SiegeEntity) playerInv.player.world.getEntityByID(containerBuffer.readInt());

     

  9. I am trying to create an entity with a gui that displays slots for their armor, mainhand, offhand, and a 10 slot inventory. Currently my gui will open when the entity is right-clicked by the player, but it is unfortunately NOT interactable.

     

    Entity Super Class - SiegeEntity:

    Spoiler

    package com.siegemod.entities;

    import com.siegemod.container.PeasantContainer;

    import net.minecraft.entity.AgeableEntity;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityType;
    import net.minecraft.entity.ILivingEntityData;
    import net.minecraft.entity.SharedMonsterAttributes;
    import net.minecraft.entity.SpawnReason;
    import net.minecraft.entity.ai.goal.HurtByTargetGoal;
    import net.minecraft.entity.ai.goal.LookAtGoal;
    import net.minecraft.entity.ai.goal.LookRandomlyGoal;
    import net.minecraft.entity.ai.goal.MoveThroughVillageGoal;
    import net.minecraft.entity.ai.goal.MoveTowardsVillageGoal;
    import net.minecraft.entity.ai.goal.SwimGoal;
    import net.minecraft.entity.ai.goal.WaterAvoidingRandomWalkingGoal;
    import net.minecraft.entity.merchant.villager.AbstractVillagerEntity;
    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.entity.player.ServerPlayerEntity;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.INamedContainerProvider;
    import net.minecraft.item.ItemStack;
    import net.minecraft.item.MerchantOffer;
    import net.minecraft.nbt.CompoundNBT;
    import net.minecraft.util.Hand;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.util.text.ITextComponent;
    import net.minecraft.world.DifficultyInstance;
    import net.minecraft.world.IWorld;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.network.NetworkHooks;

    public abstract class SiegeEntity extends AbstractVillagerEntity {

        protected final double WALK_SPEED = 0.4D;
        // Convert to ItemHandler
        //private final Inventory PEASANT_INVENTORY = new Inventory(16);

        // 0 = wander, 1 = follow, 2 = locked follow, 3 = guard, 4 = locked guard.
        protected double stance = 0;
        protected PlayerEntity king;
        protected PlayerEntity[] allies;

        protected BlockPos bedPosition;
        protected BlockPos destination;
        protected ItemStack targetItem;

        public SiegeEntity(EntityType<? extends AbstractVillagerEntity> entityType, World worldIn, PlayerEntity kingIn) {
            super(entityType, worldIn);
            // this.king = kingIn;
        }

        @Override
        protected void registerGoals() {
            this.goalSelector.addGoal(0, new SwimGoal(this));
            // We're going to need a custom avoid entity goal
            // We're going to need a custom choose target goal
            this.goalSelector.addGoal(3, new MoveTowardsVillageGoal(this, WALK_SPEED));
            this.goalSelector.addGoal(3, new MoveThroughVillageGoal(this, WALK_SPEED, false, 4, () -> {
                return true;
            }));
            this.goalSelector.addGoal(6, new WaterAvoidingRandomWalkingGoal(this, WALK_SPEED));
            this.goalSelector.addGoal(7, new LookAtGoal(this, PlayerEntity.class, 6.0F));
            this.goalSelector.addGoal(8, new LookRandomlyGoal(this));

            this.targetSelector.addGoal(2, new HurtByTargetGoal(this));
        }

        @Override
        protected void registerAttributes() {
            super.registerAttributes();
            this.getAttribute(SharedMonsterAttributes.MAX_HEALTH).setBaseValue(20.0D);
            this.getAttribute(SharedMonsterAttributes.FOLLOW_RANGE).setBaseValue(64.0D);
            this.getAttribute(SharedMonsterAttributes.MOVEMENT_SPEED).setBaseValue(0.6F);

            this.getAttributes().registerAttribute(SharedMonsterAttributes.ATTACK_DAMAGE).setBaseValue(1.0D);

            this.getAttribute(SharedMonsterAttributes.ARMOR).setBaseValue(0.0D);
            this.getAttribute(SharedMonsterAttributes.ARMOR_TOUGHNESS).setBaseValue(0.0D);
            this.getAttribute(SharedMonsterAttributes.KNOCKBACK_RESISTANCE).setBaseValue(10.0F);
        }

        @Override
        public boolean attackEntityAsMob(Entity entityIn) {
            this.swingArm(getActiveHand());
            return super.attackEntityAsMob(entityIn);
        }

        public void livingTick() {
            this.updateArmSwingProgress();
            super.livingTick();
        }

        @Override
        public ILivingEntityData onInitialSpawn(IWorld worldIn, DifficultyInstance difficultyIn, SpawnReason reason, ILivingEntityData spawnDataIn, CompoundNBT dataTag) {
            // Temporary method of choosing king. Implement join kingdom feature in future.
            if (reason == SpawnReason.COMMAND) {
                this.king = world.getClosestPlayer(this.getPosX(), this.getPosY(), this.getPosZ(), 64, false);
            }
            return super.onInitialSpawn(worldIn, difficultyIn, reason, spawnDataIn, dataTag);
        }

        @Override
        public void writeAdditional(CompoundNBT compound) {
            super.writeAdditional(compound);
        }

        @Override
        public void readAdditional(CompoundNBT compound) {
            super.readAdditional(compound);
        }

        public PlayerEntity getKing() {
            return king;
        }

        @Override
        public AgeableEntity createChild(AgeableEntity ageable) {
            return null;
        }

        @Override
        protected void onVillagerTrade(MerchantOffer offer) {
        }

        @Override
        protected void populateTradeData() {
        }

        @Override
        public final boolean processInteract(PlayerEntity player, Hand hand) {
            if (hand == Hand.MAIN_HAND) {
                if (getKing() == null) {
                    // Open join kingdom request screen.
                    // OpenGui only accepts ServerPlayerEntity
                    // Also works to ensure we are serverside
                    System.out.println("king is null");
                } else if (player == getKing() && player instanceof ServerPlayerEntity) {
                    System.out.println("king is " + player.toString());
                    NetworkHooks.openGui((ServerPlayerEntity) player, new SiegeContainerProvider(this));
                    return true;
                }
            }
            return super.processInteract(player, hand);
        }

        public static class SiegeContainerProvider implements INamedContainerProvider {

            private final SiegeEntity PEASANT;

            public SiegeContainerProvider(SiegeEntity peasantIn) {
                this.PEASANT = peasantIn;
            }

            @Override
            public Container createMenu(int containerId, PlayerInventory playerInv, PlayerEntity player) {
                return new PeasantContainer(player, PEASANT);
            }

            @Override
            public ITextComponent getDisplayName() {
                return PEASANT.getDisplayName();
            }
        }
    }

    Entity Class - PeasantEntity:

    Spoiler

    package com.siegemod.entities.friendly;

    import com.siegemod.entities.SiegeEntity;
    import com.siegemod.entities.enemy.EnemyEntity;

    import net.minecraft.entity.EntityType;
    import net.minecraft.entity.ai.goal.AvoidEntityGoal;
    import net.minecraft.entity.merchant.villager.AbstractVillagerEntity;
    import net.minecraft.entity.monster.ZombieEntity;
    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.world.World;

    public class PeasantEntity extends SiegeEntity {

        public PeasantEntity(EntityType<? extends AbstractVillagerEntity> entityType, World worldIn) {
            this(entityType, worldIn, null);
        }

        public PeasantEntity(EntityType<? extends AbstractVillagerEntity> entityType, World worldIn, PlayerEntity kingIn) {
            super(entityType, worldIn, kingIn);
        }

        @Override
        protected void registerGoals() {
            this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, EnemyEntity.class, 16.0F, WALK_SPEED, WALK_SPEED * 1.2D));
            this.goalSelector.addGoal(2, new AvoidEntityGoal<>(this, ZombieEntity.class, 16.0F, WALK_SPEED, WALK_SPEED * 1.2D));
        }
    }

    Container Class:

    Spoiler

    package com.siegemod.container;

    import com.siegemod.entities.SiegeEntity;

    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.Inventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.Slot;
    import net.minecraft.item.ItemStack;
    import net.minecraft.network.PacketBuffer;

    public class PeasantContainer extends Container {

        public SiegeEntity peasant;
        public Inventory peasantInventory;

        public PeasantContainer(int containerId, PlayerInventory playerInv, PacketBuffer containerBuffer) {
            super(SiegeContainerTypes.PEASANT_CONTAINER.get(), containerId);
        }

        public PeasantContainer(PlayerEntity player, SiegeEntity peasantIn) {
            super(SiegeContainerTypes.PEASANT_CONTAINER.get(), 0);
            // replace with ItemHandler in future
            this.peasantInventory = new Inventory(16); //peasantInventory.getPeasantInventory.getInv();
            assertInventorySize(peasantInventory, 16);
            this.peasant = peasantIn;
            /*
            // Armor Inventory
            int armorInvYPos = 8;
            int sizePerSlot = 18;
            for (int column = 0; column < 4; ++column) {
                this.addSlot(new Slot(this.peasantInventory, 4, 8, armorInvYPos + (column * sizePerSlot)));
            }
            
            // MainHand
            this.addSlot(new Slot(this.peasantInventory, 4, 32, 62));
            
            // OffHand
            this.addSlot(new Slot(this.peasantInventory, 5, 32, 62));
            
            // Main Inventory
            int invXPos = 80;
            int invYPos = 8;
            int slotsInEachRow = 5;
            for (int row = 0; row < 5; ++row) {
                for (int column = 0; column < 4; ++column) {
                    this.addSlot(new Slot(this.peasantInventory, row + column * slotsInEachRow + 6, invXPos + (column * sizePerSlot), invYPos + (row * sizePerSlot)));
                }
            }*/
            // Temporary layout
            //ARMOR
            this.addSlot(new Slot(this.peasantInventory, 0, 8, 8));
            this.addSlot(new Slot(this.peasantInventory, 1, 8, 26));
            this.addSlot(new Slot(this.peasantInventory, 2, 8, 44));
            this.addSlot(new Slot(this.peasantInventory, 3, 8, 62));
            //MAINHAND & OFFHAND
            this.addSlot(new Slot(this.peasantInventory, 4, 32, 62));
            this.addSlot(new Slot(this.peasantInventory, 5, 56, 62));
            //MAIN
            this.addSlot(new Slot(this.peasantInventory, 6, 80, 8));
            this.addSlot(new Slot(this.peasantInventory, 7, 98, 8));
            this.addSlot(new Slot(this.peasantInventory, 8, 116, 8));
            this.addSlot(new Slot(this.peasantInventory, 9, 134, 8));
            this.addSlot(new Slot(this.peasantInventory, 10, 152, 8));
            this.addSlot(new Slot(this.peasantInventory, 11, 80, 26));
            this.addSlot(new Slot(this.peasantInventory, 12, 98, 26));
            this.addSlot(new Slot(this.peasantInventory, 13, 116, 26));
            this.addSlot(new Slot(this.peasantInventory, 14, 134, 26));
            this.addSlot(new Slot(this.peasantInventory, 15, 152, 26));

            // Player Main Inventory
            for (int row = 0; row < 3; ++row) {
                for (int column = 0; column < 9; ++column) {
                    this.addSlot(new Slot(player.inventory, column + row * 9 + 9, 8 + column * 18, 102 + row * 18 + -18));
                }
            }
            // Player Hotbar
            for (int row = 0; row < 9; ++row) {
                this.addSlot(new Slot(player.inventory, row, 8 + row * 18, 142));
            }
        }

        @Override
        public boolean canInteractWith(PlayerEntity playerIn) {
            return true;// peasant != null && playerIn.getDistance(peasant) <= PlayerEntity.REACH_DISTANCE.getDefaultValue() + 1;
        }

        public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
            ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = this.inventorySlots.get(index);
            if (slot != null && slot.getHasStack()) {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
                if (index < this.peasantInventory.getSizeInventory()) {
                    if (!this.mergeItemStack(itemstack1, this.peasantInventory.getSizeInventory(), this.inventorySlots.size(), true)) {
                        return ItemStack.EMPTY;
                    }
                } else if (!this.mergeItemStack(itemstack1, 0, this.peasantInventory.getSizeInventory(), false)) {
                    return ItemStack.EMPTY;
                }

                if (itemstack1.isEmpty()) {
                    slot.putStack(ItemStack.EMPTY);
                } else {
                    slot.onSlotChanged();
                }
            }

            return itemstack;
        }

        public SiegeEntity getPeasant() {
            return this.peasant;
        }
    }

    Container Screen Class:

    Spoiler

    package com.siegemod.container;

    import com.mojang.blaze3d.systems.RenderSystem;
    import com.siegemod.SiegeMod;

    import net.minecraft.client.gui.screen.inventory.ContainerScreen;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.util.ResourceLocation;
    import net.minecraft.util.text.ITextComponent;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.api.distmarker.OnlyIn;

    @OnlyIn(Dist.CLIENT)
    public class PeasantScreen extends ContainerScreen<PeasantContainer> {

        private static final ResourceLocation PEASANT_GUI = new ResourceLocation(SiegeMod.MODID, "gui/peasant_gui.png");

        public PeasantScreen(PeasantContainer screenContainer, PlayerInventory inv, ITextComponent titleIn) {
            super(screenContainer, inv, titleIn);
            this.guiLeft = 0;
            this.guiTop = 0;
            this.xSize = 176;
            this.ySize = 166;
        }

        @Override
        protected void init() {
            super.init();
        }

        @Override
        protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
            RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
            this.getMinecraft().getTextureManager().bindTexture(PEASANT_GUI);
            int x = (this.width - this.xSize) / 2;
            int y = (this.height - this.ySize) / 2;
            this.blit(x, y, 0, 0, this.xSize, this.ySize);
        }

        @Override
        public void render(int mouseX, int mouseY, float partialTicks) {
            this.renderBackground();
            super.render(mouseX, mouseY, partialTicks);
            this.renderHoveredToolTip(mouseX, mouseY);
        }
    }

    ContainerTypes Class:

    Spoiler

    package com.siegemod.container;

    import com.siegemod.SiegeMod;

    import net.minecraft.inventory.container.ContainerType;
    import net.minecraftforge.common.extensions.IForgeContainerType;
    import net.minecraftforge.fml.RegistryObject;
    import net.minecraftforge.registries.DeferredRegister;
    import net.minecraftforge.registries.ForgeRegistries;

    public class SiegeContainerTypes {

        public static final DeferredRegister<ContainerType<?>> CONTAINER_TYPES = new DeferredRegister<>(ForgeRegistries.CONTAINERS, SiegeMod.MODID);

        public static final RegistryObject<ContainerType<PeasantContainer>> PEASANT_CONTAINER = CONTAINER_TYPES.register(SiegeMod.MODID, () -> {
            return IForgeContainerType.create(PeasantContainer::new);
        });
    }

    ClientEventBusSubscriber:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.SiegeMod;
    import com.siegemod.container.PeasantScreen;
    import com.siegemod.container.SiegeContainerTypes;
    import com.siegemod.entities.SiegeEntityTypes;
    import com.siegemod.entities.render.PeasantRenderer;

    import net.minecraft.client.gui.ScreenManager;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.eventbus.api.SubscribeEvent;
    import net.minecraftforge.fml.client.registry.RenderingRegistry;
    import net.minecraftforge.fml.common.Mod;
    import net.minecraftforge.fml.common.Mod.EventBusSubscriber.Bus;
    import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;

    @Mod.EventBusSubscriber(modid = SiegeMod.MODID, bus = Bus.MOD, value = Dist.CLIENT)
    public class ClientEventBusSubscriber {

        @SubscribeEvent
        public static void clientSetup(FMLClientSetupEvent event) {

            ScreenManager.registerFactory(SiegeContainerTypes.PEASANT_CONTAINER.get(), PeasantScreen::new);

            RenderingRegistry.registerEntityRenderingHandler(SiegeEntityTypes.PEASANT.get(), PeasantRenderer::new);
        }
    }

    Main Class:

    Spoiler

    package com.siegemod;

    import org.apache.logging.log4j.LogManager;
    import org.apache.logging.log4j.Logger;

    import com.siegemod.container.SiegeContainerTypes;
    import com.siegemod.entities.SiegeEntityTypes;

    import net.minecraft.client.Minecraft;
    import net.minecraftforge.common.MinecraftForge;
    import net.minecraftforge.eventbus.api.IEventBus;
    import net.minecraftforge.eventbus.api.SubscribeEvent;
    import net.minecraftforge.fml.common.Mod;
    import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
    import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
    import net.minecraftforge.fml.event.server.FMLServerStartingEvent;
    import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

    @Mod("siegemod")
    public class SiegeMod {
        // this is what you'll use to output anything to the log (instead of sysout if
        // you like)
        public static final Logger LOGGER = LogManager.getLogger();
        public static final String MODID = "siegemod";
        public static SiegeMod instance;
        public static Minecraft mc = Minecraft.getInstance();

        public SiegeMod() {
            final IEventBus modEventBus = FMLJavaModLoadingContext.get().getModEventBus();

            instance = this;

            FMLJavaModLoadingContext.get().getModEventBus().addListener(this::setup);
            FMLJavaModLoadingContext.get().getModEventBus().addListener(this::doClientStuff);

            MinecraftForge.EVENT_BUS.register(this);

            SiegeEntityTypes.ENTITY_TYPES.register(modEventBus);
            SiegeContainerTypes.CONTAINER_TYPES.register(modEventBus);
        }

        private void setup(final FMLCommonSetupEvent event) {

        }

        private void doClientStuff(final FMLClientSetupEvent event) {

        }

        @SubscribeEvent
        public void onServerStarting(FMLServerStartingEvent event) {

        }

        // You can use EventBusSubscriber to automatically subscribe events on the
        // contained class (this is subscribing to the MOD
        // Event bus for receiving Registry Events)
        @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD)
        public static class RegistryEvents {
        }
    }

    I will be converting from Inventory to ItemHandler soon, but for now I just want the container to open.

     

    --SOLUTION--

    Main Entity Class:

    Spoiler

    package com.siegemod.entities;

    import java.util.UUID;
    import java.util.function.Consumer;

    import com.siegemod.container.PeasantContainer;
    import com.siegemod.container.PeasantInventory;

    import net.minecraft.entity.AgeableEntity;
    import net.minecraft.entity.Entity;
    import net.minecraft.entity.EntityType;
    import net.minecraft.entity.ILivingEntityData;
    import net.minecraft.entity.SharedMonsterAttributes;
    import net.minecraft.entity.SpawnReason;
    import net.minecraft.entity.ai.goal.HurtByTargetGoal;
    import net.minecraft.entity.ai.goal.LookAtGoal;
    import net.minecraft.entity.ai.goal.LookRandomlyGoal;
    import net.minecraft.entity.ai.goal.MoveThroughVillageGoal;
    import net.minecraft.entity.ai.goal.MoveTowardsTargetGoal;
    import net.minecraft.entity.ai.goal.MoveTowardsVillageGoal;
    import net.minecraft.entity.ai.goal.SwimGoal;
    import net.minecraft.entity.merchant.villager.AbstractVillagerEntity;
    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.entity.player.ServerPlayerEntity;
    import net.minecraft.inventory.Inventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.INamedContainerProvider;
    import net.minecraft.item.ItemStack;
    import net.minecraft.item.MerchantOffer;
    import net.minecraft.nbt.CompoundNBT;
    import net.minecraft.nbt.ListNBT;
    import net.minecraft.network.PacketBuffer;
    import net.minecraft.pathfinding.GroundPathNavigator;
    import net.minecraft.util.Hand;
    import net.minecraft.util.math.BlockPos;
    import net.minecraft.util.text.ITextComponent;
    import net.minecraft.world.DifficultyInstance;
    import net.minecraft.world.IWorld;
    import net.minecraft.world.World;
    import net.minecraftforge.fml.network.NetworkHooks;

    public abstract class SiegeEntity extends AbstractVillagerEntity {
        private final PeasantInventory peasantInventory;
        private final SiegeEntityInventoryContainerProvider containerProvider;
        public SiegeEntity(EntityType<? extends AbstractVillagerEntity> entityType, World worldIn, PlayerEntity kingIn) {
            super(entityType, worldIn);
            this.peasantInventory = new PeasantInventory(new Inventory(16), this);
            this.containerProvider = new SiegeEntityInventoryContainerProvider(this);
        }
        @Override
        public final boolean processInteract(PlayerEntity player, Hand hand) {
            if (hand == Hand.MAIN_HAND && player instanceof ServerPlayerEntity && !world.isRemote) {
                    SiegeEntity peasant = this;
                    NetworkHooks.openGui((ServerPlayerEntity) player, this.containerProvider, new Consumer<PacketBuffer>() {
                        @Override
                        public void accept(PacketBuffer buffer) {
                            buffer.writeInt(peasant.getEntityId());
                        }
                    });
                    return true;
            }
            return super.processInteract(player, hand);
        }

        @Override
        public void writeAdditional(CompoundNBT compound) {
            super.writeAdditional(compound);
            ListNBT listnbt = new ListNBT();
            for (int i = 0; i < this.peasantInventory.getSlots(); ++i) {
                ItemStack itemstack = this.peasantInventory.getStackInSlot(i);
                if (!itemstack.isEmpty()) {
                    listnbt.add(itemstack.write(new CompoundNBT()));
                }
            }
            compound.put("PeasantInventory", listnbt);
        }

        @Override
        public void readAdditional(CompoundNBT compound) {
            super.readAdditional(compound);

            ListNBT listnbt = compound.getList("PeasantInventory", 10);
            for (int i = 0; i < listnbt.size(); ++i) {
                ItemStack itemstack = ItemStack.read(listnbt.getCompound(i));
                if (!itemstack.isEmpty()) {
                    this.peasantInventory.insertItem(i, itemstack, false);
                }
            }
        }

        public PeasantInventory getPeasantInventory() {
            return peasantInventory;
        }

        public class SiegeEntityInventoryContainerProvider implements INamedContainerProvider {

            private final SiegeEntity peasant;

            public SiegeEntityInventoryContainerProvider(SiegeEntity peasantIn) {
                this.peasant = peasantIn;
            }

            @Override
            public Container createMenu(int containerId, PlayerInventory playerInv, PlayerEntity player) {
                return new PeasantContainer(containerId, playerInv, this.peasant);
            }

            @Override
            public ITextComponent getDisplayName() {
                return peasant.getDisplayName();
            }
        }

    ContainerFactory:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.container.PeasantContainer;

    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.network.PacketBuffer;
    import net.minecraftforge.fml.network.IContainerFactory;

    public class SiegeContainerFactory implements IContainerFactory<Container> {

        @Override
        public Container create(int windowId, PlayerInventory inv, PacketBuffer data) {
            return new PeasantContainer(windowId, inv, data);
        }
    }

    ScreenFactory:

    Spoiler

    package com.siegemod.util;

    import com.siegemod.container.PeasantScreen;

    import net.minecraft.client.gui.ScreenManager.IScreenFactory;
    import net.minecraft.client.gui.screen.inventory.ContainerScreen;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.util.text.ITextComponent;

    public class SiegeScreenFactory implements IScreenFactory<Container, ContainerScreen<Container>> {

        @Override
        public ContainerScreen<Container> create(Container container, PlayerInventory inv, ITextComponent ITextComponent) {
            return new PeasantScreen(container, inv, ITextComponent);
        }
    }

    Container Class:

    Spoiler

    package com.siegemod.container;

    import com.mojang.datafixers.util.Pair;
    import com.siegemod.entities.SiegeEntity;

    import net.minecraft.enchantment.EnchantmentHelper;
    import net.minecraft.entity.player.PlayerEntity;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.EquipmentSlotType;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.inventory.container.PlayerContainer;
    import net.minecraft.inventory.container.Slot;
    import net.minecraft.item.ItemStack;
    import net.minecraft.network.PacketBuffer;
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.api.distmarker.OnlyIn;

    public class PeasantContainer extends Container {

        public SiegeEntity peasant;
        public IInventory peasantInventory;

        public PeasantContainer(int containerId, PlayerInventory playerInv, PacketBuffer containerBuffer) {
            this(containerId, playerInv, (SiegeEntity) playerInv.player.world.getEntityByID(containerBuffer.readInt()));
        }

        public PeasantContainer(int containerId, PlayerInventory playerInv, SiegeEntity peasantIn) {
            super(SiegeContainerTypes.PEASANT_CONTAINER.get(), containerId);
            this.peasant = peasantIn;
            this.peasantInventory = peasant.getPeasantInventory().getInv();
            this.peasantInventory.openInventory(playerInv.player);

     

            // Entity Slots

     

            // Player Main Inventory
            for (int row = 0; row < 3; ++row)
                for (int column = 0; column < 9; ++column)
                    this.addSlot(new Slot(playerInv, column + row * 9 + 9, 8 + column * 18, 102 + row * 18 + -18));

            // Player Hotbar
            for (int row = 0; row < 9; ++row) {
                this.addSlot(new Slot(playerInv, row, 8 + row * 18, 142));
            }
        }

        @Override
        public boolean canInteractWith(PlayerEntity playerIn) {
            return true;
        }

        @Override
        public ItemStack transferStackInSlot(PlayerEntity playerIn, int index) {
            ItemStack itemstack = ItemStack.EMPTY;
            Slot slot = this.inventorySlots.get(index);
            if (slot != null && slot.getHasStack()) {
                ItemStack itemstack1 = slot.getStack();
                itemstack = itemstack1.copy();
                if (index < this.peasantInventory.getSizeInventory()) {
                    if (!this.mergeItemStack(itemstack1, this.peasantInventory.getSizeInventory(), this.inventorySlots.size(), true)) {
                        return ItemStack.EMPTY;
                    }
                } else if (!this.mergeItemStack(itemstack1, 1, this.peasantInventory.getSizeInventory(), false)) {
                    return ItemStack.EMPTY;
                }
                if (itemstack1.isEmpty()) {
                    slot.putStack(ItemStack.EMPTY);
                } else {
                    slot.onSlotChanged();
                }
            }
            return itemstack;
        }

        public SiegeEntity getPeasant() {
            return this.peasant;
        }
    }

    Screen Class:

    Spoiler

    package com.siegemod.container;

    import com.mojang.blaze3d.systems.RenderSystem;
    import com.siegemod.SiegeMod;
    import com.siegemod.entities.SiegeEntity;

    import net.minecraft.client.gui.screen.inventory.ContainerScreen;
    import net.minecraft.client.gui.screen.inventory.InventoryScreen;
    import net.minecraft.entity.player.PlayerInventory;
    import net.minecraft.inventory.container.Container;
    import net.minecraft.util.ResourceLocation;
    import net.minecraft.util.text.ITextComponent;
    import net.minecraftforge.api.distmarker.Dist;
    import net.minecraftforge.api.distmarker.OnlyIn;

    @OnlyIn(Dist.CLIENT)
    public class PeasantScreen extends ContainerScreen<Container> {

        private static final ResourceLocation PEASANT_GUI = new ResourceLocation(SiegeMod.MODID, "gui/peasant_gui.png");

        private float mousePosx;
        private float mousePosY;

        private final SiegeEntity peasant;

        public PeasantScreen(Container screenContainer, PlayerInventory inv, ITextComponent titleIn) {
            super((PeasantContainer) screenContainer, inv, titleIn);
            this.peasant = ((PeasantContainer) screenContainer).getPeasant();
            this.guiLeft = 0;
            this.guiTop = 0;
            this.xSize = 176;
            this.ySize = 166;
        }

        @Override
        protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
            RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F);
            this.getMinecraft().getTextureManager().bindTexture(PEASANT_GUI);
            int i = (this.width - this.xSize) / 2;
            int j = (this.height - this.ySize) / 2;
            this.blit(i, j, 0, 0, this.xSize, this.ySize);
            InventoryScreen.drawEntityOnScreen(i + 52, j + 50, 22, (float) (i + 51) - this.mousePosx, (float) (j + 75 - 50) - this.mousePosY, this.peasant);
        }

        @Override
        public void render(int p_render_1_, int p_render_2_, float p_render_3_) {
            this.renderBackground();
            this.mousePosx = (float) p_render_1_;
            this.mousePosY = (float) p_render_2_;
            super.render(p_render_1_, p_render_2_, p_render_3_);
            this.renderHoveredToolTip(p_render_1_, p_render_2_);
        }
    }

     

  10. Hello!

     

    Title.

    The Forge Documentation page doesn't show examples of how to save/load data from other classes (like MyEventHandler), it kind of explains which methods to use, but I'm still unsure how to do it properly and I want to do it properly.

     

    Both the MyWorldSavedData#write/readNBTTagCompounds() are run, and MyEventHandler#countFullMoons() is run properly.

     

    MyWorldSavedData:

    Spoiler

    package com.ani.s;

    import net.minecraft.nbt.NBTTagCompound;
    import net.minecraft.world.World;
    import net.minecraft.world.storage.MapStorage;
    import net.minecraft.world.storage.WorldSavedData;

    public class MyWorldSavedData extends WorldSavedData {

        static final String DATA_NAME = MyVariousVariables.MODID + "_MyWorldSavedData";

        // Do I need to create a new variable in this class for every variable I want to save?
        private int amount_of_full_moons;

        public MyWorldSavedData() {
            super(DATA_NAME);
        }

        public MyWorldSavedData(String s) {
            super(s);
        }

        @Override
        public void readFromNBT(NBTTagCompound nbt) {
            amount_of_full_moons = nbt.getInteger("amount_of_full_moons");

            System.out.println("READ FROM NBT " + amount_of_full_moons);
        }

        @Override
        public NBTTagCompound writeToNBT(NBTTagCompound nbt) {
            nbt.setInteger("amount_of_full_moons", amount_of_full_moons);

            System.out.println("WRITE TO NBT " + amount_of_full_moons);
            return nbt;
        }

        public static MyWorldSavedData get(World world) {
            MapStorage storage = world.getPerWorldStorage();
            MyWorldSavedData instance = (MyWorldSavedData) storage.getOrLoadData(MyWorldSavedData.class, DATA_NAME);
            if (instance == null) {
                instance = new MyWorldSavedData();
                storage.setData(DATA_NAME, instance);
            }
            return instance;
        }
    }

    MyEventHandler:

    Spoiler

    package com.ani.s;

    import net.minecraftforge.fml.common.Mod;
    import net.minecraftforge.fml.common.eventhandler.SubscribeEvent;
    import net.minecraftforge.fml.common.gameevent.TickEvent.WorldTickEvent;

    @Mod.EventBusSubscriber
    public class MyEventHandler {

        public int amount_of_full_moons;

        @SubscribeEvent
        public void countFullMoons(WorldTickEvent event) {
            if (event.phase == event.phase.START && event.world.provider.isSurfaceWorld()) {
                // How do I properly use MyWorldSavedData to load 'amount_of_full_moons' here?

                if (event.world.getWorldTime() == 13000 && event.world.getCurrentMoonPhaseFactor() >= 1F) {
                    ++amount_of_full_moons;

                    // How do I properly use MyWorldSavedData to save 'amount_of_full_moons' here?
                    MyWorldSavedData.get(event.world).markDirty();
                }
            }
        }
    }

     

  11. 10 minutes ago, Draco18s said:

    This will always be true. Minecraft, the class, does not exist on the server.

    Ahhh thank you. What's the easiest way to call a specific entity using an entity ID on the server?

    I'm using this. ctx is the MessageContext parameter in #onMessage().

    ctx.getServerHandler().player.world.getEntityByID(message.peasant_id);

  12. Hello!

    I followed SimpleImpl as closely as I could, but my ServerMessageHandler is being run on the client side!

     

    It is printing out "Remote = true" after I add this to it:

    System.out.println("Remote = " + Minecraft.getMinecraft().world.isRemote);

     

    Here is everything:

     

    Registering my ServerMessageHandler:

    Spoiler

    package com.ani.s;

    import net.minecraftforge.fml.common.Mod;
    import net.minecraftforge.fml.common.Mod.EventHandler;
    import net.minecraftforge.fml.common.Mod.Instance;
    import net.minecraftforge.fml.common.SidedProxy;
    import net.minecraftforge.fml.common.event.FMLInitializationEvent;
    import net.minecraftforge.fml.common.event.FMLPostInitializationEvent;
    import net.minecraftforge.fml.common.event.FMLPreInitializationEvent;
    import net.minecraftforge.fml.common.network.NetworkRegistry;
    import net.minecraftforge.fml.common.network.simpleimpl.SimpleNetworkWrapper;
    import net.minecraftforge.fml.relauncher.Side;

    import com.ani.s.packets.ClientMessage;
    import com.ani.s.packets.ClientMessageHandler;
    import com.ani.s.packets.ServerMessage;
    import com.ani.s.packets.ServerMessageHandler;
    import com.ani.s.proxies.CommonProxy;

    @Mod(modid = SiegeVariables.MODID, name = SiegeVariables.NAME, version = SiegeVariables.VERSION)
    public class SiegeMod {

        @SidedProxy(serverSide = SiegeVariables.SERVER_SIDE, clientSide = SiegeVariables.CLIENT_SIDE)
        public static CommonProxy proxy;
        @Instance(SiegeVariables.MODID)
        public static SiegeMod instance;

        public static int handler_id;

        public static final SimpleNetworkWrapper MESSAGE_HANDLER_INSTANCE = NetworkRegistry.INSTANCE.newSimpleChannel(SiegeVariables.MODID);

        public static final SiegeModTab CREATIVETAB = new SiegeModTab();

        @EventHandler
        public void preInit(FMLPreInitializationEvent event) {
            SiegeModEntityRegistry.init();
            SiegeModRecipes.init();
            proxy.registerModels();
            proxy.register();
            MESSAGE_HANDLER_INSTANCE.registerMessage(ClientMessageHandler.class, ClientMessage.class, handler_id++, Side.CLIENT);
            MESSAGE_HANDLER_INSTANCE.registerMessage(ServerMessageHandler.class, ServerMessage.class, handler_id++, Side.SERVER);
        }

        @EventHandler
        public void init(FMLInitializationEvent event) {
        }

        @EventHandler
        public void postInit(FMLPostInitializationEvent event) {
        }
    }
     

    My ServerMessage:

    Spoiler

    package com.ani.s.packets;

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

    public class ServerMessage implements IMessage {
        public int peasant_id;
        public int stance;
        public ServerMessage() {
        }

        public ServerMessage(int p_peasant_id) {
            peasant_id = p_peasant_id;
        }

        public void toBytes(ByteBuf buf) {
            buf.writeInt(peasant_id);
            buf.writeInt(stance);
        }

        public void fromBytes(ByteBuf buf) {
            peasant_id = buf.readInt();
            stance = buf.readInt();
        }
    }

    And my ServerMessageHandler (ignore all the "!= null"s, I've had... issues):

    Spoiler

    package com.ani.s.packets;

    import net.minecraft.client.Minecraft;
    import net.minecraft.entity.Entity;
    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 com.ani.s.entity.EntityCitizen;

    public class ServerMessageHandler implements IMessageHandler<ServerMessage, IMessage> {

        public IMessage onMessage(ServerMessage message, MessageContext ctx) {
            if (message != null) {
                System.out.println("Remote = " + Minecraft.getMinecraft().world.isRemote);
                if (Minecraft.getMinecraft().world != null && Minecraft.getMinecraft().world.getEntityByID(message.peasant_id) != null) {
                    Entity entity = Minecraft.getMinecraft().world.getEntityByID(message.peasant_id);
                    if (entity != null && entity instanceof EntityCitizen) {
                        EntityCitizen citizen = (EntityCitizen) entity;
                        citizen.cycleStance(message.stance);
                    }
                }
            }
            return null;
        }
    }

    Packet is sent from WorkerGUI Class (WorkerGUI is opened when interacting with EntityCitizen) in #mouseReleased()

    Spoiler

    package com.ani.s.inventory;

    import net.minecraft.client.audio.SoundHandler;
    import net.minecraft.client.gui.GuiButton;
    import net.minecraft.client.gui.inventory.GuiContainer;
    import net.minecraft.client.renderer.GlStateManager;
    import net.minecraft.entity.EntityList;
    import net.minecraft.inventory.IInventory;
    import net.minecraft.util.ResourceLocation;
    import net.minecraftforge.fml.relauncher.Side;
    import net.minecraftforge.fml.relauncher.SideOnly;

    import com.ani.s.SiegeMod;
    import com.ani.s.SiegeVariables;
    import com.ani.s.entity.EntityCitizen;
    import com.ani.s.packets.ServerMessage;

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

        public final ResourceLocation TEXTURE = new ResourceLocation(SiegeVariables.MODID + ":textures/gui/worker_gui.png");

        private EntityCitizen owner;
        private final int SIZE_X = 176;
        private final int SIZE_Y = 186;
        private int button_id;

        public WorkerGUI(final EntityCitizen ent, IInventory playerInventory) {
            super(new WorkerContainer(ent, ent.getWorkerInventory(), playerInventory));
            owner = ent;
        }

        @Override
        protected void drawGuiContainerBackgroundLayer(float partialTicks, int mouseX, int mouseY) {
            GlStateManager.color(1.0F, 1.0F, 1.0F);
            this.mc.getTextureManager().bindTexture(TEXTURE);
            this.drawModalRectWithCustomSizedTexture(this.guiLeft, this.guiTop, 0, 0, SIZE_X, SIZE_Y, 256, 256);
            int pos = this.guiLeft + 30;

            GuiButton butt = new GuiButton(++button_id, this.guiLeft + 10, this.guiTop + 18, 156, 20, owner.getStringFromStance(owner.client_message.stance)) {
                @Override
                public void mouseReleased(int mouseX, int mouseY) {
                    if (mousePressed(mc, mouseX, mouseY)) {
                        ServerMessage server_message = new ServerMessage(owner.getEntityId());
                        server_message.stance = owner.stance + 1;
                        SiegeMod.MESSAGE_HANDLER_INSTANCE.sendToServer(server_message);

                    }
                }

                @Override
                public void playPressSound(SoundHandler soundHandlerIn) {
                }
            };
            this.addButton(butt);

            drawCenteredString(fontRenderer, EntityList.getEntityString(owner), pos, this.guiTop + 5, 0xFFFFFF);

            drawCenteredString(fontRenderer, owner.client_message.king_name, pos + ((SIZE_X / 3)), this.guiTop + 5, 0xFFFFFF);

            drawCenteredString(fontRenderer, "H: " + owner.client_message.saturation, pos + ((SIZE_X / 3) * 2), this.guiTop + 5, 0xFFFFFF);
        }
    }

    Thanks!

×
×
  • Create New...

Important Information

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