COMMUNITY

Difficulties Getting Haxe to Compile to a Blender Plugin

I’m trying to get Haxe to work for writing Blender plugins, specifically so that we can write the Armory Blender plugin in Haxe ( and if I ever write my own Blender plugin, I’d want to write it in Haxe, obviously :roll_eyes: ), but there are a few of difficulties I am having. If anybody could help me out that would be great.

I have what I have developed so far in a blender extern generator on GitHub. So far I nearly have the system working, but I’ve still got some things to work out.

Handling bl_info, register(), and unregister()

So my first problem is related to the fact that Haxe doesn’t let you define module level fields. For every blender plugin there has to be a global scoped bl_info dictionary containing the addon info like name, etc. You have a similar issue with the required register() and unregister() functions which need to be defined in the global scope of the module.

I managed to solve for this in a sub-optimal manner by having a two-stage compilation, where the first on compile the plugin like any Haxe program, and the second one uses a macro to add the extra content to the file generated in the first step:

The biggest problem with this setup is that it ends up compiling the program twice, which takes a little bit longer because of the large amount of extern classes from the Blender API. It is a bigger problem because of how much it slows autocompletion, I just don’t know if there is another way to do that.

Import Name is Different than Class Name

The next problem I am having has to do with imports. There is a weird thing about Blender’s bpy package, that you can’t import bpy.types. That causes an issue when I need to use the bpy.types.Operator class. At first I had the extern classes structured like this, with a :pythonImport meta.

@:pythonImport("bpy.types.Operator") extern class Operator {

The problem with this is that it causes Haxe to generate an import that looks like import bpy.types.Operator as bpy_types_operator_Operator, which break when running in Blender because bpy.types is not a module.

My current work-around is to add import bpy to the output post-processing step that I mentioned above and switched the :pythonImport meta to a :native metadata. This is bad for the same reason as the above problem, because I don’t want to have to have to compile the program two times to get the final output. Also I would need to add logic to be able to tell which extra imports I need to add, which should be possible, but isn’t optimal. I’m not sure if there is a way to get more control over how Haxe generates the Python imports.

Overriding Class Variables

On a more Blender and less Haxe note I am having trouble with not being able to tell whether or not to make a class attribute static or not. So in the plugin code you need to do something like the following, but it causes Haxe to complain that I can’t re-define bl_idname or bl_label because they are already defined in Operator.

class SimpleOperator extends Operator {
	var bl_idname = "object.simple_operator";
	var bl_label = "Tool Name";

	public override function execute(context:Dynamic) {
		trace("Hello World");
		return new Set(["FINISHED"]);
	}
}

That actually makes sense, and is fixed if you make the field static, which it probably needs to be anyway. The problem is that I don’t know how to tell what class fields to make static from the XML documentation. This is the only problem I don’t have a workaround for so far.

1 Like

You know you’re an awesome dev when nobody knows how to help you. :smiley:

1 Like

I am not python expert here are my 2cents.

  1. Perhaps @:expose could be used to expose fields to module level?
  2. I think @:pythonImport("bpy", 'types.Operator') extern class Operator {} is the answer
  3. From the blender doc and my scarse python knowledge, I believe it is a static variable. Because it is declared at class level. If it is an instance variable it would be declared in __init__ as self.foo = 'xx'.
1 Like

Hi there, I realize this is old but as it seems what disturbed you the most was the intellisense (correct?). There is this bpy module: fake-bpy-module-2.92 · PyPI which can be used to speed up intellisense as its using an alternative build solution to create the bpy but excluding all definitions (so declarations only) which I would place my bet can speed up any language server quite significantly.

Its cool to see that its possible to do Blender addons in Haxe however. How come this doesnt appear to be used in the current implementation of Armory 3D?

Hey there! This was a while ago, but I think intellisense was one of the annoying issues. The fake bpy module is a good idea, but it’s not actually the Python intellisense that is an issue it’s the Haxe intellisense. Python intellisense isn’t use at all in this case.

The bpy module just has so many types that it was rather slow for the Haxe language server to search through them or something, I guess. It might not be a problem on a faster computer, I don’t know :man_shrugging: At the time I was on a 4GB RAM machine with 4, 2.1 GHZ CPU’s if I remember correctly.

I ran out of memory a lot running things like browsers and VSCode at the same time.

Here’s the original Armory issue which was closed to focus on other things at the time:

Also, I’m not sure if that static classes issue that I never fixed would be a problem.

In the end it might be possible to do well, it just wasn’t worth the effort to try to make work at the time.