View Javadoc

1   package cz.cuni.amis.pogamut.ut2004.agent.navigation.stuckdetector;
2   
3   import java.util.logging.Level;
4   import java.util.logging.Logger;
5   
6   import cz.cuni.amis.pogamut.base.agent.navigation.IStuckDetector;
7   import cz.cuni.amis.pogamut.base.communication.worldview.IWorldView;
8   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
9   import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
10  import cz.cuni.amis.pogamut.base3d.worldview.object.ILocated;
11  import cz.cuni.amis.pogamut.ut2004.bot.impl.UT2004Bot;
12  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbcommands.SendMessage;
13  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.GlobalChat;
14  import cz.cuni.amis.pogamut.ut2004.communication.messages.gbinfomessages.Self;
15  
16  /**
17   * Simple {@link IStuckDetector} that watches whether the bot moves at all.
18   * <p>
19   * <p>
20   * You may define a period of time (timeout) in which the bot should move on,
21   * i.e., if the bot won't move a bit in a specified amount of time, it will
22   * report a stuck.
23   * 
24   * @author Jimmy, knight
25   */
26  public class UT2004TimeStuckDetector implements IStuckDetector {
27  
28  	/**
29  	 * Default distance that is regarded as "bot did not move a bit".
30  	 */
31  	private static final double NO_MOVEMENT_SIZE = 10;
32  
33  	/**
34  	 * Default timeout after which the detector reports stuck if the bot did not
35  	 * move. In miliseconds!
36  	 */
37  	private static int DEFAULT_TIMEOUT = 3000;
38  
39  	/**
40  	 * Default timeout when the bot is waiting for something... In milliseconds!
41  	 */
42  	private static int DEFAULT_WAITING_TIMEOUT = 10000;
43  
44  	/**
45  	 * Owner of the detector.
46  	 */
47  	private UT2004Bot bot;
48  
49  	/**
50  	 * Timeout used by the detector, when the bot is not waiting, initialized in
51  	 * the constructor.
52  	 */
53  	private double timeout;
54  
55  	/**
56  	 * Timeout used by the detector when the bot is waiting, initialized in the
57  	 * constructor.
58  	 */
59  	private double waitingTimeout;
60  
61  	private boolean botWaiting = false;
62  
63  	/**
64  	 * In reset set to false. In isStuck set to true - indicator if this
65  	 * detector was already queried after reset about bot stucking.
66  	 */
67  	private boolean bWasIsStuckCalled = false;
68  	/** Here we store current time of the simulation. */
69  	private long currentTime;
70  
71  	/**
72  	 * Listener watching for the {@link Self} message. Recalls
73  	 * {@link UT2004TimeStuckDetector#eventSelf(IWorldObjectEvent)}.
74  	 * 
75  	 * @author Jimmy
76  	 */
77  	private class SelfListener implements IWorldObjectListener<Self> {
78  
79  		public SelfListener(IWorldView worldView) {
80  			worldView.addObjectListener(Self.class, this);
81  		}
82  
83  		@Override
84  		public void notify(IWorldObjectEvent<Self> event) {
85  			eventSelf(event);
86  		}
87  
88  	};
89  
90  	/**
91  	 * Listener that triggers
92  	 * {@link UT2004TimeStuckDetector#eventSelf(IWorldObjectEvent)}.
93  	 */
94  	private SelfListener selfListener;
95  
96  	/**
97  	 * Last time when the bot has moved (its velocity had been greater than
98  	 * {@link UT2004TimeStuckDetector#NO_MOVEMENT_SIZE}.
99  	 */
100 	private Double lastMovementTime = null;
101 
102 	/**
103 	 * Whether we should report that the bot has stuck.
104 	 */
105 	private boolean stuck = false;
106 	
107 	private boolean enabled;
108 
109 	private Logger log;
110 
111 	public UT2004TimeStuckDetector(UT2004Bot bot) {
112 		this(bot, DEFAULT_TIMEOUT, DEFAULT_WAITING_TIMEOUT);
113 	}
114 
115 	public UT2004TimeStuckDetector(UT2004Bot bot, double timeoutMillis,
116 			double waitingTimeoutMillis) {
117 		if (this.log == null) {
118 			this.log = bot.getLogger().getCategory(
119 					this.getClass().getSimpleName());
120 		}
121 		this.bot = bot;
122 		this.timeout = timeoutMillis;
123 		this.waitingTimeout = waitingTimeoutMillis;
124 		selfListener = new SelfListener(bot.getWorldView());
125 	}
126 
127 	public void eventSelf(IWorldObjectEvent<Self> event) {
128 		if (!enabled) return;
129 		// we always update current time
130 		currentTime = event.getObject().getSimTime();
131 		// if we were not yet querried about stucking we will simply do nothing!
132 		if (!bWasIsStuckCalled) {
133 			return;
134 		}
135 		if (event.getObject().getVelocity().size() > NO_MOVEMENT_SIZE || lastMovementTime == null) {
136 			lastMovementTime = (double) event.getObject().getSimTime();
137 		}
138 		if (botWaiting) {
139 			if (event.getObject().getSimTime() - lastMovementTime >= waitingTimeout) {
140 				stuck = true;
141 				if (log != null && log.isLoggable(Level.WARNING)) log.warning("Bot is WAITING for more than " + waitingTimeout + " ms, considering that it has stuck.");
142 			}
143 		} else {
144 			if (event.getObject().getSimTime() - lastMovementTime >= timeout) {
145 				stuck = true;
146 				if (log != null && log.isLoggable(Level.WARNING)) log.warning("Bot should be moving but it is standing still for more than " + timeout + " ms, considering that it has stuck.");
147 			}
148 		}
149 	}
150 	
151 	@Override
152 	public void setEnabled(boolean state) {
153 		if (this.enabled == state) return;
154 		this.enabled = state;		
155 	}
156 
157 	@Override
158 	public void setBotWaiting(boolean state) {
159 		botWaiting = state;
160 		lastMovementTime = null;
161 	}
162 
163 	@Override
164 	public boolean isStuck() {
165 		if (!bWasIsStuckCalled) {
166 			// isStuck called for the first time after reset - we return false
167 			// and we reset lastMovementTime
168 			lastMovementTime = (double) currentTime;
169 			bWasIsStuckCalled = true;
170 			return false;
171 		}
172 		return stuck;
173 	}
174 
175 	@Override
176 	public void reset() {
177 		if (log != null && log.isLoggable(Level.FINER)) log.finer("Reset.");
178 		lastMovementTime = Double.NEGATIVE_INFINITY;
179 		bWasIsStuckCalled = false;
180 		stuck = false;
181 	}
182 
183 	@Override
184 	public void setBotTarget(ILocated target) {
185 		// WE DO NOT CARE
186 	}
187 
188 }