Jump to content

Can/How Get A Server Sided Container


8iggy

Recommended Posts

To begin where are you trying to access info for the container? From the server or client? If it's the latter you'll need to send a C2S packet. Then the easiest way to collect info is when the player opens the inventory, since they have a containerMenu variable. The packet would look something like:

 Spoiler
public class C2SPacketForContainer {
    private final String input1;
    private final String input2;

    public C2SPacketForContainer(String input1, String input2) {
        this.input1 = input1;
        this.input2 = input2;
    }
    public C2SPacketForContainer(PacketBuffer packetBuffer) {
        input1 = packetBuffer.readUtf();
        input2 = packetBuffer.readUtf();
    }

    public void encode(PacketBuffer packetBuffer) {
        packetBuffer.writeUtf(input1);
        packetBuffer.writeUtf(input2);
    }

    public static C2SPacketForContainer decode(PacketBuffer packetBuffer) {
        return new C2SPacketForContainer(packetBuffer.readUtf(), packetBuffer.readUtf());
    }

    public void handle(Supplier<NetworkEvent.Context> supplier) {
        NetworkEvent.Context context = supplier.get();
        context.enqueueWork(() -> {
            ServerPlayerEntity player = context.getSender();
            if (player != null) {
                Container container = player.containerMenu;
                if (container instanceof MyContainer) {
                    MyContainer menu = (MyContainer) container;
                    (do stuff)
                }
            }
        });
        context.setPacketHandled(true);
    }
}

 

Edited by urbanxx001
Link to comment
Share on other sites

7 minutes ago, urbanxx001 said:

To begin where are you trying to access info for the container? From the server or client? If it's the latter you'll need to send a C2S packet. Then the easiest way to collect info is when the player opens the inventory, since they have a containerMenu variable. The packet would look something like:

  Hide contents
public class C2SPacketForContainer {
    private final String input1;
    private final String input2;

    public C2SPacketForContainer(String input1, String input2) {
        this.input1 = input1;
        this.input2 = input2;
    }
    public C2SPacketForContainer(PacketBuffer packetBuffer) {
        input1 = packetBuffer.readUtf();
        input2 = packetBuffer.readUtf();
    }

    public void encode(PacketBuffer packetBuffer) {
        packetBuffer.writeUtf(input1);
        packetBuffer.writeUtf(input2);
    }

    public static C2SPacketForContainer decode(PacketBuffer packetBuffer) {
        return new C2SPacketForContainer(packetBuffer.readUtf(), packetBuffer.readUtf());
    }

    public void handle(Supplier<NetworkEvent.Context> supplier) {
        NetworkEvent.Context context = supplier.get();
        context.enqueueWork(() -> {
            ServerPlayerEntity player = context.getSender();
            if (player != null) {
                Container container = player.containerMenu;
                if (container instanceof MyContainer) {
                    MyContainer menu = (MyContainer) container;
                    (do stuff)
                }
            }
        });
        context.setPacketHandled(true);
    }
}

 

I'm trying to get it info from the server and into the client. I'm still new to forge so I'm not sure if this will work for that.

Link to comment
Share on other sites

17 minutes ago, urbanxx001 said:

To begin where are you trying to access info for the container? From the server or client? If it's the latter you'll need to send a C2S packet. Then the easiest way to collect info is when the player opens the inventory, since they have a containerMenu variable. The packet would look something like:

  Hide contents
public class C2SPacketForContainer {
    private final String input1;
    private final String input2;

    public C2SPacketForContainer(String input1, String input2) {
        this.input1 = input1;
        this.input2 = input2;
    }
    public C2SPacketForContainer(PacketBuffer packetBuffer) {
        input1 = packetBuffer.readUtf();
        input2 = packetBuffer.readUtf();
    }

    public void encode(PacketBuffer packetBuffer) {
        packetBuffer.writeUtf(input1);
        packetBuffer.writeUtf(input2);
    }

    public static C2SPacketForContainer decode(PacketBuffer packetBuffer) {
        return new C2SPacketForContainer(packetBuffer.readUtf(), packetBuffer.readUtf());
    }

    public void handle(Supplier<NetworkEvent.Context> supplier) {
        NetworkEvent.Context context = supplier.get();
        context.enqueueWork(() -> {
            ServerPlayerEntity player = context.getSender();
            if (player != null) {
                Container container = player.containerMenu;
                if (container instanceof MyContainer) {
                    MyContainer menu = (MyContainer) container;
                    (do stuff)
                }
            }
        });
        context.setPacketHandled(true);
    }
}

 

So I put It into my code and it seems like the class PacketBuffer doesn't have a method called write/readUtf. I'm currently using 1.16.5 forge. And I also don't know how to use the class.

for example

C2SPacketForContainer packet = new C2SPacketForContainer(what do i put here?);

 

Link to comment
Share on other sites

42 minutes ago, 8iggy said:

So I put It into my code and it seems like the class PacketBuffer doesn't have a method called write/readUtf. I'm currently using 1.16.5 forge. And I also don't know how to use the class.

The inputs are just a template- in this case it's two strings, but they can be ints, chars, etc. or none at all, depending if you need to initially send info across sides. I'd suggest reading Forge's documentation on packets first if you haven't used them before: 
Forge Docs Networking

You usually send the packet by invoking handler methods:

ModPacketHandler.sendToServer(new C2SPacketForContainer(input1, input2));

Where the handler class has packet registration and the methods:

Spoiler
public class ModPacketHandler {
    public static int networkId = 0;

    private static final String NETWORK_PROTOCOL_VERSION = "1";
    public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel(
            Main.getLocation("main"),
            () -> NETWORK_PROTOCOL_VERSION,
            NETWORK_PROTOCOL_VERSION::equals,
            NETWORK_PROTOCOL_VERSION::equals
    );

    public static void registerC2SPackets() {
        CHANNEL.registerMessage(networkId++,
                C2SPacketForContainer.class,
                C2SPacketForContainer::encode,
                C2SPacketForContainer::decode,
                C2SPacketForContainer::handle,
                Optional.of(NetworkDirection.PLAY_TO_SERVER)
        );
    }

    public static void registerS2CPackets() {
        CHANNEL.registerMessage(networkId++,
                S2CPacketForContainer.class,
                S2CPacketForContainer::encode,
                S2CPacketForContainer::decode,
                S2CPacketForContainer::handle,
                Optional.of(NetworkDirection.PLAY_TO_CLIENT)
        );
    };

	// The only C2S Method

    /**
     * Sends a packet to the server
     * @param msg  Packet to send
     */
    public static void sendToServer(Object msg) {
        CHANNEL.sendToServer(msg);
    }

	// Multiple S2C Methods

    /**
     * Sends a packet to a player
     * @param msg     Packet to send
     * @param player  Player to send to
     */
    public static void sendToClient(Object msg, ServerPlayerEntity player) {
        if (!(player instanceof FakePlayer)) {
            CHANNEL.sendTo(msg, player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
        }
    }

    /**
     * Sends a packet to players tracking an entity. For tile entities, use chunk or all method instead.
     * @param msg     Packet to send
     * @param entity  Entity being tracked
     */
    public static void sendToClientsTrackingEntity(Object msg, Entity entity) {
        CHANNEL.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), msg);
    }

    /**
     * Sends a packet to the sender and players tracking an entity. For tile entities, use chunk or all method instead.
     * @param msg     Packet to send
     * @param entity  Entity being tracked
     */
    public static void sendToClientAndClientsTrackingEntity(Object msg, Entity entity) {
        CHANNEL.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), msg);
    }

    /**
     * Sends a packet to players within a chunk at a position
     * @param msg          Packet to send
     * @param serverWorld  World instance
     * @param pos          Position within chunk
     */
    public static void sendToClientsTrackingChunk(Object msg, ServerWorld serverWorld, BlockPos pos) {
        Chunk chunk = serverWorld.getChunkAt(pos);
        CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> chunk), msg);
    }

    /**
     * Sends a packet to all players
     * @param msg  Packet to send
     */
    public static void sendToAllClients(Object msg) {
        CHANNEL.send(PacketDistributor.ALL.noArg(), msg);
    }

}

 

The register methods are called in common setup.

Spoiler
 private static void commonSetup(FMLCommonSetupEvent event) {
        event.enqueueWork(() -> {
            ModPacketHandler.registerC2SPackets();
            ModPacketHandler.registerS2CPackets();
        });
}

 

Edited by urbanxx001
Link to comment
Share on other sites

19 hours ago, urbanxx001 said:

The inputs are just a template- in this case it's two strings, but they can be ints, chars, etc. or none at all, depending if you need to initially send info across sides. I'd suggest reading Forge's documentation on packets first if you haven't used them before: 
Forge Docs Networking

You usually send the packet by invoking handler methods:

ModPacketHandler.sendToServer(new C2SPacketForContainer(input1, input2));

Where the handler class has packet registration and the methods:

  Reveal hidden contents
public class ModPacketHandler {
    public static int networkId = 0;

    private static final String NETWORK_PROTOCOL_VERSION = "1";
    public static final SimpleChannel CHANNEL = NetworkRegistry.newSimpleChannel(
            Main.getLocation("main"),
            () -> NETWORK_PROTOCOL_VERSION,
            NETWORK_PROTOCOL_VERSION::equals,
            NETWORK_PROTOCOL_VERSION::equals
    );

    public static void registerC2SPackets() {
        CHANNEL.registerMessage(networkId++,
                C2SPacketForContainer.class,
                C2SPacketForContainer::encode,
                C2SPacketForContainer::decode,
                C2SPacketForContainer::handle,
                Optional.of(NetworkDirection.PLAY_TO_SERVER)
        );
    }

    public static void registerS2CPackets() {
        CHANNEL.registerMessage(networkId++,
                S2CPacketForContainer.class,
                S2CPacketForContainer::encode,
                S2CPacketForContainer::decode,
                S2CPacketForContainer::handle,
                Optional.of(NetworkDirection.PLAY_TO_CLIENT)
        );
    };

	// The only C2S Method

    /**
     * Sends a packet to the server
     * @param msg  Packet to send
     */
    public static void sendToServer(Object msg) {
        CHANNEL.sendToServer(msg);
    }

	// Multiple S2C Methods

    /**
     * Sends a packet to a player
     * @param msg     Packet to send
     * @param player  Player to send to
     */
    public static void sendToClient(Object msg, ServerPlayerEntity player) {
        if (!(player instanceof FakePlayer)) {
            CHANNEL.sendTo(msg, player.connection.connection, NetworkDirection.PLAY_TO_CLIENT);
        }
    }

    /**
     * Sends a packet to players tracking an entity. For tile entities, use chunk or all method instead.
     * @param msg     Packet to send
     * @param entity  Entity being tracked
     */
    public static void sendToClientsTrackingEntity(Object msg, Entity entity) {
        CHANNEL.send(PacketDistributor.TRACKING_ENTITY.with(() -> entity), msg);
    }

    /**
     * Sends a packet to the sender and players tracking an entity. For tile entities, use chunk or all method instead.
     * @param msg     Packet to send
     * @param entity  Entity being tracked
     */
    public static void sendToClientAndClientsTrackingEntity(Object msg, Entity entity) {
        CHANNEL.send(PacketDistributor.TRACKING_ENTITY_AND_SELF.with(() -> entity), msg);
    }

    /**
     * Sends a packet to players within a chunk at a position
     * @param msg          Packet to send
     * @param serverWorld  World instance
     * @param pos          Position within chunk
     */
    public static void sendToClientsTrackingChunk(Object msg, ServerWorld serverWorld, BlockPos pos) {
        Chunk chunk = serverWorld.getChunkAt(pos);
        CHANNEL.send(PacketDistributor.TRACKING_CHUNK.with(() -> chunk), msg);
    }

    /**
     * Sends a packet to all players
     * @param msg  Packet to send
     */
    public static void sendToAllClients(Object msg) {
        CHANNEL.send(PacketDistributor.ALL.noArg(), msg);
    }

}

 

The register methods are called in common setup.

  Reveal hidden contents
 private static void commonSetup(FMLCommonSetupEvent event) {
        event.enqueueWork(() -> {
            ModPacketHandler.registerC2SPackets();
            ModPacketHandler.registerS2CPackets();
        });
}

 

Thanks! In The ModPacketHandler Class. What Is Main? If It's My Main Class getLocation Isn't A Method In It.

Edited by 8iggy
Link to comment
Share on other sites

15 hours ago, 8iggy said:

Thanks! In The ModPacketHandler Class. What Is Main? If It's My Main Class getLocation Isn't A Method In It.

Sorry, yes Luis is right it's just a helper function for resourcelocation:

public static ResourceLocation getLocation(String name) {
        return new ResourceLocation(MOD_ID, name);
    }

As he and diesieben said though, if it's a simple problem like calling openGui and registering the screen, then packets are unnecessary, but you need to describe it in more detail. 

Edited by urbanxx001
Link to comment
Share on other sites

8 hours ago, urbanxx001 said:

Sorry, yes Luis is right it's just a helper function for resourcelocation:

public static ResourceLocation getLocation(String name) {
        return new ResourceLocation(MOD_ID, name);
    }

As he and diesieben said though, if it's a simple problem like calling openGui and registering the screen, then packets are unnecessary, but you need to describe it in more detail. 

Can I access all the items using openGUI or registering the screen?

Link to comment
Share on other sites

11 hours ago, urbanxx001 said:

Sorry, yes Luis is right it's just a helper function for resourcelocation:

public static ResourceLocation getLocation(String name) {
        return new ResourceLocation(MOD_ID, name);
    }

As he and diesieben said though, if it's a simple problem like calling openGui and registering the screen, then packets are unnecessary, but you need to describe it in more detail. 

Thanks! I'm going to test this but I'm still having some errors with other stuff. If it's ok with you can I send a message here if I have anymore issues?

Link to comment
Share on other sites

21 hours ago, Luis_ST said:

You still capitalizing every word...

the name sounds like it will return a ResourceLocation or the mod id, not sure because urbanxx001 didn't say what the method does

can you actually explain your exact goal to us, because it can be that there is a easier way to do this

I always say the same thing every time and people still don't get it but I'm trying to get all the items from a server sided menu/inventory. Get all the info in them aswell, like the lore and display name. I figured out how to do it all but don't know how to get an instance of a server menu/inventory.

Link to comment
Share on other sites

19 minutes ago, 8iggy said:

but don't know how to get an instance of a server menu/inventory.

You can't if you're on the client. That's why packets exist and why OpenGui does what it does.

You can only interact with the data the client knows about and OpenGui will send the inventory contents to the client (including all of the lore, because how else would you be able to see it?)

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

 

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

 

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

Link to comment
Share on other sites

41 minutes ago, 8iggy said:

Thanks! I'm going to test this but I'm still having some errors with other stuff. If it's ok with you can I send a message here if I have anymore issues?

Of course this is your thread and we're here to help you.

If the place you're trying to access the items is a part of the inventory object (the block, tile entity, container, etc. classes) then it's easier. But if you're still in the process of creating your inventory, I'd suggest any of the following:

-Forge docs on Tile Entities

-Minecraft By Example topics. 

-Examine the source code for objects like Chests.

38 minutes ago, 8iggy said:

 I figured out how to do it all but don't know how to get an instance of a server menu/inventory.

Outside of block/TE/container, an easy way is the player's containerMenu value that I mentioned before, which is whatever menu is currently open:

Container container = player.containerMenu
Edited by urbanxx001
Link to comment
Share on other sites

33 minutes ago, urbanxx001 said:

Of course this is your thread and we're here to help you.

If the place you're trying to access the items is a part of the inventory object (the block, tile entity, container, etc. classes) then it's easier. But if you're still in the process of creating your inventory, I'd suggest any of the following:

-Forge docs on Tile Entities

-Minecraft By Example topics. 

-Examine the source code for objects like Chests.

Outside of block/TE/container, an easy way is the player's containerMenu value that I mentioned before, which is whatever menu is currently open:

Container container = player.containerMenu

I feel really dumb... Sorry for being such a pain. Thanks to everyone who replied to this thread!

  • Like 1
Link to comment
Share on other sites

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.