This commit is contained in:
1820982382
2026-08-01 16:42:53 +08:00
parent e2ab0fb78b
commit 7b341980bd
322 changed files with 15941 additions and 0 deletions
@@ -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]);
}
}