Search Unity

[OPEN SOURCE] SmartData - an editor-driven, designer-friendly framework for data and events

Discussion in 'Assets and Asset Store' started by Lyje, Sep 24, 2018.

  1. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Need a flexible way to connect everything in your game without singletons, hard-coding or overly-complex architecture? SmartData might be what you're looking for. It's in beta, available free on github here.

    SmartData uses ScriptableObjects to safely and simply pass data and events around your game. It includes completely custom editors and creation tools to maximise its usefulness. It even has a visual debugger to see what's hooked up to what, and when data is passed around.



    SmartData is based on Ryan Hipple's brilliant Unite 2017 talk on ScriptableObjects. If you haven't seen it, you really should, especially if you're interested in SmartData!



    What is SmartData?

    At its core. SmartData uses ScriptableObject assets to store data. You create an asset using the built-in tools, and just drag-and-drop it onto the things that need to access that data or listen to its events.







    SmartVars can be created for any data type using the built-in type creator. This includes auto-complete and lots of powerful advanced features.



    What is SmartData not?
    It's not a visual code language or editor! While lots of SmartData's functionality is exposed to designers, you'll probably need a coder.

    More Information and Download
    Please check out the github page for much more information, including the wiki. Further docs and tutorials are on the way! https://github.com/sigtrapgames/SmartData
    To download a Unity package, check out the releases page here! https://github.com/sigtrapgame/SmartData/releases

    We're really looking forward to seeing what you guys do with this, and please give us any feedback, bugs, feature requests or general questions! Thanks :)
     
  2. McSpidey

    McSpidey

    Joined:
    Aug 23, 2013
    Posts:
    2
    Nice work!
     
    Lyje likes this.
  3. TriangularCube

    TriangularCube

    Joined:
    Apr 6, 2016
    Posts:
    15
    Wow this looks amazing, can't wait to give this a shot.
     
    Last edited: Oct 28, 2018
  4. saint11

    saint11

    Joined:
    Sep 19, 2013
    Posts:
    1
    This is amazing :) It's really helping me to structure my code in more effective ways.

    Tiny suggestion, I added a "Dispatch on Spawn" checkbox in the Dispatch Smart Event
    upload_2018-10-26_13-49-16.png
    This way I can do quick stuff like attaching it to explosion and other effect prefabs.
     

    Attached Files:

  5. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    There's actually already a SmartEventOnLifecycle script - it'll fire an event on awake, start, onenable etc depending on what you want. I don't blame you for not finding it though - there's a lot of undocumented stuff in there!
     

    Attached Files:

  6. TriangularCube

    TriangularCube

    Joined:
    Apr 6, 2016
    Posts:
    15
    So EventVars don't have any mechanism for data payloads? Any plans to add one, since Relay already does that? Or does that just not fit with the whole Scriptable Object event architecture concept?
     
    Last edited: Nov 3, 2018
  7. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    SmartVars are basically EventVars with a payload. You can either treat them as shared data (by using
    value
    or just listen to their event when they're updated/dispatched :)

    EDIT: Is this from the information on the wiki btw? I'll try to make it clearer if so!
     
    Last edited: Oct 30, 2018
  8. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Speaking of the wiki - for anyone not aware, I've started writing an introductory guide to using SmartData on the github's wiki here.

    It's very WIP - lots still to do! But hopefully it's an easier learning curve than before. Please let me know if you have any feedback, particularly on what might be unclear - I want to make it as easy as possible to get started with SmartData without oversimplifying.
     
  9. TriangularCube

    TriangularCube

    Joined:
    Apr 6, 2016
    Posts:
    15
    Yeah I'm just starting to see that they've got update functions on listen. Don't think they were on the Wiki before.

    I appreciate all you're doing btw, I know it sounds like I'm whining but I swear I'm not! ;)
     
  10. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Doesn't sound like that at all, no worries! This sort of feedback is exactly what I need :)
     
  11. TinyTools

    TinyTools

    Joined:
    Oct 5, 2017
    Posts:
    4
    First. Smart Data is amazing, Safed me alot of time, because i don't have to implement all the toughts of Ryan by myself :) And its easy to use and easy to understand.

    Have a litte suggetion. If I use a IntVarWriter for example, I can listen to value changes when using Smart- or MultiVars. But I can't listen to "local" value changes, if I don't want a reference to a SmartVar or MultiVar.

    My usecase looks like the following. I have a Health Script which i want to use for my Players and my Enemies. My Enemies dont have any IntVars because i want to have them flexible.

    I also have a kind of EventVarInvoker which is just a script where i can decide to use a EventVar or an UnityEvent.
    For my enemies i use just Unity Events.
    Now I implemented a "GenericScriptNameBecauseIDontHaveAFancyNameAtm" which listen to my SmartWriter value and invoke my Events if my value was increased, decreased or if the vale reached some limits.
    I know i could create some extra checks and call my "ValueChanged()" Method directly but it would be cool if we could have some mechanism to have always a underlying relay which we can listen to.

    Sry for the wall of text :p

    PS: Could you complete the Decorator Wiki, because i have no clue what they are for <3
     
  12. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Thanks, glad you're finding it useful! :)

    To be sure I understand - you're looking for changes to a local int to trigger the IntWriter OnUpdated callback? That is certainly doable technically, although we should be careful from a design standpoint. I think it makes a lot of sense for the UnityEvent to be triggered - which is a very easy change to the SmartData codebase too - but does it make sense to allow code bindings? I'd love to hear your thoughts!

    Not sure I follow what you're trying to do here, or at least, what you're trying to do that isn't already there! You can bind a callback to the SmartWriter with BindListener, but is it that you're wanting to have other types of callbacks too?

    Semi-related - your EventVarInvoker makes me think I should do the same local-with-UnityEvent with EventDispatchers, and allow a "LOCAL" UnityEvent as well as EventVars and EventMultis.

    It's on my to-do list :) Turns out there's a whole load of writing needed for all this stuff! I try to find time when I can.

    Simplest way to understand what they do (sort of) is make a FloatVar, then add a FloatRange decorator to it. Set min and max to, say, 0 and 1, then hit play and in the inspector try to increase the FloatVar's runtime value above 1.

    Basically Decorators get callbacks from the SmartObject they're attached to when the value changes. They can then change that value or do something else. For instance, the FloatRange decorator clamps the value and sets the FloatVar's value to that clamped value.

    A really nice use for Decorators - semi-supported out of the box - is network replication. You make a Decorator whose OnUpdated callback (on the server only) sends the value over the network to its counterpart, which then updates the SmartObject on the client.

    I've also just added support for having SmartRefs serialized on Decorators, so you can even have Decorators that set the value of other SmartObjects etc, and still show up in the SmartGraph properly. You don't want to go more than a level or two deep with that of course, as it turns into spaghetti, but it's another nice demonstration of the power of Decorators. I keep finding new uses for them in the real-world projects I'm using SmartData for.
     
  13. TinyTools

    TinyTools

    Joined:
    Oct 5, 2017
    Posts:
    4
    Sorry for the late reply, was bussy at work :)
    Our designers don't care so much about software design i think. :) If they use the OnUpdated Callback to create some fancy gameplay logic they don't want do create always a IntVar for every test they do. Especially for Enemies in my case.
    I already did that. I have 6 underlying events (EventInvoker) OnValueIncreased, OnValueDecreased, OnValueReachedMax, OnNoLongerAtMax... and some for the min case. I bind a OnValueChanged Method to the SmartWriter. And here is the problem, if i use a local value in my SmartWriter. OnValueChanged get not called. I created a workaround for this case at the moment where i call my OnValueChaged manually if the SmartWriter value is local.

    That's sort of what i try to do with my Health script at the moment, with one difference or problem :( If I use the local value I have no benefits of the clamping functionality.

    At the moment I can live with my workaround and the rest works like a charm.

    A completely other question:
    Is it possible to move the relay and smart data folders in the Plugins subfolder.
    Unfortunately SmartData broke on my last attempt
     
  14. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Ah, I see - sorry, didn't realise you were still talking about the local update thing! Thought you had two separate feature requests :) Yes, that makes sense. I'll look into local-mode UnityEvents and code callbacks. As mentioned, the UnityEvents should be fairly simple to implement, but the code callbacks will require a reasonable amount of work - SmartRefs will need their own underlying Relay as you've noted.

    Decorators are the one thing I don't think I can do locally unfortunately. Potentially I could make SmartRefs take Decorators, but a) it'd be a lot of work and b) it would make things a lot more complex for designers - I'd rather have one well-defined way of doing something than multiple ways which you can only decide between if you really know everything about the framework.

    I'll have a look at that - not tried to move it myself. I thought however it should be ok, as I've tried to make everything relative to Resources folders. Although perhaps Resources folders don't work the same within Plugins.... not sure!
     
  15. TinyTools

    TinyTools

    Joined:
    Oct 5, 2017
    Posts:
    4
    Hey we had recently the case that we want to listen events on deactivated ListenSmartEvent Components. For that case we changed the SmartComponentBase a bit. We moved the OnEnable() code to the Awake method. And removed the OnDisable() part.

    Colliders in Unity work similar, they always check collision. So you can activate them if a collision occurs.

    In our example it was an player who got killed and we want to revive him. But the revive event failed, because the player object was disabled.
     
  16. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Interesting! I might build in a toggle to allow that behaviour.
     
  17. Arkade

    Arkade

    Joined:
    Oct 11, 2012
    Posts:
    616
    Hey, I can't imagine I'm unique in simultaneously thinking "this is very cool" and "the first thing I want to know is performance implications". For some, there's no way to commit to a framework without knowing lots about how it performs -- both short term and how it scales. Could you add something to your docs (sorry if it's there already, I had a little look inc. the FAQ but must have missed).
    Thanks
     
  18. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    I'll be totally honest - I haven't really done any performance profiling. There are two main reasons - firstly, SD is changing rapidly at the moment (I haven't pushed anything lately but there's a lot of development going on internally), and secondly it isn't primarily focused on performance

    The goal of SD is to abstract "global" data and events. It's not intended for use in hot code paths, tight loops etc. In most cases, you'd do your perf-constrained calculations with local vars and just "publish" the result by setting the value of a SmartRef.

    However I have had no performance issues with it thus far, and have no reason to believe it would be a bottleneck in most use cases.

    That said, the internal event system is my Relay framework, which is profiled and tuned for performance. As soon as you start using UnityEvents, obviously everything gets slow, but that's optional.

    I do want to look at profiling at some point though :)
     
  19. BTStone

    BTStone

    Joined:
    Mar 10, 2012
    Posts:
    1,123
    Hey there, I'm interested in this concept but how exactly would I tackle this kind of scenario with SmartVariables:

    You have an enemy as a prefab- This enemy has a SmartVariable for Health. This Health value is set to 50. So far so good.
    When my game spawns 10 of these enemies and my player attacks one of them and makes 50 damage to one then all of them update their Health-Values, right? Since it's the very same SmartVariable which is basically shared and all of them have only 50 Health left now although the player attacked only one?
     
  20. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    This, currently, is the major failing of this pattern. It's not (yet) very good at dealing with dynamically instantiated objects with independent data. I've got some thoughts on this (see the FAQ on the wiki for a little more detail) but it's not trivial.

    You can runtime instantiate SmartObjects like any other ScriptableObject, but there's not yet a good way of defining what things are going to be interested in a new SmartObject. You can manually create, assign, subscribe from script of course but you lose a lot of the nice features as you're no longer data-driven in the same way.

    You can sort-of hack this behaviour currently using SmartMultis by assigning (preferably sequential) integer IDs to enemies, then request that index from the Multi and it'll instantiate it if necessary. It's not that great though as there isn't a way to remove elements from a Multi (by design).

    The other option - which is similar to what you might do in a more traditional design - is to use a SmartSet to register all the enemies, give each one a public health float (and/or an event/Relay to go with it) and hook up to that.

    As I say, I've got some plans for solving this issue (and have talked a bit about it with Ryan Hipple, the guy who gave that first talk) but they're BIG. Like, version 2.0 type stuff, and SmartData isn't anywhere near being out of beta yet IMO. So please don't hold your breath!

    Like I said in the previous post, I don't want to present SD as a silver bullet; it's great at some things (like, really really great!) but can't map to every problem domain. I recommend playing around with it, getting a feel for how it can help you, and use it as another tool in your kit. Hope that helps!
     
    SpyrosUn and BTStone like this.
  21. vizgl

    vizgl

    Joined:
    Nov 4, 2014
    Posts:
    28
    Interesting approach and tool. But I have question.
    How can I pass arguments when dispatching event?
     
  22. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Typed SmartObjects - e.g. SmartInt, SmartBool - work both as shared data and typed events. Just set the value and their events will fire.
     
  23. Player7

    Player7

    Joined:
    Oct 21, 2015
    Posts:
    1,535
    Looks interesting think I will try it out and see how it goes.
     
  24. vizgl

    vizgl

    Joined:
    Nov 4, 2014
    Posts:
    28
    What about few arguments, I want pass int and Transform at the same time
     
  25. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Multiple arguments aren't supported, but you can make a struct which holds an int and a Transform and create a custom SmartType for that struct.
     
  26. SpyrosUn

    SpyrosUn

    Joined:
    Nov 20, 2016
    Posts:
    103
    I was deeply impressed by watching Ryan's video and this is how i bumped into this forum post actually. Was looking to see if there's more of Ryan's suggestions and it looks like you have already created a framework for this. Will definitely be trying this out. Btw, I would gladly pay for something like this, in order to ensure that you have the resources to keep working on this and make it better and more efficient. I am sure many others would do.

    Dynamically generated sets for holding multiple instances would be a must. Maybe you can think about creating a 2.0 version, as you mention above, and have a paid version on the store. I would for sure grab that :)

    Thanks !
     
    Last edited: Jun 17, 2019
    Lyje likes this.
  27. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Version 0.2.1 is out on github! This release fixes a number of editor bugs which caused serialisation issues. If you've been having trouble with dragging-and-dropping SmartVars into SmartRefs, this is now fixed!
     
  28. stychu

    stychu

    Joined:
    May 9, 2016
    Posts:
    4
    Is this still actively in development?? Would love to start playing with this <3
     
  29. Lyje

    Lyje

    Joined:
    Mar 24, 2013
    Posts:
    140
    Yes! That said, updates are irregular - it basically gets updated as I use SmartData in our projects.
     
    stychu likes this.
unityunity