00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 package com.realtime.crossfire.jxclient.items;
00023
00024 import com.realtime.crossfire.jxclient.faces.Face;
00025 import com.realtime.crossfire.jxclient.server.crossfire.messages.UpdItem;
00026 import com.realtime.crossfire.jxclient.util.EventListenerList2;
00027 import com.realtime.crossfire.jxclient.util.HashedEventListenerList;
00028 import java.util.Collection;
00029 import java.util.Collections;
00030 import java.util.HashMap;
00031 import java.util.HashSet;
00032 import java.util.List;
00033 import java.util.ListIterator;
00034 import java.util.Map;
00035 import java.util.concurrent.CopyOnWriteArrayList;
00036 import org.jetbrains.annotations.NotNull;
00037 import org.jetbrains.annotations.Nullable;
00038
00043 public class ItemSet {
00044
00049 @NotNull
00050 private final Map<Integer, CfItem> allItems = new HashMap<Integer, CfItem>();
00051
00055 @NotNull
00056 private final Map<Integer, List<CfItem>> items = new HashMap<Integer, List<CfItem>>();
00057
00061 @NotNull
00062 private final Object sync = new Object();
00063
00067 @Nullable
00068 private CfItem player = null;
00069
00073 private int openContainerFloor = 0;
00074
00079 @NotNull
00080 private final EventListenerList2<ItemSetListener> itemSetListeners = new EventListenerList2<ItemSetListener>(ItemSetListener.class);
00081
00086 @NotNull
00087 private final HashedEventListenerList<ItemListener> itemListeners = new HashedEventListenerList<ItemListener>(ItemListener.class);
00088
00093 public void addItemSetListener(@NotNull final ItemSetListener listener) {
00094 itemSetListeners.add(listener);
00095 }
00096
00101 public void removeItemSetListener(@NotNull final ItemSetListener listener) {
00102 itemSetListeners.remove(listener);
00103 }
00104
00110 public void addInventoryListener(final int tag, @NotNull final ItemListener listener) {
00111 itemListeners.add(tag, listener);
00112 }
00113
00119 public void removeInventoryListener(final int tag, @NotNull final ItemListener listener) {
00120 itemListeners.remove(tag, listener);
00121 }
00122
00129 @NotNull
00130 public List<CfItem> getItemsByLocation(final int location) {
00131 final List<CfItem> result = items.get(location);
00132 if (result == null) {
00133 return Collections.emptyList();
00134 }
00135 return Collections.unmodifiableList(result);
00136 }
00137
00144 public int getNumberOfItemsByLocation(final int location) {
00145 final Collection<CfItem> result = items.get(location);
00146 return result == null ? 0 : result.size();
00147 }
00148
00157 private int removeItemByTag(final int tag, final boolean notifyListeners) {
00158 synchronized (sync) {
00159 final CfItem item = allItems.remove(tag);
00160 if (item == null) {
00161 return -1;
00162 }
00163
00164 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00165 listener.itemRemoved(item);
00166 }
00167
00168 final int where = item.getLocation();
00169 final List<CfItem> list = items.get(where);
00170 if (list == null) {
00171 throw new AssertionError("cannot find item "+item.getTag());
00172 }
00173
00174 final int index = list.indexOf(item);
00175 if (list.remove(index) == null) {
00176 throw new AssertionError("cannot find item "+item.getTag());
00177 }
00178
00179 if (list.isEmpty() && items.remove(item.getLocation()) != list) {
00180 throw new AssertionError();
00181 }
00182
00183 for (final ItemListener itemListener : itemListeners.getListeners(where)) {
00184 itemListener.inventoryRemoved(where, index);
00185 }
00186
00187 if (notifyListeners) {
00188 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00189 listener.itemRemoved(item);
00190 }
00191 }
00192
00193 for (final ItemListener itemListener : itemListeners.getListeners(tag)) {
00194 itemListener.itemRemoved(tag);
00195 }
00196
00197 return index;
00198 }
00199 }
00200
00205 public void removeItems(@NotNull final int[] tags) {
00206 for (final int tag : tags) {
00207 if (removeItemByTag(tag, true) == -1) {
00208 System.err.println("removeItem3: item "+tag+" does not exist");
00209 }
00210 }
00211 }
00212
00217 public void addItem(@NotNull final CfItem item) {
00218 addItem(item, true);
00219 }
00220
00227 private void addItem(@NotNull final CfItem item, final boolean notifyListeners) {
00228 removeItemByTag(item.getTag(), true);
00229
00230 if (allItems.put(item.getTag(), item) != null) {
00231 throw new AssertionError("duplicate item "+item.getTag());
00232 }
00233
00234 final int where = item.getLocation();
00235 List<CfItem> list = items.get(where);
00236 if (list == null) {
00237 list = new CopyOnWriteArrayList<CfItem>();
00238 if (items.put(where, list) != null) {
00239 throw new AssertionError();
00240 }
00241 }
00242
00243 list.add(item);
00244
00245 if (notifyListeners) {
00246 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00247 listener.itemAdded(item);
00248 }
00249 }
00250
00251 for (final ItemListener itemListener : itemListeners.getListeners(where)) {
00252 itemListener.inventoryAdded(where, list.size()-1, item);
00253 }
00254 }
00255
00261 @NotNull
00262 private List<CfItem> getInventoryByTag(final int tag) {
00263 final List<CfItem> inventory = items.get(tag);
00264 if (inventory == null) {
00265 return Collections.emptyList();
00266 }
00267 return Collections.unmodifiableList(inventory);
00268 }
00269
00275 @Nullable
00276 public CfItem getItemByTag(final int tag) {
00277 return allItems.get(tag);
00278 }
00279
00284 @Nullable
00285 public CfItem getPlayer() {
00286 synchronized (sync) {
00287 return player;
00288 }
00289 }
00290
00295 public void setPlayer(@Nullable final CfItem player) {
00296 synchronized (sync) {
00297 if (this.player == player) {
00298 return;
00299 }
00300
00301 this.player = player;
00302 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00303 listener.playerChanged(player);
00304 }
00305 }
00306 }
00307
00312 @NotNull
00313 public Iterable<CfItem> getPlayerInventory() {
00314 synchronized (sync) {
00315 return player == null ? Collections.<CfItem>emptyList() : getInventoryByTag(player.getTag());
00316 }
00317 }
00318
00324 @Nullable
00325 private CfItem getItemOrPlayer(final int tag) {
00326 synchronized (sync) {
00327 if (player != null && player.getTag() == tag) {
00328 return player;
00329 }
00330
00331 return allItems.get(tag);
00332 }
00333 }
00334
00339 public void cleanInventory(final int tag) {
00340 final List<CfItem> inventoryItems = getItemsByLocation(tag);
00341 final ListIterator<CfItem> it = inventoryItems.listIterator(inventoryItems.size());
00342 while (it.hasPrevious()) {
00343 final CfItem item = it.previous();
00344 removeItemByTag(item.getTag(), true);
00345 }
00346 }
00347
00362 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) {
00363 synchronized (sync) {
00364 final CfItem item = getItemOrPlayer(tag);
00365 if (item == null) {
00366 if (flags != UpdItem.UPD_FACE) {
00367 System.err.println("updateItem: undefined item "+tag);
00368 }
00369 return;
00370 }
00371
00372 final boolean wasOpen = (flags&UpdItem.UPD_FLAGS) != 0 && openContainerFloor == item.getTag() && item.isOpen();
00373 item.update(flags, valFlags, valWeight, valFace, valName, valNamePl, valAnim, valAnimSpeed, valNrof);
00374 if ((flags&UpdItem.UPD_LOCATION) != 0 && item.getLocation() != valLocation) {
00375 removeItemByTag(item.getTag(), false);
00376 item.setLocation(valLocation);
00377 addItem(item, false);
00378
00379 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00380 listener.itemMoved(item);
00381 }
00382 }
00383 if ((flags&~UpdItem.UPD_LOCATION) != 0) {
00384 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00385 listener.itemChanged(item);
00386 }
00387 for (final ItemListener itemListener : itemListeners.getListeners(tag)) {
00388 itemListener.itemChanged(tag);
00389 }
00390 }
00391 if ((flags&UpdItem.UPD_FLAGS) != 0) {
00392 if (item.isOpen()) {
00393 setOpenContainer(item.getTag());
00394 } else if (wasOpen) {
00395 setOpenContainer(0);
00396 }
00397 }
00398 }
00399 }
00400
00404 public void reset() {
00405 synchronized (sync) {
00406 if (player != null) {
00407 cleanInventory(player.getTag());
00408 }
00409 final Iterable<CfItem> tmp = new HashSet<CfItem>(allItems.values());
00410 for (final CfItem item : tmp) {
00411 removeItemByTag(item.getTag(), true);
00412 }
00413 setOpenContainer(0);
00414 setPlayer(null);
00415 }
00416 }
00417
00422 private void setOpenContainer(final int openContainerFloor) {
00423 if (this.openContainerFloor == openContainerFloor) {
00424 return;
00425 }
00426
00427 this.openContainerFloor = openContainerFloor;
00428 for (final ItemSetListener listener : itemSetListeners.getListeners()) {
00429 listener.openContainerChanged(openContainerFloor);
00430 }
00431 }
00432
00437 public int getOpenContainer() {
00438 return openContainerFloor;
00439 }
00440
00448 @Nullable
00449 public CfItem getInventoryItem(final int tag, final int index) {
00450 final List<CfItem> inventoryItems = getInventoryByTag(tag);
00451 try {
00452 return 0 <= index && index < inventoryItems.size() ? inventoryItems.get(index) : null;
00453 } catch (final ArrayIndexOutOfBoundsException ignored) {
00454 return null;
00455 }
00456 }
00457
00458 }