stride icon indicating copy to clipboard operation
stride copied to clipboard

Asset compiler crashes when using `System.Windows.Forms`

Open azeno opened this issue 1 year ago • 9 comments

Release Type: GitHub

Version: main branch

Platform(s): Windows

Describe the bug We have troubles building our solution with latest Stride source builds as the asset compiler crashes during the build. This crash wasn't present before and seems to be have introduced by https://github.com/stride3d/stride/pull/2082.

To Reproduce Steps to reproduce the behavior:

  1. Start Game Studio from current main branch
  2. Create a new game using Windows as platform
  3. Add a public class which inherits from System.Windows.Forms.Control, for example
using System.Windows.Forms;

namespace GameUsingWindowsForms
{
    public class SomeControl : Control
    {
    }
}
  1. Build the game

Expected behavior It shouldn't crash.

Screenshots image

azeno avatar Feb 05 '24 18:02 azeno

I cannot reproduce. I added a Forms to the project, it compiled correctly and I could run the Game.

It worked both with the Form added to the Windows app project or to the Game project.

However, you shouldn't add a form to the Game project. It isn't meant to have platform-specific code (that project is supposed to be shared between multiple platforms). In fact, I think the templates are kind of incorrect to set the target framework to net8.0-windowsfor that project as it should be net-8.0.

Can you try again after cleaning up any previous build artifacts (e.g. running git clean -xfd) or share your code somehow?

Kryptos-FR avatar Feb 05 '24 21:02 Kryptos-FR

Our setup is far more complex than just a game project and a platform specific project. I was only using this simple setup to illustrate the issue. Getting rid of the platform specific thing would be nice but unfortunately not realistic in all the scenarios we're usually in.

I'll try your suggestions later the day and upload my example project.

azeno avatar Feb 06 '24 12:02 azeno

  • Updated VS 2022 to latest and made sure all prerequisites are present (which they were)
  • Repaired VS 2022 (just to be sure)
  • Removed all USER.nuget\packages\Stride* (just to be sure)
  • Opened developer command prompt for VS2022
  • cd stride
  • git clean -xfd
  • cd build
  • dotnet restore Stride.sln
  • msbuild Stride.sln
  • cd USER\GameUsingWindowsForms
  • dotnet build
  • All good :)

Went back to our solution, dotnet build, and also all good. Jesus. Thanks for your help!

azeno avatar Feb 06 '24 13:02 azeno

Sorry, wait, I did all that with releases/4.2.0.2067

azeno avatar Feb 06 '24 13:02 azeno

Ok, now did all the steps from above (except the VS update) with master branch and the result is sadly what I initially posted: asset compiler crashes with a type load exception not finding System.Windows.Forms

Attached you find the test project I was using: GameUsingWindowsForms.zip

azeno avatar Feb 06 '24 13:02 azeno

In a quick test I modified the crashing RegisterCompilersFromAssembly method like this and it compiled fine:

private void RegisterCompilersFromAssembly(Assembly assembly)
{
    // Process Asset types.
    foreach (var type in GetSuccesfullyLoadedTypes(assembly))
    {
        // Only process Asset types
        if (!typeof(IAssetCompiler).IsAssignableFrom(type) || !type.IsClass)
            continue;

        // Asset compiler
        var compilerAttribute = type.GetCustomAttribute<AssetCompilerAttribute>();

        if (compilerAttribute == null) // no compiler attribute in this asset
            continue;

        try
        {
            ProcessAttribute(compilerAttribute, type);
        }
        catch (Exception ex)
        {
            log.Error($"Unable to instantiate compiler [{compilerAttribute.TypeName}]", ex);
        }
    }

    // Taken from https://stackoverflow.com/questions/7889228/how-to-prevent-reflectiontypeloadexception-when-calling-assembly-gettypes
    [DebuggerNonUserCode]
    static IEnumerable<Type> GetSuccesfullyLoadedTypes(Assembly assembly)
    {
        try
        {
            return assembly.GetTypes();
        }
        catch (ReflectionTypeLoadException e)
        {
            // If some types can't be loaded, this exception is thrown.
            // The [DebuggerNonUserCode] makes sure these exceptions are not thrown in the developers
            // face when they have "Just My Code" turned on in their debugging settings.
            return e.Types.Where(t => t != null);
        }
    }
}

Is the IAssetCompiler interface intended to be implemented by user assemblies? If not, wouldn't it be ok to suppress the error like above?

azeno avatar Feb 06 '24 13:02 azeno

Thanks for the small project. I can reproduce now.

Kryptos-FR avatar Feb 06 '24 16:02 Kryptos-FR

~~@azeno silly question, but how did you manage to break inside the Assets.CompilerApp? I launched the GameStudio with he debugger attached but it didn't break on that exception.~~

edit: I managed to do it.

IAssetCompiler is supposed to be available to user assemblies to be able to design custom assets. However that scenario is not fully tested (and probably missing some parts to work entirely). It will be revisited once we have proper cross-platform support and start working on the plugin system for the editor.

I think your proposed change is a good workaround for the time being.

Note for later: if the same issue arise again after the proposed quick fix, another solution would be to multi-target Stride.Core.Assets.CompilerApp to both $(StrideXplatEditorTargetFramework);$(StrideEditorTargetFramework) and adapt Stride.Core.Assets.CompilerApp.targets to call the right version depending of the user project target.

Kryptos-FR avatar Feb 06 '24 21:02 Kryptos-FR

Linking to #2034 to keep track.

Kryptos-FR avatar Feb 07 '24 08:02 Kryptos-FR