UniRx icon indicating copy to clipboard operation
UniRx copied to clipboard

Add support for .net standard to project

Open grofit opened this issue 6 years ago β€’ 53 comments

Unity recently mentioned in an article on .net update that ideally libraries for unity should be targetting .net standard profile:

The .NET Standard 2.0 profile matches the profile of the same name published by the .NET Foundation. This is a great profile to choose for a new Unity project. It is smaller than .NET 4.x and we recommend it for size-constrained platforms such as mobiles. In addition, we’ll make sure this profile works on all platforms Unity supports. If you are a developer of libraries used with Unity, this is the profile you want to target.

Given the nuget version of the project is out of date, and unity are going to be slowly phasing out the old runtime now would be a good time to update the nuget project and add .net standard support in. I would probably also suggest dropping support for anything < unity 2017 as you have older releases for that, it would make the code base simpler to maintain and build.

If it helps I have made a branch which is a large re-work of the codebase which is still not entirely finished but supports .net standard, has full test coverage with xUnit and has split the projects into a purely .net layer and a unity layer:

https://github.com/grofit/unirx/tree/pure-dotnet-and-namespaces

grofit avatar Apr 03 '18 07:04 grofit

Nice work !

It would be nice to know if @neuecc gives you the greenlight πŸ‘

RDeluxe avatar Apr 08 '18 20:04 RDeluxe

Tbh the fork is just a proof of concept I think it is more something that could be used as a basis, ultimately not much needs to change I think to support .net standard in unity, the main issue is getting unirx to consumable as a .net standard dll which would make it consumable on any .net platform (also why I have some appetite to resurrect the nuget package version). I think Unity allows this via those assembly definition things but its all a bit woolly at the moment and going forward I think there is some appetite from unity to move shared libs to pure C# projects that expose dlls rather than C# files in unity, the problem then becomes how to manage the myriad of different versions needed for different platforms etc (i.e AoT) which are currently handled via pragmas.

grofit avatar Apr 09 '18 08:04 grofit

With Unity 2018 supporting .NET Standard 2.0, I wonder if we could just use the official dotnet/reactive along with the UnityEngineBridge or not?

laicasaane avatar May 05 '18 22:05 laicasaane

This was discussed in the channel a bit, problem is:

  • System.Reactive v3.* dont seem to work in unity and version 4 is on hiatus at the moment, see their issue log for more info
  • Performance and GC is a lot worse in System.Reactive code (I have not seen this for myself but this is one thing a lot of people mention when it comes up in conversation
  • I dont think its simple to extend Observable so UniRx would have to have some other UnityObservable or something, I had to solve this in the branch I created above but even then its not ideal

I would love for this to be the case as then the amount of maintainable code shrinks, and I think it was even mentioned in another issue on here, but at the moment we are just waiting for UniRx to update or System.Reactive.

grofit avatar May 07 '18 19:05 grofit

Things seem to be working nicely using System.Reactive, although I do have some issues with AOT and System.Reactive.Linq which I assume are due to this static var: https://github.com/dotnet/reactive/blob/master/Rx.NET/Source/src/System.Reactive/Linq/Observable_.cs

Xerios avatar Jun 10 '18 19:06 Xerios

Also, I discussed briefly with the devs of RxNET, and here are some things worth mentioning:

  • System.Reactive 4.0 is out, and the community has finally gathered back up
  • According to them, performance and GC shouldn't be any worse. As a matter of fact, UniRx was based on old System.Reactive structure, along with their old architecture which has improved a lot since then.
  • System.Reactive 4.1 is the next version they'll be pushing out, with the goal of further improving performance.

Xerios avatar Jun 10 '18 19:06 Xerios

Well if you at happy enough with the new rx.net 4.* working on most devices I have a partial rework into pure .net that I can convert into some sort of rx.net for unity or something, the main task would be:

  • Remove anything that already exists in rx.net
  • Isolate Scheduler related functionality for unity
  • Make sure all unity specific functionality consumes System.Reactive based classes
  • Make sure extension methods target System.Reactive classes wherever needed

There is one thing I think most people would like to keep and that is an Observable instance that basically exposes the common System.Reactive and unity specific methods in one place, i.e Observable.EveryFrame. This was a hassle when I was trying to map over to a pure .net version as in unirx Observable was a static partial which was basically getting appended to all over the shop, and I expect something similar in rx.net. To work around this in mine I converted the unirx version to a class with static methods and just inherited a new Observable in the unity namespace which added the custom bits in, although in this scenario it may need to be more of a facade, where we create it like that but just wrap all the underlying calls to system.reactive.

Anyway I am happy to put in some of the work on a prototype if there is some appetite for it based on my .net standard port, but in terms of testing etc I could do with some of you guys to help out there.

I would also say that it may be worth splitting out certain things into other packages, like ReactiveProperty, ReactiveCollection, ReactiveDictionary, IMessageBroker etc all of these structures are great and would help people doing game dev in regular .net (i.e monogame, godot etc) so maybe that could go into some other package separate to the unity one.

grofit avatar Jun 10 '18 19:06 grofit

I think it would be best to start with System.Reactive rather than basing on UniRx. And afterwards port the unity specific functions, which should be pretty easy.

Like I said, if AOT fails compiling certain functions such as Linq namespace ( which contains a lot of necessary functions like SkipUntil TakeUntil ) then there's a high chance it will also fail compiling on various platforms, like WebGL in my case.

When I say failing to compile, I actually mean that the functions aren't parsed. So what I end up with, are some errors the moment SkipUntil, Repeat or any of those Linq functions are executed. It's worth pointing out that even with errors, it still compiles but with missing functions.

Xerios avatar Jun 10 '18 20:06 Xerios

Sounds good, keep us up to date with progress as I would love to just rely upon rx.net and just bolt on this unity stuff!

grofit avatar Jun 10 '18 21:06 grofit

Making System.Reactive AOT compatible appears to be quite challenging, especially when I'm lacking a huge portion of knowledge and experience with AOT/IL2CPP. I'll seek some help on the official rxnet slack channel.

Xerios avatar Jun 14 '18 11:06 Xerios

Hi, I try to understand what you are talking here about but I'm not much wiser after I read all. So simple question any ETA for Netstandard 2.0 support?

ledvinam avatar Jun 17 '18 10:06 ledvinam

Unless @neuecc himself gives you an ETA there isnt one, currently @Xerios is investigating if we even need Unirx any more as we can potentially use rx.net as the basis then add the unity specific stuff on in a new library (or this one if the maintainer decides to go that route and add more maintainers)

grofit avatar Jun 17 '18 11:06 grofit

There's no ETA on standard 2.0 support since neuecc lost motivation to continue working on this ( according to his blogpost ). Although he may come back, it's hard to tell, UniRx isn't his only project and it's understandable.

We might not get any additional changes anytime soon. You might've noticed that there were no proper updates for months! UniRx already works with Netstandard 2.0, so I don't see what you can get out of it.

I've tried porting Rx.NET over few days to something AOT-compatible, but every time I would end up having to remove or modify more and more features that made Rx.NET better than UniRx, eventually ending up rewriting a lot of features. Issue is mostly related to the AOT compiler that Unity currently uses, hopefully Unity devs will switch to CoreRT for their AOT compiler, which would fix most issues and allow Rx.NET to be compiled to IL2CPP properly.

Porting Rx.NET to AOT-friendly version is definitely not a one man task, and the effort will completely go to waste once AOT improvements have been implemented.

For now, the best thing to do if you need to use IL2CPP-restricted build, is to continue using UniRx. It is functional and has most Rx functions implemented. If you're building for non-IL2CPP platforms such as standalone builds, then you can use RxNET directly without any issues.

Xerios avatar Jun 17 '18 11:06 Xerios

Do you really mean it "UniRx already works with Netstandard 2.0"? When I switch to NET 4.x backend and Netstandard 2.0 I get few errors. How should I understand what you stated above?

Thanks, Marek.

ledvinam avatar Jun 17 '18 11:06 ledvinam

I've just tried it with an empty project and I don't. I've been developing using NET 4.x + netstandard 2.0 + UniRx for months now and I've never encountered any issues.

You could fork this repo and fix your specific issues yourself, but seeing the lack of activity in the Pull Requests section, I doubt anything would be merged back into this repo anytime soon.

Xerios avatar Jun 17 '18 11:06 Xerios

Hi, I had to add on few places NET_STANDARD_2_0 preprocessor. Especially there where there was defined NET_4_6 or NETFX_CORE. Can anyone fix it in repository please? Marek.

ledvinam avatar Jun 17 '18 15:06 ledvinam

To be precise it is in files FromCoroutine, TaskObservableExtensions, Tuble, IProgress, IObserver, IObservable, AsyncSubject, CancellationDisposable. Hope it helps, Marek.

ledvinam avatar Jun 17 '18 15:06 ledvinam

Create a new issue describing your bug with a way to reproduce, then wait forever in despair because no-one will come to rescue you πŸ˜€

There hasn't been a single update since December... Your best luck would be to see if one of the 25 pull requests or any of the 390 forks actually contains the fix.

In any case, as for me, I moved on to pure RxNET, so godspeed brave soul, godspeed.

Xerios avatar Jun 17 '18 15:06 Xerios

Well just compiled Built Unity Android and all works :-) So no issue with that only that perprocessors NET_STANDARD_2_0. I fixed my version and I guess I won’t be updating long time.

You have workable RxNET? with that Unity extensions on top of it?

Can you share?

On Jun 17, 2018, at 10:14 PM, Sam Megidov [email protected] wrote:

Create a new issue describing your bug with a way to reproduce, then wait forever in despair because no-one will come to rescue you πŸ˜€

There hasn't been a single update since December... Your best luck would be to see if one of the 25 pull requests or any of the 390 forks actually contains the fix.

In any case, as for me, I moved on to pure RxNET, so godspeed brave soul, godspeed.

β€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/neuecc/UniRx/issues/300#issuecomment-397885447, or mute the thread https://github.com/notifications/unsubscribe-auth/AcnLooDnhttt09c6soSoRbx8Ws3k6f5lks5t9nJDgaJpZM4TEkeM.

ledvinam avatar Jun 17 '18 15:06 ledvinam

Rx.NET works with Unity, read my comments. Any build that requires IL2CPP, doesn't.

Xerios avatar Jun 17 '18 15:06 Xerios

I see then I stick to UniRx since it is compilable after my fix also with il2cpp. :-)

Cheers.

On Jun 17, 2018, at 10:20 PM, Sam Megidov [email protected] wrote:

Rx.NET works with Unity, read my comments. Any build that requires IL2CPP, doesn't.

β€” You are receiving this because you commented. Reply to this email directly, view it on GitHub https://github.com/neuecc/UniRx/issues/300#issuecomment-397885890, or mute the thread https://github.com/notifications/unsubscribe-auth/AcnLoqjoBzkAlm9V1L7kCtkl6SnjTZXQks5t9nOtgaJpZM4TEkeM.

ledvinam avatar Jun 17 '18 15:06 ledvinam

@Xerios Any further news on this? and is there any issue on the rx.net board around anything they can do to improve this use case?

grofit avatar Jul 06 '18 14:07 grofit

Current Rx.NET bases on a lot of features that aren't supported with AOT, and making it AOT compatible means that you'll have to rework on almost half of the codebase. No wonder why neuecc started from scratch, converting the whole library is not an easy task, and keeping it up-to-date will be even harder.

Me personally, I'd wait until Unity team improves their AOT compiler.

Xerios avatar Jul 06 '18 19:07 Xerios

Is this something on the roadmap (unitys), and if it is will this hopefully mitigate the problem?

I am in a tricky spot as at the moment I need to support users of unirx and rx.net within the same codebase, and atm I am having to create a tiny rx implementation to satisfy the basic internal stuff and let the consumer pick which one they want to use, but its getting more and more painful to add new features without access to one of the given libs.

grofit avatar Jul 09 '18 09:07 grofit

@Xerios , could you point some exact classes in Rx.NET (preferably core classes) which work bad with AOT?

  1. Reflection Emit - totally disallowed
  2. Expression LINQ - possible in AOT, but better to avoid because interpreted
  3. Reflection MethodInfo Delegate.Create should work fine with link.xml. Still may try to avoid reflection.

dzmitry-lahoda avatar Nov 19 '18 11:11 dzmitry-lahoda

I did https://github.com/Xerios/AdvancedCameraControls targeting Android IL2CPP. Seems link.xml may help. Does not looks like code generation is used, just some delegate invocation(which should work, or this is a Unity runtime issue).

11-19 15:16:33.711  6589  6608 E Unity   : ExecutionEngineException: Attempting to call method 'System.Reactive.Linq.QueryLanguage::Multicast<UnityEngine.Vector2, UnityEngine.Vector2>' for which no ahead of time (AOT) code was generated.

11-19 15:16:33.711  6589  6608 E Unity   :   at InputManager.OnEnable () [0x00000] in <00000000000000000000000000000000>:0 

11-19 15:16:33.711  6589  6608 E Unity   :  

11-19 15:16:33.711  6589  6608 E Unity   : (Filename: currently not available on il2cpp Line: -1)

11-19 15:16:33.711  6589  6608 E Unity   : 


11-19 15:16:33.714  6589  6608 E Unity   : ArgumentNullException: Value cannot be null.

11-19 15:16:33.714  6589  6608 E Unity   : Parameter name: source

11-19 15:16:33.714  6589  6608 E Unity   :   at CameraController.OnEnable () [0x00000] in <00000000000000000000000000000000>:0 

11-19 15:16:33.714  6589  6608 E Unity   :  

11-19 15:16:33.714  6589  6608 E Unity   : (Filename: currently not available on il2cpp Line: -1)

11-19 15:16:33.714  6589  6608 E Unity   : 

Similar error https://forum.unity.com/threads/unity-5-0-3f2-il2cpp-problem-attempting-to-call-method-system-reflection-monoproperty-getteradapt.332335/

dzmitry-lahoda avatar Nov 19 '18 12:11 dzmitry-lahoda

Been a while since I dived into this, but as far as I remember, a lot of code related to schedulers wasn't compatible, lots of auto-generated LINQ wasn't compatible and some other things. There were some totally readable code that didn't get compiled to AOT which made things even more confusing for me. Neuecc found some rather weird but working solutions to those problems, and there were many of those around, to a point that justifies UniRx existence.

I've seen that AsyncRx.NET has been shaping itself up quite nicely, has anyone tried it with AOT ?

Xerios avatar Nov 19 '18 12:11 Xerios

Rx.NET has some interesting directive, which seems used to close generics:

#if CRIPPLED_REFLECTION
                    InfoOf(() => And<TLeft, TRight>(default, default)),
#else
                    ((MethodInfo)MethodBase.GetCurrentMethod()).MakeGenericMethod(typeof(TLeft), typeof(TRight)),
#endif

dzmitry-lahoda avatar Nov 19 '18 14:11 dzmitry-lahoda

I have pinged in the rx.net thread too but did either of you get rx.net working in unity IL2CPP (with link.xml or whatever other stuff is needed)? @Xerios @dzmitry-lahoda

grofit avatar Apr 03 '19 11:04 grofit

Nope, given up on this long time ago. I've been moving away from reactive extensions recently, in favor of pure C# and DOTS ( Unity's ECS ).

Once async streams (C# 8.0) lands in Unity, I can only imagine this library becoming redundant.

Xerios avatar Apr 03 '19 11:04 Xerios