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...
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
If it's an editor script, you could try EditorGUIUtility.Load (http://unity3d.com/support/documentation/ScriptReference/EditorGUIUtility.Load.html). Your assets need to be in the Assets/Editor Default Resources/ for that function to work. Note that I have no experience with building dll's for Unity, so I have no idea whatsoever whether this will work any better than Resources.Load.
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.
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?
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.
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...
I only embed the textures. The GUIStyles I create as needed. Example: Code (csharp): public static GUIStyle MyStyle { get { if (s_MyStyle == null) { s_MyStyle = new GUIStyle (GUI.skin.GetStyle ("Button")); s_MyStyle.normal.background = MyTexture; s_MyStyle.name = "MyStyle"; } return s_MyStyle; } } if (GUILayout.Button ("MyButton", MyStyle)) { Debug.Log ("MyLog"); }
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): System.Reflection.Assembly thisExe; thisExe = System.Reflection.Assembly.GetExecutingAssembly(); string [] resources = thisExe.GetManifestResourceNames(); Do you use Resources.Load? Thanks again for the help!
Resources.Load works on files which doesn't help you with data embedded in assemblies. For that I use Assembly.GetManifestResourceStream.
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...
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): // loads a png resources from the PlayMakerEditor dll public static Texture2D LoadDllResource(string resourceName, int width, int height) { // first try to load as local resource, in case not running dll version // also lets you override dll resources locally for rapid iteration Texture2D texture = (Texture2D)Resources.Load(resourceName); if (texture != null) { Debug.Log("Loaded local resource: " + resourceName); return texture; } // if unavailable, try assembly Assembly myAssembly = Assembly.GetExecutingAssembly(); Stream myStream = myAssembly.GetManifestResourceStream("HutongGames.PlayMakerEditor.Editor.Resources." + resourceName + ".png"); texture = new Texture2D(width, height, TextureFormat.ARGB32, false); texture.LoadImage(ReadToEnd(myStream)); if (texture == null) { Debug.LogError("Missing Dll resource: " + resourceName); } return texture; } static byte[] ReadToEnd(Stream stream) { long originalPosition = stream.Position; stream.Position = 0; try { byte[] readBuffer = new byte[4096]; int totalBytesRead = 0; int bytesRead; while ((bytesRead = stream.Read(readBuffer, totalBytesRead, readBuffer.Length - totalBytesRead)) > 0) { totalBytesRead += bytesRead; if (totalBytesRead == readBuffer.Length) { int nextByte = stream.ReadByte(); if (nextByte != -1) { byte[] temp = new byte[readBuffer.Length * 2]; Buffer.BlockCopy(readBuffer, 0, temp, 0, readBuffer.Length); Buffer.SetByte(temp, totalBytesRead, (byte)nextByte); readBuffer = temp; totalBytesRead++; } } } byte[] buffer = readBuffer; if (readBuffer.Length != totalBytesRead) { buffer = new byte[totalBytesRead]; Buffer.BlockCopy(readBuffer, 0, buffer, 0, totalBytesRead); } return buffer; } finally { stream.Position = originalPosition; } } Anyway, just got this working, will probably tidy up the code some later... Hope this helps.
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.
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
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.
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.
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): static List<Texture2D> loadedTextures = new List<Texture2D>(); // When loading texture: loadedTextures.Add(texture); // OnDisable: foreach (Texture2D texture in loadedTextures) { UnityEngine.Object.DestroyImmediate(texture); } Also tried the allowDestroyingAssets flag even though I don't think it applies in this case... Any ideas?
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,