Jump to content

Texture for an ItemGroup not appearing, but that item's texture works fine as an item


Recommended Posts

Posted

This picture shows it perfectly. The item's texture works fine, but when it is used in an ItemGroup it doesn't show up. There's nothing in the log that indicates a problem.

 

The ItemGroup is created with the item shown there using this:

public static final ModItemGroup modItemGroup = new ModItemGroup("ModItemGroup", new ItemStack(ItemInit.moditem));

 

Which refers to this:

public class ModItemGroup extends net.minecraft.item.ItemGroup {

    private ItemStack icon;

    public ModItemGroup(String label, ItemStack icon) {
        super(label);
        this.icon = icon;
    }

    @OnlyIn(Dist.CLIENT)
    @Override
    public ItemStack createIcon() {
        return icon;
    }
}

 

The item it's using is very simple, but just in case I set it up incorrectly here it is:

public class ModItem extends Item {

    public ModItem() {
        super(new Properties().group(ItemGroupInit.modItemGroup));
    }
}

 

What's going on here?

Posted
49 minutes ago, TheKingElessar said:

public static final ModItemGroup modItemGroup

You have a static initializer. This will cause your code to run at an unpredictable time. In this case, it runs before Items are registered.

  • Like 1

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.

Posted (edited)

Like Draco said, the ItemGroup constructor is called before your ItemInit.moditem has even been created. Generally, you can assume that ItemGroups are created before Items are.

This is what I do to get around it:

 

public class ModItemGroup extends net.minecraft.item.ItemGroup {

    private IItemProvider icon;

    public ModItemGroup(String label, IItemProvider icon) {
        super(label);
        this.icon = icon;
    }

    @OnlyIn(Dist.CLIENT)
    @Override
    public ItemStack createIcon() {
        return new ItemStack(icon);
    }
}

 

public static final ModItemGroup modItemGroup = new ModItemGroup("ModItemGroup", ()->(ItemInit.moditem));

 

Normally I would use Supplier<Item> here, but IItemProvider already does the same thing with better integration such as being able to be passed directly to an ItemStack's constructor.

 

This doesn't care whether moditem has already been initialized when modItemGroup is created. It only needs to exist by the time modItemGroup.createIcon() is called.
Either way though, static initializers are unpredictable and that's why I personally avoid them wherever possible.

Edited by TheOnlyTrueEnte
more context
  • Like 2
Posted (edited)

It took me a good while to finally wrap my head around the lambda statement, but I finally understand it! Your solution works great.

 

Question:

17 hours ago, TheOnlyTrueEnte said:

It only needs to exist by the time modItemGroup.createIcon() is called

Why is this? How is this different from my original (not working) method? Does it have to do with this code in the ItemStack constructor?

this.item = itemIn == null ? null : itemIn.asItem();

When modItem hasn't been created yet and modItemGroup is created, does it set the modItemGroup's ItemStack's Item as null? If so, how does it then update it? I could be very far off the mark for why it works, though, so please correct me.

 

Another question:

17 hours ago, TheOnlyTrueEnte said:

Either way though, static initializers are unpredictable and that's why I personally avoid them wherever possible

I'm pretty (completely) new to Forge, what are some alternatives to static initializers? Is the static keyword even needed? That's just what I saw being used in one case online.

Edited by TheKingElessar
Posted
  • Thanks 2

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
16 hours ago, TheKingElessar said:

Question:

Why is this? How is this different from my original (not working) method? Does it have to do with this code in the ItemStack constructor?


this.item = itemIn == null ? null : itemIn.asItem();

When modItem hasn't been created yet and modItemGroup is created, does it set the modItemGroup's ItemStack's Item as null? If so, how does it then update it? I could be very far off the mark for why it works, though, so please correct me.

The ItemStack constructor isn't the problem. When you do this:

public static final ModItemGroup modItemGroup = new ModItemGroup("ModItemGroup", new ItemStack(ItemInit.moditem));

ItemInit.moditem hasn't been constructed yet. So its value is actually null and that's what gets passed to the ItemStack constructor. If the constructor was simply:

this.item = ItemIn.asItem();

You'd get a NullPointerException because you can't do null.asItem(). You just can't create an ItemStack from moditem yet, there's no way around it, so you have to create it at a later time, like in ItemGroup#createIcon.

The next logical step would be doing this:

//don't do this it doesn't work
public class ModItemGroup extends net.minecraft.item.ItemGroup {

    private Item icon;

    public ModItemGroup(String label, Item icon) {
        super(label);
        this.icon = icon;
    }

    @OnlyIn(Dist.CLIENT)
    @Override
    public ItemStack createIcon() {
        return new ItemStack(icon);
    }
}

You create an ItemStack in createIcon from the Item that you directly pass to your ModItemGroup's constructor. You still have the same problem though, moditem is null by the time the constructor's called and this.icon = icon just sets the Item icon to null. What you need is a reference to the Item that is updated when the Item is finally initialized. Java doesn't have references but the lambda ()->ItemList.moditem acts as one. If you evaluate it before moditem is inizialited, it returns null. If you evaluate it after it's initialized, such as in ItemGroup#createIcon, it correctly returns your item.

Posted
3 minutes ago, TheKingElessar said:

So I was able to get the @ObjectHolder annotation working for my Items, but my ItemGroups are still using static initializers. Since you don't register ItemGroups how should I do this with them?

I'm very new to Forge modding so take it with a grain of salt, but I have a static method ModItemGroup#initialize that initializes the fields. I call that method in the first line of my Item registry event listener. I hate that this prevents my ItemGroups from being final but I'm sure there's a way to inject them, similarly to how @ObjectHolder works.

Posted
9 minutes ago, TheOnlyTrueEnte said:

If you evaluate it after it's initialized, such as in ItemGroup#createIcon, it correctly returns your item.

So the class extending net.minecraft.item.ItemGroup (in my case ModItemGroup) is created, the IItemProvider "icon" contains a null Item because the Item it refers to hasn't been registered yet, then createIcon is called after Item initialization, which creates a new ItemStack from the Item stored in "icon". This last part I'm not quite understanding: when the ItemStack is created, doesn't it use the null Item? As far as I can tell it doesn't recreate it or refresh it or whatever.

 

 
 
 
14 minutes ago, TheOnlyTrueEnte said:

I call that method in the first line of my Item registry event listener.

I was about to ask why you wouldn't do it after all the items have been registered, therefore avoiding this entire problem, but then I realized when items are registered they have to be initialized, meaning they have to be assigned (if you want them part of one) to an ItemGroup.

 

Okay, I think I understand it all now except for my above question. Thanks for the explanation!

Posted
21 minutes ago, TheOnlyTrueEnte said:

I'm very new to Forge modding so take it with a grain of salt, but I have a static method ModItemGroup#initialize that initializes the fields. I call that method in the first line of my Item registry event listener. I hate that this prevents my ItemGroups from being final but I'm sure there's a way to inject them, similarly to how @ObjectHolder works.

Actually, could you go into this a little more? I'm not quite understanding how you can avoid a static variable but still let it be referenced by an Item that's created.

Posted (edited)
21 minutes ago, TheKingElessar said:

So the class extending net.minecraft.item.ItemGroup (in my case ModItemGroup) is created, the IItemProvider "icon" contains a null Item because the Item it refers to hasn't been registered yet, then createIcon is called after Item initialization, which creates a new ItemStack from the Item stored in "icon". This last part I'm not quite understanding: when the ItemStack is created, doesn't it use the null Item? As far as I can tell it doesn't recreate it or refresh it or whatever.

new ModItemGroup("name", ()->ItemList.moditem) doesn't just immediately evaluate the lambda and then pass its result. As you pointed out, it would evaluate to null and just pass null.

Instead, it passes the entire function. The way I use IItemProvider in this case is as a function that returns an Item. The function is only evaluated in ModItemGroup#createIcon, inside of the ItemStack constructor (when it does ItemIn.asItem()). I just realized that this looks especially funky because you can directly pass IItemProvider to an ItemStack constructor, which is what I'm doing.

 

It's easier to see what happens if you imagine that I use Supplier<Item> instead of IItemProvider and inside of createIcon I do: return new ItemStack(icon.get()); This way, it's apparent where the function is evaluated.

 

I suggest that you read into Java Functional Interfaces such as Supplier<Item>. They're pretty sexy, especially for someone with a C++ background who really misses pointers sometimes.

Edited by TheOnlyTrueEnte
Posted
16 minutes ago, TheKingElessar said:

Actually, could you go into this a little more? I'm not quite understanding how you can avoid a static variable but still let it be referenced by an Item that's created.

Static variables are fine but static initializers are weird because it isn't always apparent in what order values are initialized. In your case, for example, ItemList initializes items with their ItemGroups but ModItemGroup initializes itemgroups with their displayed Items. Well, which one's inizialized first? I mean I know its ModItemGroup but it's still not readable.

Posted
8 hours ago, TheOnlyTrueEnte said:

It's easier to see what happens if you imagine that I use Supplier<Item> instead of IItemProvider and inside of createIcon I do: return new ItemStack(icon.get()); This way, it's apparent where the function is evaluated.

 

I suggest that you read into Java Functional Interfaces such as Supplier<Item>. They're pretty sexy, especially for someone with a C++ background who really misses pointers sometimes.

I used a Supplier<ItemStack> https://github.com/Cadiboo/Example-Mod/blob/1.13.2/src/main/java/io/github/cadiboo/examplemod/init/ModItemGroups.java

About Me

Spoiler

My Discord - Cadiboo#8887

My WebsiteCadiboo.github.io

My ModsCadiboo.github.io/projects

My TutorialsCadiboo.github.io/tutorials

Versions below 1.14.4 are no longer supported on this forum. Use the latest version to receive support.

When asking support remember to include all relevant log files (logs are found in .minecraft/logs/), code if applicable and screenshots if possible.

Only download mods from trusted sites like CurseForge (minecraft.curseforge.com). A list of bad sites can be found here, with more information available at stopmodreposts.org

Edit your own signature at www.minecraftforge.net/forum/settings/signature/ (Make sure to check its compatibility with the Dark Theme)

Posted
19 hours ago, TheOnlyTrueEnte said:

The function is only evaluated in ModItemGroup#createIcon, inside of the ItemStack constructor (when it does ItemIn.asItem()).

Oh, okay. That makes sense.

 

19 hours ago, TheOnlyTrueEnte said:

Static variables are fine but static initializers are weird because it isn't always apparent in what order values are initialized.

Sort of like how you want to initialize Items in an @ObjectHolder as null, but then assign them in the registration. Okay!

 

11 hours ago, Cadiboo said:

I'll look into functional interfaces! :)

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.