[Released] the.laboratory - Forge Framework

1290681--62139--$splash.png

About | Community | Documentation | Asset Store

Hello guys!

My Unity Framework Forge was accepted in the AssetStore!

Basically it is a set of scripts to speed up the development of applications and FREE!!

I could spam the entire post with the features but you are welcome to download it anytime!

I put some effort in making it well documented with an in-editor Manual, Examples e scripting reference everywhere!

The package isn’t a DLL so you can see what each script is doing!

==== Examples ====

They are in the final product and well explained inside the project.

Activity: Update Engine (Threads Unity)
[Example02] This example shows the usage of the interfaces in place of MonoBehaviours. Basically it creates 25k executing nodes, so the user can see the perfomance of them running Update loops.
[Example03] This example shows the effect of running heavy tasks on a single for loop versus using the Activity’s Thread functionality.

Timer: Time based functionalities.
[Example01] Shows basic usage of the Timer class.

Tween: Script animation running on top of the Activity engine.
[Example01] Shows basic usage of the Tween class.
[Example02] Shows a more complex usage of the Tween class.

Tags: activity, thread, threading, timer, tween, reflection, editor, inspector, window, event, dispatcher, entity, renderqueue, xml

Right now I’m correcting the version of the framework.
I expect to make it available to 3.5+ as soon as possible!
The first ‘HelpWindow’ used ScriptableObjects as source of content and I would lose everything moving this to 3.5!
To make it simple I adjusted the HelpWindow to accept a XML as source! Also this system will be useful for you guys, as using a simple syntax will be possible to create a indexed content window just like the Manual!

This friday the 3.5+ version was submitted!
I guess until mid-week it will be available!
Until then I will post the 2 upcoming features in the future.

I will adapt the editor scripts of the XML help window, so it will be possible to you guys create information windows in a HTML-like style without coding in an OnGUI callback.

And also I will finish the TextureAtlas component to be more user-friendly. It will feature the possibility of building and saving the atlas itself, or building it at runtime by dynamically changing the list of targets. This is useful when you are not sure what textures will be needed prior the application is running!

Hi guys!

Now it is live!

Forge is now 3.5+ compatible!

Go Grab It!

Sorry for the incovenience!

**Edit0

It seens the logo and artwork got bugged in the last submit! I sent a request to correct this!
But the contents are all ok!

**Edit1

Now it is corrected!

Today I submitted Forge version 1.0.296 to AssetStore.

This next update will feature:

  • Some bug fixes
  • Introduction of Editor features:
  • Like an Asset creator window (to easily create Prefabs and ScriptableObjects instances)
  • Partial documentation + manual for new EditorGUILayout features.
  • First Editor scripts to be documented and ready to use.

Here are some screens before the package arrives!

Looks good. I thought of creating a framework similar to this. It’s nice to see this in action :slight_smile: Just need to try it out.
Thanks.

Thanks a lot!

Please give a feedback or rate it if you found it useful!

More features are coming (some of them are already there but undocumented)

It’s very Nice. Sample scenes remind me of Direct3D samples :slight_smile: I’ll stay tuned for more updates.

Hey all!

Forge 1.0.296 is out!

Go grab it! Feedbacks/Ratings/Requests are welcome!

Thanks!

Hello,

Just downloaded Forge and it seems great!

One problem that I noticed that if you import Forge into a project that contains Playmaker (1.6.3) it breaks Playmaker, so nothing will compile!

I fixed this by uncommenting all occurrences of

 //namespace thelab.editor.window {

and the matching closing brace

//}

to reinstate the namespace

The files concerned are shown below and are in thelab/forge/source/editor/window folder

BaseEditorWindow.cs
CreateAssetWindow.cs
EditorAssetWindow.cs
EditorGUIToolCatalogWindow.cs
ForgeHelpWindow.cs
HelpWindow.cs

I hope this doesn’t break anything? Seems OK?

Cheers

Paul

Thank you guys for the 100+ downloads mark!

I know that a framework with a broad scope of functionalities is a bit complex to use and rate.
So the “early adopters” have my thanks!

I am finishing new tools to release at the AssetStore and as soon as possible I will adapt the AngryBots demo with Forge’s capabilities
as a showcase of the features.

For those who used and have some feedback or ratings I’d appreciate some intel in the AssetStore page.
This way I can work with some better directions for the future.

Also you can add me in the Google+ Page here [http://forge.thelaborat.org/]. There I can help you with Forge and also Unity C# coding stuff!

Thanks!!

Hi Eduardo,

I´ve some points for discussion.

  1. For our purpose it is quiet important to be able to control the event dispatch order. Therefore I´d like to ask to add a int based execution order to every listener e.g. as follows

earlier execution < 0
default == 0
later execution > 0

When registering a listener without providing the order, 0 will be used by default. If its important that a listener is executed earlier then the default ones it should have a lower order value. It looks like that this feature cannot be achieved with the current delegate implementation right?

  1. The second thing would be to allow adding removing listener during event dispatch by adding new listener or removing registered listener after all listener have been called.

  2. When dispatching an event a limit order can be provided which works as follows:

Signature:

Usage:

We currently use this feature in our framework to suppress propagation of e.g. input events to all listeners while e.g. a menu is open.

  1. Following the previous line of thought we also allow every listener to decide wether the event should be dispatched to listener with a higher order or not. E.g. the return value is always bool indicating if listener with a higher order should be called at all (all listener with the same order value will be called after this listener though).

What do you think?

Mirko

Hi!

Thanks for the feedback!

Indeed it is a good practice to create “priorities” for events. I didn’t do that with the “EventDispatcher” class because it would exceed the premise of “simply sending events”.

The EventDispatcher class was modeled to be a “base” for other types of behaviors. So I would not modify this class, rather I would extend its functionality creating something like this.

public class PriorityEventDispatcher
{

  //Table of Dispatcher indexed by priority levels.
  Dictionary<int,EventDispatcher> m_dispatcher;

  //Samples a Dispatcher of a given priority if needed.
  public EventDispatcher this[int p_priority] { get { return m_dispatcher.ContainsKey(p_priority) ? m_dispatcher[p_priority] : null; } }

  public PriorityEventDispatcher()
  {
    m_dispatcher = new Dictionary<int,EventDispatcher>();
  }

  public void AddListener(Enum p_type,Delegate p_method, int p_priority)
  {
    if(!m_dispatcher.ContainsKey(p_priority)) m_dispatcher[p_priority] = new EventDispatcher();
    m_dispatcher[p_priority].AddListener(p_type,p_method);
  }

  public void AddListener(Enum p_type,Delegate p_method) { AddListener(p_type,p_method,0); }

  public void Dispatch(BaseEvent p_event, int p_priority)
  {
    //Get all dispatchers of a given priority.
    List<KeyValuePair<int,EventDispatcher>> list = m_dispatcher.ToList<KeyValuePair<int,EventDispatcher>>();
    list.RemoveAll(...) //Removes all that don't fits in the priority;
    list.Sort(...) //Sorts by priority low to high
    //Will dispatch the event with the correct priority rule.
    for(int i=0;i<list.Count;i++) list[i].Value.Dispatch(p_event);
  }

  public void Dispatch(BaseEvent p_event) { Dispatch(p_event,0); }
  

}

I think this example above (it is missing some methods but the outline is correct) would cover the priorities part.

Now about the part of “event that returns some message after execution”, I would keep the listeners returning “void” but extends the “BaseEvent” class to carry more data from each dispatch.

For instance, I am finishin a UI system where I created a “UIEvent : BaseEvent”.
In this extension I added a bool called “stopPropagation”.
This bool is used to when a child node dispatch an event, each listener can do “event.stopPropagation = true” and the event will not
go up to the next parent.

But you gave some ideas I could experiment later on. You can use the snippet above, but I will consider putting this “PriorityEventDispatcher” in the package in the next update.

Thanks!

Hey!

Just to add more about the events talk.
The framework has a component called “Entity” wich can be used both as base class for your game’s elements and a hierarchical event dispatcher.

Let’s assume a GameObject hierarchy like this:

application
  ui
    menu
      button_start
      button_option
      button_credits
  controller
    ui
    game
  view
    game
      player
      enemy
    scenario

All classes from all elements would extends Entity wich internally is a MonoBehaviour, so no harm done.

The Entity class has an EventDispatcher like interface. You Add/Remove listeners and Dispatch events.

Now let’s define an Enum.

public enum AppEventType
{
  MouseClick,
  MouseHover,
  Hit,
  Die
}

So, if in your code you do something like this:

//inside controller.ui GameObject
application.ui.AddListener(AppEventType.MouseClick,OnUIEvent);

void OnUIEvent(EntityEvent e)
{
  switch(e.target.name)
  {
    case "button_start": /*...*/ break;
    case "button_options": /*...*/ break;
    case "button_credits": /*...*/ break;
  }
}

//inside button_start, button_option and button_credits when a Click occurs.
Dispatch(new EntityEvent(AppEventType.MouseClick));

As you can see, the event will go from the inside of “button_x” and go up until it reaches “application.ui” where the listener added at the “controller.ui” is located.

No need of priorites to filter who listen to what.

Hi Eduardo,

Thank you for your comprehensive answer. I understand and agree with your design decisions.

One thing I´m concerned about with that solution is the performance impact though. In an integrated priority dispatcher (like in our case) the list of listeners per event type is always ordered and can be executed one after another until some blocking occurs. Whenever a listener is added it is inserted at the correct index based on its priority. There is only one event type dictionary lookup and one for-loop per event call. If a listener is added or removed during iteration it is buffered until the iteration has finished.

I know the principles of not optimizing before testing :-). Just the solution you have sketched adds quiet a lot of extra work (creating arrays, several dictionary lookups, sorting) per event call…

In our project we most of the time use priority events even if most of the listener have the default priority because there is the one listener which should be executed before all others.
We use the event listener especially for the update cycles where we need to ensure that e.g. a player item updates after the player has updated its status or a view component updates all textures after the model has run its updates etc.

Mirko

Edit: Sorry I just read your latest update and therefore did not address it above. While I feel this could be a nice alternative for priorities I´m hesitating to order the Unity scene hierarchy of all objects accordingly. The worst case could be that some dynamic object needs to be the “event parent” of another dynamic object which would create a transformation dependency between both…

All your concerns about speed are correct. Certainly that PriorityDispatcher was a sketch.
This would be the way I would implement it.

public class PriorityDispatcher
{
   List<EventDispatcher> m_list;

  public PriorityDispatcher(int p_max_priority)
  {
     m_list = new List<EventDispatcher>();
     for(int i=0;i<p_max_priority;i++) m_list.Add(new EventDispatcher()); //create all instances once
  }
  
  //will use only positive priorities to avoid mapping intervals to [0,N]
  public void AddListener(Enum p_type,Delegate p_method,int p_priority)
  {
    m_list[p_priority].AddListener(p_type,p_method);
  }

  public void Dispatch(BaseEvent p_event,int p_priority)
  {
    for(int i=0;i<p_priority;i++) m_list[i].Dispatch(p_event);
  }

}

But one thing I would not do is use both EventDispatcher or C# delegates to relay messages at Update speed (~16ms). Both of them are really slow for these situations.

For instance in a project I made we had a TouchController that in the Update method it reads the touch data and relay constant information about it. Using delegates it was really slow and even more in mobile builds.

So for these 60fps speed callbacks we came up with the solution of using interfaces.
The rough sketch of it is:

public interface ITouchHandler
{
  public void OnTouch(Vector2 p);

  public void OnTouchSwipe(Vector2 from,Vector2 to);

}
public class TouchController : MonoBehaviour
{
  //can be filled in Editor mode.
  public List<MonoBehaviour> Handlers;

  
  List<ITouchHandler> m_list;

  void Awake()
  {
    m_list = new  List<ITouchHandler>();
    MonoBehaviour[] local_scripts = GetComponents<MonoBehaviours>();
    foreach(MonoBehaviour m in local_scripts) if(m is ITouchHandler) m_list.Add(m as ITouchHandler);
    foreach(MonoBehaviour m in Handlers) if(m is ITouchHandler) m_list.Add(m as ITouchHandler);
  }

  void Update()
  {
    if(touch)  for(int i=0;i<m_list.Count;i++) m_list[i].OnTouch(pos);
    if(swype) for(int i=0;i<m_list.Count;i++) m_list[i].OnTouchSwype(from,to);
  }

}

This way any script you want to handle Touch just needs to implement the interface and be dragged to the TouchController list.
Or if the script it self is in the same GameObject it will be added during awake.
You can also make methods like Add/Remove if you want to manage the listeners.

But the fact is that calling a list of interfaces is a lot faster than calling delegates or event dispatchers. In this context a prioritize speed normally.

The cool part is also that the “Touch System” gets self contained without the need of an extra Event system.

Thanks!

Coming Soon - Forge 1.0.304

Hey all!

Following a chat I had in this Thread, today I submitted the new version 1.0.304 of Forge which should come together with version 1.0.303 (mostly fixes).

The new features will make it more easy to inspect and create dictionaries in Editor mode.

Below you can see the release notes for both of them and some screens of 1.0.304 features.

=== 1.0.304 ===

- Added: DictionaryPair classes to be serialized and used to create Dictionaries.
- Added: ‘ToDictionary’ method for ‘Reflection’ class, allowing to convert Pair lists do Dictionary.
- Docs: Added Script reference for new features.
- Docs: Added Manual entry at Engine > System > Dictionary

=== 1.0.303 ===

- Fix: AssetCache class fails to load some entries.
- Fix: HelpWindow sometimes fails on Unity 4.0 unpacking due scripts being loaded before help Assets.
- Docs: Added some txt files to help users getting started.

Released - Forge 1.0.305

Hi!

Because of issues in 1.0.304 I made some fixes and submitted as 1.0.305!

The hilight of this version is the Dictionary structures to help inspect it in Editor!

Release Notes

– 1.0.305 –

  • Fix: By the new guidelines, the ‘thelab’ menu was moved to the “Help” section.
  • Docs: Updated ‘Troubleshoot’ section to show the new location of support information.

– 1.0.304 –

  • Added: DictionaryPair classes to be serialized and used to create Dictionaries.
  • Added: ‘ToDictionary’ method for ‘Reflection’ class, allowing to convert Pair lists do Dictionary.
  • Docs: Added Script reference for new features.
  • Docs: Added Manual entry at Engine > System > Dictionary

Also be sure to check the Inspector Gear video about its basic functionalities and the advantages of using it to create editors and inspectors about 6x times faster than from scratch!

Monthly Feedback Check!

Hi!

One month has passed and suprisingly the number of DL is steady :slight_smile:

Thank you guys for the preference!
If possible I’d like to hear your feedback here or in the AssetStore page.

I am a bit busy in a personal project but I intend to add a new feature to Forge to wrap the loading and uploading of elements in forge.
The interface should be something like this:

Web.Load<T>(p_url,delegate(T p_data,float p_progress) { }); //will load the data informing the progress and when it reaches 1.0f 'p_data' will be available.

Web.Load<T>(p_url,function(T p_data) { }); //will load the data and, when it finishes, will call the method passing the data.

Web.Load<T>(p_url,object,"attribute"); //will load the data and after that will set the attribute of the object -> object.attribute = p_data;

Pending Review - Forge 1.0.306

Hi everyone! It’s been a while!

The new Forge 1.0.306 version will come with nice new features!

The first one is the new ‘Web’ class!

This class will make it easy to load and keep track of progress of your data. In editor mode I created a window called “Web Cache Window” that shows the list of all load operations made and its results.

public delegate void Handler<T>(T p_data, float p_progress, string p_error);

static public WWW Load<T>(string p_url, Handler<T> p_callback, float p_timeout = 0f)

//Usage
//Keep the 'WWW' if you want more control
WWW loader = Web.Load<Texture2D>("www.texture.com",delegate(Texture2D tex,float progress, string error)
{
  if(progress >= 1f) { /*Handle Data*/ }
  if(error != "") { /*Handle Error*/ }
  if(progress<1f) { /*Handle Progress*/ }


},[timeout=0]);

//Fast
Web.Load<string>("www.mydata.com",delegate(string text)
{
  if(text == null) { /*Error*/ } else { /*Handle data*/ }
},[timeout=0]);

//Get/Set
//'Texture' == hack to load non readable Texture2D
Web.Set<Texture>(material,"mainTexture","www.texture.com",[timeout=0]);

The result of Load calls can be seen below, also it is possible to call URLs directly from the Web Cache debug window.
Check the script reference for complete information.

The next class that I added is the ‘ByteArray’ class. It allows the serialization/unserialization of many primitive data types including Texture2D!
After turning them into “byte[ ]” the class offers methods for LZMA compression and conversion to Base64 format.

//Usage basic
ByteArray a = new ByteArray(num_elements,element_size); //e.g. 2 Vector2 == 2_vec2 * (2_floats * 4_bytes)

a.Write(new Vector2(2f,3.5f));
a.Write(new Vector2(1f,1.5f));

a.Compress() //LZMA Compression

string b64_string  = a.Encode64();

a.Decode64(); //back to bytes

a.Decompress(); //back to original data

a.position = 0; //reset reading head.

a.ReadVector2();
a.position += 2 * 4; //move it 2 floats of 4 bytes;
a.ReadVector2();

When the package is approved I will come back with more info!

Thanks!

Release Notes

– 1.0.306 –

  • Added: ByteArray class to handle byte serialization, unserialization, compression and convertion to base64 operations.
  • Added: Web class to simplify the loading of assets using the WWW class.
  • Added: WebCache window to debug loading operations made by the Web class.
  • Docs: Updated script reference for the new classes.
  • Docs: Updated examples for the new ‘Web’ and ‘ByteArray’ feature.
  • Docs: Updated the manual with information about the new ‘Web’ class and its WebCache window.