Crossfire JXClient, Trunk  R20561
ItemSet.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.items;
23 
28 import java.util.Collection;
29 import java.util.Collections;
30 import java.util.HashMap;
31 import java.util.HashSet;
32 import java.util.List;
33 import java.util.ListIterator;
34 import java.util.Map;
35 import java.util.concurrent.CopyOnWriteArrayList;
36 import org.jetbrains.annotations.NotNull;
37 import org.jetbrains.annotations.Nullable;
38 
43 public class ItemSet {
44 
49  @NotNull
50  private final Map<Integer, CfItem> allItems = new HashMap<>();
51 
55  @NotNull
56  private final Map<Integer, List<CfItem>> items = new HashMap<>();
57 
61  @NotNull
62  private final Object sync = new Object();
63 
67  @Nullable
68  private CfItem player;
69 
73  private int openContainerFloor;
74 
79  @NotNull
81 
86  @NotNull
88 
93  public void addItemSetListener(@NotNull final ItemSetListener listener) {
94  itemSetListeners.add(listener);
95  }
96 
101  public void removeItemSetListener(@NotNull final ItemSetListener listener) {
102  itemSetListeners.remove(listener);
103  }
104 
110  public void addInventoryListener(final int tag, @NotNull final ItemListener listener) {
111  itemListeners.add(tag, listener);
112  }
113 
119  public void removeInventoryListener(final int tag, @NotNull final ItemListener listener) {
120  itemListeners.remove(tag, listener);
121  }
122 
129  @NotNull
130  public List<CfItem> getItemsByLocation(final int location) {
131  final List<CfItem> result = items.get(location);
132  if (result == null) {
133  return Collections.emptyList();
134  }
135  return Collections.unmodifiableList(result);
136  }
137 
144  public int getNumberOfItemsByLocation(final int location) {
145  final Collection<CfItem> result = items.get(location);
146  return result == null ? 0 : result.size();
147  }
148 
156  private int removeItemByTag(final int tag, final boolean notifyListeners) {
157  synchronized (sync) {
158  final CfItem item = allItems.remove(tag);
159  if (item == null) {
160  return -1;
161  }
162 
163  for (final ItemSetListener listener : itemSetListeners) {
164  listener.itemRemoved(item);
165  }
166 
167  final int where = item.getLocation();
168  final List<CfItem> list = items.get(where);
169  if (list == null) {
170  throw new AssertionError("cannot find item "+item.getTag());
171  }
172 
173  final int index = list.indexOf(item);
174  if (list.remove(index) == null) {
175  throw new AssertionError("cannot find item "+item.getTag());
176  }
177 
178  if (list.isEmpty() && items.remove(item.getLocation()) != list) {
179  throw new AssertionError();
180  }
181 
182  for (final ItemListener itemListener : itemListeners.getListeners(where)) {
183  itemListener.inventoryRemoved(where, index);
184  }
185 
186  if (notifyListeners) {
187  for (final ItemSetListener listener : itemSetListeners) {
188  listener.itemRemoved(item);
189  }
190  }
191 
192  for (final ItemListener itemListener : itemListeners.getListeners(tag)) {
193  itemListener.itemRemoved(tag);
194  }
195 
196  return index;
197  }
198  }
199 
204  public void removeItems(@NotNull final int[] tags) {
205  for (final int tag : tags) {
206  if (removeItemByTag(tag, true) == -1) {
207  System.err.println("removeItem3: item "+tag+" does not exist");
208  }
209  }
210  }
211 
216  public void addItem(@NotNull final CfItem item) {
217  addItem(item, true);
218  }
219 
226  private void addItem(@NotNull final CfItem item, final boolean notifyListeners) {
227  removeItemByTag(item.getTag(), true);
228 
229  if (allItems.put(item.getTag(), item) != null) {
230  throw new AssertionError("duplicate item "+item.getTag());
231  }
232 
233  final int where = item.getLocation();
234  List<CfItem> list = items.get(where);
235  if (list == null) {
236  list = new CopyOnWriteArrayList<>();
237  if (items.put(where, list) != null) {
238  throw new AssertionError();
239  }
240  }
241 
242  list.add(item);
243 
244  if (notifyListeners) {
245  for (final ItemSetListener listener : itemSetListeners) {
246  listener.itemAdded(item);
247  }
248  }
249 
250  for (final ItemListener itemListener : itemListeners.getListeners(where)) {
251  itemListener.inventoryAdded(where, list.size()-1, item);
252  }
253  }
254 
260  @NotNull
261  private List<CfItem> getInventoryByTag(final int tag) {
262  final List<CfItem> inventory = items.get(tag);
263  if (inventory == null) {
264  return Collections.emptyList();
265  }
266  return Collections.unmodifiableList(inventory);
267  }
268 
274  @Nullable
275  public CfItem getItemByTag(final int tag) {
276  return allItems.get(tag);
277  }
278 
283  @Nullable
284  public CfItem getPlayer() {
285  synchronized (sync) {
286  return player;
287  }
288  }
289 
294  public void setPlayer(@Nullable final CfItem player) {
295  synchronized (sync) {
296  if (this.player == player) {
297  return;
298  }
299 
300  this.player = player;
301  for (final ItemSetListener listener : itemSetListeners) {
302  listener.playerChanged(player);
303  }
304  }
305  }
306 
311  @NotNull
312  public Iterable<CfItem> getPlayerInventory() {
313  synchronized (sync) {
314  return player == null ? Collections.<CfItem>emptyList() : getInventoryByTag(player.getTag());
315  }
316  }
317 
323  @Nullable
324  private CfItem getItemOrPlayer(final int tag) {
325  synchronized (sync) {
326  if (player != null && player.getTag() == tag) {
327  return player;
328  }
329 
330  return allItems.get(tag);
331  }
332  }
333 
338  public void cleanInventory(final int tag) {
339  final List<CfItem> inventoryItems = getItemsByLocation(tag);
340  final ListIterator<CfItem> it = inventoryItems.listIterator(inventoryItems.size());
341  while (it.hasPrevious()) {
342  final CfItem item = it.previous();
343  removeItemByTag(item.getTag(), true);
344  }
345  }
346 
361  public void updateItem(final int flags, final int tag, final int valLocation, final int valFlags, final int valWeight, final Face valFace, @NotNull final String valName, @NotNull final String valNamePl, final int valAnim, final int valAnimSpeed, final int valNrof) {
362  synchronized (sync) {
363  final CfItem item = getItemOrPlayer(tag);
364  if (item == null) {
365  if (flags != UpdItem.UPD_FACE) { // XXX: suppress frequent error message due to server bug
366  System.err.println("updateItem: undefined item "+tag);
367  }
368  return;
369  }
370 
371  final boolean wasOpen = (flags&UpdItem.UPD_FLAGS) != 0 && openContainerFloor == item.getTag() && item.isOpen();
372  item.update(flags, valFlags, valWeight, valFace, valName, valNamePl, valAnim, valAnimSpeed, valNrof);
373  if ((flags&UpdItem.UPD_LOCATION) != 0 && item.getLocation() != valLocation) {
374  removeItemByTag(item.getTag(), false);
375  item.setLocation(valLocation);
376  addItem(item, false);
377 
378  for (final ItemSetListener listener : itemSetListeners) {
379  listener.itemMoved(item);
380  }
381  }
382  if ((flags&~UpdItem.UPD_LOCATION) != 0) {
383  for (final ItemSetListener listener : itemSetListeners) {
384  listener.itemChanged(item);
385  }
386  for (final ItemListener itemListener : itemListeners.getListeners(tag)) {
387  itemListener.itemChanged(tag);
388  }
389  }
390  if ((flags&UpdItem.UPD_FLAGS) != 0) {
391  if (item.isOpen()) {
392  setOpenContainer(item.getTag());
393  } else if (wasOpen) {
394  setOpenContainer(0);
395  }
396  }
397  }
398  }
399 
403  public void reset() {
404  synchronized (sync) {
405  if (player != null) {
406  cleanInventory(player.getTag());
407  }
408  final Iterable<CfItem> tmp = new HashSet<>(allItems.values());
409  for (final CfItem item : tmp) {
410  removeItemByTag(item.getTag(), true);
411  }
412  setOpenContainer(0);
413  setPlayer(null);
414  }
415  }
416 
421  private void setOpenContainer(final int openContainerFloor) {
422  if (this.openContainerFloor == openContainerFloor) {
423  return;
424  }
425 
426  this.openContainerFloor = openContainerFloor;
427  for (final ItemSetListener listener : itemSetListeners) {
428  listener.openContainerChanged(openContainerFloor);
429  }
430  }
431 
436  public int getOpenContainer() {
437  return openContainerFloor;
438  }
439 
446  @Nullable
447  public CfItem getInventoryItem(final int tag, final int index) {
448  final List<CfItem> inventoryItems = getInventoryByTag(tag);
449  try {
450  return 0 <= index && index < inventoryItems.size() ? inventoryItems.get(index) : null;
451  } catch (final ArrayIndexOutOfBoundsException ignored) {
452  return null;
453  }
454  }
455 
456 }
final EventListenerList2< ItemSetListener > itemSetListeners
The list of ItemSetListeners to be notified about changes.
Definition: ItemSet.java:80
void setPlayer(@Nullable final CfItem player)
Sets the player object this client controls.
Definition: ItemSet.java:294
void removeItems(@NotNull final int[] tags)
Deletes items by tag.
Definition: ItemSet.java:204
CfItem getInventoryItem(final int tag, final int index)
Returns a CfItem from the inventory of an item.
Definition: ItemSet.java:447
void updateItem(final int flags, final int tag, final int valLocation, final int valFlags, final int valWeight, final Face valFace, @NotNull final String valName, @NotNull final String valNamePl, final int valAnim, final int valAnimSpeed, final int valNrof)
Processes an "upditem" command.
Definition: ItemSet.java:361
List< CfItem > getItemsByLocation(final int location)
Returns a list of items in a given location.
Definition: ItemSet.java:130
Iterable< CfItem > getPlayerInventory()
Returns the player&#39;s inventory.
Definition: ItemSet.java:312
int UPD_FACE
The update flags value for face updates.
Definition: UpdItem.java:48
void setOpenContainer(final int openContainerFloor)
Sets the currently opened container.
Definition: ItemSet.java:421
int getNumberOfItemsByLocation(final int location)
Returns the number of items in a given location.
Definition: ItemSet.java:144
void addItemSetListener(@NotNull final ItemSetListener listener)
Adds an ItemSetListener to be notified about changes.
Definition: ItemSet.java:93
void remove(final int index, @NotNull final T listener)
Removes a listener.
final Map< Integer, List< CfItem > > items
Maps location (=tag) to list of items in that location.
Definition: ItemSet.java:56
int UPD_FLAGS
The update flags value for flags updates.
Definition: UpdItem.java:38
Interface for listeners for changes of item locations.
Manages image information ("faces") needed to display the map view, items, and spell icons...
CfItem getItemOrPlayer(final int tag)
Returns an item by tag.
Definition: ItemSet.java:324
CfItem getItemByTag(final int tag)
Returns an item by tag.
Definition: ItemSet.java:275
int getLocation()
Returns the location.
Definition: CfItem.java:398
void removeInventoryListener(final int tag, @NotNull final ItemListener listener)
Removes an ItemListener to be notified about changes.
Definition: ItemSet.java:119
int getOpenContainer()
Returns the currently opened container.
Definition: ItemSet.java:436
void removeItemSetListener(@NotNull final ItemSetListener listener)
Removes an ItemSetListener to be notified about changes.
Definition: ItemSet.java:101
Interface for listeners in ItemSet related events.
void addInventoryListener(final int tag, @NotNull final ItemListener listener)
Adds an ItemListener to be notified about changes.
Definition: ItemSet.java:110
void reset()
Resets the manager&#39;s state.
Definition: ItemSet.java:403
void update(final int updateFlags, final int flags, final int weight, @NotNull final Face face, @NotNull final String name, @NotNull final String namePl, final int anim, final int animSpeed, final int nrof)
Processes an "upditem" command.
Definition: CfItem.java:422
int UPD_LOCATION
The update flags value for location updates.
Definition: UpdItem.java:33
void add(@NotNull final T listener)
Adds a listener.
void addItem(@NotNull final CfItem item)
Adds an item.
Definition: ItemSet.java:216
CfItem getPlayer()
Returns the player object this client controls.
Definition: ItemSet.java:284
void addItem(@NotNull final CfItem item, final boolean notifyListeners)
Adds a CfItem.
Definition: ItemSet.java:226
CfItem player
The current player object this client controls.
Definition: ItemSet.java:68
List< CfItem > getInventoryByTag(final int tag)
Returns the inventory of an item.
Definition: ItemSet.java:261
void cleanInventory(final int tag)
Clears the inventory of an item.
Definition: ItemSet.java:338
final Map< Integer, CfItem > allItems
Maps item tags to items.
Definition: ItemSet.java:50
void setLocation(final int location)
Updates the location.
Definition: CfItem.java:268
Interface defining constants for the "upditem" Crossfire protocol message.
Definition: UpdItem.java:28
Model class maintaining the CfItems known to the player.
Definition: ItemSet.java:43
int removeItemByTag(final int tag, final boolean notifyListeners)
Removes a CfItem.
Definition: ItemSet.java:156
final HashedEventListenerList< ItemListener > itemListeners
The registered ItemListeners to be notified about changes.
Definition: ItemSet.java:87
Iterable< T > getListeners(final int index)
Returns an array of all the listeners.
The representation of a Crossfire Item, client-side.
Definition: CfItem.java:36
void remove(@NotNull final T listener)
Removes a listener.
final Object sync
The synchronization object for player.
Definition: ItemSet.java:62
void add(final int index, @NotNull final T listener)
Adds a listener.
int openContainerFloor
The currently opened container or.
Definition: ItemSet.java:73
boolean isOpen()
Returns whether this item is an opened container.
Definition: CfItem.java:374