Crossfire JXClient, Trunk
InventoryView.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 
25 import java.util.ArrayList;
26 import java.util.Comparator;
27 import java.util.List;
28 import javax.swing.SwingUtilities;
29 import org.jetbrains.annotations.NotNull;
30 import org.jetbrains.annotations.Nullable;
31 
38 public class InventoryView extends AbstractItemView {
39 
43  @NotNull
44  private final ItemSet itemSet;
45 
49  @NotNull
50  private final Comparator<CfItem> comparator;
51 
55  @NotNull
56  private final Object sync = new Object();
57 
61  private long changeTimestamp = System.currentTimeMillis();
62 
66  @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
67  private int currentPlayerTag;
68 
73  @NotNull
74  private final List<CfItem> items = new ArrayList<>();
75 
80  @NotNull
81  @SuppressWarnings("FieldCanBeLocal")
83 
84  @Override
85  public void playerChanged(@Nullable final CfItem player) {
86  setCurrentPlayerTag(player == null ? -1 : player.getTag());
87  }
88 
89  @Override
90  public void openContainerChanged(final int tag) {
91  // ignore
92  }
93 
94  };
95 
99  @NotNull
101 
102  @Override
103  public void itemChanged(final int tag) {
104  if (tag != currentPlayerTag) {
105  throw new IllegalArgumentException("tag="+tag+" but expecting currentPlayerTag="+currentPlayerTag);
106  }
108  }
109 
110  @Override
111  public void itemRemoved(final int tag) {
112  // ignore; will be detected by itemSetListener
113  }
114 
115  @Override
116  public void inventoryAdded(final int tag, final int index, @NotNull final CfItem item) {
117  if (tag != currentPlayerTag) {
118  throw new IllegalArgumentException("tag="+tag+" but expecting currentPlayerTag="+currentPlayerTag);
119  }
121  }
122 
123  @Override
124  public void inventoryRemoved(final int tag, final int index) {
125  if (tag != currentPlayerTag) {
126  throw new IllegalArgumentException("tag="+tag+" but expecting currentPlayerTag="+currentPlayerTag);
127  }
129  }
130 
131  };
132 
136  @NotNull
138 
142  @NotNull
143  @SuppressWarnings("FieldAccessedSynchronizedAndUnsynchronized")
145 
151  public InventoryView(@NotNull final ItemSet itemSet, @NotNull final Comparator<CfItem> comparator) {
152  this.itemSet = itemSet;
153  this.comparator = comparator;
154  final Thread thread = new Thread(this::run, "inventory view refresh");
155  thread.setDaemon(true);
156  //noinspection CallToThreadStartDuringObjectConstruction
157  thread.start();
159  final CfItem player = itemSet.getPlayer();
160  currentPlayerTag = player == null ? -1 : player.getTag();
161  }
162 
167  private void setCurrentPlayerTag(final int currentPlayerTag) {
168  if (this.currentPlayerTag != currentPlayerTag) {
169  if (this.currentPlayerTag != -1) {
171  }
172  this.currentPlayerTag = currentPlayerTag;
173  if (this.currentPlayerTag != -1) {
174  itemSet.addInventoryListener(this.currentPlayerTag, playerInventoryListener);
175  }
176  }
177 
178  synchronized (sync) {
179  changeTimestamp = System.currentTimeMillis();
180  sync.notifyAll();
181  }
182  }
183 
187  private void run() {
188  try {
189  while (!Thread.currentThread().isInterrupted()) {
190  final long milliseconds;
191  synchronized (sync) {
192  if (changeTimestamp == 0) {
193  //noinspection WaitOrAwaitWithoutTimeout
194  sync.wait();
195  continue;
196  }
197 
198  milliseconds = changeTimestamp+50-System.currentTimeMillis();
199  if (milliseconds <= 0) {
200  changeTimestamp = 0;
201  }
202  }
203 
204  if (milliseconds > 0) {
205  //noinspection BusyWait
206  Thread.sleep(milliseconds);
207  continue;
208  }
209 
210  SwingUtilities.invokeLater(this::doRebuildInventory);
211  }
212  } catch (final InterruptedException ignored) {
213  Thread.currentThread().interrupt();
214  }
215  }
216 
220  private void doRebuildInventory() {
221  final int oldSize;
222  final int newSize;
223  synchronized (items) {
224  oldSize = items.size();
225  for (final CfItem item : items) {
226  item.removeCfItemModifiedListener(itemModifiedListener);
227  }
228  items.clear();
229  if (currentPlayerTag != -1) {
230  for (final CfItem item : itemSet.getPlayerInventory()) {
231  final int index = findInsertionIndex(item);
232  if (index != -1) {
233  items.add(index, item);
234  item.addCfItemModifiedListener(itemModifiedListener);
235  }
236  }
237  }
238  newSize = items.size();
239  }
240  addModifiedRange(0, Math.max(oldSize, newSize)-1);
241  }
242 
243  @Override
244  public int getSize() {
245  synchronized (items) {
246  return items.size();
247  }
248  }
249 
250  @Nullable
251  @Override
252  public CfItem getItem(final int index) {
253  try {
254  synchronized (items) {
255  return items.get(index);
256  }
257  } catch (final IndexOutOfBoundsException ignored) {
258  return null;
259  }
260  }
261 
267  private int findInsertionIndex(@NotNull final CfItem item) {
268  if (!filter.matches(item)) {
269  return -1;
270  }
271 
272  int i;
273  synchronized (items) {
274  for (i = 0; i < items.size(); i++) {
275  if (comparator.compare(items.get(i), item) >= 0) {
276  break;
277  }
278  }
279  }
280  return i;
281  }
282 
287  public void setFilter(@NotNull final InventoryFilter filter) {
288  if (this.filter == filter) {
289  return;
290  }
291 
292  this.filter = filter;
294  }
295 
296 }
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.InventoryView.itemSet
final ItemSet itemSet
Definition: InventoryView.java:44
com.realtime.crossfire.jxclient.items.AbstractItemView
Definition: AbstractItemView.java:35
com.realtime.crossfire.jxclient.items.ItemListener
Definition: ItemListener.java:32
com.realtime.crossfire.jxclient.items.InventoryView.setCurrentPlayerTag
void setCurrentPlayerTag(final int currentPlayerTag)
Definition: InventoryView.java:167
com.realtime.crossfire.jxclient.items.InventoryView.sync
final Object sync
Definition: InventoryView.java:56
com.realtime.crossfire.jxclient.items.ItemSet
Definition: ItemSet.java:44
com.realtime.crossfire.jxclient.items.InventoryView.items
final List< CfItem > items
Definition: InventoryView.java:74
com.realtime.crossfire.jxclient.items.InventoryView.run
void run()
Definition: InventoryView.java:187
com.realtime.crossfire.jxclient.items.ItemSet.getPlayer
CfItem getPlayer()
Definition: ItemSet.java:272
com.realtime.crossfire.jxclient.items.InventoryView.comparator
final Comparator< CfItem > comparator
Definition: InventoryView.java:50
com.realtime.crossfire.jxclient.items.AbstractItemView.addModifiedRange
void addModifiedRange(final int firstIndex, final int lastIndex)
Definition: AbstractItemView.java:103
com.realtime.crossfire.jxclient.items.InventoryView.playerInventoryListener
final ItemListener playerInventoryListener
Definition: InventoryView.java:100
com.realtime.crossfire.jxclient.items.InventoryView.itemModifiedListener
final CfItemListener itemModifiedListener
Definition: InventoryView.java:137
com.realtime.crossfire.jxclient.items.InventoryFilter
Definition: InventoryFilter.java:9
com.realtime.crossfire.jxclient.items.InventoryView.getSize
int getSize()
Definition: InventoryView.java:244
com.realtime.crossfire.jxclient.items.CfItem
Definition: CfItem.java:37
com.realtime.crossfire.jxclient.items.InventoryView.filter
InventoryFilter filter
Definition: InventoryView.java:144
com.realtime.crossfire.jxclient.items.InventoryView.itemSetListener
final ItemSetListener itemSetListener
Definition: InventoryView.java:82
com.realtime.crossfire.jxclient.items.InventoryFilter.matches
matches
Definition: InventoryFilter.java:16
com.realtime.crossfire.jxclient.items.InventoryView.doRebuildInventory
void doRebuildInventory()
Definition: InventoryView.java:220
com.realtime.crossfire.jxclient.items.CfItem.getTag
int getTag()
Definition: CfItem.java:287
com.realtime.crossfire.jxclient.items.InventoryView.getItem
CfItem getItem(final int index)
Definition: InventoryView.java:252
com.realtime.crossfire.jxclient.items.ItemSet.addInventoryListener
void addInventoryListener(final int tag, @NotNull final ItemListener listener)
Definition: ItemSet.java:112
com.realtime.crossfire.jxclient.items.ItemSet.addItemSetListener
void addItemSetListener(@NotNull final ItemSetListener listener)
Definition: ItemSet.java:95
com.realtime.crossfire.jxclient.items.InventoryView.findInsertionIndex
int findInsertionIndex(@NotNull final CfItem item)
Definition: InventoryView.java:267
com.realtime.crossfire.jxclient.items.CfItemListener
Definition: CfItemListener.java:31
com.realtime.crossfire.jxclient.items.InventoryView.setFilter
void setFilter(@NotNull final InventoryFilter filter)
Definition: InventoryView.java:287
com.realtime.crossfire.jxclient.items.ItemSet.getPlayerInventory
Iterable< CfItem > getPlayerInventory()
Definition: ItemSet.java:301
com.realtime.crossfire.jxclient.items.InventoryView.changeTimestamp
long changeTimestamp
Definition: InventoryView.java:61
com.realtime.crossfire.jxclient.items.ItemSetListener
Definition: ItemSetListener.java:32
com.realtime.crossfire.jxclient.items.InventoryView
Definition: InventoryView.java:38
com.realtime.crossfire.jxclient.items.InventoryView.currentPlayerTag
int currentPlayerTag
Definition: InventoryView.java:67