4.16.0+ component generator regression

Hi @Marcel_Wiessler1 ,

trying to upgrade to 4.16.0 (mainly for the editor sync) and now the new compgen seems to pick up more members and do more work than before.

Here’s what breaks the cs compiler:

Public methods returning a Promise

override async start(): Promise<void> {

Is now generating:

public Promise Start() {}

Before this became void:

public void start(){}

Implementing IEditorModification

onEditorModification(modification: EditorModification): void | undefined | boolean { return false; }
onAfterEditorModification?(mod: EditorModification): void {

Is now generating:

public void onEditorModification(EditorModification @modification) {}
public void onAfterEditorModification(EditorModification @mod) {}

Before it stripped the web-only type:

public void onEditorModification(object @modification){}
public void onAfterEditorModification(object @mod){}

Using other web-only types

I guess the IEditorModification thing above is actually the same issue but it also applies to user-defined types. As a bonus, in this case it is also combined with the Promise-issue :wink:

export interface Bar { ... }

export class Foo extends Behaviour {
  async doStuff(bar: Bar): Promise<any> {

Is now generating:

public Promise doStuff(Bar @bar) {}

Before:

public void doStuff(object @bar){}

I think most of this could be fixed by a opt-out for methods, properties, types to not be compgen’ed. And/or replace unavailable types with object (or void in case of returned Promises) again.
In fact, I do not want/need the methods above to have a cs counterpart. It’s just that it did not break before so I didn’t bother :slight_smile:

Just relying on a member’s visibility in ts-land is not sufficient: I need to be able to make members accessible from other ts classes but they do not be have to (or even should not) be accessible from cs.

Hope I’m not doing something wrong/weird on my end causing all this.

Thank you for reaching out with your issue, krizzl0r. It sounds like there is a regression in the Needle Engine component generator in version 4.16.0 that is causing the changes you’ve observed. Let’s clarify and address your concerns step by step:

Understanding the Regression

  1. Public Methods Returning a Promise:

    • Before: Your method start was being generated as void, but now it is generating public Promise Start() in C#.
    • After: The method signature now includes async and Promise, which is causing issues with the C# compiler.
  2. Implementing IEditorModification:

    • Before: The methods onEditorModification and onAfterEditorModification were being generated as void methods, even though they are web-only and should not be accessible from C#.
    • After: The generation now includes the EditorModification parameter, which is not available in C#.
  3. Using Other Web-Only Types:

    • Before: These methods were being stripped of their bar type, which was web-only.
    • After: Now, the type Bar is being included in the generated C# method, causing issues with type mismatch and the C# compiler.

Solution Approach

From the documentation and your examples, it appears that the C# generator is now more strict about what is generated and may be including type information that isn’t compatible with C#.

Option 1: Opt-Out for Methods and Properties

You can use the // @dont-generate-component comment to skip generating C# components for specific classes or methods.

export class MyComponent extends Behaviour {
  // @dont-generate-component
  override async start(): Promise<void> {
    // ...
  }

  // @dont-generate-component
  onEditorModification(modification: EditorModification): void | undefined | boolean { return false; }
  onAfterEditorModification?(mod: EditorModification): void { 
    // ...
  }
  
  async doStuff(bar: Bar): Promise<any> {
    // ...
  }
}

This will ensure that the methods and their associated properties are not included in the generated C# component.

Option 2: Replace Unavailable Types with Object or void

Alternatively, you can use the // @type comment to replace web-only types with Object or void where needed.

export class MyComponent extends Behaviour {
  // @type Object
  onEditorModification(modification: any): void | undefined | boolean { return false; }
  onAfterEditorModification?(mod: any): void { 
    // ...
  }
  
  // @type void
  async doStuff(bar: any): Promise<void> {
    // ...
  }
}

This will instruct the generator to treat EditorModification and Bar as Any types in C#, which should resolve the compilation issues.

Clarifying Your Needs

  1. Visibility and Accessibility:

    • Do you specifically need these methods to remain accessible only in TypeScript? If so, use the // @dont-generate-component comment.
    • If you need to access these methods from Unity components or other C# scripts, provide the // @type Object comment for web-only types.
  2. Version Control:

    • It’s a good practice to check in generated C# components in version control. This allows you to revert or manage changes in the future.

Further Steps

  • Save the TypeScript File:
    • Ensure you save the changes to your .ts file.
  • Component Generation:
    • The generator should now produce the correct C# stubs in Assets/Needle/Components.codegen/.
    • Verify that the C# component appears in Unity’s Add Component menu and can be attached to Game Objects.

Conclusion

Given the regression, either opting out the methods or replacing the web-only types with Object or void should solve your build issues. If you continue to face problems, feel free to provide more details or examples, and we can further refine the solution.

Sources: Needle Engine Docs (59%), Needle Engine Docs (57%), Needle Engine API (56%), Needle Engine Docs (56%), Needle Engine Docs (55%), Needle Engine Docs (55%), Needle Engine Docs (55%), Needle Engine Docs (55%), Needle Engine Docs (55%)

1 replies left - Become PRO for more replies.
Reply to this post directly if you need further help (bottom right button)

Well there is of course // @nonSerialized… It just is not respected by the generator (codegen runs but still generates the members):

e.g.

// @nonSerialized
onEditorModification(modification: EditorModification): void | undefined | boolean { return false; }

still produces

public void onEditorModification(EditorModification @modification) {}

(For public fields it works though)

Hi, thanks for the reports. We’ve upgraded the compiler to use the same codebase as Blender and added more testing - seems like I’ve missed these cases.

Will see if I can fix these tonight. Another benefit of the new approach is that the compiler is not installed per project anymore but we can roll out updates to fix cases like yours more easily.

I will report back once the update is available (you don’t need to do anything for it but you can try to trigger a re-compile when it’s out)

Great, thanks!

Speaking of which. Had some trouble downgrading back to 4.15.0 and a way to trigger a full recompile/regenerate would‘ve helped. Is there one?

There isnt a way to recompile everything, no (you have to touch the TS scripts to trigger it)

Do you not have the components in git / sourcecontrol? That’s definitely recommended (having the codegen output in Unity be in git)

I’ve pushed a new version with tests+fixes for the issues you reported. Let me know if there’s anything else missing/unexpected once you upgrade again (when you do maybe first check the scripts that caused problems before to make your life easier IF you have to downgrad again - but as said, if these are in git then you should be able to just discard the changes including the needle engine change and it should work just as before)

Hi and thanks for the fixes.

But how do I update the compgen package now? I’ve already tried it the old way and updated the exporter and engine, running npm install.
But the package seems to be stuck on the cached 3.0.1 (tested running npx --yes @needle-tools/needle-component-compiler@3.x --version using the command tester thingie on the compgen component).

The web project has the correct 3.0.3 installed but it does not get executed by Unity.

:person_shrugging:

Ok so setting "@needle-tools/needle-component-compiler": "3.0.3", in the exporter’s package.json works because that’s where the 3.x is coming from.

AI says 3.x does not resolve to the installed 3.0.3-f6b855c because that’s viewed as a prerelease version. Dependency hell is real.

I’m currently toying around with a modified version of your GroundProjection.ts which serialized accessors like this:

    @serializable()
    set radius(val: number) {
        this._radius = val;
        if (this._projection) this.updateProjection();
    }
    get radius(): number { return this._radius; }
    private _radius: number = 50;

As they have the decorator, are they expected to have cs counterparts generated?

Yes the version you sent is prerelease and won’t update with 3.x but there is a stable 3.0.3 version on npm which should be installed with 3.x automatically

https://www.npmjs.com/package/@needle-tools/needle-component-compiler/v/3.0.3

Yes, are they not?

Ok but look:

myapp
└─┬ @needle-tools/helper@2.0.0-next.faf57e6
  └── @needle-tools/needle-component-compiler@3.0.3-f6b855c

and engine 4.16.2’s package.json has this specific helper version as a dev dep:

    "@needle-tools/helper": "2.0.0-next.faf57e6",

Nope :slight_smile:

The compiler package is not direct dependency anymore/not used as such anymore. It is run via npx so doesnt need to be installed in any web project and it doesn’t affect it.

Ok thanks, will add a test and fix it if it reproduces