Creating items and forcing them to inventory

Hello there!

I am having trouble creating items (that go into a player’s inventory). Because the docs only show how to manipulate items, I couldn’t figure out how to create items from a config value (something like ‘item: “WOODEN_HOE”’).

Is it also possible to overwrite an item in player’s inventory? Instead of “offering” the new item, “forcing” the new item (created like specified above) to a specific slot.

Thanks in advance.

@tomudding
Question 1:
There are really two ways you could create an item from the config (to create an item, just use ItemStack.builder()):

  • Serializations - ItemStack(s) can be written to the config as there object using a translator, like so (pseudo-code):

Use ConfigurateTranslator to make stuff work:

ConfigurateTranslator translator = ConfigurateTranslator.instance();
//Getting
ConfigNode someNode = ...
ItemStack.Builder builder = ItemStack.builder().fromContainer(translator.translateFrom(someNode));
//Setting
ItemStack someStack = ...
ConfigNode itemNode = translator.translateData(someStack.toContainer());
ItemStack someStack = ... ConfigNode someNode = ... someNode.getNode("item").setValue(TypeToken.of(ItemStack.class), someStack); As well as retrieved from the config: ConfigNode someNode = ... ItemStack someStack = someNode.getNode("item").getValue(TypeToken.of(ItemStack.class));
  • Custom Loading - if you don’t want the serialization in the config, and just want one or two values, you can custom load the item, doing something like (pseudo-code):
ConfigNode someNode = ...
ItemStack.Builder builder = ItemStack.builder();
builder.quantity(someNode.getNode("quantity").getInt();
ItemType type = Sponge.getRegistry().getType(ItemType.class, someNode.getNode("type").getString()).orElse(...);
builder.itemType(type);
ItemStack stack = builder.build();
//If you want to continue further, you need to use the data API
stack.offer(Keys.DISPLAY_NAME, TextSerializers.formattingCode('&').deserializeUnchecked(someNode.getNode("name").getString());

Note: If you want to use a single integer metadata in custom loading, you first have to create a config node, and then deserialize it. (Something like this)

Question 2:
I am slightly less versed in the InventoryAPI than in Item loading, but I’ll give it a go.

In the InventoryAPI, offering items is very easy, but setting items is slightly more complex, in order to do this (I believe) you have to iterate over the slots, something like this:

Inventory inventory = ...;
ItemStack stack = ...;
int index = 0;
for(Inventory slot : inventory.slots()) {
    if(index == ...) {
        slot.set(stack);
        break;
    }
    index++;
}

There may be a better way to do this, but I’m not aware of it, @mumfrey would know.

1 Like

Thanks for helping me out. I’ll look into the inventory iteration to see if I can create something funny.

[19:04:59] [Server thread/INFO] [STDERR]: [com.gmail.trentech.pji.utils.InventoryHelper:set:152]: ninja.leaping.configurate.objectmapping.ObjectMappingException: Unable to build instance of org.spongepowered.api.item.inventory.ItemStack

@TrenTech
Two possibilities:

  • I’m insane (likely)
  • The config node isn’t right (unlikely)
  • I’m wrong and item stacks can’t be serialized (impossible, they definitely are)

So what does the config node look like?

Edit:
Oh wait, answer found, I’m insane!

De-serializing an itemstack:

ConfigNode someNode = ...
ItemStack.Builder builder = ItemStack.builder().fromContainer(ConfigurateTranslator.instance().translateFrom(node));

I guess I figured that Sponge had made typetokens and stuff for them… guess not.

Actually I tried that too and couldn’t get it to work either. The ItemStack Builder complained that there was no itemtype set or something. I’ll have to sift through the logs.

I think we’re all insane

EDIT: here it is. I’m %100 sure the node is correct so I have no idea why its not working

java.lang.IllegalStateException: Item type has not been set
        at com.google.common.base.Preconditions.checkState(Preconditions.java:176) ~[minecraft_server.1.8.9.jar:?]
        at org.spongepowered.common.item.inventory.SpongeItemStackBuilder.build(SpongeItemStackBuilder.java:222) ~[SpongeItemStackBuilder.class:1.8.9-1722-3.1.0-BETA-1131]
        at com.gmail.trentech.pji.utils.InventoryHelper.set(InventoryHelper.java:132) ~[InventoryHelper.class:?]
        at com.gmail.trentech.pji.EventManager.ClientConnectionEventJoin(EventManager.java:25) ~[EventManager.class:?]
        at org.spongepowered.common.event.listener.JoinListener_EventManager_ClientConnectionEventJoin39.handle(Unknown Source) ~[?:?]
        at org.spongepowered.common.event.RegisteredListener.handle(RegisteredListener.java:86) ~[RegisteredListener.class:1.8.9-1722-3.1.0-BETA-1131]
        at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:236) [SpongeModEventManager.class:1.8.9-1722-3.1.0-BETA-1131]
        at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:196) [SpongeModEventManager.class:1.8.9-1722-3.1.0-BETA-1131]
        at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:276) [SpongeModEventManager.class:1.8.9-1722-3.1.0-BETA-1131]
        at org.spongepowered.mod.event.SpongeModEventManager.post(SpongeModEventManager.java:248) [SpongeModEventManager.class:1.8.9-1722-3.1.0-BETA-1131]
        at org.spongepowered.common.SpongeImpl.postEvent(SpongeImpl.java:127) [SpongeImpl.class:1.8.9-1722-3.1.0-BETA-1131]
        at net.minecraft.server.management.ServerConfigurationManager.initializeConnectionToPlayer(ServerConfigurationManager.java:319) [lx.class:?]
        at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.completeServerSideConnection(NetworkDispatcher.java:239) [NetworkDispatcher.class:?]
        at net.minecraftforge.fml.common.network.handshake.NetworkDispatcher.serverToClientHandshake(NetworkDispatcher.java:142) [NetworkDispatcher.class:?]
        at net.minecraftforge.fml.common.network.internal.FMLNetworkHandler.fmlServerHandshake(FMLNetworkHandler.java:65) [FMLNetworkHandler.class:?]
        at net.minecraft.server.network.NetHandlerLoginServer.func_147326_c(NetHandlerLoginServer.java:133) [lo.class:?]
        at net.minecraft.server.network.NetHandlerLoginServer.func_73660_a(NetHandlerLoginServer.java:60) [lo.class:?]
        at net.minecraft.network.NetworkManager.func_74428_b(NetworkManager.java:289) [ek.class:?]
        at net.minecraft.network.NetworkSystem.func_151269_c(NetworkSystem.java:189) [ll.class:?]
        at net.minecraft.server.MinecraftServer.func_71190_q(MinecraftServer.java:724) [MinecraftServer.class:?]
        at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(DedicatedServer.java:344) [ko.class:?]
        at net.minecraft.server.MinecraftServer.func_71217_p(MinecraftServer.java:605) [MinecraftServer.class:?]
        at net.minecraft.server.MinecraftServer.run(MinecraftServer.java:481) [MinecraftServer.class:?]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_66]

I have a problem with offering the item to the player’s inventory. I use

Optional<ItemType> typeOptional = Sponge.getRegistry().getType(ItemType.class, "magma_cream");
if (typeOptional.isPresent()) {
    ItemType item = typeOptional.get();

    ItemStack stack = ItemStack.builder().itemType(item).quantity(1).build();
    player.getInventory().offer(stack); // this is line 112
}

but I get this error

java.lang.IllegalStateException
	at com.google.common.base.Preconditions.checkState(Preconditions.java:161) ~[minecraft_server.1.8.jar:?]
	at org.spongepowered.api.item.inventory.transaction.InventoryTransactionResult$Builder.build(InventoryTransactionResult.java:181) ~[InventoryTransactionResult$Builder.class:1.8-3.0.0-BETA-132]
	at org.spongepowered.common.item.inventory.adapter.impl.Adapter$Logic.appendSequential(Adapter.java:222) ~[Adapter$Logic.class:1.8-3.0.0-BETA-132]
	at org.spongepowered.common.item.inventory.adapter.impl.Adapter$Logic.appendSequential(Adapter.java:193) ~[Adapter$Logic.class:1.8-3.0.0-BETA-132]
	at org.spongepowered.common.item.inventory.adapter.impl.MinecraftInventoryAdapter.offer(MinecraftInventoryAdapter.java:72) ~[MinecraftInventoryAdapter.class:1.8-3.0.0-BETA-132]
	at nl.tomudding.plugins.sponge.items.SpongeItems.onPlayerJoin(SpongeItems.java:112) ~[SpongeItems.class:?]
	at org.spongepowered.common.event.listener.JoinListener_SpongeItems_onPlayerJoin6.handle(Unknown Source) ~[?:?]
	at org.spongepowered.common.event.RegisteredListener.handle(RegisteredListener.java:86) ~[RegisteredListener.class:1.8-3.0.0-BETA-132]
	at org.spongepowered.common.event.SpongeEventManager.post(SpongeEventManager.java:247) [SpongeEventManager.class:1.8-3.0.0-BETA-132]
	at org.spongepowered.common.event.SpongeEventManager.post(SpongeEventManager.java:258) [SpongeEventManager.class:1.8-3.0.0-BETA-132]
	at org.spongepowered.common.SpongeImpl.postEvent(SpongeImpl.java:117) [SpongeImpl.class:1.8-3.0.0-BETA-132]
	at net.minecraft.server.management.ServerConfigurationManager.initializeConnectionToPlayer(SourceFile:309) [sn.class:?]
	at net.minecraft.server.management.ServerConfigurationManager.func_72355_a(SourceFile:132) [sn.class:?]
	at net.minecraft.server.network.NetHandlerLoginServer.func_147326_c(SourceFile:96) [rq.class:?]
	at net.minecraft.server.network.NetHandlerLoginServer.func_73660_a(SourceFile:54) [rq.class:?]
	at net.minecraft.network.NetworkManager.func_74428_b(SourceFile:187) [gr.class:?]
	at net.minecraft.network.NetworkSystem.func_151269_c(SourceFile:151) [rc.class:?]
	at net.minecraft.server.MinecraftServer.func_71190_q(SourceFile:176) [MinecraftServer.class:?]
	at net.minecraft.server.dedicated.DedicatedServer.func_71190_q(SourceFile:305) [po.class:?]
	at net.minecraft.server.MinecraftServer.func_71217_p(SourceFile:531) [MinecraftServer.class:?]
	at net.minecraft.server.MinecraftServer.run(SourceFile:447) [MinecraftServer.class:?]
	at java.lang.Thread.run(Unknown Source)

I may ne mistaken, but I don’t think players are fully loaded on ClientConnectionEvemt.Join, try testing that code on a different event.

It wasn’t the ClientConnectionEvent, it was the way I created/set the Player object in the event.

Edit: no, it doesn’t work on 3.0.0 (SpongeAPI/Vanilla), but it works on 3.1.0

@TrenTech
Could you print out the data just before you try to deserialize it?

@tomudding Is everything is working now or are there still issues?

This is the string out before deserialization

node.getString()

{ItemType=minecraft:sand, ContentVersion=1, UnsafeDamage=1, Count=7}

Can you print out what the DataView that is translated from the translator looks like? There’s several things that could be going wrong.

MemoryDataContainer{map={1=MemoryDataView{path=1, map={ItemType=minecraft:sand, ContentVersion=1, UnsafeDamage=1, Count=7}}}}

@zml Could this be an issue with how Configurate is storing things in a ConfigurationNode? I’m pretty sure that the translator is simply needing to be fixed in this regard.

@TrenTech, what you can do for now is call view = view.getView(DataQuery.of("1")).get() and then use that to translate into an ItemStack.

still get the same error

outputs

MemoryDataView{path=1, map={Count=8, ItemType=minecraft:stone, ContentVersion=1, UnsafeDamage=4}}

I’m getting the same issue when trying to deserialize ItemStack’s from ConfigurateNodes - any news on this issue?

This has been fixed as of Fix ConfigurateTranslator not translating Maps and Lists in nodes wit… · SpongePowered/SpongeAPI@6066a68 · GitHub