Modopedia

Custom Page Components


Modopedia allows you to register your own Page Components for books. I'll be using the Text Box as an example of how to implement one.

Step 1.) Create a PageComponent class

First, create a new class extending net.favouriteless.modopedia.api.book.page_components.PageComponent, the JavaDocs in the class will explain how to use each method. I recommend storing the ID of the page component in a constant in this class to make it easier to find.

public class TextPageComponent extends PageComponent {
public static final ResourceLocation ID = Modopedia.id("text");
}

Step 2.) Grab your variables from the lookup

Next, override init and use it to grab any values you need from the Lookup provided to you. You need to cache every value you need here as the lookup is discarded after initialisation. Make sure to call super.init if you want the position and page number to load correctly.

Mandatory fields should use Lookup#get while optional fields should use Lookup#getOrDefault and/or Lookup#has. The keys used here are will be the names of the fields in your component's JSON objects. If any exceptions are thrown, the component will get replaced with an error component on the page, so the user can see what happened. It is recommended to throw a descriptive exception to make this clearer for the user.

private List<TextChunk> textChunks;
private int width;
private int lineHeight;
@Override
public void init(Book book, Lookup lookup, Level level) {
super.init(book, lookup, level);
Justify justify = lookup.getOrDefault("justify", Justify.LEFT).as(Justify.class);
Style baseStyle = Style.EMPTY.withFont(book.getFont()).withColor(book.getTextColour());
width = lookup.getOrDefault("width", book.getLineWidth()).asInt();
lineHeight = lookup.getOrDefault("line_height", Minecraft.getInstance().font.lineHeight).asInt();
textChunks = TextParser.parse(lookup.get("text").asString(), baseStyle, width, lineHeight, language, justify);
}

Step 3.) Rendering and click handling

The final step of creating your PageComponent class is to (if your component needs it) implement render and/or input handling. The PoseStack in render is already transformed to the position of the PageComponent and any mouse positions provided are relative to the page.

@Override
public void render(GuiGraphics graphics, BookRenderContext context, int mouseX, int mouseY, float partialTicks) {
for(TextChunk word : textChunks) {
word.render(graphics, x, y, mouseX - x, mouseY - y);
}
}
@Override
public boolean mouseClicked(BookRenderContext context, double mouseX, double mouseY, int button) {
for(TextChunk chunk : textChunks) {
if(chunk.mouseClicked(context, mouseX - x, mouseY - y, button))
return true;
}
return false;
}

Step 4.) Registering your PageComponent

The last thing you need to do for Modopedia to load your new PageComponent is add it to PageComponentRegistry. You can do this by calling PageComponentRegistry#register in your mod's Client Entrypoint. The ID you use to register your processor will be what pages use to reference it in their field.

PageComponentRegistry.get().register(TextPageComponent.ID, TextPageComponent::new);