Crossfire JXClient, Trunk
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-2017,2019-2023 Andreas Kirschbaum
20  * Copyright (C) 2010-2012,2014-2018,2020-2023 Nicolas Weeger
21  */
22 
23 package com.realtime.crossfire.jxclient.items;
24 
29 import java.util.Collection;
30 import java.util.Collections;
31 import java.util.HashMap;
32 import java.util.HashSet;
33 import java.util.List;
34 import java.util.ListIterator;
35 import java.util.Map;
36 import java.util.concurrent.CopyOnWriteArrayList;
37 import org.jetbrains.annotations.NotNull;
38 import org.jetbrains.annotations.Nullable;
39 
44 public class ItemSet {
45 
50  @NotNull
51  private final Map<Integer, CfItem> allItems = new HashMap<>();
52 
56  @NotNull
57  private final Map<Integer, List<CfItem>> items = new HashMap<>();
58 
63  @NotNull
64  private final Object sync = new Object();
65 
69  @Nullable
70  private CfItem player;
71 
75  private int openContainerFloor;
76 
81  @NotNull
83 
88  @NotNull
90 
95  public void addItemSetListener(@NotNull final ItemSetListener listener) {
96  itemSetListeners.add(listener);
97  }
98 
103  public void removeItemSetListener(@NotNull final ItemSetListener listener) {
104  itemSetListeners.remove(listener);
105  }
106 
112  public void addInventoryListener(final int tag, @NotNull final ItemListener listener) {
113  itemListeners.add(tag, listener);
114  }
115 
121  public void removeInventoryListener(final int tag, @NotNull final ItemListener listener) {
122  itemListeners.remove(tag, listener);
123  }
124 
131  @NotNull
132  public List<CfItem> getItemsByLocation(final int location) {
133  synchronized (sync) {
134  final List<CfItem> result = items.get(location);
135  if (result == null) {
136  return Collections.emptyList();
137  }
138  return Collections.unmodifiableList(result);
139  }
140  }
141 
148  public int getNumberOfItemsByLocation(final int location) {
149  synchronized (sync) {
150  final Collection<CfItem> result = items.get(location);
151  return result == null ? 0 : result.size();
152  }
153  }
154 
160  private int removeItemByTag(final int tag) {
161  final int where;
162  final int index;
163  synchronized (sync) {
164  final CfItem item = allItems.remove(tag);
165  if (item == null) {
166  return -1;
167  }
168 
169  where = item.getLocation();
170  final List<CfItem> list = items.get(where);
171  if (list == null) {
172  throw new AssertionError("cannot find item "+item.getTag());
173  }
174 
175  index = list.indexOf(item);
176  if (list.remove(index) == null) {
177  throw new AssertionError("cannot find item "+item.getTag());
178  }
179 
180  if (list.isEmpty() && items.remove(item.getLocation()) != list) {
181  throw new AssertionError();
182  }
183  }
184 
185  for (ItemListener itemListener : itemListeners.getListeners(where)) {
186  itemListener.inventoryRemoved(where, index);
187  }
188 
189  for (ItemListener itemListener : itemListeners.getListeners(tag)) {
190  itemListener.itemRemoved(tag);
191  }
192 
193  return index;
194  }
195 
200  public void removeItems(final int @NotNull [] tags) {
201  for (int tag : tags) {
202  if (removeItemByTag(tag) == -1) {
203  System.err.println("removeItem3: item "+tag+" does not exist");
204  }
205  }
206  }
207 
212  public void addItem(@NotNull final CfItem item) {
213  removeItemByTag(item.getTag());
214  final int index;
215  final int where;
216  synchronized (sync) {
217  if (allItems.put(item.getTag(), item) != null) {
218  throw new AssertionError("duplicate item "+item.getTag());
219  }
220 
221  where = item.getLocation();
222  List<CfItem> list = items.get(where);
223  if (list == null) {
224  list = new CopyOnWriteArrayList<>();
225  if (items.put(where, list) != null) {
226  throw new AssertionError();
227  }
228  }
229 
230  list.add(item);
231  index = list.size()-1;
232  }
233 
234  for (ItemListener itemListener : itemListeners.getListeners(where)) {
235  itemListener.inventoryAdded(where, index, item);
236  }
237  }
238 
244  @NotNull
245  private List<CfItem> getInventoryByTag(final int tag) {
246  synchronized (sync) {
247  final List<CfItem> inventory = items.get(tag);
248  if (inventory == null) {
249  return Collections.emptyList();
250  }
251  return Collections.unmodifiableList(inventory);
252  }
253  }
254 
260  @Nullable
261  public CfItem getItemByTag(final int tag) {
262  synchronized (sync) {
263  return allItems.get(tag);
264  }
265  }
266 
271  @Nullable
272  public CfItem getPlayer() {
273  synchronized (sync) {
274  return player;
275  }
276  }
277 
282  public void setPlayer(@Nullable final CfItem player) {
283  synchronized (sync) {
284  if (this.player == player) {
285  return;
286  }
287 
288  this.player = player;
289  }
290 
291  for (ItemSetListener listener : itemSetListeners) {
292  listener.playerChanged(player);
293  }
294  }
295 
300  @NotNull
301  public Iterable<CfItem> getPlayerInventory() {
302  synchronized (sync) {
303  return player == null ? Collections.emptyList() : getInventoryByTag(player.getTag());
304  }
305  }
306 
312  @Nullable
313  private CfItem getItemOrPlayer(final int tag) {
314  synchronized (sync) {
315  if (player != null && player.getTag() == tag) {
316  return player;
317  }
318 
319  return allItems.get(tag);
320  }
321  }
322 
327  public void cleanInventory(final int tag) {
328  final List<CfItem> inventoryItems = getItemsByLocation(tag);
329  final ListIterator<CfItem> it = inventoryItems.listIterator(inventoryItems.size());
330  while (it.hasPrevious()) {
331  final CfItem item = it.previous();
332  removeItemByTag(item.getTag());
333  }
334  }
335 
350  public void updateItem(final int flags, final int tag, final int valLocation, final int valFlags, final int valWeight, @NotNull final Face valFace, @NotNull final String valName, @NotNull final String valNamePl, final int valAnim, final int valAnimSpeed, final int valNrof) {
351  final CfItem item = getItemOrPlayer(tag);
352  if (item == null) {
353  //System.err.println("updateItem: undefined item "+tag); // XXX: this is a server bug
354  return;
355  }
356 
357  final boolean wasOpen;
358  final boolean clearMarked;
359  synchronized (sync) {
360  wasOpen = (flags&UpdItem.UPD_FLAGS) != 0 && openContainerFloor == item.getTag() && item.isOpen();
361  clearMarked = (flags&UpdItem.UPD_LOCATION) != 0 && (player == null || valLocation != player.getTag());
362  }
363  item.update(flags, valFlags, valWeight, valFace, valName, valNamePl, valAnim, valAnimSpeed, valNrof, clearMarked);
364  if ((flags&UpdItem.UPD_LOCATION) != 0 && item.getLocation() != valLocation) {
365  removeItemByTag(item.getTag());
366  item.setLocation(valLocation);
367  addItem(item);
368  }
369 
370  if ((flags&~UpdItem.UPD_LOCATION) != 0) {
371  for (ItemListener itemListener : itemListeners.getListeners(tag)) {
372  itemListener.itemChanged(tag);
373  }
374  }
375  if ((flags&UpdItem.UPD_FLAGS) != 0) {
376  if (item.isOpen()) {
377  setOpenContainer(item.getTag());
378  } else if (wasOpen) {
379  setOpenContainer(0);
380  }
381  }
382  }
383 
387  public void reset() {
388  final int playerTag;
389  synchronized (sync) {
390  playerTag = player == null ? -1 : player.getTag();
391  }
392  if (playerTag != -1) {
393  cleanInventory(playerTag);
394  }
395  final Iterable<CfItem> tmp;
396  synchronized (sync) {
397  tmp = new HashSet<>(allItems.values());
398  }
399  for (CfItem item : tmp) {
400  removeItemByTag(item.getTag());
401  }
402  setOpenContainer(0);
403  setPlayer(null);
404  }
405 
410  private void setOpenContainer(final int openContainerFloor) {
411  synchronized (sync) {
412  if (this.openContainerFloor == openContainerFloor) {
413  return;
414  }
415 
416  this.openContainerFloor = openContainerFloor;
417  }
418 
419  for (ItemSetListener listener : itemSetListeners) {
420  listener.openContainerChanged(openContainerFloor);
421  }
422  }
423 
428  public int getOpenContainer() {
429  synchronized (sync) {
430  return openContainerFloor;
431  }
432  }
433 
440  @Nullable
441  public CfItem getInventoryItem(final int tag, final int index) {
442  final List<CfItem> inventoryItems = getInventoryByTag(tag);
443  try {
444  return 0 <= index && index < inventoryItems.size() ? inventoryItems.get(index) : null;
445  } catch (final ArrayIndexOutOfBoundsException ignored) {
446  return null;
447  }
448  }
449 
456  public void setMarkedItemTag(final int markedItemTag) {
457  final List<CfItem> inventory;
458  synchronized (sync) {
459  if (player == null) {
460  return;
461  }
462 
463  inventory = items.get(player.getTag());
464  if (inventory == null) {
465  return;
466  }
467  }
468 
469  for (final CfItem item : inventory) {
470  item.setMarked(item.getTag() == markedItemTag);
471  }
472  }
473 
474 }
com.realtime.crossfire.jxclient
com.realtime.crossfire.jxclient.items.ItemSet.allItems
final Map< Integer, CfItem > allItems
Definition: ItemSet.java:51
com.realtime.crossfire.jxclient.items.ItemSet.removeInventoryListener
void removeInventoryListener(final int tag, @NotNull final ItemListener listener)
Definition: ItemSet.java:121
com.realtime.crossfire.jxclient.items.ItemSet.setMarkedItemTag
void setMarkedItemTag(final int markedItemTag)
Definition: ItemSet.java:456
com.realtime.crossfire.jxclient.items.ItemListener
Definition: ItemListener.java:32
com.realtime.crossfire.jxclient.items.ItemSet.setPlayer
void setPlayer(@Nullable final CfItem player)
Definition: ItemSet.java:282
com.realtime.crossfire.jxclient.items.ItemSet.getItemsByLocation
List< CfItem > getItemsByLocation(final int location)
Definition: ItemSet.java:132
com.realtime.crossfire.jxclient.items.ItemSet.getItemByTag
CfItem getItemByTag(final int tag)
Definition: ItemSet.java:261
com.realtime.crossfire.jxclient.items.ItemSet
Definition: ItemSet.java:44
com.realtime.crossfire.jxclient.util.EventListenerList2
Definition: EventListenerList2.java:37
com.realtime.crossfire.jxclient.items.ItemSet.items
final Map< Integer, List< CfItem > > items
Definition: ItemSet.java:57
com.realtime.crossfire.jxclient.items.ItemSet.reset
void reset()
Definition: ItemSet.java:387
com.realtime.crossfire.jxclient.items.ItemSet.cleanInventory
void cleanInventory(final int tag)
Definition: ItemSet.java:327
com.realtime.crossfire.jxclient.faces
Definition: AbstractFaceQueue.java:23
com.realtime.crossfire.jxclient.items.ItemSet.removeItems
void removeItems(final int @NotNull[] tags)
Definition: ItemSet.java:200
com.realtime.crossfire.jxclient.items.ItemSet.getPlayer
CfItem getPlayer()
Definition: ItemSet.java:272
com.realtime.crossfire.jxclient.protocol
Definition: MagicMap.java:23
com.realtime.crossfire.jxclient.items.ItemSet.getOpenContainer
int getOpenContainer()
Definition: ItemSet.java:428
com.realtime.crossfire.jxclient.items.CfItem.isOpen
boolean isOpen()
Definition: CfItem.java:401
com.realtime.crossfire.jxclient.items.ItemSet.getInventoryItem
CfItem getInventoryItem(final int tag, final int index)
Definition: ItemSet.java:441
com.realtime.crossfire.jxclient.items.ItemSet.removeItemByTag
int removeItemByTag(final int tag)
Definition: ItemSet.java:160
com.realtime.crossfire.jxclient.items.ItemSet.itemSetListeners
final EventListenerList2< ItemSetListener > itemSetListeners
Definition: ItemSet.java:82
com.realtime.crossfire.jxclient.items.ItemSet.getNumberOfItemsByLocation
int getNumberOfItemsByLocation(final int location)
Definition: ItemSet.java:148
com.realtime.crossfire.jxclient.items.CfItem.getLocation
int getLocation()
Definition: CfItem.java:445
com.realtime.crossfire.jxclient.items.CfItem
Definition: CfItem.java:37
com.realtime.crossfire.jxclient.items.CfItem.setLocation
void setLocation(final int location)
Definition: CfItem.java:279
com.realtime.crossfire.jxclient.items.ItemSet.getItemOrPlayer
CfItem getItemOrPlayer(final int tag)
Definition: ItemSet.java:313
com.realtime.crossfire.jxclient.items.ItemSet.sync
final Object sync
Definition: ItemSet.java:64
com.realtime.crossfire.jxclient.items.ItemSet.getInventoryByTag
List< CfItem > getInventoryByTag(final int tag)
Definition: ItemSet.java:245
com.realtime.crossfire.jxclient.util
Definition: Codec.java:23
com.realtime.crossfire.jxclient.protocol.UpdItem.UPD_FLAGS
int UPD_FLAGS
Definition: UpdItem.java:39
com.realtime.crossfire.jxclient.protocol.UpdItem.UPD_LOCATION
int UPD_LOCATION
Definition: UpdItem.java:34
com.realtime.crossfire.jxclient.items.ItemSet.setOpenContainer
void setOpenContainer(final int openContainerFloor)
Definition: ItemSet.java:410
com.realtime.crossfire.jxclient.items.ItemSet.removeItemSetListener
void removeItemSetListener(@NotNull final ItemSetListener listener)
Definition: ItemSet.java:103
com.realtime.crossfire.jxclient.util.HashedEventListenerList
Definition: HashedEventListenerList.java:30
com.realtime.crossfire
com.realtime.crossfire.jxclient.items.ItemSet.addItem
void addItem(@NotNull final CfItem item)
Definition: ItemSet.java:212
com.realtime.crossfire.jxclient.items.CfItem.getTag
int getTag()
Definition: CfItem.java:287
com.realtime
com.realtime.crossfire.jxclient.items.ItemSet.updateItem
void updateItem(final int flags, final int tag, final int valLocation, final int valFlags, final int valWeight, @NotNull final Face valFace, @NotNull final String valName, @NotNull final String valNamePl, final int valAnim, final int valAnimSpeed, final int valNrof)
Definition: ItemSet.java:350
com.realtime.crossfire.jxclient.items.ItemSet.addInventoryListener
void addInventoryListener(final int tag, @NotNull final ItemListener listener)
Definition: ItemSet.java:112
com
com.realtime.crossfire.jxclient.items.ItemSet.addItemSetListener
void addItemSetListener(@NotNull final ItemSetListener listener)
Definition: ItemSet.java:95
com.realtime.crossfire.jxclient.items.ItemSet.openContainerFloor
int openContainerFloor
Definition: ItemSet.java:75
com.realtime.crossfire.jxclient.items.ItemSet.itemListeners
final HashedEventListenerList< ItemListener > itemListeners
Definition: ItemSet.java:89
com.realtime.crossfire.jxclient.protocol.UpdItem
Definition: UpdItem.java:29
com.realtime.crossfire.jxclient.items.CfItem.update
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, final boolean clearMarked)
Definition: CfItem.java:470
com.realtime.crossfire.jxclient.items.ItemSet.getPlayerInventory
Iterable< CfItem > getPlayerInventory()
Definition: ItemSet.java:301
com.realtime.crossfire.jxclient.items.ItemSetListener
Definition: ItemSetListener.java:32
com.realtime.crossfire.jxclient.items.ItemSet.player
CfItem player
Definition: ItemSet.java:70
com.realtime.crossfire.jxclient.faces.Face
Definition: Face.java:37