Crossfire JXClient, Trunk  R20561
SpellsManager.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-2012 Andreas Kirschbaum.
20  */
21 
22 package com.realtime.crossfire.jxclient.spells;
23 
31 import java.util.ArrayList;
32 import java.util.Collections;
33 import java.util.Comparator;
34 import java.util.HashMap;
35 import java.util.Iterator;
36 import java.util.List;
37 import java.util.Map;
38 import java.util.concurrent.CopyOnWriteArrayList;
39 import java.util.stream.Collectors;
40 import org.jetbrains.annotations.NotNull;
41 import org.jetbrains.annotations.Nullable;
42 
49 public class SpellsManager implements Iterable<Spell> {
50 
54  public static final int UPD_SP_MANA = 1;
55 
59  public static final int UPD_SP_GRACE = 2;
60 
64  public static final int UPD_SP_DAMAGE = 4;
65 
69  @NotNull
70  private final List<Spell> spells = new CopyOnWriteArrayList<>();
71 
75  @NotNull
76  private final List<Spell> filteredSpells = new CopyOnWriteArrayList<>();
77 
82  private int skillFilter = -1;
83 
88  @NotNull
89  private final Map<String, Spell> unknownSpells = new HashMap<>();
90 
95  @NotNull
97 
102  @NotNull
103  private final Comparator<Spell> spellNameComparator = new SpellComparator();
104 
109  @NotNull
110  @SuppressWarnings("FieldCanBeLocal")
112 
113  @Override
114  public void start() {
115  // ignore
116  }
117 
118  @Override
119  public void metaserver() {
120  // ignore
121  }
122 
123  @Override
124  public void preConnecting(@NotNull final String serverInfo) {
125  // ignore
126  }
127 
128  @Override
129  public void connecting(@NotNull final String serverInfo) {
130  spells.clear();
131  spellSkills.clear();
132  filteredSpells.clear();
133  }
134 
135  @Override
136  public void connecting(@NotNull final ClientSocketState clientSocketState) {
137  // ignore
138  }
139 
140  @Override
141  public void connected() {
142  // ignore
143  }
144 
145  @Override
146  public void connectFailed(@NotNull final String reason) {
147  // ignore
148  }
149 
150  };
151 
155  private final SkillSet skillSet;
156 
160  private final Stats stats;
161 
165  private final Skill skillAll = new Skill("All skills");
166 
170  private final List<Skill> spellSkills = new ArrayList<>();
171 
175  private static final Comparator<Skill> SKILL_COMPARATOR = (o1, o2) -> o1.toString().compareTo(o2.toString());
176 
183  public SpellsManager(@NotNull final GuiStateManager guiStateManager, @NotNull final SkillSet skillSet, @NotNull final Stats stats) {
184  guiStateManager.addGuiStateListener(guiStateListener);
185  this.skillSet = skillSet;
186  this.stats = stats;
187  }
188 
193  public void addCrossfireSpellChangedListener(@NotNull final SpellsManagerListener listener) {
194  listeners.add(listener);
195  }
196 
201  public void removeCrossfireSpellChangedListener(@NotNull final SpellsManagerListener listener) {
202  listeners.remove(listener);
203  }
204 
220  public void addSpell(final int tag, final int level, final int castingTime, final int mana, final int grace, final int damage, final int skill, final int path, final int faceNum, @NotNull final String spellName, @NotNull final String message) {
221  final Spell key = new Spell(spellName, skillSet, stats);
222  key.setParameters(faceNum, tag, message, level, castingTime, mana, grace, damage, skill, path); // set spell path which is used in the comparator
223 
224  int index = Collections.binarySearch(spells, key, spellNameComparator);
225  final Spell spell;
226  if (index < 0) {
227  final Spell existingSpell;
228  synchronized (unknownSpells) {
229  existingSpell = unknownSpells.remove(spellName);
230  }
231  if (existingSpell == null) {
232  spell = key;
233  } else {
234  spell = existingSpell;
235  spell.setParameters(faceNum, tag, message, level, castingTime, mana, grace, damage, skill, path);
236  }
237  index = -index-1;
238  spells.add(index, spell);
239  } else {
240  spell = spells.get(index);
241  spell.setParameters(faceNum, tag, message, level, castingTime, mana, grace, damage, skill, path);
242  }
243 
244  rebuildSkills();
245  filterSpells();
246 
247  for (final SpellsManagerListener listener : listeners) {
248  listener.spellAdded(index);
249  }
250  }
251 
260  public void updateSpell(final int flags, final int tag, final int mana, final int grace, final int damage) {
261  for (final Spell spell : spells) {
262  if (spell.getTag() == tag) {
263  spell.updateParameters((flags&UPD_SP_MANA) != 0, mana, (flags&UPD_SP_GRACE) != 0, grace, (flags&UPD_SP_DAMAGE) != 0, damage);
264  break;
265  }
266  }
267  }
268 
273  public void deleteSpell(final int tag) {
274  int index = 0;
275  for (final Spell spell : spells) {
276  if (spell.getTag() == tag) {
277  deleteSpellByIndex(index);
278  break;
279  }
280  index++;
281  }
282  rebuildSkills();
283  filterSpells();
284  }
285 
290  private void deleteSpellByIndex(final int index) {
291  final Spell spell = spells.remove(index);
292  synchronized (unknownSpells) {
293  unknownSpells.put(spell.getName(), spell);
294  }
295 
296  for (final SpellsManagerListener listener : listeners) {
297  listener.spellRemoved(index);
298  }
299 
300  spell.setUnknown(true);
301 
302  rebuildSkills();
303  }
304 
311  @NotNull
312  public Spell getSpell(@NotNull final String spellName) {
313  for (final Spell spell : spells) {
314  if (spell.getName().equals(spellName)) {
315  return spell;
316  }
317  }
318 
319  final Spell spell = new Spell(spellName, skillSet, stats);
320  spell.setUnknown(true);
321  synchronized (unknownSpells) {
322  unknownSpells.put(spell.getName(), spell);
323  }
324  return spell;
325  }
326 
330  @NotNull
331  @Override
332  public Iterator<Spell> iterator() {
333  return Collections.unmodifiableList(filteredSpells).iterator();
334  }
335 
340  public int getSpells() {
341  return filteredSpells.size();
342  }
343 
349  @Nullable
350  public Spell getSpell(final int index) {
351  try {
352  return filteredSpells.get(index);
353  } catch (final IndexOutOfBoundsException ignored) {
354  return null;
355  }
356  }
357 
363  public boolean displaysFace(final int faceNum) {
364  for (final Spell spell : spells) {
365  if (spell.getFaceNum() == faceNum) {
366  return true;
367  }
368  }
369 
370  return false;
371  }
372 
376  public void selectCharacter() {
377  spells.clear();
378  filteredSpells.clear();
379  }
380 
385  public void filterSkill(final int index) {
386  if (index < 0 || index >= spellSkills.size()) {
387  return;
388  }
389 
390  final int id = skillSet.getSkillId(spellSkills.get(index).toString());
391 
392  if (skillFilter == id) {
393  return;
394  }
395 
396  skillFilter = id;
397  filterSpells();
398 
399  for (final SpellsManagerListener listener : listeners) {
400  listener.spellAdded(0);
401  }
402  }
403 
407  private void filterSpells() {
408  filteredSpells.clear();
409  filteredSpells.addAll(spells.stream().filter(spell -> skillFilter == -1 || spell.getSkill() == skillFilter).collect(Collectors.toList()));
410  }
411 
415  private void rebuildSkills() {
416  spellSkills.clear();
417  for (final Spell spell : spells) {
418  final Skill skill = skillSet.getSkill(spell.getSkill());
419  if (skill != null && !spellSkills.contains(skill)) {
420  spellSkills.add(skill);
421  }
422  }
423  Collections.sort(spellSkills, SKILL_COMPARATOR);
424  spellSkills.add(0, skillAll);
425  }
426 
431  public int getSpellSkills() {
432  return spellSkills.size();
433  }
434 
440  @Nullable
441  public Skill getSpellSkill(final int index) {
442  return 0 <= index && index < spellSkills.size() ? spellSkills.get(index) : null;
443  }
444 
445 }
final Comparator< Spell > spellNameComparator
A Comparator to compare Spell instances by spell path and name.
void addSpell(final int tag, final int level, final int castingTime, final int mana, final int grace, final int damage, final int skill, final int path, final int faceNum, @NotNull final String spellName, @NotNull final String message)
Adds a new spell.
static final Comparator< Skill > SKILL_COMPARATOR
Compare 2 skills.
Interface for listeners interested gui state changes.
void filterSpells()
Rebuilds the list of spells to display.
String getName()
Returns the spell name.
Definition: Spell.java:197
void updateSpell(final int flags, final int tag, final int mana, final int grace, final int damage)
Updates spell information.
final Skill skillAll
Dummy skill for "all skills".
final List< Spell > filteredSpells
Spells currently exposed, based on the filter.
void selectCharacter()
An character name was sent to the server.
Interface for listeners interested in SpellsManager events.
SpellsManager(@NotNull final GuiStateManager guiStateManager, @NotNull final SkillSet skillSet, @NotNull final Stats stats)
Creates a new instance.
int getSpells()
Returns the number of known spells.
final Map< String, Spell > unknownSpells
All unknown spells that have been referenced before.
void deleteSpell(final int tag)
Deletes a spell.
final List< Spell > spells
All known spells.
static final int UPD_SP_GRACE
Flag for updspell command: grace is present.
static final int UPD_SP_MANA
Flag for updspell command: mana is present.
One skill of the character.
Definition: Skill.java:32
void removeCrossfireSpellChangedListener(@NotNull final SpellsManagerListener listener)
Removes a SpellsManagerListener to notify about changes.
int getSkillId(final String name)
Get a skill identifier from the skill name.
Definition: SkillSet.java:182
final EventListenerList2< SpellsManagerListener > listeners
The SpellsManagerListeners to notify about changes.
void setParameters(final int faceNum, final int tag, @NotNull final String message, final int level, final int castingTime, final int mana, final int grace, final int damage, final int skill, final int path)
Updates the spell&#39;s parameters.
Definition: Spell.java:250
Describes a Crossfire spell.
Definition: Spell.java:36
void deleteSpellByIndex(final int index)
Deletes a spell by index into spells.
void addCrossfireSpellChangedListener(@NotNull final SpellsManagerListener listener)
Adds a SpellsManagerListener to notify about changes.
final SkillSet skillSet
The SkillSet containing skills from the server.
A Comparator to compare Spell instances by spell path and name.
void add(@NotNull final T listener)
Adds a listener.
Skill getSkill(final int id)
Returns the given skill as a Skill object.
Definition: SkillSet.java:172
void rebuildSkills()
Rebuilds the list of skills from the spells.
int getSpellSkills()
Returns the number of spell skills.
static final int UPD_SP_DAMAGE
Flag for updspell command: damage is present.
void filterSkill(final int index)
Filters spells to display by the specified skill index.
final List< Skill > spellSkills
Skills used by the spell, including the "all" skill.
int skillFilter
Skill to filter spells by, as a skill id in SkillSet.
This is the representation of all the statistics of a player, like its speed or its experience...
Definition: Stats.java:43
final Stats stats
The Stats for the player.
Skill getSpellSkill(final int index)
Returns the specified spell skill.
Maintain the set of skills as sent by the server.
Definition: SkillSet.java:38
void setUnknown(final boolean unknown)
Marks this spell as known or unknown for the character.
Definition: Spell.java:230
boolean displaysFace(final int faceNum)
Returns whether any spell has the given face.
void remove(@NotNull final T listener)
Removes a listener.
Connection progress states of the Crossfire server connection.
final GuiStateListener guiStateListener
The GuiStateListener for detecting established or dropped connections.
Spell getSpell(final int index)
Returns a Spell instance by index.
Spell getSpell(@NotNull final String spellName)
Returns a Spell instance by spell name.