280 lines
9.3 KiB
Java
280 lines
9.3 KiB
Java
package server.command;
|
|
|
|
import java.lang.reflect.Array;
|
|
import java.lang.reflect.InvocationTargetException;
|
|
import java.util.List;
|
|
import java.util.Map;
|
|
import java.util.Set;
|
|
import java.util.function.Function;
|
|
import java.util.regex.Pattern;
|
|
|
|
import common.collect.Lists;
|
|
import common.collect.Maps;
|
|
import common.collect.Sets;
|
|
import common.color.TextColor;
|
|
import common.log.Log;
|
|
import server.Server;
|
|
import server.command.commands.*;
|
|
|
|
public class CommandEnvironment {
|
|
private final Server server;
|
|
private final Map<String, CachedExecutable> executables = Maps.newTreeMap();
|
|
private final List<PatternReplacer> replacers = Lists.newArrayList();
|
|
private final Set<String> builtins = Sets.newHashSet();
|
|
private final Map<String, String> variables = Maps.newHashMap();
|
|
|
|
private Executor currentExecutor;
|
|
private Object previousOutput;
|
|
|
|
public CommandEnvironment(Server server) {
|
|
this.server = server;
|
|
this.registerDefaults();
|
|
}
|
|
|
|
public void registerExecutable(Executable executable) {
|
|
CachedExecutable cached = CachedExecutable.cacheExecutable(executable);
|
|
if(this.executables.containsKey(cached.name()))
|
|
throw new IllegalStateException("Befehl " + cached.name() + " ist bereits registriert");
|
|
this.executables.put(cached.name(), cached);
|
|
this.registerReplacer(cached.name(), new Function<String, String>() {
|
|
public String apply(String str) {
|
|
Object o;
|
|
try {
|
|
o = CommandEnvironment.this.execute(str, false);
|
|
}
|
|
catch(Throwable e) {
|
|
throw new RunException(e, "Variable konnte nicht ersetzt werden: '%s' konnte nicht ausgeführt werden", str);
|
|
}
|
|
if(o == null)
|
|
throw new RunException("Variable konnte nicht ersetzt werden: null von '%s' zurückgegeben", str);
|
|
return o.toString();
|
|
}
|
|
});
|
|
}
|
|
|
|
public void registerReplacer(String var, Function<String, String> function) {
|
|
if(this.builtins.contains(var))
|
|
throw new IllegalStateException("Variable " + var + " ist bereits registriert");
|
|
this.replacers.add(new PatternReplacer(Pattern.compile("\\$\\((" + Pattern.quote(var) + "[^\\)]*)\\)"), function));
|
|
this.builtins.add(var);
|
|
}
|
|
|
|
public void registerVariable(String var, Variable variable) {
|
|
if(this.builtins.contains(var))
|
|
throw new IllegalStateException("Variable " + var + " ist bereits registriert");
|
|
this.replacers.add(new PatternReplacer(Pattern.compile("\\$\\((" + Pattern.quote(var) + ")\\)"), new Function<String, String>() {
|
|
public String apply(String ign) {
|
|
return variable.get();
|
|
}
|
|
}));
|
|
this.builtins.add(var);
|
|
}
|
|
|
|
public Server getServer() {
|
|
return this.server;
|
|
}
|
|
|
|
public Map<String, CachedExecutable> getExecutables() {
|
|
return this.executables;
|
|
}
|
|
|
|
public Executor getExecutor() {
|
|
return this.currentExecutor;
|
|
}
|
|
|
|
private String substitute(String str) {
|
|
StringBuffer sb = new StringBuffer(str);
|
|
for(PatternReplacer replacer : this.replacers) {
|
|
replacer.replace(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) {
|
|
String exec = argv[0];
|
|
String var = null;
|
|
int eq = exec.indexOf('=');
|
|
if(eq >= 0) {
|
|
var = exec.substring(0, eq);
|
|
exec = exec.substring(eq + 1);
|
|
}
|
|
CachedExecutable cached = this.executables.get(exec);
|
|
if(cached == null)
|
|
throw new RunException("Befehl '%s' existiert nicht", exec);
|
|
for(int z = 0; z < argv.length; z++) {
|
|
String arg = argv[z];
|
|
if(arg.startsWith("$(") && arg.endsWith(")")) {
|
|
String resolve = this.variables.get(arg.substring(2, arg.length() - 1));
|
|
if(resolve != null)
|
|
argv[z] = resolve;
|
|
}
|
|
}
|
|
ArgumentSplitter args = ArgumentSplitter.parseArgs(this, cmd, argv, cached);
|
|
List<Object> params = Lists.newArrayList(this, this.currentExecutor);
|
|
for(Parameter param : cached.executable().getParamList()) {
|
|
ArgCombiner combiner = param.combiner();
|
|
if(combiner != null) {
|
|
Object[] data = (Object[])Array.newInstance(combiner.getInputClass(), param.parsers().size());
|
|
for(int z = 0; z < data.length; z++) {
|
|
data[z] = args.get(param.name(), param.parsers().get(z).getName());
|
|
if(data[z] == null) {
|
|
data = null;
|
|
break;
|
|
}
|
|
}
|
|
params.add(data == null ? null : combiner.combine(data));
|
|
continue;
|
|
}
|
|
if(param.parsers().isEmpty()) {
|
|
params.add(args.has(param.name()));
|
|
continue;
|
|
}
|
|
for(ArgumentParser parser : param.parsers()) {
|
|
params.add(args.get(param.name(), parser.getName()));
|
|
}
|
|
}
|
|
try {
|
|
o = cached.method().invoke(cached.executable(), params.toArray(new Object[params.size()]));
|
|
}
|
|
catch(InvocationTargetException e) {
|
|
if(e.getCause() instanceof RuntimeException)
|
|
throw ((RuntimeException)e.getCause());
|
|
else
|
|
throw new RuntimeException(e.getCause());
|
|
}
|
|
catch(IllegalAccessException | IllegalArgumentException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
// o = cached.getExecutable().exec(this, args);
|
|
if(setPrev)
|
|
this.previousOutput = o;
|
|
if(var != null && !var.isEmpty() && !this.builtins.contains(var)) {
|
|
if(o != null)
|
|
this.variables.put(var, String.valueOf(o));
|
|
else
|
|
this.variables.remove(var);
|
|
}
|
|
}
|
|
return o;
|
|
}
|
|
|
|
public void execute(String cmd, Executor exec) {
|
|
Executor prev = this.currentExecutor;
|
|
this.currentExecutor = exec;
|
|
try {
|
|
this.execute(cmd, true);
|
|
}
|
|
catch(RunException e) {
|
|
Throwable cause = e;
|
|
do {
|
|
exec.log(TextColor.RED + cause.getMessage());
|
|
cause = cause.getCause();
|
|
}
|
|
while(cause != null);
|
|
}
|
|
catch(Throwable t) {
|
|
exec.log(TextColor.RED + "Fehler: %s", t.getMessage());
|
|
Log.CONSOLE.error(t, "Fehler beim Ausführen von Befehl '%s'", cmd);
|
|
}
|
|
finally {
|
|
this.currentExecutor = prev;
|
|
this.previousOutput = null;
|
|
this.variables.clear();
|
|
}
|
|
}
|
|
|
|
public List<String> complete(String cmd, Executor exec) {
|
|
this.currentExecutor = exec;
|
|
List<String> list = Lists.newArrayList();
|
|
try {
|
|
String[][] cmds = ArgumentParser.splitString(cmd.endsWith(" ") ? cmd + "END" : cmd);
|
|
Iterable<String> comp = this.executables.keySet();
|
|
String param = cmd;
|
|
if(cmds.length > 0 && cmds[cmds.length - 1].length > 0) {
|
|
String[] argv = cmds[cmds.length - 1];
|
|
param = cmd.endsWith(" ") ? "" : argv[argv.length - 1];
|
|
if(argv.length > 1) {
|
|
int eq = argv[0].indexOf('=');
|
|
CachedExecutable cached = this.executables.get(eq >= 0 ? argv[0].substring(eq + 1) : argv[0]);
|
|
if(cached == null)
|
|
return list;
|
|
comp = ArgumentSplitter.parseComplete(this, argv, cached, param);
|
|
}
|
|
}
|
|
for(String cmp : comp) {
|
|
if(cmp.regionMatches(true, 0, param, 0, param.length()))
|
|
list.add(cmp);
|
|
}
|
|
}
|
|
catch(Throwable t) {
|
|
list.clear();
|
|
if(!(t instanceof RunException))
|
|
Log.CONSOLE.error(t, "Konnte Befehl '%s' nicht vervollständigen", cmd);
|
|
}
|
|
finally {
|
|
this.currentExecutor = null;
|
|
}
|
|
return list;
|
|
}
|
|
|
|
public void registerDefaults() {
|
|
this.registerVariable("!", new Variable() {
|
|
public String get() {
|
|
return CommandEnvironment.this.previousOutput == null ? null : CommandEnvironment.this.previousOutput.toString();
|
|
}
|
|
});
|
|
|
|
this.registerExecutable(new CommandHelp());
|
|
this.registerExecutable(new CommandSpawn());
|
|
this.registerExecutable(new CommandPotion());
|
|
this.registerExecutable(new CommandMilk());
|
|
this.registerExecutable(new CommandAdmin());
|
|
this.registerExecutable(new CommandRevoke());
|
|
this.registerExecutable(new CommandTp());
|
|
this.registerExecutable(new CommandTele());
|
|
this.registerExecutable(new CommandWorld());
|
|
this.registerExecutable(new CommandOfflinetp());
|
|
this.registerExecutable(new CommandWarp());
|
|
this.registerExecutable(new CommandTime());
|
|
this.registerExecutable(new CommandRemove());
|
|
this.registerExecutable(new CommandWeather());
|
|
this.registerExecutable(new CommandKick());
|
|
this.registerExecutable(new CommandMessage());
|
|
this.registerExecutable(new CommandShutdown());
|
|
this.registerExecutable(new CommandPasswd());
|
|
this.registerExecutable(new CommandPubkey());
|
|
this.registerExecutable(new CommandPlayers());
|
|
this.registerExecutable(new CommandUsers());
|
|
this.registerExecutable(new CommandSave());
|
|
this.registerExecutable(new CommandRegister());
|
|
this.registerExecutable(new CommandRegkey());
|
|
this.registerExecutable(new CommandFind());
|
|
this.registerExecutable(new CommandBlock());
|
|
this.registerExecutable(new CommandSeed());
|
|
this.registerExecutable(new CommandSv());
|
|
this.registerExecutable(new CommandClear());
|
|
this.registerExecutable(new CommandEntity());
|
|
this.registerExecutable(new CommandItem());
|
|
this.registerExecutable(new CommandRunat());
|
|
this.registerExecutable(new CommandRunas());
|
|
this.registerExecutable(new CommandExp());
|
|
this.registerExecutable(new CommandMagic());
|
|
this.registerExecutable(new CommandGod());
|
|
this.registerExecutable(new CommandNoclip());
|
|
this.registerExecutable(new CommandRename());
|
|
this.registerExecutable(new CommandRepair());
|
|
this.registerExecutable(new CommandMore());
|
|
this.registerExecutable(new CommandReturn());
|
|
this.registerExecutable(new CommandDeathspot());
|
|
this.registerExecutable(new CommandLoad());
|
|
this.registerExecutable(new CommandWarps());
|
|
this.registerExecutable(new CommandSetwarp());
|
|
this.registerExecutable(new CommandDelwarp());
|
|
this.registerExecutable(new CommandShowwarp());
|
|
this.registerExecutable(new CommandTphere());
|
|
}
|
|
}
|