Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Basic Embedding
#11
I finally got around to putting together a more complete tutorial on this subject, and added it to my website. Here's a link.

Mad Wonder's Guide to Embedding Tilengine in Unity

Hopefully it is easy enough to follow. I included a zip file with most of the used assets, including a copy of the final script file. I also re-factored the script to be a bite more generic. I included that UpdateFrame reference you mentioned, and I also calculated and constructed the byte array on my own instead of relying on the Texture2D for retrieval. I tested it in Unity 5.6 as well as Unity 2018.3, and it worked perfectly in both. It should work on just about any version of Unity, but any version before 5.0 will require the Pro license. Pre-5.0 versions of Unity would only let you use native plug-ins if you had the Pro license, and Tilengine would definitely fall under that restriction. Most people have already upgraded to 5.0 or above, though, so I don't think it should be a problem.
Reply
#12
Great work! Ill post a link to your tutorial in Tilengine's Facebook page.
Thanks!
Reply
#13
I'm still poking around, trying to figure out what I can do with Tilengine. I have a question. I used a mapping of the TLN_Init function, and had it output it's return value to an IntPtr in C#. This seems to allow me to run multiple instances of the engine. I was even able to use the TLN_SetContext function with the IntPtr to switch between contexts.

My question is, do I need to be worried about memory leaks, or will the C# garbage collector handle the freeing of the associated memory? If I try to use the TLN_Deinit or TLN_DeleteContext functions, it is possible to crash the Unity Editor while I'm using it. If I don't bother running those functions while in the Editor, it doesn't appear to cause any issues. And the IntPtr type in C# is considered safe, it is likely playing nice with the garbage collector. I wasn't able to find as much documentation about this approach as I would like, and I just wanted to make sure I wasn't doing something that might eat up all my system's resources.
Reply
#14
Hi Richard!

I'm not a C# expert, but I'll try to help. You should not be worried about the GC destroying anything. All references to returned Tilengine objects are IntPtr encapsulated insie a struct. Both items (IntPtr and structs) are value types that exist in the stack, so they do not have the memory allocation lifecycle of object types. They cannot be automatically finalized or garbage collected. In other words, if you don't explicitly delete/deinit tilengine instances by calling Delete() (or Deinit()) on them, they will stay forever, nobody will destroy them for you.

I don't know how Unity handles external libraries, but you should never do TLN_Deinit() or TLN_DeleteContext() if someone is still trying to draw. They should be the very last calls before unloading the library.
Reply
#15
Well, Unity has an editing environment that I have to take into account. For running Tilengine in Unity's deployment environment, there is no problem. For that I can initialize Tilengine once for every instance, and then call Deinit or DeleteContext just before the program shuts down. Easy. But Unity's editing environment complicates matters.

The editor is running constantly, and it runs a "preview" environment whenever you press the play button. Scripts for Unity frequently have to have their values initialized for that preview. In order to get Tilengine running in the preview, I have to call the Init function every time the preview is activated. I have been able to get this working, in fact, I've even gotten it working with more than one instance simultaneously. You just have to be a bit more careful in manually setting the context.

What concerns me is that it is typical when working with Unity to use the "preview" feature a lot. Like, a WHOLE LOT. People slap that play button all the time, in order to get a quick look at what their most recent changes have done to their scenes. And because of how Unity's editor is structured, I can't call the Deinit or DeleteContext functions when the preview stops. Which means that the Init function can, and likely will, get called A LOT, with no calls to Deinit or DeleteContext. Now, thankfully this isn't a loop issue or a frame update issue. I can insure that it only gets called once per instance per preview session. But I'm slightly concerned that this might cause some manner of memory leak, with how repeatedly Init is getting called. I don't want to inadvertently max out someone's system RAM while they're in the middle of working on a game. (just because they used the preview a bit more aggressively than usual)
Reply
#16
Hi Richard, thanks for your detailed overview about Unity's editor workflow. I can think about two solutions:

If Unity runs standard C# with garbagge collector, yoo can create a class that implements de Disposable interface. If the Unity environment destroys all objects when the preview is closed, the GC should call the Dispose() method that you defined in your class, and this method should call the TLN_Deinit() or TLN_DeleteContext(). This should be the way in regular desktop applications.

If that solution is not possible (I don't know how Unity handles C#), I could do a small modification to Tilengine to work with just one instance: calling multiple times TLN_Init() will keep returning the same context. That would allow the context to persist across multiple launches. That's how Tilengine worked before I implemented multiple contexts.

Do you think any of these solutions should work?
Reply
#17
Big thanks, megamarc! I dug a little deeper into the documentation for the IDisposable interface, and I think that's got me where I needed to be. Here's a link to the documentation I used. It provides a pretty good example of how to tie memory management into a manual approach as well as a standard garbage collector approach. I was able to cook up a quick prototype class and script that handles the object creation, destruction, and disposal, and was able to get it calling the necessary DeleteContext function without any fuss and without any crashes in the Editor. I should be able to integrate this into the project I'm working on easily enough. I'm feeling a lot better about the memory management side of things.

One last quickie question, I don't need to call both DeleteContext and Deinit, do I? If I'm reading the documentation correctly, Deinit is used to delete the currently assigned context without providing a pointer, so I should be able to call one or the other, but shouldn't need to call both. Especially if I'm being careful about my instances, and disposing of my contexts correctly.
Reply
#18
Hi again! I'm glad you're doing good progress, you're working hard on integrating tilengine in Unity Smile

Regarding your question: no, you don't need to call both Deinit() and DeleteContext(), just one of them. In fact Deinit() just calls DeleteContext() for the active context.
Reply
#19
I was able to get some coding in over the weekend. And I've got a new tutorial posted!

Embedding Tilengine in Unity: Memory Management

This tutorial takes it back to the basics, and rolls a minimalist DLLImport wrapper for the Tilengine functions. It also bundles up the references and primary functions of Tilengine up into an IDisposable class to make it more palatable to C#'s garbage collector. It seems to be working fairly well in Unity, with the Tilengine contexts getting created and destroyed properly, and at the appropriate times. This approach is much more friendly and stable when it comes to Unity's editor environment. With this approach, I was also able to test multiple Tilengine contexts running concurrently, without any issues.

Now obviously, this is just an early prototype, as most of the functionality is missing with this approach. But the rest is just a matter of structure, and deciding how best to integrate the various Tilengine structures into Unity's interface.

Also, as a bit of a personal challenge, I took the basics that I had developed here and tried integrating them into the Monogame framework. I had to make some adjustments for the framework-specific structures. But the underlying code for the memory management and Tilengine mapping required no changes at all. I was able to get a very similar project embedded and running in Monogame as well with little difficulty. I'll be posting another Monogame-specific tutorial soon as well.
Reply
#20
Great work Richard! I'm glad to see that you're doing well and I appreciate your effort about the integration. I'll put a link on facebook to your new tutorial.

By the way I'm a little busy now but I'm finishing a big update to the engine that I expect to release soon.
Reply


Forum Jump:


Users browsing this thread: 4 Guest(s)