From 36923cece7526680c568d415f0c4fb9ae3571c9d Mon Sep 17 00:00:00 2001 From: covers1624 Date: Sun, 21 Jan 2024 02:27:17 +1030 Subject: [PATCH] Update to new MixinCompiler version. Notable changes: - MixinCompiler now lets us reference trait classes from the game class loader. - MixinCompiler no longer force defines our modified classes onto the game class loader. It defines them on its own class loader, along with our extension classes. - All traits + markers and Passthrough Interfaces are now registered with `RegisterMultipartTraitsEvent`. - Java traits can now properly override the parent constructor, and aren't forced to no-arg ctors. - Substantial architectural improvements to MixinCompiler. --- build.gradle | 7 +- build.properties | 4 +- .../codechicken/multipart/CBMultipart.java | 23 +++- .../api/RegisterMultipartTraitsEvent.java | 85 +++++++++++++++ .../api/annotation/MultiPartMarker.java | 11 -- .../api/annotation/MultiPartTrait.java | 39 ------- .../api/annotation/package-info.java | 9 -- .../multipart/api/part/AnimateTickPart.java | 3 - .../api/part/CapabilityProviderPart.java | 4 - .../api/part/NeighborTileChangePart.java | 3 - .../api/part/PartialOcclusionPart.java | 3 - .../multipart/api/part/SlottedPart.java | 4 - .../multipart/api/part/TickablePart.java | 4 - .../api/part/redstone/RedstonePart.java | 3 - .../multipart/block/TileMultipart.java | 6 - .../multipart/trait/TAnimateTickTile.java | 9 +- .../multipart/trait/TCapabilityTile.java | 8 +- .../multipart/trait/TInventoryTile.java | 9 +- .../trait/TPartialOcclusionTile.java | 8 +- .../multipart/trait/TRedstoneTile.java | 8 +- .../multipart/trait/TSlottedTile.java | 8 +- .../multipart/trait/TTickableTile.java | 8 +- .../multipart/trait/TTileChangeTile.java | 10 +- .../multipart/trait/TileMultipartClient.java | 5 + .../multipart/util/ForgeMixinBackend.java | 59 ++++++++++ .../multipart/util/MultipartGenerator.java | 103 +++++++++--------- 26 files changed, 276 insertions(+), 167 deletions(-) create mode 100644 src/main/java/codechicken/multipart/api/RegisterMultipartTraitsEvent.java delete mode 100644 src/main/java/codechicken/multipart/api/annotation/MultiPartMarker.java delete mode 100644 src/main/java/codechicken/multipart/api/annotation/MultiPartTrait.java delete mode 100644 src/main/java/codechicken/multipart/api/annotation/package-info.java create mode 100644 src/main/java/codechicken/multipart/util/ForgeMixinBackend.java diff --git a/build.gradle b/build.gradle index f2a76be..c5bec8d 100644 --- a/build.gradle +++ b/build.gradle @@ -87,11 +87,8 @@ dependencies { // compileOnly fg.deobf("mezz.jei:jei-${config.mc_version}:${config.jei_version}") //Packed into built jar. - shadow("codechicken:TraitMixinCompiler:${config.mixin_version}") { transitive = false } - shadow("codechicken:TraitMixinCompiler-forge:${config.mixin_version}") { transitive = false } - shadow("codechicken:TraitMixinCompiler-scala:${config.mixin_version}") { transitive = false } - shadow("codechicken:ChickenASM:${config.chicken_asm_version}") { transitive = false } - shadow("codechicken:ChickenASM-modlauncher:${config.chicken_asm_version}") { transitive = false } + shadow("io.codechicken:TraitMixinCompiler:${config.mixin_version}") { transitive = false } + shadow("io.codechicken:ChickenASM:${config.chicken_asm_version}") { transitive = false } testImplementation 'org.junit.jupiter:junit-jupiter-api:5.0.0' } diff --git a/build.properties b/build.properties index 324badb..d8a6a7f 100644 --- a/build.properties +++ b/build.properties @@ -5,6 +5,6 @@ mod_version=3.3.0 ccl_version=4.3.2.+ ccl_version_max=5.0.0 -mixin_version=2.0.0.20 -chicken_asm_version=3.1.0.15 +mixin_version=3.0.0.21 +chicken_asm_version=4.0.0.18 #jei_version=7.6.1.+ diff --git a/src/main/java/codechicken/multipart/CBMultipart.java b/src/main/java/codechicken/multipart/CBMultipart.java index 370eb7e..3ca3413 100644 --- a/src/main/java/codechicken/multipart/CBMultipart.java +++ b/src/main/java/codechicken/multipart/CBMultipart.java @@ -1,18 +1,25 @@ package codechicken.multipart; import codechicken.lib.world.TileChunkLoadHook; +import codechicken.multipart.api.RegisterMultipartTraitsEvent; +import codechicken.multipart.api.part.*; +import codechicken.multipart.api.part.redstone.RedstonePart; import codechicken.multipart.handler.PlacementConversionHandler; import codechicken.multipart.init.CBMultipartModContent; import codechicken.multipart.init.ClientInit; import codechicken.multipart.init.DataGenerators; import codechicken.multipart.init.MultiPartRegistries; import codechicken.multipart.network.MultiPartNetwork; +import codechicken.multipart.trait.*; import codechicken.multipart.util.MultipartGenerator; import codechicken.multipart.util.MultipartLoadHandler; import codechicken.multipart.util.TickScheduler; +import net.minecraft.world.Container; +import net.minecraft.world.WorldlyContainer; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.fml.DistExecutor; import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import static codechicken.multipart.CBMultipart.MOD_ID; @@ -31,11 +38,25 @@ public CBMultipart() { DistExecutor.unsafeRunWhenOn(Dist.CLIENT, () -> ClientInit::init); - MultipartGenerator.INSTANCE.loadAnnotations(); + MultipartGenerator.INSTANCE.load(); MultipartLoadHandler.init(); MultiPartNetwork.init(); PlacementConversionHandler.init(); TickScheduler.init(); TileChunkLoadHook.init(); + + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onRegisterMultipartTraits); + } + + private void onRegisterMultipartTraits(RegisterMultipartTraitsEvent event) { + event.registerClientTrait(AnimateTickPart.class, TAnimateTickTile.class); + event.registerTrait(CapabilityProviderPart.class, TCapabilityTile.class); + event.registerTrait(Container.class, TInventoryTile.class); + event.registerTrait(WorldlyContainer.class, TInventoryTile.class); + event.registerTrait(PartialOcclusionPart.class, TPartialOcclusionTile.class); + event.registerTrait(RedstonePart.class, TRedstoneTile.class); + event.registerTrait(SlottedPart.class, TSlottedTile.class); + event.registerTrait(TickablePart.class, TTickableTile.class); + event.registerServerTrait(NeighborTileChangePart.class, TTileChangeTile.class); } } diff --git a/src/main/java/codechicken/multipart/api/RegisterMultipartTraitsEvent.java b/src/main/java/codechicken/multipart/api/RegisterMultipartTraitsEvent.java new file mode 100644 index 0000000..cbc907b --- /dev/null +++ b/src/main/java/codechicken/multipart/api/RegisterMultipartTraitsEvent.java @@ -0,0 +1,85 @@ +package codechicken.multipart.api; + +import codechicken.multipart.api.part.MultiPart; +import codechicken.multipart.block.TileMultipart; +import codechicken.multipart.util.MultipartGenerator; +import net.minecraftforge.eventbus.api.Event; +import net.minecraftforge.fml.event.IModBusEvent; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; + +/** + * Fired on the mod bus for mods to register their traits and passthrough interfaces + * for {@link TileMultipart} classes. + *

+ * This is fired at the end of mod loading, from {@link FMLLoadCompleteEvent}. + *

+ * Created by covers1624 on 20/1/24. + */ +public final class RegisterMultipartTraitsEvent extends Event implements IModBusEvent { + + private final MultipartGenerator generator; + + public RegisterMultipartTraitsEvent(MultipartGenerator generator) { + this.generator = generator; + } + + /** + * Register {@code trait} to be mixed into the {@link TileMultipart} when + * {@code marker} is found implemented on a {@link MultiPart} instance. + * + * @param marker The part marker class. + * @param trait The trait to implement. + */ + public void registerTrait(Class marker, Class trait) { + generator.registerTrait(marker, trait); + } + + /** + * The same as {@link #registerTrait(Class, Class)} however, only effective client side. + * + * @param marker The part marker class. + * @param trait The trait to implement. + */ + public void registerClientTrait(Class marker, Class trait) { + generator.registerTrait(marker, trait, null); + } + + /** + * The same as {@link #registerTrait(Class, Class)} however, only effective server side (including integrated server). + * + * @param marker The part marker class. + * @param trait The trait to implement. + */ + public void registerServerTrait(Class marker, Class trait) { + generator.registerTrait(marker, null, trait); + } + + /** + * Register the specified class, when found on a {@link MultiPart} instance:
+ * - Implemented the interface on the {@link TileMultipart} instance with all methods proxied through to your part.
+ * - Only allow one instance of a part with this interface in the block space. + * + * @param iFace The interface to register. + */ + public void registerPassthroughInterface(Class iFace) { + generator.registerPassThroughInterface(iFace); + } + + /** + * The same as {@link #registerPassthroughInterface(Class)} however, only effective client side. + * + * @param iFace The interface to register. + */ + public void registerClientPassthroughInterface(Class iFace) { + generator.registerPassThroughInterface(iFace, true, false); + } + + /** + * The same as {@link #registerPassthroughInterface(Class)} however, only effective server side (including integrated server). + * + * @param iFace The interface to register. + */ + public void registerServerPassthroughInterface(Class iFace) { + generator.registerPassThroughInterface(iFace, false, true); + } +} diff --git a/src/main/java/codechicken/multipart/api/annotation/MultiPartMarker.java b/src/main/java/codechicken/multipart/api/annotation/MultiPartMarker.java deleted file mode 100644 index fd9f013..0000000 --- a/src/main/java/codechicken/multipart/api/annotation/MultiPartMarker.java +++ /dev/null @@ -1,11 +0,0 @@ -package codechicken.multipart.api.annotation; - -/** - * Source level marker interface for trait navigation. - *

- * Created by covers1624 on 21/10/20. - */ -public @interface MultiPartMarker { - - Class value(); -} diff --git a/src/main/java/codechicken/multipart/api/annotation/MultiPartTrait.java b/src/main/java/codechicken/multipart/api/annotation/MultiPartTrait.java deleted file mode 100644 index 8aceb3b..0000000 --- a/src/main/java/codechicken/multipart/api/annotation/MultiPartTrait.java +++ /dev/null @@ -1,39 +0,0 @@ -package codechicken.multipart.api.annotation; - -import codechicken.mixin.forge.TraitSide; - -import java.lang.annotation.*; - -/** - * A trait! - * Specifies that for the given target, the annotated class should be applied to said target - * when the specified marker exists. where the MixinCompiler searches for the marker - * is up to the target to decide and should be documented there. - * - * Created by covers1624 on 2/1/20. - */ -@Target (ElementType.TYPE) -@Retention (RetentionPolicy.RUNTIME) -@Repeatable (MultiPartTrait.TraitList.class) -public @interface MultiPartTrait { - - /** - * The marker for the Trait. - */ - Class value(); - - /** - * The side for the Trait. - */ - TraitSide side() default TraitSide.COMMON; - - /** - * Created by covers1624 on 4/13/20. - */ - @Target (ElementType.TYPE) - @Retention (RetentionPolicy.RUNTIME) - @interface TraitList { - - MultiPartTrait[] value(); - } -} diff --git a/src/main/java/codechicken/multipart/api/annotation/package-info.java b/src/main/java/codechicken/multipart/api/annotation/package-info.java deleted file mode 100644 index 29fe84c..0000000 --- a/src/main/java/codechicken/multipart/api/annotation/package-info.java +++ /dev/null @@ -1,9 +0,0 @@ -@FieldsAreNonnullByDefault -@MethodsReturnNonnullByDefault -@ParametersAreNonnullByDefault -package codechicken.multipart.api.annotation; - -import net.covers1624.quack.annotation.FieldsAreNonnullByDefault; -import net.covers1624.quack.annotation.MethodsReturnNonnullByDefault; - -import javax.annotation.ParametersAreNonnullByDefault; diff --git a/src/main/java/codechicken/multipart/api/part/AnimateTickPart.java b/src/main/java/codechicken/multipart/api/part/AnimateTickPart.java index 0d74c5d..8ce9934 100644 --- a/src/main/java/codechicken/multipart/api/part/AnimateTickPart.java +++ b/src/main/java/codechicken/multipart/api/part/AnimateTickPart.java @@ -1,7 +1,5 @@ package codechicken.multipart.api.part; -import codechicken.multipart.api.annotation.MultiPartMarker; -import codechicken.multipart.trait.TAnimateTickTile; import net.minecraft.util.RandomSource; import net.minecraft.world.level.block.Block; @@ -11,7 +9,6 @@ *

* Created by covers1624 on 2/9/20. */ -@MultiPartMarker (TAnimateTickTile.class) public interface AnimateTickPart extends MultiPart { void animateTick(RandomSource random); diff --git a/src/main/java/codechicken/multipart/api/part/CapabilityProviderPart.java b/src/main/java/codechicken/multipart/api/part/CapabilityProviderPart.java index e1bd140..b8fadeb 100644 --- a/src/main/java/codechicken/multipart/api/part/CapabilityProviderPart.java +++ b/src/main/java/codechicken/multipart/api/part/CapabilityProviderPart.java @@ -1,8 +1,5 @@ package codechicken.multipart.api.part; -import codechicken.multipart.api.annotation.MultiPartMarker; -import codechicken.multipart.api.part.MultiPart; -import codechicken.multipart.trait.TCapabilityTile; import net.minecraft.core.Direction; import net.minecraftforge.common.capabilities.ICapabilityProvider; import org.jetbrains.annotations.Nullable; @@ -10,7 +7,6 @@ /** * Created by covers1624 on 7/1/21. */ -@MultiPartMarker (TCapabilityTile.class) public interface CapabilityProviderPart extends MultiPart, ICapabilityProvider { boolean hasCapabilities(@Nullable Direction dir); diff --git a/src/main/java/codechicken/multipart/api/part/NeighborTileChangePart.java b/src/main/java/codechicken/multipart/api/part/NeighborTileChangePart.java index 188430d..3f7ece9 100644 --- a/src/main/java/codechicken/multipart/api/part/NeighborTileChangePart.java +++ b/src/main/java/codechicken/multipart/api/part/NeighborTileChangePart.java @@ -1,13 +1,10 @@ package codechicken.multipart.api.part; -import codechicken.multipart.api.annotation.MultiPartMarker; -import codechicken.multipart.trait.TTileChangeTile; import net.minecraft.core.Direction; /** * Mixin interface for parts that want to be notified of neighbor tile change events (comparators or inventory maintainers) */ -@MultiPartMarker (TTileChangeTile.class) public interface NeighborTileChangePart extends MultiPart { /** diff --git a/src/main/java/codechicken/multipart/api/part/PartialOcclusionPart.java b/src/main/java/codechicken/multipart/api/part/PartialOcclusionPart.java index c0362fb..4f004f0 100644 --- a/src/main/java/codechicken/multipart/api/part/PartialOcclusionPart.java +++ b/src/main/java/codechicken/multipart/api/part/PartialOcclusionPart.java @@ -1,7 +1,5 @@ package codechicken.multipart.api.part; -import codechicken.multipart.api.annotation.MultiPartMarker; -import codechicken.multipart.trait.TPartialOcclusionTile; import net.minecraft.world.phys.shapes.VoxelShape; /** @@ -11,7 +9,6 @@ *

* This part marker is managed by the mixin trait {@link codechicken.multipart.trait.TPartialOcclusionTile}. */ -@MultiPartMarker (TPartialOcclusionTile.class) public interface PartialOcclusionPart extends MultiPart { /** diff --git a/src/main/java/codechicken/multipart/api/part/SlottedPart.java b/src/main/java/codechicken/multipart/api/part/SlottedPart.java index 337c7e5..50109d4 100644 --- a/src/main/java/codechicken/multipart/api/part/SlottedPart.java +++ b/src/main/java/codechicken/multipart/api/part/SlottedPart.java @@ -1,15 +1,11 @@ package codechicken.multipart.api.part; -import codechicken.multipart.api.annotation.MultiPartMarker; -import codechicken.multipart.trait.TSlottedTile; - /** * Interface for parts that fill a slot based configuration as defined in PartMap. * If this is implemented, calling partMap(slot) on the host tile will return this part if the corresponding bit in the slotMask is set *

* Marker interface for TSlottedTile */ -@MultiPartMarker (TSlottedTile.class) public interface SlottedPart extends MultiPart { /** diff --git a/src/main/java/codechicken/multipart/api/part/TickablePart.java b/src/main/java/codechicken/multipart/api/part/TickablePart.java index 77099f8..6e82720 100644 --- a/src/main/java/codechicken/multipart/api/part/TickablePart.java +++ b/src/main/java/codechicken/multipart/api/part/TickablePart.java @@ -1,12 +1,8 @@ package codechicken.multipart.api.part; -import codechicken.multipart.api.annotation.MultiPartMarker; -import codechicken.multipart.trait.TTickableTile; - /** * Created by covers1624 on 18/9/20. */ -@MultiPartMarker (TTickableTile.class) public interface TickablePart { void tick(); diff --git a/src/main/java/codechicken/multipart/api/part/redstone/RedstonePart.java b/src/main/java/codechicken/multipart/api/part/redstone/RedstonePart.java index d77836b..25a0327 100644 --- a/src/main/java/codechicken/multipart/api/part/redstone/RedstonePart.java +++ b/src/main/java/codechicken/multipart/api/part/redstone/RedstonePart.java @@ -1,8 +1,6 @@ package codechicken.multipart.api.part.redstone; -import codechicken.multipart.api.annotation.MultiPartMarker; import codechicken.multipart.api.part.MultiPart; -import codechicken.multipart.trait.TRedstoneTile; import codechicken.multipart.trait.extern.RedstoneTile; /** @@ -11,7 +9,6 @@ * Marker interface for TRedstoneTile. This means that if a part is an instance of {@link RedstonePart}, * the container tile may be cast to {@link RedstoneTile} */ -@MultiPartMarker (TRedstoneTile.class) public interface RedstonePart extends MultiPart { /** diff --git a/src/main/java/codechicken/multipart/block/TileMultipart.java b/src/main/java/codechicken/multipart/block/TileMultipart.java index 044b322..19848f9 100644 --- a/src/main/java/codechicken/multipart/block/TileMultipart.java +++ b/src/main/java/codechicken/multipart/block/TileMultipart.java @@ -90,12 +90,6 @@ public TileMultipart(BlockPos pos, BlockState state) { super(CBMultipartModContent.MULTIPART_TILE_TYPE.get(), pos, state); } - // TODO Mixin compiler needs to support ctors with arguments, provided they are identical to the base class ctor. - protected TileMultipart() { - this(null, null); - throw new UnsupportedOperationException("Exists for traits."); - } - public List getPartList() { return partList; } diff --git a/src/main/java/codechicken/multipart/trait/TAnimateTickTile.java b/src/main/java/codechicken/multipart/trait/TAnimateTickTile.java index 3908a0b..1a88ccd 100644 --- a/src/main/java/codechicken/multipart/trait/TAnimateTickTile.java +++ b/src/main/java/codechicken/multipart/trait/TAnimateTickTile.java @@ -1,20 +1,23 @@ package codechicken.multipart.trait; -import codechicken.mixin.forge.TraitSide; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.AnimateTickPart; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.block.TileMultipart; +import net.minecraft.core.BlockPos; import net.minecraft.util.RandomSource; +import net.minecraft.world.level.block.state.BlockState; import java.util.List; /** * Created by covers1624 on 2/9/20. */ -@MultiPartTrait (value = AnimateTickPart.class, side = TraitSide.CLIENT) public class TAnimateTickTile extends TileMultipart { + public TAnimateTickTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public void animateTick(RandomSource random) { List jPartList = getPartList(); diff --git a/src/main/java/codechicken/multipart/trait/TCapabilityTile.java b/src/main/java/codechicken/multipart/trait/TCapabilityTile.java index 2401295..bbfcfa8 100644 --- a/src/main/java/codechicken/multipart/trait/TCapabilityTile.java +++ b/src/main/java/codechicken/multipart/trait/TCapabilityTile.java @@ -1,12 +1,13 @@ package codechicken.multipart.trait; import codechicken.multipart.api.part.CapabilityProviderPart; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.block.TileMultipart; import codechicken.multipart.capability.ChainedProvider; import net.minecraft.Util; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; import net.minecraftforge.common.capabilities.Capability; import net.minecraftforge.common.util.LazyOptional; import org.jetbrains.annotations.Nullable; @@ -16,7 +17,6 @@ /** * Created by covers1624 on 7/1/21. */ -@MultiPartTrait (CapabilityProviderPart.class) public class TCapabilityTile extends TileMultipart { //null and all sides. @@ -27,6 +27,10 @@ public class TCapabilityTile extends TileMultipart { private ChainedProvider[] providers = new ChainedProvider[7]; + public TCapabilityTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public LazyOptional getCapability(Capability cap, @Nullable Direction side) { ChainedProvider p = providers[ordinal(side)]; diff --git a/src/main/java/codechicken/multipart/trait/TInventoryTile.java b/src/main/java/codechicken/multipart/trait/TInventoryTile.java index 4021568..0caba28 100644 --- a/src/main/java/codechicken/multipart/trait/TInventoryTile.java +++ b/src/main/java/codechicken/multipart/trait/TInventoryTile.java @@ -1,16 +1,17 @@ package codechicken.multipart.trait; import codechicken.lib.util.ArrayUtils; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.block.TileMultipart; import it.unimi.dsi.fastutil.ints.IntArrayList; import it.unimi.dsi.fastutil.ints.IntList; +import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.world.Container; import net.minecraft.world.WorldlyContainer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.block.state.BlockState; import javax.annotation.Nullable; import java.util.ArrayList; @@ -20,8 +21,6 @@ /** * Created by covers1624 on 1/1/21. */ -@MultiPartTrait (Container.class) -@MultiPartTrait (WorldlyContainer.class) public class TInventoryTile extends TileMultipart implements WorldlyContainer { private List invList = new ArrayList<>(); @@ -30,6 +29,10 @@ public class TInventoryTile extends TileMultipart implements WorldlyContainer { private int[] invSize = new int[0]; private int[][] faceSlots = ArrayUtils.fill(new int[6][0], null); + public TInventoryTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public void copyFrom(TileMultipart that) { super.copyFrom(that); diff --git a/src/main/java/codechicken/multipart/trait/TPartialOcclusionTile.java b/src/main/java/codechicken/multipart/trait/TPartialOcclusionTile.java index 28724aa..817c160 100644 --- a/src/main/java/codechicken/multipart/trait/TPartialOcclusionTile.java +++ b/src/main/java/codechicken/multipart/trait/TPartialOcclusionTile.java @@ -1,9 +1,10 @@ package codechicken.multipart.trait; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.api.part.PartialOcclusionPart; import codechicken.multipart.block.TileMultipart; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; @@ -17,7 +18,6 @@ *

* Created by covers1624 on 2/9/20. */ -@MultiPartTrait (PartialOcclusionPart.class) public class TPartialOcclusionTile extends TileMultipart { //Static cache. @@ -27,6 +27,10 @@ public class TPartialOcclusionTile extends TileMultipart { private static VoxelShape lastOcclusionTestedShape; private static boolean lastOcclusionTestedResult; + public TPartialOcclusionTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public void bindPart(MultiPart newPart) { super.bindPart(newPart); diff --git a/src/main/java/codechicken/multipart/trait/TRedstoneTile.java b/src/main/java/codechicken/multipart/trait/TRedstoneTile.java index 6869a33..297f0bd 100644 --- a/src/main/java/codechicken/multipart/trait/TRedstoneTile.java +++ b/src/main/java/codechicken/multipart/trait/TRedstoneTile.java @@ -1,12 +1,13 @@ package codechicken.multipart.trait; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.EdgePart; import codechicken.multipart.api.part.FacePart; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.api.part.redstone.RedstonePart; import codechicken.multipart.block.TileMultipart; import codechicken.multipart.trait.extern.RedstoneTile; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; import static codechicken.lib.vec.Rotation.rotateSide; import static codechicken.multipart.api.RedstoneInteractions.connectionMask; @@ -16,9 +17,12 @@ /** * Created by covers1624 on 31/12/20. */ -@MultiPartTrait (RedstonePart.class) public class TRedstoneTile extends TileMultipart implements RedstoneTile { + public TRedstoneTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public int getDirectSignal(int side) { int max = 0; diff --git a/src/main/java/codechicken/multipart/trait/TSlottedTile.java b/src/main/java/codechicken/multipart/trait/TSlottedTile.java index 5e51f0b..2468b82 100644 --- a/src/main/java/codechicken/multipart/trait/TSlottedTile.java +++ b/src/main/java/codechicken/multipart/trait/TSlottedTile.java @@ -1,20 +1,24 @@ package codechicken.multipart.trait; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.api.part.SlottedPart; import codechicken.multipart.block.TileMultipart; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; import java.util.Arrays; /** * Created by covers1624 on 1/1/21. */ -@MultiPartTrait (SlottedPart.class) public class TSlottedTile extends TileMultipart { private MultiPart[] v_partMap = new MultiPart[27]; + public TSlottedTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public void copyFrom(TileMultipart that) { super.copyFrom(that); diff --git a/src/main/java/codechicken/multipart/trait/TTickableTile.java b/src/main/java/codechicken/multipart/trait/TTickableTile.java index c44bef1..a398601 100644 --- a/src/main/java/codechicken/multipart/trait/TTickableTile.java +++ b/src/main/java/codechicken/multipart/trait/TTickableTile.java @@ -1,10 +1,11 @@ package codechicken.multipart.trait; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.TickablePart; import codechicken.multipart.api.part.MultiPart; import codechicken.multipart.block.TileMultipart; import codechicken.multipart.api.TickableTile; +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; import java.util.ArrayList; import java.util.List; @@ -12,11 +13,14 @@ /** * Created by covers1624 on 18/9/20. */ -@MultiPartTrait (TickablePart.class) public class TTickableTile extends TileMultipart implements TickableTile { private final List tickingParts = new ArrayList<>(); + public TTickableTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public void copyFrom(TileMultipart that) { super.copyFrom(that); diff --git a/src/main/java/codechicken/multipart/trait/TTileChangeTile.java b/src/main/java/codechicken/multipart/trait/TTileChangeTile.java index c504f72..b4ec4be 100644 --- a/src/main/java/codechicken/multipart/trait/TTileChangeTile.java +++ b/src/main/java/codechicken/multipart/trait/TTileChangeTile.java @@ -1,24 +1,26 @@ package codechicken.multipart.trait; import codechicken.lib.math.MathHelper; -import codechicken.mixin.forge.TraitSide; -import codechicken.multipart.api.annotation.MultiPartTrait; -import codechicken.multipart.api.part.NeighborTileChangePart; import codechicken.multipart.api.part.MultiPart; +import codechicken.multipart.api.part.NeighborTileChangePart; import codechicken.multipart.block.TileMultipart; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; +import net.minecraft.world.level.block.state.BlockState; import java.util.List; /** * Created by covers1624 on 23/9/20. */ -@MultiPartTrait (value = NeighborTileChangePart.class, side = TraitSide.SERVER) public class TTileChangeTile extends TileMultipart { private boolean weakTileChanges = false; + public TTileChangeTile(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public void copyFrom(TileMultipart that) { super.copyFrom(that); diff --git a/src/main/java/codechicken/multipart/trait/TileMultipartClient.java b/src/main/java/codechicken/multipart/trait/TileMultipartClient.java index 07cc529..2f90a2a 100644 --- a/src/main/java/codechicken/multipart/trait/TileMultipartClient.java +++ b/src/main/java/codechicken/multipart/trait/TileMultipartClient.java @@ -4,12 +4,17 @@ import net.minecraft.client.Minecraft; import net.minecraft.client.multiplayer.ClientLevel; import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.state.BlockState; /** * Manual trait implemented on every client side TileMultiPart. */ public class TileMultipartClient extends TileMultipart { + public TileMultipartClient(BlockPos pos, BlockState state) { + super(pos, state); + } + @Override public boolean isClientTile() { return true; diff --git a/src/main/java/codechicken/multipart/util/ForgeMixinBackend.java b/src/main/java/codechicken/multipart/util/ForgeMixinBackend.java new file mode 100644 index 0000000..b4df9a7 --- /dev/null +++ b/src/main/java/codechicken/multipart/util/ForgeMixinBackend.java @@ -0,0 +1,59 @@ +package codechicken.multipart.util; + +import codechicken.asm.ClassHierarchyManager; +import codechicken.mixin.api.MixinBackend; +import cpw.mods.modlauncher.TransformingClassLoader; +import net.covers1624.quack.reflect.PrivateLookups; +import net.minecraftforge.fml.loading.FMLEnvironment; +import org.jetbrains.annotations.Nullable; + +import java.lang.invoke.MethodHandle; +import java.lang.invoke.MethodType; + +/** + * Created by covers1624 on 2/11/20. + */ +public class ForgeMixinBackend extends MixinBackend.SimpleMixinBackend { + + private static final TransformingClassLoader cl = (TransformingClassLoader) Thread.currentThread().getContextClassLoader(); + private static final MethodHandle m_buildTransformedClassNodeFor; + + static { + try { + m_buildTransformedClassNodeFor = PrivateLookups.getTrustedLookup() + .findVirtual(TransformingClassLoader.class, "buildTransformedClassNodeFor", MethodType.methodType(byte[].class, String.class, String.class)); + } catch (Throwable e) { + throw new RuntimeException("Unable to retrieve methods via reflection.", e); + } + ClassHierarchyManager.addByteLookupFunc(cName -> getBytesForClass(cName, "computing_frames")); + } + + public ForgeMixinBackend() { + super(cl); + } + + @Override + public byte @Nullable [] getBytes(String name) { + return getBytesForClass(name, "codechicken.multipart.util.ForgeMixinBackend"); + } + + @Override + public boolean filterMethodAnnotations(String annType, String value) { + if (FMLEnvironment.dist == null) { + return false; + } + String side = "net.minecraftforge.api.distmarker.Dist." + FMLEnvironment.dist.name(); + return annType.equals("net.minecraftforge.api.distmarker.OnlyIn") && !value.equals(side); + } + + private static byte @Nullable [] getBytesForClass(String cName, String reason) { + String jName = cName.replace("/", "."); + if (jName.equals("java.lang.Object")) return null; + + try { + return (byte[]) m_buildTransformedClassNodeFor.invokeExact(cl, jName, reason); + } catch (Throwable e) { + throw new RuntimeException("Failed to get bytes for class '" + cName + "'.", e); + } + } +} diff --git a/src/main/java/codechicken/multipart/util/MultipartGenerator.java b/src/main/java/codechicken/multipart/util/MultipartGenerator.java index 9725588..aff8fc7 100644 --- a/src/main/java/codechicken/multipart/util/MultipartGenerator.java +++ b/src/main/java/codechicken/multipart/util/MultipartGenerator.java @@ -1,19 +1,21 @@ package codechicken.multipart.util; import codechicken.asm.ASMHelper; -import codechicken.asm.CC_ClassWriter; import codechicken.asm.ObfMapping; -import codechicken.mixin.api.*; -import codechicken.mixin.forge.ForgeMixinBackend; -import codechicken.mixin.forge.SidedGenerator; +import codechicken.mixin.SidedFactory; +import codechicken.mixin.api.MixinCompiler; +import codechicken.mixin.api.MixinDebugger; +import codechicken.mixin.api.MixinFactory; +import codechicken.mixin.api.MixinLanguageSupport; +import codechicken.mixin.util.ClassInfo; import codechicken.mixin.util.JavaTraitGenerator; import codechicken.mixin.util.SimpleDebugger; import codechicken.mixin.util.Utils; -import codechicken.multipart.api.annotation.MultiPartTrait; import codechicken.multipart.api.part.MultiPart; +import codechicken.multipart.api.RegisterMultipartTraitsEvent; import codechicken.multipart.block.TileMultipart; import codechicken.multipart.init.CBMultipartModContent; -import com.google.common.collect.ImmutableList; +import codechicken.multipart.trait.TileMultipartClient; import com.google.common.collect.ImmutableSet; import com.google.common.collect.Streams; import net.covers1624.quack.collection.FastStream; @@ -21,14 +23,17 @@ import net.minecraft.core.BlockPos; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; +import net.minecraftforge.fml.ModLoader; +import net.minecraftforge.fml.event.lifecycle.FMLLoadCompleteEvent; +import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext; import org.apache.commons.lang3.tuple.Pair; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import org.jetbrains.annotations.Nullable; -import org.objectweb.asm.ClassWriter; import org.objectweb.asm.FieldVisitor; import org.objectweb.asm.Label; import org.objectweb.asm.MethodVisitor; +import org.objectweb.asm.Type; import org.objectweb.asm.tree.ClassNode; import org.objectweb.asm.tree.MethodNode; @@ -37,17 +42,15 @@ import java.util.stream.Collectors; import java.util.stream.Stream; -import static codechicken.mixin.util.Utils.asmName; import static net.covers1624.quack.util.SneakyUtils.throwUnchecked; import static org.objectweb.asm.Opcodes.*; /** - * Please use {@link MultiPartTrait} annotations. - *

- * TODO allow parallel registration of traits. Requires mixin compiler changes. (parallel stream processing of annotations) * Created by covers1624 on 4/5/20. + * + * @see RegisterMultipartTraitsEvent */ -public class MultipartGenerator extends SidedGenerator { +public class MultipartGenerator extends SidedFactory { private static final Logger logger = LogManager.getLogger(); private static final CrashLock LOCK = new CrashLock("Already initialized."); @@ -59,25 +62,21 @@ public class MultipartGenerator extends SidedGenerator passthroughTraits = new HashMap<>(); - private final MixinFactory.TraitKey clientTrait = registerTrait(asmName("codechicken.multipart.trait.TileMultipartClient")); + private final MixinFactory.TraitKey clientTrait = registerTrait(TileMultipartClient.class); private MultipartGenerator() { - super(MixinCompiler.create(new ForgeMixinBackend(), makeDebugger(), getMixinSupports()), TileMultipart.class, Factory.class, "cmp"); - Optional javaSupport = mixinCompiler.findLanguageSupport("java"); - javaSupport// - .orElseThrow(() -> new RuntimeException("Unable to find JavaMixinLanguageSupport instance..."))// + super(MixinCompiler.create(new ForgeMixinBackend(), makeDebugger()), TileMultipart.class, Factory.class, "cmp"); + Objects.requireNonNull(mixinCompiler.getLanguageSupport("java")) .setTraitGeneratorFactory(MultipartJavaTraitGenerator::new); } /** - * Overload for {@link #registerPassThroughInterface(String, boolean, boolean)}, + * Overload for {@link #registerPassThroughInterface(Class, boolean, boolean)}, * passing true to both boolean parameters. * * @param iFace The interface. */ - @AsmName - @JavaName - public void registerPassThroughInterface(String iFace) { + public void registerPassThroughInterface(Class iFace) { registerPassThroughInterface(iFace, true, true); } @@ -97,19 +96,20 @@ public void registerPassThroughInterface(String iFace) { * @param client If this interface should be used client side. * @param server If this interface should be used server side. */ - @AsmName - @JavaName - public void registerPassThroughInterface(String iFace, boolean client, boolean server) { - iFace = Utils.asmName(iFace); + public void registerPassThroughInterface(Class iFace, boolean client, boolean server) { MixinFactory.TraitKey key = registerPassthroughTrait(iFace); - String tName = key.getTName(); - registerTrait(iFace, client ? tName : null, server ? tName : null); + Class trait = mixinCompiler.getDefinedClass(key.tName()); + registerTrait(iFace, client ? trait : null, server ? trait : null); } - //Internal, loads all MultiPartTrait annotations. - public void loadAnnotations() { + // Internal. + public void load() { LOCK.lock(); - loadAnnotations(MultiPartTrait.class, MultiPartTrait.TraitList.class); + FMLJavaModLoadingContext.get().getModEventBus().addListener(this::onModLoadingComplete); + } + + private void onModLoadingComplete(FMLLoadCompleteEvent event) { + ModLoader.get().postEvent(new RegisterMultipartTraitsEvent(this)); } public ImmutableSet getTraits(MultiPart part, boolean client) { @@ -131,7 +131,8 @@ public TileMultipart generateCompositeTile(@Nullable BlockEntity tile, BlockPos return construct(traits).newInstance(pos, CBMultipartModContent.MULTIPART_BLOCK.get().defaultBlockState()); } - public TraitKey registerPassthroughTrait(@AsmName String iName) { + public TraitKey registerPassthroughTrait(Class iClass) { + String iName = Utils.asmName(iClass); TraitKey key = passthroughTraits.get(iName); if (key != null) { return key; @@ -145,6 +146,7 @@ public TraitKey registerPassthroughTrait(@AsmName String iName) { String vName = "impl"; String iDesc = "L" + iName + ";"; + ClassNode mpCNode = Objects.requireNonNull(mixinCompiler.getClassNode(Utils.asmName(TileMultipart.class)), "Did not get class for TileMultipart?"); ClassNode iNode = mixinCompiler.getClassNode(iName); if (iNode == null) { throwUnchecked(new ClassNotFoundException("Unable to generate PassThrough trait for interface: " + iName + ", class not found.")); @@ -154,25 +156,33 @@ public TraitKey registerPassthroughTrait(@AsmName String iName) { throw new IllegalArgumentException("Class: " + iName + ", is not an interface."); } - ClassWriter cw = new CC_ClassWriter(ClassWriter.COMPUTE_MAXS | ClassWriter.COMPUTE_FRAMES); + ClassNode cNode = new ClassNode(); - cw.visit(V1_8, ACC_SUPER, tName, null, "codechicken/multipart/block/TileMultipart", new String[] { iName }); + cNode.visit(V1_8, ACC_SUPER, tName, null, "codechicken/multipart/block/TileMultipart", new String[] { iName }); { - FieldVisitor fv = cw.visitField(ACC_PRIVATE, vName, iDesc, null, null); + FieldVisitor fv = cNode.visitField(ACC_PRIVATE, vName, iDesc, null, null); fv.visitEnd(); } { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "", "()V", null, null); + MethodNode superCtor = FastStream.of(mpCNode.methods) + .filter(e -> e.name.equals("")) + .only(); + MethodVisitor mv = cNode.visitMethod(ACC_PUBLIC, "", superCtor.desc, null, null); mv.visitCode(); - mv.visitVarInsn(ALOAD, 0); - mv.visitMethodInsn(INVOKESPECIAL, "codechicken/multipart/block/TileMultipart", "", "()V", false); + int idx = 0; + mv.visitVarInsn(ALOAD, idx++); + for (Type arg : Type.getArgumentTypes(superCtor.desc)) { + mv.visitVarInsn(arg.getOpcode(ILOAD), idx); + idx += arg.getSize(); + } + mv.visitMethodInsn(INVOKESPECIAL, "codechicken/multipart/block/TileMultipart", "", superCtor.desc, false); mv.visitInsn(RETURN); mv.visitMaxs(-1, -1); } { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "bindPart", "(Lcodechicken/multipart/api/part/MultiPart;)V", null, null); + MethodVisitor mv = cNode.visitMethod(ACC_PUBLIC, "bindPart", "(Lcodechicken/multipart/api/part/MultiPart;)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); @@ -192,7 +202,7 @@ public TraitKey registerPassthroughTrait(@AsmName String iName) { } { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "partRemoved", "(Lcodechicken/multipart/api/part/MultiPart;I)V", null, null); + MethodVisitor mv = cNode.visitMethod(ACC_PUBLIC, "partRemoved", "(Lcodechicken/multipart/api/part/MultiPart;I)V", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitVarInsn(ALOAD, 1); @@ -212,7 +222,7 @@ public TraitKey registerPassthroughTrait(@AsmName String iName) { mv.visitEnd(); } { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, "canAddPart", "(Lcodechicken/multipart/api/part/MultiPart;)Z", null, null); + MethodVisitor mv = cNode.visitMethod(ACC_PUBLIC, "canAddPart", "(Lcodechicken/multipart/api/part/MultiPart;)Z", null, null); mv.visitCode(); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, tName, vName, iDesc); @@ -233,14 +243,13 @@ public TraitKey registerPassthroughTrait(@AsmName String iName) { } methods(iNode).forEach(m -> { - MethodVisitor mv = cw.visitMethod(ACC_PUBLIC, m.name, m.desc, m.signature, m.exceptions.toArray(new String[0])); + MethodVisitor mv = cNode.visitMethod(ACC_PUBLIC, m.name, m.desc, m.signature, m.exceptions.toArray(new String[0])); mv.visitVarInsn(ALOAD, 0); mv.visitFieldInsn(GETFIELD, tName, vName, iDesc); Utils.finishBridgeCall(mv, m.desc, INVOKEINTERFACE, iName, m.name, m.desc, true); }); - cw.visitEnd(); - mixinCompiler.defineInternal(tName, cw.toByteArray()); - key = registerTrait(tName); + cNode.visitEnd(); + key = registerTrait(cNode); passthroughTraits.put(iName, key); return key; } @@ -326,10 +335,4 @@ private static MixinDebugger makeDebugger() { } return new SimpleDebugger(Paths.get("./asm/multipart"), DEBUG_TYPE); } - - @Deprecated //Remove in 1.16.3 - private static Collection> getMixinSupports() { - // TODO load the Scala language support if scala is present. - return ImmutableList.of(MixinLanguageSupport.JavaMixinLanguageSupport.class); - } }