diff --git a/build.gradle b/build.gradle index 4dc3203c..e25a3cb1 100644 --- a/build.gradle +++ b/build.gradle @@ -5,6 +5,13 @@ plugins { id 'net.minecraftforge.gradle' version '6.0.+' } +repositories { + maven { + name "Su5ed LegacyDev Fork" + url "https://maven.su5ed.dev/releases" + } +} + // eclipse thinks test needs resources if this is not here sourceSets { test { @@ -115,12 +122,28 @@ dependencies { runtimeOnly 'curse.maven:the-one-probe-245211:2667280' runtimeOnly 'curse.maven:ctm-267602:2915363' + constraints { + implementation('net.minecraftforge:legacydev:0.3.0.0-legacyExt') { + because 'needed to have all ATs work properly' + } + + implementation('org.ow2.asm:asm-debug-all:5.2') { + because 'newer ASM versions include module info that causes errors in Java 8' + } + } + configurations.forEach { // mergetool pollutes the classpath with conflicting classes it.exclude(group: 'net.minecraftforge', module: 'mergetool') - - // newer ASM versions include module info that causes errors in Java 8 - it.resolutionStrategy.force 'org.ow2.asm:asm-debug-all:5.2' + + // legacydev forge dep wants fatjar as the classifier, but 3.0 lacks it + it.resolutionStrategy.eachDependency { + if (it.requested.module.toString() == "net.minecraftforge:legacydev") { + it.artifactSelection { + it.selectArtifact(DependencyArtifact.DEFAULT_TYPE, null, null) + } + } + } } // if the curse maven is down or otherwise not working: diff --git a/gradle.properties b/gradle.properties index c9b3bb64..fcf1af30 100644 --- a/gradle.properties +++ b/gradle.properties @@ -2,8 +2,8 @@ # This is required to provide enough memory for the Minecraft decompilation process. org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false -version=2.1.12 -apiversion=2.1.12 +version=2.1.13 +apiversion=2.1.13 mcversion=1.12.2 forgeminversion=14.23.5.2816 forgeversion=14.23.5.2860 diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 7f93135c..c1962a79 100644 Binary files a/gradle/wrapper/gradle-wrapper.jar and b/gradle/wrapper/gradle-wrapper.jar differ diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 3fa8f862..509c4a29 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,7 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip networkTimeout=10000 -validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1aa94a42..aeb74cbb 100755 --- a/gradlew +++ b/gradlew @@ -83,8 +83,7 @@ done # This is normally unused # shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Use the maximum available, or set MAX_FD != -1 to use that value. MAX_FD=maximum @@ -131,13 +130,10 @@ location of your Java installation." fi else JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. Please set the JAVA_HOME variable in your environment to match the location of your Java installation." - fi fi # Increase the maximum file descriptors if we can. @@ -145,7 +141,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac @@ -153,7 +149,7 @@ if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then '' | soft) :;; #( *) # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -202,11 +198,11 @@ fi # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. set -- \ "-Dorg.gradle.appname=$APP_BASE_NAME" \ diff --git a/src/main/java/thecodex6824/thaumicaugmentation/common/internal/TAHooksCommon.java b/src/main/java/thecodex6824/thaumicaugmentation/common/internal/TAHooksCommon.java index 91fb76ab..b41878fb 100644 --- a/src/main/java/thecodex6824/thaumicaugmentation/common/internal/TAHooksCommon.java +++ b/src/main/java/thecodex6824/thaumicaugmentation/common/internal/TAHooksCommon.java @@ -73,231 +73,233 @@ public final class TAHooksCommon { private TAHooksCommon() {} - + private static boolean hasWard(World world, BlockPos pos) { - if (world != null && pos != null && world.getChunkProvider() != null && world.isBlockLoaded(pos)) { - Chunk chunk = world.getChunk(pos); - if (chunk != null) { - IWardStorage ward = chunk.getCapability(CapabilityWardStorage.WARD_STORAGE, null); - if (ward != null) - return ward.hasWard(pos); - } - } - - return false; + if (world != null && pos != null && world.getChunkProvider() != null && world.isBlockLoaded(pos)) { + Chunk chunk = world.getChunk(pos); + if (chunk != null) { + IWardStorage ward = chunk.getCapability(CapabilityWardStorage.WARD_STORAGE, null); + if (ward != null) + return ward.hasWard(pos); + } + } + + return false; } - + public static float checkWardHardness(float oldHardness, World world, BlockPos pos) { - return hasWard(world, pos) ? -1.0F : oldHardness; + return hasWard(world, pos) ? -1.0F : oldHardness; } - + public static float checkWardResistance(float oldResistance, World world, BlockPos pos) { - return hasWard(world, pos) ? 6000000.0F : oldResistance; + return hasWard(world, pos) ? 6000000.0F : oldResistance; } - - public static int checkWardFlammability(int oldFlammability, IBlockAccess access, BlockPos pos) { - if (oldFlammability == 0) - return 0; - else if (access instanceof World) - return hasWard((World) access, pos) ? 0 : oldFlammability; - else - return oldFlammability; + + public static boolean checkWardFlammability(IBlockAccess access, BlockPos pos) { + boolean flammableAllowed = true; + if (access instanceof World) { + flammableAllowed = !hasWard((World) access, pos); + } + + return flammableAllowed; + } + + public static int checkWardFlammability(int oldValue, World world, BlockPos pos) { + // this return will be bitwise anded with the original fire encouragement/flammability value + // the oldValue == 0 check is to skip the capability lookup if there is no point + return oldValue == 0 || hasWard(world, pos) ? 0 : oldValue; } - - public static int checkWardFireEncouragement(int oldEncouragement, IBlockAccess access, BlockPos pos) { - if (oldEncouragement == 0) - return 0; - else if (access instanceof World) - return hasWard((World) access, pos) ? 0 : oldEncouragement; - else - return oldEncouragement; + + public static int checkWardNeighborFireEncouragement(int oldValue, World world, BlockPos pos, EnumFacing facing) { + // same deal as above + return oldValue == 0 || hasWard(world, pos.offset(facing)) ? 0 : oldValue; } - + public static boolean checkWardRandomTick(WorldServer world, BlockPos pos, IBlockState state, Random rand) { - return !hasWard(world, pos); + return !hasWard(world, pos); } - + public static boolean checkWardGeneric(World world, BlockPos pos) { - return !hasWard(world, pos); + return !hasWard(world, pos); } @SuppressWarnings({"rawtypes", "unchecked"}) private static boolean isCompatibleSlab(World world, BlockPos pos, EnumFacing dir, ItemStack slab) { - IBlockState state = world.getBlockState(pos); - if (state.getPropertyKeys().contains(BlockSlab.HALF) && state.getBlock() instanceof BlockSlab) { - BlockSlab block = (BlockSlab) state.getBlock(); - Comparable item = block.getTypeForItem(slab); - if (dir == EnumFacing.UP && state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM || - dir == EnumFacing.DOWN && state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.TOP) { - - Object value = state.getValue(block.getVariantProperty()); - try { - return item.compareTo(value) == 0; - } - catch (ClassCastException ex) { - // if getTypeForItem and the variant property value have different types, this may happen - // ex: rustic slabs return int for getTypeForItem, but vanilla slabs use EnumBlockHalf - } - } - } - - return false; + IBlockState state = world.getBlockState(pos); + if (state.getPropertyKeys().contains(BlockSlab.HALF) && state.getBlock() instanceof BlockSlab) { + BlockSlab block = (BlockSlab) state.getBlock(); + Comparable item = block.getTypeForItem(slab); + if (dir == EnumFacing.UP && state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.BOTTOM || + dir == EnumFacing.DOWN && state.getValue(BlockSlab.HALF) == BlockSlab.EnumBlockHalf.TOP) { + + Object value = state.getValue(block.getVariantProperty()); + try { + return item.compareTo(value) == 0; + } + catch (ClassCastException ex) { + // if getTypeForItem and the variant property value have different types, this may happen + // ex: rustic slabs return int for getTypeForItem, but vanilla slabs use EnumBlockHalf + } + } + } + + return false; } public static boolean checkWardSlab(World world, BlockPos pos, EnumFacing placeDir, ItemStack stack) { - if (placeDir.getAxis() == EnumFacing.Axis.Y && isCompatibleSlab(world, pos, placeDir, stack)) - return !hasWard(world, pos) && !hasWard(world, pos.offset(placeDir)); - else - return !hasWard(world, pos.offset(placeDir)); + if (placeDir.getAxis() == EnumFacing.Axis.Y && isCompatibleSlab(world, pos, placeDir, stack)) + return !hasWard(world, pos) && !hasWard(world, pos.offset(placeDir)); + else + return !hasWard(world, pos.offset(placeDir)); } - + public static void checkElytra(ItemStack chestArmorStack, EntityPlayerMP player) { - IBaublesItemHandler baubles = player.getCapability(BaublesCapabilities.CAPABILITY_BAUBLES, null); - if (baubles != null) { - ItemStack stack = baubles.getStackInSlot(BaubleType.BODY.getValidSlots()[0]); - if (stack.getItem() instanceof IElytraCompat && ((IElytraCompat) stack.getItem()).allowElytraFlight(player, stack)) - player.setElytraFlying(); - } + IBaublesItemHandler baubles = player.getCapability(BaublesCapabilities.CAPABILITY_BAUBLES, null); + if (baubles != null) { + ItemStack stack = baubles.getStackInSlot(BaubleType.BODY.getValidSlots()[0]); + if (stack.getItem() instanceof IElytraCompat && ((IElytraCompat) stack.getItem()).allowElytraFlight(player, stack)) + player.setElytraFlying(); + } } - + public static boolean updateElytraFlag(EntityLivingBase entity, boolean flag) { - if (flag) - return true; - else if (entity instanceof EntityPlayer) { - EntityPlayer player = (EntityPlayer) entity; - IBaublesItemHandler baubles = player.getCapability(BaublesCapabilities.CAPABILITY_BAUBLES, null); - if (baubles != null) { - ItemStack stack = baubles.getStackInSlot(BaubleType.BODY.getValidSlots()[0]); - if (stack.getItem() instanceof IElytraCompat) - return ((IElytraCompat) stack.getItem()).allowElytraFlight(player, stack); - } - } - - return false; + if (flag) + return true; + else if (entity instanceof EntityPlayer) { + EntityPlayer player = (EntityPlayer) entity; + IBaublesItemHandler baubles = player.getCapability(BaublesCapabilities.CAPABILITY_BAUBLES, null); + if (baubles != null) { + ItemStack stack = baubles.getStackInSlot(BaubleType.BODY.getValidSlots()[0]); + if (stack.getItem() instanceof IElytraCompat) + return ((IElytraCompat) stack.getItem()).allowElytraFlight(player, stack); + } + } + + return false; } - + public static ItemStack getLeftoverInfusionIngredientStack(ItemStack input, Object output) { - if (output instanceof ItemStack && input.getItem() != ItemsTC.primordialPearl) { - if (((ItemStack) output).getItem() == TAItems.MORPHIC_TOOL) - return ItemStack.EMPTY; - else if (MorphicArmorHelper.hasMorphicArmor((ItemStack) output)) - return ItemStack.EMPTY; - } - - return input; + if (output instanceof ItemStack && input.getItem() != ItemsTC.primordialPearl) { + if (((ItemStack) output).getItem() == TAItems.MORPHIC_TOOL) + return ItemStack.EMPTY; + else if (MorphicArmorHelper.hasMorphicArmor((ItemStack) output)) + return ItemStack.EMPTY; + } + + return input; } - + public static void onBaubleChanged(@Nullable EntityLivingBase entity) { - if (entity != null && !entity.getEntityWorld().isRemote) { - AugmentEventHandler.onEquipmentChange(entity); - PacketBaubleChange pkt = new PacketBaubleChange(entity.getEntityId()); - TANetwork.INSTANCE.sendToAllTracking(pkt, entity); - if (entity instanceof EntityPlayerMP) - TANetwork.INSTANCE.sendTo(pkt, (EntityPlayerMP) entity); - } + if (entity != null && !entity.getEntityWorld().isRemote) { + AugmentEventHandler.onEquipmentChange(entity); + PacketBaubleChange pkt = new PacketBaubleChange(entity.getEntityId()); + TANetwork.INSTANCE.sendToAllTracking(pkt, entity); + if (entity instanceof EntityPlayerMP) + TANetwork.INSTANCE.sendTo(pkt, (EntityPlayerMP) entity); + } } - + public static boolean isInOuterLands(Entity entity) { - World world = entity.getEntityWorld(); - if (world != null && world.provider != null) { - EntityInOuterLandsEvent event = new EntityInOuterLandsEvent(entity); - MinecraftForge.EVENT_BUS.post(event); - return event.getResult() == Result.ALLOW || (event.getResult() == Result.DEFAULT && - world.provider.getDimension() == TADimensions.EMPTINESS.getId()); - } - - return false; + World world = entity.getEntityWorld(); + if (world != null && world.provider != null) { + EntityInOuterLandsEvent event = new EntityInOuterLandsEvent(entity); + MinecraftForge.EVENT_BUS.post(event); + return event.getResult() == Result.ALLOW || (event.getResult() == Result.DEFAULT && + world.provider.getDimension() == TADimensions.EMPTINESS.getId()); + } + + return false; } - + public static boolean shouldAllowRunicShield(ItemStack stack) { - return stack.hasCapability(BaublesCapabilities.CAPABILITY_ITEM_BAUBLE, null); + return stack.hasCapability(BaublesCapabilities.CAPABILITY_ITEM_BAUBLE, null); } - + public static RayTraceResult fireTrajectoryGetEntityEvent(RayTraceResult original, FocusMediumTouch touch, Trajectory trajectory, double range) { - if (original != null && original.entityHit != null) { - FocusTouchGetEntityEvent.Trajectory event = new FocusTouchGetEntityEvent.Trajectory(touch, trajectory, original, range); - MinecraftForge.EVENT_BUS.post(event); - if (!event.isCanceled()) - return event.getRay(); - else - return new RayTraceResult(null); - } - - return original; + if (original != null && original.entityHit != null) { + FocusTouchGetEntityEvent.Trajectory event = new FocusTouchGetEntityEvent.Trajectory(touch, trajectory, original, range); + MinecraftForge.EVENT_BUS.post(event); + if (!event.isCanceled()) + return event.getRay(); + else + return new RayTraceResult(null); + } + + return original; } - + public static RayTraceResult fireTargetGetEntityEvent(RayTraceResult original, FocusMediumTouch touch, Trajectory trajectory, double range) { - if (original != null && original.entityHit != null) { - FocusTouchGetEntityEvent.Target event = new FocusTouchGetEntityEvent.Target(touch, trajectory, original, range); - MinecraftForge.EVENT_BUS.post(event); - if (!event.isCanceled()) - return event.getRay(); - else - return new RayTraceResult(null); - } - - return original; + if (original != null && original.entityHit != null) { + FocusTouchGetEntityEvent.Target event = new FocusTouchGetEntityEvent.Target(touch, trajectory, original, range); + MinecraftForge.EVENT_BUS.post(event); + if (!event.isCanceled()) + return event.getRay(); + else + return new RayTraceResult(null); + } + + return original; } - + public static boolean fireFluxRiftDestroyBlockEvent(EntityFluxRift rift, BlockPos pos, IBlockState state) { - return MinecraftForge.EVENT_BUS.post(new FluxRiftDestroyBlockEvent(rift, pos, state)); + return MinecraftForge.EVENT_BUS.post(new FluxRiftDestroyBlockEvent(rift, pos, state)); } - + public static boolean onAttemptTeleport(EntityLivingBase entity, double origX, double origY, double origZ) { - if (!entity.getEntityWorld().isRemote) { - WorldServer w = (WorldServer) entity.getEntityWorld(); - BlockPos check = entity.getPosition(); - if (w.getChunkProvider().isInsideStructure(w, "EldritchSpire", check)) { - MapGenEldritchSpire.Start start = ((ChunkGeneratorEmptiness) w.getChunkProvider().chunkGenerator).getSpireStart(check); - if (start != null) { - IWardStorage storage = w.getChunk(check).getCapability(CapabilityWardStorage.WARD_STORAGE, null); - return !(storage instanceof IWardStorageServer && ((IWardStorageServer) storage).isWardOwner(start.getWard())); - } - } - } - - return true; + if (!entity.getEntityWorld().isRemote) { + WorldServer w = (WorldServer) entity.getEntityWorld(); + BlockPos check = entity.getPosition(); + if (w.getChunkProvider().isInsideStructure(w, "EldritchSpire", check)) { + MapGenEldritchSpire.Start start = ((ChunkGeneratorEmptiness) w.getChunkProvider().chunkGenerator).getSpireStart(check); + if (start != null) { + IWardStorage storage = w.getChunk(check).getCapability(CapabilityWardStorage.WARD_STORAGE, null); + return !(storage instanceof IWardStorageServer && ((IWardStorageServer) storage).isWardOwner(start.getWard())); + } + } + } + + return true; } public static boolean checkSweepingEdge(EntityPlayer player, ItemStack stack) { - return stack.getItem() == TAItems.PRIMAL_CUTTER; + return stack.getItem() == TAItems.PRIMAL_CUTTER; } private static int[] getValidMetadata(Item item) { - IntRBTreeSet visitedMeta = new IntRBTreeSet(); - for (CreativeTabs tab : item.getCreativeTabs()) { - NonNullList stacks = NonNullList.create(); - item.getSubItems(tab, stacks); - for (ItemStack stack : stacks) { - if (stack.getItem() == item) - visitedMeta.add(stack.getMetadata()); - } - } - - return visitedMeta.toIntArray(); + IntRBTreeSet visitedMeta = new IntRBTreeSet(); + for (CreativeTabs tab : item.getCreativeTabs()) { + NonNullList stacks = NonNullList.create(); + item.getSubItems(tab, stacks); + for (ItemStack stack : stacks) { + if (stack.getItem() == item) + visitedMeta.add(stack.getMetadata()); + } + } + + return visitedMeta.toIntArray(); } public static ItemStack cycleItemStack(ItemStack fallback, Object thing, int counter) { - if (thing instanceof ItemStack) { - ItemStack stack = (ItemStack) thing; - if (!stack.isEmpty() && stack.getHasSubtypes() && stack.getMetadata() == OreDictionary.WILDCARD_VALUE) { - int[] validMeta = getValidMetadata(stack.getItem()); - if (validMeta.length > 0) { - int timer = 5000 / validMeta.length; - int metaIndex = (int) ((counter + System.currentTimeMillis() / timer) % validMeta.length); - ItemStack copy = stack.copy(); - copy.setItemDamage(validMeta[metaIndex]); - return copy; - } - } - } - - return fallback; + if (thing instanceof ItemStack) { + ItemStack stack = (ItemStack) thing; + if (!stack.isEmpty() && stack.getHasSubtypes() && stack.getMetadata() == OreDictionary.WILDCARD_VALUE) { + int[] validMeta = getValidMetadata(stack.getItem()); + if (validMeta.length > 0) { + int timer = 5000 / validMeta.length; + int metaIndex = (int) ((counter + System.currentTimeMillis() / timer) % validMeta.length); + ItemStack copy = stack.copy(); + copy.setItemDamage(validMeta[metaIndex]); + return copy; + } + } + } + + return fallback; } public static boolean onAddTile(Chunk chunk, BlockPos pos, TileEntity tile) { - return !tile.hasCapability(CapabilityImpetusNode.IMPETUS_NODE, null) || - chunk.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK) != tile; + return !tile.hasCapability(CapabilityImpetusNode.IMPETUS_NODE, null) || + chunk.getTileEntity(pos, Chunk.EnumCreateEntityType.CHECK) != tile; } - + } diff --git a/src/main/java/thecodex6824/thaumicaugmentation/core/TATransformer.java b/src/main/java/thecodex6824/thaumicaugmentation/core/TATransformer.java index ae275c29..f68b8768 100644 --- a/src/main/java/thecodex6824/thaumicaugmentation/core/TATransformer.java +++ b/src/main/java/thecodex6824/thaumicaugmentation/core/TATransformer.java @@ -20,179 +20,218 @@ package thecodex6824.thaumicaugmentation.core; -import net.minecraft.launchwrapper.IClassTransformer; +import java.util.ArrayList; + import org.objectweb.asm.ClassReader; import org.objectweb.asm.ClassWriter; import org.objectweb.asm.tree.ClassNode; -import thecodex6824.thaumicaugmentation.core.transformer.*; -import java.util.ArrayList; +import net.minecraft.launchwrapper.IClassTransformer; +import thecodex6824.thaumicaugmentation.core.transformer.ITransformer; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerAttemptTeleport; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerBaubleSlotChanged; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerBipedRotationCustomTCArmor; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerBipedRotationVanilla; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerCycleItemStackMetadata; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerEldritchGuardianFog; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerElytraClientCheck; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerElytraServerCheck; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerFluxRiftDestroyBlock; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerInfusionLeftoverItems; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerRenderCape; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerRenderEntities; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerRunicShieldingAllowBaublesCap; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerSweepingEdgeCheck; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerTCBlueprintCrashFix; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerTCRobesElytraFlapping; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerThaumostaticHarnessSprintCheck; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerTouchTargetEntitySelection; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerTouchTrajectoryEntitySelection; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerUpdateElytra; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerVoidRobesArmorBarFix; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockCanCatchFire; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockFlammability; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockGrassPath; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockHardness; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockNeighborFireEncouragement; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockNoEndermanPickup; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockNoRabbitSnacking; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockNoSheepGrazing; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockNoVillagerFarming; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockRandomTick; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockResistance; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockSlabs; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWardBlockTaintImmunity; +import thecodex6824.thaumicaugmentation.core.transformer.TransformerWorldAddTile; public class TATransformer implements IClassTransformer { private static final ArrayList TRANSFORMERS = new ArrayList<>(); - + static { - // required as there is no generic hardness hook for calls outside of player breaking - TRANSFORMERS.add(new TransformerWardBlockHardness()); - // required as there is no generic resistance hook for calls outside of player breaking and explosions - TRANSFORMERS.add(new TransformerWardBlockResistance()); - // required to make fire not linger on warded blocks - TRANSFORMERS.add(new TransformerWardBlockFlammability()); - // required to make fire not make warded blocks catch on fire - TRANSFORMERS.add(new TransformerWardBlockFireEncouragement()); - // required to cancel random updates for warded blocks - // scheduled and neighbor updates are handled in event handlers - TRANSFORMERS.add(new TransformerWardBlockRandomTick()); - // required to prevent shoveling warded grass - TRANSFORMERS.add(new TransformerWardBlockGrassPath()); - // slabs are dumb and bypass all the checks when being placed on another slab - TRANSFORMERS.add(new TransformerWardBlockSlabs()); - - // required as EntityMobGriefingEvent does not provide a blockpos - // the position is also not determined and put into the AI fields until the event has already passed, so no reflection - TRANSFORMERS.add(new TransformerWardBlockNoEndermanPickup()); - // same - TRANSFORMERS.add(new TransformerWardBlockNoRabbitSnacking()); - // same - TRANSFORMERS.add(new TransformerWardBlockNoSheepGrazing()); - // same - TRANSFORMERS.add(new TransformerWardBlockNoVillagerFarming()); - // required because TC calls Block#getBlockHardness instead of the blockstate method - TRANSFORMERS.add(new TransformerWardBlockTaintImmunity()); - - // required to cancel sprinting client side immediately - // using events allows 1-tick sprints, and holding down sprint will allow constant sprinting - TRANSFORMERS.add(new TransformerThaumostaticHarnessSprintCheck()); - - // required to allow clients to recognize they are wearing elytra - TRANSFORMERS.add(new TransformerElytraClientCheck()); - // required to allow the server to recognize players are wearing elytra - TRANSFORMERS.add(new TransformerElytraServerCheck()); - // required to maintain the elytra flying flag for custom elytra - TRANSFORMERS.add(new TransformerUpdateElytra()); - - // required to have custom arm rotations for things like the impulse cannon - TRANSFORMERS.add(new TransformerBipedRotationVanilla()); - // required to make any ModelBiped transformers work on TC armor at all - TRANSFORMERS.add(new TransformerBipedRotationCustomTCArmor()); - // fixes annoying robe legging flapping (as if the player is walking) while elytra flying - TRANSFORMERS.add(new TransformerTCRobesElytraFlapping()); - // required to hook render pass 0 for batch rendering of TEs with shaders - // RenderWorldLastEvent almost works but it is after render pass 0, so it will draw over transparent blocks - TRANSFORMERS.add(new TransformerRenderEntities()); - - // required to fix morphic tool recipe dupe while also allowing container items to be used - // backup non-coremod mitigation disables container items, which players expressed a desire to keep - TRANSFORMERS.add(new TransformerInfusionLeftoverItems()); - - // required to have augments on baubles detected properly without having to loop over them all every tick - // performance with the looping method is terrible, and a change event should really have been added... - TRANSFORMERS.add(new TransformerBaubleSlotChanged()); - - // required because TC always creates fog near eldritch guardians if not in the outer lands - // but since the outer lands don't exist they always do it - // even if it did exist its hardcodedness is problematic - TRANSFORMERS.add(new TransformerEldritchGuardianFog()); - - // required because any attempt by TC to render a tile entity in a blueprint that is - // an AnimationTESR will crash the game - TRANSFORMERS.add(new TransformerTCBlueprintCrashFix()); - - // fixes armor counting twice visually for void robe armor - // I get a lot of reports/questions about it, so here it is - TRANSFORMERS.add(new TransformerVoidRobesArmorBarFix()); - - // makes runic shielding infusion work on items with baubles capability - // TC only checks for the interface on the item... - TRANSFORMERS.add(new TransformerRunicShieldingAllowBaublesCap()); - - // allow disabling cape render when wearing custom elytra - // the special render event from forge seems to be unimplemented? - TRANSFORMERS.add(new TransformerRenderCape()); - - // allow bolts to ignore certain entities (for void shield) - // also the trajectory and target code is pretty much copy pasted with a different return value - // so 2 transformers are required - TRANSFORMERS.add(new TransformerTouchTrajectoryEntitySelection()); - TRANSFORMERS.add(new TransformerTouchTargetEntitySelection()); - - // to fire an event when a flux rift tries to eat a block - // used for rift jar detection - TRANSFORMERS.add(new TransformerFluxRiftDestroyBlock()); - - // to prevent chorus fruit and such from breaking into spires - TRANSFORMERS.add(new TransformerAttemptTeleport()); - - // to allow non-sword items to have sweeping edge (primal cutter) - TRANSFORMERS.add(new TransformerSweepingEdgeCheck()); - - // to allow wildcard metadata in required research items when they are non-damageable - TRANSFORMERS.add(new TransformerCycleItemStackMetadata()); - - // to fix the forge bug that calls invalidate on tiles if they are loaded while tiles are being processed - TRANSFORMERS.add(new TransformerWorldAddTile()); + // required as there is no generic hardness hook for calls outside of player breaking + TRANSFORMERS.add(new TransformerWardBlockHardness()); + // required as there is no generic resistance hook for calls outside of player breaking and explosions + TRANSFORMERS.add(new TransformerWardBlockResistance()); + // required to make fire not linger on warded blocks + TRANSFORMERS.add(new TransformerWardBlockCanCatchFire()); + // required to make fire not make warded blocks catch on fire + TRANSFORMERS.add(new TransformerWardBlockNeighborFireEncouragement()); + // required to make fire not consume warded blocks if they happen to be next to a flammable block + TRANSFORMERS.add(new TransformerWardBlockFlammability()); + // required to cancel random updates for warded blocks + // scheduled and neighbor updates are handled in event handlers + TRANSFORMERS.add(new TransformerWardBlockRandomTick()); + // required to prevent shoveling warded grass + TRANSFORMERS.add(new TransformerWardBlockGrassPath()); + // slabs are dumb and bypass all the checks when being placed on another slab + TRANSFORMERS.add(new TransformerWardBlockSlabs()); + + // required as EntityMobGriefingEvent does not provide a blockpos + // the position is also not determined and put into the AI fields until the event has already passed, so no reflection + TRANSFORMERS.add(new TransformerWardBlockNoEndermanPickup()); + // same + TRANSFORMERS.add(new TransformerWardBlockNoRabbitSnacking()); + // same + TRANSFORMERS.add(new TransformerWardBlockNoSheepGrazing()); + // same + TRANSFORMERS.add(new TransformerWardBlockNoVillagerFarming()); + // required because TC calls Block#getBlockHardness instead of the blockstate method + TRANSFORMERS.add(new TransformerWardBlockTaintImmunity()); + + // required to cancel sprinting client side immediately + // using events allows 1-tick sprints, and holding down sprint will allow constant sprinting + TRANSFORMERS.add(new TransformerThaumostaticHarnessSprintCheck()); + + // required to allow clients to recognize they are wearing elytra + TRANSFORMERS.add(new TransformerElytraClientCheck()); + // required to allow the server to recognize players are wearing elytra + TRANSFORMERS.add(new TransformerElytraServerCheck()); + // required to maintain the elytra flying flag for custom elytra + TRANSFORMERS.add(new TransformerUpdateElytra()); + + // required to have custom arm rotations for things like the impulse cannon + TRANSFORMERS.add(new TransformerBipedRotationVanilla()); + // required to make any ModelBiped transformers work on TC armor at all + TRANSFORMERS.add(new TransformerBipedRotationCustomTCArmor()); + // fixes annoying robe legging flapping (as if the player is walking) while elytra flying + TRANSFORMERS.add(new TransformerTCRobesElytraFlapping()); + // required to hook render pass 0 for batch rendering of TEs with shaders + // RenderWorldLastEvent almost works but it is after render pass 0, so it will draw over transparent blocks + TRANSFORMERS.add(new TransformerRenderEntities()); + + // required to fix morphic tool recipe dupe while also allowing container items to be used + // backup non-coremod mitigation disables container items, which players expressed a desire to keep + TRANSFORMERS.add(new TransformerInfusionLeftoverItems()); + + // required to have augments on baubles detected properly without having to loop over them all every tick + // performance with the looping method is terrible, and a change event should really have been added... + TRANSFORMERS.add(new TransformerBaubleSlotChanged()); + + // required because TC always creates fog near eldritch guardians if not in the outer lands + // but since the outer lands don't exist they always do it + // even if it did exist its hardcodedness is problematic + TRANSFORMERS.add(new TransformerEldritchGuardianFog()); + + // required because any attempt by TC to render a tile entity in a blueprint that is + // an AnimationTESR will crash the game + TRANSFORMERS.add(new TransformerTCBlueprintCrashFix()); + + // fixes armor counting twice visually for void robe armor + // I get a lot of reports/questions about it, so here it is + TRANSFORMERS.add(new TransformerVoidRobesArmorBarFix()); + + // makes runic shielding infusion work on items with baubles capability + // TC only checks for the interface on the item... + TRANSFORMERS.add(new TransformerRunicShieldingAllowBaublesCap()); + + // allow disabling cape render when wearing custom elytra + // the special render event from forge seems to be unimplemented? + TRANSFORMERS.add(new TransformerRenderCape()); + + // allow bolts to ignore certain entities (for void shield) + // also the trajectory and target code is pretty much copy pasted with a different return value + // so 2 transformers are required + TRANSFORMERS.add(new TransformerTouchTrajectoryEntitySelection()); + TRANSFORMERS.add(new TransformerTouchTargetEntitySelection()); + + // to fire an event when a flux rift tries to eat a block + // used for rift jar detection + TRANSFORMERS.add(new TransformerFluxRiftDestroyBlock()); + + // to prevent chorus fruit and such from breaking into spires + TRANSFORMERS.add(new TransformerAttemptTeleport()); + + // to allow non-sword items to have sweeping edge (primal cutter) + TRANSFORMERS.add(new TransformerSweepingEdgeCheck()); + + // to allow wildcard metadata in required research items when they are non-damageable + TRANSFORMERS.add(new TransformerCycleItemStackMetadata()); + + // to fix the forge bug that calls invalidate on tiles if they are loaded while tiles are being processed + TRANSFORMERS.add(new TransformerWorldAddTile()); } - + public TATransformer() {} - + private boolean isTransformNeeded(String transformedName) { - if (!ThaumicAugmentationCore.isEnabled()) - return false; - - for (ITransformer t : TRANSFORMERS) { - if (t.isTransformationNeeded(transformedName)) - return true; - } - - return false; + if (!ThaumicAugmentationCore.isEnabled()) + return false; + + for (ITransformer t : TRANSFORMERS) { + if (t.isTransformationNeeded(transformedName)) + return true; + } + + return false; } - + @Override public byte[] transform(String name, String transformedName, byte[] basicClass) { - if (isTransformNeeded(transformedName)) { - ClassNode node = new ClassNode(); - ClassReader reader = new ClassReader(basicClass); - reader.accept(node, 0); - - boolean didSomething = false; - boolean computeFrames = false; - for (ITransformer transformer : TRANSFORMERS) { - if (transformer.isTransformationNeeded(transformedName)) { - if (ThaumicAugmentationCore.getExcludedTransformers().contains(transformer.getClass().getName())) - ThaumicAugmentationCore.getLogger().info("Excluding transformer {} due to config request", transformer.getClass().getName()); - else if (!transformer.transform(node, name, transformedName)) { - ThaumicAugmentationCore.getLogger().error("A class transformer has failed! This is probably very bad..."); - ThaumicAugmentationCore.getLogger().error("Class: " + transformedName + ", Transformer: " + transformer.getClass()); - if (transformer.getRaisedException() != null) { - ThaumicAugmentationCore.getLogger().error("Additional information: ", transformer.getRaisedException()); - if (!transformer.isAllowedToFail()) - throw transformer.getRaisedException(); - } - else if (!transformer.isAllowedToFail()) - throw new RuntimeException(); - } - else { - didSomething = true; - computeFrames |= transformer.needToComputeFrames(); - } - } - } - - if (didSomething) { - ClassWriter writer = !computeFrames ? new ClassWriter(ClassWriter.COMPUTE_MAXS) : new ClassWriter(ClassWriter.COMPUTE_FRAMES) { - @Override - protected String getCommonSuperClass(String type1, String type2) { - return "java/lang/Object"; - } - }; - node.accept(writer); - ThaumicAugmentationCore.getLogger().info("Successfully transformed class " + transformedName); - return writer.toByteArray(); - } - } - - return basicClass; + if (isTransformNeeded(transformedName)) { + ClassNode node = new ClassNode(); + ClassReader reader = new ClassReader(basicClass); + reader.accept(node, 0); + + boolean didSomething = false; + boolean computeFrames = false; + for (ITransformer transformer : TRANSFORMERS) { + if (transformer.isTransformationNeeded(transformedName)) { + if (ThaumicAugmentationCore.getExcludedTransformers().contains(transformer.getClass().getName())) + ThaumicAugmentationCore.getLogger().info("Excluding transformer {} due to config request", transformer.getClass().getName()); + else if (!transformer.transform(node, name, transformedName)) { + ThaumicAugmentationCore.getLogger().error("A class transformer has failed! This is probably very bad..."); + ThaumicAugmentationCore.getLogger().error("Class: " + transformedName + ", Transformer: " + transformer.getClass()); + if (transformer.getRaisedException() != null) { + ThaumicAugmentationCore.getLogger().error("Additional information: ", transformer.getRaisedException()); + if (!transformer.isAllowedToFail()) + throw transformer.getRaisedException(); + } + else if (!transformer.isAllowedToFail()) + throw new RuntimeException(); + } + else { + didSomething = true; + computeFrames |= transformer.needToComputeFrames(); + } + } + } + + if (didSomething) { + ClassWriter writer = !computeFrames ? new ClassWriter(ClassWriter.COMPUTE_MAXS) : new ClassWriter(ClassWriter.COMPUTE_FRAMES) { + @Override + protected String getCommonSuperClass(String type1, String type2) { + return "java/lang/Object"; + } + }; + + node.accept(writer); + ThaumicAugmentationCore.getLogger().info("Successfully transformed class " + transformedName); + return writer.toByteArray(); + } + } + + return basicClass; } - + } diff --git a/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFireEncouragement.java b/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockCanCatchFire.java similarity index 71% rename from src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFireEncouragement.java rename to src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockCanCatchFire.java index df53a047..5a71109d 100644 --- a/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFireEncouragement.java +++ b/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockCanCatchFire.java @@ -21,17 +21,18 @@ package thecodex6824.thaumicaugmentation.core.transformer; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; import thecodex6824.thaumicaugmentation.core.ThaumicAugmentationCore; -public class TransformerWardBlockFireEncouragement extends Transformer { +public class TransformerWardBlockCanCatchFire extends Transformer { - private static final String CLASS = "net.minecraft.block.Block"; + private static final String CLASS = "net.minecraft.block.BlockFire"; @Override public boolean needToComputeFrames() { @@ -52,26 +53,30 @@ public boolean isAllowedToFail() { @Override public boolean transform(ClassNode classNode, String name, String transformedName) { try { - MethodNode fire = TransformUtil.findMethod(classNode, "getFireSpreadSpeed", - "(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)I"); + MethodNode fire = TransformUtil.findMethod(classNode, "canCatchFire", + "(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)Z"); boolean found = false; int ret = 0; while ((ret = TransformUtil.findFirstInstanceOfOpcode(fire, ret, Opcodes.IRETURN)) != -1) { - AbstractInsnNode insertAfter = fire.instructions.get(ret).getPrevious(); - fire.instructions.insert(insertAfter, new MethodInsnNode(Opcodes.INVOKESTATIC, + InsnList toInsert = new InsnList(); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1)); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 2)); + toInsert.add(new MethodInsnNode(Opcodes.INVOKESTATIC, TransformUtil.HOOKS_COMMON, - "checkWardFireEncouragement", - "(ILnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;)I", + "checkWardFlammability", + "(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;)Z", false )); - fire.instructions.insert(insertAfter, new VarInsnNode(Opcodes.ALOAD, 2)); - fire.instructions.insert(insertAfter, new VarInsnNode(Opcodes.ALOAD, 1)); - ret += 4; - found = true; + toInsert.add(new InsnNode(Opcodes.IAND)); + + fire.instructions.insert(fire.instructions.get(ret).getPrevious(), toInsert); + ret += 5; + found = true; + } + + if (!found) { + throw new TransformerException("Could not locate required instructions"); } - - if (!found) - throw new TransformerException("Could not locate required instructions"); return true; } diff --git a/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFlammability.java b/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFlammability.java index a8541459..1185d437 100644 --- a/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFlammability.java +++ b/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockFlammability.java @@ -21,8 +21,9 @@ package thecodex6824.thaumicaugmentation.core.transformer; import org.objectweb.asm.Opcodes; -import org.objectweb.asm.tree.AbstractInsnNode; import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; import org.objectweb.asm.tree.MethodInsnNode; import org.objectweb.asm.tree.MethodNode; import org.objectweb.asm.tree.VarInsnNode; @@ -31,54 +32,64 @@ public class TransformerWardBlockFlammability extends Transformer { - private static final String CLASS = "net.minecraft.block.Block"; - + private static final String CLASS = "net.minecraft.block.BlockFire"; + @Override public boolean needToComputeFrames() { - return false; + return false; } - + @Override public boolean isTransformationNeeded(String transformedName) { - return !ThaumicAugmentationCore.getConfig().getBoolean("DisableWardFocus", "gameplay.ward", false, "") && - transformedName.equals(CLASS); + return !ThaumicAugmentationCore.getConfig().getBoolean("DisableWardFocus", "gameplay.ward", false, "") && + transformedName.equals(CLASS); } - + @Override public boolean isAllowedToFail() { - return false; + return false; } - + @Override public boolean transform(ClassNode classNode, String name, String transformedName) { - try { - MethodNode fire = TransformUtil.findMethod(classNode, "getFlammability", - "(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)I"); - boolean found = false; - int ret = 0; - while ((ret = TransformUtil.findFirstInstanceOfOpcode(fire, ret, Opcodes.IRETURN)) != -1) { - AbstractInsnNode insertAfter = fire.instructions.get(ret).getPrevious(); - fire.instructions.insert(insertAfter, new MethodInsnNode(Opcodes.INVOKESTATIC, - TransformUtil.HOOKS_COMMON, - "checkWardFlammability", - "(ILnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;)I", - false - )); - fire.instructions.insert(insertAfter, new VarInsnNode(Opcodes.ALOAD, 2)); - fire.instructions.insert(insertAfter, new VarInsnNode(Opcodes.ALOAD, 1)); - ret += 4; - found = true; - } - - if (!found) - throw new TransformerException("Could not locate required instructions"); - - return true; - } - catch (Throwable anything) { - error = new RuntimeException(anything); - return false; - } + try { + MethodNode fire = TransformUtil.findMethod( + classNode, + "tryCatchFire", + "(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;ILjava/util/Random;ILnet/minecraft/util/EnumFacing;)V" + ); + + int ret = 0; + if ((ret = TransformUtil.findFirstInstanceOfMethodCall( + fire, + ret, + "getFlammability", + "(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)I", + "net/minecraft/block/Block" + ) + ) != -1) { + InsnList toInsert = new InsnList(); + toInsert.add(new InsnNode(Opcodes.DUP)); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1)); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 2)); + toInsert.add(new MethodInsnNode(Opcodes.INVOKESTATIC, + TransformUtil.HOOKS_COMMON, + "checkWardFlammability", + "(ILnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;)I", + false + )); + toInsert.add(new InsnNode(Opcodes.IAND)); + + fire.instructions.insert(fire.instructions.get(ret), toInsert); + return true; + } + + throw new TransformerException("Could not locate required instructions"); + } + catch (Throwable anything) { + error = new RuntimeException(anything); + return false; + } } - + } diff --git a/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockNeighborFireEncouragement.java b/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockNeighborFireEncouragement.java new file mode 100644 index 00000000..b11452d1 --- /dev/null +++ b/src/main/java/thecodex6824/thaumicaugmentation/core/transformer/TransformerWardBlockNeighborFireEncouragement.java @@ -0,0 +1,108 @@ +/** + * Thaumic Augmentation + * Copyright (c) 2019 TheCodex6824. + * + * This file is part of Thaumic Augmentation. + * + * Thaumic Augmentation is free software: you can redistribute it and/or modify + * it under the terms of the GNU Lesser General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * Thaumic Augmentation is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public License + * along with Thaumic Augmentation. If not, see . + */ + +package thecodex6824.thaumicaugmentation.core.transformer; + +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.Type; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.InsnList; +import org.objectweb.asm.tree.InsnNode; +import org.objectweb.asm.tree.MethodInsnNode; +import org.objectweb.asm.tree.MethodNode; +import org.objectweb.asm.tree.VarInsnNode; + +import thecodex6824.thaumicaugmentation.core.ThaumicAugmentationCore; + +public class TransformerWardBlockNeighborFireEncouragement extends Transformer { + + private static final String CLASS = "net.minecraft.block.BlockFire"; + + @Override + public boolean needToComputeFrames() { + return false; + } + + @Override + public boolean isTransformationNeeded(String transformedName) { + return !ThaumicAugmentationCore.getConfig().getBoolean("DisableWardFocus", "gameplay.ward", false, "") && + transformedName.equals(CLASS); + } + + @Override + public boolean isAllowedToFail() { + return false; + } + + @Override + public boolean transform(ClassNode classNode, String name, String transformedName) { + try { + MethodNode fire = TransformUtil.findMethod( + classNode, + TransformUtil.remapMethodName( + "net/minecraft/block/BlockFire", + "func_176538_m", + Type.INT_TYPE, + Type.getType("Lnet/minecraft/world/World;"), Type.getType("Lnet/minecraft/util/math/BlockPos;") + ), + "(Lnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;)I" + ); + + boolean found = false; + int ret = 0; + while ((ret = TransformUtil.findFirstInstanceOfMethodCall( + fire, + ret, + "getFireSpreadSpeed", + "(Lnet/minecraft/world/IBlockAccess;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)I", + "net/minecraft/block/Block" + ) + ) != -1) { + InsnList toInsert = new InsnList(); + toInsert.add(new InsnNode(Opcodes.DUP)); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 1)); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 2)); + toInsert.add(new VarInsnNode(Opcodes.ALOAD, 7)); + toInsert.add(new MethodInsnNode(Opcodes.INVOKESTATIC, + TransformUtil.HOOKS_COMMON, + "checkWardNeighborFireEncouragement", + "(ILnet/minecraft/world/World;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/EnumFacing;)I", + false + )); + toInsert.add(new InsnNode(Opcodes.IAND)); + + fire.instructions.insert(fire.instructions.get(ret), toInsert); + ret += 7; + found = true; + } + + if (!found) { + throw new TransformerException("Could not locate required instructions"); + } + + return true; + } + catch (Throwable anything) { + error = new RuntimeException(anything); + return false; + } + } + +}