Skip to content

Commit

Permalink
Work on more optimisations for guide loading.
Browse files Browse the repository at this point in the history
  • Loading branch information
AlexIIL committed Jan 23, 2019
1 parent d4567f7 commit 016bcb1
Show file tree
Hide file tree
Showing 12 changed files with 214 additions and 38 deletions.
2 changes: 1 addition & 1 deletion build.properties
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mc_version=1.12.2
forge_version=14.23.0.2544
mappings_version=snapshot_20171120
mod_version=7.99.22-pre2
mod_version=7.99.22-pre3
72 changes: 51 additions & 21 deletions common/buildcraft/lib/client/guide/GuideManager.java
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,6 @@
import net.minecraft.client.resources.IResourceManager;
import net.minecraft.client.resources.IResourceManagerReloadListener;
import net.minecraft.client.resources.Language;
import net.minecraft.client.util.SuffixArray;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.profiler.Profiler;
Expand Down Expand Up @@ -62,6 +61,10 @@
import buildcraft.lib.misc.ItemStackKey;
import buildcraft.lib.misc.LocaleUtil;
import buildcraft.lib.misc.ProfilerUtil;
import buildcraft.lib.misc.data.ProfilerBC;
import buildcraft.lib.misc.data.ProfilerBC.IProfilerSection;
import buildcraft.lib.misc.search.ISuffixArray;
import buildcraft.lib.misc.search.VanillaSuffixArray;

public enum GuideManager implements IResourceManagerReloadListener {
INSTANCE;
Expand All @@ -80,7 +83,7 @@ public enum GuideManager implements IResourceManagerReloadListener {
public static final boolean DEBUG = BCDebugging.shouldDebugLog("lib.guide.loader");

/** Internal use only! Use {@link #addChild(ResourceLocation, JsonTypeTags, PageLink)} instead! */
public SuffixArray<PageLink> quickSearcher;
public ISuffixArray<PageLink> quickSearcher;
/** Every {@link PageLink} that has been added to {@link #quickSearcher}. */
private final Set<PageLink> pageLinksAdded = new HashSet<>();
private final Map<GuideBook, Map<TypeOrder, ContentsNode>> contents = new HashMap<>();
Expand Down Expand Up @@ -135,9 +138,9 @@ private void reload0(IResourceManager resourceManager) {
prof.profilingEnabled = true;
prof.startSection("root");
prof.startSection("reload");
GuideGroupManager.get("lols", "hi");
Stopwatch watch = Stopwatch.createStarted();

GuideGroupManager.get("lols", "hi");
prof.startSection("book_registry");
GuideBookRegistry.INSTANCE.reload();
prof.endStartSection("page_registry");
Expand Down Expand Up @@ -185,13 +188,13 @@ private void reload0(IResourceManager resourceManager) {
}

// load the default ones
loadLangInternal(resourceManager, DEFAULT_LANG);
loadLangInternal(resourceManager, DEFAULT_LANG, prof);
// replace any existing with the new ones.

prof.endStartSection("load_real_lang");

if (!DEFAULT_LANG.equals(langCode)) {
loadLangInternal(resourceManager, langCode);
loadLangInternal(resourceManager, langCode, prof);
}

prof.endStartSection("contents_page");
Expand All @@ -205,14 +208,16 @@ private void reload0(IResourceManager resourceManager) {
int e = p - a;
prof.endSection();
prof.endSection();
BCLog.logger.info("[lib.guide] " + pageLinksAdded.size() + " search terms");
BCLog.logger.info("[lib.guide] Loaded " + p + " possible and " + a + " actual guide pages (" + e
+ " not found) in " + time / 1000 + "ms.");
BCLog.logger.info("[lib.guide] Performance information for guide loading:");
ProfilerUtil.logProfilerResults(prof, "root", time * 1000);
BCLog.logger.info("[lib.guide] End of guide loading performance information.");
}

private void loadLangInternal(IResourceManager resourceManager, String lang) {
private void loadLangInternal(IResourceManager resourceManager, String lang, Profiler prof) {
ProfilerBC p = new ProfilerBC(prof);
main_iteration: for (Entry<ResourceLocation, PageEntry<?>> mapEntry : GuidePageRegistry.INSTANCE
.getReloadableEntryMap().entrySet()) {
ResourceLocation entryKey = mapEntry.getKey();
Expand All @@ -222,8 +227,10 @@ private void loadLangInternal(IResourceManager resourceManager, String lang) {
for (Entry<String, IPageLoader> entry : PAGE_LOADERS.entrySet()) {
ResourceLocation fLoc = new ResourceLocation(domain, path + "." + entry.getKey());

try (InputStream stream = resourceManager.getResource(fLoc).getInputStream()) {
GuidePageFactory factory = entry.getValue().loadPage(stream, entryKey, mapEntry.getValue());
try (IProfilerSection s = p.start("get_resource");
InputStream stream = resourceManager.getResource(fLoc).getInputStream();
IProfilerSection l = p.start("load")) {
GuidePageFactory factory = entry.getValue().loadPage(stream, entryKey, mapEntry.getValue(), prof);
// put the original page in so that the different lang variants override it
pages.put(entryKey, factory);
if (GuideManager.DEBUG) {
Expand Down Expand Up @@ -263,7 +270,7 @@ private void generateContentsPage(Profiler prof) {
for (GuideBook book : GuideBookRegistry.INSTANCE.getAllEntries()) {
genTypeMap(book);
}
quickSearcher = new SuffixArray<>();
quickSearcher = new VanillaSuffixArray<>();
pageLinksAdded.clear();
prof.endStartSection("add_pages");

Expand All @@ -287,12 +294,37 @@ private void generateContentsPage(Profiler prof) {
}

prof.endStartSection("add_default");
ContentsNode othersRoot = new ContentsNode(LocaleUtil.localize("buildcraft.guide.contents.all_group"), 0);
for (Entry<GuideBook, Map<TypeOrder, ContentsNode>> bookEntry : contents.entrySet()) {
@Nullable
GuideBook book = bookEntry.getKey();
if (book != null && !book.appendAllEntries) {
continue;
}
for (ContentsNode root : bookEntry.getValue().values()) {
root.addChild(othersRoot);
}
}
final IEntryLinkConsumer adder = (tags, page) -> {
assert tags.domain == null;
assert tags.subType == null;
prof.startSection("add_child");
addChild(null, tags, page);
if (pageLinksAdded.add(page)) {
quickSearcher.add(page, page.getSearchName());
}
String title = LocaleUtil.localize(tags.type);
IContentsNode subNode = othersRoot.getChild(title);
if (subNode instanceof ContentsNode) {
subNode.addChild(page);
} else if (subNode == null) {
ContentsNode subContents = new ContentsNode(title, 1);
othersRoot.addChild(subContents);
subContents.addChild(page);
} else {
throw new IllegalStateException("Unknown node type " + subNode.getClass());
}
prof.endSection();
};
prof.endStartSection("add_default");
for (PageValueType<?> type : GuidePageRegistry.INSTANCE.types) {
prof.startSection(type.getClass().getName().replace('.', '/'));
type.iterateAllDefault(adder);
Expand All @@ -301,6 +333,7 @@ private void generateContentsPage(Profiler prof) {

prof.endStartSection("generate_quick_search");
quickSearcher.generate();

prof.endStartSection("sort");
for (Map<TypeOrder, ContentsNode> map : contents.values()) {
for (ContentsNode node : map.values()) {
Expand All @@ -322,41 +355,38 @@ private void addChild(ResourceLocation bookType, JsonTypeTags tags, PageLink pag
if (pageLinksAdded.add(page)) {
quickSearcher.add(page, page.getSearchName());
}
for (Entry<GuideBook, Map<TypeOrder, ContentsNode>> bookEntry : contents.entrySet()) {

for (Entry<GuideBook, Map<TypeOrder, ContentsNode>> bookEntry : contents.entrySet()) {
@Nullable
GuideBook book = bookEntry.getKey();

if (bookType == null) {
if (book != null && !book.appendAllEntries) {
continue;
}
} else if (book != null && !book.name.equals(bookType)) {
if (book != null && !book.name.equals(bookType)) {
continue;
}
Map<TypeOrder, ContentsNode> map = bookEntry.getValue();
for (Entry<TypeOrder, ContentsNode> entry : map.entrySet()) {
TypeOrder order = entry.getKey();
ContentsNode node = entry.getValue();

String[] ordered = tags.getOrdered(order);
ContentsNode[] nodePath = new ContentsNode[ordered.length];
ContentsNode node = entry.getValue();
for (int i = 0; i < ordered.length; i++) {
String title = LocaleUtil.localize(ordered[i]);
IContentsNode subNode = node.getChild(title);
if (subNode instanceof ContentsNode) {
node = (ContentsNode) subNode;
nodePath[i] = node;
} else if (subNode == null) {
ContentsNode subContents = new ContentsNode(title, i);
node.addChild(subContents);
node = subContents;
nodePath[i] = node;
} else {
throw new IllegalStateException("Unknown node type " + subNode.getClass());
}
}
node.addChild(page);
nodePath[nodePath.length - 1].addChild(page);
}
}

}

@Nullable
Expand Down
2 changes: 1 addition & 1 deletion common/buildcraft/lib/client/guide/data/JsonTypeTags.java
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,7 @@ public JsonTypeTags(String type) {
public String[] getOrdered(TypeOrder typeOrder) {
if (domain == null && subType == null) {
// Built-in type for "others"
return new String[] { "buildcraft.guide.contents.all_group", type };
return new String[] { type };
}

String[] strings = new String[typeOrder.tags.size()];
Expand Down
3 changes: 2 additions & 1 deletion common/buildcraft/lib/client/guide/loader/IPageLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,11 +9,12 @@
import java.io.IOException;
import java.io.InputStream;

import net.minecraft.profiler.Profiler;
import net.minecraft.util.ResourceLocation;

import buildcraft.lib.client.guide.entry.PageEntry;
import buildcraft.lib.client.guide.parts.GuidePageFactory;

public interface IPageLoader {
GuidePageFactory loadPage(InputStream in, ResourceLocation name, PageEntry<?> entry) throws IOException;
GuidePageFactory loadPage(InputStream in, ResourceLocation name, PageEntry<?> entry, Profiler prof) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -13,17 +13,18 @@
import java.io.Reader;
import java.nio.charset.StandardCharsets;

import net.minecraft.profiler.Profiler;
import net.minecraft.util.ResourceLocation;

import buildcraft.lib.client.guide.entry.PageEntry;
import buildcraft.lib.client.guide.parts.GuidePageFactory;

public interface IPageLoaderText extends IPageLoader {
@Override
default GuidePageFactory loadPage(InputStream in, ResourceLocation name, PageEntry<?> entry) throws IOException {
default GuidePageFactory loadPage(InputStream in, ResourceLocation name, PageEntry<?> entry, Profiler prof) throws IOException {
Reader reader = new InputStreamReader(in, StandardCharsets.UTF_8);
return loadPage(new BufferedReader(reader), name, entry);
return loadPage(new BufferedReader(reader), name, entry, prof);
}

GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, PageEntry<?> entry) throws IOException;
GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, PageEntry<?> entry, Profiler prof) throws IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.profiler.Profiler;
import net.minecraft.util.ResourceLocation;

import net.minecraftforge.oredict.OreDictionary;
Expand Down Expand Up @@ -88,8 +89,9 @@ public static ItemStack loadComplexItemStack(String line) {
}

@Override
public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, PageEntry<?> entry)
public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, PageEntry<?> entry, Profiler prof)
throws IOException {
prof.startSection("md");
StringBuilder replaced = new StringBuilder();
String line;
while ((line = reader.readLine()) != null) {
Expand All @@ -99,7 +101,9 @@ public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, P
replaced.append('\n');
}

return XmlPageLoader.INSTANCE.loadPage(new BufferedReader(new StringReader(replaced.toString())), name, entry);
BufferedReader nReader = new BufferedReader(new StringReader(replaced.toString()));
prof.endSection();
return XmlPageLoader.INSTANCE.loadPage(nReader, name, entry, prof);
}

private static String replaceSpecialForXml(String line) {
Expand Down
25 changes: 24 additions & 1 deletion common/buildcraft/lib/client/guide/loader/XmlPageLoader.java
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,21 @@
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.TimeUnit;
import java.util.function.BooleanSupplier;

import javax.annotation.Nonnull;
import javax.annotation.Nullable;

import com.google.common.base.Stopwatch;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableMap;

import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTException;
import net.minecraft.profiler.Profiler;
import net.minecraft.util.ResourceLocation;
import net.minecraft.util.text.TextFormatting;

Expand Down Expand Up @@ -55,6 +58,8 @@
import buildcraft.lib.expression.Tokenizer.TokenResult;
import buildcraft.lib.expression.TokenizerDefaults;
import buildcraft.lib.misc.LocaleUtil;
import buildcraft.lib.misc.data.ProfilerBC;
import buildcraft.lib.misc.data.ProfilerBC.IProfilerSection;

// This isn't a proper XML loader - there isn't a root tag.
// Instead it just assumes everything is a paragraph, unless more specific tags are given
Expand Down Expand Up @@ -186,8 +191,15 @@ public static void putMulti(String string, SpecialParser parser) {
}

@Override
public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, PageEntry<?> entry)
public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, PageEntry<?> entry, Profiler prof)
throws IOException {
try (IProfilerSection p = new ProfilerBC(prof).start("xml")) {
return loadPage0(reader, name, entry, prof);
}
}

private static GuidePageFactory loadPage0(BufferedReader reader, ResourceLocation name, PageEntry<?> entry,
Profiler prof) throws IOException, InvalidInputDataException {
// Needs to support:
// - start/end tags (such as <lore></lore>)
// - nested tags (such as <lore>Spooky<bold> Skeletons</bold></lore>)
Expand Down Expand Up @@ -226,12 +238,16 @@ public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, P
if (line.startsWith("\\/\\/")) {
line = "//" + line.substring(4);
}
prof.startSection("parse_tag");
XmlTag tag = parseTag(line);
prof.endSection();
if (tag != null) {
if (tag.state == XmlTagState.COMPLETE) {
SpecialParser parser = TAG_FACTORIES.get(tag.name);
if (parser != null) {
prof.startSection("use_" + tag.name);
List<GuidePartFactory> factories = parser.parse(tag);
prof.endSection();
if (factories != null) {
nestedParts.peek().addAll(factories);
line = line.substring(tag.originalString.length());
Expand Down Expand Up @@ -262,7 +278,9 @@ public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, P
"Tried to close " + tag.name + " before instead of " + nameTag.name + "!");
}
List<GuidePartFactory> subParts = nestedParts.pop();
prof.startSection("join_" + tag.name);
GuidePartFactory joined = joiner.join(nameTag, subParts);
prof.endSection();
if (joined == null) {
nestedParts.peek().addAll(subParts);
int len = tag.originalString.length();
Expand All @@ -281,6 +299,7 @@ public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, P
if (line.length() == 0) {
line = " ";
}
prof.startSection("text_format");
Set<TextFormatting> formattingElements = EnumSet.noneOf(TextFormatting.class);
Deque<TextFormatting> formatColours = new ArrayDeque<>();
String completeLine = "";
Expand Down Expand Up @@ -328,6 +347,7 @@ public GuidePageFactory loadPage(BufferedReader reader, ResourceLocation name, P

final String modLine = completeLine;
nestedParts.peek().add(new GuideTextFactory(modLine));
prof.endSection();
}
List<GuidePartFactory> factories = nestedParts.pop();
if (nestedParts.size() != 0) {
Expand Down Expand Up @@ -531,6 +551,7 @@ private static List<GuidePartFactory> loadAllRecipesAndUsages(XmlTag tag) {
}

public static List<GuidePartFactory> loadAllCrafting(@Nonnull ItemStack stack) {
Stopwatch watch = Stopwatch.createStarted();
List<GuidePartFactory> list = new ArrayList<>();
List<GuidePartFactory> recipeParts = RecipeLookupHelper.getAllRecipes(stack);
if (recipeParts.size() > 0) {
Expand All @@ -556,6 +577,8 @@ public static List<GuidePartFactory> loadAllCrafting(@Nonnull ItemStack stack) {
}
list.addAll(usageParts);
}
BCLog.logger.info("[lib.guide] Took " + watch.elapsed(TimeUnit.MICROSECONDS) + "µs to load " + list.size()
+ " crafting recipes for " + stack);
return list;
}

Expand Down
Loading

0 comments on commit 016bcb1

Please sign in to comment.