package openmods.infobook; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; import com.google.common.base.Strings; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import com.google.common.collect.Sets; import cpw.mods.fml.common.registry.FMLControlledNamespacedRegistry; import cpw.mods.fml.common.registry.GameData; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Set; import java.util.SortedMap; import net.minecraft.block.Block; import net.minecraft.item.Item; import net.minecraft.item.ItemStack; import net.minecraft.util.StatCollector; import openmods.Log; import openmods.OpenMods; import openmods.gui.component.BaseComponent; import openmods.gui.component.GuiComponentBook; import openmods.gui.component.page.ItemStackTocPage; import openmods.gui.component.page.StandardRecipePage; import openmods.gui.listener.IMouseDownListener; import openmods.utils.CachedInstanceFactory; public class PageBuilder { public interface StackProvider<T> { public ItemStack createStack(String modId, String name, T item); } private static final CachedInstanceFactory<ICustomBookEntryProvider> PROVIDERS = CachedInstanceFactory.create(); private static class Entry { public final BaseComponent page; public final ItemStack stack; public Entry(BaseComponent page, ItemStack stack) { this.page = page; this.stack = stack; } } private final SortedMap<String, Entry> pages = Maps.newTreeMap(); private Set<String> modIds; private List<ItemStackTocPage> tocPages; protected String getMediaLink(String modId, String type, String id) { final String lang = OpenMods.proxy.getLanguage().or("unknown"); return "https://videos.openmods.info/" + lang + "/tutorial." + modId + "." + type + "." + id; } public <T> void addPages(String type, FMLControlledNamespacedRegistry<T> registry, StackProvider<T> provider) { @SuppressWarnings("unchecked") Set<String> ids = registry.getKeys(); Splitter splitter = Splitter.on(':'); for (String id : ids) { final T obj = registry.getObject(id); if (obj == null) continue; final BookDocumentation doc; final Class<?> cls = obj.getClass(); try { // other mods can derp here doc = cls.getAnnotation(BookDocumentation.class); } catch (Throwable t) { Log.warn(t, "Failed to get annotation from %s", cls); continue; } if (doc == null) continue; Iterator<String> components = splitter.split(id).iterator(); final String itemModId = components.next(); if (modIds != null && !modIds.contains(itemModId)) continue; final String itemName = components.next(); final Class<? extends ICustomBookEntryProvider> customProviderCls = doc.customProvider(); if (customProviderCls == BookDocumentation.EMPTY.class) { final ItemStack stack = provider.createStack(itemModId, itemName, obj); if (stack == null) continue; final String customName = doc.customName(); addPage(Strings.isNullOrEmpty(customName)? itemName : customName, itemModId.toLowerCase(Locale.ENGLISH), type, doc.hasVideo(), stack); } else { ICustomBookEntryProvider customProvider = PROVIDERS.getOrCreate(customProviderCls); for (ICustomBookEntryProvider.Entry e : customProvider.getBookEntries()) addPage(e.name, itemModId.toLowerCase(Locale.ENGLISH), type, doc.hasVideo(), e.stack); } } } public void insertTocPages(GuiComponentBook book, int rows, int columns, float scale) { Preconditions.checkState(tocPages == null, "Table Of Contents page already added"); tocPages = Lists.newArrayList(); int tocEntriesCount = pages.size(); while (tocEntriesCount > 0) { ItemStackTocPage page = new ItemStackTocPage(rows, columns, scale); tocEntriesCount -= page.getCapacity(); tocPages.add(page); book.addPage(page); } } public void insertPages(GuiComponentBook book) { for (Entry e : pages.values()) { if (tocPages != null) { final int target = book.getNumberOfPages(); addToToc(book, e.stack, target); } book.addPage(e.page); } } private void addToToc(final GuiComponentBook book, ItemStack stack, final int target) { for (ItemStackTocPage tocPage : tocPages) if (tocPage.addEntry(stack, new IMouseDownListener() { @Override public void componentMouseDown(BaseComponent component, int x, int y, int button) { book.changePage(target); } })) return; throw new IllegalStateException(String.format("Tried to add more TOC entries than allocated")); } private void addPage(String id, String modId, String type, boolean hasVideo, ItemStack stack) { final String nameKey = getTranslationKey(id, modId, type, "name"); final String descriptionKey = getTranslationKey(id, modId, type, "description"); final String translatedName = StatCollector.translateToLocal(nameKey); final StandardRecipePage page; if (hasVideo) { final String mediaKey = getMediaLink(modId, type, id); page = new StandardRecipePage(nameKey, descriptionKey, mediaKey, stack); } else { page = new StandardRecipePage(nameKey, descriptionKey, stack); } pages.put(translatedName + ":" + id, new Entry(page, stack)); } protected String getTranslationKey(String name, String modId, String type, String category) { return String.format("%s.%s.%s.%s", type, modId, name, category); } public void includeModId(String modid) { if (modIds == null) modIds = Sets.newHashSet(); modIds.add(modid); } public void addItemPages(StackProvider<Item> provider) { addPages("item", GameData.getItemRegistry(), provider); } public void createItemPages() { addItemPages(new StackProvider<Item>() { @Override public ItemStack createStack(String itemModId, String itemName, Item item) { return new ItemStack(item); } }); } public void addBlockPages(StackProvider<Block> provider) { addPages("tile", GameData.getBlockRegistry(), provider); } public void createBlockPages() { addBlockPages(new StackProvider<Block>() { @Override public ItemStack createStack(String blockModId, String blockName, Block block) { return new ItemStack(block); } }); } }