Skip to content

Commit

Permalink
Allow customizing Tinker's Construct manuals in dreamcraft (#794)
Browse files Browse the repository at this point in the history
* Apply spotless

* Added unit testing

* Include mod dependencies in tests

* Copied TiCo manuals from assets/tinker/manuals/en_US in TinkersConstruct
No changes made to the content yet to help content review

* Added BookDataStoreProxy

* Added BookDataReader

* Added BookLoader interface as a facade for the com.dreammaster.mantle package

* Load Tinker's Construct books from dreamcraft

* Reduced visibility of MantleBookLoader members
  • Loading branch information
YannickMG authored Jan 19, 2024
1 parent a6067b9 commit 79e2e72
Show file tree
Hide file tree
Showing 19 changed files with 2,659 additions and 2 deletions.
9 changes: 9 additions & 0 deletions addon.gradle
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
test {
useJUnitPlatform()
testLogging {
events "passed", "skipped", "failed"
}
}
configurations {
testImplementation.extendsFrom compileOnly
}
9 changes: 9 additions & 0 deletions dependencies.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,13 @@ dependencies {

runtimeOnlyNonPublishable("curse.maven:biomes-o-plenty-220318:2499612")
runtimeOnlyNonPublishable("com.github.GTNewHorizons:WailaHarvestability:1.2.0-GTNH:dev")

// Core unit testing platform
testImplementation(platform('org.junit:junit-bom:5.9.2'))
testImplementation('org.junit.jupiter:junit-jupiter')

// Extra unit testing libraries
testImplementation('org.assertj:assertj-core:3.+')
testImplementation('org.mockito:mockito-core:5.+')
testImplementation('org.mockito:mockito-junit-jupiter:5.+')
}
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package com.dreammaster.coremod.transformers;

import static org.objectweb.asm.Opcodes.*;
import static org.objectweb.asm.Opcodes.ACC_PUBLIC;
import static org.objectweb.asm.Opcodes.ALOAD;
import static org.objectweb.asm.Opcodes.ARETURN;
import static org.objectweb.asm.Opcodes.INVOKEVIRTUAL;
import static org.objectweb.asm.Opcodes.POP;

import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.tree.AbstractInsnNode;
Expand Down
11 changes: 10 additions & 1 deletion src/main/java/com/dreammaster/main/MainRegistry.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,16 @@
package com.dreammaster.main;

import static gregtech.api.enums.Dyes.MACHINE_METAL;
import static gregtech.api.enums.Mods.*;
import static gregtech.api.enums.Mods.Avaritia;
import static gregtech.api.enums.Mods.BartWorks;
import static gregtech.api.enums.Mods.BloodMagic;
import static gregtech.api.enums.Mods.GalactiGreg;
import static gregtech.api.enums.Mods.Railcraft;
import static gregtech.api.enums.Mods.SGCraft;
import static gregtech.api.enums.Mods.Thaumcraft;
import static gregtech.api.enums.Mods.TinkerConstruct;
import static gregtech.api.enums.Mods.TwilightForest;
import static gregtech.api.enums.Mods.Witchery;
import static gregtech.api.recipe.RecipeMaps.compressorRecipes;
import static gregtech.api.util.GT_RecipeBuilder.SECONDS;

Expand Down
50 changes: 50 additions & 0 deletions src/main/java/com/dreammaster/mantle/BookDataReader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
package com.dreammaster.mantle;

import java.io.IOException;
import java.io.InputStream;
import java.util.Objects;

import javax.annotation.Nonnull;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.xml.sax.SAXException;

/**
* This class doesn't support loading different XML documents based on Minecraft's currently configured language. Books
* are instead intended to be translated through lang files.
*/
class BookDataReader {

private static final DocumentBuilderFactory DB_FACTORY = DocumentBuilderFactory.newInstance();

@Nonnull
Document readBook(String xmlDocumentLocation) {
try (InputStream stream = loadBook(xmlDocumentLocation)) {
return readBookDocument(stream);
} catch (ParserConfigurationException | SAXException | IOException e) {
throw new IllegalStateException(
"Failed to load book data from " + xmlDocumentLocation + ":\n" + e.getMessage(),
e);
}
}

@Nonnull
private InputStream loadBook(String path) throws IOException {
InputStream inputStream = getClass().getResourceAsStream(path);
if (Objects.isNull(inputStream)) {
throw new IOException("File " + path + " does not exist.");
}
return inputStream;
}

@Nonnull
private Document readBookDocument(InputStream stream)
throws ParserConfigurationException, SAXException, IOException {
Document doc = DB_FACTORY.newDocumentBuilder().parse(stream);
doc.getDocumentElement().normalize();
return doc;
}

}
38 changes: 38 additions & 0 deletions src/main/java/com/dreammaster/mantle/BookDataStoreProxy.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
package com.dreammaster.mantle;

import java.util.Objects;

import com.dreammaster.main.MainRegistry;

import eu.usrv.yamcore.auxiliary.LogHelper;
import mantle.books.BookData;
import mantle.books.BookDataStore;

/**
* This class helps us avoid issues with books already loaded by another mod.
*/
class BookDataStoreProxy {

private static final BookDataStoreProxy INSTANCE = new BookDataStoreProxy(MainRegistry.Logger);

static BookDataStoreProxy getInstance() {
return INSTANCE;
}

private final LogHelper logger;

BookDataStoreProxy(LogHelper logger) {
Objects.requireNonNull(logger);
this.logger = logger;

}

void addBook(BookData bookData) {
Objects.requireNonNull(bookData);
try {
BookDataStore.addBook(bookData);
} catch (IllegalArgumentException e) {
logger.error("Cannot override book " + bookData.unlocalizedName + " which is already defined elsewhere.");
}
}
}
16 changes: 16 additions & 0 deletions src/main/java/com/dreammaster/mantle/BookLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package com.dreammaster.mantle;

public interface BookLoader {

static BookLoader of(String unlocalizedName, String modId, String xmlDocumentPath) {
return MantleBookLoader.readBook(unlocalizedName, modId, xmlDocumentPath);
}

BookLoader setTooltip(String tooltip);

BookLoader setItemImage(String itemImage);

BookLoader makeTranslatable();

void addToBookDataStore();
}
79 changes: 79 additions & 0 deletions src/main/java/com/dreammaster/mantle/MantleBookLoader.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
package com.dreammaster.mantle;

import java.util.Objects;
import java.util.stream.Stream;

import net.minecraft.util.ResourceLocation;
import net.minecraft.util.StatCollector;

import com.google.common.annotations.VisibleForTesting;
import com.google.common.base.Strings;

import gregtech.GT_Mod;
import gregtech.api.interfaces.internal.IGT_Mod;
import mantle.books.BookData;

final class MantleBookLoader implements BookLoader {

private static final BookDataReader BOOK_DATA_READER = new BookDataReader();
private static final BookDataStoreProxy BOOK_DATA_STORE_PROXY = BookDataStoreProxy.getInstance();
private final BookDataStoreProxy bookDataStoreProxy;
private final BookData data;
private final IGT_Mod sideChecker;
private final BookDataReader bookDataReader;

static BookLoader readBook(String unlocalizedName, String modId, String xmlDocumentPath) {
return new MantleBookLoader(BOOK_DATA_STORE_PROXY, BOOK_DATA_READER, GT_Mod.gregtechproxy)
.setRequiredData(unlocalizedName, modId, xmlDocumentPath);
}

@VisibleForTesting
MantleBookLoader(BookDataStoreProxy bookDataStoreProxy, BookDataReader bookDataReader, IGT_Mod sideChecker) {
Stream.of(bookDataStoreProxy, bookDataReader, sideChecker).forEach(Objects::requireNonNull);
this.bookDataStoreProxy = bookDataStoreProxy;
this.bookDataReader = bookDataReader;
this.sideChecker = sideChecker;
this.data = new BookData();
}

@VisibleForTesting
BookLoader setRequiredData(String unlocalizedName, String modId, String xmlDocumentPath) {
Objects.requireNonNull(unlocalizedName);
Objects.requireNonNull(modId);
Objects.requireNonNull(xmlDocumentPath);
this.data.unlocalizedName = unlocalizedName;
this.data.modID = modId;
if (sideChecker.isClientSide()) {
data.doc = bookDataReader.readBook(xmlDocumentPath);
}
return this;
}

@Override
public BookLoader setTooltip(String tooltip) {
Objects.requireNonNull(tooltip);
data.toolTip = "§o" + StatCollector.translateToLocal(tooltip);
return this;
}

@Override
public BookLoader setItemImage(String itemImage) {
Objects.requireNonNull(itemImage);
data.itemImage = new ResourceLocation(data.modID, itemImage);
return this;
}

@Override
public BookLoader makeTranslatable() {
data.isTranslatable = true;
return this;
}

@Override
public void addToBookDataStore() {
if (Strings.isNullOrEmpty(data.unlocalizedName)) {
throw new IllegalStateException("You must call setRequiredData before addToBookDataStore.");
}
bookDataStoreProxy.addBook(data);
}
}
22 changes: 22 additions & 0 deletions src/main/java/com/dreammaster/scripts/ScriptTinkersConstruct.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
import static gregtech.api.enums.Mods.GregTech;
import static gregtech.api.enums.Mods.IguanaTweaksTinkerConstruct;
import static gregtech.api.enums.Mods.IndustrialCraft2;
import static gregtech.api.enums.Mods.Mantle;
import static gregtech.api.enums.Mods.Minecraft;
import static gregtech.api.enums.Mods.Natura;
import static gregtech.api.enums.Mods.NewHorizonsCoreMod;
Expand All @@ -33,6 +34,7 @@
import net.minecraftforge.oredict.OreDictionary;

import com.dreammaster.gthandler.CustomItemList;
import com.dreammaster.mantle.BookLoader;
import com.dreammaster.oredict.OreDictHelper;
import com.dreammaster.tinkersConstruct.TConstructHelper;

Expand All @@ -50,6 +52,15 @@

public class ScriptTinkersConstruct implements IScriptLoader {

/**
* Purposefully adding this static method here and keeping it private rather than adding onto TConstructHelper to
* avoid future proliferation of overloads of this method.
*/
private static void addBook(String bookName, String unlocalizedName, String tooltip, String itemImage) {
BookLoader.of(unlocalizedName, TinkerConstruct.ID, "/assets/dreamcraft/tinker/manuals/" + bookName + ".xml")
.setTooltip(tooltip).setItemImage(itemImage).makeTranslatable().addToBookDataStore();
}

@Override
public String getScriptName() {
return "Tinkers Construct";
Expand All @@ -59,6 +70,7 @@ public String getScriptName() {
public List<String> getDependencies() {
return Arrays.asList(
TinkerConstruct.ID,
Mantle.ID,
RandomThings.ID,
TinkersMechworks.ID,
BloodArsenal.ID,
Expand Down Expand Up @@ -3499,5 +3511,15 @@ public void loadRecipes() {
.itemOutputs(getModItem(TinkerConstruct.ID, "decoration.stoneladder", 4, 0, missing))
.duration(3 * SECONDS).eut(30).addTo(assemblerRecipes);

addManuals();
}

private void addManuals() {
addBook("firstday", "tconstruct.manual.beginner", "manual1.tooltip", "tinker:tinkerbook_diary");
addBook("materials", "tconstruct.manual.toolstation", "manual2.tooltip", "tinker:tinkerbook_toolstation");
addBook("smeltery", "tconstruct.manual.smeltery", "manual3.tooltip", "tinker:tinkerbook_smeltery");
addBook("diary", "tconstruct.manual.diary", "manual4.tooltip", "tinker:tinkerbook_blue");
addBook("weaponry", "tconstruct.manual.weaponry", "manual5.tooltip", "tinker:tinkerbook_green");
}

}
Loading

0 comments on commit 79e2e72

Please sign in to comment.