initial commit

This commit is contained in:
Sen 2025-03-11 00:23:54 +01:00 committed by Sen
parent 3c9ee26b06
commit 22186c33b9
1458 changed files with 282792 additions and 0 deletions

View 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;
}
}

View file

@ -0,0 +1,7 @@
package game.command;
public class BooleanParser extends EnumParser {
public BooleanParser(String name, Boolean def) {
super(name, def, true, false);
}
}

View 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;
}
}

View 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);
}
}

View 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);
}

View 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;
}
}

View 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;
}
}

View 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()]);
}
}

View 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;
}
}

View 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];
}
}

View 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();
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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;
}
}

View 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"));
}
}

View 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();
}
});
}
}

View 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;
}
}

View 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;
}
}

View 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));
}
}

View 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;
}
}

View file

@ -0,0 +1,5 @@
package game.command;
public interface Variable {
public String get();
}

View 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);
}
}