PogamutUT2004


Fast Traces in getSimpleRayCasting()

I would like to use fast ray traces for something, and I don't mind
having the bot do nothing while waiting for the FastTraceResponse.
Therefore, I would like one method that sends the fast trace message,
and blocks for the response, which is then returned by the method.
Of course, somewhere in here there has to be a listener for
FastTraceResponses as well. Here is what I'm trying:

private final BlockingQueue pendingFastTraces = new ArrayBlockingQueue(1, true);
    
IWorldEventListener fastTraceResponseHandler = new IWorldEventListener() {

        @Override
        public void notify(FastTraceResponse ftr) {
            try {
                pendingFastTraces.put(ftr);
            } catch (InterruptedException ex) {
            }
        }
    };

This is added via:

world.addEventListener(FastTraceResponse.class, fastTraceResponseHandler);


Then there is the method call to get the trace result.

public Boolean quickTraceThroughWall(Location target) {
        String id = "Quick";
        body.getSimpleRayCasting().fastTrace(id, target);
        FastTraceResponse ftr;
        try {
            ftr = pendingFastTraces.take();
        } catch (InterruptedException ex) {
            return null;
        }
        return ftr.isResult();
    }


The BlockingQueue is supposed to automatically handle synchronization.
The take() method should make the Thread wait for the listener to put the trace response
in the queue, but what happens when I run this is the take() causes a the logic thread to
wait (I've looked at the profile) while the mediator (which handles the listener) continues
to run, but never actually executes the notify method.

Any advice for how to accomplish what I want?
Also, just to preemptively deal with possible trouble-shooting advice I might get:

I know that the listener works, because if I remove the BlockingQueue and simply have a
println() in the listener's notify() method, it prints out the value of the trace response.
The issue is that the listener is starving.

Also, despite the fact that the BlockingQueue is supposed to be a helpful abstraction that
makes things easier, I've also tried doing this using synchronized blocks, and I run into
the same problem:

FastTraceResponse storedFTR = null;
    final Object mutex = this;

IWorldEventListener fastTraceResponseHandler = new IWorldEventListener() {

        @Override
        public void notify(FastTraceResponse ftr) {
            synchronized(mutex){
                storedFTR = ftr;
                mutex.notifyAll();
            }
        }
    };


    public Boolean quickTraceThroughWall(Location target) {
        String id = "Quick";
        body.getSimpleRayCasting().fastTrace(id, target);
        Boolean result = null;
        synchronized (mutex) {
            while(storedFTR == null){
                try {
                    mutex.wait(500);
                } catch (InterruptedException ex) {
                    return null;
                }
            }
            result = storedFTR.isResult();
            storedFTR = null;
        }
        return result;
}


This code has the same problem: quickTraceThroughWall waits forever, and the listener
never executes.
Hmmm, seems that the preexisting synchronization prevents the mediator from doing anything
with the listeners while the logic() method is being executed by the logic thread. It is impossible
to get a result from a fast trace response listener during the same call to logic() that made the request.

That's annoying...
That could be possible.

It could work like this: While in one call of logic method the whole worldView is locked - the updates are not propagated and are in queue waiting for logic to finish. After it finishes everything updates. This would be there because we want to have consistent state of worldView during one call of the logic method. The conditionals I am using are due to that I am not sure how this really works - Jakub Gemrot knows exactly, but he is out of town I guess. I've notified him, so when he will have time he'll respond.

Could you try this: Create a listener on EndMessage event and in notify method of EndMessage listener call some method of yours (lets call it CustomLogic) where you'll try to use the synchronization you were talking about. This CustomLogic should be called as often as logic and it could not suffer from the limitations of logic. (Although I am thinking that the worldView sync. will be probably in all calls of methods on the bot...)

Sorry for this fuzzy answer. :-)
Michal
Yeah, that's the problem.

Once in logic, all events are postponed, so you're waiting forever.

Such behavior may be changed, but it would require you to play with Guice / UT2004BotController and all nasty Pogamut stuffs that are under the hood...

Cheers,
Jimmy
 

News

News RSS RSS feed for News link



Pogamut

Quarterly RSS RSS feed for quarterly reports

Acknowledgement

This work is supported by GA UK 1053/2007/A-INF/MFF (2007-8), GA UK 351/2006/A-INF/MFF (2006-8), the Ministry of Education of the Czech Republic (grant MSM0021620838) (2008-9), by the Program "Information Society" under project 1ET100300517 (2006-9), and the project Integration of IT Tools into Education of Humanities (2006-8) and by the project CZ.2.17/3.1.00/31162, which are financed by the European Social Fund, the state budget of the Czech Republic, and by the budget of Municipal House Prague.