The Plugin Inspector is a mess

I’m having a heck of a time with the plugin importer in Unity 6. It seems like it’s broken in so many different ways.

Like, it’s always been somewhat broken, but it’s super broken now.

For context, I’m working on an asset with a native plugin that has a macOS version (Intel + Apple Silicon), and a Windows version in x86, x64 and ARM64. This seems like a fairly normal thing to be doing. Users would expect all these to work.

Due to the number of settings involved, I want to use an editor script to get all the plugin importers and set the various platforms and settings. Right off the bat, if this script runs with [InitializeOnLoad], it breaks. I think it’s running before the editor is ready so the meta files are never produced and the editor really doesn’t like that. Annoying, but okay I’ll just run it manually.

So, if I trigger it to load with a menu item, it works a bit better, but depending on when and where I’m running it, the editor will decide to ignore some of the settings entirely, depending on what platform I’m running on.

So, set it up manually in the inspector. Well, I can pretty easily get into a state where, for example, the x64 importer will not let me set the Standalone CPU to x64. It’ll just jump back to Any CPU. No errors or warnings or anything. I hit apply and it resets.

Let’s talk about Any CPU. Any CPU on Windows is nonsensical. To my knowledge, and unlike, say, macOS, you cannot bundle the various architectures into one DLL. So this option is pointless.

Also, why is there an x86 checkbox and then immediately below it a CPU dropdown for x64 and ARM64? They should all be in the dropdown.

The default import behavior is bonkers. It seems to just apply all platforms and all CPU architectures. This creates all kinds of problems. For one, if the editor decides it doesn’t like the importer settings (which can happen on a whim such as an editor restart). Now it blows up about multiple plugins with the same name existing. A much more sensible default is to disable for all platforms and editor—because Unity seems unable to guess. So, let the user turn things on. (Speaking of which, isn’t there a header in the DLL you can check so Unity can guess?). There is no world in which DLLs should be included for macOS, tvOS, iOS, most consoles, etc. so why default to this?

“Any OS” for editor settings is nonsensical in most cases—especially as a default. “None” would at least make sense (considering the all platforms default) and that doesn’t exist. The whole platform selection as a bunch of checkboxes is nonsensical. They’re almost all mutually exclusive, except for Editor and Standalone. It really should be a drop down with Windows, macOS and Linux broken out separately, and have an Editor checkbox for those three in the platform settings. Too late now, I guess.

x86 is not allowed in the Editor. If it was selected in earlier Unity versions or set through an editor script, then just ignore it or at least unset it. Don’t set to wrong defaults.

Running Unity in Windows, it refuses to believe macOS exists as a platform when set through an editor script. I’m using:
pluginImporter.SetEditorData( “OS”, “OSX” );
This works on macOS, but not Windows. There’s no error, but the resulting meta file for the plugin is empty except for fileFormatVersion and guid. No error in console… although click on the plugin and woah…

As I type this I’m looking at the editor spewing the following two errors on repeat while the macOS plugin is selected:

[Worker0] Could not generate preview image
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

[Worker0] Import Error Code:(4)
Message: Build asset version error: assets/TestPlugin/plugins/macos/TestPlugin.bundle in SourceAssetDB has modification time of '2024-04-08T17:00:18.7728406Z' while content on disk has modification time of '2024-04-08T18:23:58.1885264Z'
UnityEngine.GUIUtility:ProcessEvent (int,intptr,bool&)

What are these? Who knows? Who cares? I’ve seen similar errors running Unity on macOS clicking on plugins. Click away, click back on the plugin and no errors. But changing settings may not be possible anymore. At this point it’s all blurring together and I don’t know what’s causing what anymore.

And these are just some of the things I’ve been running into.

Compounding all this is a common situation with Unity upgrades. So, for example, if I release the plugin for Unity 2021 LTS and set up the importer settings to the best of my ability. Someone uses the plugin and then upgrades Unity… chaos ensues. In the past, with InControl, I’ve published for every Unity LTS and even some old versions just so if someone imports, they would have reasonable plugin importer settings. This mostly works, but all goes out the window with a Unity upgrade. It’s especially bad when there’s a new architecture (Apple Silicon or ARM64) where the older Unity version doesn’t know about it. It sure would be nice if Unity just gracefully ignored plugin settings it doesn’t understand and didn’t just overwrite them with bad defaults.

Sorry to gripe, but I just really hope someone gives the plugin importer a long hard look and tries to make it a stable and sane experience for both users and asset developers. If I can’t even get it working for myself, how am I going to get it working for customers?

Your code?

In InitializeOnLoad and static ctors the AssetDatabase is not “readied” yet. Any ADB methods you use in there may not work as expeced. Put your code within this block:

EditorApplication.delayCall += () =>
{
    // AssetDatabase is fully functional here
}

Again, your code?

Within an AssetImporter the AssetDatabase again may not function as expected. You’d have to defer calls to OnPostProcessAllAssets or similar “postprocess assets” method.

The other very common possibility is simply incorrect use of AssetDatabase methods.

Are these DLLs technically required or do they benefit the customer in some way?

1 Like

Thank you for taking the time to write this all down. I really appreciate it. As a result of this & another thread, I’ve filled 4 bug reports (and found 2 more than I need to fill out) and I will be working on fixing them.

Now, to answer some of your concerns:

Indeed, it looks like asset importer won’t run until InitializeOnLoad methods returns. I’m not sure if that’s a bug or by design.

This bug was known internally for a couple weeks: https://issuetracker.unity3d.com/issues/architecture-for-windows-native-plugins-resets-to-any-cpu-when-applying-in-the-inspector-window

You can make AnyCPU native plugins for Windows - they have to have no executable code but some people used that in the past. I agree that it’s not great as default. I filled out a bug report here: https://issuetracker.unity3d.com/issues/windows-plugin-architecture-is-not-auto-detected-if-the-plugin-is-outside-the-plugin-folder

This is an artifact of the fact that StandaloneWindows and StandaloneWindows64 are two separate BuildTarget enum values, which makes the settings for each of them stored independently. Quite a spaghetti, but we are actively working to address that in a future release.

This is legacy behaviour, but I’ve created this bug report: https://issuetracker.unity3d.com/issues/windows-plugin-architecture-is-not-auto-detected-if-the-plugin-is-outside-the-plugin-folder

That said, we DO currently have some heuristics on enabling platforms, except they’re based on folder names rather than binary contents:

Assets/.../Editor - sets compatible with all editor platforms
Assets/.../Editor/... - sets compatible with all editor platforms
Assets/.../Editor/x86 - sets compatible with nothing
Assets/.../Editor/x86_64 - sets compatible with all editor platforms and sets the CPU to x64
Assets/.../Editor/x64 - sets compatible with all editor platforms and sets the CPU to x64
Assets/.../Editor/arm64 - sets compatible with only macOS editor platform and sets the CPU to x64 - OOPS, missing Windows ARM64 editor!
Assets/.../Plugins/x86 - sets compatible with Windows x86 player.
Assets/.../Plugins/x86_64 - sets compatible with Windows, Mac and Linux editors & players and sets the CPU to x64
Assets/.../Plugins/x64 - sets compatible with Windows, Mac and Linux editors & players and sets the CPU to x64
Assets/.../Plugins/arm64 - sets compatible with Mac editor and Windows & Mac players and sets the CPU to ARM64 - OOPS, missing Windows ARM64 editor!
Assets/Plugins/Android - sets compatible with Android
Assets/Plugins/Android/.../x86/*.so - sets compatible with Android, sets CPU to x86
Assets/Plugins/Android/.../x86_64/*.so - sets compatible with Android, sets CPU to x64
Assets/Plugins/Android/.../armeabi-v7a/*.so - sets compatible with Android, sets CPU to ARM 32-bit
Assets/Plugins/Android/.../arm64-v8a/*.so - sets compatible with Android, sets CPU to ARM 64-bit
Assets/Plugins/Android/.../<ANYTHING ELSE>/*.so - sets compatible with Android, attempts to autodetect architecture
Assets/Plugins/Android/.../armeabi - disables the plugin
Assets/Plugins/iOS/... - sets compatible with iOS
Assets/Plugins/AppleTV/... - sets compatible with AppleTV
Assets/Plugins/Metro/... - sets compatible with UWP
Assets/Plugins/WSA/... - sets compatible with UWP
Assets/Plugins/[Metro|WSA]/.../x86/*.dll - sets compatible with UWP, sets CPU to x86
Assets/Plugins/[Metro|WSA]/.../x64/*.dll - sets compatible with UWP, sets CPU to x64
Assets/Plugins/[Metro|WSA]/.../arm/*.dll - sets compatible with UWP, sets CPU to arm
Assets/Plugins/[Metro|WSA]/<ANYTHING_ELSE>/*.dll - attempts to autodetect architecture, but forgets ARM64 is an option - OOPS!
Assets/Plugins/Metro/.../Win80/... - disables the plugin
Assets/Plugins/Metro/.../Win81/... - disables the plugin
Assets/Plugins/Metro/.../WindowsPhone81/... - disables the plugin
Assets/Plugins/WebGL - sets compatible with WebGL
*.jar, *.aar, *.java, *.kt, *.androidlib - sets compatible with Android
*.winmd, *.config - sets compatible with UWP
*.jslib, *.bc, *.jspre - sets compatible with WebGL
*.mm, *.m, *.xib, *.swift - sets compatible with iOS and tvOS
*.bundle, *.dylib - sets compatible with macOS & all editors, AnyCPU architecture
*.xcprivacy - sets compatible with iOS, macOS, tvOS and visionOS

// After fixing https://issuetracker.unity3d.com/issues/windows-plugin-architecture-is-not-auto-detected-if-the-plugin-is-outside-the-plugin-folder:
*.dll - sets compatible with windows editor & player, autodetects architecture

I found 2 bugs while writing up this list… time well spent.

In most cases I suspect it doesn’t matter as the editor will just ignore the native plugins it doesn’t understand (like .dylibs on Windows).

That is a bug. I’ve filled two bug reports about it:

https://issuetracker.unity3d.com/issues/editor-log-spam-when-unity-with-an-editor-plugin-in-the-project-that-targets-x86-editor
https://issuetracker.unity3d.com/issues/two-variants-of-a-windows-editor-only-plugin-one-targeting-x86-and-one-targeting-x64-prevents-the-player-build

I cannot reproduce these. I am both able to use that code snippet you posted and I don’t see any console spam. I’m on 6000.0.0b15. If you are still able to reproduce, can you report a bug with a project setup to reproduce this issue?

These are bugs. If you run into any of them, please report them. We should be supporting seemless upgrading of plugins.

1 Like

It could be addressed by simply removing the x86 (32bit) build target.

I expect nobody in their right mind to target 32bit Windows these days, less so going forward with Unity 6+.
I found this article mentioning Microsoft disallowing 32bit Windows 10 OEM installations being sold by vendors in 2020 as well as the Steam Hardware Survey results of the same year which shows the 32-Bit Windows 10 users accounted for a mere 0.2%.
The 2024 Steam hardware survey doesn’t even list any 32 bit OS at all.

IMO it’s time to pull the plug on the 32-bitters. :wink:

@Tautvydas-Zilys Not all heroes where capes. I really appreciate the work you put into looking into this and finding these bugs more definitively.

Also really appreciate the heuristics list. I’ve been dealing with the plugin importer for about 8 years with InControl with it mostly working. I think the reason I ran into a fresh set of bugs is because this new project is not using quite the same folder layout. That’s simply because Visual Studio has a variable $(Platform) and I decided to use it to simplify my build settings. The variable will equal either Win32, x64 or ARM64 depending on platform. Also, I’m putting them in separate OS folders: e.g. Assets/Plugins/Windows/x64 … might be nice to account for that in the heuristics list, but I’ll reconfigure things to put them according to what’s there.

In case anything interesting pops out at you, here’s my editor script for setting up the plugin importers: Setup plugin importers in Unity · GitHub

I’m kind of curious what pluginImporter.SetEditorData( "DefaultValueInitialized", "true" ); does. I just have that in to reproduce the meta file Unity produces when setup through the inspector. ¯_(ツ)_/¯

I trigger this script manually with the MenuItem. I tried the EditorApplication.delayCall that @CodeSmile recommended (thanks!) but it seems that there’s still some readiness issue as AssetImporter.GetAtPath() returns null. Not a huge deal as this is primarily a publishing preflight step for me. I have that commented out in the script linked above.

As to the errors spewing, I’m using 6000.0.0b13 (the latest I can get in Unity Hub right now). I primarily see it running the Windows Arm64 version of Unity (which definitely seems buggier). I can get at least one “[Worker0] Could not generate preview image” error on macOS, but only if I get the “corrupted” meta files due to the InitializeOnLoad issue and then click on plugins. On Windows Arm64, it’s just open the project, wait for the editor to finish loading, click on the macOS plugin and boom. I’ve submitted a bug report with the project: IN-73259

That is a marker for editor to know whether it needs to set defaults. When you first drop in a plugin with an empty meta file or no meta file to the project, editor will check whether that tag exists and if not, apply the defaults using the heuristics I posted above. Then it sets that tag so it doesn’t do that again.

Thanks!

Fixes for these issues landed to 6000.0.0b16:

Hopefully this makes your life a bit easier trying to target multiple Unity versions with your plugins!

2 Likes

Thanks! Can confirm it’s behaving much better now in b16.

One other quirk I’ve come across in Unity 6 is that AssetImporter.GetAtPath() returns null the first time after editor launch, even if delayed or triggered manually well after everything settles. Simply making the call twice seems to be a workaround for now. ¯_(ツ)_/¯

Looking at internal code that uses that API, it seems we always do this first when running code at startup or just after the plugins are copied into the project:

AssetDatabase.ImportAsset(path, ImportAssetOptions.ForceUpdate);
var importer = (PluginImporter)AssetImporter.GetAtPath(path);

I think AssetImporter.GetAtPath() depends on the asset being imported, and it might not be at the point you’re trying to run that code.

1 Like

Thanks, that seems to do the trick. I also added ImportAssetOptions.ForceSynchronousImport for good measure and a file/directory check as AssetDatabase.ImportAsset will complain if the asset path doesn’t exist.