diff --git a/nova/src/main/kotlin/xyz/xenondevs/nova/patch/impl/worldgen/NovaRuleTestPatch.kt b/nova/src/main/kotlin/xyz/xenondevs/nova/patch/impl/worldgen/NovaRuleTestPatch.kt index fa326b5f847..2c2aaae8eb9 100644 --- a/nova/src/main/kotlin/xyz/xenondevs/nova/patch/impl/worldgen/NovaRuleTestPatch.kt +++ b/nova/src/main/kotlin/xyz/xenondevs/nova/patch/impl/worldgen/NovaRuleTestPatch.kt @@ -13,7 +13,7 @@ import net.minecraft.world.level.levelgen.structure.templatesystem.PosRuleTest import net.minecraft.world.level.levelgen.structure.templatesystem.ProcessorRule import net.minecraft.world.level.levelgen.structure.templatesystem.RuleProcessor import net.minecraft.world.level.levelgen.structure.templatesystem.RuleTest -import org.objectweb.asm.Opcodes.INVOKESTATIC +import org.objectweb.asm.Opcodes import org.objectweb.asm.Opcodes.INVOKEVIRTUAL import org.objectweb.asm.tree.JumpInsnNode import org.objectweb.asm.tree.LabelNode @@ -23,13 +23,11 @@ import xyz.xenondevs.bytebase.jvm.VirtualClassPath import xyz.xenondevs.bytebase.util.calls import xyz.xenondevs.bytebase.util.next import xyz.xenondevs.bytebase.util.previousLabel +import xyz.xenondevs.bytebase.util.replaceEvery import xyz.xenondevs.bytebase.util.replaceFirst -import xyz.xenondevs.commons.collections.findNthOfType import xyz.xenondevs.nova.patch.MultiTransformer import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.BLOCK_GETTER_GET_BLOCK_STATE_METHOD import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.FEATURE_PLACE_CONTEXT_RANDOM_METHOD -import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.ORE_FEATURE_CAN_PLACE_ORE_METHOD -import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.ORE_FEATURE_DO_PLACE_METHOD import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.PROCESSOR_RULE_INPUT_PREDICATE_FIELD import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.PROCESSOR_RULE_LOC_PREDICATE_FIELD import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.PROCESSOR_RULE_POS_PREDICATE_FIELD @@ -41,12 +39,26 @@ import xyz.xenondevs.nova.util.reflection.ReflectionRegistry.TARGET_BLOCK_STATE_ import xyz.xenondevs.nova.util.reflection.ReflectionUtils import xyz.xenondevs.nova.world.generation.ExperimentalWorldGen import xyz.xenondevs.nova.world.generation.ruletest.NovaRuleTest +import java.util.function.Function + +private val ORE_FEATURE_DO_PLACE_METHOD = ReflectionUtils.getMethod( + OreFeature::class, + "doPlace", + WorldGenLevel::class, // level + RandomSource::class, // random + OreConfiguration::class, // config + Double::class, Double::class, // minX, maxX + Double::class, Double::class, // minZ, maxZ + Double::class, Double::class, // minY, maxY + Int::class, Int::class, Int::class, // x, y, z + Int::class, Int::class // width, height +) /** * This patch allows [NovaRuleTest]s to be used in [OreFeature]s, [ReplaceBlockFeature]s and structure [ProcessorRule]s */ @OptIn(ExperimentalWorldGen::class) -internal object NovaRuleTestPatch : MultiTransformer(setOf(OreFeature::class, ReplaceBlockFeature::class, RuleProcessor::class), computeFrames = true) { +internal object NovaRuleTestPatch : MultiTransformer(setOf(OreFeature::class, ReplaceBlockFeature::class, RuleProcessor::class)) { override fun transform() { transformOreFeature() @@ -55,30 +67,30 @@ internal object NovaRuleTestPatch : MultiTransformer(setOf(OreFeature::class, Re } private fun transformOreFeature() { - val placeMethod = VirtualClassPath[ORE_FEATURE_DO_PLACE_METHOD] - placeMethod.localVariables?.clear() - val canPlaceCall = placeMethod.instructions.find { it.opcode == INVOKESTATIC && (it as MethodInsnNode).calls(ORE_FEATURE_CAN_PLACE_ORE_METHOD) } as MethodInsnNode - val cantPlaceLabel = (canPlaceCall.next as JumpInsnNode).label - val prevLabel = canPlaceCall.previousLabel() - placeMethod.instructions.insertBefore(prevLabel, buildInsnList { - addLabel() - aLoad(56) - aLoad(2) - aLoad(23) - aLoad(1) - aLoad(58) - invokeStatic(ReflectionUtils.getMethodByName(NovaRuleTestPatch::class, "checkOreNovaRuleTest")) - ifeq(cantPlaceLabel) - }) - val canPlaceMethod = VirtualClassPath[ORE_FEATURE_CAN_PLACE_ORE_METHOD] - val novaRuleLabel = canPlaceMethod.instructions.findNthOfType(2) - canPlaceMethod.instructions.insert(buildInsnList { - addLabel() - aLoad(4) - getField(TARGET_BLOCK_STATE_TARGET_FIELD) - instanceOf(NovaRuleTest::class) - ifne(novaRuleLabel) - }) + VirtualClassPath[ORE_FEATURE_DO_PLACE_METHOD].replaceEvery( + 0, 0, + { + aLoad(1) // level + invokeStatic(::canPlaceOre) + } + ) { it.opcode == Opcodes.INVOKESTATIC && (it as MethodInsnNode).calls(OreFeature::canPlaceOre) } + } + + @JvmStatic + fun canPlaceOre( + state: BlockState, + adjacentStateAccessor: Function, + random: RandomSource, + config: OreConfiguration, + targetState: OreConfiguration.TargetBlockState, + pos: BlockPos.MutableBlockPos, + level: WorldGenLevel + ): Boolean { + if (targetState.target is NovaRuleTest) { + return checkOreNovaRuleTest(state, random, pos, level, targetState) + } else { + return OreFeature.canPlaceOre(state, adjacentStateAccessor, random, config, targetState, pos) + } } private fun transformReplaceBlockFeature() { @@ -105,7 +117,7 @@ internal object NovaRuleTestPatch : MultiTransformer(setOf(OreFeature::class, Re aLoad(3) aLoad(2) aLoad(6) - invokeStatic(ReflectionUtils.getMethodByName(NovaRuleTestPatch::class, "checkOreNovaRuleTest")) + invokeStatic(::checkOreNovaRuleTest) ifne(trueLabel) addLabel() @@ -121,7 +133,7 @@ internal object NovaRuleTestPatch : MultiTransformer(setOf(OreFeature::class, Re 0, buildInsnList { aLoad(1) - invokeStatic(ReflectionUtils.getMethodByName(NovaRuleTestPatch::class, "testProcessorRule")) + invokeStatic(::testProcessorRule) } ) { it.opcode == INVOKEVIRTUAL && (it as MethodInsnNode).calls(PROCESSOR_RULE_TEST_METHOD) } } diff --git a/nova/src/main/kotlin/xyz/xenondevs/nova/util/reflection/ReflectionRegistry.kt b/nova/src/main/kotlin/xyz/xenondevs/nova/util/reflection/ReflectionRegistry.kt index 60856b10c4a..6f3ceaeb75f 100644 --- a/nova/src/main/kotlin/xyz/xenondevs/nova/util/reflection/ReflectionRegistry.kt +++ b/nova/src/main/kotlin/xyz/xenondevs/nova/util/reflection/ReflectionRegistry.kt @@ -1,7 +1,6 @@ package xyz.xenondevs.nova.util.reflection import net.minecraft.core.BlockPos -import net.minecraft.core.BlockPos.MutableBlockPos import net.minecraft.core.Holder import net.minecraft.core.HolderSet import net.minecraft.core.Registry @@ -10,7 +9,6 @@ import net.minecraft.world.level.BlockGetter import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.LevelHeightAccessor import net.minecraft.world.level.LevelReader -import net.minecraft.world.level.WorldGenLevel import net.minecraft.world.level.biome.Biome import net.minecraft.world.level.biome.Biome.ClimateSettings import net.minecraft.world.level.biome.Biome.TemperatureModifier @@ -24,9 +22,7 @@ import net.minecraft.world.level.chunk.LevelChunkSection import net.minecraft.world.level.chunk.UpgradeData import net.minecraft.world.level.levelgen.blending.BlendingData import net.minecraft.world.level.levelgen.feature.FeaturePlaceContext -import net.minecraft.world.level.levelgen.feature.OreFeature import net.minecraft.world.level.levelgen.feature.ReplaceBlockFeature -import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration import net.minecraft.world.level.levelgen.feature.configurations.OreConfiguration.TargetBlockState import net.minecraft.world.level.levelgen.structure.templatesystem.ProcessorRule import net.minecraft.world.level.levelgen.structure.templatesystem.RuleProcessor @@ -42,7 +38,6 @@ import java.security.ProtectionDomain import java.util.* import net.minecraft.world.entity.LivingEntity as MojangLivingEntity import net.minecraft.world.item.ItemStack as MojangStack -import java.util.function.Function as JavaFunction // TODO: Retire ReflectionRegistry, put the fields as top level constants in the files that use them instead @Suppress("MemberVisibilityCanBePrivate") @@ -64,8 +59,6 @@ internal object ReflectionRegistry { val LIVING_ENTITY_PLAY_BLOCK_FALL_SOUND_METHOD = getMethod(MojangLivingEntity::class, true, "playBlockFallSound") val RULE_PROCESSOR_PROCESS_BLOCK_METHOD = getMethod(RuleProcessor::class, false, "processBlock", LevelReader::class, BlockPos::class, BlockPos::class, StructureTemplate.StructureBlockInfo::class, StructureTemplate.StructureBlockInfo::class, StructurePlaceSettings::class) val PROCESSOR_RULE_TEST_METHOD = getMethod(ProcessorRule::class, false, "test", BlockState::class, BlockState::class, BlockPos::class, BlockPos::class, BlockPos::class, RandomSource::class) - val ORE_FEATURE_CAN_PLACE_ORE_METHOD = getMethod(OreFeature::class, true, "canPlaceOre", BlockState::class, JavaFunction::class, RandomSource::class, OreConfiguration::class, TargetBlockState::class, MutableBlockPos::class) - val ORE_FEATURE_DO_PLACE_METHOD = getMethod(OreFeature::class, true, "doPlace", WorldGenLevel::class, RandomSource::class, OreConfiguration::class, Double::class, Double::class, Double::class, Double::class, Double::class, Double::class, Int::class, Int::class, Int::class, Int::class, Int::class) val REPLACE_BLOCK_PLACE_METHOD = getMethod(ReplaceBlockFeature::class, false, "place", FeaturePlaceContext::class) val RULE_TEST_TEST_METHOD = getMethod(RuleTest::class, false, "test", BlockState::class, RandomSource::class) val BLOCK_GETTER_GET_BLOCK_STATE_METHOD = getMethod(BlockGetter::class, false, "getBlockState", BlockPos::class)