Search Unity

  1. Megacity Metro Demo now available. Download now.
    Dismiss Notice
  2. Unity support for visionOS is now available. Learn more in our blog post.
    Dismiss Notice

Resources.Load in C# dll

Discussion in 'Scripting' started by Alex-Chouls, Oct 4, 2010.

  1. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    I'm in the process of converting an editor script into a C# dll. The editor script works fine, but I'm having problems with the dll.

    I load the GUISkin and icons using Resources.Load, but it doesn't work inside the dll. The skin doesn't seem to load...

    Should it work? How would I go about getting it to work? Or is there another approach I should use for loading resources in a dll?

    Using Unity3 Pro...
     
  2. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    That is a very good question. One which will be very hard to answer without any code snippets or descriptions on how you build the assembly :)
     
  3. tomvds

    tomvds

    Joined:
    Oct 10, 2008
    Posts:
    1,028
  4. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    The DLL must be built using Framework 2.0, if you are using Framwork 3.5 or above in Visual Studio, it will not work correctly, if at all. Check your project settings for the output and make sure you are set to use Framework 2.0 other than this limit, it should work because they import the namespace and classes correctly in Unity unless something has changed, but like AA says, need to see code or know what you are doing on your end to know if this is a problem or not.
     
  5. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    False alarm - I had copied the skin and unknowingly lost references to the textures. Once I hooked those up again it worked! I guess I was expecting a problem with the dll so I saw it! Thanks for the suggestions...

    I'm using Framework 3.5 and it seems to be working ok, but I just started testing. I'll switch to 2.0.

    I've attached a sneak peak at the project. It's a visual fsm editor for rapid prototyping and development. It's an evolution on something I developed a few years ago - but Unity is a much nicer underlying engine than I was using then!!

    BTW, is there a way to embed GUISkins in a C# dll?
     

    Attached Files:

  6. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    Very nice - good polish on that UI. How is the runtime implementation?

    With regards to GUISkins in dlls, what I do in my Behave project is I embed the textures in the assembly and then set up static properties to retrieve the textures and GUIStyles.
     
  7. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    Thanks!

    The FSMs are monobehaviours. Each state has a list of parameterized actions authored in the editor. Things like PlayAnimation, EnableBehavior, MoveTowards... You can also write your own actions and they show up in the tool. The Fsm manages events and variables, so you can have, for example, actions like Compare, or MathOperator on 2 float variables. Together this lets you author nicely self contained, maintainable, portable behaviours. A scene might have a bunch of simple FSMs that talk to each other, or it could have one cut scene manager FSM... it's up to you.

    My plan is to release 2 dlls: PlayMaker (runtime), PlayMakerEditor (editor), and the c# source code for the actions, to make it easy to write your own (a new action can be just a few lines of code, but it's easier if you have examples).

    Ultimately I'm hoping the tool will empower artists/designers to author gameplay (or whatever they want!). Scripting and code organization are still big barriers for a lot of creative people - this tool should offer users the structure (FSMs) and flexibility (parameterized actions) to realize their visions!

    And of course I built it to use myself!

    Can I ask how you embed the GUIStyle in the dll? Do you still author it in Unity? Or build it in code? Right now I have a GUISkin in Unity that I can tweak, but I want to be able to package it in the dll with minimal refactoring...
     
  8. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    I only embed the textures. The GUIStyles I create as needed. Example:
    Code (csharp):
    1. public static GUIStyle MyStyle
    2. {
    3.     get
    4.     {
    5.         if (s_MyStyle == null)
    6.         {
    7.             s_MyStyle = new GUIStyle (GUI.skin.GetStyle ("Button"));
    8.             s_MyStyle.normal.background = MyTexture;
    9.             s_MyStyle.name = "MyStyle";
    10.         }
    11.         return s_MyStyle;
    12.     }
    13. }
    14.  
    15. if (GUILayout.Button ("MyButton", MyStyle))
    16. {
    17.     Debug.Log ("MyLog");
    18. }
    19.  
     
    Last edited: Oct 6, 2010
  9. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    Thanks!

    I was hoping for a way to package the GUISkin and textures together, maybe add them all to a .asset file. But digging around it doesn't seem possible... Guess I'll make the styles in code...

    So you add textures as Embedded Resources then do something like this to find them?

    Code (csharp):
    1. System.Reflection.Assembly thisExe;
    2. thisExe = System.Reflection.Assembly.GetExecutingAssembly();
    3. string [] resources = thisExe.GetManifestResourceNames();
    Do you use Resources.Load?

    Thanks again for the help!
     
  10. AngryAnt

    AngryAnt

    Keyboard Operator

    Joined:
    Oct 25, 2005
    Posts:
    3,045
    Last edited: Oct 7, 2010
  11. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    Sorry to be dim, but I don't understand how to get a Unity Texture from that Stream... do I have to use a TextAsset and LoadImage? But how do I get a TextAsset from the Stream? There's a missing step I can't figure out...

    Do you have a code snippet?

    Much appreciated!

    [EDIT] Nevermind, figured it out. Just read a byte[] from the stream and used Texture2D.LoadImage().

    [EDIT] But still interested in how you do it, if you have a snippet...
     
    Last edited: Oct 7, 2010
  12. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Wait a sec, you mean I "CAN" embed resources into the DLL and load them in this way????
     
  13. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    Here's what I do:

    • Add the resources (png) to the Visual Studio project.
    • Select their Properties and change Build Action to Embedded Resource
    • Use a static helper function to load the resource. See below.
    ReadToEnd() just returns a byte[] from the stream. Found the code on the internet :) - seems a little long winded, but robust. Should probably error check a little more on my end...

    Obviously you'd need to change the path of the resource in the dll. I use Red Gate's .NET Reflector to poke around dlls.

    Code (csharp):
    1.  
    2. // loads a png resources from the PlayMakerEditor dll
    3. public static Texture2D LoadDllResource(string resourceName, int width, int height)
    4. {
    5.     // first try to load as local resource, in case not running dll version
    6.     // also lets you override dll resources locally for rapid iteration
    7.  
    8.     Texture2D texture = (Texture2D)Resources.Load(resourceName);
    9.     if (texture != null)
    10.     {
    11.         Debug.Log("Loaded local resource: " + resourceName);
    12.         return texture;
    13.     }
    14.  
    15.     // if unavailable, try assembly
    16.  
    17.     Assembly myAssembly = Assembly.GetExecutingAssembly();
    18.     Stream myStream = myAssembly.GetManifestResourceStream("HutongGames.PlayMakerEditor.Editor.Resources." + resourceName + ".png");
    19.     texture = new Texture2D(width, height, TextureFormat.ARGB32, false);
    20.     texture.LoadImage(ReadToEnd(myStream));
    21.  
    22.     if (texture == null)
    23.     {
    24.         Debug.LogError("Missing Dll resource: " + resourceName);
    25.     }
    26.  
    27.     return texture;
    28. }
    29.  
    30. static byte[] ReadToEnd(Stream stream)
    31. {
    32.     long originalPosition = stream.Position;
    33.     stream.Position = 0;
    34.  
    35.     try
    36.     {
    37.         byte[] readBuffer = new byte[4096];
    38.  
    39.         int totalBytesRead = 0;
    40.         int bytesRead;
    41.  
    42.         while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0)
    43.         {
    44.             totalBytesRead += bytesRead;
    45.  
    46.             if (totalBytesRead == readBuffer.Length)
    47.             {
    48.                 int nextByte = stream.ReadByte();
    49.                 if (nextByte != -1)
    50.                 {
    51.                     byte[] temp = new byte[readBuffer.Length * 2];
    52.                     Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length);
    53.                     Buffer.SetByte(temp, totalBytesRead, (byte)nextByte);
    54.                     readBuffer = temp;
    55.                     totalBytesRead++;
    56.                 }
    57.             }
    58.         }
    59.  
    60.         byte[] buffer = readBuffer;
    61.         if (readBuffer.Length != totalBytesRead)
    62.         {
    63.             buffer = new byte[totalBytesRead];
    64.             Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead);
    65.         }
    66.         return buffer;
    67.     }
    68.     finally
    69.     {
    70.         stream.Position = originalPosition;
    71.     }
    72. }
    73.  
    Anyway, just got this working, will probably tidy up the code some later...

    Hope this helps.
     
  14. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Helps much, I was trying to figure out how to secure my assets so that others can't grab my asset bundles and just use them. This opens up many doors for me.
     
  15. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    only partially as meshes will still fail to be securable this way and they are the only thing that really needs securing as audio and textures can be grabbed from the graphics / audio pipeline with a single click without any fancy black art
     
  16. zumwalt

    zumwalt

    Joined:
    Apr 18, 2007
    Posts:
    2,287
    Not when the first 128 bytes of every file is missing from the assets bundle and the asset bundle itself is missing the first 128 bytes, without the right dll and the know how to stitch them all back together, it doesn't matter.
     
  17. Dreamora

    Dreamora

    Joined:
    Apr 5, 2008
    Posts:
    26,601
    as if the asset bundle was of any interest for audio but especially textures. your data need to go to dedicated hardware and you can debug the procedures that lead there and as part of that debugging you can just grab textures.
    Textures are really the least interesting asset part for protecting because they can't be protected no matter what you do

    the only thing you can't grab are animated models yet they are the only thing that people normally invest the least time in protecting

    all this method does isp revent others from directly using your asset bundle but if they can run your game, they can get all textures you show to them even a single time without problems.
     
    Last edited: Oct 7, 2010
  18. Alex-Chouls

    Alex-Chouls

    Joined:
    Mar 24, 2009
    Posts:
    2,651
    One catch I've run into is I'm leaking textures loaded in the dll.

    I tried adding all the textures to a list as I load them, and then calling DestroyImmediate on each item in the list on EditorWindow.OnDisable.

    Now if I close the editor window and save the scene, no leaks. But if I save the scene with the editor window open, I get "cleaning up leaked objects..."

    The code is very basic:

    Code (csharp):
    1. static List<Texture2D> loadedTextures = new List<Texture2D>();
    2.  
    3. // When loading texture:
    4. loadedTextures.Add(texture);
    5.  
    6. // OnDisable:
    7.  
    8. foreach (Texture2D texture in loadedTextures)
    9. {
    10.     UnityEngine.Object.DestroyImmediate(texture);
    11. }
    Also tried the allowDestroyingAssets flag even though I don't think it applies in this case...

    Any ideas?
     
  19. tatoforever

    tatoforever

    Joined:
    Apr 16, 2009
    Posts:
    4,364
    Hey Alex,
    Sorry to bump out this three week old thread.
    I'm pretty interested in your PlayMaker system.
    We have a very rudimentary FSM but is not integrated into Unity.
    Do you have plans to sell PlayMaker?
    If so, i would like to buy your playMaker as soon as is out. Any release date? :)
    King regards,
     
    Last edited: Oct 27, 2010