[修正] 奥术配方研究 key 修复与奥术合成终端充能完善
- 配方: 1k/4k/16k/64k 存储组件、无线傀儡背包、源质发信器 研究 key 改为实际注册节点 (ESSENTIASTORAGE / GOLEMWIFIBACKPACK / ESSENTIATERMINAL) - 配方: 扩散/凝聚核心材料 quicksilver → quicksilver_drop - 配方: 知识记录仪/蒸馏编码台/源质终端 显示器三变体合并为 thaumicenergistics:monitors tag (9 份重复配方 → 3 份) - 终端: 新增法杖自动充能 (内存卡链接 Vis Interface P2P 频率, IGridTickable 每 tick 抽取, 速率与原版充能中继一致 5 cV/tick) - 装配器: 删除无调用方且会静默失败的 findMatchingArcaneRecipe; vis 折扣魔法值统一为 BASE_VIS_DISCOUNT 常量 - 清理: 删除 Feature 空壳层/ThEFeatureBase/AEPartGridBlock 等死代码 (-362 行), 删除空 registerScanEvent, 硬编码节点数, lang 死键 - 编译: IDEA 全项目通过 (problems: [])
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
package thaumicenergistics;
|
||||
|
||||
import appeng.api.features.GridLinkables;
|
||||
import appeng.api.features.P2PTunnelAttunement;
|
||||
import appeng.api.parts.PartModels;
|
||||
import appeng.api.stacks.AEKeyType;
|
||||
import appeng.api.stacks.AEKeyTypesInternal;
|
||||
@@ -19,7 +20,6 @@ import net.neoforged.neoforge.client.event.RegisterMenuScreensEvent;
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
import thaumicenergistics.common.container.*;
|
||||
import thaumicenergistics.common.features.FeatureRegistry;
|
||||
import thaumicenergistics.common.features.RecipeRegistration;
|
||||
import thaumicenergistics.common.integration.appeng.AEssentiaKeyType;
|
||||
import thaumicenergistics.common.integration.appeng.ThEAppliedEnergistics;
|
||||
@@ -107,12 +107,11 @@ public final class ThaumicEnergistics {
|
||||
event.enqueueWork(() -> {
|
||||
RecipeRegistration.registerAll();
|
||||
ThEThaumcraft.init();
|
||||
P2PTunnelAttunement.registerAttunementTag(ModItems.VIS_INTERFACE.get());
|
||||
GridLinkables.register(ModItems.GOLEM_WIFI_BACKPACK.get(), ItemGolemWirelessBackpack.LINKABLE_HANDLER);
|
||||
GridLinkables.register(ModItems.WIRELESS_ESSENTIA_TERMINAL.get(),
|
||||
appeng.items.tools.powered.WirelessTerminalItem.LINKABLE_HANDLER);
|
||||
});
|
||||
|
||||
FeatureRegistry.registerAll();
|
||||
}
|
||||
|
||||
private void registerUpgrades(FMLCommonSetupEvent event) {
|
||||
|
||||
@@ -1,21 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/**
|
||||
* 功能:奥术自动合成。
|
||||
* 启用奥术装配器及相关合成样板。
|
||||
* 自 1.7.10 FeatureAutocrafting_Arcane 移植(约 7k 行)。
|
||||
*/
|
||||
public class FeatureAutocraftingArcane extends ThEFeatureBase {
|
||||
public FeatureAutocraftingArcane() { super("arcane_crafting_terminal"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// Arcane Assembler 方块经 ModBlocks 注册
|
||||
// TODO: Register arcane crafting pattern encoder, crafting CPU integration
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPostInit() {
|
||||
// TODO: Register arcane crafting recipes, research entries
|
||||
}
|
||||
}
|
||||
@@ -1,20 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/**
|
||||
* 源质存储元件功能。
|
||||
* 注册 cell 物品、元件工作台与存储组件物品。
|
||||
* 自 1.7.10 FeatureCells 移植(约 12k 行)。
|
||||
*/
|
||||
public class FeatureCells extends ThEFeatureBase {
|
||||
public FeatureCells() { super("cells"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// 物品经 init 包的 ModItems 注册——本功能校验其存在
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPostInit() {
|
||||
// TODO: Register cell recipes, research entries, cell workbench functionality
|
||||
}
|
||||
}
|
||||
@@ -1,35 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
import thaumicenergistics.ThaumicEnergistics;
|
||||
import thaumicenergistics.init.ModItems;
|
||||
|
||||
/**
|
||||
* 功能:源质 IO 总线。
|
||||
* 启用源质输入/输出/存储总线Part部件
|
||||
* Part注册已移至模组主类ThaumicEnergistics构造方法中,
|
||||
* 通过AE2官方PartHelper.registerPart() API完成,
|
||||
* 本Feature负责功能开关、配方注册、研究数据等跨模组集成内容。
|
||||
*/
|
||||
public class FeatureEssentiaIOBuses extends ThEFeatureBase {
|
||||
public FeatureEssentiaIOBuses() { super("io_buses"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// ===== Part核心注册已在ThaumicEnergistics构造方法中完成 =====
|
||||
// 原因:AE2 PartHelper.registerPart()需要DeferredItem注册完成后立即调用,
|
||||
// Feature.register()的调用时机同样满足,但为了集中管理Part注册入口,统一在主类中处理。
|
||||
|
||||
// ===== 以下登记本Feature涉及的物品,供跨模组引用追踪 =====
|
||||
ThaumicEnergistics.LOG.info(" -> EssentiaImportBus PartItem: {} (ready)",
|
||||
ModItems.ESSENTIA_IMPORT_BUS.getId());
|
||||
ThaumicEnergistics.LOG.info(" -> EssentiaExportBus PartItem: {} (pending)",
|
||||
ModItems.ESSENTIA_EXPORT_BUS.getId());
|
||||
ThaumicEnergistics.LOG.info(" -> EssentiaStorageBus PartItem: {} (pending)",
|
||||
ModItems.ESSENTIA_STORAGE_BUS.getId());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPostInit() {
|
||||
// 后置初始化:注册神秘时代研究条目、AE2合成配方等
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/**
|
||||
* 源质监控功能。
|
||||
* 启用源质水平检测器、存储监控器与转换监控器部件。
|
||||
* 自 1.7.10 FeatureEssentiaMonitoring 移植(约 6k 行)。
|
||||
*/
|
||||
public class FeatureEssentiaMonitoring extends ThEFeatureBase {
|
||||
public FeatureEssentiaMonitoring() { super("monitoring"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// TODO: Register monitoring-related parts when AE2 part API is integrated
|
||||
}
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/** 功能:源质供应器。从 AE 网络核心抽取源质。 */
|
||||
public class FeatureEssentiaProvider extends ThEFeatureBase {
|
||||
public FeatureEssentiaProvider() { super("essentia_provider"); }
|
||||
@Override protected void doRegister() {}
|
||||
}
|
||||
@@ -1,21 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/**
|
||||
* 功能:源质谐振仓。
|
||||
* 启用基于源质的能量生产。
|
||||
* 自 1.7.10 FeatureEssentiaVibrationChamber 移植(约 4k 行)。
|
||||
*/
|
||||
public class FeatureEssentiaVibrationChamber extends ThEFeatureBase {
|
||||
public FeatureEssentiaVibrationChamber() { super("vibration_chamber"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// EVC 方块经 ModBlocks 注册
|
||||
// TODO: Register fuel values for each essentia type
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPostInit() {
|
||||
// TODO: Register EVC recipe, research entry
|
||||
}
|
||||
}
|
||||
@@ -1,11 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/** 功能:无线傀儡背包。启用傀儡访问 AE 网络。 */
|
||||
public class FeatureGolemBackpack extends ThEFeatureBase {
|
||||
public FeatureGolemBackpack() { super("golem_backpack"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// GridLinkables 注册在 commonSetup 阶段完成(需要物品已绑定)
|
||||
}
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
/**
|
||||
* 功能:注魔供应器。
|
||||
* 为 TC 注魔自动供应源质。
|
||||
* 自 1.7.10 FeatureInfusionProvider 移植(约 4k 行)。
|
||||
*/
|
||||
public class FeatureInfusionProvider extends ThEFeatureBase {
|
||||
public FeatureInfusionProvider() { super("infusion_provider"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
// Infusion Provider 方块经 ModBlocks 注册
|
||||
// TODO: Register infusion detection and essentia delivery logic
|
||||
}
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
import thaumicenergistics.ThaumicEnergistics;
|
||||
|
||||
public final class FeatureRegistry {
|
||||
private FeatureRegistry() {}
|
||||
private static final ThEFeatureBase[] FEATURES = {
|
||||
new FeatureCells(), new FeatureEssentiaIOBuses(), new FeatureEssentiaMonitoring(),
|
||||
new FeatureEssentiaVibrationChamber(), new FeatureInfusionProvider(),
|
||||
new FeatureAutocraftingArcane(), new FeatureVisRelayInterface(),
|
||||
new FeatureGolemBackpack(), new FeatureEssentiaProvider()
|
||||
};
|
||||
public static void registerAll() {
|
||||
for (var f : FEATURES) { ThaumicEnergistics.LOG.info("Feature [{}] {}", f.getName(), f.isEnabled() ? "enabled":"disabled"); f.register(); }
|
||||
}
|
||||
public static void postInitAll() { for (var f : FEATURES) f.postInit(); }
|
||||
}
|
||||
@@ -1,17 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
import appeng.api.features.P2PTunnelAttunement;
|
||||
import thaumicenergistics.init.ModItems;
|
||||
|
||||
public class FeatureVisRelayInterface extends ThEFeatureBase {
|
||||
public FeatureVisRelayInterface() { super("vis_interface"); }
|
||||
|
||||
@Override
|
||||
protected void doRegister() {
|
||||
P2PTunnelAttunement.registerAttunementTag(ModItems.VIS_INTERFACE.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doPostInit() {
|
||||
}
|
||||
}
|
||||
@@ -54,6 +54,8 @@ public final class RecipeRegistration {
|
||||
public static CrucibleRecipe CERTUS_DUPE_RECIPE;
|
||||
|
||||
private static final TagKey<Item> WISP_ESSENCES = tag("thaumicenergistics", "wisp_essences");
|
||||
/** AE2 三种显示器(普通/暗/半暗)任一可用。 */
|
||||
private static final TagKey<Item> MONITORS = tag("thaumicenergistics", "monitors");
|
||||
|
||||
@SuppressWarnings("SameParameterValue")
|
||||
private static TagKey<Item> tag(String ns, String path) {
|
||||
@@ -80,7 +82,7 @@ public final class RecipeRegistration {
|
||||
}
|
||||
|
||||
private static void registerShapedArcane() {
|
||||
STORAGE_COMPONENT_1K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE1K", stack(ModItems.STORAGE_COMPONENT_1K),
|
||||
STORAGE_COMPONENT_1K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE", stack(ModItems.STORAGE_COMPONENT_1K),
|
||||
new AspectList().add(Aspect.FIRE, 3).add(Aspect.ORDER, 1),
|
||||
"EQ ",
|
||||
"QPQ",
|
||||
@@ -89,7 +91,7 @@ public final class RecipeRegistration {
|
||||
'Q', ae("certus_quartz_crystal"),
|
||||
'P', ae("logic_processor"));
|
||||
|
||||
STORAGE_COMPONENT_4K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE4K", stack(ModItems.STORAGE_COMPONENT_4K),
|
||||
STORAGE_COMPONENT_4K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE", stack(ModItems.STORAGE_COMPONENT_4K),
|
||||
new AspectList().add(Aspect.FIRE, 3).add(Aspect.ORDER, 2),
|
||||
"EPE",
|
||||
"1G1",
|
||||
@@ -99,7 +101,7 @@ public final class RecipeRegistration {
|
||||
'1', stack(ModItems.STORAGE_COMPONENT_1K),
|
||||
'G', ae("quartz_glass"));
|
||||
|
||||
STORAGE_COMPONENT_16K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE16K", stack(ModItems.STORAGE_COMPONENT_16K),
|
||||
STORAGE_COMPONENT_16K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE", stack(ModItems.STORAGE_COMPONENT_16K),
|
||||
new AspectList().add(Aspect.FIRE, 3).add(Aspect.ORDER, 4),
|
||||
"SPE",
|
||||
"4G4",
|
||||
@@ -110,7 +112,7 @@ public final class RecipeRegistration {
|
||||
'G', ae("quartz_glass"),
|
||||
'E', WISP_ESSENCES);
|
||||
|
||||
STORAGE_COMPONENT_64K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE64K", stack(ModItems.STORAGE_COMPONENT_64K),
|
||||
STORAGE_COMPONENT_64K = ThaumcraftApi.addArcaneCraftingRecipe("ESSENTIASTORAGE", stack(ModItems.STORAGE_COMPONENT_64K),
|
||||
new AspectList().add(Aspect.FIRE, 3).add(Aspect.ORDER, 8),
|
||||
"SPS",
|
||||
"6G6",
|
||||
@@ -140,7 +142,7 @@ public final class RecipeRegistration {
|
||||
'F', tc("fire_shard"),
|
||||
'W', ae("certus_quartz_wrench"));
|
||||
|
||||
GOLEM_WIFI_BACKPACK_RECIPE = ThaumcraftApi.addArcaneCraftingRecipe("GOLEMWIFI", stack(ModItems.GOLEM_WIFI_BACKPACK),
|
||||
GOLEM_WIFI_BACKPACK_RECIPE = ThaumcraftApi.addArcaneCraftingRecipe("GOLEMWIFIBACKPACK", stack(ModItems.GOLEM_WIFI_BACKPACK),
|
||||
new AspectList().add(Aspect.AIR, 6).add(Aspect.FIRE, 4).add(Aspect.ORDER, 3),
|
||||
"tIt",
|
||||
"nRn",
|
||||
@@ -189,58 +191,17 @@ public final class RecipeRegistration {
|
||||
" T ",
|
||||
"IPI",
|
||||
'I', new ItemStack(Items.IRON_INGOT, 4),
|
||||
'L', ae("monitor"),
|
||||
'L', MONITORS,
|
||||
'T', tc("thaumonomicon"),
|
||||
'P', ae("logic_processor"));
|
||||
|
||||
ThaumcraftApi.addArcaneCraftingRecipe("KNOWLEDGEINSCRIBER", stack(ModBlocks.KNOWLEDGE_INSCRIBER),
|
||||
new AspectList().add(Aspect.WATER, 5).add(Aspect.EARTH, 5).add(Aspect.FIRE, 5).add(Aspect.AIR, 5).add(Aspect.ORDER, 5).add(Aspect.ENTROPY, 5),
|
||||
"ILI",
|
||||
" T ",
|
||||
"IPI",
|
||||
'I', new ItemStack(Items.IRON_INGOT, 4),
|
||||
'L', ae("dark_monitor"),
|
||||
'T', tc("thaumonomicon"),
|
||||
'P', ae("logic_processor"));
|
||||
|
||||
ThaumcraftApi.addArcaneCraftingRecipe("KNOWLEDGEINSCRIBER", stack(ModBlocks.KNOWLEDGE_INSCRIBER),
|
||||
new AspectList().add(Aspect.WATER, 5).add(Aspect.EARTH, 5).add(Aspect.FIRE, 5).add(Aspect.AIR, 5).add(Aspect.ORDER, 5).add(Aspect.ENTROPY, 5),
|
||||
"ILI",
|
||||
" T ",
|
||||
"IPI",
|
||||
'I', new ItemStack(Items.IRON_INGOT, 4),
|
||||
'L', ae("semi_dark_monitor"),
|
||||
'T', tc("thaumonomicon"),
|
||||
'P', ae("logic_processor"));
|
||||
|
||||
|
||||
DISTILLATION_ENCODER_BLOCK = ThaumcraftApi.addArcaneCraftingRecipe("DISTILLATIONENCODER", stack(ModBlocks.DISTILLATION_ENCODER),
|
||||
new AspectList().add(Aspect.ORDER, 5).add(Aspect.ENTROPY, 5).add(Aspect.FIRE, 3),
|
||||
"ILI",
|
||||
" G ",
|
||||
"IPI",
|
||||
'I', new ItemStack(Items.IRON_INGOT, 4),
|
||||
'L', ae("monitor"),
|
||||
'G', tc("thaumometer"),
|
||||
'P', ae("engineering_processor"));
|
||||
|
||||
ThaumcraftApi.addArcaneCraftingRecipe("DISTILLATIONENCODER", stack(ModBlocks.DISTILLATION_ENCODER),
|
||||
new AspectList().add(Aspect.ORDER, 5).add(Aspect.ENTROPY, 5).add(Aspect.FIRE, 3),
|
||||
"ILI",
|
||||
" G ",
|
||||
"IPI",
|
||||
'I', new ItemStack(Items.IRON_INGOT, 4),
|
||||
'L', ae("dark_monitor"),
|
||||
'G', tc("thaumometer"),
|
||||
'P', ae("engineering_processor"));
|
||||
|
||||
ThaumcraftApi.addArcaneCraftingRecipe("DISTILLATIONENCODER", stack(ModBlocks.DISTILLATION_ENCODER),
|
||||
new AspectList().add(Aspect.ORDER, 5).add(Aspect.ENTROPY, 5).add(Aspect.FIRE, 3),
|
||||
"ILI",
|
||||
" G ",
|
||||
"IPI",
|
||||
'I', new ItemStack(Items.IRON_INGOT, 4),
|
||||
'L', ae("semi_dark_monitor"),
|
||||
'L', MONITORS,
|
||||
'G', tc("thaumometer"),
|
||||
'P', ae("engineering_processor"));
|
||||
}
|
||||
@@ -250,23 +211,23 @@ public final class RecipeRegistration {
|
||||
// 1. 扩散核心
|
||||
DIFFUSION_CORE = ThaumcraftApi.addShapelessArcaneCraftingRecipe("DIGISENTIA", stack(ModItems.DIFFUSION_CORE),
|
||||
new AspectList().add(Aspect.WATER, 2).add(Aspect.ENTROPY, 2),
|
||||
tc("quicksilver"),
|
||||
tc("quicksilver"),
|
||||
tc("quicksilver"),
|
||||
tc("quicksilver_drop"),
|
||||
tc("quicksilver_drop"),
|
||||
tc("quicksilver_drop"),
|
||||
tc("entropy_shard"),
|
||||
ae("annihilation_core"));
|
||||
|
||||
// 2. 凝聚核心
|
||||
COALESCENCE_CORE = ThaumcraftApi.addShapelessArcaneCraftingRecipe("DIGISENTIA", stack(ModItems.COALESCENCE_CORE),
|
||||
new AspectList().add(Aspect.WATER, 2).add(Aspect.ORDER, 2),
|
||||
tc("quicksilver"),
|
||||
tc("quicksilver"),
|
||||
tc("quicksilver"),
|
||||
tc("quicksilver_drop"),
|
||||
tc("quicksilver_drop"),
|
||||
tc("quicksilver_drop"),
|
||||
tc("order_shard"),
|
||||
ae("formation_core"));
|
||||
|
||||
// 3. 原质等级发射器
|
||||
ESSENTIA_LEVEL_EMITTER = ThaumcraftApi.addShapelessArcaneCraftingRecipe("ESSENTIAMONITORING", new ItemStack(ModItems.ESSENTIA_LEVEL_EMITTER.get(), 1),
|
||||
ESSENTIA_LEVEL_EMITTER = ThaumcraftApi.addShapelessArcaneCraftingRecipe("ESSENTIATERMINAL", new ItemStack(ModItems.ESSENTIA_LEVEL_EMITTER.get(), 1),
|
||||
new AspectList().add(Aspect.FIRE, 4),
|
||||
ae("calculation_processor"),
|
||||
new ItemStack(Items.REDSTONE_TORCH),
|
||||
@@ -275,26 +236,7 @@ public final class RecipeRegistration {
|
||||
// 4. 原质终端
|
||||
ESSENTIA_TERMINAL = ThaumcraftApi.addShapelessArcaneCraftingRecipe("ESSENTIATERMINAL", stack(ModItems.ESSENTIA_TERMINAL_ITEM),
|
||||
new AspectList().add(Aspect.WATER, 5).add(Aspect.ORDER, 2).add(Aspect.FIRE, 1),
|
||||
//'ae2:semi_dark_monitor' 'ae2:monitor' 'ae2:dark_monitor'三者任一
|
||||
ae("monitor"),
|
||||
stack(ModItems.DIFFUSION_CORE),
|
||||
stack(ModItems.COALESCENCE_CORE),
|
||||
ae("logic_processor"),
|
||||
tc("vis_filter"));
|
||||
|
||||
ThaumcraftApi.addShapelessArcaneCraftingRecipe("ESSENTIATERMINAL", stack(ModItems.ESSENTIA_TERMINAL_ITEM),
|
||||
new AspectList().add(Aspect.WATER, 5).add(Aspect.ORDER, 2).add(Aspect.FIRE, 1),
|
||||
//'ae2:semi_dark_monitor' 'ae2:monitor' 'ae2:dark_monitor'三者任一
|
||||
ae("dark_monitor"),
|
||||
stack(ModItems.DIFFUSION_CORE),
|
||||
stack(ModItems.COALESCENCE_CORE),
|
||||
ae("logic_processor"),
|
||||
tc("vis_filter"));
|
||||
|
||||
ThaumcraftApi.addShapelessArcaneCraftingRecipe("ESSENTIATERMINAL", stack(ModItems.ESSENTIA_TERMINAL_ITEM),
|
||||
new AspectList().add(Aspect.WATER, 5).add(Aspect.ORDER, 2).add(Aspect.FIRE, 1),
|
||||
//'ae2:semi_dark_monitor' 'ae2:monitor' 'ae2:dark_monitor'三者任一
|
||||
ae("semi_dark_monitor"),
|
||||
MONITORS,
|
||||
stack(ModItems.DIFFUSION_CORE),
|
||||
stack(ModItems.COALESCENCE_CORE),
|
||||
ae("logic_processor"),
|
||||
|
||||
@@ -1,43 +0,0 @@
|
||||
package thaumicenergistics.common.features;
|
||||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import thaumicenergistics.ThaumicEnergistics;
|
||||
import thaumicenergistics.config.ThEConfig;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
/**
|
||||
* 所有功能模块的基类。每个功能可独立启停。
|
||||
* 自 1.7.10 ThEFeatureBase 移植。
|
||||
*/
|
||||
public abstract class ThEFeatureBase {
|
||||
private final String name;
|
||||
protected boolean enabled;
|
||||
|
||||
protected ThEFeatureBase(String name) {
|
||||
this.name = name;
|
||||
this.enabled = ThEConfig.isFeatureEnabled(name);
|
||||
}
|
||||
|
||||
public final String getName() { return name; }
|
||||
public final boolean isEnabled() { return enabled; }
|
||||
|
||||
/** 模组构造期间调用,用于注册物品与方块。 */
|
||||
public void register() {
|
||||
if (!enabled) return;
|
||||
ThaumicEnergistics.LOG.info("Feature [{}] loading...", name);
|
||||
doRegister();
|
||||
}
|
||||
|
||||
/** 所有功能注册完成后调用,用于跨功能设置。 */
|
||||
public void postInit() {
|
||||
if (!enabled) return;
|
||||
doPostInit();
|
||||
}
|
||||
|
||||
/** 覆写以注册本功能特有的方块/物品。 */
|
||||
protected abstract void doRegister();
|
||||
/** 覆写以进行注册后设置(配方、研究等)。 */
|
||||
protected void doPostInit() {}
|
||||
}
|
||||
@@ -1,22 +0,0 @@
|
||||
package thaumicenergistics.common.grid;
|
||||
|
||||
/**
|
||||
* 表示连接到 AE2 网格的部件。
|
||||
* 对应 1.7.10 AEPartGridBlock——为 1.21.1 简化。
|
||||
* TODO: 通过 AE2 19.x API 完整连接 IGridNode。
|
||||
*/
|
||||
public class AEPartGridBlock {
|
||||
private final Object part; // 占位 PartBase 或 IPartItem
|
||||
|
||||
public AEPartGridBlock(Object part) { this.part = part; }
|
||||
|
||||
public double getIdlePowerUsage() {
|
||||
// TODO: Delegate to part
|
||||
return 1.0;
|
||||
}
|
||||
|
||||
public Object getGridNode() {
|
||||
// TODO: AE2 IGridNode
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import thaumcraft.api.ThaumcraftApi;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
import thaumcraft.api.events.ResearchCompletedEvent;
|
||||
@@ -60,8 +59,6 @@ public final class ThEThaumcraft {
|
||||
ResourceLocation.fromNamespaceAndPath(MODID, "textures/research/tab_icon.png"),
|
||||
ResourceLocation.fromNamespaceAndPath(MODID, "textures/research/research_background.png"));
|
||||
|
||||
registerScanEvent();
|
||||
|
||||
// ⚠ 必须先在当前 tab 注册伪前置节点(替代 TC 原版研究),
|
||||
// 否则 setParents 跨分类引用时线画不出来。
|
||||
registerPseudoParents();
|
||||
@@ -69,45 +66,25 @@ public final class ThEThaumcraft {
|
||||
// 注册事件监听:当 TC 原版研究解锁时,自动 complete 对应伪前置节点
|
||||
registerPseudoSync();
|
||||
|
||||
// 严格按照 1.7.10 FeatureRegistry 构造函数中的注册顺序
|
||||
// 1. FeatureThaumicEnergistics → BASEENERGISTICS (0,0)
|
||||
// 注册顺序沿袭 1.7.10 移植(决定研究 tab 内节点坐标布局),勿随意调整。
|
||||
registerBaseEnergistics();
|
||||
// 2. FeatureAutocrafting_Arcane → ARCANE_ASSEMBLER + KNOWLEDGE_INSCRIBER
|
||||
registerArcaneAssembler();
|
||||
registerKnowledgeInscriber();
|
||||
// 3. FeatureCells → ESSENTIASTORAGE (0,2) 向左延伸 1k/4k/16k/64k
|
||||
registerEssentiaStorage();
|
||||
// 4. FeatureACT → ARCANECRAFTINGTERMINAL (2,-1)
|
||||
registerArcaneCraftingTerminal();
|
||||
// 5. FeatureVisRelayInterface → VISINTERFACE (4,-1)
|
||||
registerVisInterface();
|
||||
// 6. FeatureEssentiaIOBuses → ESSENTIABUSES (-2,-2)
|
||||
registerEssentiaBuses();
|
||||
// 7. FeatureInfusionProvider → INFUSIONPROVIDER (-5,-2)
|
||||
registerInfusionProvider();
|
||||
// 8. FeatureEssentiaProvider → ESSENTIAPROVIDER (-2,-4)
|
||||
registerEssentiaProvider();
|
||||
// 9. FeatureEssentiaMonitoring → ESSENTIATERMINAL (-1,-4)
|
||||
registerEssentiaTerminal();
|
||||
// 10. FeatureConversionCores → DIGISENTIA (0,-2)
|
||||
registerDigisentia();
|
||||
// 12. FeatureWrenchFocus → FOCUS_AEWRENCH (-3,-7)
|
||||
registerFocusAEWrench();
|
||||
// 13. FeatureQuartzDupe → CERTUS_DUPE (-5,-5)
|
||||
registerCertusDupe();
|
||||
// 14. FeatureEssentiaVibrationChamber → VIBRATIONCHAMBER (1,-4)
|
||||
registerEssentiaVibrationChamber();
|
||||
// 15. FeatureAutocrafting_Essentia → DISTILLATIONENCODER (-4,-4)
|
||||
registerDistillationEncoder();
|
||||
// 16. FeatureGolemBackpack → GOLEMWIFIBACKPACK (0,-6)
|
||||
registerGolemWifiBackpack();
|
||||
|
||||
LOG.info("ThaumicEnergistics research registered ({} nodes).", 13);
|
||||
}
|
||||
|
||||
private static void registerScanEvent() {
|
||||
ThaumcraftApi.registerScanEventhandler((scanner, level, player) ->
|
||||
java.util.Optional.empty());
|
||||
LOG.info("ThaumicEnergistics research registered.");
|
||||
}
|
||||
|
||||
// ==================== 伪前置节点(跨分类引用 TC 原版研究) ====================
|
||||
|
||||
@@ -5,24 +5,38 @@ import java.util.List;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.inventory.MenuType;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import appeng.api.implementations.items.IMemoryCard;
|
||||
import appeng.api.implementations.items.MemoryCardMessages;
|
||||
import appeng.api.ids.AEComponents;
|
||||
import appeng.api.inventories.InternalInventory;
|
||||
import appeng.api.networking.IGrid;
|
||||
import appeng.api.networking.IGridNode;
|
||||
import appeng.api.networking.ticking.IGridTickable;
|
||||
import appeng.api.networking.ticking.TickRateModulation;
|
||||
import appeng.api.networking.ticking.TickingRequest;
|
||||
import appeng.api.parts.IPartItem;
|
||||
import appeng.api.parts.IPartModel;
|
||||
import appeng.core.AppEng;
|
||||
import appeng.items.parts.PartModels;
|
||||
import appeng.me.service.P2PService;
|
||||
import appeng.menu.locator.MenuLocators;
|
||||
import appeng.menu.MenuOpener;
|
||||
import appeng.parts.PartModel;
|
||||
import appeng.parts.p2p.P2PTunnelPart;
|
||||
import appeng.parts.reporting.AbstractTerminalPart;
|
||||
import appeng.util.inv.AppEngInternalInventory;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.common.items.TCFunctionalItems;
|
||||
import thaumicenergistics.ThaumicEnergistics;
|
||||
import thaumicenergistics.common.integration.tc.TCReflection;
|
||||
import thaumicenergistics.init.ModMenuTypes;
|
||||
|
||||
public class ArcaneCraftingTerminalPart extends AbstractTerminalPart {
|
||||
public class ArcaneCraftingTerminalPart extends AbstractTerminalPart implements IGridTickable {
|
||||
|
||||
public static final ResourceLocation INV_CRAFTING = AppEng.makeId("arcane_crafting_terminal_crafting");
|
||||
public static final ResourceLocation INV_WAND = ThaumicEnergistics.id("arcane_crafting_terminal_wand");
|
||||
@@ -42,12 +56,22 @@ public class ArcaneCraftingTerminalPart extends AbstractTerminalPart {
|
||||
|
||||
public static final int WAND_SLOT_INDEX = 0;
|
||||
|
||||
/** 充能间隔:每 tick 抽取一次。与 TC 能量节点池子每 tick 重置的频率、原版充能中继一致;无需放大。 */
|
||||
private static final int VIS_REPLENISH_INTERVAL = 1;
|
||||
/** 每 tick 每要素最大充能 cV,与原版奥术工作台充能中继(MagicWorkbenchCharger)一致(5 cV/tick = 1 vis/s)。 */
|
||||
private static final int MAX_CVIS_PER_TICK = 5;
|
||||
private static final String NBT_KEY_VIS_SOURCE_FREQ = "visSourceFreq";
|
||||
|
||||
/** 内存卡设定的 vis 源 P2P 频率;0 = 未设置(不自动充能)。 */
|
||||
private short visSourceFreq = 0;
|
||||
|
||||
private final AppEngInternalInventory craftingGrid = new AppEngInternalInventory(this, 9);
|
||||
private final AppEngInternalInventory wandInv = new AppEngInternalInventory(this, 1);
|
||||
|
||||
public ArcaneCraftingTerminalPart(IPartItem<?> partItem) {
|
||||
super(partItem);
|
||||
this.getMainNode().setIdlePowerUsage(0.5);
|
||||
this.getMainNode().addService(IGridTickable.class, this);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -63,6 +87,88 @@ public class ArcaneCraftingTerminalPart extends AbstractTerminalPart {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* 内存卡右键终端:读取 Vis Interface 的 P2P 频率,设为法杖充能的 vis 源。
|
||||
* 复刻奥术装配器 {@code TileArcaneAssembler.onMemoryCardActivate} 的行为:
|
||||
* 卡上带 P2P 频率(从 vis_interface shift+右键复制来的)→ 设为 vis 源;
|
||||
* 空白卡 → 清空;其它 → 交给 AE2 标准内存卡逻辑。
|
||||
*/
|
||||
@Override
|
||||
public boolean onUseItemOn(ItemStack heldItem, Player player, InteractionHand hand, Vec3 pos) {
|
||||
if (heldItem.getItem() instanceof IMemoryCard memoryCard) {
|
||||
Short freq = heldItem.get(AEComponents.EXPORTED_P2P_FREQUENCY);
|
||||
if (freq != null) {
|
||||
this.visSourceFreq = freq;
|
||||
getHost().markForSave();
|
||||
memoryCard.notifyUser(player, MemoryCardMessages.SETTINGS_LOADED);
|
||||
return true;
|
||||
} else if (heldItem.get(AEComponents.EXPORTED_SETTINGS_SOURCE) == null) {
|
||||
// 空白卡 → 清空 vis 源
|
||||
if (this.visSourceFreq != 0) {
|
||||
this.visSourceFreq = 0;
|
||||
getHost().markForSave();
|
||||
}
|
||||
memoryCard.notifyUser(player, MemoryCardMessages.SETTINGS_CLEARED);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return super.onUseItemOn(heldItem, player, hand, pos);
|
||||
}
|
||||
|
||||
// ===== 法杖自动充能(内存卡链接 Vis Interface 作为 vis 源) =====
|
||||
|
||||
@Override
|
||||
public TickingRequest getTickingRequest(IGridNode node) {
|
||||
return new TickingRequest(VIS_REPLENISH_INTERVAL, VIS_REPLENISH_INTERVAL, false);
|
||||
}
|
||||
|
||||
@Override
|
||||
public TickRateModulation tickingRequest(IGridNode node, int ticksSinceLastCall) {
|
||||
if (visSourceFreq == 0) {
|
||||
return TickRateModulation.SAME;
|
||||
}
|
||||
ItemStack wandStack = wandInv.getStackInSlot(0);
|
||||
if (wandStack.isEmpty() || !(wandStack.getItem() instanceof TCFunctionalItems.WandCastingItem wand)) {
|
||||
return TickRateModulation.SAME;
|
||||
}
|
||||
IGrid grid = node.getGrid();
|
||||
if (grid == null) {
|
||||
return TickRateModulation.SAME;
|
||||
}
|
||||
P2PService p2p = P2PService.get(grid);
|
||||
if (p2p == null) {
|
||||
return TickRateModulation.SAME;
|
||||
}
|
||||
P2PTunnelPart<?> input = p2p.getInput(visSourceFreq);
|
||||
if (!(input instanceof VisInterfacePart visSource)) {
|
||||
return TickRateModulation.SAME;
|
||||
}
|
||||
|
||||
boolean changed = false;
|
||||
int maxVis = wand.getMaxVis(wandStack);
|
||||
for (Aspect primal : Aspect.getPrimalAspects()) {
|
||||
int needed = maxVis - wand.getVis(wandStack, primal);
|
||||
if (needed <= 0) {
|
||||
continue;
|
||||
}
|
||||
ResourceLocation id = TCReflection.getAspectId(primal);
|
||||
if (id == null) {
|
||||
continue;
|
||||
}
|
||||
// 每 tick 申请真实量(与池子每 tick 重置对齐),充入真实量,vis 守恒
|
||||
int got = visSource.consumeVis(id, Math.min(MAX_CVIS_PER_TICK, needed));
|
||||
if (got > 0) {
|
||||
wand.addRealVis(wandStack, primal, got, true);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
if (changed) {
|
||||
// 法杖 vis 存储在 ItemStack NBT,手动标记保存
|
||||
getHost().markForSave();
|
||||
}
|
||||
return TickRateModulation.SAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
public MenuType<?> getMenuType(Player player) {
|
||||
return ModMenuTypes.ARCANE_CRAFTING_TERMINAL.get();
|
||||
@@ -95,6 +201,7 @@ public class ArcaneCraftingTerminalPart extends AbstractTerminalPart {
|
||||
super.readFromNBT(data, registries);
|
||||
this.craftingGrid.readFromNBT(data, "craftingGrid", registries);
|
||||
this.wandInv.readFromNBT(data, "wandInv", registries);
|
||||
this.visSourceFreq = data.contains(NBT_KEY_VIS_SOURCE_FREQ) ? data.getShort(NBT_KEY_VIS_SOURCE_FREQ) : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -102,6 +209,9 @@ public class ArcaneCraftingTerminalPart extends AbstractTerminalPart {
|
||||
super.writeToNBT(data, registries);
|
||||
this.craftingGrid.writeToNBT(data, "craftingGrid", registries);
|
||||
this.wandInv.writeToNBT(data, "wandInv", registries);
|
||||
if (visSourceFreq != 0) {
|
||||
data.putShort(NBT_KEY_VIS_SOURCE_FREQ, visSourceFreq);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -16,7 +16,6 @@ import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.Container;
|
||||
import net.minecraft.world.SimpleContainer;
|
||||
|
||||
import appeng.api.config.Actionable;
|
||||
@@ -47,7 +46,6 @@ import appeng.api.util.AECableType;
|
||||
|
||||
import thaumcraft.api.IVisDiscountGear;
|
||||
import thaumcraft.api.IWarpingGear;
|
||||
import thaumcraft.api.ThaumcraftApi;
|
||||
import thaumcraft.api.aspects.Aspect;
|
||||
import thaumcraft.api.aspects.AspectList;
|
||||
import thaumcraft.api.crafting.IArcaneRecipe;
|
||||
@@ -68,6 +66,8 @@ public class TileArcaneAssembler extends ThETileBase
|
||||
Aspect.EARTH, Aspect.ORDER, Aspect.ENTROPY
|
||||
};
|
||||
|
||||
/** 基础 vis 折扣(0.8 = 80% 成本)。calculateVisDiscounts 从该值起再减护甲折扣;无护甲时即此值。 */
|
||||
private static final float BASE_VIS_DISCOUNT = 0.8F;
|
||||
private static final int CVIS_MULTIPLIER = 10;
|
||||
private static final int MAX_STORED_CVIS = 187 * CVIS_MULTIPLIER;
|
||||
private static final int BASE_TICKS_PER_CRAFT = 20;
|
||||
@@ -152,7 +152,7 @@ public class TileArcaneAssembler extends ThETileBase
|
||||
actionSource = IActionSource.ofMachine(this);
|
||||
|
||||
for (Aspect primal : PRIMALS) {
|
||||
visDiscount.put(primal, 0.8F);
|
||||
visDiscount.put(primal, BASE_VIS_DISCOUNT);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -392,7 +392,7 @@ public class TileArcaneAssembler extends ThETileBase
|
||||
private int getRequiredCvisForAspect(Aspect aspect) {
|
||||
if (currentRecipeAspects == null) return 0;
|
||||
int baseCost = currentRecipeAspects.getAmount(aspect) * CVIS_MULTIPLIER;
|
||||
float discount = visDiscount.getOrDefault(aspect, 1.0F);
|
||||
float discount = visDiscount.getOrDefault(aspect, BASE_VIS_DISCOUNT);
|
||||
return Math.max(0, Math.round(baseCost * discount));
|
||||
}
|
||||
|
||||
@@ -402,7 +402,7 @@ public class TileArcaneAssembler extends ThETileBase
|
||||
|
||||
private void calculateVisDiscounts() {
|
||||
for (Aspect primal : PRIMALS) {
|
||||
float discount = 0.8F;
|
||||
float discount = BASE_VIS_DISCOUNT;
|
||||
|
||||
for (int i = 0; i < 4; i++) {
|
||||
ItemStack armor = internalInventory.getItem(ARMOR_SLOT_START + i);
|
||||
@@ -536,21 +536,6 @@ public class TileArcaneAssembler extends ThETileBase
|
||||
return !isCrafting;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public IArcaneRecipe findMatchingArcaneRecipe(Container craftingGrid) {
|
||||
if (level == null) return null;
|
||||
for (Object recipeObj : ThaumcraftApi.getCraftingRecipes()) {
|
||||
if (recipeObj instanceof IArcaneRecipe recipe) {
|
||||
try {
|
||||
if (recipe.matches(craftingGrid, level, null)) {
|
||||
return recipe;
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public boolean isCrafting() { return isCrafting; }
|
||||
public int getSpeedUpgrades() { return speedUpgrades; }
|
||||
public int getCraftTickCounter() { return craftTickCounter; }
|
||||
@@ -561,7 +546,7 @@ public class TileArcaneAssembler extends ThETileBase
|
||||
}
|
||||
public AspectList getStoredVis() { return storedVis; }
|
||||
public SimpleContainer getInternalInventory() { return internalInventory; }
|
||||
public float getVisDiscountForAspect(Aspect aspect) { return visDiscount.getOrDefault(aspect, 1.0F); }
|
||||
public float getVisDiscountForAspect(Aspect aspect) { return visDiscount.getOrDefault(aspect, BASE_VIS_DISCOUNT); }
|
||||
public float getWarpPowerMultiplier() { return warpPowerMultiplier; }
|
||||
|
||||
public void setSpeedUpgrades(int count) {
|
||||
|
||||
@@ -1,10 +1,7 @@
|
||||
package thaumicenergistics.config;
|
||||
import java.util.Set;
|
||||
public final class ThEConfig {
|
||||
private ThEConfig() {}
|
||||
public static final double EVC_POWER_PER_TICK = 5.0;
|
||||
public static final int CELL_1K = 1024, CELL_4K = 4096, CELL_16K = 16384, CELL_64K = 65536;
|
||||
public static final int CELL_MAX_TYPES = 12;
|
||||
private static final Set<String> ENABLED = Set.of("cells","io_buses","monitoring","arcane_crafting_terminal","essentia_provider","infusion_provider","vibration_chamber","vis_interface","golem_backpack");
|
||||
public static boolean isFeatureEnabled(String n) { return ENABLED.contains(n); }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user