Crossfire JXClient, Trunk
AskfaceFaceQueue.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.faces;
24 
25 import java.util.HashMap;
26 import java.util.LinkedList;
27 import java.util.List;
28 import java.util.Map;
29 import javax.swing.ImageIcon;
30 import org.jetbrains.annotations.NotNull;
31 
37 public class AskfaceFaceQueue extends AbstractFaceQueue {
38 
44  private static final int CONCURRENT_ASKFACE_COMMANDS = 8;
45 
49  @NotNull
50  private final Object sync = new Object();
51 
55  @NotNull
56  private final AskfaceQueue askfaceQueue;
57 
63  @NotNull
64  private final Map<Integer, Face> pendingAskfaces = new HashMap<>();
65 
70  @NotNull
71  private final Map<Integer, Face> pendingFaces = new HashMap<>();
72 
76  @NotNull
77  private final List<Face> pendingFacesQueue = new LinkedList<>();
78 
83  public AskfaceFaceQueue(@NotNull final AskfaceQueue askfaceQueue) {
84  this.askfaceQueue = askfaceQueue;
85  this.askfaceQueue.addFaceReceivedListener(this::faceReceived);
86  }
87 
88  @Override
89  public void reset() {
90  synchronized (sync) {
91  pendingAskfaces.clear();
92  pendingFaces.clear();
93  pendingFacesQueue.clear();
94  }
95  }
96 
97  @Override
98  public void loadFace(@NotNull final Face face) {
99  final int faceNum = face.getFaceNum();
100  if (faceNum <= 0 || faceNum > 65535) {
101  fireFaceFailed(face);
102  return;
103  }
104 
105  synchronized (sync) {
106  if (pendingFaces.put(faceNum, face) != null) {
107  // move image to front of queue
108  pendingFacesQueue.remove(face);
109  pendingFacesQueue.add(0, face);
110  return;
111  }
112  pendingFacesQueue.add(0, face);
113 
114  sendAskface();
115  }
116  }
117 
121  private void sendAskface() {
122  for (Face face : pendingFacesQueue) {
124  break;
125  }
126 
127  final int faceNum = face.getFaceNum();
128  if (pendingAskfaces.put(faceNum, face) == null) {
129  askfaceQueue.sendAskface(faceNum);
130  }
131  }
132  }
133 
141  private void faceReceived(final int faceNum, final int faceSetNum, final byte @NotNull [] data) {
142  synchronized (sync) {
143  final Face face = pendingAskfaces.remove(faceNum);
144  if (face == null) {
145  System.err.println("received unexpected image for face "+faceNum);
146  } else {
147  //noinspection RedundantIfStatement
148  if (pendingFaces.remove(faceNum) != face) {
149  assert false;
150  }
151  //noinspection RedundantIfStatement
152  if (!pendingFacesQueue.remove(face)) {
153  assert false;
154  }
155 
156  processFaceData(face, data);
157  }
158  sendAskface();
159  }
160  }
161 
167  private void processFaceData(@NotNull final Face face, final byte @NotNull [] data) {
168  final ImageIcon originalImageIcon;
169  try {
170  originalImageIcon = new ImageIcon(data);
171  } catch (final IllegalArgumentException ex) {
172  System.err.println("Invalid .png data for face "+face+": "+ex.getMessage());
173  return;
174  }
175 
176  if (originalImageIcon.getIconWidth() <= 0 || originalImageIcon.getIconHeight() <= 0) {
177  fireFaceFailed(face);
178  return;
179  }
180 
181  fireFaceLoaded(face, FaceImagesUtils.newFaceImages(originalImageIcon));
182  }
183 
184 }
com.realtime.crossfire.jxclient.faces.AskfaceQueue.addFaceReceivedListener
void addFaceReceivedListener(@NotNull AskfaceFaceQueueListener listener)
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.sync
final Object sync
Definition: AskfaceFaceQueue.java:50
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.loadFace
void loadFace(@NotNull final Face face)
Definition: AskfaceFaceQueue.java:98
com.realtime.crossfire.jxclient.faces.FaceImagesUtils.newFaceImages
static FaceImages newFaceImages(@NotNull final ImageIcon originalImageIcon)
Definition: FaceImagesUtils.java:51
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.askfaceQueue
final AskfaceQueue askfaceQueue
Definition: AskfaceFaceQueue.java:56
com.realtime.crossfire.jxclient.faces.AskfaceQueue.sendAskface
void sendAskface(int faceNum)
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.AskfaceFaceQueue
AskfaceFaceQueue(@NotNull final AskfaceQueue askfaceQueue)
Definition: AskfaceFaceQueue.java:83
com.realtime.crossfire.jxclient.faces.AskfaceQueue
Definition: AskfaceQueue.java:31
com.realtime.crossfire.jxclient.faces.AbstractFaceQueue.fireFaceLoaded
void fireFaceLoaded(@NotNull final Face face, @NotNull final FaceImages faceImages)
Definition: AbstractFaceQueue.java:58
com.realtime.crossfire.jxclient.faces.AbstractFaceQueue.fireFaceFailed
void fireFaceFailed(@NotNull final Face face)
Definition: AbstractFaceQueue.java:68
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.CONCURRENT_ASKFACE_COMMANDS
static final int CONCURRENT_ASKFACE_COMMANDS
Definition: AskfaceFaceQueue.java:44
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.sendAskface
void sendAskface()
Definition: AskfaceFaceQueue.java:121
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.pendingFacesQueue
final List< Face > pendingFacesQueue
Definition: AskfaceFaceQueue.java:77
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue
Definition: AskfaceFaceQueue.java:37
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.pendingAskfaces
final Map< Integer, Face > pendingAskfaces
Definition: AskfaceFaceQueue.java:64
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.faceReceived
void faceReceived(final int faceNum, final int faceSetNum, final byte @NotNull[] data)
Definition: AskfaceFaceQueue.java:141
com.realtime.crossfire.jxclient.faces.AbstractFaceQueue
Definition: AbstractFaceQueue.java:34
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.pendingFaces
final Map< Integer, Face > pendingFaces
Definition: AskfaceFaceQueue.java:71
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.processFaceData
void processFaceData(@NotNull final Face face, final byte @NotNull[] data)
Definition: AskfaceFaceQueue.java:167
com.realtime.crossfire.jxclient.faces.AskfaceFaceQueue.reset
void reset()
Definition: AskfaceFaceQueue.java:89
com.realtime.crossfire.jxclient.faces.FaceImagesUtils
Definition: FaceImagesUtils.java:36
com.realtime.crossfire.jxclient.faces.Face
Definition: Face.java:37