Search Unity

  1. If you have experience with import & exporting custom (.unitypackage) packages, please help complete a survey (open until May 15, 2024).
    Dismiss Notice
  2. Unity 6 Preview is now available. To find out what's new, have a look at our Unity 6 Preview blog post.
    Dismiss Notice

HOTween: a fast and powerful Unity tween engine

Discussion in 'Assets and Asset Store' started by Demigiant, Jan 7, 2012.

  1. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Mhmm now your coding post was very yummy. Thanks for the insight: will ponder about it for a long time :)

    About the double type phantom, sorry :p generatedTweeners is not in the DLL though: could you try to simply rename Tweener to Holoville.HOTween.Tweener in row 44 and 54 of HOTweenComponent (in the HOTweenManager folder), and let me know if it solves it?
     
  2. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    One thing I forgot mentioning: The [System.Serializable] tag does work for serializing classes and making their members show up in the inspector - which's a nice feature so you can bulk-edit variables in debug mode. The problem is that System.Serializable only seems to work for native variable types, if you hold other class references in the class, serialization starts to become unreliable - or used to, haven't tried it in latest Unity releases. That's why we've been using a combination of ScriptableObjects (for complex classes) and [System.Serializable] for simpler classes. The problem with ScriptableObjects is their access speed, quite slow in comparison.

    So, the playbackwards toggle worked perfectly, it just took me some trial-and-error time to figure out that I should use PlayForward (to play the 'non-reverse' tween) instead of Play to prevent having to restart it. It's now working incredibly smooth and reliably, I could never get it half as good using iTween :)

    Your suggested code fix also worked great, thanks - and sorry for just skimming over the code and not realizing it was a simple method attribute.

    So all is in peace again in the world and I can stop annoying you - and finish up that damn vector GUI demo! ^_^
     
  3. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Thanks for the addition Breno :) I encountered the same issue and use the same approach with more complex classes. Though I quite dislike ScriptableObjects, and end up using them only to store project-related preferences in the project panel (not with HOTween Editor though).

    Also, sorry for the PlayForward: I should have mentioned it instead of having you stumble around :p I added the fix for your issue to HOTween Editor, and will release it with the next update (I'm still not sure why it happens - I tried putting iTween and HOTween's Visual Editor in the same project, and that didn't happen to me).

    Well, now go in peace and have fun with the damn vector GUI demo! :D
     
  4. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hello,

    I progressed well with HOTween integration with playmaker, but I am having an issue as I test color tweening.

    The red and alpha channel are simply ignored... how odd?! so I though, ok this might be the job for PlugColor but it's not in the build nor in the sources, tho it's in the doc and doxygen. Am I missing something? I do want to simply animate a color, not a material's color.

    Is there anything I should know for proper color tweening? Should I end up having to animate each channel individually?

    bye,

    Jean
     
  5. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hey Jean :)

    I'm not sure what's the issue you're having. PlugColor is not publicly accessible because it's one of the default plugins, and thus is automatically applied when tweening Color types. That said, animating a color is as simple as
    Code (csharp):
    1.  
    2. Color toColor = new Color(1,0,1,0);
    3. HOTween.To(myInstanceWithSomeColorProperty, 2, "colorPropertyName", toColor);
    4.  
    I animate colors a lot in my games, and never had any issue similar to the one you mentioned. I made a quick demonstration that you can check out here.

    Let me know
     
    Last edited: Aug 1, 2012
  6. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hi,

    yes, I found out about the fact that PlugColor is internal, I am really not sure about what's going on there... I'll forward to Hutongs developer, maybe he'll be able to have more insight, I'll try to mess with it some more this afternoon, I implemented PlugSetColor, and that is working just fine.

    bye,

    Jean
     
  7. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey again, Daniele!

    Looks like HOTween.isTweening performance is really low... I got FPS drop using it ~300 times per frame once per few seconds even on my i7 desktop =\
    I saw it uses foreach in HOTween.IsTweening which could be replaced by usual faster for. Maybe there is some another way to improve it's performance..

    Thanks!
     
  8. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hey Dmitriy :)

    I'll definitely look into it, but wow: why are you calling it 300 times in a frame? Maybe I can suggest another solution. Also, how many tweens do you have running?

    P.S. Coming from ActionScript like you, me too I initially thought that for loops would be faster than foreach. But I made a test system and it appears that for loops are faster only when there's a single operation inside the loop, otherwise foreach rules. Also, while in AS you should declare variables outside a loop to make it faster, in C# you can declare them inside, and the compiler will take care of it.
     
  9. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    I'm calling it about 300 times once per few seconds - I need to check about 300 objects - I tween them separately from each other and I wish to stop all that tweens if they are still working before continue with further logic.
    Well, it's a bit complicated to describe why I need to do it)

    I found another solution - a combination of (_tween != null) (!_tween.isPaused) works blazingly fast.
    I could introduce own variable to make it even faster, but that's already enough for me.
     
  10. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Great. I will try to optimize it anyway, but consider that HOTween.IsTweening is a relatively expensive operation, if there are many tweens around to check (number of checks x number of existing tweens).

    Since from what I understood you have access to the tween instances, what you're doing is definitely the way to go.
     
  11. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Thanks!

    Also I see this in the profiler
    http://j.mp/N650xK
    when the Tweener creates first time...

    I wonder why do it creates all common plugins as well, even if I use PlugVector3Y only?
    I see a big script usage peak in profiler when I create 96 Tweeners at once.
     
  12. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hey Dmitriy :)

    sorry if I'm taking a little time, but I was working on some fixes and improvements to PlugVector3Path (and now am eagerly waiting for some improvements by Sandro, MaDDoX's partner, before releasing them).

    What you saw in the profiler should be the static constructors being called the first time a tween is created, since when creating a tween some static properties from default plugins need to be accessed. Anyway, gonna investigate it better tomorrow.
     
  13. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    It's great, thanks!
     
  14. badawe

    badawe

    Joined:
    Jan 17, 2011
    Posts:
    297
    Maybe we found a bug!


    If we have something like that:


    Code (csharp):
    1.  
    2. Sequence tSequence = new Sequence();
    3.         tSequence.autoKillOnComplete = false;
    4.        
    5.         tSequence.AppendInterval(.5f);
    6.         tSequence.Append(
    7.             HOTween.From(sprText.transform, .5f, new TweenParms()
    8.                 .Prop("localScale", new Vector3(0, 0, 0))
    9.                 .OnStart(ActivateObject, sprText.gameObject)
    10.                 .Ease(EaseType.EaseOutElastic))
    11.             );
    12.        
    13.         tSequence.AppendInterval(1.45f);
    14.        
    15.        
    16.         tSequence.Append(
    17.             HOTween.To(sprText.transform, .3f, new TweenParms()
    18.                 .Prop("localScale", new Vector3(0,0,0))
    19.                 .Ease(EaseType.EaseInBack)
    20.                                 .OnComplete(EndAnim))
    21.             );
    22.        
    23.         tSequence.Play();
    24.  

    The callback is never called, but if i remove the first appendelay, the call back is called!

    Maybe I'm doing something wrong?
     
  15. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Everything looks ok in what you wrote, so I guess you did find a bug, sorry for that. Now I'm going to sleep, but tomorrow morning I'm gonna fix it.

    In the meantime, to get it to work with the same result, you can remove the first AppendInterval, and instead add a PrependInterval before the Play:

    Code (csharp):
    1.  
    2. tSequence.PrependInterval(.5f);
    3. tSequence.Play();
    4.  
     
  16. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,700
    Cool looking brand. Do you handle paths, edited via a visual editor, like Bob's iTween and if yes, how does the object traverse? Is it sensitive to distance between nodes, regarding speed?


    Thanks!
     
  17. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Thanks renman3000 :)

    HOTween handles catmull-rom paths with PlugVector3Path (you can find an example UnityPackage here - though remember to update the HOTween DLL included, since it's quite old now, and a lot of stuff changed), but no visual editor (there is a HOTween Visual Editor, but for animations, not for the creation of waypoints). Though if you need a really good waypoint creator I'd suggest Baroni's Simple Waypoint System, which implements both iTween (for straight cornered paths) and HOTween (for curved ones).

    HOTween's path uses constant length calculation, so speed is not sensitive to distance between nodes, and you can also use easing curves.
     
    Last edited: Aug 6, 2012
  18. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,700
    Hm ok.
    Sorry for asking, but is there a fee for your product?
     
  19. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Absolutely not (though donations are well accepted :)), it's free and open-source (on Google Code).
     
  20. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    New HOTween update: v1.1.335

    - Greatly optimized partial paths
    - HOTween Inspector: now "completed but not killed" tweens are displayed as a separate group (while previously they appeared as "running tweens")
    - Fixed floating point imprecision bug when calculating total elapsed loops
    - Fixed path lockRotationAxis bug
    - Fixed bug where incremental loops would behave correctly only after two cycles, when set to infinite

    New HOTween Visual Editor update: v1.0.031

    - Fixed occasional "cannot convert Holoville.HOTween.Tweener' expression to type Tweener'" error (which happened in case other classes named "Tweener" - and not related to HOTween - were present in a project)

    As usual, you can get the latest versions on HOTween's website, and read the full changelogs on Google Code.

    @badawe: this release fixes your bug - damn floating points :D
     
  21. renman3000

    renman3000

    Joined:
    Nov 7, 2011
    Posts:
    6,700
    Thanks.


    ::)))((
     
  22. Jean-Fabre

    Jean-Fabre

    Joined:
    Sep 6, 2007
    Posts:
    429
    Hello Daniele,

    Not too sure how GetTweenersByTarget is supposed to work. What object reference do you expect ? if I have a reference to a gameObject, this doesn't seem to work.

    bye,

    Jean
     
  23. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hi Jean :)

    GetTweenersByTarget requires the target you gave to the tween (first parameter of HOTween.To/From). For example:
    Code (csharp):
    1.  
    2. HOTween.To(myGameObject.transform, 1, "position", new Vector3(2,2,2));
    3. // Target for GetTweenByTarget would be myGameObject.transform
    4.  
    5. HOTween.To(myInstanceOfSomething, 1, "someFloat", 12);
    6. // Target for GetTweenByTarget would be myInstanceOfSomething
    7.  
     
  24. sebako

    sebako

    Joined:
    Jun 27, 2009
    Posts:
    301
    Heya,

    I just found Hotween and I really love it!
    However I do got an issue in relation with RageSpline,
    I have my Spline which is a Default RageSpline Script (Line in this case)
    Now I have change the Outline Color 1 to 0, 0, 0, 0 and I wanna tween it to 0, 0, 0, 255
    I created the tween using the Visual Editor and in the Inspector I do see that the alpha value is
    increasing as expected, however the line is not appearing onscreen if I play the scene.

    Do you have any idea what might cause this?

    Thanks in advance! Keep up the good work!

    -Seb
     
  25. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Thanks Seb, glad you're liking it :)

    If you see the Color value increasing correctly, then it must be something related to RageSpline. I don't know much about it (I have it, but still didn't get a chance to try it), but if I should make a wild guess, I'd say that maybe outline colors can't be directly changed at runtime: you'll probably have to call something like "myRageSplineObject.refreshOutlineColor()"?

    Did you try to assign a new color at runtime without any tweening? If that doesn't work, as I suppose, you might try asking MaDDoX (one of the formidable creators of RageTools, who know "took charge" of RageSpline too).

    Let me know :)
     
  26. sebako

    sebako

    Joined:
    Jun 27, 2009
    Posts:
    301
    Hey Izitmee,

    thanks for the thoughts on this issue. If I change the value on runtime manually it will update immediately.
    So I believe your thoughts are correct and it seems to be that I have to refresh the ragespline object manually.

    All good and working now. Thank you!

    Cheers

    -Seb
     
  27. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Glad you got it working.

    Cheers :)

    Daniele
     
  28. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    Sebako is right, you need to add a small script to the ragespline-host game object with a "auto-refresh mesh" every few frames or so for that to work. I'd try a waitforseconds (0.12) then calling the ragespline.refreshmesh().

    Izitmee, did you add that code change you've asked me to do manually to your version? Just checking 'coz now I got a bunch of code relying on that specific holoville.HOTween.tweener type, and it wouldn't make sense to "branch" from the official version :) BTW, Sandro had to draw back from that HOTween refactor, it was done next to some RageSpline refactorings which broke backwards compatibility so we've reverted it all back.
     
  29. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Ow, sorry about the broken refactoring. Guess I won't be able to steal your coding style after all ;)

    And yes, I added that Holoville.HOTween.Tweener fix to the latest Visual Editor release (v1.0.031)
     
  30. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Hey again!
    How can I use Back.EaseOut with overshoot?

    I mean how can I change the overshoot value at runtime?

    Thanks!
     
  31. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Hey!

    You can't - unless you edit the source code - sorry. That's something I planned to allow on HOTween v2 (way far in development: I designed the API logic and made some tests for the new architecture months ago, but then kept it for later), though since you mentioned it I'll look into it within tomorrow. Should be easy enough to implement.
     
  32. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Huge thanks for your blazingly fast and encouraging answer! It would be awesome to have control on overshoot!
     
  33. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    New HOTween update: v1.1.340

    - Now the overshoot of Back eases and the amplitude and period of Elastic eases can be modified when choosing the Ease TweenParm. The Ease method now has two additional overloads: one to set eventual overshoot, and another to set eventual amplitude and period.

    EaseBack example:
    Code (csharp):
    1.  
    2. HOTween.To(mySomething, 4, new TweenParms()
    3.    .Prop("position", new Vector3(5,0,0))
    4.    .Ease(EaseType.EaseOutBack, 4 /*custom overshoot*/)
    5. );
    6.  
    EaseElastic example:
    Code (csharp):
    1.  
    2. HOTween.To(mySomething, 4, new TweenParms()
    3.    .Prop("position", new Vector3(5,0,0))
    4.    .Ease(EaseType.EaseOutElastic, 1 /*custom amplitude*/, 2 /*custom period*/)
    5. );
    6.  
    As usual, you can find it on HOTween's website.

    @Dmitriy: done!!! Damn I'm such a nerd! ;)
     
  34. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    I'd like to contribute into the HOTween in terms of performance (saw sources and have few ideas about optimization). Please, let me know if it's possible (on goolge code as example).
     
  35. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Wow, Daniele, you're really nerd one =)

    Thank you so much! I'll try it immediately!
     
  36. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Sure that would be very welcome, I know there's a lot that could be improved/optimized (that's why I'd love to scrap it and go with HOTween v2) :)

    Though I'd ask you to send me a commit patch the first times, instead than allowing you direct commit privilege, so I can check that everything is ok and that the coding style doesn't get messed up (as it already happened once - though I learned a lot from that :p)
     
  37. codestage

    codestage

    Joined:
    Jul 27, 2012
    Posts:
    1,931
    Sure, I'll PM you!
     
  38. sebako

    sebako

    Joined:
    Jun 27, 2009
    Posts:
    301
    Hot Stuff! Thanks for the Update :)
     
  39. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    Oh yeah, almost forgot: well-deserved beer money sent ;)
     
  40. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Wooow huge bows of gratefulness Breno, thanks a lot! :) Now I will get extremely drunk with that donation ;)
     
  41. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    Hey, I wasn't meaning to kill you lol :D

    So, Sandro was checking on how to change HOTween so the visual component can take some "finished" callback, he found the call (tweener.onComplete(MethodRef)) is in the source files and due to namespaces he couldn't use it within Unity without method name conflicts. Maybe you got some pre-set environment for that? Anyways, his idea is to add a method overload to onComplete, something like:

    tweener.onComplete(targetGameObject, MethodNameString, [value])

    With such an overload it'd keep compatible with any existing code while giving us the flexibility to assign a target game object for a simple Unity send message - which's sufficiently performant when it's a one-shot event like this, while not having to rely on code-defined enums, delegates and such. With this implemented we'd not only be able to fire any custom methods in our scripts, but we'd also have a way to play a specific HOTweenComponent tween in the target game object, by ID - which would be passed as the optional 'value' field, similar to this:

    tweener.onComplete(targetGameObject, "PlayById", "click");

    What do you think, way too trippy, as if we drank all that beer before coming up with it? :)
     
  42. sebako

    sebako

    Joined:
    Jun 27, 2009
    Posts:
    301
    this is exactly what I am looking for right now!

    One more question tho .... how is it memory wise, cause currently I initialize all my required tweens when my animation component gets loaded and store the objects into an dictionary, right now I don't have trouble with it but I'd better be sure before I have to rewrite the entire System later on. :D

    -Seb
     
  43. ZJP

    ZJP

    Joined:
    Jan 22, 2010
    Posts:
    2,649
    +10000
     
  44. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Sorry for the late reply, I was drunk :D Aha no, joking, it's that my internet connection died.

    Anyway, I see you're teaming up on me for that sendMessage thing, so now that I'm cornered I'll have to do it :) Jokes apart, I always ignored sendMessages in Unity, since I don't like them. But now that you mention it, I see it might be a cool addition - especially since it could be used with other Tweeners, as you mentioned - and quite easy to implement. Getting to work on it immediately - should be ready for this evening or tomorrow max.
     
  45. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    P.S. @sebako: I'm not sure I understood what you meant with your question, sorry :p What is the subject of your "memory wise" question? Your dictionary logic or the eventual sendMessage?
     
  46. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    Awesome as usual Daniele - btw, you got me with that last "I was drunk" joke, I lol'ed :D

    I'm also not sure I got Seb's question, apparently he's storing a dictionary of objects / tweens when initializing the scene so he doesn't have to go through the list (foreach) during play - when trying to find an specific-ID tween in a given game object. Which makes sense actually, the memory expense is minimal, you'd need to have thousands of tweens in that dictionary for it to make any meaningful difference in memory usage. Right now I'm storing a list with the tweens for each RageButton host-gameObject, but I still go through the list to find the actual ID. That's theoretically slower but hardly meaningful for 99.99% practical situations, and I gain the small advantage of being able to inspect that list inside Unity - the Unity inspector isn't compatible with dictionaries.

    Anyways, send message for these applications would reduce memory consumption to zero, but it won't matter either way - memory consumption with our structures is already negligible and SendMessage won't impact performance negatively unless you call it in an update-like, per-frame method.

    PS.: Sorry for the cross-promotion, but I guess you guys might want to check the HOTween-powered "Time tunnel" GUI demo ;)
     
    Last edited: Aug 10, 2012
  47. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    New HOTween update: v1.1.360

    - Added overload to OnComplete method parameter and ApplyCallbacks, which implements a SendMessage behaviour
    - Low-level optimizations by Dmitriy Yukhanov

    Using onComplete with a SendMessage behaviour example:
    Code (csharp):
    1.  
    2. HOTween.To(myTransform, 1, new TweenParms()
    3.   .Prop("position", new Vector3(4,0,0))
    4.   .OnComplete(mySendMessageTarget, "SampleMethodName", someValue)
    5. );
    6.  
    New HOTween Visual Editor update: v1.0.100 (min HOTween version required: v1.1.360)

    - Added OnComplete options to the tweens. Now you can visually set a tween's OnComplete behaviour to either: a) play all other tweens, b) play tweens by Id, c) call a Unity SendMessage. Now that I implemented it, I see it's actually very cool, thanks for suggesting it :)

    As usual, latest files are on HOTween's website.

    @MaDDoX: aha, glad I got you :D HOTweenComponent (which is just part of the visual editor, and not related to IHOTweenComponent - I named it dumbly, but now I can't change it or it will have to be re-assigned to all existing projects :B) doesn't contain any of HOTween's methods. That's why I implemented 3 different options for the new OnComplete Visual Editor behaviour, in order to allow both SendMessage and Play/PlayById :p
    Also, sorry for not answering this before, but I'm not sure I understood how Sandro was trying to access the onComplete method, and where he had naming issues. The tweener.onComplete property shouldn't be accessible at all outside the source, since it's an internal DLL member.
    Btw, cross-promotion rocks, as does your demo: supersweet, love the moving tunnel :)
     
    Last edited: Aug 11, 2012
  48. sebako

    sebako

    Joined:
    Jun 27, 2009
    Posts:
    301
    Hey guys,

    yeah I meant the memory :) Tested it and its really no big difference unless I use like 2000 tweens or something.
    Also thanks for the sexy update, will test it tomorrow.

    cheers

    seb
     
  49. MaDDoX

    MaDDoX

    Joined:
    Nov 10, 2009
    Posts:
    764
    This is cool beyond words Daniele! Not to mention the ability to select a value type and set it by drag and drop or send it. Just-wow :) For those who didn't see it yet, I'm attaching a screenshot showing the new interface and how a tween in our GUI demo was set:

    I know, actually he was asking about how do you set your environment to actually compile the source code into a DLL, if you have any test files set up or if you build everything then test straight into Unity, etc.

    Thx! HOTween + RageTools ftw ;)
     

    Attached Files:

    Last edited: Aug 14, 2012
  50. Demigiant

    Demigiant

    Joined:
    Jan 27, 2011
    Posts:
    3,242
    Glad you like it! :) And the screenshot looks so cool. I suppose you're left-handed? :)

    About the DLL, I compile directly and then test it into Unity. On each DLL project I set a post-build task that copies the assembly to a "bin.global" folder (where each DLL has its own folder). Every Unity project that requires one of those DLLs, just creates a symlink to the desired folder, so each time I compile a DLL every Unity project is automatically updated. Best way I could find (at least on Windows) to "kind of" have external folders/resources work with Unity :p