Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

ModuleConnector: allow module instances communicate with each other #141

Open
creynders opened this issue Jun 22, 2013 · 13 comments
Open

ModuleConnector: allow module instances communicate with each other #141

creynders opened this issue Jun 22, 2013 · 13 comments
Assignees

Comments

@creynders
Copy link
Member

If you try to have several instance of the same module communicate with each other through the module connector, you run into an infinite loop:

moduleConnector.onChannel('A-and-B')
.receiveEvent(ModularConnectorEvent.SOME_TYPE);

moduleConnector.onChannel('A-and-B')
.relayEvent (ModularConnectorEvent.SOME_TYPE);

see http://knowledge.robotlegs.org/discussions/robotlegs-2/3327-go-modular-for-multiple-games

@ghost ghost assigned creynders Jun 22, 2013
@creynders
Copy link
Member Author

cc @Ondina

@Ondina
Copy link
Member

Ondina commented Jun 22, 2013

@creynders
Copy link
Member Author

Yeah I saw it, but though that's ok as a temporary solution, this is something that needs to be fixed.
Need to think on how to fix it though.

@Ondina
Copy link
Member

Ondina commented Jun 22, 2013

Of course.

@creynders
Copy link
Member Author

Wow, you're totally losing me :)

How does that exactly help? You'd still need to do this:

[Inject (name='A-and-B')]
public var eventDispatcher:IEventDispatcher;

eventDispatcher.dispatchEvent(ModularConnectorEvent.A_TO_B_MESSAGE);

Right? We're still talking about a module instance sending events to other instances of the same module, right?

@Ondina
Copy link
Member

Ondina commented Jun 22, 2013

Yeah, I deleted the bs. My intention was to have a dispatcher for the inter-instances communication that doesn’t relay any events and kind of a local interceptor that would decide what to do with the received event, maybe made clear in the mappings or a guard ...weird, I know.

As I understand (still studying the code), the infinite loop is caused by having the same dispatcher as a receiver and as a relayer, listening to and dispatching the same event. The moment it receives the event, it relays it again.

Anyway, I’ll continue studying the ModuleConnector & Co and keep my mouth shut ;)

@creynders
Copy link
Member Author

Anyway, I’ll continue studying the ModuleConnector & Co and keep my mouth shut ;)

No, no, that's how solutions are found. 99% BS and 1% good ideas. At least
that's how it is for me. :)

@darscan
Copy link
Member

darscan commented Jun 22, 2013

I remember worrying about circular relays.. and even possibly coming up with solution.. and then totally forgetting. The fix probably needs to live in the EventRelay.

@Ondina
Copy link
Member

Ondina commented Jul 26, 2013

I made another attempt to break the infinite loop. BS or not, but it works.

I couldn't create a gist for some reasons, so here is the code:
https://github.com/Ondina/robotlegs-bender-modular-air/wiki/ModuleConnectionConfigurator---breaking-the-infinite-loop

[1] localDispatcher dispatches
[2] channelDispatcher listens
[3] channelDispatcher dispatches
[4] localDispatcher listens
[5] localDispatcher dispatches
[6] channelDispatcher listens
[7] channelDispatcher dispatches
and so on

Here is the loop breaker:


public function onEventDispatched(event:*):void
{
    if (_channelDispatcher == event.target)
    {
        _localDispatcher.removeEventListener(event.type, _channelDispatcher.dispatchEvent);
    }
    else
    {
        _localDispatcher.addEventListener(event.type, _channelDispatcher.dispatchEvent);
    }
}

I looked at the EventRelay and I think it's not the right place to make changes, since all it does is adding and removing listeners and it shouldn't have to know about events being dispatched.
In fact, the ModuleConnectionConfigurator should not be burdened with that either, but where else do we have access to the dispatchers and the event types?

I also thought about using event's useCapture and phases or event.stopPropagation() inside of EventRelay , but I couldn't work it out, maybe because it doesn't make sense at all? Sorry for the ramblings, but infinite loops are dizzying...

I'm sure you'll come up with something better, so I'm really very curious about your solution to that ouroboric situation :)

@darscan could you, at least, give me a hint about the solution you had in mind

@darscan
Copy link
Member

darscan commented Jul 26, 2013

Interesting solution! I honestly can't remember where my thinking was at regarding this stuff. I'll have another dabble this w/e, and give more thought to your solution as well.

@Ondina
Copy link
Member

Ondina commented Jul 27, 2013

@darscan alright, there is no rush

Another thing I've tried was to have a callback function for each dispatcher, where they'd let the other dispatcher dispatch the event only if it wasn't already dispatched, depending on a counter. I could make it work only for instances of the same module. Somehow the counting was messed up for other modules and I gave up on this approach.
I don't know what's better, relaying events manually depending on some condition, or adding/removing event listeners as I showed in my previous message. Anyway, adding/removing listeners was easier for me to implement while keeping the original logic of all the involved classes.

Btw, I changed the code a bit:


public function onEventDispatched(event:Event):void
{
   if (_channelDispatcher == event.target)
         _localToChannelRelay.removeType(event.type);
   else
        _localToChannelRelay.addType(event.type);
}

and added the type (EventRelay.addType) to the _types only if the type is not in _types.

[EDIT]
I made it work (relaying events manually based on a counter) for all modules - different instances of same module *and different modules as well. I had to reset the counter in case the module did not have a mapping for receiving an event type. Still, not convinced it's a good approach.

@Ondina
Copy link
Member

Ondina commented Jul 30, 2013

Progress report

https://github.com/Ondina/robotlegs-bender-modular-air/wiki/ModuleConnectionConfigurator---take-2

It's just a draft.

I add listeners to the parentDispatcher:


_parentDispatcher.addEventListener(ModularRouterEvent.LOCAL_TO_PARENT, parentToLocalRouter);

and to the localDispatcher:


public function addListener(eventType:String):void
{
    _eventTypeDispatched[eventType] = false;
    _localDispatcher.addEventListener(eventType, localToParentRouter);
}

The handlers:


private function localToParentRouter(event:Event):void
{
    if (!_eventTypeDispatched[event.type])
    {
        _eventTypeDispatched[event.type] = true;
        _parentDispatcher.dispatchEvent(new ModularRouterEvent(ModularRouterEvent.LOCAL_TO_PARENT, _context, event, event.type));
    }
    _eventTypeDispatched[event.type] = false;
}
private function parentToLocalRouter(event:ModularRouterEvent):void
{
    if (_context != event.context)
    {
        _eventTypeDispatched[event.eventType] = true;
        _localDispatcher.dispatchEvent(event.eventClass);
    }
}

@Ondina
Copy link
Member

Ondina commented Jul 31, 2013

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants