How verify if chest is double chest

Hi guys, need help to verify if a chest is double chest using InteractBlockEvent, i started using SpongeAPI a short time ago and I’m having difficulties compared to BukkitAPI

Sponge is a learning curve compared to Bukkit as Bukkit has the ability to assume some features of the minecraft server as it was designed to work on its own and only its own. Sponge can work with Forge (and anything if someone makes it) so Sponge can not assume.

Anyway I can think of 2 ways. One that will work on all Sponge versions until 1.12.2 (AKA it wont work on 1.13 … but its simpler to make).

Way 1 X.X-1.13+
The one that works on all versions would be to get the Tile Entity and cast it to a Chest. From there get the Inventory of the chest and then check the max size of the inventory and check if it is 54 (I think thats a double) or 27 (I think thats a single).

Way 2 X.X-1.12.2
Get all 4 main Directions (AKA NORTH, EAST, SOUTH and WEST) and then compare that with the current chest block and check for another chest block. (In Minecraft Alpha-1.12.2 Release you can not place a chest next to another chest without making it a double and then you cannot place another chest next to that double, but you can in 1.13 - I still would not recommend this way as plugins and mods can actually place single chests next to one another (I think) and it not forward compatible … not that it would be anyway

1 Like

I made it:

Code
@Listener
public void onUseTicket(InteractBlockEvent event){
    Player player = event.getCause().first(Player.class).get();
    if(event.getTargetBlock().getExtendedState().getType() == BlockTypes.CHEST){
        Chest chest = (Chest)event.getTargetBlock().getExtendedState().getType();
        if(chest.getInventory().capacity() != 54) return;
        Sponge.getServer().getBroadcastChannel().send(Text.of("It's a DoubleChest"));
    }
}

but cause this error:

Error
[Sponge]: Could not pass InteractBlockEvent$Secondary$Impl to Plugin{id=modernage, name=ModernAge Brasil, version=1.0-SNAPSHOT, source=mods\ModernAge.jar}
java.lang.AbstractMethodError: Method net/minecraft/tileentity/TileEntityChest.getInventory()Lorg/spongepowered/api/item/inventory/type/TileEntityInventory; is abstract
	at net.minecraft.tileentity.TileEntityChest.getInventory(SourceFile) ~[aky.class:?]
	at org.spongepowered.api.block.tileentity.carrier.TileEntityCarrier.getInventory(TileEntityCarrier.java:38) ~[TileEntityCarrier.class:1.8.9-4.2.0-BETA-352]
	at me.muloo.modernage.Main.onUseTicket(Main.java:72) ~[Main.class:?]
	at org.spongepowered.common.event.listener.InteractBlockEventListener_Main_onUseTicket5.handle(Unknown Source) ~[?:?]
	at org.spongepowered.common.event.RegisteredListener.handle(RegisteredListener.java:95) ~[RegisteredListener.class:1.8.9-4.2.0-BETA-352]
	at org.spongepowered.common.event.SpongeEventManager.post(SpongeEventManager.java:261) [SpongeEventManager.class:1.8.9-4.2.0-BETA-352]
	at org.spongepowered.common.event.SpongeEventManager.post(SpongeEventManager.java:274) [SpongeEventManager.class:1.8.9-4.2.0-BETA-352]
	at org.spongepowered.common.SpongeImpl.postEvent(SpongeImpl.java:129) [SpongeImpl.class:1.8.9-4.2.0-BETA-352]
	at org.spongepowered.common.event.SpongeCommonEventFactory.callInteractBlockEventSecondary(SpongeCommonEventFactory.java:633) [SpongeCommonEventFactory.class:1.8.9-4.2.0-BETA-352]
	at org.spongepowered.common.event.SpongeCommonEventFactory.callInteractBlockEventSecondary(SpongeCommonEventFactory.java:628) [SpongeCommonEventFactory.class:1.8.9-4.2.0-BETA-352]
	at net.minecraft.server.management.ItemInWorldManager.func_180236_a(SourceFile:105) [lg.class:?]
	at net.minecraft.network.NetHandlerPlayServer.func_147346_a(SourceFile:583) [lm.class:?]
	at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.func_148833_a(SourceFile:59) [ja.class:?]
	at net.minecraft.network.play.client.C08PacketPlayerBlockPlacement.func_148833_a(SourceFile:10) [ja.class:?]
	at org.spongepowered.common.network.PacketUtil.onProcessPacket(PacketUtil.java:121) [PacketUtil.class:1.8.9-4.2.0-BETA-352]
	at net.minecraft.network.PacketThreadUtil$1.redirect$onProcessPacket$0(SourceFile:39) [fh$1.class:?]
	at net.minecraft.network.PacketThreadUtil$1.run(SourceFile:13) [fh$1.class:?]
	at java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source) [?:1.8.0_161]
	at java.util.concurrent.FutureTask.run(Unknown Source) [?:1.8.0_161]
	at net.minecraft.util.Util.func_181617_a(SourceFile:44) [g.class:?]
	at net.minecraft.server.MinecraftServer.func_71190_q(SourceFile:143) [MinecraftServer.class:?]
	at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(SourceFile:299) [ko.class:?]
	at net.minecraft.server.MinecraftServer.func_71217_p(SourceFile:535) [MinecraftServer.class:?]
	at net.minecraft.server.MinecraftServer.run(SourceFile:451) [MinecraftServer.class:?]
	at java.lang.Thread.run(Unknown Source) [?:1.8.0_161]

Nice attempt. However BlockType can not be cast into a Chest. Check out “Tile Entity” link I put in the above post. Or you can take a look below. Also in java the == only applies to primitive types (aka int, double, float, char, etc.)

Summary

I have written in comments into the code with numbers, those numbers relate to text just below here.

  1. @First is a simpler way to find the first type within the cause tracker. Because I specified a player, it will find the first Player. You can read more here

  2. Personally I don’t like working with BlockSnapshots (much prefer BlockState) but because we can only get the tile entity from a location (I believe), we must get the location

  3. TileEntity is like BlockState from Bukkit (I.E if(block.getState() instanceof Chest). You can read more in the link provided in my last post.

  4. This part of the code just throws out the event if the block does not have a TileEntity attached. As all Chests have a TileEntity attached the block (if returned true for not having one) will not be a chest.

  5. This part checks that the TileEntity is a chests TileEntity as only Chests and DoubleChests can have this TileEntity. It throws out if not a chest

     @Listener
     public void onUseTicket(InteractBlockEvent event, @First Player player) { //1
         BlockSnapshot snapshot = event.getTargetBlock();
         Location<World> loc = snapshot.getLocation().get(); //2
         Optional<TileEntity> opTile = loc.getTileEntity(); //3
         if(!opTile.isPresent()){ //4
           return;
         } 
         TileEntity tile = opTile.get();
         if(!(tile instanceof Chest)) { //5
           return;
         }
         Chest chest = (Chest)tile;
         if(chest.getInventory().capacity() != 54){
           return;
         }
     }
    
1 Like

Your code works, but it only takes inventory from a single chest, even if they are connected it only takes the 27

Oh yeah. Sorry. Forgot they changed it. At the

chest.getInventory()

There is a new method called

Optional<Inventory> opInv = chest.getDoubleChestInventory();

If that is present its a double chest, if not its a single

1 Like

Hello, may take a look at Javadoc at this section :slight_smile:

https://jd.spongepowered.org/7.0.0/org/spongepowered/api/data/key/Keys.html#CONNECTED_DIRECTIONS

In fact try to get the key CONECTED DIRECTION of BlockState with::

        if(blockState.get(Keys.CONNECTED_DIRECTIONS).isPresent()){
            blockState.getTargetBlock().get(Keys.CONNECTED_DIRECTIONS).get;
        }

My bad… this method doesn’t works…

This is not true, == is also used for enums. It references memory pointers. Since enums will only have 1 instance, using == is the correct way to do this.

Ok sure i missed of the use of it in enums. But im not sure what you mean by “correct way to do this”. In his code i dont see use a enum’s

Oh i see, BlockTypes is not an enum, but still behaves the same way since they are constants.

It depends on the implementation of sponge if they are constant (besides the init where sponge gives them their actual values). Why the implementation would change these values (after the correct BlockType is set), i personally don’t see. But if you got the BlockType from somewhere else (such as from a Location object) it may not be the exact same object based on the implementation.

Just food for thought.

They are public static final, so they will never change. So no matter the implementation, they would still be the exact same object. With the exact same memory pointer?
https://re.tuck.ga/7f/9a1f

Sorry forgot they were final. But the implementation still matters as getting the object value from a block could be a brand new instance of a blocktype. You cannot rely on all implementations essentially searching for a blocktype directly from the list.

I do understand what you mean and for the most part your correct, im just bringing up a “what if” scenario

1 Like

You can use == to compare CatalogTypes such as BlockType, BlockState, EntityType etc… As mentioned in the documentation it’s guaranteed by the implementation.