Wednesday, July 30, 2008

Of Disappointment

I came to the conclusion that I really wanted to implement object pooling for the Entity System, but I think I've hit two or three (or many more) snags along the way.

The more I try to add this feature to the ES, the more I realize I have to rewrite a good part of the compiler too (make it 80%). I have based the design of the ES upon different assumptions, and now stitching new stuff is proving to be very difficult.

Moreover, I'm not sure all of this will be eventually worth the effort.

So, as much as I'd love to release an ES with an object pool, I don't seem able to pull it off with the current design. It'll have to wait for a new ES version, when perhaps I'll have the time to rewrite it from scratch. This will also mean I'll break the compatibility with assemblies produced with the old compiler.

Bah.

Edit: hell, since I love to rewrite code, I think I'm going to redo the compiler from scratch, this time taking in account everything. I haven't been analysing the problem at hand enough, and that's the result! Don't follow my example! ç_ç/

3 comments:

Ash said...

The most important issue regarding component-based entity systems that has got me by the balls for quite some time now, is a matter of communication. How should one setup the route for components and entities to communicate?

This sounds really easy at first, but there are several problems that are bothering me. First and foremost, is lack of knowledge! I've been programming for a long time now but I've never even touched the surface of even-driven programming on one hand and multi-threading on the other.

I want my system to be multi-threaded. As far as I know, there are only two methods for separate threads to communicate: shared memory access and events. This is where events kick in, in my design.

Besides, I'm mainly a C++ programmer. Of course every competent programmer can read and understand programs that are written in another language in a matter of minutes, but it's one thing to understand programs written in another language; it's totally another thing to be familiar with a language's quirks and ups and downs.

The moral of the story is that I don't have the luxury of using .NET delegates, events and rock-solid and easy-to-use threads which complicates the matters even further.

I haven't really got enough time to play with the event system. I'm sure it's nothing mind-blowing and given enough time, I can easily handle it but the point is that our quest for a kick-ass component-based entity system has lead us into an unknown realm with its own set of complications. Trying to get a multi-threaded event-based system up and running on top of all that complicates the matters even further.

I was wondering how you are going to tackle this problem. How *exactly* are you going to route events between components? We talked about that once before. Have you updated your system ever since? There are several types of communication that I can think of:

1) A component trying to send a message to another component in the same entity.

2) A component trying to send a message to a component of the same type in another entity.

3) A component trying to send a message to a component of different type in another entity.

How many levels/routes are you going to design? What's your approach?

Regards,
Ashkan

PS. I also had another question regarding resource caching that I left as a comment at the end of a related post (which I can't remember the name). Please give it a look.

Many thanks

Raine said...

Ashkan: First, thanks a lot for stopping by, it's great to read such comments on my newly created blog! :)

I'll reply first to your question: everything revolves around messages. Messages are sent and received by any entity. Messages are universal, and every entity can receive any message, provided they "can" (read: they have a component with a particular handler for it).

What comes next is a different story, though.

Components basically define an aspect of the entity containing them. This is why components include Handlers, whose job is to process a particular Message type.

If an entity has a MyMessage handler, it will process it, otherwise the message will pass by basically unnoticed.

We don't know beforehand if an entity has a component with a handler for a particular message. All we know is that we have a system, many system-wide messages and that we want to have entities in this system ready to react to some (or all, it doesn't matter) messages.

So, in all the uncertainty created by the combination of entities and their components, we only know about messages. Imagine a deaf man; every Sound message wouldn't be "processed" because the lack of a "Hearing" component. The "Sound message" is decoupled from any entity or any component. It's just there, sent by the System (which has a Sound message by design).

Long story short, either the System or an Entity sends messages to another Entity or a family of Entities. There's no component-to-component communication.

I don't know if my Target entity has a "Hearing" component, and I don't want to check either.

This hasn't changed much since the last time we spoke, actually.

The last thing to consider is "event (message) priority". The flags in the Handler descriptor allow us to suggest they way many different handlers stack on each other, making it possible to define an ever more complex behaviour independently from the handler combinations present in an entity.

I'm not a C++ expert (I don't want to be one right now); however, trying to recreate the ease of use of threads in the .net framework could be a winning move. An object encapsulating threading functionality would surely help, imho. As for delegates, I have to say I'm not using them to dispatch messages.

I have a list of IMessage objects, all of which provide an implementation for the Invoke method, which gets called eventually.

Events the way they are in C++ are different from what I'm aiming for (and C# events are in the same ballpark). I need the last say on when messages are processed, and not rely on the async nature of events.

So I feel like suggesting implementing a simple producer / consumer queue allowing you to process messages (or whatever) serially, no matter where they come from (be it the main thread or the ES thread itself).

Looking forward to hearing from you, and please let me know if I was unclear... :)

Ash said...

Roberto,

Thanks for taking the time and sharing your view. Sorry if I couldn't get to you sooner as I've been very busy lately.

I will respond as soon as I find some free time to think about your solutions...

Keep up the good work pal :)

Regards,
Ashkan