Jump to content

[1.9.4] [solved] adding a pre-written book to a loot table


salvestrom

Recommended Posts

I may have finally run aground with the way my pre-written books are added.

 

The loot table entry below only produces an item for the bookScale class (also below). the itemstacks have no unlocalised name so I cant reference them directly as a string. elsewhere in the code, I can reference the subitems, via "bookScale.eastScale" or "bookScale.eastScale.getMetadata()" which is how I was doing it when loot tables were handled directly in code. is there a way to add items to loot tables in the code still?

 

The book in the loot table:

 

 

{

"type": "item",

"name": "thejungle:bookScale",

"weight": 10,

"functions": [

            {

            "function": "set_data",

            "data": 367

                      }

                  ]

 

},

 

 

The book class (chopped down to remove all page data):

 

 

public class bookScale extends ItemWrittenBook {

 

public static ItemStack eastScale;

public static ItemStack westScale;

public static ItemStack northScale;

public static ItemStack southScale;

 

public bookScale()

    {

super();

    this.setUnlocalizedName("bookScale"); //Omnibusaurus Codex

    this.setContainerItem(this);

    this.setCreativeTab(w2theJungle.JungleModTab);

    this.setHasSubtypes(true);

    }

 

 

 

 

{

{

eastScale = new ItemStack(Items.WRITTEN_BOOK);

eastScale.setItemDamage(367);

       

    NBTTagCompound tag = new NBTTagCompound();

    eastScale.setTagCompound(tag);

        }

}

 

@SuppressWarnings({"rawtypes", "unchecked"})

    @Override

@SideOnly(Side.CLIENT)

public void getSubItems(Item i, CreativeTabs c, List list)

      {

list.add(bookScale.eastScale);

list.add(bookScale.westScale);

list.add(bookScale.northScale);

list.add(bookScale.southScale);

}

}

 

 

 

Link to comment
Share on other sites

Either use the

set_nbt

function in the loot table file to set the NBT or create your own

LootFunction

that sets the appropriate NBT.

 

You're setting the

bookScale.eastScale

field to an

ItemStack

of

Items.WRITTEN_BOOK

instead of the

bookScale

instance, are you sure this is what you want?

 

I recommend following Java and MCP naming conventions:

PascalCase

for class names, prefixed with the base type that they extend (i.e.

ItemBookScale

instead of

bookScale

).

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

I've had the field for the subitems set every which way over the course of the orginial mods development. i dont recall if using the bookscale instance actually works. ill try it. in the mean time, regarding the nbt function for loot tables, are you talking about creating a custom loot tag?

Link to comment
Share on other sites

I've had the field for the subitems set every which way over the course of the orginial mods development. i dont recall if using the bookscale instance actually works. ill try it.

Do you ever create an register an instance of

bookScale

? If so, why use the vanilla book for its sub-items? If not, why does it extend

Item

at all?

 

changing the field to bookScale throws up a null pointer at the setItemDamage line.

A

NullPointerException

is thrown when you attempt access a method or field of a

null

value. You'll have to figure out what's

null

and why it's

null

.

 

in the mean time, regarding the nbt function for loot tables, are you talking about creating a custom loot tag?

I mean you should use a loot function (either

set_nbt

or your own custom function) in the loot table file to fill out the page data for the book.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

can i create a custom function that accepts an itemstack?

 

Your

LootFunction

will receive the

ItemStack

it's supposed to modify as an argument in the

LootFunction#apply

. There's not much point in specifying a whole

ItemStack

as an argument in the loot table itself, you may as well just use

set_nbt

.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

sorry, what i meant was a custom type. the issue lies in the type being an item. calling getItem on bookScale will not return any of the actual books.

 

adding the nbt directly in the loot table seems overboard as a solution, is all. its about 30+ pages across 4 books and multiple loot tables. if i need to change anything in any book, all those files need to be altered.

 

i know loot tables can be nested, but that doesn't replicate simply adding an item to an existing loot table - if the nested table has multiple rolls it will do all those rolls, each time it gets selected. hmm. as i type, i think i know a way around that. so anyway, yeah. custom type? also, if i set the nbt in the loot table, id still need the nbt in the bookScale.class for the creative tab.

Link to comment
Share on other sites

Create a

LootFunction

that takes some sort of book ID (probably a

ResourceLocation

) as an argument in the loot table and fills the

ItemStack

with the NBT for that book.

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

ok, let me see if ive got the logic clear here.

 

i create a custom lootfunction. the function needs to be able to distinguish which book is being specified. then, in the lootFunction#apply i can call the nbt for that book and apply it to the passed in stack before returning it. the nbt will still actually be set in the bookScale.class?

 

i wonder. what if i set the method apply to create a new itemstack right there depending on the getMetadata of the passed in stack and return that? eg. if(stack.getMetadata() = 367) return new bookScale.eastScale;??

Link to comment
Share on other sites

i create a custom lootfunction. the function needs to be able to distinguish which book is being specified. then, in the lootFunction#apply i can call the nbt for that book and apply it to the passed in stack before returning it. the nbt will still actually be set in the bookScale.class?

Yes, I'd recommend creating a method in

bookScale

to apply the NBT for the specified book to a provided

ItemStack

and then using this in both

bookScale#getSubItems

and the

LootFunction

.

 

Now that I think about it more, you shouldn't be storing pre-written text directly in NBT anyway. Any text you display to the user should be translated to the client's locale, which won't work if you store the English text in the NBT.

 

The best way to do this is the following:

  • Store the number of pages in each book somewhere
  • Store the book ID in the
    ItemStack

    using metadata or NBT

  • Don't extend
    ItemWrittenBook


  • Create a client-only (
    @SideOnly(Side.CLIENT)

    ) method (we'll call it

    getBookStack

    , but the name doesn't really matter) that takes the book ID or

    ItemStack

    and returns an

    ItemStack

    of

    Items.WRITTEN_BOOK

    with the translated text for that book in the NBT.

    • To gather the translated text for a book, iterate from 0 (inclusive) to
      numPages

      (exclusive) and call

      I18n.format

      with a translation key containing the book name and the page number (e.g.

      book.<yourmod>:bookScale.east.page.0

      ,

      book.<yourmod>:bookScale.west.page.5

      , etc.).

    • Provide translations for these keys in your mod's lang files.

     

    [*]Use the

    IGuiHandler

    system to open the vanilla book GUI when the item is right clicked (only on the client):

    • Pass the book's ID as the
      x

      argument of

      EntityPlayer#openGUI

      (since you don't need actual coordinates for item-based GUIs)

    • Return
      null

      from

      IGuiHandler#getServerGuiElement

      (since your GUI doesn't have a server component)

    • Return an instance of
      GuiScreenBook

      from

      IGuiHandler#getClientGuiElement

      . Pass it an

      ItemStack

      of

      Items.WRITTEN_BOOK

      returned from

      getBookStack

      .

Please don't PM me to ask for help. Asking your question in a public thread preserves it for people who are having the same problem in the future.

Link to comment
Share on other sites

thanks for the help thus far. your above post is taking me into pretty deep waters from my point of view, though. although it would be really great to allow the books to be translated into different languages, i'm trying to stay focused on getting my mod updated to 1.9.4+. i'm going to give the custom lootfunction a shot first. With this in mind, how do i get the game to use my custom function class?

 

i found these in forgehooks:

 

public static LootEntry deserializeJsonLootEntry(String type, JsonObject json, int weight, int quality, LootCondition[] conditions){ return null; }

public static String getLootEntryType(LootEntry entry){ return null; } //Companion to above function

 

the former is called in LootEntry#deserialise, the latter in lootEntry#serialise

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



  • Recently Browsing

    • No registered users viewing this page.
  • Posts

    • As the title says i keep on crashing on forge 1.20.1 even without any mods downloaded, i have the latest drivers (nvidia) and vanilla minecraft works perfectly fine for me logs: https://pastebin.com/5UR01yG9
    • Hello everyone, I'm making this post to seek help for my modded block, It's a special block called FrozenBlock supposed to take the place of an old block, then after a set amount of ticks, it's supposed to revert its Block State, Entity, data... to the old block like this :  The problem I have is that the system breaks when handling multi blocks (I tried some fix but none of them worked) :  The bug I have identified is that the function "setOldBlockFields" in the item's "setFrozenBlock" function gets called once for the 1st block of multiblock getting frozen (as it should), but gets called a second time BEFORE creating the first FrozenBlock with the data of the 1st block, hence giving the same data to the two FrozenBlock :   Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=head] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@73681674 BlockEntityData : id:"minecraft:bed",x:3,y:-60,z:-6} Old Block Fields set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=3, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} Frozen Block Entity set BlockState : Block{minecraft:black_bed}[facing=east,occupied=false,part=foot] BlockPos{x=2, y=-60, z=-6} BlockEntity : net.minecraft.world.level.block.entity.BedBlockEntity@6d1aa3da BlockEntityData : {id:"minecraft:bed",x:2,y:-60,z:-6} here is the code inside my custom "freeze" item :    @Override     public @NotNull InteractionResult useOn(@NotNull UseOnContext pContext) {         if (!pContext.getLevel().isClientSide() && pContext.getHand() == InteractionHand.MAIN_HAND) {             BlockPos blockPos = pContext.getClickedPos();             BlockPos secondBlockPos = getMultiblockPos(blockPos, pContext.getLevel().getBlockState(blockPos));             if (secondBlockPos != null) {                 createFrozenBlock(pContext, secondBlockPos);             }             createFrozenBlock(pContext, blockPos);             return InteractionResult.SUCCESS;         }         return super.useOn(pContext);     }     public static void createFrozenBlock(UseOnContext pContext, BlockPos blockPos) {         BlockState oldState = pContext.getLevel().getBlockState(blockPos);         BlockEntity oldBlockEntity = oldState.hasBlockEntity() ? pContext.getLevel().getBlockEntity(blockPos) : null;         CompoundTag oldBlockEntityData = oldState.hasBlockEntity() ? oldBlockEntity.serializeNBT() : null;         if (oldBlockEntity != null) {             pContext.getLevel().removeBlockEntity(blockPos);         }         BlockState FrozenBlock = setFrozenBlock(oldState, oldBlockEntity, oldBlockEntityData);         pContext.getLevel().setBlockAndUpdate(blockPos, FrozenBlock);     }     public static BlockState setFrozenBlock(BlockState blockState, @Nullable BlockEntity blockEntity, @Nullable CompoundTag blockEntityData) {         BlockState FrozenBlock = BlockRegister.FROZEN_BLOCK.get().defaultBlockState();         ((FrozenBlock) FrozenBlock.getBlock()).setOldBlockFields(blockState, blockEntity, blockEntityData);         return FrozenBlock;     }  
    • It is an issue with quark - update it to this build: https://www.curseforge.com/minecraft/mc-mods/quark/files/3642325
    • Remove Instant Massive Structures Mod from your server     Add new crash-reports with sites like https://paste.ee/  
  • Topics

×
×
  • Create New...

Important Information

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