1 package cz.cuni.amis.pogamut.defcon.communication.worldview.modules.managers.fleets;
2
3 import java.util.ArrayList;
4 import java.util.Collections;
5 import java.util.Iterator;
6 import java.util.LinkedList;
7 import java.util.List;
8 import java.util.Queue;
9 import java.util.SortedMap;
10 import java.util.TreeMap;
11
12 import com.google.inject.Inject;
13
14 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectEvent;
15 import cz.cuni.amis.pogamut.base.communication.worldview.object.IWorldObjectListener;
16 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectDestroyedEvent;
17 import cz.cuni.amis.pogamut.base.communication.worldview.object.event.WorldObjectFirstEncounteredEvent;
18 import cz.cuni.amis.pogamut.base3d.worldview.object.Location;
19 import cz.cuni.amis.pogamut.defcon.agent.impl.DefConAgentLogicController;
20 import cz.cuni.amis.pogamut.defcon.agent.impl.ILogicUpdateListener;
21 import cz.cuni.amis.pogamut.defcon.ai.fleetai.IFleetAI;
22 import cz.cuni.amis.pogamut.defcon.base3d.worldview.object.DefConLocation;
23 import cz.cuni.amis.pogamut.defcon.communication.messages.commands.PlaceFleet;
24 import cz.cuni.amis.pogamut.defcon.communication.messages.infos.Fleet;
25 import cz.cuni.amis.pogamut.defcon.consts.UnitType;
26
27
28
29
30
31
32
33
34 public class FleetsManager {
35
36 protected final DefConAgentLogicController<?> logic;
37
38 protected final SortedMap<Integer, List<Fleet>> enemyFleets = new TreeMap<Integer, List<Fleet>>();
39 protected final ArrayList<FleetWithAI> ownFleets = new ArrayList<FleetWithAI>();
40 protected final int ownTeamId;
41
42 protected final LinkedList<QueuedPlacing> queuedPlacings = new LinkedList<QueuedPlacing>();
43 protected final LinkedList<QueuedPlacing> oldPlacings = new LinkedList<QueuedPlacing>();
44
45
46
47
48
49
50
51 public class FleetWithAI {
52 Fleet fleet;
53 IFleetAI ai;
54
55 public FleetWithAI(Fleet fleet, IFleetAI ai) {
56 this.fleet = fleet;
57 this.ai = ai;
58 }
59
60 public final IFleetAI getAI() {
61 return ai;
62 }
63
64 public final void setAI(IFleetAI ai) {
65 this.ai = ai;
66 }
67
68 public final Fleet getFleet() {
69 return fleet;
70 }
71 }
72
73 protected class QueuedPlacing {
74 protected final Queue<DefConLocation> placementOptions;
75 protected final IPlacingFinishedListener callback;
76 protected final int expectedCount;
77 protected final Object data;
78 protected final ArrayList<Fleet> succeeded = new ArrayList<Fleet>();
79 protected final List<DefConLocation> last = new ArrayList<DefConLocation>();
80 protected final UnitType[] fleetComposition;
81 protected double lastPlacementTime;
82 protected static final double LAST_PLACEMENT_MS_LIMIT = 2500d;
83
84 public QueuedPlacing(int expectedCount,
85 UnitType[] fleetComposition,
86 Queue<DefConLocation> placementOptions,
87 Object data,
88 IPlacingFinishedListener callback) {
89
90 if (expectedCount <= 0 || fleetComposition == null
91 || placementOptions == null
92 || placementOptions.size() < expectedCount) {
93 throw new IllegalArgumentException(
94 "Invalid parameters for QueuedPlacing.");
95 }
96
97 for (int teamId : logic.getGameInfo().getEnemyTeamIds()) {
98 enemyFleets
99 .put(teamId, new ArrayList<Fleet>());
100 }
101
102 this.expectedCount = expectedCount;
103 this.placementOptions = placementOptions;
104 this.callback = callback;
105 this.data = data;
106 this.fleetComposition = fleetComposition;
107 }
108
109 public final Queue<DefConLocation> getPlacementOptions() {
110 return placementOptions;
111 }
112
113 public final int getExpectedCount() {
114 return expectedCount;
115 }
116
117 public final List<DefConLocation> getLast() {
118 return last;
119 }
120
121 public final void doPlace() {
122 if (succeeded.size() + placementOptions.size() < expectedCount ||
123 !logic.getGameInfo().canCreateFleet(fleetComposition)) {
124 queuedPlacings.remove(this);
125 oldPlacings.add(this);
126 if (callback != null) {
127 callback.placingFinished(succeeded, data, false);
128 }
129 return;
130 }
131
132 int lastCount = last.size();
133 DefConLocation location = null;
134 while (!placementOptions.isEmpty() && lastCount == last.size()) {
135 location = placementOptions.poll();
136
137 if (queuePlacingsContain(location))
138 continue;
139
140 if (!isValidPlacement(location, fleetComposition.length))
141 continue;
142
143 last.add(location);
144 break;
145 }
146
147 if (lastCount == last.size()) {
148 return;
149 }
150
151 lastPlacementTime = System.currentTimeMillis();
152 if (!placeFleetWorker(location, fleetComposition)) {
153 oldPlacings.add(this);
154 queuedPlacings.remove(this);
155 if (callback != null) {
156 callback.placingFinished(succeeded, data, false);
157 }
158 }
159 }
160
161 public final void successfulPlacement(Fleet fleet) {
162 succeeded.add(fleet);
163
164 if (succeeded.size() == expectedCount) {
165 queuedPlacings.remove(this);
166 oldPlacings.remove(this);
167 if (callback != null) {
168 callback.placingFinished(succeeded, data, true);
169 }
170 } else {
171 doPlace();
172 }
173 }
174
175 public void refresh() {
176 if (System.currentTimeMillis() - lastPlacementTime > LAST_PLACEMENT_MS_LIMIT) {
177 doPlace();
178 }
179 }
180 }
181
182 protected boolean queuePlacingsContain(Location location) {
183 for (QueuedPlacing placing : queuedPlacings) {
184 if (placing.getLast() != null && placing.getLast().equals(location)) {
185 return true;
186 }
187 }
188 return false;
189 }
190
191 @Inject
192 public FleetsManager(DefConAgentLogicController<?> logic) {
193 ownTeamId = logic.getWorldView().getGameInfo()
194 .getOwnTeamId();
195 this.logic = logic;
196 logic.getWorldView().addObjectListener(Fleet.class, listener);
197 logic.addGameLogicListener(logicUpdateListener);
198 }
199
200 protected final IWorldObjectListener<Fleet> listener =
201 new IWorldObjectListener<Fleet>() {
202
203 @Override
204 public void notify(IWorldObjectEvent<Fleet> event) {
205
206 if (event instanceof WorldObjectFirstEncounteredEvent<?>) {
207 addFleet(event.getObject());
208 }
209 if (event instanceof WorldObjectDestroyedEvent<?>) {
210 removeFleet(event.getObject());
211 }
212 }
213 };
214
215 protected final ILogicUpdateListener logicUpdateListener = new ILogicUpdateListener() {
216
217 @Override
218 public void update() {
219 if (!queuedPlacings.isEmpty())
220 queuedPlacings.peek().refresh();
221
222 for (FleetWithAI fleet : ownFleets) {
223 IFleetAI ai = fleet.getAI();
224
225 if (ai != null)
226 ai.update();
227 }
228 }
229
230 };
231
232 protected void addFleet(Fleet fleet) {
233 if (fleet.getTeamId() == ownTeamId) {
234 addOwnFleet(fleet);
235 } else {
236 addEnemyFleet(fleet);
237 }
238 }
239
240 protected void removeFleet(Fleet fleet) {
241 if (fleet.getTeamId() == ownTeamId) {
242 removeOwnFleet(fleet);
243 } else {
244 removeEnemyFleet(fleet);
245 }
246 }
247
248 protected void addEnemyFleet(Fleet fleet) {
249
250 int enemyId = fleet.getTeamId();
251 List<Fleet> singleEnemyFleets = enemyFleets
252 .get(enemyId);
253
254 if (!singleEnemyFleets.contains(fleet))
255 singleEnemyFleets.add(fleet);
256
257 }
258
259 protected void removeEnemyFleet(Fleet fleet) {
260
261 int enemyId = fleet.getTeamId();
262 List<Fleet> singleEnemyFleets = enemyFleets
263 .get(enemyId);
264
265 if (singleEnemyFleets.contains(fleet)) {
266 logic.getLog().info("Removing enemy fleet: " + fleet.getId());
267 singleEnemyFleets.remove(fleet);
268 }
269 }
270
271 protected void addOwnFleet(Fleet fleet) {
272 if (!ownFleets.contains(fleet)) {
273 ownFleets.add(new FleetWithAI(fleet, null));
274
275 logic.getLog().info(
276 "Placed fleet to: " + fleet.getLocation() + " "
277 + fleet.getId());
278 } else {
279 logic.getLog().info(
280 "WUT?! Placed fleet to: " + fleet.getLocation() + " "
281 + fleet.getId());
282 }
283
284
285 for (QueuedPlacing placings : queuedPlacings) {
286
287 for (Location loc : placings.getLast()) {
288 if (loc.equals(fleet.getLocation())) {
289 placings.successfulPlacement(fleet);
290 return;
291 }
292 }
293 }
294
295 for (QueuedPlacing placings : oldPlacings) {
296
297 for (Location loc : placings.getLast()) {
298 if (loc.equals(fleet.getLocation())) {
299 placings.successfulPlacement(fleet);
300 return;
301 }
302 }
303 }
304
305 }
306
307 protected void removeOwnFleet(Fleet fleet) {
308
309 Iterator<FleetWithAI> ownFleetsIterator = ownFleets.iterator();
310
311 while (ownFleetsIterator.hasNext()) {
312 FleetWithAI ownFleet = ownFleetsIterator.next();
313
314 if (ownFleet.fleet.getId().getLongId() != fleet.getId().getLongId())
315 continue;
316
317 logic.getLog().info("Removing own fleet: " + fleet.getId());
318
319 ownFleetsIterator.remove();
320
321 if (ownFleet.getAI() != null) {
322 ownFleet.getAI().dispose();
323 ownFleet.setAI(null);
324 return;
325 }
326
327 }
328 }
329
330
331
332
333
334
335 public SortedMap<Integer, List<Fleet>> getEnemyFleets() {
336 return Collections.unmodifiableSortedMap(enemyFleets);
337 }
338
339
340
341
342
343
344 public List<Fleet> getEnemyFleets(int enemyId) {
345
346
347
348 return Collections.unmodifiableList(enemyFleets.get(enemyId));
349 }
350
351
352
353
354
355
356 public List<FleetWithAI> getOwnFleets() {
357 return Collections.unmodifiableList(ownFleets);
358 }
359
360
361
362
363
364
365
366
367 public boolean assignAI(Fleet fleet, IFleetAI ai) {
368 for (FleetWithAI fleetWithAI : ownFleets) {
369 if (fleetWithAI.getFleet().equals(fleet)) {
370 fleetWithAI.setAI(ai);
371 return true;
372 }
373 }
374
375 return false;
376 }
377
378
379
380
381
382
383
384
385 public boolean assignAI(int fleetId, IFleetAI ai) {
386 for (FleetWithAI fleetWithAI : ownFleets) {
387 if (fleetWithAI.getFleet().getId().getLongId() == fleetId) {
388 fleetWithAI.setAI(ai);
389 return true;
390 }
391 }
392
393 return false;
394 }
395
396
397
398
399
400
401
402
403
404
405 public boolean placeFleet(DefConLocation location, UnitType[] ships,
406 Object initData,
407 IPlacingFinishedListener finishedListener) {
408
409 LinkedList<DefConLocation> tmp = new LinkedList<DefConLocation>();
410 tmp.add(location);
411
412 return placeFleet(tmp, ships, 1, initData, finishedListener);
413 }
414
415 protected boolean isValidPlacement(Location location, int count) {
416 if (logic.getGameInfo()
417 .isValidFleetPlacement(location, count)) {
418 return true;
419 } else {
420 return false;
421 }
422 }
423
424 protected boolean placeFleetWorker(DefConLocation location, UnitType[] ships) {
425
426
427 logic.getGameInfo().canCreateFleet(ships);
428
429 logic.getLog().info(
430 String.format("Placing fleet to: %s.", location.toString()));
431
432
433 logic.getAct().act(new PlaceFleet(location, ships));
434
435 return true;
436 }
437
438
439
440
441
442
443
444
445
446
447
448
449 public boolean placeFleet(
450 List<DefConLocation> orderedPlacements,
451 UnitType[] fleetComposition, int fleetsCount,
452 Object initData,
453 IPlacingFinishedListener finishedListener) {
454
455 if (fleetsCount <= 0 || orderedPlacements.size() < fleetsCount)
456 return false;
457
458 LinkedList<DefConLocation> placements = new LinkedList<DefConLocation>();
459
460 for (DefConLocation placement : orderedPlacements) {
461 placements.addLast(placement);
462 }
463
464 Iterator<DefConLocation> placementsIterator = placements.listIterator();
465
466 while (placementsIterator.hasNext()) {
467
468 Location location = placementsIterator.next();
469 if (!isValidPlacement(location, fleetComposition.length)) {
470 placementsIterator.remove();
471 if (placements.size() < fleetsCount) {
472 break;
473 }
474 }
475 }
476
477 if (placements.size() < fleetsCount) {
478 return false;
479 }
480
481 QueuedPlacing placing = new QueuedPlacing(fleetsCount,
482 fleetComposition, placements, initData, finishedListener);
483
484 queuedPlacings.add(placing);
485
486 if (queuedPlacings.size() == 1) {
487 placing.doPlace();
488 }
489
490 return true;
491 }
492 }