Search Unity

  1. Unity 2020.2 has been released.
    Dismiss Notice
  2. Good news ✨ We have more Unite Now videos available for you to watch on-demand! Come check them out and ask our experts any questions!
    Dismiss Notice

Problems compiling DLLs from MonoDevelop

Discussion in 'Scripting' started by guavaman, Aug 24, 2012.

  1. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    EDIT: Problem solved. See here for a how-to on setting up for DLL compiling in MonoDevelop using UnityScript.

    I've puzzled my way through getting MD to compile DLLs for UnityScript, but when I actually use those DLLs in Unity I keep getting errors which I believe are because MonoDevelop is compiling for the .Net 4.0 framework even though I have set the target framework to 2.0.

    I have duplicated exactly all the settings in Unity's own Assembly-UnityScript.unityproj and included the exact same references, but when I check my compiled DLLs with ILSpy, it tells me the runtime is 4.0 whereas the default Unity project DLLs compiled to Library/ScriptAssemblies all show as runtime 2.0 in ILSpy. Expanding the references in ILSpy, mine show mscorlib 4.0.0.0, and Unity's show 2.0.5.0. I can't figure out how to force MonoDevelop to compile to the .Net 2.0 framework.

    Even stranger, Unity's Assembly-UnityScript.unityproj says the target framework is .Net 3.5, but the final compiled DLLs show runtime 2.0 in ILSpy. Some kind of behind the scenes magic must be going on when Unity compiles its projects.

    By the way, the error is:
    Code (csharp):
    1. MissingMethodException: Method not found: 'System.Type.op_Equality`;
    Every site I've come across says this is because System.Type.op_Equality was added in .Net 4.0 and is not supported in earlier versions like Unity uses.
     
    Last edited: Sep 17, 2012
  2. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Another tidbit of information... After spending hours and hours trying everthing including the kitchen sink, I've come to the conclusion that after the intial build in MonoDevelop Unity changes its compiled DLLs in a 2nd pass (synchronization?) or perhaps it just simply recompiles not using MD the second time. The Assembly-UnityScript.dll file built in MonoDevelop goes to the folder /Temp/Debug/bin. This version of the DLL shows runtime 4.0 in ILSpy. Once you click over to Unity though, it again compiles and creates a new version of Assembly-UnityScript.dll in Library/ScriptAssemblies. This version always shows runtime 2.0 in ILSpy.

    In other words, no matter what settings I use or references I include in MonoDevelop, it ALWAYS compiles to .Net 4.0.

    EDIT: Solved! See this post below.
     
    Last edited: Aug 25, 2012
  3. JohnnyA

    JohnnyA

    Joined:
    Apr 9, 2010
    Posts:
    4,918
    Given that the options in player setting for api compatibility are for .net 2.0 and .net 2.0 subset it doesn't seem strange that the runtime is reported as 2.0.
     
  4. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Hmm, that's true. So that setting there must be the 2nd build target once Unity recompiles the solution outside MonoDevelop.

    What seems strange is MonoDevelop seems incapable of outputting a runtime 2.0 DLL.... Just did some more testing. I take that back. MonoDevelop can easily output a 2.0 DLL ... in C# but NOT in UnityScript. Only Unity's compiler can output a 2.0 in UnityScript, which means there's no solution to the bug and I have to just abandon making external libraries from my existing US code. Seems they overlooked actually implementing the Compile Target option in MD with US even though the GUI supports it.

    YET AGAIN it's a dang UnityScript flaw. I can't tell you how many times I've hit a wall in the last 2 years because UnityScript is either missing features or poorly supported as in the case of MD and its cornucopia of UnityScript oversights and bugs. All you people using C#, you have a totally different experience coding for Unity. At least the tools work right for you.

    Unity, we are paying a whole lot of money for this thing. Either fully support the language or get rid of it.
     
  5. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    This is not implemented in the Mono version of .NET.

    Whilst the operator is not implemented, you can perform type comparisons using the following instead:

    Code (csharp):
    1.  
    2. // This is C#
    3. object.Equals(typeof(A), typeof(A)) == true;
    4.  
    Another solution is to use the following:

    Code (csharp):
    1.  
    2. //
    3. System.Type TyA = typeof(A);
    4. System.Type TyB = typeof(B);
    5.  
    6. if (TyA.FullName == TyB.FullName) {
    7.    // Nope! doesn't happen because different type
    8. }
    9.  
     
    Last edited: Aug 24, 2012
  6. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Thanks for those. The object comparison worked fine and now the error is gone, but I still question whether its wise for me to use .Net 4.0 assemblies in Unity. Do you think it would cause any other problems? I imagine it would require that users install the .Net 4.0 runtime to play the game, which in itself isn't a bad thing, but since Unity doesn't run on 4.0, would it include the 4.0 runtime installer?

    Also, I'm wondering, if the Type.Equality operator wasn't included until 4.0, why do direct type comparisons work in Unity's default assemblies? Am I to assume when Unity does its 2.0 compile pass it does some auto substitution of things like that?
     
  7. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    Unity does not use .NET 4.0, it uses Mono (which is not the same thing). The version of Mono includes some of the 4.0 features, but certainly not all of them.

    I have been targeting 4 when building but using the minimal amount of features possible. The only reason that I am targeting 4.0 and not 3.5 is that I like to use default function arguments (whilst this works with .NET 3.5 it requires Mono 4). This is certainly confusing, just make sure that you test thoroughly before release!

    I always build using the MonoDevelop IDE because whilst building with Visual Studio does work, I have encountered a number of serious issues that have led to corruption of prefabs (when DLL is updated). This does not stop me from using Visual Studio for coding because it is a better IDE which doesn't crash (unlike MonoDevelop which always crashes and causes me to recode the same thing), but I never build using Visual Studio.

    I am always interested in hearing the views of other developers, so please let me know how you get on and any other issues that you encounter. This particular issue is not a Unity one though but rather one with Mono. There are issues with compiling DLLs for Unity, so please be careful!
     
  8. fholm

    fholm

    Joined:
    Aug 20, 2011
    Posts:
    2,049
    Both of those are horrible...

    Code (csharp):
    1.  
    2. if(ReferenceEquals(typeof(A), typeof(B))) { ... }
    3.  
     
  9. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    Unity does not support the new CLR thats used by .NET 4 assemblies.
    In consequence when you drop a .NET 4 assembly in, you will get an error which prevents you from running and compiling the game till the assembly is removed again.

    That might change somewhen in the future, but that future will definitely not be this year anymore as it is at earliest going to happen with Unity 4.1 if not later, as 4.0 is the same mono version as used in 3.x
     
  10. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    True. So I guess I don't have to worry about the .NET 4.0 installer then. I'm just worried about hitting other incompatibilities between .NET 4 and Mono. But the compiled DLLs do include references to mscorlib.dll v4.0.0.0 (ones I compile) and v2.0.5.0 (ones Unity compiles). These are references to Microsoft .NET dlls as far as I'm aware.

    If only they'd make the compiling process they use internally available it would solve all these issues. It seems really silly to code blindly in .Net 4.0 only to have to go into Unity and test everything for incompatibilities. The type equality operator works in Unity assemblies compiled by the engine.

    That's interesting. I figured Visual Studio would totally replace MD. I take it you haven't had the prefab corruption problem with DLLs export from MD?
    MonoDevelop doesn't ever crash on me which is good I guess, but that's about the only good thing it does do. You don't even get underlining in US and code completion 1) does not work right 95% of the time and 2) drags your system to a crawl in a class longer than a couple thousand lines or so.

    Thanks for your help! :) If I can get this thing divided up between DLLs and scripts it will save a lot of time compiling when testing.
    Actually I think this is a Unity issue because they are the ones who are supposed to support the UnityScript language and they're providing the MonoDevelop build with addins for UnityScript. The code to set a build target in US is broken and nobody but they can fix it. Plus I think it's really weird they do that double-compliation where Unity compiles differently internally than the tool they give you to code in. Being able to use things like the type equality operator in Unity assemblies and not your own makes it almost like they've got 2 versions of UnityScript, one with more features than the other. It's just weird.

    Thanks!
     
    Last edited: Aug 24, 2012
  11. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Interesting. Do you mean when you do a release build? Because it is letting me run the game in the editor with the .NET 4 assembly I compiled in MD, albeit with errors unless I implement workarounds.
     
    Last edited: Aug 24, 2012
  12. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    I was hoping to use Visual Studio as a replacement too. When I use Visual Studio prefabs acquire additional broken components when replacing the DLL with the newer compiled version. The issue is intermittent but occurs frequently when compiling with VS, the issue has never occurred for me when my DLLs compiled using MonoDevelop.

    Here is a related forum thread that I started:
    http://forum.unity3d.com/threads/144601-Unusual-issue-with-editor-script

    I have MonoDevelop open for around 8 hours at a time and find that during that time it will crash 2 or 3 times. Whilst I am not certain on the cause, the problem seems to be caused by the compile warning/error overlays. During development I have a lot of warning overlays due to missing XML comments (I write documentation once testing has been completed).

    But now I am just literally hitting the build button in MonoDevelop with no source files open, it doesn't crash at all.

    According to Dantus you do have access to another compiler provided by Unity which must be run from the command line:
    With the exception of the missing operators for comparing `System.Type` I have not experienced any other issues with targeting .NET 4 (except of course with the prefab issue with Visual Studio). Once I have finished the project that I am currently working on I am going to spend some time comparing the three compilers.
     
  13. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
  14. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,408
    Framework versions 3.0 and 3.5 were purely updates to the libraries - adding WCF/WPF/WF, LINQ, and so on; they didn't change the actual CLR, and so still use runtime 2.0. Framework 4.0 changed the CLR which is why its assemblies are incompatible.

    Anyway, I'm not sure why you're having trouble; I've got at least one externally-compiled UnityScript DLL, and Unity (3.4.2) picks it up with no problems.

    Which versions of Unity and Monodevelop are you using?

    How did you go about setting the target framework in MD?
     
  15. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    @superpig I have set the target framework for my DLL project using the project options box in MonoDevelop to "Mono / .NET 4.0" which seems to be working perfectly for me at least. The only reason I am targeting this (as opposed to Mono / .NET 3.5) is that I require default function arguments which do not appear to be otherwise available.

    Would you mind shedding a little light on that for me?
     
  16. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    With Visual Studio it is possible to compile a DLL to target .NET 2.0 runtime whilst using the C# 4.0 compiler. I am wondering if this is possible with MonoDevelop...
     
  17. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Okay after many more hours of fiddling and fuddling around, I finally found a solution!

    I tracked down Unity's internal UnityScript compiler. It's at C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\unity\us.exe. Figuring out how to use it was a lot of head bashing, but then I decided to see if the Unity log was any help and lo and behold everything I needed was in there. When Unity imports, it logs everything its doing and told me just about all the command line arguments I needed to compile exactly like the Editor does.

    Here's a batch file you can place within your external solution project folder. It will compile all the JS files within that folder (and subfolders I believe) into a .NET 2.0 DLL which it will put in bin\Debug. Edit: It now copies the .DLL and .MDB to a folder you choose in your UnityProject/Assets folder. It also includes instructions on integrating with MonoDevelop so you can do your final compile directly to your game folder.

    PHP:
    @echo off
    REM by guavaman 
    (http://forum.unity3d.com/members/12523-guavaman) 8/25/2012

    REM This batch file should be placed in project directory with the .js files
    REM Uses Unity
    's internal compiler to compile a DLL and MDB from a directory of .js files
    REM and copies them to a target directory.

    REM NOTE: Make sure your source directory path (the current directory) has no spaces in it because quotes will not work to contain it.

    REM Workflow:
    REM You can add this to MonoDevelop as a menu item in your project so you can compile
    REM normally in MD for error checking, then once you'
    re done and you want a final DLL,
    REM run the menu item Project -> Compile to Unity.
    REM To install in MonoDevelop as a menu itemgo to MonoDevelopproject optionscustom commandsclick "(Select a project operation)" and change it to "Custom Command".
      
    REM NameCompile to Unity
      REM Command
    compile.bat
      REM Working Directory
    : ${ProjectDir}
      
    REM Check "Run on External Console"

    REM ---- YOU MUST EDIT THESE VARIABLES -----

    REM User defined variables Set these variables based on your installation
      REM TARGET_DIR 
    the directory to which the final .dll and .mdb file should be copied
      REM Target directory should be somewhere within REM your Unity project
    \Assets directory.
    set UNITY_INSTALL_DIR=C:\Program Files (x86)\Unity
    set TARGET_DIR
    =C:\PATH_TO_YOUR_UNITY_PROJECT\Assets\Assemblies

    REM Add additional DLL references 
    if necessary
    REM Example
    :
        
    REM set ADDITIONAL_DDLS=-r:"FULL_PATH_TO_DLL\Assembly.dll" -r:"FULL_PATH_TO_DLL\Assembly.dll" -r:"FULL_PATH_TO_DLL\Assembly.dll"
    set ADDITIONAL_DDL_REFS=

    REM ---- DO NOT CHANGE ANYTHING BELOW THIS LINE ----

    REM Get the directory name
    ::setlocal enableextensions,enabledelayedexpansion
    SET CDIR
    =%~p0
    SET CDIR
    =%CDIR:~1,-1%
    SET CDIR=%CDIR:\=,%
    SET CDIR=%CDIR: =_%
    FOR %%
    a IN (%CDIR%) DO SET "PROJECT_NAME=%%a"
    SET PROJECT_NAME=%PROJECT_NAME:_= %

    REM Set up other varabiles
    set SOURCE_DIR
    =%~dp0
    set OUTPUT_DIR
    =%SOURCE_DIR%bin\Debug
    set UNITY_DLL_DIR
    =%UNITY_INSTALL_DIR%\Editor\Data\Managed
    set MONO_PREFIX
    =%UNITY_INSTALL_DIR%\Editor\Data\Mono
    set MONO
    =%MONO_PREFIX%\bin\mono.exe
    set MONO_PATH
    =%MONO_PREFIX%\lib\mono\unity
    set MONO_CFG_DIR
    =%MONO_PREFIX%\etc

    REM Compile
    echo Compiling...
    echo 
    Compiling... > compile_log.txt
    "%MONO%" %MONO_OPTIONS% --runtime=moonlight --security=temporary-smcs-hack "%MONO_PATH%\us.exe" -debug -target:library -i:UnityEngine -i:System.Collections -base:UnityEngine.MonoBehaviour -nowarn:BCW0016 -nowarn:BCW0003 -method:Main -out:"%OUTPUT_DIR%\%PROJECT_NAME%.dll" -x-type-inference-rule-attribute:UnityEngineInternal.TypeInferenceRuleAttribute -define:UNITY_3_5_5 -define:UNITY_3_5 -define:UNITY_EDITOR -define:ENABLE_PROFILER -define:UNITY_STANDALONE_WIN -define:ENABLE_GENERICS -define:ENABLE_DUCK_TYPING -define:ENABLE_TERRAIN -define:ENABLE_MOVIES -define:ENABLE_WEBCAM -define:ENABLE_MICROPHONE -define:ENABLE_NETWORK -define:ENABLE_CLOTH -define:ENABLE_WWW -define:ENABLE_SUBSTANCE -r:"%UNITY_DLL_DIR%\UnityEngine.dll" -r:"%UNITY_DLL_DIR%\UnityEditor.dll" %ADDITIONAL_DDL_REFS% -i:UnityEditor -srcdir:%SOURCE_DIR% >> compile_log.txt

    REM Check 
    if compile was completed successfully
    IF errorlevel 1 (
      echo 
    Compile failedSee %SOURCE_DIR%\compile_log.txt for details!
      echo 
    Compile failed! >> compile_log.txt
      
    GOTO END
    ) ELSE (
      echo 
    Compile completed!
      echo 
    Compile completed! >> compile_log.txt
    )

    REM Copy the files to target directory
    echo Copying files to target folder...
    echo. >> 
    compile_log.txt
    echo Copying files to target folder... >> compile_log.txt
    echo xcopy "%OUTPUT_DIR%\%PROJECT_NAME%.*" "%TARGET_DIR%\" /Y >> compile_log.txt
    xcopy "
    %OUTPUT_DIR%\%PROJECT_NAME%.*" "%TARGET_DIR%\" /Y >> compile_log.txt
    IF errorlevel 1 (
      echo File copy failed! See %SOURCE_DIR%\compile_log.txt for details!
      echo File copy failed! >> compile_log.txt
     MonoDevelop.
    ) ELSE (
      echo .DLL and .MDB copied to %TARGET_DIR%!
      echo .DLL and .MDB copied to %TARGET_DIR%! >> compile_log.txt
    )

    :END
    This has nothing to do with the .unityproj options so don't expect any settings from MonoDevelop to carry over.

    I can't believe it was this tough to get a proper DLL compiled from UnityScript that won't choke on things like .NET 4.0 incompatibilities. Maybe I should make a small guide.

    Oh yeah, one EXCELLENT side effect of compiling like this is that you get a .MDB file automatically with no need to use PDB2MDB, which breaks on anything with an IEnumerable in it including MonoBehaviour.
     
    Last edited: Aug 25, 2012
  18. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Glad to hear. Still, backup, backup, backup! :)

    Yes, I assumed it would be there somewhere and I've been digging all day long. Finally found out how to make it work! Now I'll have to see if I can get a little more integration with MD.

    It works for me too in C#. It only fails in UnityScript.
     
  19. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    It is picking it up fine, but depending on what you do in the code you may or may not get errors. For example, the issue with the missing type comparison operator. There are also some issues like having to explicitly type System.Type whereas just Type would work before.

    Unity latest. 3.5.5f3, MonoDev 2.8.2, came with Unity.

    Through the GUI, project options, General. I've also fiddled with everything possible inside the .unityproj files.
     
  20. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    I have been experimenting and have found some points of interest (at least to me):

    Point 1 MonoDevelop uses the Microsoft .NET compiler when used on Windows from the framework associated with the target platform.

    When target is "Mono / .NET 3.5" it uses "C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe"
    When target is "Mono / .NET 4" it uses "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe"

    Point 2 Visual Studio always uses the compiler "C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe" regardless of the target framework.

    Point 3 Despite using the latest C# compiler, Visual Studio links to the targeted framework libraries (as expected). This means that new language features of C# can be used in conjunction with older versions of the .NET framework.

    To me it seems that MonoDevelop should be following suite by always using the newer compiler, whilst using the specified target framework.

    I have been comparing the build command line used by Visual Studio and MonoDevelop and am confused as to why one causes me issues with Unity, whilst the other doesn't (when targeting .NET 4 from both IDEs). For some reason the MonoDevelop version works and the Visual Studio one causes issues with prefabs.

    Note: I have re-ordered command arguments and placed onto separate lines for easier comparison.

    MonoDevelop : Target = Mono / .NET 4
    Code (csharp):
    1.  
    2. C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe
    3. /noconfig
    4. /warn:4
    5. "/define:TRACE"
    6. /optimize+
    7. "/out:C:\TestLibraries\TestEditor\bin\Release\TestEditor.dll"
    8. /t:library
    9.  
    10. /nologo
    11.  
    12.  "/r:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll"
    13.  "/r:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll"
    14.  "/r:C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEditor.dll"
    15.  "/r:C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll"
    16.  
    17.  /fullpaths
    18.  /utf8output
    19.  
    MonoDevelop : Target = Mono / .NET 3.5
    Code (csharp):
    1.  
    2. C:\Windows\Microsoft.NET\Framework\v3.5\csc.exe
    3. /warn:4
    4. "/define:TRACE"
    5. /optimize+
    6. "/out:C:\TestLibraries\TestEditor\bin\Release\TestEditor.dll"
    7. /t:library
    8.  
    9. /nologo
    10. -nostdlib
    11.  
    12.  "/r:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll"
    13.  "/r:C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll"
    14.  "/r:C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEditor.dll"
    15.  "/r:C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll"
    16.  
    17.  /fullpaths
    18.  /utf8output
    19.  
    Visual Studio : Target = .NET 4
    Code (csharp):
    1.  
    2. C:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe
    3. /noconfig
    4. /nowarn:1701,1702
    5. /warn:4
    6. /define:TRACE
    7. /optimize+
    8. /out:obj\Release\TestEditor.dll
    9. /target:library
    10.  
    11. /nostdlib+ /errorreport:prompt
    12.  
    13. /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\mscorlib.dll"
    14. /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.Core.dll"
    15. /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\.NETFramework\v4.0\System.dll"
    16. /reference:"C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll"
    17.  
    18. /debug:pdbonly
    19. /filealign:512
    20.  
    Visual Studio : Target = .NET 3.5
    Code (csharp):
    1.  
    2. C:\Windows\Microsoft.NET\Framework\v4.0.30319\Csc.exe
    3. /noconfig
    4. /nowarn:1701,1702
    5. /warn:4
    6. /define:TRACE
    7. /optimize+
    8. /out:obj\Release\TestEditor.dll
    9. /target:library
    10.  
    11. /nostdlib+ /errorreport:prompt
    12.  
    13. /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\mscorlib.dll
    14. /reference:"C:\Program Files (x86)\Reference Assemblies\Microsoft\Framework\v3.5\System.Core.dll"
    15. /reference:C:\Windows\Microsoft.NET\Framework\v2.0.50727\System.dll
    16. /reference:"C:\Program Files (x86)\Unity\Editor\Data\Managed\UnityEngine.dll"
    17.  
    18. /debug:pdbonly
    19. /filealign:512
    20.  
    Point 4 According to the MonoDevelop settings, Unity will use MonoDevelop to build project when debugging. See "Tools -> Options -> Unity -> Debugger"

    These are more notes than anything, but perhaps there is something hidden in here somewhere :p
     
  21. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Do you have a simple repro case for the problems you got with Visual Studio DLLs containing Unity components?

    e.g.
    1) Build a DLL with a component in it;
    2) Create a prefab containing a GameObject using the component;
    3) Modify the component in the DLL, rebuild it;
    4) Reopen Unity and... what happens?

    I ask because this all works fine for me, building with Visual Studio 2012, targetting framework 3.5, with Unity 3.5. There were definitely problems with Unity 3.3ish a couple of years ago, but from my perspective the problems were fixed over a year ago and it's worked fairly well since then.

    I tried adding fields to an existing component used both in a prefab, and in the scene, as well as adding more components. You do need to be careful with meta files - especially, you never want to delete the DLL as Unity will then delete the meta file, and when it gets recreated it may have a different GUID. So even though it's a generated file, you still want to add it to source control.
     
  22. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    @gfoot I do not close Unity to build my DLLs during development, I simply overwrite them with the newer versions using a post-build command (I use the same technique with both MonoDevelop and Visual Studio). This is similar to what would happen when updating from the asset store, the old DLLs get overwritten with the newer ones.

    Your steps to reproduce the problem are very close:

    1) Unity already open with a project that contains a DLL with a component in it.
    2) Create several GameObject prefabs that use the component.
    3) Save Project and exit and reload to ensure that prefabs were saved (for fair test).
    4) Make some changes to DLL and rebuild and overwrite DLL.
    5) If the intermittent problem has occurred this time, each prefab will contain the component as specified, plus an additional title-less component that just contains the default values.

    Each time the issue occurs, an additional broken component is accumulated. If unnoticed you have to remove a LOT of broken components that compare with `null` if checked using a script.

    In the project that I use to test my editor extension I do not use source control (unless I am testing something related to source control).

    I am actively experimenting with this (especially now that it seems MonoDevelop was using the same compiler all along!?) I want to see if I can find the one-off cause that is seemingly intermittent. If I can come up with a case that fails every time then I will attach it to a forum post here. I have been unable to reproduce the issue from the ground up with a new DLL and project.
     
  23. tornadotwins

    tornadotwins

    Joined:
    May 21, 2008
    Posts:
    308
    Glad you figured out your problem. I haven't figured out mine, but with each and every search I end up at this post, so I thought I'd ask here:

    - I build my DLL in MonoDevelop
    - I can't put the output directory to my assets folder, because that would move the UnityScript / UnityEditor DLLs as well causing major mayhem.
    - So instead I tried using Custom Commends (after-build commands), but I'm not getting any files copied over to a different direction.

    I'm on Mac, and not sure what syntax to use to copy files. Everything I've googled doesn't work. Anyone got some handy tips??

    (I saw your batch file pasted as PHP code, but it's a little beyond my understanding and it's probably Windows only...)

    -TT
     
  24. superpig

    superpig

    Drink more water! Unity Technologies

    Joined:
    Jan 16, 2011
    Posts:
    4,408
    Can't you turn off Local Copy for those references? Right-click them in MD and untick 'Local Copy.' Then you should be able to drop the output directly into your Assets folder without those other references being copied through as well.
     
  25. tornadotwins

    tornadotwins

    Joined:
    May 21, 2008
    Posts:
    308
    Well! That was easy! I didn't know you could do that... haha. Makes total sense.

    I noticed by the way that the bug in post-build custom commands is the fact that it doesn't like spaces in file paths, even when the path has "quotation marks" around them. Very odd.

    But this fixes it as well, thanks SuperPig!

    -TT
     
  26. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    @Tornadotwins

    How is your workflow with MD exporting DLLs? I constantly have to close MD because it keeps locking the DLL files I copy over to the final path. I'm wondering if it's because I'm copying from the compile folder after instead of building directly into the game project folder like you are.

    You don't sound like you need it anymore, but in order to copy files from the After Build command, at least on Windows you put something like:

    xcopy "SOURCE" "TARGET" /Y
    and make sure to check "run on external console"

    I don't know if this will work on Mac or not, but the MD console doesn't seem to be the same as a Windows console as there are many Windows commands that don't work like copy and dir.

    The batch file was only useful if you were trying to compile UnityScripts into dlls, not CS, and I doubt very much it would run on a Mac. Anyway, since I'm having to use the external mono.exe + us.exe to compile my UnityScript files to .Net 2.0, I'm kind of bypassing MonoDevelop's compile. It's a bit clunky, but at least I'm not going to get a bunch of errors in Unity because of .Net incompatibilites.
     
  27. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    This probably won't help you any, but its interesting that when Unity compiles it is a completely different process:

    Compiler: C:\Program Files (x86)\Unity\Editor\Data\Mono\bin\mono.exe
    It also invokes one of these:
    UnityScript: C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\unity\us.exe
    C Sharp: C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\unity\smcs.exe

    And the mscorlib.dll referenced in the final compiles is the one in C:\Program Files (x86)\Unity\Editor\Data\Mono\lib\mono\unity\mscorlib.dll

    How were you able to determine the command line used by the compiler in MD? I'm curious to see how it's compiling from within MonoDevelop on UnityScripts. I've come up with a whole system to circumvent MD's compile involving a couple of C# programs to help automate the process using the built-in Unity compilers but it is a little clunky compared to just pressing F7.
     
    Last edited: Aug 29, 2012
  28. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    1. Select "Tools -> Options -> Build (tab)"
    2. Ensure that "Log verbosity" is set to "Normal"
    3. Click OK and rebuild a project (selecting build will not work if your project is already up to date)
    4. Click the status panel button that resembles: (-) # /!\ #
    5. Ensure that "Build Output" is toggled
    6. Scroll through build output on right side of "Error List" panel

    I do not use UnityScripts myself because I much prefer C# so I *should* be okay with using the .NET compiler. I have been experimenting with the project settings in Visual Studio and found that "Make COM Visible" was set by default when creating the project using MonoDevelop (which is not default for Visual Studio projects). I turned this off and the issue with prefabs has not yet occurred - early days ;-) perhaps.

    Obviously it is a different story for UnityScript, but C# should compile (with Visual Studio) and be usable with Mono because Mono claims to be fully compliant with .NET 3.5 and the generated code is IL. When using Visual Studio it is even possible to take advantage of the latest language features of C# 4 whilst still targeting .NET 3.5 because those features do not actually depend upon .NET 4 framework nor the .NET 4.0 runtime (they are just syntax candy, like default function parameters for example).

    When targeting .NET 3.5, the .NET 2.0 runtime is used because .NET 3.5 did not introduce a new runtime. When targeting .NET 4.0 you are using the .NET 4.0 runtime.

    This is very confusing, especially given the way in which Microsoft have used version numbers! At the start of the week I was blissfully unaware that C# 4 was .NET 4. When actually you have the language (C# 4.0), the runtime (.NET 2.0 for safeness with Unity) and the framework (.NET 3.5 is latest framework for .NET 2.0 runtime - though not all classes are available for Mono).
     
  29. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Very odd. I've done this before and saw no useful information in the output. Suspicious, I tried compiling a C# file and sure enough, the command line output showed up like you said. UnityScript files do not show anything useful when compiled, even with build log verbosity set to Diagnostic (highest):

    Much smarter to use C#. The tools they give us for US don't even work right. It's getting tiresome. If my project weren't so big I'd try to convert it all to C#, but then that'd probably also require a bunch of shuffling with references in all the scene files, libraries, and prefabs to get them to link back correctly. Actually, I'm facing this task right now as I finally try to switch most of my classes over to using the .DLL files I've been working on all this time. Adding the DLL and deleting the old script file doesn't work as Unity loses the connection to the class even though the name is the same and leaves all the prefabs and scene objects with plain Monobehaviours with serialized data where the old MB extended classes used to be.

    I hope the .COM visible solved your problem. I'm curious to know in the coming days/weeks if you experience any problems as I am positive I will not be doing another project in US. :)

    This is some good info, thanks! I was unaware about the skipped runtime version.
     
  30. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Actually I've discovered that MonoDevelop's UnityScript compile command line is hard coded into the DLL at Unity\MonoDevelop\Addins\BackendBindings\UnityScript\UnityScript.MonoDevelop.dll under UnityScript.MonoDevelop.ProjectModel.WriteOptionsToResponseFile(). I noticed it's missing some options which are specified on Unity's internal compiler such as the -nowarn tags to squelch the annoying bogus warnings. Also, interestingly, the mscorlib.dll that's referenced in this DLL is version 4.0, which may explain why everything compiles to .NET 4.0 when using UnityScript. (In Unity's compiler, the mscorlib.dll it references for the builds is version 2.x which is stored in the Unity\Editor\Data\Mono\lib\mono\2.0). However there are no local copies of mscorlib.dll in any MonoDevelop folder, so it must be using the copy in C:\Windows\Microsoft.NET\Framework\v4.0.30319

    So far I have been unsuccessful in decompiling and recompiling the dll (ILSpy simply does not output usable code! Scads of illegal things it tries to do like calling a constructor of a base class directly within a method...). The intended result would be to 1) silence the bogus warnings by adding in the -nowarn lines and 2) force it to use mscorlib.dll version 2.x. This way I'd be able to just use MonoDevelop to output my DLLs without having to resort to the unwieldy roundabout setup I've created.
     
    Last edited: Aug 29, 2012
  31. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    Maybe email support@unity3d.com and alert them that the command line is incorrect - they may be able to fix it in a future release, if not make it configurable.
     
  32. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Okay, will do. I don't expect any action though as exactly ZERO bugs I've reported to unity in the last 3 years have been fixed.

    EDIT: I think some of the assumptions I made below are wrong. I totally forgot about the asset database, which is probably a critical component in the mix. I'm starting to think I may have to do it through a bunch of add component, copy data, delete orig component. I guess I would have to first add all the components and copy serialized data on prefabs, go through every scene copying changed serialized data from the prefabs, then finally delete the component from the prefabs.

    On another note, does anybody know where to begin with the process of replacing references on prefabs and scene objects with new scripts? I'm trying to move all my loose scripts into DLLs. So far I've got a fully compiled set of DLLs created from modified versions of all my scripts in another folder. These DLLs contain replacements for all the MonoBehaviour classes I use. I want to move these DLLs into Assets/Assemblies and have Unity import them, ultimately for the DLL MonoBehaviours to replace the references to all the loose scripts. Obviously this is not a trivial task. (Unity will lose all references once the loose scripts are deleted.) I'm thinking the key would be to manually change all references in all prefabs and all scene objects to point to the DLL versions of every class before I delete the loose scripts. So far I've found these tools that might be of help to me:

    AssetDatabase.GUIDToAssetPath
    Using External Version Control Systems with Unity

    Probably doing this from within Unity using a script would be the best way, but I just haven't been able to find a complete set of functions to get at what I need. The other option is doing this manually.

    By enabling the .meta file creation, Unity will create meta files that contain a GUID for each asset. I assume this GUID is used for the internal references in prefabs as I find it inside the .prefab file when viewing it in a text editor. The .prefab file also contains a reference to the original asset (script) location as well as a reference to a cache file in the Library folder. The prefab also does not contain any named class references, instead the referenced Library file contains the actual named references to the class. (So maybe I need to both update the .prefab and the library file at the same time?)

    I'm guessing that if I were to change a MonoBehaviour reference on a prefab to another class's GUID and location, that might update the reference so long as the two classes have exactly the same serialized property fields.

    There are a couple of problems though. With a MonoBehaviour that resides inside a DLL, Unity creates an entry with a little drop down that reveals the MonoBehaviours that you can then use. However, I don't know if these individual MonoBehaviours inside the DLL have their own GUID or just use the GUID of the DLL itself or if there is any other reference that might point it to the right class.

    The other problem is one of simply editing the binary .prefab and Library cache files. Usually the new path to the dll asset will be longer or shorter than what was already in the file, so that means changing the length of the binary file which would require that I know something about the .prefab file format.

    Also, I'd need to know where in-scene objects are stored... I suppose within the scene file.

    Actually this whole process would be useful in converting entire projects to C# as well, which I very well may end up doing in the end.
     
    Last edited: Aug 30, 2012
  33. gfoot

    gfoot

    Joined:
    Jan 5, 2011
    Posts:
    550
    The DLL has only one GUID.

    Regarding the library cache files, and asset database, turn on "external version control" support, so that all the inter-object references are stored in meta files instead. Then the Library directory is just a cache of preimported data - if things get knotted, you can just delete it and let Unity recreate it.

    The meta files are text-based and it's easy to see the GUID of an object there.

    You also want to turn on text-based asset serialization, at least while you fix up the references. It's a pro-only feature. With it turned on, you can clearly see how Unity references other assets by GUID, but also stores a fileID and a type code. For .cs files outside DLLs, the fileID seems to always be 11500000, but for classes defined in a DLL it looks like it uses different (negative?) numbers for each class in the DLL. I don't know the meaning of these numbers, but I presume there is a strong one because it must somehow be linking the class name to the number. I can't see a table anywhere. I hope the number is not just a 32-bit hash of the class name, as that would be quite vulnerable to clashes.

    In any case, it's simple to change a .cs file reference into a reference to a class in a DLL just by editing the (text) prefab file. Even in the binary format, I'd expect the 32-bit fileID to appear in a hex dump just before the GUID, and the width of the data is the same either way, so you should be able to make the changes.

    Indeed, and text-based serialization works here too.

    That's interesting.

    Anyway, the technique above seems to work - the tricky bit is finding out what fileID you need to use for each class, which is obvious if you just try applying the DLL component to a test GameObject but not so practical to automate outside Unity. Maybe you could use an empty Unity project with a script to apply every class from the DLL to individual, named GameObjects, so you can then construct a fileID index.

    A quick web search also turned up this thread - same problem, no posted solution, but maybe it's worth asking what he figured out: http://forum.unity3d.com/threads/125011-Question-about-m_Script-in-YAML-Unity-prefab-format
     
  34. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Aha, this is what I needed! I knew about the version control setting, but I didn't realize this feature existed. This is excellent not only for what I'm doing now but could really help in the case of serialized data corruption problems.

    I just did a little test and changing the reference works. I never expected it to be this straightforward. Excellent.

    I think this approach will be fine. It won't take that long to build a table from all my MonoBehaviours. I have ~160 of them or so.

    Thanks for the link! I'll ask him if I can't get this working, but it looks pretty straightforward from here. And thanks again for taking the time to go into such detail. This is most helpful! :)
     
  35. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Oh boy... New problem... I was doing some tests and found that Unity is unable to recognize classes extended two steps from MonoBehaviour if each class resides in a different DLL. Tested in both C# and UnityScript.

    Example:

    AssemblyA.dll
    class BaseClass : MonoBehaviour { void Start() {} }

    AssemblyB.dll (compiled w/ reference to AssemblyA.dll)
    class ExtendedClass : BaseClass { void Start() {} }

    Import both DLL files into Unity.

    AssemblyA shows up in the inspector with a dropdown which includes BaseClass. BaseClass can be dragged onto gameobjects, the component on the gameobject shows up in the inspector as BaseClass.

    AssemblyB shows up in the inspector with no dropdown. The only way to add the contained class to a gameobject is with a script: gameObject.AddComponent(ExtendedClass). However, the component on the gameobject shows up as Script. This makes it impossible to tell what component you are viewing.

    I built my new structure for using external DLL's as follows: (listed in compile order)
    Utility classes
    Base MB classes (extend MonoBehaviour, contain all field/property definitions, stub methods, reference to Utility)
    Extended MB classes (extensions of base classes, contain all methods [game code], attached to game objects, separated into various dll's by category, reference to Utility and Base)

    I separated the MonoBehaviours into base and extended so I could leave my existing code and pass around the base classes without any of the extended classes being dependent on each other. I could then split up my extended mb classes (where most of the game code is) into smaller chunks so compiling would be quick for whatever I'm working on at the moment.

    But if I can't find a way around this MonoBehaviour inheritance issue, I think my whole plan is going to go up in smoke. Anyone seen this before? And if not, maybe you can suggest a different approach to my structure that doesn't require the base classes?
     
    Last edited: Aug 30, 2012
  36. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    Oh no!!!!!! you are absolutely right, I was able to reproduce the exact same problem.

    You should definitely submit a bug report.
     
  37. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    I'll do that. In the mean time I was thinking there might be a way to work around it by using two editor scripts, one to assign the monobehaviours to game objects and the other to make make the display show the class name like it used to. But before I got to that, I noticed something troubling in the serialized data in the Scene file:

    m_Script: {fileID: 956415588}

    You'll notice there are no GUID or type fields as in a normal entry. The scene file saves and loads okay, but with no GUID I don't imagine it would keep the link to the DLL in the long run. I tried to manually add the GUID of the DLL and type = 1 and on the next load the component just showed MonoBehaviour missing.

    Going back to the version before I added the GUID, I tried to make a prefab out of the object... Once I did that, the inspector showed "Type Mismatch" in the field next to Script. When viewing the .prefab file, the line is now: m_Script: {fileID: 0} It completely lost the reference. I have a simple Debug.Log() in the class that writes out a couple of variables from the base class and the extended class, and once I hit play I got:

    Fatal Error
    The file "Memory Stream" is corrupted! Remove it and launch Unity again.
    [Position out of bounds!]

    There are a bunch of problems and it's not going to work this way.
     
  38. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    When I was experiencing broken prefabs "Type Mismatch" was appearing in the field next to Script sometimes. I found that when I saved the scene and reloaded the project, it just went "Script not found" (or words to those effect)
     
  39. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Maybe you were experiencing the same thing. Perhaps the GUID or FileID was changing when you reimported the DLL? If it happens again, maybe you should check the .prefab file and see if fileID changed to 0 or if the GUID is gone.
     
  40. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Re: MonoBehaviour inheritance spanning multiple DLLs problem

    Well, I've found a sort of disgusting workaround using ILMerge from Microsoft to merge the BaseClasses.dll and all the other extended classes dlls together to form one combined DLL. Because both the base classes and the extended classes are in the same DLL, Unity can see the MonoBehaviours and it works correctly. You end up with one gigantic DLL with all your classes inside it, but at least Unity doesn't choke on them.

    A couple of things about using ILMerge:
    1) You need all the other dependencies to be in the same folder as the merging such as UnityEngine.dll, UnityEditor.dll, and Boo.Lang.dll and UnityScript.Lang.dll in the case of UnityScript compiled DLLs.
    2) ILMerge can output merged PDB files (just don't specify the /ndebug switch).

    In my case, I haven't yet figured out how to get a PDB file out of Unity's command line compiler as it always gives MDB files which ILMerge can't merge. Previously I was happy the compiler was outputting MDB files because I had problems with PDB2MDB, but now I need PDBs if I am to use ILMerge. Anyway, I'll try to figure this out next.

    Sadly, this adds yet two more batch processing steps every single time I want to compile a script. Base classes must be merged with all extended classes and then that combined DLL copied to Unity. All this means slower compiles when speeding up my annoying compile times was the whole point of this restructuring. Still, it's faster than recompiling everything every time like Unity does by default.

    Man, this thing is quickly becoming a big time frankenstein!
     
    Last edited: Aug 31, 2012
  41. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    I wanted to better understand parts of the YAML files Unity generates before I go forward with my attempt to replace all references across my project with classes inside my DLL. Specifically, I wanted to understand how component references work in .unity and .prefab files.

    Example:
    m_Script: {fileID: 302420156, guid: aeb7d86900e748345a354f4ffd0e3311, type: 1}

    Here are my findings:

    guid:
    guid is a unique identifier of a file created automatically by Unity for every file.
    guid is used as a reference to point to a file.
    When used in combination with fileID, the two provide a reference to a particular component in a particular file.

    fileID:
    fileID is an identifier for an individual component created automatically by Unity.
    fileID is used as a reference to point to a particular component.
    Every component in every file has a fileId (in prefab files, scene files, script files).
    Each fileID is unique within a file, but not across files.
    If no GUID is defined, fileID points to a component in the current file.
    If a GUID is defined, fileID points to a component in the file referenced by the GUID.
    fileID generation for MonoBehaviour-based classes within a DLL seems to be based on the namespace and class name. * See below *

    type:
    1 seems to stand for Identity. Appears in m_Script: entry which defines the component.
    2 seems to stand for Object Reference. Appears in serialized data if a reference is made.

    ---------------------

    fileId generation within a DLL:

    I've attempted to determine how fileIds are generated for MonoBehaviour-derrived classes within a DLL. I did a number of tests across different Unity projects, source DLLs, with and without additional subclassing, different languages (C# / UnityScript), different .NET versions, etc. My conclusion is that the fileId is determined by:

    1) The class name itself.
    2) The name of the namespace the class resides in.

    Across all projects in all languages and .NET versions, this held true. A class with a certain name always generated the same fileId. Only when a class was put inside a different namespace did the fileId change.

    This has some implications for MonoBehaviour-derrived classes:
    1) You can never change the name of a class inside your DLL or all your scene and prefab references will break.
    2) Same goes for namespace. Change it, break it.
    3) You CAN change the inherited type of a class and not destroy the links. (As long as all eventually inherit from MonoBehaviour that is). * However, if the new class type is in a different namespace, the fileId may change and break references. (Not thoroughly tested.)
    4) If you need to do replacements across a project, you can get the new fileIds by starting a new project, import your DLLs, create a game object, drop all your MonoBehaviours on it, save the scene, open the scene file in a text editor, and extract your fileIds. (Though you should also use a script to list components on your object in Unity to get them all in case some of your MB's automatically added other components to the mix to keep your names matching with your fileIds. NOTE: listing all components on a game object in unity gives them to you in the opposite order they're stored in the file.)

    In the case of CS/JS script files for MonoBehaviours, the reason they all have the same fileID (11500000) is that a CS/JS file can only contain one MonoBehaviour-derrived class. If you have more than one MonoBehaviour class inside a CS file, you have no visual way to assign it. 11500000 must be a fixed value.

    I can't be 100% certain there isn't some additional identifying factor(s) in play here beyond the class name and namespace name, but from the looks of it a hash based on the name is exactly what it is.

    Hope this helps someone.
     
    Last edited: Sep 1, 2012
    lexnewgatexyz, Pelican_7 and ganaware like this.
  42. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    Changing the namespace seemed to work when I tested.
    • Create DLL with component "TestMonoBehaviour"
    • Add DLL to project and add component to a GameObject in a scene + save it as a prefab just for the fun of it
    • Place "TestMonoBehaviour" into a different namespace
    • Replace DLL with the new one
    • Game object and prefab still refer to correct class (to my amazement)

    ** I will retest this to make sure, but it did in fact work for me at least. **

    I wonder if this varies depending upon whether you have source control switched on / off... I had source control switched off (with binary prefabs) and this connection was maintained.

    But like you found, it is also interesting that you can change the base class of a MonoBehaviour or ScriptableObject class (from say MyBaseA to MyBaseB) and that is maintained. But obviously you cannot change the name of the class because then yes all references lost.
     
  43. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Interesting. I tested by making a second class with the same name as the first inside a new namespace. The 2nd copy of the class had a different fileId. I will have to test again and update my post above...
     
  44. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    So you had two classes with the same name in different namespaces?

    Sorry I misunderstood, then my test was slightly different because I literally moved the class into a different namespace. I don't think there would be a situation where I would need two classes with the same name in different namespaces in the same library (that were special Unity scriptables).

    My use-case was to move the older deprecated classes into a namespace called "Legacy" without breaking existing projects. And then introduce the new classes within a separate DLL thus allowing users to remove the original DLL when they no longer require it.
     
  45. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Well, I just neglected to try it the way you did it. But I just tried it and it did not work. Moving my single class into a new namespace broke the reference. Just to be safe, I'm clearing the Library folder and closing/opening Unity each time I make a change. Maybe you could try that.

    I have a subclass of the class I moved into the namespace. I had to change the type of the subclass to the Namespace.class. Oddly, the first time I tried moving the base class into a namespace, both broke. The second time I tried it the base broke, but the subclass did fine. ?

    Edit: Did test a few more times in a different project entirely and got the same result. The confirmation for me is that the fileId I get when I put my class in the namespace matches the new fileId I got in another project when I put the same class name in the same namespace name. I'll try turning off source control and see...

    Edit 2: I just tried the same thing without clearing library and with version control and asset serialization set to mixed and it fails every time.

    Edit 3: This time I made a prefab like you did, left Unity open, as well as having vc and as off. It still broke.

    Edit 4: Just tried doing it with a class already in a namespace called Legacy. Left Unity open, all the rest. I just changed the name of the namespace wrapping the class and it broke. I'm not sure what's different between what you and me are doing, but I just can't replicate your situation where it doesn't break. :(
     
    Last edited: Sep 1, 2012
  46. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    I have just tried to reproduce the same scenario on my desktop (PC) and it is indeed not working. The last time I tried it was on my Mac (if I remember) which I will try again tomorrow. Out of interest what OS and version of Unity are you using?

    This is very annoying because I was hoping to utilise this trait.

    It would be fantastic if there was a way to specify a custom ID for a class for which you are responsible for its uniqueness. That would allow you to move classes between DLLs, scripts, etc. for example,

    Code (csharp):
    1.  
    2. [ClassGUID("e466358e-7bf0-4cf7-87c9-6c70db2c2a90")]
    3. public class TestMonoBehaviour : MonoBehaviour { ... }
    4.  
    Still, I doubt that will happen...
     
  47. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
  48. guavaman

    guavaman

    Joined:
    Nov 20, 2009
    Posts:
    4,483
    Interesting. Windows Vista 64-bit + Unity Pro 3.5.5f3

    A lot more work in general needs to go into this area of using DLLs. Unity always seems focused on the casual users and attracting more hobbiests by adding the latest and greatest one-click-game-making type features. Sad.

    Me too.

    Thanks! That is useful.
     
  49. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    It would be nice if they did more for extension authors. For example, the asset store hasn't even got gift vouchers... There is no automated way to update existing customers of an editor extension to a new one (like say, changed data structure and need to migrate existing projects over). The ability to move the existing class into a different namespace (to avoid conflicts with replacement extension) would have solved this issue for me.

    The most alarming thing is that you cannot even warn people that updating to the latest version of your extension will cause data loss. Before downloading an update it should say "Backup your project before proceeding." and then some custom text like "The latest version of our extension uses a different data structure and you may experience data loss."
     
    Last edited: Sep 1, 2012
  50. numberkruncher

    numberkruncher

    Joined:
    Feb 18, 2012
    Posts:
    949
    Okay, it seems that the memory of my notes was a little confused yesterday.

    - Moving a MonoBehaviour into a different namespace does not work (like you said, sorry about that)
    - But... moving the class of a serialized property into a different namespace survives:

    Code (csharp):
    1.  
    2. // Before
    3. namespace A {
    4.  
    5. [System.Serializable]
    6. public class SomeSpecialData {
    7.     int x;
    8. }
    9.  
    10. public class TestMonoBehaviour : MonoBehaviour {
    11.     public A.SomeSpecialData specialData;
    12. }
    13.  
    14. }
    15.  
    16.  
    17. // After
    18. namespace A.Legacy {
    19.  
    20. [System.Serializable]
    21. public class SomeSpecialData {
    22.     int x;
    23. }
    24.  
    25. }
    26.  
    27. namespace A {
    28.  
    29. public class TestMonoBehaviour : MonoBehaviour {
    30.     public A.Legacy.SomeSpecialData specialData;
    31. }
    32.  
    33. }
    34.  
     
unityunity