initial commit
This commit is contained in:
parent
3c9ee26b06
commit
22186c33b9
1458 changed files with 282792 additions and 0 deletions
97
java/src/game/command/ArgumentParser.java
Normal file
97
java/src/game/command/ArgumentParser.java
Normal file
|
@ -0,0 +1,97 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.collect.Lists;
|
||||
|
||||
public abstract class ArgumentParser {
|
||||
public static String[][] splitString(String str) {
|
||||
// if(str.isEmpty()) {
|
||||
// return new String[0];
|
||||
// }
|
||||
int pos;
|
||||
int last = 0;
|
||||
boolean space = true;
|
||||
boolean quote = false;
|
||||
boolean escape = false;
|
||||
char c;
|
||||
String arg = "";
|
||||
List<String> args = Lists.<String>newArrayList();
|
||||
List<String[]> cmds = Lists.<String[]>newArrayList();
|
||||
for(pos = 0; pos < str.length(); pos++) {
|
||||
c = str.charAt(pos);
|
||||
if(escape) {
|
||||
escape = false;
|
||||
switch(c) {
|
||||
case '\\':
|
||||
case ' ':
|
||||
case '"':
|
||||
case ';':
|
||||
arg += c;
|
||||
break;
|
||||
default:
|
||||
throw new ScriptException("Unbekannte Sequenz bei Zeichen %d: '\\%c'", pos + 1, c);
|
||||
}
|
||||
}
|
||||
else if(c == '\\') {
|
||||
space = false;
|
||||
escape = true;
|
||||
}
|
||||
else if(c == '"') {
|
||||
space = false;
|
||||
quote = !quote;
|
||||
last = pos;
|
||||
}
|
||||
else if(c == ' ' && !quote) {
|
||||
if(!space) {
|
||||
args.add(arg);
|
||||
arg = "";
|
||||
}
|
||||
space = true;
|
||||
}
|
||||
else if(c == ';' && !quote) {
|
||||
if(!space) {
|
||||
args.add(arg);
|
||||
arg = "";
|
||||
}
|
||||
if(!args.isEmpty()) {
|
||||
cmds.add(args.toArray(new String[args.size()]));
|
||||
args.clear();
|
||||
}
|
||||
}
|
||||
else {
|
||||
space = false;
|
||||
arg += c;
|
||||
}
|
||||
}
|
||||
if(escape)
|
||||
throw new ScriptException("Unvollständige Sequenz bei Zeichen %d", pos + 1);
|
||||
if(quote)
|
||||
throw new ScriptException("Nicht geschlossenes Anführungszeichen bei %d", last + 1);
|
||||
if(!space)
|
||||
args.add(arg);
|
||||
if(!args.isEmpty()) {
|
||||
cmds.add(args.toArray(new String[args.size()]));
|
||||
args.clear();
|
||||
}
|
||||
return cmds.toArray(new String[cmds.size()][]);
|
||||
}
|
||||
|
||||
private final String name;
|
||||
|
||||
public ArgumentParser(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public abstract Object parse(ScriptEnvironment env, String input);
|
||||
public abstract Object getDefault(ScriptEnvironment env);
|
||||
public abstract String[] getCompletions(ScriptEnvironment env);
|
||||
|
||||
public final String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public final String toString() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
7
java/src/game/command/BooleanParser.java
Normal file
7
java/src/game/command/BooleanParser.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package game.command;
|
||||
|
||||
public class BooleanParser extends EnumParser {
|
||||
public BooleanParser(String name, Boolean def) {
|
||||
super(name, def, true, false);
|
||||
}
|
||||
}
|
60
java/src/game/command/CachedExecutable.java
Normal file
60
java/src/game/command/CachedExecutable.java
Normal file
|
@ -0,0 +1,60 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
public class CachedExecutable {
|
||||
private final Executable executable;
|
||||
private final String name;
|
||||
private final Map<String, Parameter> parameters;
|
||||
private final List<Parameter> positionals;
|
||||
|
||||
protected CachedExecutable(Executable executable, Map<String, Parameter> parameters, List<Parameter> positionals) {
|
||||
this.executable = executable;
|
||||
this.parameters = parameters;
|
||||
this.positionals = positionals;
|
||||
this.name = executable.getName();
|
||||
}
|
||||
|
||||
public static CachedExecutable cacheExecutable(Executable executable) {
|
||||
Map<String, Parameter> parameters = Maps.newTreeMap();
|
||||
Map<String, Parameter> params = executable.getParameters();
|
||||
parameters.putAll(params);
|
||||
Parameter[] positions = new Parameter[parameters.size()];
|
||||
int pos = -1;
|
||||
for(Parameter param : params.values()) {
|
||||
if(param.isPositional()) {
|
||||
positions[param.getPosition()] = param;
|
||||
pos = param.getPosition() > pos ? param.getPosition() : pos;
|
||||
}
|
||||
if(param.hasShortName())
|
||||
parameters.put("" + param.getShortName(), param);
|
||||
}
|
||||
List<Parameter> positionals = Lists.newArrayList();
|
||||
for(int z = 0; z <= pos; z++) {
|
||||
if(positions[z] == null)
|
||||
throw new NullPointerException("positions[" + z + "]");
|
||||
positionals.add(positions[z]);
|
||||
}
|
||||
return new CachedExecutable(executable, parameters, positionals);
|
||||
}
|
||||
|
||||
public Executable getExecutable() {
|
||||
return this.executable;
|
||||
}
|
||||
|
||||
public Map<String, Parameter> getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
public List<Parameter> getPositionals() {
|
||||
return this.positionals;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
27
java/src/game/command/ColorParser.java
Normal file
27
java/src/game/command/ColorParser.java
Normal file
|
@ -0,0 +1,27 @@
|
|||
package game.command;
|
||||
|
||||
import game.color.DyeColor;
|
||||
|
||||
public class ColorParser extends IntParser {
|
||||
public ColorParser(String name, Integer def, Object ... completions) {
|
||||
super(name, true, def, null, null, completions);
|
||||
}
|
||||
|
||||
public ColorParser(String name, Integer def) {
|
||||
this(name, def, (Object[])DyeColor.values());
|
||||
}
|
||||
|
||||
public Integer parse(ScriptEnvironment env, String input) {
|
||||
if(input.startsWith("#")) {
|
||||
input = input.substring(1);
|
||||
}
|
||||
else {
|
||||
DyeColor color = DyeColor.getByString(input);
|
||||
if(color != null)
|
||||
return color.getColor();
|
||||
}
|
||||
if(input.length() != 6)
|
||||
throw new ScriptException("Der Farbcode muss 6 Stellen haben, habe %d ('%s')", input.length(), input);
|
||||
return super.parse(env, input);
|
||||
}
|
||||
}
|
7
java/src/game/command/Completer.java
Normal file
7
java/src/game/command/Completer.java
Normal file
|
@ -0,0 +1,7 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public interface Completer {
|
||||
void complete(List<String> comp, ScriptEnvironment env, ScriptArgs args, ScriptArg arg);
|
||||
}
|
17
java/src/game/command/CompletingParser.java
Normal file
17
java/src/game/command/CompletingParser.java
Normal file
|
@ -0,0 +1,17 @@
|
|||
package game.command;
|
||||
|
||||
public abstract class CompletingParser extends ArgumentParser {
|
||||
private final String[] defCompletions;
|
||||
|
||||
public CompletingParser(String name, Object ... completions) {
|
||||
super(name);
|
||||
this.defCompletions = new String[completions.length];
|
||||
for(int z = 0; z < completions.length; z++) {
|
||||
this.defCompletions[z] = String.valueOf(completions[z]);
|
||||
}
|
||||
}
|
||||
|
||||
public String[] getCompletions(ScriptEnvironment env) {
|
||||
return this.defCompletions;
|
||||
}
|
||||
}
|
14
java/src/game/command/DefaultingParser.java
Normal file
14
java/src/game/command/DefaultingParser.java
Normal file
|
@ -0,0 +1,14 @@
|
|||
package game.command;
|
||||
|
||||
public abstract class DefaultingParser extends CompletingParser {
|
||||
private final Object def;
|
||||
|
||||
public DefaultingParser(String name, Object def, Object ... completions) {
|
||||
super(name, completions);
|
||||
this.def = def;
|
||||
}
|
||||
|
||||
public Object getDefault(ScriptEnvironment env) {
|
||||
return this.def;
|
||||
}
|
||||
}
|
30
java/src/game/command/DimensionParser.java
Normal file
30
java/src/game/command/DimensionParser.java
Normal file
|
@ -0,0 +1,30 @@
|
|||
package game.command;
|
||||
|
||||
import game.dimension.Dimension;
|
||||
import game.init.UniverseRegistry;
|
||||
|
||||
public class DimensionParser extends NonDefaultingParser {
|
||||
public DimensionParser(String name) {
|
||||
super(name);
|
||||
}
|
||||
|
||||
public Object parse(ScriptEnvironment env, String input) {
|
||||
Dimension dim = UniverseRegistry.getDimension(input);
|
||||
if(dim != null)
|
||||
return dim;
|
||||
int id = Integer.MIN_VALUE;
|
||||
try {
|
||||
id = Integer.parseInt(input);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
}
|
||||
dim = UniverseRegistry.getDimension(id);
|
||||
if(dim == null)
|
||||
throw new ScriptException("Unbekannte Dimension '%s'", input);
|
||||
return dim;
|
||||
}
|
||||
|
||||
public String[] getCompletions(ScriptEnvironment env) {
|
||||
return UniverseRegistry.getWorldNames().toArray(new String[UniverseRegistry.getWorldNames().size()]);
|
||||
}
|
||||
}
|
33
java/src/game/command/DoubleParser.java
Normal file
33
java/src/game/command/DoubleParser.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package game.command;
|
||||
|
||||
public class DoubleParser extends DefaultingParser {
|
||||
private final Double min;
|
||||
private final Double max;
|
||||
|
||||
public DoubleParser(String name, Double def, Double min, Double max, Object ... completions) {
|
||||
super(name, def, completions);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public Double parse(ScriptEnvironment env, String input) {
|
||||
double value;
|
||||
try {
|
||||
value = Double.parseDouble(input);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
throw new ScriptException("Ungültige Gleitkommazahl '%s'", input);
|
||||
}
|
||||
if(this.min != null && value < this.min)
|
||||
if(this.max != null)
|
||||
throw new ScriptException("Die Zahl muss im Bereich %f .. %f liegen, habe %f", this.min, this.max, value);
|
||||
else
|
||||
throw new ScriptException("Die Zahl muss mindestens %f betragen, habe %f", this.min, value);
|
||||
if(this.max != null && value > this.max)
|
||||
if(this.min != null)
|
||||
throw new ScriptException("Die Zahl muss im Bereich %f .. %f liegen, habe %f", this.min, this.max, value);
|
||||
else
|
||||
throw new ScriptException("Die Zahl darf höchstens %f betragen, habe %f", this.max, value);
|
||||
return value;
|
||||
}
|
||||
}
|
44
java/src/game/command/EnumParser.java
Normal file
44
java/src/game/command/EnumParser.java
Normal file
|
@ -0,0 +1,44 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import game.collect.Maps;
|
||||
|
||||
public class EnumParser extends DefaultingParser {
|
||||
private final Map<String, Object> lookup = Maps.newHashMap();
|
||||
private final Object[] selections;
|
||||
|
||||
private static <T> String joinArgs(T[] iter) {
|
||||
StringBuilder sb = new StringBuilder("'");
|
||||
for(T obj : iter) {
|
||||
if(sb.length() > 1)
|
||||
sb.append("', '");
|
||||
sb.append(String.valueOf(obj));
|
||||
}
|
||||
return sb.append("'").toString();
|
||||
}
|
||||
|
||||
public EnumParser(String name, Object def, Object ... selections) {
|
||||
super(name, def, selections);
|
||||
this.selections = selections;
|
||||
for(Object o : selections) {
|
||||
this.lookup.put(o.toString().toLowerCase(), o);
|
||||
}
|
||||
}
|
||||
|
||||
public Object parse(ScriptEnvironment env, String input) {
|
||||
Object value = this.lookup.get(input.toLowerCase());
|
||||
if(value != null)
|
||||
return value;
|
||||
int id = -1;
|
||||
try {
|
||||
id = Integer.parseInt(input);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
}
|
||||
if(id < 0 || id >= this.selections.length)
|
||||
throw new ScriptException("Ungültige Auswahl '%s', muss eine von diesen Optionen sein: %s", input,
|
||||
joinArgs(this.selections));
|
||||
return this.selections[id];
|
||||
}
|
||||
}
|
9
java/src/game/command/Executable.java
Normal file
9
java/src/game/command/Executable.java
Normal file
|
@ -0,0 +1,9 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface Executable {
|
||||
Object exec(ScriptEnvironment env, ScriptArgs args);
|
||||
Map<String, Parameter> getParameters();
|
||||
String getName();
|
||||
}
|
35
java/src/game/command/IntParser.java
Normal file
35
java/src/game/command/IntParser.java
Normal file
|
@ -0,0 +1,35 @@
|
|||
package game.command;
|
||||
|
||||
public class IntParser extends DefaultingParser {
|
||||
private final Integer min;
|
||||
private final Integer max;
|
||||
private final boolean hex;
|
||||
|
||||
public IntParser(String name, boolean hex, Integer def, Integer min, Integer max, Object ... completions) {
|
||||
super(name, def, completions);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
this.hex = hex;
|
||||
}
|
||||
|
||||
public Integer parse(ScriptEnvironment env, String input) {
|
||||
int value;
|
||||
try {
|
||||
value = Integer.parseInt(input, this.hex ? 16 : 10);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
throw new ScriptException("Ungültige " + (this.hex ? "Hexadezimalzahl" : "Ganzzahl") + " '%s'", input);
|
||||
}
|
||||
if(this.min != null && value < this.min)
|
||||
if(this.max != null)
|
||||
throw new ScriptException("Die Zahl muss im Bereich %d .. %d liegen, habe %d", this.min, this.max, value);
|
||||
else
|
||||
throw new ScriptException("Die Zahl muss mindestens %d betragen, habe %d", this.min, value);
|
||||
if(this.max != null && value > this.max)
|
||||
if(this.min != null)
|
||||
throw new ScriptException("Die Zahl muss im Bereich %d .. %d liegen, habe %d", this.min, this.max, value);
|
||||
else
|
||||
throw new ScriptException("Die Zahl darf höchstens %d betragen, habe %d", this.max, value);
|
||||
return value;
|
||||
}
|
||||
}
|
33
java/src/game/command/LongParser.java
Normal file
33
java/src/game/command/LongParser.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package game.command;
|
||||
|
||||
public class LongParser extends DefaultingParser {
|
||||
private final Long min;
|
||||
private final Long max;
|
||||
|
||||
public LongParser(String name, Long def, Long min, Long max, Object ... completions) {
|
||||
super(name, def, completions);
|
||||
this.min = min;
|
||||
this.max = max;
|
||||
}
|
||||
|
||||
public Long parse(ScriptEnvironment env, String input) {
|
||||
long value;
|
||||
try {
|
||||
value = Long.parseLong(input);
|
||||
}
|
||||
catch(NumberFormatException e) {
|
||||
throw new ScriptException("Ungültige Ganzzahl '%s'", input);
|
||||
}
|
||||
if(this.min != null && value < this.min)
|
||||
if(this.max != null)
|
||||
throw new ScriptException("Die Zahl muss im Bereich %d .. %d liegen, habe %d", this.min, this.max, value);
|
||||
else
|
||||
throw new ScriptException("Die Zahl muss mindestens %d betragen, habe %d", this.min, value);
|
||||
if(this.max != null && value > this.max)
|
||||
if(this.min != null)
|
||||
throw new ScriptException("Die Zahl muss im Bereich %d .. %d liegen, habe %d", this.min, this.max, value);
|
||||
else
|
||||
throw new ScriptException("Die Zahl darf höchstens %d betragen, habe %d", this.max, value);
|
||||
return value;
|
||||
}
|
||||
}
|
11
java/src/game/command/NonDefaultingParser.java
Normal file
11
java/src/game/command/NonDefaultingParser.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package game.command;
|
||||
|
||||
public abstract class NonDefaultingParser extends CompletingParser {
|
||||
public NonDefaultingParser(String name, Object ... completions) {
|
||||
super(name, completions);
|
||||
}
|
||||
|
||||
public Object getDefault(ScriptEnvironment env) {
|
||||
return null;
|
||||
}
|
||||
}
|
47
java/src/game/command/Parameter.java
Normal file
47
java/src/game/command/Parameter.java
Normal file
|
@ -0,0 +1,47 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Parameter {
|
||||
private final String name;
|
||||
private final char shortName;
|
||||
private final boolean required;
|
||||
private final int position;
|
||||
private final List<ArgumentParser> parsers;
|
||||
|
||||
public Parameter(String name, char shortName, int position, boolean required, List<ArgumentParser> parsers) {
|
||||
this.name = name;
|
||||
this.shortName = shortName;
|
||||
this.position = position;
|
||||
this.required = required;
|
||||
this.parsers = parsers;
|
||||
}
|
||||
|
||||
public boolean isPositional() {
|
||||
return this.position > 0;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public List<ArgumentParser> getParsers() {
|
||||
return this.parsers;
|
||||
}
|
||||
|
||||
public boolean isRequired() {
|
||||
return this.required;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
|
||||
public boolean hasShortName() {
|
||||
return this.shortName != 0;
|
||||
}
|
||||
|
||||
public char getShortName() {
|
||||
return this.shortName;
|
||||
}
|
||||
}
|
49
java/src/game/command/PatternReplacer.java
Normal file
49
java/src/game/command/PatternReplacer.java
Normal file
|
@ -0,0 +1,49 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.function.Function;
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class PatternReplacer {
|
||||
private final String variable;
|
||||
private final boolean matchAll;
|
||||
private final Pattern pattern;
|
||||
private final Function<String, String> function;
|
||||
|
||||
public PatternReplacer(String variable, boolean matchAll, Function<String, String> function) {
|
||||
this.variable = variable;
|
||||
this.matchAll = matchAll;
|
||||
this.pattern = Pattern.compile("\\$\\((" + variable + (matchAll ? "[^\\)]*" : "") + ")\\)");
|
||||
this.function = function;
|
||||
}
|
||||
|
||||
public void replaceVar(StringBuffer sb) {
|
||||
String str = sb.toString();
|
||||
sb.delete(0, sb.length());
|
||||
Matcher matcher = this.pattern.matcher(str);
|
||||
while(matcher.find()) {
|
||||
String orig = matcher.group(1);
|
||||
String rep = this.function.apply(orig);
|
||||
if(rep == null)
|
||||
throw new ScriptException("Variable '%s' konnte in diesem Kontext nicht ersetzt werden", orig);
|
||||
matcher.appendReplacement(sb, rep);
|
||||
}
|
||||
matcher.appendTail(sb);
|
||||
}
|
||||
|
||||
public String getVariable() {
|
||||
return this.variable;
|
||||
}
|
||||
|
||||
public boolean matchesAll() {
|
||||
return this.matchAll;
|
||||
}
|
||||
|
||||
public Pattern getPattern() {
|
||||
return this.pattern;
|
||||
}
|
||||
|
||||
public Function<String, String> getFunction() {
|
||||
return this.function;
|
||||
}
|
||||
}
|
33
java/src/game/command/ScriptArg.java
Normal file
33
java/src/game/command/ScriptArg.java
Normal file
|
@ -0,0 +1,33 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class ScriptArg {
|
||||
private final Parameter parameter;
|
||||
private final int position;
|
||||
private final String[] inputs;
|
||||
private final Map<String, Object> values;
|
||||
|
||||
public ScriptArg(Parameter parameter, int position, String[] inputs, Map<String, Object> values) {
|
||||
this.parameter = parameter;
|
||||
this.position = position;
|
||||
this.inputs = inputs;
|
||||
this.values = values;
|
||||
}
|
||||
|
||||
public Parameter getParameter() {
|
||||
return this.parameter;
|
||||
}
|
||||
|
||||
public int getPosition() {
|
||||
return this.position;
|
||||
}
|
||||
|
||||
public String[] getInputs() {
|
||||
return this.inputs;
|
||||
}
|
||||
|
||||
public Map<String, Object> getValues() {
|
||||
return this.values;
|
||||
}
|
||||
}
|
311
java/src/game/command/ScriptArgs.java
Normal file
311
java/src/game/command/ScriptArgs.java
Normal file
|
@ -0,0 +1,311 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import game.block.Block;
|
||||
import game.collect.Maps;
|
||||
import game.entity.Entity;
|
||||
import game.entity.npc.EntityNPC;
|
||||
import game.entity.types.EntityLiving;
|
||||
import game.item.Item;
|
||||
import game.item.ItemStack;
|
||||
import game.world.BlockPos;
|
||||
import game.world.State;
|
||||
import game.world.Vec3;
|
||||
import game.world.WorldPos;
|
||||
|
||||
public class ScriptArgs {
|
||||
private final String command;
|
||||
private final Map<String, ScriptArg> arguments;
|
||||
|
||||
protected ScriptArgs(Map<String, ScriptArg> arguments, String command) {
|
||||
this.arguments = arguments;
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
private static <T> String joinArgs(Iterable<T> iter) {
|
||||
StringBuilder sb = new StringBuilder("'");
|
||||
for(T obj : iter) {
|
||||
if(sb.length() > 1)
|
||||
sb.append("', '");
|
||||
sb.append(String.valueOf(obj));
|
||||
}
|
||||
return sb.append("'").toString();
|
||||
}
|
||||
|
||||
public static ScriptArgs parseArgs(ScriptEnvironment env, String str, String[] argv, CachedExecutable cached) {
|
||||
Map<String, Parameter> parameters = cached.getParameters();
|
||||
List<Parameter> positionals = cached.getPositionals();
|
||||
// String[] argv = ArgumentParser.splitString(str);
|
||||
Map<String, ScriptArg> args = Maps.newHashMap();
|
||||
int ppos = 0;
|
||||
boolean parse = true;
|
||||
for(int z = 1; z < argv.length; z++) {
|
||||
String arg = argv[z];
|
||||
Parameter param = null;
|
||||
boolean pos = false;
|
||||
if(parse && arg.equals("--")) {
|
||||
parse = false;
|
||||
continue;
|
||||
}
|
||||
else if(parse && (arg.startsWith("--") || (arg.startsWith("-") && arg.length() == 2))) {
|
||||
param = parameters.get(arg.substring(arg.startsWith("--") ? 2 : 1));
|
||||
if(param != null && param.isPositional() && !args.containsKey(param.getName())) {
|
||||
for(int n = 0; n < positionals.size(); n++) {
|
||||
if(param == positionals.get(n)) {
|
||||
positionals.remove(n);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if(ppos < positionals.size()) {
|
||||
param = positionals.get(ppos++);
|
||||
pos = true;
|
||||
}
|
||||
else {
|
||||
throw new ScriptException("Position %d: Parameter '%s' ist überflüssig", z, arg);
|
||||
}
|
||||
if(param == null)
|
||||
throw new ScriptException("Position %d: Argument '%s' ist unbekannt", z, arg);
|
||||
if(args.containsKey(param.getName()))
|
||||
throw new ScriptException("Position %d: Parameter '%s' mehrfach angegeben", z, param.getName());
|
||||
int nargs = param.getParsers().size();
|
||||
// if(!pos)
|
||||
// z += 1;
|
||||
if(z + (pos ? 0 : 1) + nargs >= argv.length)
|
||||
if(nargs == 1 && param.getName().equals(param.getParsers().get(0).getName()))
|
||||
throw new ScriptException("Position %d: Argument '%s' benötigt einen Parameter", z, param.getName());
|
||||
else
|
||||
throw new ScriptException("Position %d: Argument '%s' benötigt %d Parameter (%s)", z, param.getName(), nargs,
|
||||
joinArgs(param.getParsers()));
|
||||
Map<String, Object> params = Maps.newHashMapWithExpectedSize(nargs);
|
||||
String[] inputs = new String[nargs + (pos ? 0 : 1)];
|
||||
int apos = 0;
|
||||
for(int n = pos ? 0 : 1; n < nargs + (pos ? 0 : 1); n++) {
|
||||
String par = inputs[n] = argv[z + n];
|
||||
ArgumentParser parser = param.getParsers().get(apos);
|
||||
if(parse && (par.startsWith("--") || (par.startsWith("-") && par.length() == 2)))
|
||||
if(nargs == 1 && param.getName().equals(parser.getName()))
|
||||
throw new ScriptException("Position %d: Argument '%s': '%s' als Parameter verwendet", z + n, param.getName(), par);
|
||||
else
|
||||
throw new ScriptException("Position %d: Argument '%s': '%s' als Parameter '%s' (#%d) verwendet", z + n,
|
||||
param.getName(), par, parser.getName(), apos + 1);
|
||||
try {
|
||||
params.put(parser.getName(), parser.parse(env, par));
|
||||
}
|
||||
catch(Throwable e) {
|
||||
if(nargs == 1 && param.getName().equals(parser.getName()))
|
||||
throw new ScriptException(e, "Position %d: Argument '%s': Parameter konnte nicht interpretiert werden", z + n,
|
||||
param.getName());
|
||||
else
|
||||
throw new ScriptException(e, "Position %d: Argument '%s': Parameter '%s' (#%d) konnte nicht interpretiert werden", z + n,
|
||||
param.getName(), parser.getName(), apos + 1);
|
||||
}
|
||||
apos += 1;
|
||||
}
|
||||
if(!pos)
|
||||
inputs[0] = arg;
|
||||
args.put(param.getName(), new ScriptArg(param, z, inputs, params));
|
||||
z += nargs;
|
||||
}
|
||||
for(Parameter param : parameters.values()) {
|
||||
if(!args.containsKey(param.getName())) {
|
||||
if(param.isRequired()) {
|
||||
for(ArgumentParser parser : param.getParsers()) {
|
||||
if(parser.getDefault(env) == null)
|
||||
throw new ScriptException("Argument '%s' muss angegeben werden", param.getName());
|
||||
}
|
||||
}
|
||||
Map<String, Object> params = Maps.newHashMapWithExpectedSize(param.getParsers().size());
|
||||
for(ArgumentParser parser : param.getParsers()) {
|
||||
params.put(parser.getName(), parser.getDefault(env));
|
||||
}
|
||||
args.put(param.getName(), new ScriptArg(param, -1, null, params));
|
||||
}
|
||||
}
|
||||
return new ScriptArgs(args, str);
|
||||
}
|
||||
|
||||
public ScriptArg getArg(String name) {
|
||||
return this.arguments.get(name);
|
||||
}
|
||||
|
||||
public boolean hasArg(String name) {
|
||||
return this.arguments.containsKey(name);
|
||||
}
|
||||
|
||||
protected <T> T getDefault(String name, String par, T def) {
|
||||
ScriptArg arg = this.arguments.get(name);
|
||||
if(arg == null)
|
||||
return def;
|
||||
Object value = arg.getValues().get(par);
|
||||
return value == null ? def : (T)value;
|
||||
}
|
||||
|
||||
protected <T> T getDefault(String name, T def) {
|
||||
return this.getDefault(name, name, def);
|
||||
}
|
||||
|
||||
protected <T> T getUnchecked(String name, String par) {
|
||||
return this.getDefault(name, par, null);
|
||||
}
|
||||
|
||||
protected <T> T getUnchecked(String name) {
|
||||
return this.getDefault(name, null);
|
||||
}
|
||||
|
||||
public boolean getBool(String name, boolean def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public boolean getBool(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public <T extends Enum<?>> T getEnum(String name, T def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public <T extends Enum<?>> T getEnum(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public int getInt(String name, int def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public int getInt(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public long getLong(String name, long def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public long getLong(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public double getDouble(String name, double def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public double getDouble(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public String getString(String name, String def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public String getString(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public String[] getStrings(String name, String[] def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public String[] getStrings(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public Entity getEntity(String name, Entity def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public Entity getEntity(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public EntityLiving getLiving(String name, EntityLiving def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public EntityLiving getLiving(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public EntityNPC getNpc(String name, EntityNPC def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public EntityNPC getNpc(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public Block getBlock(String name, Block def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public Block getBlock(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public State getState(String name, State def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public State getState(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public Item getItem(String name, Item def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public Item getItem(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public ItemStack getStack(String name, ItemStack def) {
|
||||
return this.getDefault(name, def);
|
||||
}
|
||||
|
||||
public ItemStack getStack(String name) {
|
||||
return this.getUnchecked(name);
|
||||
}
|
||||
|
||||
public BlockPos getColumnPos(String name, BlockPos def) {
|
||||
return this.hasArg(name) ? this.getColumnPos(name) : def;
|
||||
}
|
||||
|
||||
public BlockPos getColumnPos(String name) {
|
||||
return new BlockPos(this.getUnchecked(name, "x"), 0, this.getUnchecked(name, "z"));
|
||||
}
|
||||
|
||||
public BlockPos getBlockPos(String name, BlockPos def) {
|
||||
return this.hasArg(name) ? this.getBlockPos(name) : def;
|
||||
}
|
||||
|
||||
public BlockPos getBlockPos(String name) {
|
||||
return new BlockPos(this.getUnchecked(name, "x"), this.getUnchecked(name, "y"), this.getUnchecked(name, "z"));
|
||||
}
|
||||
|
||||
public WorldPos getWorldPos(String name, WorldPos def) {
|
||||
return this.hasArg(name) ? this.getWorldPos(name) : def;
|
||||
}
|
||||
|
||||
public WorldPos getWorldPos(String name) {
|
||||
return new WorldPos(this.getUnchecked(name, "x"), this.getUnchecked(name, "y"), this.getUnchecked(name, "z"),
|
||||
this.getUnchecked(name, "dim"));
|
||||
}
|
||||
|
||||
public Vec3 getVector2D(String name, Vec3 def) {
|
||||
return this.hasArg(name) ? this.getVector2D(name) : def;
|
||||
}
|
||||
|
||||
public Vec3 getVector2D(String name) {
|
||||
return new Vec3(this.getUnchecked(name, "x"), 0.0, this.getUnchecked(name, "z"));
|
||||
}
|
||||
|
||||
public Vec3 getVector(String name, Vec3 def) {
|
||||
return this.hasArg(name) ? this.getVector(name) : def;
|
||||
}
|
||||
|
||||
public Vec3 getVector(String name) {
|
||||
return new Vec3(this.getUnchecked(name, "x"), this.getUnchecked(name, "y"), this.getUnchecked(name, "z"));
|
||||
}
|
||||
}
|
130
java/src/game/command/ScriptEnvironment.java
Normal file
130
java/src/game/command/ScriptEnvironment.java
Normal file
|
@ -0,0 +1,130 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.Function;
|
||||
|
||||
import game.Server;
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
import game.color.TextColor;
|
||||
|
||||
public class ScriptEnvironment {
|
||||
private final Server server;
|
||||
private final Map<String, CachedExecutable> executables = Maps.newTreeMap();
|
||||
private final List<PatternReplacer> replacers = Lists.newArrayList();
|
||||
|
||||
private ScriptExecutor currentExecutor;
|
||||
private Object previousOutput;
|
||||
|
||||
public ScriptEnvironment(Server server) {
|
||||
this.server = server;
|
||||
}
|
||||
|
||||
public void registerExecutable(Executable executable) {
|
||||
CachedExecutable cached = CachedExecutable.cacheExecutable(executable);
|
||||
this.executables.put(cached.getName(), cached);
|
||||
this.registerReplacer(cached.getName(), new Function<String, String>() {
|
||||
public String apply(String str) {
|
||||
Object o;
|
||||
try {
|
||||
o = ScriptEnvironment.this.execute(str, false);
|
||||
}
|
||||
catch(Throwable e) {
|
||||
throw new ScriptException(e, "Variable konnte nicht ersetzt werden: '%s' konnte nicht ausgeführt werden", str);
|
||||
}
|
||||
if(o == null)
|
||||
throw new ScriptException("Variable konnte nicht ersetzt werden: null von '%s' zurückgegeben", str);
|
||||
return o.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void registerReplacer(String var, Function<String, String> function) {
|
||||
this.replacers.add(new PatternReplacer(var, true, function));
|
||||
}
|
||||
|
||||
public void registerVariable(String var, Variable variable) {
|
||||
this.replacers.add(new PatternReplacer(var, false, new Function<String, String>() {
|
||||
public String apply(String ign) {
|
||||
return variable.get();
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
public Server getServer() {
|
||||
return this.server;
|
||||
}
|
||||
|
||||
public ScriptExecutor getExecutor() {
|
||||
return this.currentExecutor;
|
||||
}
|
||||
|
||||
private String substitute(String str) {
|
||||
StringBuffer sb = new StringBuffer(str);
|
||||
for(PatternReplacer replacer : this.replacers) {
|
||||
replacer.replaceVar(sb);
|
||||
}
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
private Object execute(String cmd, boolean setPrev) {
|
||||
String line = this.substitute(cmd);
|
||||
String[][] cmds = ArgumentParser.splitString(line);
|
||||
Object o = null;
|
||||
for(String[] argv : cmds) {
|
||||
CachedExecutable cached = this.executables.get(argv[0]);
|
||||
if(cached == null)
|
||||
throw new ScriptException("Skript '%s' existiert nicht", argv[0]);
|
||||
ScriptArgs args = ScriptArgs.parseArgs(this, cmd, argv, cached);
|
||||
o = cached.getExecutable().exec(this, args);
|
||||
if(setPrev)
|
||||
this.previousOutput = o;
|
||||
}
|
||||
return o;
|
||||
}
|
||||
|
||||
public void execute(String cmd, ScriptExecutor exec) {
|
||||
this.currentExecutor = exec;
|
||||
try {
|
||||
this.execute(cmd, true);
|
||||
}
|
||||
catch(ScriptException e) {
|
||||
Throwable cause = e;
|
||||
do {
|
||||
exec.logConsole(TextColor.RED + cause.getMessage());
|
||||
cause = cause.getCause();
|
||||
}
|
||||
while(cause != null);
|
||||
}
|
||||
catch(Throwable t) {
|
||||
exec.logConsole(TextColor.RED + "Fehler: %s", t.getMessage());
|
||||
}
|
||||
finally {
|
||||
this.currentExecutor = null;
|
||||
this.previousOutput = null;
|
||||
}
|
||||
}
|
||||
|
||||
public void complete(String cmd, ScriptExecutor exec) {
|
||||
|
||||
}
|
||||
|
||||
public void registerDefaults() {
|
||||
this.registerVariable("id", new Variable() {
|
||||
public String get() {
|
||||
return ScriptEnvironment.this.currentExecutor.getExecId();
|
||||
}
|
||||
});
|
||||
this.registerVariable("name", new Variable() {
|
||||
public String get() {
|
||||
return ScriptEnvironment.this.currentExecutor.getExecName();
|
||||
}
|
||||
});
|
||||
this.registerVariable("chain", new Variable() {
|
||||
public String get() {
|
||||
return ScriptEnvironment.this.previousOutput == null ? null : ScriptEnvironment.this.previousOutput.toString();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
28
java/src/game/command/ScriptException.java
Normal file
28
java/src/game/command/ScriptException.java
Normal file
|
@ -0,0 +1,28 @@
|
|||
package game.command;
|
||||
|
||||
public class ScriptException extends RuntimeException {
|
||||
public ScriptException(String desc) {
|
||||
super(desc);
|
||||
this.setStackTrace(new StackTraceElement[0]);
|
||||
}
|
||||
|
||||
public ScriptException(String fmt, Object ... args) {
|
||||
super(String.format(fmt, args));
|
||||
this.setStackTrace(new StackTraceElement[0]);
|
||||
}
|
||||
|
||||
public ScriptException(Throwable cause, String desc) {
|
||||
super(desc, cause);
|
||||
this.setStackTrace(new StackTraceElement[0]);
|
||||
}
|
||||
|
||||
public ScriptException(Throwable cause, String fmt, Object ... args) {
|
||||
super(String.format(fmt, args), cause);
|
||||
this.setStackTrace(new StackTraceElement[0]);
|
||||
}
|
||||
|
||||
public synchronized Throwable fillInStackTrace() {
|
||||
this.setStackTrace(new StackTraceElement[0]);
|
||||
return this;
|
||||
}
|
||||
}
|
45
java/src/game/command/ScriptExecutable.java
Normal file
45
java/src/game/command/ScriptExecutable.java
Normal file
|
@ -0,0 +1,45 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
import game.collect.Lists;
|
||||
import game.collect.Maps;
|
||||
|
||||
public abstract class ScriptExecutable implements Executable {
|
||||
private final String name;
|
||||
private final Map<String, Parameter> parameters = Maps.newHashMap();
|
||||
|
||||
private int parPos = 0;
|
||||
private boolean parReq = true;
|
||||
|
||||
protected ScriptExecutable(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
protected ScriptExecutable setParamsOptional() {
|
||||
this.parReq = false;
|
||||
return this;
|
||||
}
|
||||
|
||||
protected ScriptExecutable addParameter(String name, ArgumentParser ... parsers) {
|
||||
this.parameters.put(name, new Parameter(name, (char)0, this.parPos++, this.parReq, Lists.newArrayList(parsers)));
|
||||
return this;
|
||||
}
|
||||
|
||||
protected ScriptExecutable addParameter(String name, char shortName, ArgumentParser ... parsers) {
|
||||
this.parameters.put(name, new Parameter(name, shortName, -1, false, Lists.newArrayList(parsers)));
|
||||
return this;
|
||||
}
|
||||
|
||||
public Object exec(ScriptEnvironment env, ScriptArgs args) {
|
||||
return null;
|
||||
}
|
||||
|
||||
public Map<String, Parameter> getParameters() {
|
||||
return this.parameters;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
11
java/src/game/command/ScriptExecutor.java
Normal file
11
java/src/game/command/ScriptExecutor.java
Normal file
|
@ -0,0 +1,11 @@
|
|||
package game.command;
|
||||
|
||||
public interface ScriptExecutor {
|
||||
void logConsole(String msg);
|
||||
String getExecId();
|
||||
String getExecName();
|
||||
|
||||
default void logConsole(String fmt, Object ... args) {
|
||||
this.logConsole(String.format(fmt, args));
|
||||
}
|
||||
}
|
39
java/src/game/command/StringParser.java
Normal file
39
java/src/game/command/StringParser.java
Normal file
|
@ -0,0 +1,39 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class StringParser extends DefaultingParser {
|
||||
private final boolean allowEmpty;
|
||||
private final Integer minLength;
|
||||
private final Integer maxLength;
|
||||
private final Predicate<Character> validator;
|
||||
|
||||
public StringParser(String name, String def, boolean allowEmpty, Integer minLength, Integer maxLength, Predicate<Character> validator,
|
||||
Object ... completions) {
|
||||
super(name, def, completions);
|
||||
this.allowEmpty = allowEmpty;
|
||||
this.minLength = minLength;
|
||||
this.maxLength = maxLength;
|
||||
this.validator = validator;
|
||||
}
|
||||
|
||||
public String parse(ScriptEnvironment env, String input) {
|
||||
if(!this.allowEmpty && input.isEmpty())
|
||||
throw new ScriptException("Die Zeichenkette darf nicht leer sein");
|
||||
if(this.minLength != null && input.length() < this.minLength)
|
||||
if(this.maxLength != null)
|
||||
throw new ScriptException("Die Zeichenkette muss zwischen %d .. %d Zeichen lang sein, habe %d ('%s')",
|
||||
this.minLength, this.maxLength, input.length(), input);
|
||||
else
|
||||
throw new ScriptException("Die Zeichenkette muss mindestens %d Zeichen lang sein, habe %d ('%s')",
|
||||
this.minLength, input.length(), input);
|
||||
if(this.maxLength != null && input.length() > this.maxLength)
|
||||
if(this.minLength != null)
|
||||
throw new ScriptException("Die Zeichenkette muss zwischen %d .. %d Zeichen lang sein, habe %d ('%s')",
|
||||
this.minLength, this.maxLength, input.length(), input);
|
||||
else
|
||||
throw new ScriptException("Die Zeichenkette darf höchstens %d Zeichen lang sein, habe %d ('%s')",
|
||||
this.maxLength, input.length(), input);
|
||||
return input;
|
||||
}
|
||||
}
|
5
java/src/game/command/Variable.java
Normal file
5
java/src/game/command/Variable.java
Normal file
|
@ -0,0 +1,5 @@
|
|||
package game.command;
|
||||
|
||||
public interface Variable {
|
||||
public String get();
|
||||
}
|
38
java/src/game/command/WorldParser.java
Normal file
38
java/src/game/command/WorldParser.java
Normal file
|
@ -0,0 +1,38 @@
|
|||
package game.command;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
import game.Server;
|
||||
import game.collect.Lists;
|
||||
import game.dimension.Dimension;
|
||||
import game.world.WorldServer;
|
||||
|
||||
public class WorldParser extends DimensionParser {
|
||||
private final boolean loadedOnly;
|
||||
private final Server server;
|
||||
|
||||
public WorldParser(String name, Server server, boolean loadedOnly) {
|
||||
super(name);
|
||||
this.server = server;
|
||||
this.loadedOnly = loadedOnly;
|
||||
}
|
||||
|
||||
public WorldServer parse(ScriptEnvironment env, String input) {
|
||||
Dimension dim = (Dimension)super.parse(env, input);
|
||||
WorldServer world = this.loadedOnly ? this.server.getWorldNoLoad(dim.getDimensionId()) : this.server.getWorld(dim.getDimensionId());
|
||||
if(world == null)
|
||||
throw new ScriptException("Dimension '%s' ist nicht geladen", dim.getFormattedName(false));
|
||||
return world;
|
||||
}
|
||||
|
||||
public String[] getCompletions(ScriptEnvironment env) {
|
||||
if(this.loadedOnly) {
|
||||
List<String> loaded = Lists.newArrayList();
|
||||
for(WorldServer world : this.server.getWorlds()) {
|
||||
loaded.add(world.dimension.getDimensionName());
|
||||
}
|
||||
return loaded.toArray(new String[loaded.size()]);
|
||||
}
|
||||
return super.getCompletions(env);
|
||||
}
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue