Skip to content

Commit 2ac2550

Browse files
committed
work on disassemblers
- added disassembler debug system - fixed a bug where non-dismantle-able recipes are reversed into disassembler recipes the shapeless recipes are no longer used to generate disassembler recipes, because the "aDismantleable" is not provided since gregtech 5.09.49.93
1 parent c937b98 commit 2ac2550

File tree

7 files changed

+246
-24
lines changed

7 files changed

+246
-24
lines changed

Diff for: src/main/kotlin/cn/elytra/mod/gtnn/GTNNLateMixin.kt

+1-1
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ import org.apache.logging.log4j.Logger
1010
class GTNNLateMixin : ILateMixinLoader {
1111

1212
@JvmField
13-
val logger: Logger = LogManager.getLogger("GTNN-LateMixin-Loader")
13+
val logger: Logger = LogManager.getLogger("GTNNLateMixin")
1414

1515
override fun getMixinConfig(): String {
1616
return "mixins.gtnn.late.json"

Diff for: src/main/kotlin/cn/elytra/mod/gtnn/common/GtnnCommand.kt

+21-1
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package cn.elytra.mod.gtnn.common
22

3+
import cn.elytra.mod.gtnn.GTNN
34
import cn.elytra.mod.gtnn.modules.mixins.MixinLoader
5+
import cn.elytra.mod.gtnn.modules.simple.module.disassembler.DisassemblerHelper
46
import net.minecraft.command.CommandBase
57
import net.minecraft.command.ICommandSender
68
import net.minecraft.entity.player.EntityPlayer
@@ -30,7 +32,7 @@ object GtnnCommand : CommandBase() {
3032
): List<String> {
3133
val args = argsArray.toMutableList()
3234
return when(args.removeFirstOrNull()) {
33-
"" -> listOf("github", "loaded-mixins", "help")
35+
"" -> listOf("github", "loaded-mixins", "help", "disassemble-debug-index")
3436
else -> listOf()
3537
}
3638
}
@@ -50,15 +52,33 @@ object GtnnCommand : CommandBase() {
5052
sender.addChatMessage(ChatComponentText("Failed to open the URL, see logs for details."))
5153
}
5254
}
55+
5356
"loaded-mixins" -> {
5457
val loadedMixinNames = MixinLoader.loadedMixinModules.joinToString(", ") { it.id }
5558
sender.addChatMessage(ChatComponentText("Loaded Mixin Modules: [${loadedMixinNames}]"))
5659
}
60+
61+
"disassemble-debug-index" -> {
62+
val debugIndexStr = args.removeFirstOrNull()
63+
?: return sender.addChatMessage(ChatComponentText("Debug index required"))
64+
val debugIndex = debugIndexStr.toIntOrNull()
65+
?: return sender.addChatMessage(ChatComponentText("Debug index is an integer"))
66+
val debugIndexToRecipe = DisassemblerHelper.debugIndexToRecipe
67+
if(debugIndexToRecipe == null) {
68+
return sender.addChatMessage(ChatComponentText("Debug mode is not enabled"))
69+
}
70+
val info = debugIndexToRecipe.getOrElse(debugIndex) {
71+
return sender.addChatMessage(ChatComponentText("Debug index $debugIndex is not found!"))
72+
}
73+
info.getInfo().lineSequence().forEach { GTNN.logger.info(it) }
74+
}
75+
5776
else -> {
5877
arrayOf(
5978
"/gtnn help - show this help message",
6079
"/gtnn github - open the repository of gtnn",
6180
"/gtnn loaded-mixins - list loaded mixin modules",
81+
"/gtnn disassemble-debug-index - (with disassembler debug mode enabled) get the related recipe info with given debug index"
6282
).forEach { sender.addChatMessage(ChatComponentText(it)) }
6383
}
6484
}

Diff for: src/main/kotlin/cn/elytra/mod/gtnn/modules/mixins/MixinLoader.kt

+23-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
11
package cn.elytra.mod.gtnn.modules.mixins
22

3+
import cpw.mods.fml.common.Loader
4+
import cpw.mods.fml.common.ModContainer
5+
import cpw.mods.fml.common.versioning.ComparableVersion
36
import net.minecraft.launchwrapper.Launch
47
import net.minecraftforge.common.config.Configuration
58
import org.apache.logging.log4j.LogManager
@@ -8,7 +11,7 @@ import java.io.File
811

912
object MixinLoader {
1013

11-
val logger: Logger = LogManager.getLogger("GTNN-MixinModule-Loader")
14+
val logger: Logger = LogManager.getLogger("GTNN-Mixin-Module-Loader")
1215

1316
private val MixinModules = mutableListOf<IMixinModule>()
1417

@@ -21,7 +24,20 @@ object MixinLoader {
2124
}
2225
MixinModules += MixinModuleBuilder("disassembler-recipe-getter") {
2326
addMixin("gt5u.DisassemblerReversedRecipe_GTShapedRecipe_Mixin")
24-
addMixin("gt5u.DisassemblerReversedRecipe_GTShapelessRecipe_Mixin")
27+
addMixinDynamic {
28+
// https://github.com/GTNewHorizons/GT5-Unofficial/commit/07cc2ec931b0e479026e78298a7bd926019c9334
29+
// the commit above changed the argument of GTShapelessRecipe and removed the "aDismantleable"
30+
// causing the injection mistakenly treat the "aRemoveable" as "aDismantleable"
31+
// we should not load any shapless recipes until we have a fix to this problem
32+
val gtVersion = ComparableVersion(getModContainer("gregtech")!!.metadata.version)
33+
val tagVersionChangedTheBehavior = ComparableVersion("5.09.49.93") // must be lower than this version
34+
logger.info("Loaded GregTech version: $gtVersion")
35+
if(gtVersion < tagVersionChangedTheBehavior) {
36+
add("gt5u.DisassemblerReversedRecipe_GTShapelessRecipe_Mixin")
37+
} else {
38+
logger.info("Skipped gt5u.DisassemblerReversedRecipe_GTShapelessRecipe_Mixin due to version incompatibility")
39+
}
40+
}
2541
dependsOn(TargetMod.GregTech)
2642
mustBeEnabled()
2743
setConfigCategoryDesc("To get all the GregTech-source recipes for the Disassembler recipe map.")
@@ -70,7 +86,7 @@ object MixinLoader {
7086
MixinModules.forEach { mixinModule ->
7187
if(mixinModule.isEnabled()) {
7288
if(mixinModule.canApplyMixins()) {
73-
logger.info("Applying Mixins from $mixinModule")
89+
logger.info("Applying Mixins from ${mixinModule.id}")
7490
mixinModule.mixins.forEach { mixin ->
7591
add(mixin)
7692
logger.info("- $mixin")
@@ -83,4 +99,8 @@ object MixinLoader {
8399
}
84100
}
85101
}
102+
103+
internal fun getModContainer(modId: String): ModContainer? {
104+
return Loader.instance().modList.firstOrNull { it.modId == modId }
105+
}
86106
}

Diff for: src/main/kotlin/cn/elytra/mod/gtnn/modules/mixins/MixinModuleBuilder.kt

+29-1
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@ class MixinModuleBuilder(private val id: String) {
77
private val mixinClassesToApply: MutableSet<String> = mutableSetOf()
88
private val dependsOnTargetMods: MutableList<TargetMod> = mutableListOf()
99

10+
private val dynamicMixinClassesToApply: MutableList<MutableSet<String>.() -> Unit> = mutableListOf()
11+
1012
private var enabledByDefault: Boolean = false
1113
private var mustBeEnabled: Boolean = false
1214

@@ -27,10 +29,26 @@ class MixinModuleBuilder(private val id: String) {
2729
*/
2830
private var extraRequirementsCheck: (() -> Boolean)? = null
2931

32+
/**
33+
* Given [mixinClasses] will be constantly added when gathering Mixin classes, when this module is both
34+
* [IMixinModule.isEnabled] and [IMixinModule.canApplyMixins].
35+
*
36+
* @see addMixinDynamic
37+
*/
3038
fun addMixin(vararg mixinClasses: String) {
3139
mixinClassesToApply.addAll(mixinClasses)
3240
}
3341

42+
/**
43+
* Given [block] will be called when gathering Mixin classes, when this module is both
44+
* [IMixinModule.isEnabled] and [IMixinModule.canApplyMixins].
45+
*
46+
* You need to add the Mixin classes to the receiver.
47+
*/
48+
fun addMixinDynamic(block: MutableSet<String>.() -> Unit) {
49+
dynamicMixinClassesToApply.add(block)
50+
}
51+
3452
fun dependsOn(vararg targetMods: TargetMod) {
3553
dependsOnTargetMods.addAll(targetMods)
3654
}
@@ -54,7 +72,13 @@ class MixinModuleBuilder(private val id: String) {
5472
fun build(): IMixinModule {
5573
return object : IMixinModule {
5674
override val id: String = this@MixinModuleBuilder.id
57-
override val mixins: Set<String> = mixinClassesToApply
75+
override val mixins: Set<String>
76+
get() = buildSet {
77+
addAll(mixinClassesToApply)
78+
dynamicMixinClassesToApply.forEach {
79+
it(this)
80+
}
81+
}
5882

5983
private var enabled: Boolean = enabledByDefault
6084

@@ -89,6 +113,10 @@ class MixinModuleBuilder(private val id: String) {
89113
return dependsOnTargetMods.all { it.isLoaded }
90114
&& (extraRequirementsCheck == null || extraRequirementsCheck())
91115
}
116+
117+
override fun toString(): String {
118+
return "MixinModuleBuilder\$Generated(id=$id)"
119+
}
92120
}
93121
}
94122
}

Diff for: src/main/kotlin/cn/elytra/mod/gtnn/modules/simple/module/disassembler/DisassemblerHelper.kt

+102-5
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
package cn.elytra.mod.gtnn.modules.simple.module.disassembler
22

33
import cn.elytra.mod.gtnn.GTNN
4+
import cn.elytra.mod.gtnn.modules.simple.module.disassembler.DisassemblerHelper.debugMode
45
import cn.elytra.mod.gtnn.modules.simple.module.disassembler.DisassemblerHelper.oreDictReplace
6+
import cn.elytra.mod.gtnn.util.anyInRecipeToString
57
import com.google.common.collect.ArrayListMultimap
68
import gregtech.api.enums.*
79
import gregtech.api.items.MetaGeneratedTool
@@ -11,16 +13,102 @@ import gregtech.api.recipe.RecipeMaps
1113
import gregtech.api.util.GTModHandler
1214
import gregtech.api.util.GTOreDictUnificator
1315
import gregtech.api.util.GTRecipe
16+
import gregtech.api.util.GTRecipeBuilder
1417
import gregtech.api.util.GTUtility
1518
import ic2.api.item.IC2Items
1619
import net.minecraft.init.Blocks
1720
import net.minecraft.init.Items
1821
import net.minecraft.item.ItemStack
1922
import net.minecraftforge.oredict.OreDictionary
23+
import java.util.concurrent.atomic.AtomicInteger
24+
import kotlin.jvm.optionals.getOrNull
2025
import kotlin.math.min
2126

2227
object DisassemblerHelper {
2328

29+
private val debugMode = System.getenv("DEBUG_DISASSEMBLER") == "true"
30+
31+
sealed interface GeneratedRecipeInfo<T> {
32+
val original: T
33+
val debugIndex: Int
34+
35+
fun getInfo(): String
36+
}
37+
38+
data class AssemblerReversed(
39+
override val original: List<GTRecipe>,
40+
override val debugIndex: Int,
41+
val reason: String,
42+
): GeneratedRecipeInfo<List<GTRecipe>> {
43+
override fun getInfo(): String = buildString {
44+
appendLine("[[ Generated from Assembler recipes ]]")
45+
appendLine("Reason = $reason")
46+
appendLine("Debug Index = $debugIndex")
47+
original.forEachIndexed { index, recipe ->
48+
appendLine("<< Original recipe ($index) >>")
49+
append("inputs = ")
50+
appendLine(recipe.mInputs.joinToString(", ", "[", "]") { anyInRecipeToString(it) })
51+
}
52+
}
53+
}
54+
55+
data class CraftingTableReversed(
56+
override val original: ReversedRecipeRegistry.GTCraftingRecipe,
57+
override val debugIndex: Int,
58+
): GeneratedRecipeInfo<ReversedRecipeRegistry.GTCraftingRecipe> {
59+
override fun getInfo(): String = buildString {
60+
appendLine("[[ Generated from GregTech Crafting recipes ]]")
61+
appendLine("Debug Index = $debugIndex")
62+
append("inputs = ")
63+
appendLine(original.inputs.joinToString(", ", "[", "]") { anyInRecipeToString(it) })
64+
append("stacktrace = ")
65+
appendLine(original.adderStackTrace.stackTraceToString())
66+
}
67+
}
68+
69+
/**
70+
* A map records the reversed recipes and its original to find out which part is glitching.
71+
* Only be not-null when [debugMode] is true.
72+
*/
73+
val debugRecipeToRecipe: MutableMap<GTRecipe, MutableList<GeneratedRecipeInfo<*>>>? =
74+
if(debugMode) mutableMapOf() else null
75+
76+
val debugIndexToRecipe: MutableMap<Int, GeneratedRecipeInfo<*>>? =
77+
if(debugMode) mutableMapOf() else null
78+
79+
private val debugIndexBumper = AtomicInteger(0)
80+
81+
private fun GTRecipeBuilder.tryRecordAssemblerSourceRecipe(original: List<GTRecipe>, isHardOverride: Boolean = false) =
82+
apply {
83+
if(debugRecipeToRecipe != null) {
84+
val generated = build().getOrNull()
85+
if(generated != null) {
86+
val recipeInfoList = debugRecipeToRecipe.getOrPut(generated) { mutableListOf() }
87+
val debugIndex = debugIndexBumper.andIncrement
88+
val recipeInfo =
89+
AssemblerReversed(original, debugIndex, if(isHardOverride) "Hard-override" else "Generated")
90+
recipeInfoList.add(recipeInfo)
91+
setNEIDesc("Debug Index: $debugIndex")
92+
debugIndexToRecipe!![debugIndex] = recipeInfo
93+
}
94+
}
95+
}
96+
97+
private fun GTRecipeBuilder.tryRecordCraftingTableSourceRecipe(original: ReversedRecipeRegistry.GTCraftingRecipe) =
98+
apply {
99+
if(debugRecipeToRecipe != null) {
100+
val generated = build().getOrNull()
101+
if(generated != null) {
102+
val recipeInfoList = debugRecipeToRecipe.getOrPut(generated) { mutableListOf() }
103+
val debugIndex = debugIndexBumper.andIncrement
104+
val recipeInfo = CraftingTableReversed(original, debugIndex)
105+
recipeInfoList.add(recipeInfo)
106+
setNEIDesc("Debug Index: $debugIndex")
107+
debugIndexToRecipe!![debugIndex] = recipeInfo
108+
}
109+
}
110+
}
111+
24112
private val alwaysReplace by lazy {
25113
listOf(
26114
ItemStack(Blocks.trapped_chest, 1, OreDictionary.WILDCARD_VALUE) to
@@ -64,6 +152,9 @@ object DisassemblerHelper {
64152
val thisMaterial = itemDataInSlotIdx.mMaterial.mMaterial
65153
if(outputsInOtherRecipes != null) {
66154
for(outputsInOtherRecipe in outputsInOtherRecipes) {
155+
// check array bondary
156+
if(idx !in outputsInOtherRecipe.indices) continue
157+
67158
val dataAgainst = GTOreDictUnificator.getItemData(outputsInOtherRecipe[idx])
68159
if(!(dataAgainst == null
69160
|| dataAgainst.mMaterial == null
@@ -307,7 +398,7 @@ object DisassemblerHelper {
307398
fun loadAssemblerRecipesToDisassembler() {
308399
val assemblerRecipes = RecipeMaps.assemblerRecipes.allRecipes
309400
.filter { shouldDisassemble(it.mOutputs) }
310-
.groupBy { it.mOutputs[0] }
401+
.groupBy { GTItemStack(it.mOutputs[0]) }
311402

312403
val totalCount = assemblerRecipes.size
313404
GTNN.logger.info("Loading reversed assembler recipes, total: $totalCount")
@@ -329,6 +420,8 @@ object DisassemblerHelper {
329420
.itemOutputs(overrideOutput)
330421
.duration(overrideDuration)
331422
.eut(overrideEUt)
423+
.setNEIDesc("Generated from Assembler Recipe (Hard-overriden)")
424+
.tryRecordAssemblerSourceRecipe(recipes, true)
332425
.addTo(MTEDisassembler.RecipeMap)
333426

334427
continue@forRecipes
@@ -346,6 +439,8 @@ object DisassemblerHelper {
346439
.itemOutputs(*outputs.toTypedArray())
347440
.duration(revDuration)
348441
.eut(revEUt)
442+
.setNEIDesc("Generated from Assembler Recipe")
443+
.tryRecordAssemblerSourceRecipe(recipes)
349444
.addTo(MTEDisassembler.RecipeMap)
350445
} catch(e: Exception) {
351446
// @formatter:off
@@ -410,11 +505,11 @@ object DisassemblerHelper {
410505
}
411506

412507
/**
413-
* Adds a **REVERSED** recipe to disassembler recipe map.
414-
*
415-
* The passed-in recipe should have been reversed once before, and we don't reverse it again.
508+
* Reverse a recipe and add to disassembler recipe map.
416509
*/
417-
fun addCraftingTableReverseRecipe(revRecipe: GTRecipe) {
510+
fun handleGTCraftingRecipe(recipe: ReversedRecipeRegistry.GTCraftingRecipe) {
511+
val revRecipe = recipe.toReversedSafe() ?: return
512+
418513
if(!shouldDisassemble(revRecipe.mInputs)) return
419514

420515
try {
@@ -423,6 +518,8 @@ object DisassemblerHelper {
423518
.itemOutputs(*handleRecipeTransformation(revRecipe.mOutputs, null).toTypedArray())
424519
.duration(300)
425520
.eut(30)
521+
.setNEIDesc("Generated from GT Crafting Recipe")
522+
.tryRecordCraftingTableSourceRecipe(recipe)
426523
.addTo(MTEDisassembler.RecipeMap)
427524
} catch(e: Exception) {
428525
// @formatter:off

0 commit comments

Comments
 (0)