Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Function as class member throws illegal signature and crashes the game #31

Closed
Riernar opened this issue Jul 29, 2019 · 3 comments
Closed

Comments

@Riernar
Copy link

Riernar commented Jul 29, 2019

Hi @kindlich ,

I tried to define a custom ZenClass with a custom function as a member. Since functions can be used as globals, I expected them to be valid class members. However, my attempts throw a Java.lang.ClassFormatError: Field "f" in class ZenClassCrafttweakerExecutor_Executor_0 has illegal signature "ZenClassCrafttweakerExecutor1" and crash the whole game.

As a side note, defining functions with no arguments and no return value doesn't seems to work, hence bizarre signatures in my script. I tried function()void, function()IAny and function(void)void, though I might have overlooked something.

Expected behavior:
function are valid class members (if intended). If they should not be, trying to use them as class members should only crash the script, not the whole game.

Rationale:
Since ZenScript is intended as a scripting language, function class members may be out of scope. It would however provide great flexibility for repetitive processes and definitions. Rather than defining multiple classes that look very alike, it would be possible to use a single class and provide function members to its instances.

Also, it would allow to circumvent #26 using executor classes, which is what I was trying to do as a test. I'm trying to define a scheduling mechanism with functions being fired in proper order, at different game tweaking stages.

Versions:

  • minecraft 1.12.2
  • forge 14.23.5.2838
  • crafttweaker 4.1.19

Script used:

Click to expand

#priority 9999

zenClass Executor {
    var f as function(bool)int = function() {};

    zenConstructor() {}

    function exec() {
        var func as function(bool)int = this.f;
        func(false);
    }
}

Crash StackTrace:

Click to expand

java.lang.ClassFormatError: Field "f" in class ZenClassCrafttweakerExecutor_Executor_0 has illegal signature "ZenClassCrafttweakerExecutor1"
	at java.lang.ClassLoader.defineClass1(Native Method)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:763)
	at java.lang.ClassLoader.defineClass(ClassLoader.java:642)
	at stanhebben.zenscript.definitions.zenclasses.ParsedZenClass$1.find(ParsedZenClass.java:131)
	at stanhebben.zenscript.definitions.zenclasses.ParsedZenClass$1.access$000(ParsedZenClass.java:129)
	at stanhebben.zenscript.definitions.zenclasses.ParsedZenClass.writeClass(ParsedZenClass.java:133)
	at stanhebben.zenscript.ZenParsedFile.<init>(ZenParsedFile.java:142)
	at crafttweaker.runtime.CrTTweaker.loadScript(CrTTweaker.java:193)
	at crafttweaker.runtime.CrTTweaker.loadScript(CrTTweaker.java:105)
	at crafttweaker.mc1120.events.CommonEventHandler.registerRecipes(CommonEventHandler.java:69)
	at net.minecraftforge.fml.common.eventhandler.ASMEventHandler_59_CommonEventHandler_registerRecipes_Register.invoke(.dynamic)
	at net.minecraftforge.fml.common.eventhandler.ASMEventHandler.invoke(ASMEventHandler.java:90)
	at net.minecraftforge.fml.common.eventhandler.EventBus$1.invoke(EventBus.java:144)
	at net.minecraftforge.fml.common.eventhandler.EventBus.post(EventBus.java:182)
	at net.minecraftforge.registries.GameData.fireRegistryEvents(GameData.java:857)
	at net.minecraftforge.common.crafting.CraftingHelper.loadRecipes(CraftingHelper.java:629)
	at net.minecraftforge.fml.common.Loader.initializeMods(Loader.java:742)
	at net.minecraftforge.fml.client.FMLClientHandler.finishMinecraftLoading(FMLClientHandler.java:336)
	at net.minecraft.client.Minecraft.func_71384_a(Minecraft.java:535)
	at net.minecraft.client.Minecraft.func_99999_d(Minecraft.java:378)
	at net.minecraft.client.main.Main.main(SourceFile:123)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at net.minecraft.launchwrapper.Launch.launch(Launch.java:135)
	at net.minecraft.launchwrapper.Launch.main(Launch.java:28)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.multimc.onesix.OneSixLauncher.launchWithMainClass(OneSixLauncher.java:196)
	at org.multimc.onesix.OneSixLauncher.launch(OneSixLauncher.java:231)
	at org.multimc.EntryPoint.listen(EntryPoint.java:143)
	at org.multimc.EntryPoint.main(EntryPoint.java:34)

Thanks for looking into the issue and (potential) feature request !

EDIT: added minecraft's, forge's and CrT's versions

@Riernar
Copy link
Author

Riernar commented Sep 22, 2019

Hi @kindlich,
I just had an idea to solve this and #26 : I understand that the only step preventing using function as parameters/members is that you cannot define a Java interface (reflected as a zs type) from within zs. Is this correct ?

Would it be possible to add an interface key word to zs for that purpose ? It seems the Java code behind (linked in #26) is quit simple, though I have no idea what happens on ZenScript side with @register or how ASM work either.

Proposed zs syntax:

interface IInterfaceName {
    IItemStack,
    Type2,
    Type3
}

@kindlich
Copy link
Contributor

kindlich commented May 26, 2020

Hey there,

I apologize for the late reply.
Currently I have a rudimentary implementation for function types as parameters and members in my local dev environment.

var myTestFun as function(string)void = function(s as string) as void {print(s);};
myTestFun('Hello World');

function myAcceptFun(consumer as function(string)void) as void {
   consumer('hello from inside myAcceptFun');
}

myAcceptFun(myTestFun);
myAcceptFun(function(s as string) as void {print('Another thing: ' ~ s);});

Would print

Hello World
hello from inside myAcceptFun
Another thing: hello from inside myAcceptFun

And

zenClass myClass {
    var consumer as function(string)void;
    zenConstructor(consumer as function(string)void) {
        this.consumer = consumer;
    }
    function acceptString(x as string) as void {
        consumer(x);
    }
}
myClass(function(x as string) as void {print('inside fun: ' ~ x);}).acceptString('abc');

Would print

inside fun: abc

@Riernar
Copy link
Author

Riernar commented Jun 16, 2020

That is extremely neat ! No problem for the long wait, this isn't exactly a core feature of zs/CrT (and almost out of scope). Though it is super nice that it's now possible. Thank you !

@Riernar Riernar closed this as completed Jun 16, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants