From e24ab4d07c5649c7a66e009e4c056df2d8fdef57 Mon Sep 17 00:00:00 2001 From: Chocohead Date: Sat, 23 May 2020 03:21:32 +0100 Subject: [PATCH] Add Translation API (#11) * Add a basic translations API Allows setting the names of tiles, items and achievements, as well as adding keys directly through a file/reader/individual key * Fix up tile item registration Currently the TileItems API creates a TileItem for any Tile it is given, which doesn't respect stack meta when placing or use the tile's translation Allows custom item types to be used (like what saplings do in vanilla) * Add mod Tiles to the T_2_TI magic map Don't think this was intended to be a vanilla only thing? * Appease checkstyle's cursed paragraph formatting * Bump the version to 0.4.1 --- gradle.properties | 2 +- .../accessor/AccessorTranslationStorage.java | 14 +++ .../api/registry/TileItems.java | 42 ++++++- .../api/registry/Translations.java | 114 ++++++++++++++++++ .../impl/registry/ItemTypeRegistry.java | 21 ++-- .../impl/registry/RegistryImpl.java | 19 +-- src/main/resources/api.accessors.json | 3 +- .../test/RegistryTest.java | 8 +- 8 files changed, 198 insertions(+), 25 deletions(-) create mode 100644 src/main/java/io/github/minecraftcursedlegacy/accessor/AccessorTranslationStorage.java create mode 100644 src/main/java/io/github/minecraftcursedlegacy/api/registry/Translations.java diff --git a/gradle.properties b/gradle.properties index ee17c537..26fb0c76 100644 --- a/gradle.properties +++ b/gradle.properties @@ -6,6 +6,6 @@ org.gradle.jvmargs=-Xmx1G loader_version=392aab7 # Mod Properties - mod_version = 0.4.0 + mod_version = 0.4.1 maven_group = io.github.minecraftcursedlegacy.api archives_base_name = cursed-legacy-api diff --git a/src/main/java/io/github/minecraftcursedlegacy/accessor/AccessorTranslationStorage.java b/src/main/java/io/github/minecraftcursedlegacy/accessor/AccessorTranslationStorage.java new file mode 100644 index 00000000..19f9de51 --- /dev/null +++ b/src/main/java/io/github/minecraftcursedlegacy/accessor/AccessorTranslationStorage.java @@ -0,0 +1,14 @@ +package io.github.minecraftcursedlegacy.accessor; + +import java.util.Properties; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import net.minecraft.client.resource.language.TranslationStorage; + +@Mixin(TranslationStorage.class) +public interface AccessorTranslationStorage { + @Accessor + Properties getTranslations(); +} \ No newline at end of file diff --git a/src/main/java/io/github/minecraftcursedlegacy/api/registry/TileItems.java b/src/main/java/io/github/minecraftcursedlegacy/api/registry/TileItems.java index fe7cdd6c..63eb325e 100644 --- a/src/main/java/io/github/minecraftcursedlegacy/api/registry/TileItems.java +++ b/src/main/java/io/github/minecraftcursedlegacy/api/registry/TileItems.java @@ -1,9 +1,14 @@ package io.github.minecraftcursedlegacy.api.registry; -import io.github.minecraftcursedlegacy.impl.registry.RegistryImpl; +import java.util.function.IntFunction; + +import net.minecraft.item.ItemType; +import net.minecraft.item.PlaceableTileItem; import net.minecraft.item.TileItem; import net.minecraft.tile.Tile; +import io.github.minecraftcursedlegacy.impl.registry.RegistryImpl; + /** * Utilities for adding and registering tile items. */ @@ -13,8 +18,41 @@ public class TileItems { * @param id the id of the tile item. * @param value the tile this tile item is for. * @return the tile item created. + * @deprecated Prefer using {@link #registerTileItem(Id, Tile)} (which creates a + * {@link PlaceableTileItem} for the given tile rather than a {@link TileItem}) so + * that it will respect the item meta when deciding on the tile to place in the world. */ + @Deprecated public static TileItem addRegisteredTileItem(Id id, Tile value) { - return RegistryImpl.addTileItem(id, value, TileItem::new); + return RegistryImpl.addTileItem(id, value, itemID -> new TileItem(itemID, value)); + } + + /** + * Register an {@link ItemType} for the given {@link Tile}. + * + * @param id The identifier of the item to be registered + * @param tile The tile the item is for + * + * @return An item for the given tile + * + * @since 0.4.1 + */ + public static ItemType registerTileItem(Id id, Tile tile) { + return registerTileItem(id, tile, PlaceableTileItem::new); + } + + /** + * Register an {@link ItemType} for the given {@link Tile} created using the given factory. + * + * @param id The identifier of the item to be registered + * @param tile The tile the item is for + * @param itemFactory A factory for creating the item, given the item ID to use + * + * @return An item for the given tile + * + * @since 0.4.1 + */ + public static I registerTileItem(Id id, Tile tile, IntFunction itemFactory) { + return RegistryImpl.addTileItem(id, tile, itemFactory); } } diff --git a/src/main/java/io/github/minecraftcursedlegacy/api/registry/Translations.java b/src/main/java/io/github/minecraftcursedlegacy/api/registry/Translations.java new file mode 100644 index 00000000..f9384385 --- /dev/null +++ b/src/main/java/io/github/minecraftcursedlegacy/api/registry/Translations.java @@ -0,0 +1,114 @@ +package io.github.minecraftcursedlegacy.api.registry; + +import java.io.IOException; +import java.io.InputStream; +import java.io.Reader; + +import net.minecraft.achievement.Achievement; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.resource.language.TranslationStorage; +import net.minecraft.item.ItemType; +import net.minecraft.tile.Tile; + +import io.github.minecraftcursedlegacy.accessor.AccessorTranslationStorage; + +/** + * Utilities for adding translations for things. + * + * @see I18n Accessing the translations + * @since 0.4.1 + * + * @author Chocohead + */ +public final class Translations { + private Translations() { + } + + /** + * Add a translation for the given {@link Tile}. + * + * @param tile The tile to add the translation for + * @param translation The translated name for the tile + * + * @throws IllegalArgumentException If the given tile has not had {@link Tile#setName(String)} called + */ + public static void addTileTranslation(Tile tile, String translation) { + if (tile.method_1597() == null) throw new IllegalArgumentException("Given tile doesn't have a name: " + tile); + addTranslation(tile.method_1597().concat(".name"), translation); + } + + /** + * Add translation for the given {@link ItemType}. + * + * @param item The item to add the translation for + * @param translation The translated name for the item + * + * @throws IllegalArgumentException If the given item has not had {@link ItemType#setName(String)} called + */ + public static void addItemTranslation(ItemType item, String translation) { + if (item.getTranslationKey() == null) throw new IllegalArgumentException("Given item doesn't have a name: " + item); + addTranslation(item.getTranslationKey().concat(".name"), translation); + } + + /** + * Add a translation for an {@link Achievement} with the given name. + * + *

Make sure to call this before the Achievement is constructed! + * + * @param key The name of the achievement as given to the constructor + * @param translation The translated name for the achievement + * + * @see #addAchievementDescriptionTranslation(String, String) + */ + public static void addAchievementTranslation(String key, String translation) { + addTranslation("achievement.".concat(key), translation); + } + + /** + * Add a translation for an {@link Achievement}'s description with the given name. + * + *

Make sure to call this before the Achievement is constructed! + * + * @param key The name of the achievement as given to the constructor + * @param translation The translated name for the achievement's description + * + * @see #addAchievementTranslation(String, String) + */ + public static void addAchievementDescriptionTranslation(String key, String translation) { + addTranslation("achievement." + key + ".desc", translation); + } + + /** + * Add a translation for the given key. + * + * @param key The raw translation key + * @param translation The translated text for the key + */ + public static void addTranslation(String key, String translation) { + ((AccessorTranslationStorage) TranslationStorage.getInstance()).getTranslations().put(key, translation); + } + + /** + * Add all the translations from the given lang file. + * + * @param file The location of the lang file to load translations from + * + * @throws IOException If there is an error reading the file + */ + public static void loadLangFile(String file) throws IOException { + try (InputStream in = Translations.class.getResourceAsStream(file)) { + ((AccessorTranslationStorage) TranslationStorage.getInstance()).getTranslations().load(in); + } + } + + /** + * Add all the translations from the given {@link Reader}. + * + * @param reader A reader containing translations to read from, not closed after use + * + * @throws IOException If there is an error reading the translations + */ + public static void loadLangFile(Reader reader) throws IOException { + ((AccessorTranslationStorage) TranslationStorage.getInstance()).getTranslations().load(reader); + } +} \ No newline at end of file diff --git a/src/main/java/io/github/minecraftcursedlegacy/impl/registry/ItemTypeRegistry.java b/src/main/java/io/github/minecraftcursedlegacy/impl/registry/ItemTypeRegistry.java index a03145b6..34473c8b 100644 --- a/src/main/java/io/github/minecraftcursedlegacy/impl/registry/ItemTypeRegistry.java +++ b/src/main/java/io/github/minecraftcursedlegacy/impl/registry/ItemTypeRegistry.java @@ -2,16 +2,8 @@ import java.util.List; import java.util.Map.Entry; -import java.util.function.BiFunction; import java.util.function.IntFunction; -import io.github.minecraftcursedlegacy.accessor.AccessorPlaceableTileItem; -import io.github.minecraftcursedlegacy.accessor.AccessorRecipeRegistry; -import io.github.minecraftcursedlegacy.accessor.AccessorShapedRecipe; -import io.github.minecraftcursedlegacy.accessor.AccessorShapelessRecipe; -import io.github.minecraftcursedlegacy.accessor.AccessorTileItem; -import io.github.minecraftcursedlegacy.api.registry.Id; -import io.github.minecraftcursedlegacy.api.registry.Registry; import net.minecraft.item.ItemInstance; import net.minecraft.item.ItemType; import net.minecraft.item.PlaceableTileItem; @@ -23,6 +15,14 @@ import net.minecraft.tile.Tile; import net.minecraft.util.io.CompoundTag; +import io.github.minecraftcursedlegacy.accessor.AccessorPlaceableTileItem; +import io.github.minecraftcursedlegacy.accessor.AccessorRecipeRegistry; +import io.github.minecraftcursedlegacy.accessor.AccessorShapedRecipe; +import io.github.minecraftcursedlegacy.accessor.AccessorShapelessRecipe; +import io.github.minecraftcursedlegacy.accessor.AccessorTileItem; +import io.github.minecraftcursedlegacy.api.registry.Id; +import io.github.minecraftcursedlegacy.api.registry.Registry; + class ItemTypeRegistry extends Registry { ItemTypeRegistry(Id registryName) { super(ItemType.class, registryName, null); @@ -182,10 +182,11 @@ protected void addNewValues(List> unmapped, CompoundTag tag) } } - TileItem addTileItem(Id id, Tile tile, BiFunction constructor) { - TileItem item = constructor.apply(tile.id - Tile.BY_ID.length, tile); + I addTileItem(Id id, Tile tile, IntFunction constructor) { + I item = constructor.apply(tile.id - Tile.BY_ID.length); this.byRegistryId.put(id, item); this.bySerialisedId.put(item.id, item); + RegistryImpl.T_2_TI.put(tile, item); return item; } } \ No newline at end of file diff --git a/src/main/java/io/github/minecraftcursedlegacy/impl/registry/RegistryImpl.java b/src/main/java/io/github/minecraftcursedlegacy/impl/registry/RegistryImpl.java index 69de8372..ffdd66a1 100644 --- a/src/main/java/io/github/minecraftcursedlegacy/impl/registry/RegistryImpl.java +++ b/src/main/java/io/github/minecraftcursedlegacy/impl/registry/RegistryImpl.java @@ -1,17 +1,18 @@ package io.github.minecraftcursedlegacy.impl.registry; +import java.util.HashMap; +import java.util.Map; +import java.util.function.IntFunction; + +import net.minecraft.item.ItemType; +import net.minecraft.tile.Tile; + +import net.fabricmc.api.ModInitializer; + import io.github.minecraftcursedlegacy.accessor.AccessorEntityRegistry; import io.github.minecraftcursedlegacy.api.registry.Id; import io.github.minecraftcursedlegacy.api.registry.Registry; import io.github.minecraftcursedlegacy.impl.Hacks; -import net.fabricmc.api.ModInitializer; -import net.minecraft.item.ItemType; -import net.minecraft.item.TileItem; -import net.minecraft.tile.Tile; - -import java.util.HashMap; -import java.util.Map; -import java.util.function.BiFunction; public class RegistryImpl implements ModInitializer { private static int currentItemtypeId = Tile.BY_ID.length; @@ -93,7 +94,7 @@ protected void onRemap(Tile remappedValue, int newSerialisedId) { } } - public static TileItem addTileItem(Id id, Tile value, BiFunction constructor) { + public static I addTileItem(Id id, Tile value, IntFunction constructor) { return ((ItemTypeRegistry) ITEM_TYPE).addTileItem(id, value, constructor); } diff --git a/src/main/resources/api.accessors.json b/src/main/resources/api.accessors.json index cde39b0c..f60605c2 100644 --- a/src/main/resources/api.accessors.json +++ b/src/main/resources/api.accessors.json @@ -10,7 +10,8 @@ "AccessorShapelessRecipe", "AccessorTileItem", "AccessorAbstractPacket", - "AccessorEntityRegistry" + "AccessorEntityRegistry", + "AccessorTranslationStorage" ], "client": [ ], diff --git a/src/test/java/io/github/minecraftcursedlegacy/test/RegistryTest.java b/src/test/java/io/github/minecraftcursedlegacy/test/RegistryTest.java index 3669ba9e..a06578e7 100644 --- a/src/test/java/io/github/minecraftcursedlegacy/test/RegistryTest.java +++ b/src/test/java/io/github/minecraftcursedlegacy/test/RegistryTest.java @@ -4,6 +4,7 @@ import io.github.minecraftcursedlegacy.api.registry.Id; import io.github.minecraftcursedlegacy.api.registry.Registries; import io.github.minecraftcursedlegacy.api.registry.TileItems; +import io.github.minecraftcursedlegacy.api.registry.Translations; import net.fabricmc.api.ModInitializer; import net.minecraft.item.ItemInstance; import net.minecraft.item.ItemType; @@ -16,11 +17,14 @@ public void onInitialize() { item = Registries.ITEM_TYPE.register(new Id("modid:item"), i -> new BasicItem(i).setTexturePosition(5, 0).setName("exampleItem")); tile = Registries.TILE.register(new Id("modid:tile"), - i -> new BasicTile(i)); - tileItem = TileItems.addRegisteredTileItem(new Id("modid:tile"), tile); + i -> new BasicTile(i).setName("exampleBlock")); + tileItem = TileItems.registerTileItem(new Id("modid:tile"), tile); Recipes.addShapelessRecipe(new ItemInstance(item, 2), Tile.DIRT, Tile.SAND); Recipes.addShapedRecipe(new ItemInstance(tile), "##", '#', Tile.DIRT); + + Translations.addTileTranslation(tile, "Example Block"); + Translations.addItemTranslation(item, "Example Item"); } public static ItemType item;