Crossfire JXClient, Trunk  R20561
MapUpdaterState.java
Go to the documentation of this file.
1 /*
2  * This file is part of JXClient, the Fullscreen Java Crossfire Client.
3  *
4  * JXClient is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * JXClient is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with JXClient; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17  *
18  * Copyright (C) 2005-2008 Yann Chachkoff.
19  * Copyright (C) 2006-2011 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.map;
23 
33 import java.util.Collection;
34 import java.util.HashSet;
35 import java.util.Set;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38 
51 
55  @NotNull
56  private final Object sync = new Object();
57 
61  @NotNull
62  private final FacesManager facesManager;
63 
67  @NotNull
68  private final Animations animations;
69 
73  private int mapWidth;
74 
78  private int mapHeight;
79 
83  @NotNull
84  private final CfMap map = new CfMap();
85 
89  @NotNull
91 
95  @NotNull
97 
101  @NotNull
103 
107  @NotNull
109 
113  @NotNull
115 
119  @NotNull
120  private final Collection<Location> outOfViewMultiFaces = new HashSet<>();
121 
127  public MapUpdaterState(@NotNull final FacesManager facesManager, @Nullable final GuiStateManager guiStateManager) {
128  this.facesManager = facesManager;
129  animations = new Animations(guiStateManager);
130  }
131 
136  public void addCrossfireMapListener(@NotNull final MapListener listener) {
137  mapListeners.add(listener);
138  }
139 
144  public void removeCrossfireMapListener(@NotNull final MapListener listener) {
145  mapListeners.remove(listener);
146  }
147 
152  public void addCrossfireNewmapListener(@NotNull final NewmapListener listener) {
153  newmapListeners.add(listener);
154  }
155 
160  public void removeCrossfireNewmapListener(@NotNull final NewmapListener listener) {
161  newmapListeners.remove(listener);
162  }
163 
168  public void addCrossfireMapScrollListener(@NotNull final MapScrollListener listener) {
169  mapScrollListeners.add(listener);
170  }
171 
176  public void removeCrossfireMapScrollListener(@NotNull final MapScrollListener listener) {
177  mapScrollListeners.remove(listener);
178  }
179 
184  public void addMapSizeListener(@NotNull final MapSizeListener listener) {
185  mapSizeListeners.add(listener);
186  }
187 
192  public void removeMapSizeListener(@NotNull final MapSizeListener listener) {
193  mapSizeListeners.remove(listener);
194  }
195 
199  public void reset() {
200  synchronized (sync) {
201  newMap(mapWidth, mapHeight);
202  }
203  }
204 
208  @NotNull
209  @Override
210  public Object mapBegin() {
211  return sync;
212  }
213 
217  @Override
218  public void mapClear(final int x, final int y) {
219  assert Thread.holdsLock(sync);
220  visibleAnimations.remove(x, y);
221  outOfViewMultiFaces.clear();
222  synchronized (map) {
223  map.clearSquare(x, y);
224  }
225  }
226 
230  @Override
231  public void mapFace(@NotNull final Location location, final int faceNum) {
232  mapFace(location, faceNum, true);
233  }
234 
241  public void mapFace(@NotNull final Location location, final int faceNum, final boolean clearAnimation) {
242  assert Thread.holdsLock(sync);
243  if (clearAnimation) {
244  visibleAnimations.remove(location);
245  }
246  final Face face = facesManager.getFace2(faceNum);
247  final int x = location.getX();
248  final int y = location.getY();
249  if (x >= mapWidth || y >= mapHeight) {
250  if (face == null) {
251  outOfViewMultiFaces.remove(location);
252  } else if (face.getTileWidth() > 1 || face.getTileHeight() > 1) {
253  outOfViewMultiFaces.add(location);
254  }
255  }
256  synchronized (map) {
257  map.setFace(x, y, location.getLayer(), face);
258  }
259  }
260 
264  @Override
265  public void mapAnimation(@NotNull final Location location, final int animationNum, final int animationType) {
266  assert Thread.holdsLock(sync);
267  final Animation animation = animations.get(animationNum);
268  if (animation == null) {
269  System.err.println("unknown animation id "+animationNum+", ignoring");
270  return;
271  }
272 
273  synchronized (map) {
274  map.setFace(location.getX(), location.getY(), location.getLayer(), null);
275  }
276  visibleAnimations.add(this, location, animation, animationType);
277  }
278 
282  @Override
283  public void mapAnimationSpeed(@NotNull final Location location, final int animationSpeed) {
284  assert Thread.holdsLock(sync);
285  visibleAnimations.updateSpeed(this, location, animationSpeed);
286  }
287 
291  @Override
292  public void mapSmooth(@NotNull final Location location, final int smooth) {
293  assert Thread.holdsLock(sync);
294  synchronized (map) {
295  map.setSmooth(location.getX(), location.getY(), location.getLayer(), smooth);
296  }
297  }
298 
302  @Override
303  public void mapDarkness(final int x, final int y, final int darkness) {
304  assert Thread.holdsLock(sync);
305  synchronized (map) {
306  map.setDarkness(x, y, darkness);
307  }
308  }
309 
313  @Override
314  public void magicMap(final int x, final int y, final byte[][] data) {
315  assert Thread.holdsLock(sync);
316  synchronized (map) {
317  map.setMagicMap(x, y, data);
318  }
319  }
320 
324  @Override
325  public void mapEnd() {
326  mapEnd(true);
327  }
328 
335  public void mapEnd(final boolean alwaysProcess) {
336  assert Thread.holdsLock(sync);
337  synchronized (map) {
338  final Set<CfMapSquare> squares = map.getDirtyMapSquares();
339  if (!alwaysProcess && squares.isEmpty()) {
340  return;
341  }
342 
343  for (final MapListener listener : mapListeners) {
344  listener.mapChanged(map, squares);
345  }
346  }
347  }
348 
352  @Override
353  public void mapScroll(final int dx, final int dy) {
354  assert Thread.holdsLock(sync);
355  synchronized (map) {
356  for (final Location location : outOfViewMultiFaces) {
357  visibleAnimations.remove(location);
358  map.setFace(location.getX(), location.getY(), location.getLayer(), null);
359  }
360  outOfViewMultiFaces.clear();
361 
362  if (map.processMapScroll(dx, dy, mapWidth, mapHeight)) {
363  visibleAnimations.clear();
364  } else {
365  visibleAnimations.scroll(dx, dy);
366  }
367  }
368 
369  for (final MapScrollListener mapscrollListener : mapScrollListeners) {
370  mapscrollListener.mapScrolled(dx, dy);
371  }
372  }
373 
377  @Override
378  public void faceUpdated(@NotNull final Face face) {
379  synchronized (mapBegin()) {
380  //noinspection NestedSynchronizedStatement
381  synchronized (map) {
382  map.updateFace(face.getFaceNum(), mapWidth, mapHeight);
383  }
384  mapEnd();
385  }
386  }
387 
391  @Override
392  public void newMap(final int mapWidth, final int mapHeight) {
393  synchronized (sync) {
394  final boolean changed = this.mapWidth != mapWidth || this.mapHeight != mapHeight;
395  this.mapWidth = mapWidth;
396  this.mapHeight = mapHeight;
397  //noinspection NestedSynchronizedStatement
398  synchronized (map) {
399  map.reset(mapWidth, mapHeight);
400  }
401 
402  visibleAnimations.setMapSize(mapWidth, mapHeight);
403 
404  if (changed) {
405  for (final MapSizeListener listener : mapSizeListeners) {
406  listener.mapSizeChanged(mapWidth, mapHeight);
407  }
408  }
409 
410  for (final NewmapListener listener : newmapListeners) {
411  listener.commandNewmapReceived();
412  }
413  }
414  }
415 
420  @NotNull
421  public CfMap getMap() {
422  return map;
423  }
424 
429  public int getMapWidth() {
430  return mapWidth;
431  }
432 
437  public int getMapHeight() {
438  return mapHeight;
439  }
440 
444  @Override
445  public void addAnimation(final int animation, final int flags, @NotNull final int[] faces) {
446  animations.addAnimation(animation, flags, faces);
447  }
448 
452  @Override
453  public void tick(final int tickNo) {
454  synchronized (sync) {
455  visibleAnimations.tick(this, tickNo);
456  }
457  }
458 
459 }
void addAnimation(final int animation, final int flags, @NotNull final int[] faces)
An "addanim" command has been received.the animation ID the animation flags the faces list; must not ...
void removeMapSizeListener(@NotNull final MapSizeListener listener)
Removes a listener to be notified about map size changes.
Face getFace2(int faceNum)
Returns the Face instance for a given face ID.
void addMapSizeListener(@NotNull final MapSizeListener listener)
Adds a listener to be notified about map size changes.
final CfMap map
The current CfMap instance.
int getMapHeight()
Returns the height of the visible map area.
void setFace(final int x, final int y, final int layer, @Nullable final Face face)
Sets the face of one square.
Definition: CfMap.java:257
int getMapWidth()
Returns the width of the visible map area.
final CfMapAnimations visibleAnimations
The animations in the visible map area.
void setDarkness(final int x, final int y, final int darkness)
Sets the darkness value of one square.
Definition: CfMap.java:159
void addCrossfireNewmapListener(@NotNull final NewmapListener listener)
Adds a listener to notify about cleared maps.
void mapClear(final int x, final int y)
Part of "map2" parsing: clear a cell.the x-coordinate the y-coordinate
void addAnimation(final int animationId, final int flags, @NotNull final int[] faces)
Defines a new animation.
CfMap getMap()
Returns the current map instance.
Represents a map (as seen by the client).
Definition: CfMap.java:45
final Animations animations
The defined animations.
int getTileHeight()
Returns the face height in tiles.
Definition: Face.java:157
void updateSpeed(@NotNull final MapUpdaterState mapUpdaterState, @NotNull final Location location, final int speed)
Updates the animation speed value.
final Object sync
The object used for synchronization.
void removeCrossfireNewmapListener(@NotNull final NewmapListener listener)
Removes a listener to notify about cleared maps.
final Collection< Location > outOfViewMultiFaces
All multi-tiled faces with heads outside the visible map area.
void clearSquare(final int x, final int y)
Clears the content of one square.
Definition: CfMap.java:390
Interface for listeners interested in "tick" commands.
Interface for listeners interested on map scrolled events.
Set< CfMapSquare > getDirtyMapSquares()
Returns the dirty map squares.
Definition: CfMap.java:759
void mapSmooth(@NotNull final Location location, final int smooth)
Part of "map2" parsing: set the smooth level.the location the smooth value
void mapDarkness(final int x, final int y, final int darkness)
Part of "map2" parsing: change the darkness of a cell.the x-coordinate the y-coordinate the darkness ...
void add(@NotNull final MapUpdaterState mapUpdaterState, @NotNull final Location location, @NotNull final Animation animation, final int type)
Adds a visible animation.
void removeCrossfireMapScrollListener(@NotNull final MapScrollListener listener)
Removes a listener to notify about scrolled maps.
Object mapBegin()
Parsing of a "map2" command has been started.the synchronization object which must besynchronized wh...
Manages image information ("faces") needed to display the map view, items, and spell icons...
final FacesManager facesManager
The FacesManager to track for updated faces.
final EventListenerList2< NewmapListener > newmapListeners
The listeners to notify about cleared maps.
final EventListenerList2< MapSizeListener > mapSizeListeners
The MapSizeListeners to be notified.
void addCrossfireMapScrollListener(@NotNull final MapScrollListener listener)
Adds a listener to notify about scrolled maps.
boolean processMapScroll(final int dx, final int dy, final int width, final int height)
Processes a map scroll command.
Definition: CfMap.java:799
Listener for clients interested in map size changes.
void scroll(final int dx, final int dy)
Scrolls the animations.
void reset(final int mapWidth, final int mapHeight)
Clears the map contents.
Definition: CfMap.java:133
void updateFace(final int faceNum, final int width, final int height)
Processes an updated face image.
Definition: CfMap.java:772
MapUpdaterState(@NotNull final FacesManager facesManager, @Nullable final GuiStateManager guiStateManager)
Creates a new instance.
Manages a set of animated map squares.
void setMagicMap(final int x0, final int y0, final byte[][] data)
Sets the magic map color of one square.
Definition: CfMap.java:223
void remove(final int x, final int y)
Removes all visible animations for a tile.
void mapFace(@NotNull final Location location, final int faceNum, final boolean clearAnimation)
Updates a map square by changing a face.
Interface for listeners interested in changes within CfMap instances.
void mapAnimationSpeed(@NotNull final Location location, final int animationSpeed)
Part of "map2" parsing: set the animation speed.the location the animation speed
Interface for listeners interested in FacesManager events.
void addCrossfireMapListener(@NotNull final MapListener listener)
Adds a listener to notify about changed map squares.
Update a CfMap model from protocol commands.
void add(@NotNull final T listener)
Adds a listener.
void mapAnimation(@NotNull final Location location, final int animationNum, final int animationType)
Part of "map2" parsing: set the animation of a cell.the location the animation ID the animation type ...
void magicMap(final int x, final int y, final byte[][] data)
Part of "magicmap" parsing: set the magic map color.the x-coordinate the y-coordinate the magic map d...
void tick(@NotNull final MapUpdaterState mapUpdaterState, final int tickNo)
Processes a tick command.
int getTileWidth()
Returns the face width in tiles.
Definition: Face.java:149
Manages animations received from the server.
Definition: Animation.java:31
void faceUpdated(@NotNull final Face face)
Called when a Face has been updated.the face
void setMapSize(final int width, final int height)
Updates the map size.
int mapWidth
The width of the visible map area.
final EventListenerList2< MapListener > mapListeners
The listeners to notify about changed map squares.
void mapScroll(final int dx, final int dy)
Part of "map2" parsing: scroll the map view.the x-distance the y-distance
void mapEnd(final boolean alwaysProcess)
Finishes processing of a set of map square changes.
Interface for listeners interested in received "newmap" messages.
final EventListenerList2< MapScrollListener > mapScrollListeners
The listeners to notify about scrolled maps.
void removeCrossfireMapListener(@NotNull final MapListener listener)
Removes a listener to notify about changed map squares.
int mapHeight
The height of the visible map area.
Animation get(final int animationId)
Returns the animation for an animation id.
void remove(@NotNull final T listener)
Removes a listener.
void mapEnd()
Parsing of "map2" has been finished.
Manages animations received from the server.
Definition: Animations.java:37
void tick(final int tickNo)
A "tick" command has been received.the current tick
void newMap(final int mapWidth, final int mapHeight)
A "newmap" command has been received.the map width the map height
void mapFace(@NotNull final Location location, final int faceNum)
Part of "map2" parsing: set the face of a cell.the location the face ID
void setSmooth(final int x, final int y, final int layer, final int smooth)
Sets the smooth value of one square.
Definition: CfMap.java:188
Maintains a mapping of face numbers to face data.