Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unable to use Theraot on Unity 2017.4.22f1 #160

Open
Emik03 opened this issue Aug 22, 2021 · 7 comments
Open

Unable to use Theraot on Unity 2017.4.22f1 #160

Emik03 opened this issue Aug 22, 2021 · 7 comments

Comments

@Emik03
Copy link
Contributor

Emik03 commented Aug 22, 2021

Trying to import the managed library into the Plugins folder causes the following error.

image

This error is only present when attempting to load a compatible version of the library (net20, net30, and net35), but naturally the code won't load since it is is an incompatible framework. (net40 for example)

image

Here's the Editor.log that occurs when I open the Unity project with the dll.

When I looked up this error, it may have to do something with Mono. I found someone suggesting that recompiling the library would work, but after getting the source code to compile I can confirm to say that it still doesn't work.

Tested on Windows 10, with Visual Studio 2022 Preview 3.1 and Unity 2017.4.22f1

@theraot
Copy link
Owner

theraot commented Aug 22, 2021

First of all, I can confirm this happens, sadly.

The net20, net30, net35 use the metadata format appropriate for their version. I cam't figure out what metadata Unity needs and why these versions don't provide it.

As far as I can tell, it is not Mono. I can get a Unity 2017 project with a reference to .NET 3.5 Theraot.Core to build in both MonoDevelop and Visual Studio. It still won't run on Unity.


I know this is not the greatest solution, but you can go to Edit -> Project Settings -> Player, select Experimental (.NET 4.6 Equivalent).


I would have said to use GlitchEnzo/NuGetForUnity (2.0.1) and get the Nuget, but I tried, and it is failing with a network related error (nuget.org is redirecting to HTTPS and NuGetForUnity can't handle HTTPS). You might be able to work around it by adding a custom Nuget source (I didn't try this).

And sadly, I have left behind all attempts of writing the source code in earlier C# version, so adding the source won't work either.

@Emik03
Copy link
Contributor Author

Emik03 commented Aug 23, 2021

Unfortunately I cannot upgrade to .NET 4.6 as much as I want to. I tried using the Nuget you suggested by trying and recompiling it but to no avail.

I have however ported over small bits and pieces of the source code such as IsExternalInit, but I have gotten an error of [CS0656] Missing compiler required member 'System.Type.op_Equality'. I assume that record types are completely impossible to port over to net35?

@NN---
Copy link
Collaborator

NN--- commented Aug 23, 2021

Yeah, it seems like .NET 3.5 and below cannot use records.

https://sharplab.io/#v2:EYLgtghglgdgNAFxFANnAJiA1AHwE4CmAxgPZ7oAEAggN4C+QA==

Simple record produces the code calling [System.Private.CoreLib]System.Type::op_Equality

    .method public hidebysig newslot virtual 
        instance bool Equals (
            class A other
        ) cil managed 
    {
        .custom instance void System.Runtime.CompilerServices.NullableContextAttribute::.ctor(uint8) = (
            01 00 02 00 00
        )
        // Method begins at RVA 0x2131
        // Code size 31 (0x1f)
        .maxstack 8

        IL_0000: ldarg.0
        IL_0001: ldarg.1
        IL_0002: beq.s IL_001d

        IL_0004: ldarg.1
        IL_0005: brfalse.s IL_001a

        IL_0007: ldarg.0
        IL_0008: callvirt instance class [System.Private.CoreLib]System.Type A::get_EqualityContract()
        IL_000d: ldarg.1
        IL_000e: callvirt instance class [System.Private.CoreLib]System.Type A::get_EqualityContract()
        IL_0013: call bool [System.Private.CoreLib]System.Type::op_Equality(class [System.Private.CoreLib]System.Type, class [System.Private.CoreLib]System.Type)
        IL_0018: br.s IL_001b

        IL_001a: ldc.i4.0

        IL_001b: br.s IL_001e

        IL_001d: ldc.i4.1

        IL_001e: ret
    } // end of method A::Equals

@NN---
Copy link
Collaborator

NN--- commented Aug 23, 2021

dotnet/roslyn#55812

@Emik03
Copy link
Contributor Author

Emik03 commented Aug 24, 2021

I am pleased to say that after a lot of experimenting; I ended up trying to create a blank new project, copying over files in Framework.Core and deleting some unexpected duplicates, and it somehow just works! To me this sounds like there is a small issue regarding the solution then, since all the source files seem to work just fine. I will continue to do some trial-and-error investigation and follow-up regarding this issue and let you know what is potentially wrong.

image

image

@Emik03
Copy link
Contributor Author

Emik03 commented Aug 25, 2021

I may have found the solution!

When the line shown in the following image is removed, both the isolated project I created as well as the copy of this library appear to both work. Granted, I did have to suppress the errors caused by removing this line, but it ended up not complaining about invalid metadata after that. This also explains why I got it to work in my previous post, as a fresh new project has no Nullable attribute declared and would therefore work.

image

While dodgy, you may have to create a separate project file specifically for older Unity versions.

EDIT: I have been able to also get Unity to work with an empty library that has a Nullable attribute, so it isn't necessarily this which is causing the problem. Removing the Nullable attribute is probably doing something else which is solving the issue. Can't figure out what it currently is.

@Emik03
Copy link
Contributor Author

Emik03 commented Aug 26, 2021

Okay, I think I found the cause. Apparently when nullable reference types are enabled, Unity absolutely despises generics with constraints of either interfaces, or classes. I know that Unity processes generics in a particular way during runtime as I've previously encountered silly dependency situations with generics before, so unsurprisingly this error will happen no matter where or how it is declared, ignoring accessibility, or the type of object it is on, anything.

Here are some examples of definitions that Unity doesn't like.


Example 1

A class with generic that uses interface.

public interface I { }
public class D<T> where T : I { }

Example 2

A class with generic that uses class.

public class C : I { }
public class D<T> where T : C { }

Example 3

A nested private class with generic that uses class which inherits interface.

namespace Foo
{
    internal class Bar
    {
        private interface I { }
        private class C : I { }
        private class D<T> where T : C { }
    }
}

Example 4

A private method with generic that uses class which inherits interface.

namespace Foo
{
    internal class Bar
    {
        private interface I { }
        private class C : I { }
        private void D<T>() where T : C { }
    }
}

In other words, there are 3 solutions.

  1. Remove <Nullable> attribute. (not ideal)
  2. Remove all generic constraints to interfaces/classes. (worse)
  3. Use #nullable disable [insert generic definition] #nullable enable around every generic that uses an interface constraint. (maybe?)

All-in-all, this only affects Unity so I am not exactly sure how you should proceed with this, it may be nice to create a dedicated version for older versions of Unity. I'll likely fork this library to keep up with the latest commits while removing the attribute.

I will leave this issue open in case if you have anything further to say on the matter whether that'd be a question or statement, but I think now that we understand the problem, the cause, and how to resolve it, that we can finally put this bothersome error to rest.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants