flecs-hub/flecs-cs

NotNullAttribute error in Unity

slimshader opened this issue · 17 comments

Hi,

after importing the dll from the Artifacts section in Unity, I am getting a lot of errors related to NotNullAttribute:

Library\PackageCache\com.unity.services.core@1.4.2\Runtime\Core.Internal\Components\Threading\IUnityThreadUtils.cs(4,39): error CS0433: The type 'NotNullAttribute' exists in both 'Flecs-cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' and 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'

I realise this might be strictly Unity issue tho.

I don't use Unity so unfortunately I wouldn't know how to reproduce this to get a clear picture of the problem.

Does this have to do something with #nullable enable?

@lithiumtoast In addition to NotNullAttribute, there are many Attributes that also conflict, such as PublicApiAttribute
These Attributes should be provided by JetBrains.Annotations.cs under Msbuild.Tools
Unity defines many Attributes with the same name in the UnityEngine namespace, and the conflict occurs when the dll compiled by flecs-cs is imported into unity
There are about 12 errors with attribute conflicts

Library\PackageCache\com.unity.timeline@1.6.4\Editor\Signals\SignalEventDrawer.cs(10,6): error CS0433: The type 'UsedImplicitlyAttribute' exists in both 'Flecs-cs, Version=0.0.0.0, Culture =neutral, PublicKeyToken=null' and 'UnityEngine.CoreModule, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null'

I found out that Msbuild.Tools is deprecated, I'm not very familiar with c#, but is JetBrains.Annotations necessary? Can I delete it or rename the property?

By the way, the compilation process of flecs-cs is really smooth, and I can easily get the dll I want.
It's just that I doubt whether the dll supports unity, and unity only supports .NET Standard 2.1 and .NET 4.x
https://docs.unity3d.com/Manual/dotnetProfileSupport.html

Hello @UradaSources,

Thanks for the information.

is JetBrains.Annotations necessary?

No but then the used attributes would need to be removed at the usage sites in the code. The purpose of using these attributes is for Rider (and thus ReSharper) giving additional hints to the developer if something is weird/wrong/incorrect.

https://docs.unity3d.com/Manual/dotnetProfileSupport.html

Is there a C# compiler preprocessor variables for Unity? According to this page https://docs.unity3d.com/Manual/PlatformDependentCompilation.html there is. Something like UNITY_5_3_OR_NEWER?
Could then do conditional compilation based on this information; what do you think?

@lithiumtoast Thanks for your reply. Yes, the macros work fine, I did a simple test just now, no problem.
However, after resolving all conflicts, unity reports

Assets\Tmp\FlecsProgram.cs(38,21): error CS1705: Assembly 'Flecs-cs' with identity 'Flecs-cs, Version=0.0.0.0, Culture=neutral, PublicKeyToken=null' uses 'System.Runtime, Version =7.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' which has a higher version than referenced assembly 'System.Runtime' with identity 'System.Runtime, Version=4.1.2.0, Culture=neutral, PublicKeyToken=b03f5f7f11 d50a3a'

The net runtime supported by unity is very old, like something from the 19th century
It seems unrealistic to ask a .net7 project to be upward compatible to .net4, anyway thanks for your help.

I'm not very familiar with .net, let alone .net in unity. I found some documentation if you're interested

This is an overview of .net in unity
https://docs.unity3d.com/Manual/overview-of-dot-net-in-unity.html

I don't know why unity calls it 'API Compatibility Level' instead of 'runtime'
The latest version of unity supports .NET Standard 2.1 and .NET 4.x
https://docs.unity3d.com/Manual/dotnetProfileSupport.html

This document describes the scripting backend for Unity to run C# code
https://docs.unity3d.com/Manual/Mono.html

According to some information I have, at first, unity was written in c++, but a mono was bound so that c# could be used as a script
In order to meet various needs, they forked a mono version to make changes, which is why the supported runtime is so old
The unity team promises to gradually migrate the core code to c# in the future, and the runtime supported by that time should become more and more modern

Thanks @UradaSources

I updated the code base with a new C# project targeting .NET Standard 2.1: Flecs.Unity. The .NET7 project has been renamed to Flecs.Core.

Can you check if the Flecs.Unity C# project would work for you?

Thanks @lithiumtoast I took some time to test
It seems that flecs-cs wants people to add flecs.Core or Flecs.Unity projects directly in the vs solution
This makes it easy to handle dependencies, but it seems impossible in unity
The vs solution generated by unity is not complete, you can only view the project reference

I can only use dll, which should be the most common way to use external libraries in unity projects
I got it
Flecs.Unity.dll
flecs.dll
and I managed to get 2 dependencies
C2CS.Runtime.dll
System.Runtime.CompilerServices.Unsafe.dll
Put them directly into the Unity project, and add a Unity asmdef file to allow unsafe code
This also generates a separate project for them in the VS solution
The dependencies of these dlls should have been satisfied, the C# runtime version has no errors, and unity will no longer report any errors at runtime
But when actually calling the API, the report

NotImplementedException: The method or operation is not implemented.
System.Globalization.CompareInfo.IndexOfCore (System.String source, System.String target, System.Int32 startIndex, System.Int32 count, System.Globalization.CompareOptions options, System.Int32* matchLengthPtr) (at <605bf8b31fcb444b85176da963 870aa7>:0)
System.Globalization.CompareInfo.IndexOf (System.String source, System.String value, System.Int32 startIndex, System.Int32 count, System.Globalization.CompareOptions options, System.Int32* matchLengthPtr) (at <605bf8b31fcb444b85176da96387 0aa7>:0)
System.String.ReplaceCore (System.String oldValue, System.String newValue, System.Globalization.CultureInfo culture, System.Globalization.CompareOptions options) (at <605bf8b31fcb444b85176da963870aa7>:0)
System.String.Replace (System.String oldValue, System.String newValue, System.StringComparison comparisonType) (at <605bf8b31fcb444b85176da963870aa7>:0)
Flecs.World.GetFlecsTypeName (System.Type type) (at <d9ff5331e70d4e02bad026dfeac47078>:0)
Flecs.World.RegisterComponent[TComponent] (System.Nullable`1[T] hooks) (at <d9ff5331e70d4e02bad026dfeac47078>:0)
Test.Awake() (at Assets/Test.cs:62)

And vs issued some warnings, it seems to be related to stylecop.analyzers.unstable, I ignored it
When generating Flecs.Unity, some files generated by msbuild, such as the assembly attribute in Flecs.Unity.AssemblyInfo.cs, will report an error
After commenting them out there is no problem
I also noticed that Flecs.Unity generates some cs files besides dll files, what are they for?

I didn't know that it's not possible to add a C# project reference to the solution in Unity like it's possible in .NET Core. The documentation could be updated with the correct steps but I don't know what those are specifically. Perhaps someone else can update the README.md with instructions for Unity?

I also noticed that Flecs.Unity generates some cs files besides dll files, what are they for?

There is pre-generated files in the /Generated folder. Is that what you mean?

Thank you for your patience, getting flecs to unity seems to take more effort than expected
In addition to Generated/, there are also some cs files in bin/, like World.cs, I am not sure if they are necessary, I also noticed that they use C#10

namespace xxx;

The latest unity only supports c#9, but this should be easy to fix
After a quick search, I found some documentation
About the dll plugin
https://docs.unity3d.com/Manual/UsingDLL.html
https://docs.unity3d.com/Manual/NativePlugins.html
And some notes on the project assembly
https://docs.unity3d.com/Manual/ScriptCompilationAssemblyDefinitionFiles.html#reference-another-assembly
I'll check later, I just woke up now
and my english is poor, these texts are translated by google translate, hope there is nothing wrong

I conducted further tests, I created a standard .Net 6 console project, added the Flecs.Unity project to the solution, and added a project reference, everything was fine, and the modified HelloWorld code worked fine , printed the correct output. This should be how Flecs-cs expects people to use it
Then I reset the project to use my compiled dll instead,
C2CS.Runtime.dll
flecs.dll
Flecs.Unity.dll
System.Runtime.CompilerServices.Unsafe.dll
Everything works fine (except I need to copy the unmanaged flecs.dll to the bin folder)
In short, there is no problem with the project and dll itself, it should be some weird mechanism of unity that caused the problem

It is worth noting that NotImplementedException is thrown when calling world.RegisterComponent, and the constructor successfully creates a world object

//Create the world
var world = new World(new string[0]);
world. RegisterComponent<Position>();

The latest unity only supports c#9

Hmm. Okay, that's good to know. I would need to make some adjustments to how code is generated by default so the changes are not applied manually; that being just the namespace with curly braces.

The additional links especially this one https://docs.unity3d.com/Manual/UsingDLL.html and the section about "Debugging a DLL in Unity" would be quite topical. I'll see about downloading Unity sometime this weekend and trying it out myself.

Looking more at the stack trace posted earlier, the code that causes the exception:

return type.FullName!.Replace("+", ".", StringComparison.InvariantCulture);
. My guess is that string.Replace is not supported with 3 parameters where the 3rd parameter is the CultureInfo object instance. It would probably be worth trying to see if changing that code to just the simpler 2 parameters version would fix it.

oh! At first I thought that C2CS would use some kind of magic to call the functions in the dll. Due to a certain limitation of unity, the function signature exported in the dll could not find the implementation, so the NotImplementedException was thrown. Now it seems not so terrible, Monday I'll test some other functions. Regarding c#10, I think since only the exported dll will be used, maybe there is no need to change it to c#9?

I see, flecs_hub.flecs
not magic, just a 9000 line long DllImport file
c2cs is an amazing tool
but will DllImport seriously degrade performance?

@lithiumtoast
Great! I manually modified the Replace call and recompiled, and now it works
image

@UradaSources Thanks! I updated the README.md and the code with fixes for all problems mentioned so far.

Regarding c#10, I think since only the exported dll will be used, maybe there is no need to change it to c#9?

I changed it anyways so it uses the non-scoped file namespace for Unity generated files.

but will DllImport seriously degrade performance?

There is a very small overhead regarding calling into the C native library from C#; some folks on the Discord text channel have calculated it out to be in the nanoseconds.

@lithiumtoast Later I may add a more detailed description of "how to use flecs-cs in unity". And I'm still thinking about how to do ecs-style programming in unity, such as how to interact with unity components

I tried to write some code and found that Flecs.World lacks functions like ecs_lookup, is this Flecs.world autogenerated? Or is it a manually written wrapper? and I think this issue is completely off topic, I will study how to join the discord of flecs

Flecs.world autogenerated?

The high-level wrappers over top the bindings are not auto-generated; it's only the bindings right now that are generated.

Closing this out as using Unity is solved.