Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
135 changes: 64 additions & 71 deletions src/main/java/com/hfstudio/guidenh/guide/compiler/Frontmatter.java
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import java.util.Locale;
import java.util.Map;

import net.minecraft.nbt.JsonToNBT;
import net.minecraft.nbt.NBTBase;
import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;

import org.jetbrains.annotations.Nullable;
Expand Down Expand Up @@ -80,54 +83,23 @@ public static Frontmatter parse(ResourceLocation pageId, String yamlText) {
}
var iconIdStr = getString(navigationMap, "icon");
var iconTextureStr = getString(navigationMap, "icon_texture");
Map<?, ?> iconComponents = getCompound(navigationMap, "icon_components");

ResourceLocation parentId = null;
if (parentIdStr != null) {
parentId = IdUtils.resolveLink(parentIdStr, pageId);
}

// Parse icon item id, supporting:
// modid:name - item with default damage 0
// modid:name:meta - item with explicit damage value
// <modid:name:meta> - strict form (angle brackets stripped)
// modid:name meta - space-separated damage (filter-expression style)
int iconMeta = 0;
String iconId = null;
NBTTagCompound iconNbt = null;
if (iconIdStr != null) {
String s = iconIdStr.trim();
if (s.startsWith("<") && s.endsWith(">")) {
s = s.substring(1, s.length() - 1)
.trim();
var parsedIcon = parseIconEntryString(iconIdStr, pageId);
if (parsedIcon != null) {
iconId = parsedIcon.itemId();
iconMeta = parsedIcon.meta();
iconNbt = parsedIcon.nbt();
}
// Space-separated damage comes first (e.g. "minecraft:potion 16384")
int spaceIdx = s.indexOf(' ');
if (spaceIdx >= 0) {
String metaPart = s.substring(spaceIdx + 1)
.trim();
s = s.substring(0, spaceIdx)
.trim();
try {
iconMeta = Integer.parseInt(metaPart);
} catch (NumberFormatException ignored) {}
} else {
// Colon-separated damage: "modid:name:meta"
// ResourceLocation has exactly one colon; a second colon is the meta suffix.
int firstColon = s.indexOf(':');
if (firstColon >= 0) {
int secondColon = s.indexOf(':', firstColon + 1);
if (secondColon >= 0) {
String metaPart = s.substring(secondColon + 1);
try {
iconMeta = Integer.parseInt(metaPart);
s = s.substring(0, secondColon);
} catch (NumberFormatException ignored) {}
}
}
}
iconId = IdUtils.rawRegistryKey(s, pageId.getResourceDomain());
}

ResourceLocation iconTextureId = null;
if (iconTextureStr != null) {
iconTextureId = IdUtils.resolveLink(iconTextureStr, pageId);
Expand All @@ -136,9 +108,9 @@ public static Frontmatter parse(ResourceLocation pageId, String yamlText) {
// Parse icons: list (cycling item icons, each entry uses same syntax as icon:)
List<NavigationIconEntry> iconEntries = null;
Object iconsObj = navigationMap.get("icons");
if (iconsObj instanceof List<?>) {
iconEntries = new ArrayList<>();
for (Object entry : (List<?>) iconsObj) {
if (iconsObj instanceof List<?>iconsList) {
iconEntries = new ArrayList<>(iconsList.size());
for (Object entry : iconsList) {
NavigationIconEntry parsed = parseIconEntry(entry, pageId);
if (parsed != null) {
iconEntries.add(parsed);
Expand All @@ -150,9 +122,9 @@ public static Frontmatter parse(ResourceLocation pageId, String yamlText) {
// Parse icon_textures: list (cycling texture icons)
List<ResourceLocation> iconTextureEntries = null;
Object iconTexturesObj = navigationMap.get("icon_textures");
if (iconTexturesObj instanceof List<?>) {
iconTextureEntries = new ArrayList<>();
for (Object entry : (List<?>) iconTexturesObj) {
if (iconTexturesObj instanceof List<?>iconTexturesList) {
iconTextureEntries = new ArrayList<>(iconTexturesList.size());
for (Object entry : iconTexturesList) {
if (entry instanceof String) {
String texStr = ((String) entry).trim();
if (!texStr.isEmpty()) {
Expand All @@ -169,13 +141,19 @@ public static Frontmatter parse(ResourceLocation pageId, String yamlText) {
String requiredModSingle = getString(navigationMap, "required_mod");
Object requiredModsObj = navigationMap.get("required_mods");
if (requiredModSingle != null || requiredModsObj != null) {
requiredMods = new ArrayList<>();
int expectedSize = requiredModSingle == null ? 0 : 1;
if (requiredModsObj instanceof List<?>requiredModsList) {
expectedSize += requiredModsList.size();
} else if (requiredModsObj instanceof String) {
expectedSize++;
}
requiredMods = new ArrayList<>(expectedSize);
if (requiredModSingle != null && !requiredModSingle.trim()
.isEmpty()) {
requiredMods.add(requiredModSingle.trim());
}
if (requiredModsObj instanceof List<?>) {
for (Object entry : (List<?>) requiredModsObj) {
if (requiredModsObj instanceof List<?>requiredModsList) {
for (Object entry : requiredModsList) {
if (entry instanceof String) {
String s = ((String) entry).trim();
if (!s.isEmpty()) {
Expand All @@ -199,7 +177,7 @@ public static Frontmatter parse(ResourceLocation pageId, String yamlText) {
recommend,
iconId,
iconMeta,
iconComponents,
iconNbt,
iconTextureId,
iconEntries,
iconTextureEntries,
Expand Down Expand Up @@ -251,6 +229,32 @@ public static int getInt(Map<?, ?> map, String key) {
return mapValue;
}

@Nullable
public static NBTTagCompound parseNavigationNbt(@Nullable Object value, String key) {
if (value == null) {
return null;
}
if (value instanceof Map<?, ?>mapValue) {
return YamlNbtConverter.toNbt(mapValue);
}
if (value instanceof String stringValue) {
String text = stringValue.trim();
if (text.isEmpty()) {
return null;
}
try {
NBTBase parsed = JsonToNBT.func_150315_a(text);
if (parsed instanceof NBTTagCompound compound) {
return compound;
}
throw new IllegalArgumentException("Key " + key + " string value has to decode to a compound tag!");
} catch (Exception exception) {
throw new IllegalArgumentException("Key " + key + " has invalid SNBT!", exception);
}
}
throw new IllegalArgumentException("Key " + key + " has to be a map or SNBT string!");
}

/**
* Parses {@code author}/{@code authors}, {@code date}, and {@code updated} from
* {@link #additionalProperties()} into a {@link FrontmatterPageMeta} value object.
Expand Down Expand Up @@ -310,7 +314,10 @@ private static NavigationIconEntry parseIconEntry(Object entry, ResourceLocation
if (entryMap.containsKey("meta")) {
meta = getInt(entryMap, "meta");
}
var nbt = getCompound(entryMap, "nbt");
NBTTagCompound nbt = parsed.nbt();
if (entryMap.containsKey("nbt")) {
nbt = parseNavigationNbt(entryMap.get("nbt"), "nbt");
}
return new NavigationIconEntry(parsed.itemId(), meta, nbt);
}
return null;
Expand All @@ -324,30 +331,11 @@ private static NavigationIconEntry parseIconEntryString(String raw, ResourceLoca
s = s.substring(1, s.length() - 1)
.trim();
}
int meta = 0;
int spaceIdx = s.indexOf(' ');
if (spaceIdx >= 0) {
String metaPart = s.substring(spaceIdx + 1)
.trim();
s = s.substring(0, spaceIdx)
.trim();
try {
meta = Integer.parseInt(metaPart);
} catch (NumberFormatException ignored) {}
} else {
int firstColon = s.indexOf(':');
if (firstColon >= 0) {
int secondColon = s.indexOf(':', firstColon + 1);
if (secondColon >= 0) {
String metaPart = s.substring(secondColon + 1);
try {
meta = Integer.parseInt(metaPart);
s = s.substring(0, secondColon);
} catch (NumberFormatException ignored) {}
}
}
var parsed = IdUtils.parseItemRef(s, pageId.getResourceDomain());
if (parsed == null) {
return null;
}
return new NavigationIconEntry(IdUtils.rawRegistryKey(s, pageId.getResourceDomain()), meta, null);
return new NavigationIconEntry(parsed.rawKey(), parsed.concreteMeta(), copyNbt(parsed.nbt()));
}

@Nullable
Expand All @@ -368,4 +356,9 @@ private static String toDateString(@Nullable Object value) {
}
return value.toString();
}

@Nullable
private static NBTTagCompound copyNbt(@Nullable NBTTagCompound nbt) {
return nbt == null ? null : (NBTTagCompound) nbt.copy();
}
}
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
package com.hfstudio.guidenh.guide.compiler;

import java.util.List;
import java.util.Map;

import net.minecraft.nbt.NBTTagCompound;
import net.minecraft.util.ResourceLocation;

import org.jetbrains.annotations.Nullable;
Expand All @@ -24,7 +24,7 @@ public class FrontmatterNavigation {
private final String iconItemId;
private final int iconItemMeta;
@Nullable
private final Map<?, ?> iconComponents;
private final NBTTagCompound iconNbt;
@Nullable
private final ResourceLocation iconTextureId;
@Nullable
Expand All @@ -36,7 +36,7 @@ public class FrontmatterNavigation {
private final int loadPriority;

public FrontmatterNavigation(String title, @Nullable ResourceLocation parent, int position, int recommend,
@Nullable String iconItemId, int iconItemMeta, @Nullable Map<?, ?> iconComponents,
@Nullable String iconItemId, int iconItemMeta, @Nullable NBTTagCompound iconNbt,
@Nullable ResourceLocation iconTextureId, @Nullable List<NavigationIconEntry> iconEntries,
@Nullable List<ResourceLocation> iconTextureEntries, @Nullable List<String> requiredMods, int loadPriority) {
this.title = title;
Expand All @@ -45,7 +45,7 @@ public FrontmatterNavigation(String title, @Nullable ResourceLocation parent, in
this.recommend = recommend;
this.iconItemId = iconItemId;
this.iconItemMeta = iconItemMeta;
this.iconComponents = iconComponents;
this.iconNbt = iconNbt;
this.iconTextureId = iconTextureId;
this.iconEntries = iconEntries;
this.iconTextureEntries = iconTextureEntries;
Expand Down Expand Up @@ -80,8 +80,8 @@ public int iconItemMeta() {
}

@Nullable
public Map<?, ?> iconComponents() {
return iconComponents;
public NBTTagCompound iconNbt() {
return iconNbt;
}

@Nullable
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package com.hfstudio.guidenh.guide.compiler;

import java.util.Map;
import net.minecraft.nbt.NBTTagCompound;

import org.jetbrains.annotations.Nullable;

Expand All @@ -11,4 +11,4 @@
* (mod ID casing preserved) used for item lookup.
*/
@Desugar
public record NavigationIconEntry(String itemId, int meta, @Nullable Map<?, ?> nbt) {}
public record NavigationIconEntry(String itemId, int meta, @Nullable NBTTagCompound nbt) {}
Original file line number Diff line number Diff line change
Expand Up @@ -127,8 +127,8 @@ public static void reloadGuides(IResourceManager resourceManager) {
/**
* Scans the guide folder tree and loads all markdown files under {@code assets/<namespace>/<folder>/_<lang>/...}.
*/
static Map<ResourceLocation, ParsedGuidePage> loadPages(IResourceManager resourceManager, ResourceLocation guideId,
String folder, String defaultLanguage, @Nullable String currentLanguage) {
public static Map<ResourceLocation, ParsedGuidePage> loadPages(IResourceManager resourceManager,
ResourceLocation guideId, String folder, String defaultLanguage, @Nullable String currentLanguage) {
return loadPages(
resourceManager,
guideId,
Expand All @@ -139,8 +139,8 @@ static Map<ResourceLocation, ParsedGuidePage> loadPages(IResourceManager resourc
DataDrivenGuideLoader.getActiveResourcePacks(resourceManager));
}

static Map<ResourceLocation, ParsedGuidePage> loadPages(IResourceManager resourceManager, ResourceLocation guideId,
String folder, String defaultLanguage, @Nullable String currentLanguage,
public static Map<ResourceLocation, ParsedGuidePage> loadPages(IResourceManager resourceManager,
ResourceLocation guideId, String folder, String defaultLanguage, @Nullable String currentLanguage,
Map<String, LinkedHashMap<String, LinkedHashSet<String>>> pagePathCache,
Iterable<? extends IResourcePack> activeResourcePacks) {
long startedAt = System.nanoTime();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,13 @@
public class FrontmatterValueProvider implements AutocompleteProvider {

private static final Map<String, String[]> HINTS = new LinkedHashMap<>();

static {
HINTS.put(
"navigation",
new String[] { "\n title:", "\n parent:", "\n position:", "\n icon:", "\n icon_texture:" });
new String[] { "\n title:", "\n parent:", "\n position:",
"\n icon: minecraft:book:0:{display:{Name:\"Custom Icon\"}}",
"\n icons:\n - minecraft:book:0:{display:{Name:\"Cycling Icon\"}}", "\n icon_texture:" });
// TODO: integrate with BetterQuesting for dynamic quest UUID lookup
HINTS.put("quest_ids", new String[] { "\n - 00000000-0000-0000-0000-000000000000" });
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@
import com.hfstudio.guidenh.guide.PageCollection;
import com.hfstudio.guidenh.guide.compiler.NavigationIconEntry;
import com.hfstudio.guidenh.guide.compiler.ParsedGuidePage;
import com.hfstudio.guidenh.guide.compiler.YamlNbtConverter;
import com.hfstudio.guidenh.guide.render.GuidePageTexture;
import com.hfstudio.guidenh.guide.scene.support.GuideDebugLog;

Expand All @@ -32,7 +31,7 @@ public static GuidePageIcon createNavigationIcon(ParsedGuidePage page, @Nullable

var iconTextureEntries = navigation.iconTextureEntries();
if (iconTextureEntries != null && !iconTextureEntries.isEmpty()) {
List<GuidePageTexture> cycleTextures = new ArrayList<>();
List<GuidePageTexture> cycleTextures = new ArrayList<>(iconTextureEntries.size());
List<ResourceLocation> cycleTextureIds = new ArrayList<>(iconTextureEntries);
if (pages != null) {
for (ResourceLocation texId : iconTextureEntries) {
Expand Down Expand Up @@ -62,7 +61,7 @@ public static GuidePageIcon createNavigationIcon(ParsedGuidePage page, @Nullable

var iconEntries = navigation.iconEntries();
if (iconEntries != null && !iconEntries.isEmpty()) {
List<ItemStack> cycleItems = new ArrayList<>();
List<ItemStack> cycleItems = new ArrayList<>(iconEntries.size());
for (NavigationIconEntry entry : iconEntries) {
var stack = resolveItemStack(page, entry.itemId(), entry.meta(), entry.nbt());
if (stack != null) {
Expand All @@ -81,11 +80,7 @@ public static GuidePageIcon createNavigationIcon(ParsedGuidePage page, @Nullable
return null;
}

var stack = resolveItemStack(
page,
navigation.iconItemId(),
navigation.iconItemMeta(),
navigation.iconComponents());
var stack = resolveItemStack(page, navigation.iconItemId(), navigation.iconItemMeta(), navigation.iconNbt());
if (stack == null) return null;
return GuidePageIcon.item(stack);
}
Expand All @@ -104,7 +99,7 @@ public static GuidePageIcon createTextureIcon(ParsedGuidePage page, PageCollecti

@Nullable
private static ItemStack resolveItemStack(ParsedGuidePage page, String itemId, int meta,
@Nullable java.util.Map<?, ?> nbt) {
@Nullable NBTTagCompound nbt) {
var item = (Item) Item.itemRegistry.getObject(itemId);
if (item == null) {
GuideDebugLog
Expand All @@ -113,8 +108,7 @@ private static ItemStack resolveItemStack(ParsedGuidePage page, String itemId, i
}
var stack = new ItemStack(item, 1, meta);
if (nbt != null) {
NBTTagCompound nbtTag = YamlNbtConverter.toNbt(nbt);
stack.setTagCompound(nbtTag);
stack.setTagCompound((NBTTagCompound) nbt.copy());
}
return stack;
}
Expand Down
Loading