提交
This commit is contained in:
@@ -0,0 +1,156 @@
|
||||
package thaumicenergistics.common.integration.tc;
|
||||
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
import thaumcraft.api.research.ResearchCategories;
|
||||
import thaumcraft.api.research.ResearchItem;
|
||||
import thaumcraft.api.research.ResearchPage;
|
||||
import thaumcraft.common.research.TCResearchIndex;
|
||||
import thaumicenergistics.ThaumicEnergistics;
|
||||
|
||||
/**
|
||||
* 伪前置桩节点。在 ThE 的研究 tab 中创建一个占位节点,
|
||||
* 其图标、名称、页面全部指向 TC 原版研究,使得 ThE 节点可以跨分类连线。
|
||||
*
|
||||
* 关键实现细节:
|
||||
* - key 仍使用 PSEUDO_ 前缀(如 PSEUDO_VISPOWER),避免与原版研究在 TCResearchManager 的 CompoundTag 中冲突。
|
||||
* - 图标(icon_item/icon_resource)直接使用原版研究的图标,在 registerApiResearch 时会被正确拷贝到 TCResearchIndex.Entry。
|
||||
* - 页面(pages)直接使用原版研究的页面,使点击伪前置时能展示原版研究的内容。
|
||||
* - 名称翻译通过 ThE 的 lang 文件中添加 tc.research_name.PSEUDO_* 条目指向原版翻译 key 来解决。
|
||||
* - 解锁同步通过 ResearchCompletedEvent 事件监听实现,见 ThEThaumcraft.registerPseudoSync()。
|
||||
*/
|
||||
public class PseudoResearchItem extends ResearchItem {
|
||||
|
||||
/** 原版真实研究的 key,如 "DISTILESSENTIA" */
|
||||
private final String realKey;
|
||||
|
||||
/** 原版真实研究所在分类,如 "ALCHEMY" */
|
||||
private final String realCategory;
|
||||
|
||||
/** 指向的原版研究(用于 getName/getText/getPages 委托)。 */
|
||||
private ResearchItem realResearch;
|
||||
|
||||
private PseudoResearchItem(String pseudoKey, String category, int column, int row,
|
||||
ItemStack icon, String realKey, String realCategory) {
|
||||
super(pseudoKey, category, new AspectList(), column, row, 1, icon);
|
||||
this.realKey = realKey;
|
||||
this.realCategory = realCategory;
|
||||
// concealed: 当 parentsComplete 或 completed 时可见
|
||||
this.setStub().setConcealed();
|
||||
}
|
||||
|
||||
private PseudoResearchItem(String pseudoKey, String category, int column, int row,
|
||||
ResourceLocation icon, String realKey, String realCategory) {
|
||||
super(pseudoKey, category, new AspectList(), column, row, 1, icon);
|
||||
this.realKey = realKey;
|
||||
this.realCategory = realCategory;
|
||||
this.setStub().setConcealed();
|
||||
}
|
||||
|
||||
/**
|
||||
* 创建一个指向 TC 原版研究的伪前置。
|
||||
*
|
||||
* @param pseudoKey 伪前置在 ThE tab 中的 key(如 "PSEUDO_DISTILESSENTIA")
|
||||
* @param category ThE 研究分类(即 TAB)
|
||||
* @param realKey TC 原版研究的 key(如 "DISTILESSENTIA")
|
||||
* @param realCategory TC 原版研究所在分类(如 "ALCHEMY")
|
||||
* @param column 伪前置的 X 坐标
|
||||
* @param row 伪前置的 Y 坐标
|
||||
*/
|
||||
public static PseudoResearchItem newPseudo(String pseudoKey, String category,
|
||||
String realKey, String realCategory,
|
||||
int column, int row) {
|
||||
var realCat = ResearchCategories.researchCategories.get(realCategory);
|
||||
if (realCat == null) {
|
||||
throw new IllegalArgumentException("TC category not found: " + realCategory);
|
||||
}
|
||||
ResearchItem realResearch = realCat.research.get(realKey);
|
||||
if (realResearch == null) {
|
||||
throw new IllegalArgumentException("TC research not found: " + realKey + " in " + realCategory);
|
||||
}
|
||||
|
||||
PseudoResearchItem pseudo;
|
||||
// 图标第一优先:真实研究对应的物品(research_index.json 的 item 字段,TC tab 中即用此图标)
|
||||
ItemStack realIcon = resolveRealIconItem(realKey);
|
||||
if (!realIcon.isEmpty()) {
|
||||
pseudo = new PseudoResearchItem(pseudoKey, category, column, row, realIcon, realKey, realCategory);
|
||||
} else if (realResearch.icon_item != null && !realResearch.icon_item.isEmpty()) {
|
||||
pseudo = new PseudoResearchItem(pseudoKey, category, column, row, realResearch.icon_item, realKey, realCategory);
|
||||
} else if (realResearch.icon_resource != null) {
|
||||
pseudo = new PseudoResearchItem(pseudoKey, category, column, row, realResearch.icon_resource, realKey, realCategory);
|
||||
} else if (realCat.icon != null) {
|
||||
// 备选:真实研究所在分类的图标
|
||||
pseudo = new PseudoResearchItem(pseudoKey, category, column, row, realCat.icon, realKey, realCategory);
|
||||
} else {
|
||||
// 最终备选:ThE 研究 tab 图标
|
||||
pseudo = new PseudoResearchItem(pseudoKey, category, column, row,
|
||||
ResourceLocation.fromNamespaceAndPath(thaumicenergistics.ThaumicEnergistics.MODID, "textures/research/tab_icon.png"),
|
||||
realKey, realCategory);
|
||||
}
|
||||
|
||||
// 保存真实研究引用:内容(名称/文字/页面)通过方法委托到真实研究(TC port 渲染调 getPages())
|
||||
pseudo.realResearch = realResearch;
|
||||
|
||||
ThaumicEnergistics.LOG.debug("[Pseudo] {} ← {}:{} icon={}",
|
||||
pseudoKey, realCategory, realKey,
|
||||
pseudo.icon_item != null && !pseudo.icon_item.isEmpty()
|
||||
? pseudo.icon_item.getDescriptionId() : String.valueOf(pseudo.icon_resource));
|
||||
|
||||
return pseudo;
|
||||
}
|
||||
|
||||
/**
|
||||
* 从 TC 的权威研究索引(research_index.json)解析真实研究对应的物品图标。
|
||||
*/
|
||||
private static ItemStack resolveRealIconItem(String realKey) {
|
||||
try {
|
||||
return TCResearchIndex.entry(realKey)
|
||||
.map(entry -> {
|
||||
String itemId = entry.item();
|
||||
if (itemId == null || itemId.isEmpty()) return ItemStack.EMPTY;
|
||||
ResourceLocation id = ResourceLocation.tryParse(itemId);
|
||||
if (id == null) return ItemStack.EMPTY;
|
||||
Item item = BuiltInRegistries.ITEM.get(id);
|
||||
return (item == null || item == net.minecraft.world.item.Items.AIR) ? ItemStack.EMPTY : new ItemStack(item);
|
||||
})
|
||||
.orElse(ItemStack.EMPTY);
|
||||
} catch (Exception e) {
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
}
|
||||
|
||||
public String realKey() { return realKey; }
|
||||
|
||||
public String realCategory() { return realCategory; }
|
||||
|
||||
// ===== 内容委托:TC port 渲染研究时调用 getName/getText/getPages,全部转发到真实研究 =====
|
||||
|
||||
@Override
|
||||
public String getName() {
|
||||
return realResearch != null ? realResearch.getName() : super.getName();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getText() {
|
||||
return realResearch != null ? realResearch.getText() : super.getText();
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResearchPage[] getPages() {
|
||||
// 优先:原版研究 Java 页面(API 注册的研究有)
|
||||
if (realResearch != null && realResearch.getPages() != null && realResearch.getPages().length > 0) {
|
||||
return realResearch.getPages();
|
||||
}
|
||||
// 兜底:原版研究页面在 research_index.json 的 pages 字段(页面 key,如 tc.research_page.DISTILESSENTIA.1)
|
||||
// registerApiResearch 会从 ResearchPage.text 提取这些 key 作为 Entry.pages,渲染时据此显示原版内容
|
||||
return TCResearchIndex.entry(realKey)
|
||||
.map(entry -> entry.pages().stream()
|
||||
.filter(p -> p != null && !p.isBlank())
|
||||
.map(ResearchPage::new)
|
||||
.toArray(ResearchPage[]::new))
|
||||
.orElse(new ResearchPage[0]);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user