Files
BattleBane/src/engine/parsers/wpak/WpakLine.java
T

158 lines
4.9 KiB
Java
Raw Normal View History

// • ▌ ▄ ·. ▄▄▄· ▄▄ • ▪ ▄▄· ▄▄▄▄· ▄▄▄· ▐▄▄▄ ▄▄▄ .
// ·██ ▐███▪▐█ ▀█ ▐█ ▀ ▪██ ▐█ ▌▪▐█ ▀█▪▐█ ▀█ •█▌ ▐█▐▌·
// ▐█ ▌▐▌▐█·▄█▀▀█ ▄█ ▀█▄▐█·██ ▄▄▐█▀▀█▄▄█▀▀█ ▐█▐ ▐▌▐▀▀▀
// ██ ██▌▐█▌▐█ ▪▐▌▐█▄▪▐█▐█▌▐███▌██▄▪▐█▐█ ▪▐▌██▐ █▌▐█▄▄▌
// ▀▀ █▪▀▀▀ ▀ ▀ ·▀▀▀▀ ▀▀▀·▀▀▀ ·▀▀▀▀ ▀ ▀ ▀▀ █▪ ▀▀▀
// Magicbane Emulator Project © 2013 - 2026
// https://www.magicbane.com
package engine.parsers.wpak;
import engine.parsers.cache.CacheParserUtil;
2026-10-22 11:19:14 -04:00
import org.pmw.tinylog.Logger;
import java.util.ArrayList;
2026-10-22 11:19:14 -04:00
import java.util.regex.Matcher;
import java.util.regex.Pattern;
// One non-comment line of a wpak cfg file, split into tokens.
// Every accessor that fails names the file and line.
public class WpakLine {
2026-10-22 11:19:14 -04:00
// The client reads numbers like C atoi/atof: the leading number counts, the rest is dropped
// (Powers.cfg has "2.9.0" for a float and "10.0" for an int)
private static final Pattern intPrefix = Pattern.compile("[-+]?\\d+");
private static final Pattern floatPrefix = Pattern.compile("[-+]?(\\d+\\.?\\d*|\\.\\d+)");
public final String fileName;
public final int lineNumber;
public final String text;
public final ArrayList<String> tokens;
public WpakLine(String fileName, int lineNumber, String text, ArrayList<String> tokens) {
this.fileName = fileName;
this.lineNumber = lineNumber;
this.text = text;
this.tokens = tokens;
}
public String location() {
return fileName + ":" + lineNumber;
}
public WpakFormatException error(String message) {
return new WpakFormatException(location() + ": " + message);
}
public int size() {
return tokens.size();
}
public boolean has(int index) {
return index < tokens.size();
}
public String token(int index) {
if (!has(index))
throw error("missing token " + index + " in '" + text.trim() + "'");
return tokens.get(index);
}
public int intToken(int index) {
String value = token(index);
2026-10-22 11:19:14 -04:00
Matcher prefix;
try {
return Integer.parseInt(value);
} catch (NumberFormatException e) {
2026-10-22 11:19:14 -04:00
prefix = intPrefix.matcher(value);
}
2026-10-22 11:19:14 -04:00
if (!prefix.lookingAt())
throw error("token " + index + " '" + value + "' is not an integer");
Logger.warn(location() + ": token " + index + " '" + value + "' read as " + prefix.group() + ", as the client does");
return Integer.parseInt(prefix.group());
}
public float floatToken(int index) {
String value = token(index);
2026-10-22 11:19:14 -04:00
Matcher prefix;
try {
return Float.parseFloat(value);
} catch (NumberFormatException e) {
2026-10-22 11:19:14 -04:00
prefix = floatPrefix.matcher(value);
}
2026-10-22 11:19:14 -04:00
if (!prefix.lookingAt())
throw error("token " + index + " '" + value + "' is not a number");
Logger.warn(location() + ": token " + index + " '" + value + "' read as " + prefix.group() + ", as the client does");
return Float.parseFloat(prefix.group());
}
// The client reads a missing trailing number as 0 (String::ToInt on an empty token)
public int optionalIntToken(int index) {
if (!has(index))
return 0;
return intToken(index);
}
// TRUE/FALSE, or a number where non-zero is true
public boolean boolToken(int index) {
String value = token(index);
if (value.equalsIgnoreCase("TRUE"))
return true;
if (value.equalsIgnoreCase("FALSE"))
return false;
try {
return Integer.parseInt(value) != 0;
} catch (NumberFormatException e) {
throw error("token " + index + " '" + value + "' is not a boolean");
}
}
public boolean optionalBoolToken(int index) {
if (!has(index))
return false;
return boolToken(index);
}
public ArrayList<Integer> intTokensFrom(int index) {
ArrayList<Integer> values = new ArrayList<>();
for (int i = index; i < tokens.size(); i++)
values.add(intToken(i));
return values;
}
public <E extends Enum<E>> E enumToken(Class<E> enumClass, int index) {
String value = token(index);
String name = CacheParserUtil.enumName(value);
for (E constant : enumClass.getEnumConstants())
if (constant.name().equalsIgnoreCase(name))
return constant;
throw error("token " + index + " '" + value + "' has no " + enumClass.getSimpleName());
}
}