Crossfire JXClient, Trunk
CfAnimations.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-2017,2019-2023 Andreas Kirschbaum
20  * Copyright (C) 2010-2012,2014-2018,2020-2023 Nicolas Weeger
21  */
22 
23 package com.realtime.crossfire.jxclient.map;
24 
33 import java.util.ArrayList;
34 import java.util.Collection;
35 import java.util.HashMap;
36 import java.util.HashSet;
37 import java.util.Map;
38 import java.util.Random;
39 import java.util.random.RandomGenerator;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
42 
47 public class CfAnimations {
48 
52  @NotNull
53  private static final Object SYNC = new Object();
54 
58  @NotNull
59  private final ItemSet itemSet;
60 
64  @NotNull
65  private final FacesManager facesManager;
66 
70  @NotNull
71  private final Animations animations;
72 
76  @NotNull
77  private final Collection<Integer> unknownAnimations = new HashSet<>();
78 
83  @NotNull
84  private final RandomGenerator random = new Random();
85 
89  @NotNull
90  @SuppressWarnings("FieldCanBeLocal")
92 
93  @Override
94  public void playerChanged(@Nullable final CfItem player) {
95  if (!tags.isEmpty()) {
96  System.err.println("Warning: player inventory is not empty when changing players");
97  for (final int tag : tags.values()) {
98  tagRemove(tag);
99  }
100  tags.clear();
101  }
102 
103  if (playerTag != -1) {
105  }
106  playerTag = player == null ? -1 : player.getTag();
107  if (playerTag != -1) {
109  }
110  }
111 
112  @Override
113  public void openContainerChanged(final int tag) {
114  }
115 
116  };
117 
121  @NotNull
122  @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
124 
125  @NotNull
126  @Override
127  public Object mapBegin() {
128  return SYNC;
129  }
130 
131  @Override
132  public void mapFace(@NotNull final Location location, final int faceNum) {
133  }
134 
135  @Override
136  public void mapEnd() {
137  }
138 
139  };
140 
144  private int mapWidth;
145 
149  private int mapHeight;
150 
154  @NotNull
155  private final AnimationMap mapAnimations = new AnimationMap();
156 
160  @NotNull
161  private final AnimationSet tagAnimations = new AnimationSet();
162 
167  @NotNull
168  private final Collection<AnimationState> animationStates = new HashSet<>();
169 
173  @NotNull
174  private final Map<Integer, AnimationState> syncAnimationStates = new HashMap<>();
175 
180  @NotNull
181  private final Collection<AnimationState> pendingTickUpdates = new ArrayList<>();
182 
186  @NotNull
188 
189  @Override
190  public void itemChanged(final int tag) {
191  }
192 
193  @Override
194  public void itemRemoved(final int tag) {
195  }
196 
197  @Override
198  public void inventoryAdded(final int tag, final int index, @NotNull final CfItem item) {
199  final int itemTag = item.getTag();
200  final int anim = item.getAnim();
201  final int animSpeed = item.getAnimSpeed();
202  if (anim != 0) {
203  final Animation animation = animations.get(anim&Map2.ANIM_MASK);
204  if (animation == null) {
205  if (unknownAnimations.add(anim&Map2.ANIM_MASK)) {
206  System.err.println("Unknown animation id "+(anim&Map2.ANIM_MASK)+", ignoring");
207  }
208  return;
209  }
210 
211  final Integer prevTag = tags.put(index, itemTag);
212  if (prevTag != null) {
213  tagRemove(prevTag);
214  }
215  tagAdd(itemTag, animation, (anim>>Map2.ANIM_TYPE_SHIFT)&Map2.ANIM_TYPE_MASK);
216  tagAnimations.updateSpeed(itemTag, animSpeed);
217  }
218  }
219 
220  @Override
221  public void inventoryRemoved(final int tag, final int index) {
222  final Integer prevTag = tags.remove(index);
223  if (prevTag == null) {
224  return;
225  }
226 
227  tagRemove(prevTag);
228  }
229 
230  };
231 
235  @NotNull
236  private final Map<Integer, Integer> tags = new HashMap<>();
237 
241  private int playerTag = -1;
242 
249  public CfAnimations(@NotNull final ItemSet itemSet, @NotNull final FacesManager facesManager, @NotNull final Animations animations) {
250  this.itemSet = itemSet;
251  this.facesManager = facesManager;
252  this.animations = animations;
253 
255  }
256 
261  public void setMapListener(@NotNull final CfAnimationsMapListener mapListener) {
262  this.mapListener = mapListener;
263  }
264 
268  public void mapClear() {
270  final Collection<AnimationState> tagAnimationStates = tagAnimations.getAllAnimationStates();
271  animationStates.retainAll(tagAnimationStates);
272  for (final AnimationState animationState : animationStates) {
273  animationState.freeAllLocations();
274  }
275  syncAnimationStates.values().retainAll(tagAnimationStates);
276  pendingTickUpdates.retainAll(tagAnimationStates);
277  }
278 
285  public void mapAdd(@NotNull final Location location, @NotNull final Animation animation, final int type) {
286  mapAnimations.add(location, add(animation, type));
287  }
288 
294  public void mapRemove(final int x, final int y) {
295  for (int layer = 0; layer < Map2.NUM_LAYERS; layer++) {
296  mapAnimations.remove(new Location(x, y, layer));
297  }
298  }
299 
304  public void mapRemove(@NotNull final Location location) {
305  mapAnimations.remove(location);
306  }
307 
313  public void mapUpdateSpeed(@NotNull final Location location, final int speed) {
314  mapAnimations.updateSpeed(location, speed);
315  }
316 
323  public void mapScroll(final int dx, final int dy) {
325  }
326 
332  public void mapSetSize(final int mapWidth, final int mapHeight) {
333  this.mapWidth = mapWidth;
334  this.mapHeight = mapHeight;
335  mapClear();
336  }
337 
342  public void tick(final int tickNo) {
343  for (AnimationState animationState : pendingTickUpdates) {
344  animationState.setTickNo(tickNo);
345  }
346  pendingTickUpdates.clear();
347  final Iterable<AnimationState> animationStatesToUpdate = new ArrayList<>(animationStates);
348  synchronized (mapListener.mapBegin()) {
349  for (AnimationState animationState : animationStatesToUpdate) {
350  animationState.updateTickNo(tickNo);
351  }
353  }
354  }
355 
362  private void tagAdd(final int tag, @NotNull final Animation animation, final int type) {
363  tagAnimations.add(tag, add(animation, type));
364  }
365 
370  private void tagRemove(final int tag) {
371  tagAnimations.remove(tag);
372  }
373 
380  @NotNull
381  private AnimationState add(@NotNull final Animation animation, final int type) {
382  assert 0 <= type && type < 4;
383 
384  final AnimationState animationState;
385  final boolean addToPendingTickUpdates;
386  switch (type) {
387  default: // invalid; treated as "normal"
388  case Map2.ANIM_NORMAL: // animation starts at index 0
389  animationState = new AnimationState(animation, 0, mapListener, itemSet, facesManager);
390  addToPendingTickUpdates = true;
391  break;
392 
393  case Map2.ANIM_RANDOM: // animation starts at random index
394  animationState = new AnimationState(animation, random.nextInt(animation.getFaces()), mapListener, itemSet, facesManager);
395  addToPendingTickUpdates = true;
396  break;
397 
398  case Map2.ANIM_SYNC: // animation is synchronized with other animations
399  final int animationId = animation.getAnimationId();
400  final AnimationState tmp = syncAnimationStates.get(animationId);
401  if (tmp == null) {
402  animationState = new AnimationState(animation, 0, mapListener, itemSet, facesManager);
403  syncAnimationStates.put(animationId, animationState);
404  addToPendingTickUpdates = true;
405  } else {
406  animationState = tmp;
407  addToPendingTickUpdates = false;
408  }
409  break;
410  }
411 
412  animationStates.add(animationState);
413  if (addToPendingTickUpdates) {
414  pendingTickUpdates.add(animationState);
415  }
416 
417  return animationState;
418  }
419 
420 }
com.realtime.crossfire.jxclient.map.CfAnimations.itemSet
final ItemSet itemSet
The ItemSet to notify of changes.
Definition: CfAnimations.java:59
com.realtime.crossfire.jxclient
com.realtime.crossfire.jxclient.faces.FacesManager
Maintains a mapping of face numbers to face data.
Definition: FacesManager.java:40
com.realtime.crossfire.jxclient.items.ItemSet.addInventoryListener
void addInventoryListener(final int tag, @NotNull final ItemListener listener)
Adds an ItemListener to be notified about changes.
Definition: ItemSet.java:112
com.realtime.crossfire.jxclient.map.CfAnimations.pendingTickUpdates
final Collection< AnimationState > pendingTickUpdates
The AnimationState instances that have been added but not yet received a "tick" value.
Definition: CfAnimations.java:181
com.realtime.crossfire.jxclient.map.AnimationMap.remove
void remove(@NotNull final Location location)
Clears a Location.
Definition: AnimationMap.java:67
com.realtime.crossfire.jxclient.items.ItemSet
Model class maintaining the CfItems known to the player.
Definition: ItemSet.java:44
com.realtime.crossfire.jxclient.map.CfAnimations.CfAnimations
CfAnimations(@NotNull final ItemSet itemSet, @NotNull final FacesManager facesManager, @NotNull final Animations animations)
Creates a new instance.
Definition: CfAnimations.java:249
com.realtime.crossfire.jxclient.map.CfAnimations.unknownAnimations
final Collection< Integer > unknownAnimations
The animation IDs for which a warning has been printed.
Definition: CfAnimations.java:77
com.realtime.crossfire.jxclient.animations.Animations.get
Animation get(final int animationId)
Returns the animation for an animation id.
Definition: Animations.java:125
com.realtime.crossfire.jxclient.map.CfAnimations.mapListener
CfAnimationsMapListener mapListener
The CfAnimationsMapListener that is notified of changes.
Definition: CfAnimations.java:123
com.realtime.crossfire.jxclient.protocol.Map2.ANIM_RANDOM
int ANIM_RANDOM
Animation type: randomized animation.
Definition: Map2.java:124
com.realtime.crossfire.jxclient.map.CfAnimations.facesManager
final FacesManager facesManager
The FacesManager to track for updated faces.
Definition: CfAnimations.java:65
com.realtime.crossfire.jxclient.map.CfAnimations.tagAnimations
final AnimationSet tagAnimations
The animations in the player's inventory.
Definition: CfAnimations.java:161
com.realtime.crossfire.jxclient.items.ItemListener
Interface for listeners for changes of item locations.
Definition: ItemListener.java:32
com.realtime.crossfire.jxclient.map.CfAnimations.mapRemove
void mapRemove(@NotNull final Location location)
Removes a visible map animation.
Definition: CfAnimations.java:304
com.realtime.crossfire.jxclient.animations.Animations
Manages animations received from the server.
Definition: Animations.java:38
com.realtime.crossfire.jxclient.map.CfAnimations.mapAnimations
final AnimationMap mapAnimations
The animations in the visible map area.
Definition: CfAnimations.java:155
com.realtime.crossfire.jxclient.protocol.Map2.ANIM_SYNC
int ANIM_SYNC
Animation type: synchronized animation.
Definition: Map2.java:130
com.realtime.crossfire.jxclient.animations.Animation
Manages animations received from the server.
Definition: Animation.java:32
com.realtime.crossfire.jxclient.faces
Manages image information ("faces") needed to display the map view, items, and spell icons.
Definition: AbstractFaceQueue.java:23
com.realtime.crossfire.jxclient.map.CfAnimations.mapWidth
int mapWidth
The width of the visible map area.
Definition: CfAnimations.java:144
com.realtime.crossfire.jxclient.map.CfAnimations.mapSetSize
void mapSetSize(final int mapWidth, final int mapHeight)
Updates the map size.
Definition: CfAnimations.java:332
com.realtime.crossfire.jxclient.map.CfAnimationsMapListener.mapEnd
void mapEnd()
Parsing of "map2" has been finished.
com.realtime.crossfire.jxclient.protocol.Map2.ANIM_MASK
int ANIM_MASK
The mask for extracting the animation ID.
Definition: Map2.java:135
com.realtime.crossfire.jxclient.map.CfAnimations.SYNC
static final Object SYNC
Dummy synchronization object if no map listener has been set.
Definition: CfAnimations.java:53
com.realtime.crossfire.jxclient.map.CfAnimations.tags
final Map< Integer, Integer > tags
Maps inventory index to item tag.
Definition: CfAnimations.java:236
com.realtime.crossfire.jxclient.map.CfAnimations.tagAdd
void tagAdd(final int tag, @NotNull final Animation animation, final int type)
Adds a visible animation for an item tag.
Definition: CfAnimations.java:362
com.realtime.crossfire.jxclient.protocol
Definition: MagicMap.java:23
com.realtime.crossfire.jxclient.protocol.Map2.ANIM_NORMAL
int ANIM_NORMAL
Animation type: normal animation.
Definition: Map2.java:119
com.realtime.crossfire.jxclient.map.CfAnimations.setMapListener
void setMapListener(@NotNull final CfAnimationsMapListener mapListener)
Sets the CfAnimationsMapListener to notify of changes.
Definition: CfAnimations.java:261
com.realtime.crossfire.jxclient.map.CfAnimations.mapScroll
void mapScroll(final int dx, final int dy)
Scrolls the map animations.
Definition: CfAnimations.java:323
com.realtime.crossfire.jxclient.map.CfAnimations.animationStates
final Collection< AnimationState > animationStates
All AnimationState instances referenced by mapAnimations or tagAnimations.
Definition: CfAnimations.java:168
com.realtime.crossfire.jxclient.map.CfAnimations.mapUpdateSpeed
void mapUpdateSpeed(@NotNull final Location location, final int speed)
Updates the map animation speed value.
Definition: CfAnimations.java:313
com.realtime.crossfire.jxclient.map.AnimationSet.add
void add(final int tag, @NotNull final AnimationState animationState)
Adds a new AnimationState for an item tag.
Definition: AnimationSet.java:51
com.realtime.crossfire.jxclient.items.CfItem
The representation of a Crossfire Item, client-side.
Definition: CfItem.java:37
com.realtime.crossfire.jxclient.protocol.Map2.ANIM_TYPE_SHIFT
int ANIM_TYPE_SHIFT
The lowest bit of the animation type.
Definition: Map2.java:140
com.realtime.crossfire.jxclient.map.AnimationSet.getAllAnimationStates
Collection< AnimationState > getAllAnimationStates()
Returns all AnimationState instances.
Definition: AnimationSet.java:85
com.realtime.crossfire.jxclient.animations
Definition: Animation.java:23
com.realtime.crossfire.jxclient.map.CfAnimations.tagRemove
void tagRemove(final int tag)
Removes a visible animation for an item tag.
Definition: CfAnimations.java:370
com.realtime.crossfire.jxclient.map.CfAnimations.add
AnimationState add(@NotNull final Animation animation, final int type)
Adds a visible animation.
Definition: CfAnimations.java:381
com.realtime.crossfire.jxclient.map.AnimationMap.clear
void clear()
Forgets all state.
Definition: AnimationMap.java:48
com.realtime.crossfire.jxclient.map.CfAnimations.random
final RandomGenerator random
The random number generator for Map2#ANIM_RANDOM type animations.
Definition: CfAnimations.java:84
com.realtime.crossfire.jxclient.protocol.Map2
Interface defining constants for the "map2" Crossfire protocol message.
Definition: Map2.java:29
com.realtime.crossfire.jxclient.map.AnimationSet.updateSpeed
void updateSpeed(final int tag, final int speed)
Updates the animation speed value of an item tag.
Definition: AnimationSet.java:69
com.realtime.crossfire.jxclient.map.AnimationMap.scroll
void scroll(final int dx, final int dy, final int width, final int height)
Scrolls all locations.
Definition: AnimationMap.java:93
com.realtime.crossfire.jxclient.map.CfAnimations.playerTag
int playerTag
The tag of the player object or.
Definition: CfAnimations.java:241
com.realtime.crossfire.jxclient.map.CfAnimations
Manages a set of animated faces.
Definition: CfAnimations.java:47
com.realtime.crossfire.jxclient.items.ItemSet.addItemSetListener
void addItemSetListener(@NotNull final ItemSetListener listener)
Adds an ItemSetListener to be notified about changes.
Definition: ItemSet.java:95
com.realtime.crossfire.jxclient.map.CfAnimations.tick
void tick(final int tickNo)
Processes a tick command.
Definition: CfAnimations.java:342
com.realtime.crossfire.jxclient.map.AnimationSet.remove
void remove(final int tag)
Clears an item tag.
Definition: AnimationSet.java:60
com.realtime.crossfire.jxclient.map.CfAnimations.mapRemove
void mapRemove(final int x, final int y)
Removes all visible map animations for a tile.
Definition: CfAnimations.java:294
com.realtime.crossfire.jxclient.map.CfAnimations.mapHeight
int mapHeight
The height of the visible map area.
Definition: CfAnimations.java:149
com.realtime.crossfire
com.realtime
com.realtime.crossfire.jxclient.map.CfAnimations.syncAnimationStates
final Map< Integer, AnimationState > syncAnimationStates
All AnimationState for Map2#ANIM_SYNC animations.
Definition: CfAnimations.java:174
com.realtime.crossfire.jxclient.map.AnimationSet
Maintains AnimationState instances for item tag values.
Definition: AnimationSet.java:36
com.realtime.crossfire.jxclient.map.CfAnimationsMapListener.mapBegin
Object mapBegin()
Parsing of a "map2" command has been started.
com
com.realtime.crossfire.jxclient.protocol.Map2.NUM_LAYERS
int NUM_LAYERS
The total number of map layers to display.
Definition: Map2.java:34
com.realtime.crossfire.jxclient.map.CfAnimationsMapListener
Definition: CfAnimationsMapListener.java:5
com.realtime.crossfire.jxclient.items
Definition: AbstractItemView.java:23
com.realtime.crossfire.jxclient.map.CfAnimations.mapAdd
void mapAdd(@NotNull final Location location, @NotNull final Animation animation, final int type)
Adds a visible map animation.
Definition: CfAnimations.java:285
com.realtime.crossfire.jxclient.map.Location
A location on the map.
Definition: Location.java:32
com.realtime.crossfire.jxclient.map.AnimationState
The state of an Animation on a map.
Definition: AnimationState.java:41
com.realtime.crossfire.jxclient.items.ItemSetListener
Interface for listeners in ItemSet related events.
Definition: ItemSetListener.java:32
com.realtime.crossfire.jxclient.map.AnimationMap.add
void add(@NotNull final Location location, @NotNull final AnimationState animationState)
Adds a new AnimationState to a Location.
Definition: AnimationMap.java:58
com.realtime.crossfire.jxclient.protocol.Map2.ANIM_TYPE_MASK
int ANIM_TYPE_MASK
The mask for extracting the animation type.
Definition: Map2.java:146
com.realtime.crossfire.jxclient.map.CfAnimations.mapClear
void mapClear()
Forgets all map animations.
Definition: CfAnimations.java:268
com.realtime.crossfire.jxclient.map.AnimationMap
Maintains AnimationState instances for map locations.
Definition: AnimationMap.java:36
com.realtime.crossfire.jxclient.map.CfAnimations.playerInventoryListener
final ItemListener playerInventoryListener
Listener added to all items in itemSet.
Definition: CfAnimations.java:187
com.realtime.crossfire.jxclient.map.AnimationMap.updateSpeed
void updateSpeed(@NotNull final Location location, final int speed)
Updates the animation speed value of a Location.
Definition: AnimationMap.java:76
com.realtime.crossfire.jxclient.map.CfAnimations.itemSetListener
final ItemSetListener itemSetListener
The listener added to itemSet.
Definition: CfAnimations.java:91
com.realtime.crossfire.jxclient.items.ItemSet.removeInventoryListener
void removeInventoryListener(final int tag, @NotNull final ItemListener listener)
Removes an ItemListener to be notified about changes.
Definition: ItemSet.java:121
com.realtime.crossfire.jxclient.map.CfAnimations.animations
final Animations animations
The global Animations instance.
Definition: CfAnimations.java:71