architectury / architectury-transformer

The transformer backend to transform common module to platform-specific loadable mods.
MIT License
4 stars 12 forks source link

ExpectPlatform classes #5

Open shedaniel opened 3 years ago

shedaniel commented 3 years ago

Accept classes in @ExpectPlatform, may be confusing. Library Common:

@ExpectPlatform
public class Foo implements Supplier<Integer> {
    protected int a;

    public Foo(int a) {
        this.a = a;
    }

    @Override
    public Integer get() {
        return this.a;
    }

    // Does not need a @ExpectPlatform, just error
    public void set(int value) {
        throw new AssertionError();
    }
}

Library Fabric:

public class FooFabric extends Foo implements FabricOnlyRandomInterface {
    // Must include the same constructor as common, Foo#<init> is redirected to here
    public FooFabric(int a) {
        super(a);
    }

    @Override
    public Integer get() {
        return super.get() + 5; // Custom logic overriding the common one
    }

    @Override
    public void set(int value) {
        this.a = value - 5;
    }

    public void fabricOnlyMethod() {
        System.out.println("lol");
    }
}

Library Forge:

public class FooForge extends Foo implements ForgeOnlyRandomInterface {
    // Must include the same constructor as common, Foo#<init> is redirected to here
    public FooForge(int a) {
        super(a);
    }

    @Override
    public void set(int value) {
        this.a = value;
    }
}

Using the library in Common:

System.out.println(new Foo(10).get()); // Prints 15 on Fabric, 10 on Forge

// -> Compiles to
System.out.println(new FooFabric(10).get());
System.out.println(new FooForge(10).get());

Using the library in Fabric / Forge:

System.out.println(new Foo(10).get()); // This will crash
System.out.println(new FooFabric(10).get()); // Code have to explicitly call FooFabric#<init>
System.out.println(new FooForge(10).get()); // Code have to explicitly call FooForge#<init>
Juuxel commented 3 years ago

How would this work for libraries that are not compiled using architectury? Would they have to use the platform implementations from impl.fabric/forge instead of the common API?

KP2048 commented 2 years ago

Expect platform fields would be useful too

KP2048 commented 2 years ago

An annotation for excluding or including a method in common from being an expect platform method in the class?

KP2048 commented 2 years ago

Even better, the implementation classes could be subclasses of the common class and the overridden methods in the implementation classes could just be the implementation methods so all you would have to do is replace the object creation statements with the appropriate implementation class. The inheritance stuff would take care of the methods. You would also need to enforce somehow that the common class is used in common module and the implementation class is used in implementation module (the common still gets replaced with the implementation in common module)

wagyourtail commented 2 years ago

@Witherking25

as long as common gets replaced in implementation module, everything would work with that as common can't see the impl...

tho, I just use ServiceLoader at this point...

KP2048 commented 2 years ago

How would this work for libraries that are not compiled using architectury? Would they have to use the platform implementations from impl.fabric/forge instead of the common API?

as long as common gets replaced in implementation module, everything would work with that as common can't see the impl...

If you use common class in a fabric only mod it won’t work same thing for forge only mod You must use the platform specific class

KP2048 commented 2 years ago

Would this work? https://github.com/architectury/architectury-transformer/blob/6916af5c10464535e85c57474000de9fb18c897e/src/main/java/dev/architectury/transformer/transformers/TransformExpectPlatform.java#L84-L99