Gridarta Editor
AttributeBitmask.java
Go to the documentation of this file.
1 /*
2  * Gridarta MMORPG map editor for Crossfire, Daimonin and similar games.
3  * Copyright (C) 2000-2023 The Gridarta Developers.
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License along
16  * with this program; if not, write to the Free Software Foundation, Inc.,
17  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18  */
19 
20 package net.sf.gridarta.model.archetypetype;
21 
22 import java.util.ArrayList;
23 import java.util.Collection;
24 import java.util.HashMap;
25 import java.util.List;
26 import java.util.Map;
30 import org.apache.log4j.Category;
31 import org.apache.log4j.Logger;
32 import org.jetbrains.annotations.NotNull;
33 import org.jetbrains.annotations.Nullable;
34 
42 public class AttributeBitmask {
43 
47  @NotNull
48  private static final Category LOG = Logger.getLogger(AttributeBitmask.class);
49 
54  private static final int MAX_CHARS_PER_LINE = 35; // 50
55 
59  @NotNull
60  private final List<String> bitName = new ArrayList<>();
61 
66  private final boolean isNamed;
67 
71  @NotNull
72  private final Map<String, Integer> namedValues = new HashMap<>();
73 
77  @NotNull
78  private final Map<Integer, String> encodings = new HashMap<>();
79 
83  @NotNull
84  private final Map<Integer, String> names = new HashMap<>();
85 
91  public AttributeBitmask(final boolean isNamed) {
92  this.isNamed = isNamed;
93  }
94 
100  @NotNull
101  // feature envy is natural here - WrappingStringBuilder is a kind of library class.
102  public String getText(final int value) {
104  for (final String word : encodeValueAsList(value, names)) {
105  sb.append(word);
106  }
107  return sb.toString();
108  }
109 
119  @NotNull
120  public String encodeValue(final int value) {
121  if (!isNamed) {
122  return Integer.toString(value);
123  }
124 
125  final StringBuilder sb = new StringBuilder();
126  for (final String word : encodeValueAsList(value, encodings)) {
127  if (sb.length() > 0) {
128  sb.append(' ');
129  }
130  sb.append(word);
131  }
132  return sb.toString();
133  }
134 
145  @NotNull
146  private Iterable<String> encodeValueAsList(final int value, @NotNull final Map<Integer, String> strings) {
147  final int moveAll = getMaxValue();
148 
149  final Collection<String> negResult = new ArrayList<>();
150  negResult.add("all");
151 
152  if (value == moveAll) {
153  return negResult;
154  }
155  final Collection<String> result = new ArrayList<>();
156  if (value == 0) {
157  final String str = strings.get(0);
158  result.add(str == null ? "0" : str);
159  return result;
160  }
161 
162  /* We basically slide the bits down. Why look at moveAll? because we
163  * may want to return a string like 'all -swim', and if we just looked
164  * at mt, we couldn't get that.
165  */
166  int allCount = 0;
167  int count = 0;
168  for (int i = moveAll; i != 0; i >>= 1) {
169  final String strNull = strings.get(1 << count);
170  final String str = strNull == null ? Integer.toString(1 << count) : strNull;
171  if ((value & (1 << count)) == 0) {
172  negResult.add("-" + str);
173  allCount++;
174  } else {
175  result.add(str);
176  }
177  count++;
178  }
179  if ((value & ~moveAll) != 0) {
180  result.add(Integer.toString(value & ~moveAll));
181  return result;
182  }
183  /* Basically, if there is a single negation, return it, eg 'all -swim'.
184  * But more than that, just return the enumerated values. It doesn't
185  * make sense to return 'all -walk -fly_low' - it is shorter to return
186  * 'fly_high swim'
187  */
188  return count >= 4 && allCount <= 1 ? negResult : result;
189  }
190 
196  public int decodeValue(@NotNull final String encodedValue) {
197  if (!isNamed) {
198  return NumberUtils.parseInt(encodedValue);
199  }
200 
201  if (encodedValue.isEmpty()) {
202  return 0;
203  }
204 
205  int result = 0;
206  for (final String word : StringUtils.PATTERN_SPACES.split(encodedValue, 0)) {
207  final boolean negated;
208  final String name;
209  if (word.startsWith("-")) {
210  negated = true;
211  name = word.substring(1);
212  } else {
213  negated = false;
214  name = word;
215  }
216  final Integer integerValue = namedValues.get(name);
217  int value;
218  if (integerValue == null) {
219  try {
220  value = Integer.parseInt(name);
221  } catch (final NumberFormatException ignored) {
222  LOG.warn("Ignoring unknown bitmask value: " + name);
223  value = 0;
224  }
225  } else {
226  value = integerValue;
227  }
228  if (negated) {
229  result &= ~value;
230  } else {
231  result |= value;
232  }
233  }
234  return result;
235  }
236 
241  public int getMaxValue() {
242  return (1 << bitName.size()) - 1;
243  }
244 
249  public int getNumber() {
250  return bitName.size();
251  }
252 
258  @Nullable
259  public String getBitName(final int index) {
260  return bitName.get(index);
261  }
262 
268  public void addName(@NotNull final String name, final int value) {
269  names.put(value, name);
270  }
271 
277  public void addNamedValue(@NotNull final String name, final int value) {
278  namedValues.put(name, value);
279  encodings.put(value, name);
280  }
281 
287  public boolean containsEncoding(final int value) {
288  return encodings.containsKey(value);
289  }
290 
297  public boolean addBitName(final int bitValue, @NotNull final String name) {
298  if (bitValue >= bitName.size()) {
299  do {
300  bitName.add(null);
301  } while (bitValue >= bitName.size());
302  } else if (bitName.get(bitValue) != null) {
303  return false;
304  }
305 
306  bitName.set(bitValue, name);
307  return true;
308  }
309 
310 }
name
name
Definition: ArchetypeTypeSetParserTest-ignoreDefaultAttribute1-result.txt:2
net.sf.gridarta.utils.NumberUtils.parseInt
static int parseInt(@NotNull final String s)
Parses an integer string.
Definition: NumberUtils.java:41
net.sf.gridarta.model.archetypetype.AttributeBitmask.getNumber
int getNumber()
Returns the number of bitmask entries (not counting zero).
Definition: AttributeBitmask.java:249
net.sf.gridarta.model.archetypetype.AttributeBitmask.encodings
final Map< Integer, String > encodings
Maps bit value to external representation.
Definition: AttributeBitmask.java:78
net.sf.gridarta.utils.WrappingStringBuilder.append
void append(final String str)
Appends a word.
Definition: WrappingStringBuilder.java:61
net.sf.gridarta
Base package of all Gridarta classes.
net.sf.gridarta.model.archetypetype.AttributeBitmask.getMaxValue
int getMaxValue()
Returns the maximum allowed bitmask value.
Definition: AttributeBitmask.java:241
net.sf
net.sf.gridarta.model.archetypetype.AttributeBitmask.isNamed
final boolean isNamed
Set if the bitmask value may be encoded as strings in external representation; unset if the value is ...
Definition: AttributeBitmask.java:66
net.sf.gridarta.model.archetypetype.AttributeBitmask.encodeValueAsList
Iterable< String > encodeValueAsList(final int value, @NotNull final Map< Integer, String > strings)
Convert a value to string representation.
Definition: AttributeBitmask.java:146
net.sf.gridarta.model.archetypetype.AttributeBitmask.AttributeBitmask
AttributeBitmask(final boolean isNamed)
Constructor of a bitmask from XML element.
Definition: AttributeBitmask.java:91
net.sf.gridarta.model.archetypetype.AttributeBitmask.getText
String getText(final int value)
Generate the text to be displayed for a given bitmask value.
Definition: AttributeBitmask.java:102
net.sf.gridarta.model.archetypetype.AttributeBitmask.namedValues
final Map< String, Integer > namedValues
Maps names for value encoding in external representation.
Definition: AttributeBitmask.java:72
net.sf.gridarta.model.archetypetype.AttributeBitmask.bitName
final List< String > bitName
The names of the bitmask entries.
Definition: AttributeBitmask.java:60
net.sf.gridarta.utils.WrappingStringBuilder
Implements a string buffer that separates words by "," and wraps lines at a given margin.
Definition: WrappingStringBuilder.java:27
net.sf.gridarta.model.archetypetype.AttributeBitmask.decodeValue
int decodeValue(@NotNull final String encodedValue)
Convert a value from external representation.
Definition: AttributeBitmask.java:196
net.sf.gridarta.model.archetypetype.AttributeBitmask.addBitName
boolean addBitName(final int bitValue, @NotNull final String name)
Defines a bit name for a bit value.
Definition: AttributeBitmask.java:297
net.sf.gridarta.model.archetypetype.AttributeBitmask.encodeValue
String encodeValue(final int value)
Convert a value to external representation.
Definition: AttributeBitmask.java:120
net.sf.gridarta.model.archetypetype.AttributeBitmask.getBitName
String getBitName(final int index)
Returns the name of a bitmask value.
Definition: AttributeBitmask.java:259
net.sf.gridarta.model.archetypetype.AttributeBitmask.containsEncoding
boolean containsEncoding(final int value)
Returns whether an external encoding for value exists.
Definition: AttributeBitmask.java:287
net
net.sf.gridarta.model.archetypetype.AttributeBitmask
This class manages bitmask values which appear in Gridarta archetype attributes.
Definition: AttributeBitmask.java:42
net.sf.gridarta.utils.StringUtils
Utility class for string manipulation.
Definition: StringUtils.java:31
net.sf.gridarta.utils.StringUtils.PATTERN_SPACES
static final Pattern PATTERN_SPACES
The pattern that matches a non-empty sequence of spaces.
Definition: StringUtils.java:73
net.sf.gridarta.model.archetypetype.AttributeBitmask.LOG
static final Category LOG
The Logger for printing log messages.
Definition: AttributeBitmask.java:48
net.sf.gridarta.model.archetypetype.AttributeBitmask.addNamedValue
void addNamedValue(@NotNull final String name, final int value)
Adds a name for external encoding of a value.
Definition: AttributeBitmask.java:277
net.sf.gridarta.utils
Definition: ActionBuilderUtils.java:20
net.sf.gridarta.model.archetypetype.AttributeBitmask.addName
void addName(@NotNull final String name, final int value)
Adds a readable name for a bit value.
Definition: AttributeBitmask.java:268
net.sf.gridarta.model.archetypetype.AttributeBitmask.MAX_CHARS_PER_LINE
static final int MAX_CHARS_PER_LINE
Maximum number of characters in a line before line break (see {}).
Definition: AttributeBitmask.java:54
net.sf.gridarta.utils.WrappingStringBuilder.toString
String toString()
Returns the concatenated words as a string.
Definition: WrappingStringBuilder.java:89
net.sf.gridarta.utils.NumberUtils
Utility class for parsing strings into numbers.
Definition: NumberUtils.java:28
net.sf.gridarta.model.archetypetype.AttributeBitmask.names
final Map< Integer, String > names
Maps bit value to readable name.
Definition: AttributeBitmask.java:84