Jump to content

[1.8.9] Add procedurally generated names to the language registry


Roboguy99

Recommended Posts

I plan to have the ability to combine constant items, which I can name using the language file system, to give them a procedurally-generated name which is a combination of them. I've just about figured out how to actually get an item's translated name to combine it using:

 

StatCollector.translateToLocal(element.getUnlocalizedName() + ".name")

 

Having to append .name to get it to work feels a little hacky and makes me feel like I'm definitely missing something, but doing this successfully changes "item.x.name" into "x's name".

 

If I use the product of this combination as the unlocalized name for the compound item, I obviously get the "untranslated" "item.x y.name".

 

The possibilities for compounds is essentially endless, so adding every single one to a language file is not possible. With the deprecation of the language registry, how do I go about adding names? Am I missing something really obvious? Why change from a code-based system to one where authors must put names in files?

I have no idea what I'm doing.

Link to comment
Share on other sites

Add the individual name parts to your language files, translate each part individually and then combine them into the full name.

 

The argument of

StatCollector.translateToLocal

is the full translation key to translate, it doesn't have to end in

.name

.

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

Add the individual name parts to your language files, translate each part individually and then combine them into the full name.

 

The argument of

StatCollector.translateToLocal

is the full translation key to translate, it doesn't have to end in

.name

.

 

That sounds like what I'm doing. Every element is being registered in the language file, and then when combining the names I loop over each element in the compound, use the

StatCollector

line on each element, and append it to the string, which is returned and set as the compound's unlocalized name.

 

If I don't include that extra

.name

then the element name is not found to be translated and I get a horrible mess of a combination of unlocalized names making one big unlocalized name.

 

Code's here: https://github.com/Roboguy99/Chemistry/tree/master/src/main/java/roboguy99/chemistry/item

I have no idea what I'm doing.

Link to comment
Share on other sites

Add the individual name parts to your language files, translate each part individually and then combine them into the full name.

 

The argument of

StatCollector.translateToLocal

is the full translation key to translate, it doesn't have to end in

.name

.

 

That sounds like what I'm doing. Every element is being registered in the language file, and then when combining the names I loop over each element in the compound, use the

StatCollector

line on each element, and append it to the string, which is returned and set as the compound's unlocalized name.

 

If I don't include that extra

.name

then the element name is not found to be translated and I get a horrible mess of a combination of unlocalized names making one big unlocalized name.

 

Code's here: https://github.com/Roboguy99/Chemistry/tree/master/src/main/java/roboguy99/chemistry/item

 

The translation keys in your lang file end in

.name

, so you need to include that when using

StatCollector.translateToLocal

. If they didn't end in

.name

, you wouldn't need to include it.

 

Item#getUnlocalizedName

returns the unlocalised name without the

.name

suffix so items with subtypes (e.g. dyes) can combine the base unlocalised name with the unlocalised name of the subtype before the

.name

suffix is added.

 

You can't compare strings with

==

or

!=

, since two different string objects may have the same value. Use

Object#equals

instead.

 

I would suggest using

StringBuilder

rather than concatenation to build strings.

 

The way you're currently building your localised names should mostly work, but you should override

Item#getItemStackDisplayName

to return this name instead of setting it as the unlocalised name.

 

Your current implementation of

getCommonName

will only work for English. I would recommend having common names in your lang files, having a field or method for the unlocalised common name and translating it in

getCompoundName

. You should also check if the common name exists before building the full compound name to avoid unnecessary processing.

 

I would recommend against using the empty string as a default return value, I'd suggest using

null

to indicate no value instead.

 

What you have now won't re-translate the names when the user changes the game's locale. On the client side, you need to register an instance of

registerReloadListener

that rebuilds the localised name of every

Compound

when the client's resources are reloaded (e.g. when they change the locale). Use

Minecraft#getResourceManager

to get the resource manager, then cast it to

IReloadableResourceManager

and call

registerReloadListener

with your

registerReloadListener

instance.

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 that, I'll work my way through and slowly change everything. A few things though:

 

-The reason I put .name in the language file is because otherwise the items are displayed in-game with .name. Should I remove that?

-The getCommonName (and in fact the whole naming system) is very much in testing. Once I get it working in English, I'll set it up to be translated properly. I only started working on the mod last night.

-As I'm going to have an almost infinite number of compounds generated on-the-fly when the user "crafts" them, would it be much better to have a single "compound" item with NBT data for the name, formula, mass, etc?

I have no idea what I'm doing.

Link to comment
Share on other sites

Thanks for that, I'll work my way through and slowly change everything. A few things though:

 

-The reason I put .name in the language file is because otherwise the items are displayed in-game with .name. Should I remove that?

 

The reason they show up with .name at the end is that the default implementation of the unlocalized -> localized code takes the unlocalized string ("foo") adds "item." to the front (because it's an item, "block." if it's a block, etc.) and ".name" to the end.

 

The ".name" is to distinguish it from any other usage, such as ".tooltip" or ".description" although Minecraft typically doesn't have those.  You can see in my artifacts localization file that not everything ends in ".name", some of them don't even have a suffix, such as "time.seconds=seconds"

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

-As I'm going to have an almost infinite number of compounds generated on-the-fly when the user "crafts" them, would it be much better to have a single "compound" item with NBT data for the name, formula, mass, etc?

 

Yes, that would be a much better way to handle compounds. You could even have elements as a single

Item

with the atomic number as the metadata.

 

You could probably even use Capabilities instead of 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

Yes, that would be a much better way to handle compounds. You could even have elements as a single

Item

with the atomic number as the metadata.

 

You could probably even use Capabilities instead of NBT.

 

The reason I've kept every element separate is because I was planning on later down the line actually adding individual properties for each one (i.e. iron might be magnetic while coal burns easily, etc).

 

I'm a little confused by the capabilities. Could you give me an example of how I could use it in my case instead of NBT?

 

In saying this, I have just hit a wall using NBT/multiple elements, because I can't store a class to NBT so instead I have to save a property of the element and then (as far as I can work out) switch over every single element to find the matching one for every one in the compound.

I have no idea what I'm doing.

Link to comment
Share on other sites

To save a class to NBT, you need to convert runtime types to collection (byte array, int array, list, compound) and primitive (byte, short, int, long, float, double, string) tags.

 

The only part of a

Compound

you need to store is its structure. The

LinkedHashMap

can become a list tag, with a compound tag for each entry containing an int each for the

Element

(the atomic number) and the amount.

 

To use capabilities for this, you'd need to create an

ICompound

interface with the required

Compound

methods and register it as a capability.

 

Upon further consideration, I don't think capabilities will work for you here. Combining stacks in inventories ignores capabilities, so you could combine a stack of water and a stack of glucose together as if they were the same item. You'll have to stick to NBT in this case.

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

To save a class to NBT, you need to convert runtime types to collection (byte array, int array, list, compound) and primitive (byte, short, int, long, float, double, string) tags.

 

The only part of a

Compound

you need to store is its structure. The

LinkedHashMap

can become a list tag, with a compound tag for each entry containing an int each for the

Element

(the atomic number) and the amount.

 

To use capabilities for this, you'd need to create an

ICompound

interface with the required

Compound

methods and register it as a capability.

 

Upon further consideration, I don't think capabilities will work for you here. Combining stacks in inventories ignores capabilities, so you could combine a stack of water and a stack of glucose together as if they were the same item. You'll have to stick to NBT in this case.

 

That answers quite a bit, thanks. So one last thing - How would I go about actually getting an element from its atomic number?

I have no idea what I'm doing.

Link to comment
Share on other sites

That answers quite a bit, thanks. So one last thing - How would I go about actually getting an element from its atomic number?

 

Create an array of

Element

s indexed by their atomic number and populate it when you register each

Element

.

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

Just a tip in case you don't know: StatCollector#translateToLocalFormatted allows you to use most if not all of the same formatting arguments that String#format can use, so you can have complicated translations that are not hard-coded.

 

E.g. If you have something like the following:

return StatCollector.translateToLocalFormatted(
    "item.element.display_name", // translation key that will handle word order
    StatCollector.translateToLocal(this.getUnlocalizedName()), // first word, pre-translated
    StatCollector.translateToLocal(element.getUnlocalizedName()) // second word, pre-translated
);

Without changing the above code, your language file can now support different word orders:

// English: Item of Element
item.element.display_name=%1$s of %2$s

// Some language with different word order: Element blah Item
item.element.display_name=%2$s blah %1$s

It's not perfect as in some languages the word 'Item' or 'Element' might require a different form depending on the rest of the sentence context, but it's pretty flexible and works most of the time.

 

Also note that you should never do any translating on the server, as it has no idea what language the client has selected. I fell for that some time ago when sending various chat messages from the server (the solution there was to send ChatComponentTranslation objects).

Link to comment
Share on other sites

Sorry to keep this thread alive with off-topic questions, but I'm working on getting the compound to only exist as a single item, and save the data to NBT, and I've completely blanked when trying to work. I think I've got the code for reading/writing the NBT sorted, but I still need help with a few things...

 

How do I (ignoring any network issues likely to come up) go about actually creating a new version of the item in-game on-the fly, with specified NBT data.

How do I load the NBT for each itemstack when the world loads etc? Do I even need to do this myself?

 

I'm sure I'm just being stupid at this point; my knowledge of actual item classes and NBT is a little rusty. Any help is appreciated.

I have no idea what I'm doing.

Link to comment
Share on other sites

You don't need to load NBT yourself, no, and for creating a specific Item, you do just that:

// make a new NBT tag compound with all the stuff you need in it
NBTTagCompound tag = new NBTTagCompound();
tag.setWhateverYouNeed(...);

// then add it to the drop/loot/whatever
ItemStack stack = new ItemStack(yourItem);
stack.setTagCompound(tag);

You can do that for crafting recipes or anything you want, really. If the ItemStack already exists, you'll have to be a little more careful e.g. check for existing NBT tags first.

Link to comment
Share on other sites

You don't need to load NBT yourself, no, and for creating a specific Item, you do just that:

// make a new NBT tag compound with all the stuff you need in it
NBTTagCompound tag = new NBTTagCompound();
tag.setWhateverYouNeed(...);

// then add it to the drop/loot/whatever
ItemStack stack = new ItemStack(yourItem);
stack.setTagCompound(tag);

You can do that for crafting recipes or anything you want, really. If the ItemStack already exists, you'll have to be a little more careful e.g. check for existing NBT tags first.

 

So would it be worth moving the code for naming the compound etc to its own class which uses the itemstack rather than keeping them in the item class or does that not really matter?

 

I could probably answer that myself but it's midnight  :P

Other than that, I think I'm sorted; in most cases I should be able to use the NBT code from previous projects.

I have no idea what I'm doing.

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.

×
×
  • Create New...

Important Information

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