fix command system a bit

This commit is contained in:
Sen 2025-05-31 14:02:55 +02:00
parent 35277daca8
commit f4c024cde7
Signed by: sen
GPG key ID: 3AC50A6F47D1B722
29 changed files with 318 additions and 269 deletions

View file

@ -19,7 +19,6 @@ import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Queue;
import java.util.Map.Entry;
import java.util.concurrent.Callable;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executors;
@ -42,7 +41,6 @@ import common.init.Config;
import common.init.EntityRegistry;
import common.init.Registry;
import common.init.UniverseRegistry;
import common.init.Config.ValueType;
import common.log.Log;
import common.net.bootstrap.ServerBootstrap;
import common.net.channel.Channel;
@ -95,7 +93,6 @@ import server.biome.GenBiome;
import server.clipboard.ReorderRegistry;
import server.clipboard.RotationRegistry;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.FixedExecutor;
import server.network.HandshakeHandler;
import server.network.Player;
@ -374,94 +371,6 @@ public final class Server implements IThreadListener {
}
}
public boolean setVar(Executor exec, String line) {
if(line.length() < 1) {
for(Entry<String, Config.Value> entry : Config.VARS.entrySet()) {
Config.Value cvar = entry.getValue();
String v = cvar.getValue();
String comp = TextColor.YELLOW + entry.getKey() + TextColor.GRAY + " = ";
if(cvar.noDef && cvar.def.equals(v))
comp += TextColor.DGRAY + "[ - ]";
else if(entry.getKey().equals("password") && !v.isEmpty())
comp += TextColor.NEON + "'****'";
else if(cvar.type == ValueType.STRING)
comp += TextColor.NEON + "'" + v + "'";
else
comp += ((cvar.type == ValueType.BOOLEAN ? (v.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + v;
if(!cvar.def.equals(v)) {
comp += TextColor.GRAY + " (" + (cvar.noDef ? TextColor.DGRAY + "[ - ]" : TextColor.BROWN + cvar.def) + TextColor.GRAY + ")";
}
exec.logConsole(comp);
}
exec.logConsole(TextColor.GREEN + "SVARs insgesamt registriert: %d", Config.VARS.size());
return true;
}
line = line.trim();
String[] args = /* line.isEmpty() ? new String[0] : */ line.split(" ", -1);
if(args.length == 1) {
// case 0:
// break;
// case 1:
Config.Value cfg = Config.VARS.get(args[0]);
if(cfg == null)
return false;
String v = cfg.getValue();
String comp = TextColor.YELLOW + args[0] + TextColor.GRAY + " = ";
if(cfg.noDef && cfg.def.equals(v))
comp += TextColor.DGRAY + "[ - ]";
else if(cfg.type == ValueType.STRING)
comp += TextColor.NEON + "'" + v + "'";
else
comp += ((cfg.type == ValueType.BOOLEAN ? (v.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + v;
if(!cfg.def.equals(v))
comp += TextColor.GRAY + " (" + (cfg.noDef ? TextColor.DGRAY + "[ - ]" : TextColor.BROWN + cfg.def) + TextColor.GRAY + ")";
exec.logConsole(comp);
// break;
// default:
}
else {
Config.Value cv = Config.VARS.get(args[0]);
if(cv == null)
return false;
String value = args[1];
if(cv.type == ValueType.STRING && "\"\"".equals(value)) {
value = "";
}
// else if(cv.type == ValueType.BOOLEAN && "toggle".equalsIgnoreCase(value)) {
// value = "" + !Boolean.parseBoolean(cv.getValue());
// }
// else
if(cv.type == ValueType.BOOLEAN && !"true".equals(value) && !"false".equals(value)) {
if(!value.equalsIgnoreCase("true") && !value.equalsIgnoreCase("false")) {
exec.logConsole(TextColor.DRED + "'%s' ist nicht 'true' oder 'false'", value);
return true;
}
value = value.toLowerCase();
}
if(cv.type == ValueType.INTEGER) {
try {
Integer.parseInt(value);
}
catch(NumberFormatException e) {
exec.logConsole(TextColor.DRED + "'%s' ist keine gültige Zahl", value);
return true;
}
}
else if(cv.type == ValueType.FLOAT) {
try {
Float.parseFloat(value);
}
catch(NumberFormatException e) {
exec.logConsole(TextColor.DRED + "'%s' ist keine gültige Zahl", value);
return true;
}
}
Config.set(args[0], value, true);
exec.logConsole(TextColor.YELLOW + "%s" + TextColor.GRAY + " -> " + (cv.noDef && cv.def.equals(cv.getValue()) ? TextColor.DGRAY + "[ - ]" : ((cv.type == ValueType.BOOLEAN ? (cv.getValue().equals("true") ? TextColor.GREEN : TextColor.RED) : (cv.type == ValueType.STRING ? TextColor.NEON : TextColor.BLUE))) + "%s"), args[0], cv.type == ValueType.STRING ? ("'" + cv.getValue() + "'") : cv.getValue());
}
return true;
}
public void run(long time) {
if(!this.debug) {
Converter.convert();
@ -527,9 +436,9 @@ public final class Server implements IThreadListener {
if(Config.port >= 0)
this.bind(Config.port);
else
Log.SYSTEM.warn("Kein Port definiert, verwende 'port <1024-32767>' um einen Hosting-Port festzulegen");
Log.SYSTEM.warn("Kein Port definiert, verwende 'sv port <1024-32767>' um einen Hosting-Port festzulegen");
if(Config.accessRequired && Config.password.length() < 8)
Log.SYSTEM.warn("Kein Passwort definiert, verwende 'password <8-" + IPlayer.MAX_PASS_LENGTH + " Zeichen>' um ein Zugangspasswort festzulegen");
Log.SYSTEM.warn("Kein Passwort definiert, verwende 'sv password <8-" + IPlayer.MAX_PASS_LENGTH + " Zeichen>' um ein Zugangspasswort festzulegen");
Thread con = new Thread(new Runnable() {
private final BufferedReader reader = new BufferedReader(new InputStreamReader(new BufferedInputStream(System.in)));
@ -547,9 +456,7 @@ public final class Server implements IThreadListener {
final String cmd = line;
Server.this.schedule(new Runnable() {
public void run() {
FixedExecutor exec = new FixedExecutor(Server.this, "#con", "KONSOLE", null);
if(!Server.this.setVar(exec, cmd))
Server.this.scriptEnv.execute(cmd, exec);
Server.this.scriptEnv.execute(cmd, new FixedExecutor(Server.this, "#con", "KONSOLE", null));
}
});
}

View file

@ -8,17 +8,7 @@ import common.collect.Lists;
import common.collect.Maps;
import common.collect.Sets;
public class ArgumentSplitter {
private final String command;
private final Map<String, Argument> arguments;
private final CommandEnvironment env;
protected ArgumentSplitter(Map<String, Argument> arguments, String command, CommandEnvironment env) {
this.arguments = arguments;
this.command = command;
this.env = env;
}
public record ArgumentSplitter(Map<String, Argument> arguments, String command, CommandEnvironment env) {
private static <T> String joinArgs(Iterable<T> iter) {
StringBuilder sb = new StringBuilder("'");
for(T obj : iter) {
@ -30,13 +20,15 @@ public class ArgumentSplitter {
}
public static ArgumentSplitter parseArgs(CommandEnvironment env, String str, String[] argv, CachedExecutable cached) {
boolean lenient = str == null;
Map<String, Parameter> parameters = cached.parameters();
List<Parameter> positionals = Lists.newArrayList(cached.positionals());
// String[] argv = ArgumentParser.splitString(str);
Map<String, Argument> args = Maps.newHashMap();
int ppos = 0;
boolean parse = true;
for(int z = 1; z < argv.length; z++) {
int length = lenient ? argv.length - 1 : argv.length;
for(int z = 1; z < length; z++) {
String arg = argv[z];
Parameter param = null;
boolean pos = false;
@ -69,8 +61,10 @@ public class ArgumentSplitter {
int nargs = param.parsers().size();
// if(!pos)
// z += 1;
if(z + (pos ? 0 : 1) + nargs > argv.length)
if(nargs == 1 && param.name().equals(param.parsers().get(0).getName()))
if(z + (pos ? 0 : 1) + nargs > length)
if(lenient)
return new ArgumentSplitter(args, str, env);
else if(nargs == 1 && param.name().equals(param.parsers().get(0).getName()))
throw new RunException("Position %d: Argument '%s' benötigt einen Parameter", z, param.name());
else
throw new RunException("Position %d: Argument '%s' benötigt %d Parameter (%s)", z, param.name(), nargs,
@ -105,6 +99,8 @@ public class ArgumentSplitter {
args.put(param.name(), new Argument(param, z, inputs, params));
z += nargs - (pos ? 1 : 0);
}
if(lenient)
return new ArgumentSplitter(args, str, env);
for(Parameter param : parameters.values()) {
if(!args.containsKey(param.name())) {
if(param.neededIn(env))
@ -121,10 +117,18 @@ public class ArgumentSplitter {
return new ArgumentSplitter(args, str, env);
}
private static Iterable<String> getParam(CommandEnvironment env, String[] argv, CachedExecutable cached) {
private static Iterable<String> getParam(CommandEnvironment env, String[] argv, CachedExecutable cached, String last) {
ArgumentSplitter parsed;
try {
parsed = parseArgs(env, null, argv, cached);
}
catch(Throwable t) {
parsed = new ArgumentSplitter(Maps.newHashMap(), null, env);
}
Map<String, Parameter> parameters = cached.parameters();
List<Parameter> positionals = Lists.newArrayList(cached.positionals());
Set<String> args = Sets.newHashSet();
Executable exec = cached.executable();
int ppos = 0;
boolean parse = true;
for(int z = 1; z < argv.length; z++) {
@ -136,7 +140,8 @@ public class ArgumentSplitter {
param = positionals.get(ppos);
if(param.parsers().isEmpty()) // np
return null;
return param.parsers().get(0).getCompletions(env);
Iterable<String> custom = exec.getCustomCompletions(env, env.getExecutor(), parsed, param.name(), param.parsers().get(0).getName(), last);
return custom != null ? custom : param.parsers().get(0).getCompletions(env);
}
else {
return null;
@ -172,8 +177,10 @@ public class ArgumentSplitter {
// }
int apos = 0;
for(int n = pos ? 0 : 1; n < nargs + (pos ? 0 : 1); n++) {
if(z + n == argv.length - 1)
return param.parsers().get(apos).getCompletions(env);
if(z + n == argv.length - 1) {
Iterable<String> custom = exec.getCustomCompletions(env, env.getExecutor(), parsed, param.name(), param.parsers().get(apos).getName(), last);
return custom != null ? custom : param.parsers().get(apos).getCompletions(env);
}
String par = argv[z + n];
if(parse && (par.startsWith("--") || (par.startsWith("-") && par.length() == 2)))
return null;
@ -186,7 +193,7 @@ public class ArgumentSplitter {
}
public static Iterable<String> parseComplete(CommandEnvironment env, String[] argv, CachedExecutable cached, String last) {
Iterable<String> comp = getParam(env, argv, cached);
Iterable<String> comp = getParam(env, argv, cached, last);
if(comp == null /* || comp.length == 0 */ ) {
Set<String> params = Sets.newTreeSet();
boolean all = last.startsWith("--");
@ -210,4 +217,8 @@ public class ArgumentSplitter {
Object value = arg.values().get(par);
return value == null ? null : (T)value;
}
public <T> T get(String name) {
return this.get(name, name);
}
}

View file

@ -180,40 +180,40 @@ public abstract class Command implements Executable {
return this.addParameter(shortName, new TagParser(name, null));
}
protected Command addUser(String name, boolean defaulted) {
return this.addParameter(new UserParser(name, defaulted));
protected Command addUser(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new UserParser(name, defaulted, policy));
}
protected Command addPlayer(String name, boolean defaulted) {
return this.addParameter(new PlayerParser(name, defaulted));
protected Command addPlayer(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new PlayerParser(name, defaulted, policy));
}
protected Command addPlayerEntity(String name, boolean defaulted) {
return this.addParameter(new PlayerEntityParser(name, defaulted));
protected Command addPlayerEntity(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new PlayerEntityParser(name, defaulted, policy));
}
protected Command addEntity(String name, boolean defaulted) {
return this.addParameter(new EntityParser(name, defaulted, false));
protected Command addEntity(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new EntityParser(name, defaulted, false, policy));
}
protected Command addEntity(String name, char shortName, boolean defaulted) {
return this.addParameter(shortName, new EntityParser(name, defaulted, false));
protected Command addEntity(String name, char shortName, boolean defaulted, UserPolicy policy) {
return this.addParameter(shortName, new EntityParser(name, defaulted, false, policy));
}
protected Command addEntityList(String name, boolean defaulted) {
return this.addParameter(new EntityListParser(name, defaulted, false));
protected Command addEntityList(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new EntityListParser(name, defaulted, false, policy));
}
protected Command addEntityList(String name, char shortName, boolean defaulted) {
return this.addParameter(shortName, new EntityListParser(name, defaulted, false));
protected Command addEntityList(String name, char shortName, boolean defaulted, UserPolicy policy) {
return this.addParameter(shortName, new EntityListParser(name, defaulted, false, policy));
}
protected Command addLivingEntity(String name, boolean defaulted) {
return this.addParameter(new EntityParser(name, defaulted, true));
protected Command addLivingEntity(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new EntityParser(name, defaulted, true, policy));
}
protected Command addLivingEntityList(String name, boolean defaulted) {
return this.addParameter(new EntityListParser(name, defaulted, true));
protected Command addLivingEntityList(String name, boolean defaulted, UserPolicy policy) {
return this.addParameter(new EntityListParser(name, defaulted, true, policy));
}
protected Command addString(String name, boolean allowEmpty, Object ... completions) {

View file

@ -34,6 +34,7 @@ import server.command.commands.CommandSave;
import server.command.commands.CommandSeed;
import server.command.commands.CommandShutdown;
import server.command.commands.CommandSpawn;
import server.command.commands.CommandSv;
import server.command.commands.CommandTele;
import server.command.commands.CommandTime;
import server.command.commands.CommandTp;
@ -217,22 +218,18 @@ public class CommandEnvironment {
List<String> list = Lists.newArrayList();
try {
String[][] cmds = ArgumentParser.splitString(cmd.endsWith(" ") ? cmd + "END" : cmd);
if(cmds.length == 0)
return list;
String[] argv = cmds[cmds.length - 1];
if(argv.length == 0)
return list;
String param = cmd.endsWith(" ") ? "" : argv[argv.length - 1];
Iterable<String> comp;
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);
}
else {
comp = this.executables.keySet();
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()))
@ -241,7 +238,8 @@ public class CommandEnvironment {
}
catch(Throwable t) {
list.clear();
Log.CONSOLE.error(t, "Konnte Befehl '%s' nicht vervollständigen", cmd);
if(!(t instanceof RunException))
Log.CONSOLE.error(t, "Konnte Befehl '%s' nicht vervollständigen", cmd);
}
finally {
this.currentExecutor = null;
@ -292,6 +290,7 @@ public class CommandEnvironment {
this.registerExecutable(new CommandFind());
this.registerExecutable(new CommandBlock());
this.registerExecutable(new CommandSeed());
this.registerExecutable(new CommandSv());
this.registerExecutable(new CommandHelp(this));
}

View file

@ -9,42 +9,46 @@ import common.collect.Lists;
import common.collect.Sets;
import common.entity.Entity;
import common.entity.EntityType;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import common.init.EntityRegistry;
import server.network.Player;
import server.world.WorldServer;
public class EntityListParser extends EntityParser {
public EntityListParser(String name, boolean useSender, boolean livingOnly) {
super(name, useSender, livingOnly);
public EntityListParser(String name, boolean useSender, boolean livingOnly, UserPolicy policy) {
super(name, useSender, livingOnly, policy);
}
public Object parse(CommandEnvironment env, String input) {
if(input.equals("**")) {
List<Entity> list = Lists.newArrayList();
boolean found = false;
for(WorldServer world : env.getServer().getWorlds()) {
if(this.livingOnly) {
for(Entity ent : world.getEntities()) {
if(ent instanceof EntityLiving)
for(Entity ent : world.getEntities()) {
if(!this.livingOnly || ent instanceof EntityLiving) {
found = true;
if(!(ent instanceof EntityNPC) || !((EntityNPC)ent).isPlayer() || this.policy.applies(env, env.getExecutor(), (Player)((EntityNPC)ent).connection))
list.add(ent);
}
}
else {
list.addAll(world.getEntities());
}
}
if(list.isEmpty())
throw new RunException(this.livingOnly ? "Keine lebendigen Objekte gefunden" : "Keine Objekte gefunden");
throw new RunException(this.livingOnly ? "Keine " + (found ? "erlaubten" : "lebendigen") + " Objekte gefunden" : "Keine " + (found ? "erlaubten " : "") + "Objekte gefunden");
return list;
}
else if(input.equals("*")) {
List<Entity> list = Lists.newArrayList();
boolean found = false;
for(Player plr : env.getServer().getPlayers()) {
if(plr.getPresentEntity() != null)
list.add(plr.getPresentEntity());
if(plr.getPresentEntity() != null) {
found = true;
if(this.policy.applies(env, env.getExecutor(), plr))
list.add(plr.getPresentEntity());
}
}
if(list.isEmpty())
throw new RunException("Keine Spieler gefunden");
throw new RunException("Keine " + (found ? "erlaubten " : "") + "Spieler gefunden");
return list;
}
Set<Class<? extends Entity>> classes = Sets.newHashSet();
@ -95,18 +99,22 @@ public class EntityListParser extends EntityParser {
}
List<Entity> filtered = Lists.newArrayList(entities);
boolean negateOnly = (living == null && player == null && types.isEmpty() && classes.isEmpty() && entities.isEmpty());
boolean found = false;
for(WorldServer world : env.getServer().getWorlds()) {
for(Entity ent : world.getEntities()) {
if((!this.livingOnly || ent instanceof EntityLiving) &&
(negateOnly || (living != null && types.isEmpty() && classes.isEmpty() && living == (ent instanceof EntityLiving)) || (player != null && types.isEmpty() && classes.isEmpty() && player == ent.isPlayer()) || types.contains(ent.getType()) ||
classes.contains(ent.getClass())) &&
(living == null || living == (ent instanceof EntityLiving)) && (player == null || player == ent.isPlayer()) &&
!ntypes.contains(ent.getType()) && !nclasses.contains(ent.getClass()) && !nentities.contains(ent) && !entities.contains(ent))
filtered.add(ent);
!ntypes.contains(ent.getType()) && !nclasses.contains(ent.getClass()) && !nentities.contains(ent) && !entities.contains(ent)) {
found = true;
if(!(ent instanceof EntityNPC) || !((EntityNPC)ent).isPlayer() || this.policy.applies(env, env.getExecutor(), (Player)((EntityNPC)ent).connection))
filtered.add(ent);
}
}
}
if(filtered.isEmpty())
throw new RunException("Keine Objekte gefunden");
throw new RunException("Keine " + (found ? "erlaubten " : "") + "Objekte gefunden");
return filtered;
}

View file

@ -5,14 +5,16 @@ import java.util.List;
import common.collect.Lists;
import common.entity.Entity;
import common.entity.npc.EntityNPC;
import common.entity.types.EntityLiving;
import server.network.Player;
import server.world.WorldServer;
public class EntityParser extends PlayerEntityParser {
protected final boolean livingOnly;
public EntityParser(String name, boolean useSender, boolean livingOnly) {
super(name, useSender);
public EntityParser(String name, boolean useSender, boolean livingOnly, UserPolicy policy) {
super(name, useSender, policy);
this.livingOnly = livingOnly;
}
@ -32,6 +34,8 @@ public class EntityParser extends PlayerEntityParser {
break;
}
}
if(entity instanceof EntityNPC && ((EntityNPC)entity).isPlayer() && !this.policy.applies(env, env.getExecutor(), (Player)((EntityNPC)entity).connection))
throw new RunException(this.policy.getDenyMessage((Player)((EntityNPC)entity).connection));
}
else {
entity = (Entity)super.parse(env, input);
@ -49,7 +53,7 @@ public class EntityParser extends PlayerEntityParser {
public Collection<String> getCompletions(CommandEnvironment env) {
Entity target = env.getExecutor().getPointedEntity();
List<String> comp = target == null || (this.livingOnly && !(target instanceof EntityLiving)) ? Lists.newArrayList() : Lists.newArrayList("#" + target.getId());
List<String> comp = target == null || (this.livingOnly && !(target instanceof EntityLiving)) || (target instanceof EntityNPC && ((EntityNPC)target).isPlayer() && !this.policy.applies(env, env.getExecutor(), (Player)((EntityNPC)target).connection)) ? Lists.newArrayList() : Lists.newArrayList("#" + target.getId());
comp.addAll(super.getCompletions(env));
return comp;
}

View file

@ -7,4 +7,7 @@ public interface Executable {
Map<String, Parameter> getParameters();
List<Parameter> getParamList();
String getName();
default Iterable<String> getCustomCompletions(CommandEnvironment env, Executor exec, ArgumentSplitter parsed, String param, String parser, String arg) {
return null;
}
}

View file

@ -11,19 +11,23 @@ import common.entity.npc.EntityNPC;
import server.network.Player;
public class PlayerEntityListParser extends PlayerEntityParser {
public PlayerEntityListParser(String name, boolean useSender) {
super(name, useSender);
public PlayerEntityListParser(String name, boolean useSender, UserPolicy policy) {
super(name, useSender, policy);
}
public Object parse(CommandEnvironment env, String input) {
if(input.equals("*")) {
List<Entity> list = Lists.newArrayList();
boolean found = false;
for(Player plr : env.getServer().getPlayers()) {
if(plr.getPresentEntity() != null)
list.add(plr.getPresentEntity());
if(plr.getPresentEntity() != null) {
found = true;
if(this.policy.applies(env, env.getExecutor(), plr))
list.add(plr.getPresentEntity());
}
}
if(list.isEmpty())
throw new RunException("Keine Spieler gefunden");
throw new RunException("Keine " + (found ? "erlaubten " : "") + "Spieler gefunden");
return list;
}
Set<EntityNPC> set = Sets.newHashSet();

View file

@ -4,8 +4,8 @@ import common.entity.npc.EntityNPC;
import server.network.Player;
public class PlayerEntityParser extends PlayerParser {
public PlayerEntityParser(String name, boolean useSender) {
super(name, useSender);
public PlayerEntityParser(String name, boolean useSender, UserPolicy policy) {
super(name, useSender, policy);
}
public Object parse(CommandEnvironment env, String input) {

View file

@ -4,20 +4,24 @@ import java.util.Collection;
import java.util.List;
import java.util.Set;
import common.collect.Filter;
import common.collect.Lists;
import common.collect.Sets;
import server.network.Player;
public class PlayerListParser extends PlayerParser {
public PlayerListParser(String name, boolean useSender) {
super(name, useSender);
public PlayerListParser(String name, boolean useSender, UserPolicy policy) {
super(name, useSender, policy);
}
public Object parse(CommandEnvironment env, String input) {
if(input.equals("*")) {
if(env.getServer().getPlayers().isEmpty())
throw new RunException("Keine Spieler gefunden");
return Lists.newArrayList(env.getServer().getPlayers());
Collection<Player> filtered = Filter.filter(env.getServer().getPlayers(), player -> this.policy.applies(env, env.getExecutor(), player));
if(filtered.isEmpty())
throw new RunException("Keine erlaubten Spieler gefunden");
return Lists.newArrayList(filtered);
}
Set<Player> set = Sets.newHashSet();
for(String tok : input.split(",", -1)) {

View file

@ -2,29 +2,34 @@ package server.command;
import java.util.Collection;
import common.collect.Filter;
import server.network.Player;
public class PlayerParser extends CompletingParser {
protected final boolean useSender;
protected final UserPolicy policy;
public PlayerParser(String name, boolean useSender) {
public PlayerParser(String name, boolean useSender, UserPolicy policy) {
super(name);
this.useSender = useSender;
this.policy = policy;
}
public Object parse(CommandEnvironment env, String input) {
Player net = env.getServer().getPlayer(input);
if(net == null)
throw new RunException("Spieler '%s' wurde nicht gefunden", input);
if(!this.policy.applies(env, env.getExecutor(), net))
throw new RunException(this.policy.getDenyMessage(net));
return net;
}
public Object getDefault(CommandEnvironment env) {
return this.useSender && env.getExecutor().isPlayer() ? (Player)env.getExecutor() : null;
return this.useSender && env.getExecutor().isPlayer() && this.policy.applies(env, env.getExecutor(), (Player)env.getExecutor()) ? (Player)env.getExecutor() : null;
}
public Collection<String> getCompletions(CommandEnvironment env) {
return env.getServer().getAllPlayerNames();
return Filter.filter(env.getServer().getAllPlayerNames(), user -> this.policy.applies(env, env.getExecutor(), env.getServer().getPlayer(user)));
}
public Class<?> getTypeClass(boolean required) {

View file

@ -2,30 +2,35 @@ package server.command;
import java.util.Collection;
import common.collect.Filter;
import server.network.Player;
import server.network.User;
public class UserParser extends CompletingParser {
protected final boolean useSender;
protected final UserPolicy policy;
public UserParser(String name, boolean useSender) {
public UserParser(String name, boolean useSender, UserPolicy policy) {
super(name);
this.useSender = useSender;
this.policy = policy;
}
public Object parse(CommandEnvironment env, String input) {
User user = env.getServer().getUser(input);
if(user == null)
throw new RunException("Nutzer '%s' wurde nicht gefunden", input);
if(!this.policy.applies(env, env.getExecutor(), user))
throw new RunException(this.policy.getDenyMessage(user));
return user;
}
public Object getDefault(CommandEnvironment env) {
return this.useSender && env.getExecutor().isPlayer() ? (Player)env.getExecutor() : null;
return this.useSender && env.getExecutor().isPlayer() && this.policy.applies(env, env.getExecutor(), (Player)env.getExecutor()) ? (Player)env.getExecutor() : null;
}
public Collection<String> getCompletions(CommandEnvironment env) {
return env.getServer().getAllUserNames();
return Filter.filter(env.getServer().getAllUserNames(), user -> this.policy.applies(env, env.getExecutor(), env.getServer().getUser(user)));
}
public Class<?> getTypeClass(boolean required) {

View file

@ -0,0 +1,53 @@
package server.command;
import server.network.User;
public enum UserPolicy {
EVERYONE("Wie haste denn das nu geschafft??!") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return true;
}
},
NON_ADMINS("Spieler ist ein Admin") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return !user.isAdmin() || exec.isConsole();
}
},
NON_ADMINS_STRICT("Spieler ist ein Admin") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return !user.isAdmin();
}
},
ADMINS("Spieler ist kein Admin") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return user.isAdmin();
}
},
NOT_SELF("Diese Aktion kann nur an anderen Spielern ausgeführt werden") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return user != exec;
}
},
NON_ADMINS_NOT_SELF("Diese Aktion kann nur an anderen Spielern ohne Admin-Status ausgeführt werden") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return (!user.isAdmin() || exec.isConsole()) && user != exec;
}
},
NON_ADMINS_OR_SELF("Spieler ist ein Admin") {
public boolean applies(CommandEnvironment env, Executor exec, User user) {
return !user.isAdmin() || user == exec || exec.isConsole();
}
};
private final String denyMessage;
private UserPolicy(String denyMessage) {
this.denyMessage = denyMessage;
}
public String getDenyMessage(User user) {
return String.format("%s: %s", user.getUser(), this.denyMessage);
}
public abstract boolean applies(CommandEnvironment env, Executor exec, User user);
}

View file

@ -3,7 +3,7 @@ package server.command.commands;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.UserPolicy;
import server.network.Player;
import server.network.User;
@ -11,14 +11,10 @@ public class CommandAdmin extends Command {
public CommandAdmin() {
super("admin");
this.addUser("user", false);
this.addUser("user", false, UserPolicy.NON_ADMINS_STRICT);
}
public void exec(CommandEnvironment env, Executor exec, User user) {
if(user == exec)
throw new RunException("Du kannst nicht deinen eigenen Admin-Status erneut setzen");
else if(user.isAdmin())
throw new RunException("%s ist bereits ein Admin", user.getUser());
user.setAdmin(true);
if(user.isOnline())
((Player)user).logConsole("Du hast Administatorrechte von %s bekommen", exec.getExecId());

View file

@ -7,12 +7,13 @@ import common.util.BlockPos;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
public class CommandFind extends Command {
public CommandFind() {
super("find");
this.addEntityList("entities", false);
this.addEntityList("entities", false, UserPolicy.EVERYONE);
}
public Object exec(CommandEnvironment env, Executor exec, List<Entity> entities) {

View file

@ -3,23 +3,19 @@ package server.command.commands;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.UserPolicy;
import server.network.Player;
public class CommandKick extends Command {
public CommandKick() {
super("kick");
this.addPlayer("player", false);
this.addPlayer("player", false, UserPolicy.NON_ADMINS_NOT_SELF);
this.setParamsOptional();
this.addString("message", "Du wurdest vom Server geworfen", false);
}
public void exec(CommandEnvironment env, Executor exec, Player player, String message) {
if(player == exec)
throw new RunException("Du kannst nicht dich nicht selbst vom Server werfen");
else if(player.isAdmin())
throw new RunException("%s ist ein Admin", player.getUser());
player.disconnect(message);
exec.logConsole("%s wurde vom Server geworfen", player.getUser());
}

View file

@ -8,12 +8,13 @@ import common.potion.Potion;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
public class CommandMilk extends Command {
public CommandMilk() {
super("milk");
this.addLivingEntityList("entities", true);
this.addLivingEntityList("entities", true, UserPolicy.NON_ADMINS_OR_SELF);
this.setParamsOptional();
List<Potion> potions = Lists.newArrayList();
for(Potion potion : Potion.values()) {

View file

@ -11,6 +11,7 @@ import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.StringCompleter;
import server.command.UserPolicy;
import server.network.Player;
public class CommandOfflinetp extends Command {
@ -23,7 +24,7 @@ public class CommandOfflinetp extends Command {
}
});
this.addEntityList("entities", 'e', true);
this.addEntityList("entities", 'e', true, UserPolicy.NON_ADMINS_OR_SELF);
}
public Object exec(CommandEnvironment env, Executor exec, String user, List<Entity> entities) {

View file

@ -10,6 +10,7 @@ import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.UserPolicy;
import server.network.Player;
import server.network.User;
import server.util.Form;
@ -18,7 +19,7 @@ public class CommandPasswd extends Command {
public CommandPasswd() {
super("passwd");
this.addUser("user", true);
this.addUser("user", true, UserPolicy.NON_ADMINS_OR_SELF);
this.setParamsOptional();
this.addString("password", false);
}
@ -27,8 +28,6 @@ public class CommandPasswd extends Command {
if(exec.isPlayer()) {
if(password != null)
throw new RunException("Bei Verwendung als Spieler darf kein Passwort angegeben werden");
if(user.isAdmin() && user != exec)
throw new RunException("%s ist ein Admin", user.getUser());
if(user.getPubkey() != null && user == exec)
throw new RunException("Es darf kein Pubkey vorhanden sein, um diesen Befehl an sich selbst anzuwenden");
if(user.getPasswordHash() == null && user == exec)

View file

@ -8,12 +8,13 @@ import common.potion.PotionEffect;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
public class CommandPotion extends Command {
public CommandPotion() {
super("potion");
this.addLivingEntityList("entities", true);
this.addLivingEntityList("entities", true, UserPolicy.NON_ADMINS_OR_SELF);
this.addEnum("type", Potion.class, Potion.values());
this.setParamsOptional();
this.addInt("duration", 0, 1000000, 1000000);

View file

@ -11,6 +11,7 @@ import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.UserPolicy;
import server.network.Player;
import server.network.User;
import server.util.Form;
@ -19,7 +20,7 @@ public class CommandPubkey extends Command {
public CommandPubkey() {
super("pubkey");
this.addUser("user", true);
this.addUser("user", true, UserPolicy.NON_ADMINS_OR_SELF);
this.setParamsOptional();
this.addString("keySpec", false);
this.addString("keyData", false);
@ -31,8 +32,6 @@ public class CommandPubkey extends Command {
if(exec.isPlayer()) {
if(keySpec != null || keyData != null || keyHash != null || keyName != null)
throw new RunException("Bei Verwendung als Spieler darf kein Schlüssel angegeben werden");
if(user.isAdmin() && user != exec)
throw new RunException("%s ist ein Admin", user.getUser());
((Player)exec).displayForm(new Form() {
private Field checkField;
private Field keyField;

View file

@ -6,12 +6,13 @@ import common.entity.Entity;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
public class CommandRemove extends Command {
public CommandRemove() {
super("remove");
this.addEntityList("entities", true);
this.addEntityList("entities", true, UserPolicy.NON_ADMINS_OR_SELF);
this.setParamsOptional();
this.addFlag("kill", 'k');

View file

@ -4,6 +4,7 @@ import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.UserPolicy;
import server.network.Player;
import server.network.User;
@ -11,16 +12,12 @@ public class CommandRevoke extends Command {
public CommandRevoke() {
super("revoke");
this.addUser("user", false);
this.addUser("user", false, UserPolicy.ADMINS);
}
public void exec(CommandEnvironment env, Executor exec, User user) {
if(!exec.isConsole())
throw new RunException("Dieser Befehl kann nur der Konsole ausgeführt werden");
// else if(player == exec)
// throw new RunException("Du kannst nicht deinen eigenen Admin-Status entfernen");
else if(!user.isAdmin())
throw new RunException("%s ist kein Admin", user.getUser());
user.setAdmin(false);
if(user.isOnline())
((Player)user).logConsole("Der Host hat deine Administatorrechte entfernt");

View file

@ -0,0 +1,100 @@
package server.command.commands;
import java.util.Collection;
import java.util.Map.Entry;
import common.collect.Lists;
import common.color.TextColor;
import common.init.Config;
import common.init.Config.ValueType;
import server.command.ArgumentSplitter;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.StringCompleter;
public class CommandSv extends Command {
public CommandSv() {
super("sv");
this.setParamsOptional();
this.addString("variable", false, new StringCompleter() {
public Collection<String> complete(CommandEnvironment env) {
return Config.VARS.keySet();
}
});
this.addString("value", true);
}
public Iterable<String> getCustomCompletions(CommandEnvironment env, Executor exec, ArgumentSplitter parsed, String param, String parser, String arg) {
if(param.equals("value") && parsed.has("variable")) {
Config.Value sv = Config.VARS.get(parsed.get("variable"));
if(sv != null && sv.type == ValueType.BOOLEAN)
return Boolean.parseBoolean(sv.getValue()) ? Lists.newArrayList("false", "true") : Lists.newArrayList("true", "false");
else if(sv != null && !sv.noDef && (sv.type == ValueType.INTEGER || sv.type == ValueType.FLOAT))
return Lists.newArrayList(sv.def);
}
return null;
}
private String formatVariable(String name, Config.Value sv, String separator, boolean censor) {
String value = sv.getValue();
StringBuilder sb = new StringBuilder(TextColor.YELLOW + name + TextColor.GRAY + " " + separator + " ");
if(sv.noDef && sv.def.equals(value))
sb.append(TextColor.DGRAY + "[ - ]");
else if(censor && name.equals("password") && !value.isEmpty())
sb.append(TextColor.NEON + "'****'");
else if(sv.type == ValueType.STRING)
sb.append(TextColor.NEON + "'" + value + "'");
else
sb.append(((sv.type == ValueType.BOOLEAN ? (value.equals("true") ? TextColor.GREEN : TextColor.RED) : TextColor.BLUE)) + value);
if(!sv.def.equals(value))
sb.append(TextColor.GRAY + " (" + (sv.noDef ? TextColor.DGRAY + "[ - ]" : TextColor.BROWN + sv.def) + TextColor.GRAY + ")");
return sb.toString();
}
public Object exec(CommandEnvironment env, Executor exec, String variable, String value) {
if(variable == null) {
if(value != null)
throw new RunException("Kann keinen Wert ohne eine Variable angeben");
for(Entry<String, Config.Value> entry : Config.VARS.entrySet()) {
exec.logConsole(this.formatVariable(entry.getKey(), entry.getValue(), "=", true));
}
exec.logConsole(TextColor.GREEN + "SVARs insgesamt registriert: %d", Config.VARS.size());
return null;
}
Config.Value sv = Config.VARS.get(variable);
if(sv == null)
throw new RunException("Variable '%s' existiert nicht", variable);
if(value != null) {
if(sv.type == ValueType.BOOLEAN && !"true".equals(value) && !"false".equals(value)) {
if(value.equals("0") || value.equals("1"))
value = "" + value.equals("1");
else if(value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false"))
value = value.toLowerCase();
else
throw new RunException("'%s' ist nicht 'true' (1) oder 'false' (0)", value);
}
else if(sv.type == ValueType.INTEGER) {
try {
Integer.parseInt(value);
}
catch(NumberFormatException e) {
throw new RunException(TextColor.DRED + "'%s' ist keine gültige Zahl", value);
}
}
else if(sv.type == ValueType.FLOAT) {
try {
Float.parseFloat(value);
}
catch(NumberFormatException e) {
throw new RunException(TextColor.DRED + "'%s' ist keine gültige Zahl", value);
}
}
Config.set(variable, value, true);
}
exec.logConsole(this.formatVariable(variable, sv, value == null ? "=" : "->", false));
return sv.noDef && sv.def.equals(sv.getValue()) ? null : sv.getValue();
}
}

View file

@ -8,6 +8,7 @@ import common.util.Vec3;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
public class CommandTele extends Command {
public CommandTele() {
@ -20,7 +21,7 @@ public class CommandTele extends Command {
this.addDouble("pitch", -89.0, 89.0);
this.setParamsRequired();
this.addEntityList("entities", 'e', true);
this.addEntityList("entities", 'e', true, UserPolicy.NON_ADMINS_OR_SELF);
}
public Object exec(CommandEnvironment env, Executor exec, Vec3 position, Dimension dim, Double yaw, Double pitch, List<Entity> entities) {

View file

@ -8,14 +8,15 @@ import common.util.Position;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
public class CommandTp extends Command {
public CommandTp() {
super("tp");
this.addEntity("target", false);
this.addEntity("target", false, UserPolicy.NOT_SELF);
this.addEntityList("entities", 'e', true);
this.addEntityList("entities", 'e', true, UserPolicy.NON_ADMINS_OR_SELF);
}
public Object exec(CommandEnvironment env, Executor exec, Entity target, List<Entity> entities) {

View file

@ -11,6 +11,7 @@ import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.RunException;
import server.command.StringCompleter;
import server.command.UserPolicy;
public class CommandWarp extends Command {
public CommandWarp() {
@ -24,7 +25,7 @@ public class CommandWarp extends Command {
}
});
this.addEntityList("entities", 'e', true);
this.addEntityList("entities", 'e', true, UserPolicy.NON_ADMINS_OR_SELF);
}
public Object exec(CommandEnvironment env, Executor exec, String warp, List<Entity> entities) {

View file

@ -7,6 +7,7 @@ import common.util.BlockPos;
import server.command.Command;
import server.command.CommandEnvironment;
import server.command.Executor;
import server.command.UserPolicy;
import server.world.WorldServer;
public class CommandWorld extends Command {
@ -15,7 +16,7 @@ public class CommandWorld extends Command {
this.addWorld("dim", false);
this.addEntityList("entities", 'e', true);
this.addEntityList("entities", 'e', true, UserPolicy.NON_ADMINS_OR_SELF);
}
public Object exec(CommandEnvironment env, Executor exec, WorldServer world, List<Entity> entities) {

View file

@ -32,7 +32,6 @@ import common.init.EntityRegistry;
import common.init.Items;
import common.init.SoundEvent;
import common.init.UniverseRegistry;
import common.init.Config.ValueType;
import common.inventory.Container;
import common.inventory.ContainerChest;
import common.inventory.ContainerHorseInventory;
@ -1727,12 +1726,6 @@ public class Player extends User implements ICrafting, Executor, IPlayer
return true;
}
private boolean setVar(String line) {
if(!this.isAdmin())
return false;
return this.server.setVar(this, line);
}
public void setAdmin(boolean admin) {
super.setAdmin(admin);
if(!this.isAdmin() && this.entity != null && this.entity.noclip) {
@ -1939,8 +1932,7 @@ public class Player extends User implements ICrafting, Executor, IPlayer
switch(type) {
case COMMAND:
if(!this.setVar(msg))
this.runCommand(msg); // this.addFeed(TextColor.RED + "Befehl wurde nicht gefunden");
this.runCommand(msg); // this.addFeed(TextColor.RED + "Befehl wurde nicht gefunden");
break;
case CHAT:
@ -1970,39 +1962,6 @@ public class Player extends User implements ICrafting, Executor, IPlayer
}
}
// private Iterable<String> getWarpList(char pre) {
// switch(pre) {
// case '+':
// return Lists.newArrayList(this.server.getUsers());
// case '@':
// List<String> warps = Lists.newArrayList("spawn");
// for(String warp : this.server.getWarps().keySet()) {
// warps.add(warp);
// }
// return warps;
// case '*':
// return UniverseRegistry.getWorldNames();
// }
// return Lists.newArrayList();
// }
// private static List<String> getVarList() {
// List<String> list = ;
// list.add("time");
// return list;
// }
private List<String> getVarCompletion(String var) {
Config.Value v = Config.VARS.get(var);
if(v == null)
return Lists.newArrayList();
if(v.type == ValueType.BOOLEAN)
return Boolean.parseBoolean(v.getValue()) ? Lists.newArrayList("false", "true") : Lists.newArrayList("true", "false");
else if(!v.noDef && (v.type == ValueType.INTEGER || v.type == ValueType.FLOAT))
return Lists.newArrayList(v.def);
return Lists.newArrayList();
}
public void processComplete(CPacketComplete packetIn)
{
NetHandler.checkThread(packetIn, this, this.server);
@ -2016,16 +1975,7 @@ public class Player extends User implements ICrafting, Executor, IPlayer
this.entity.connection.sendPacket(new SPacketTabComplete(new String[0]));
return;
}
List<String> list = Lists.<String>newArrayList();
String s = packetIn.getMessage();
String[] argv = s.split(" ", -1);
s = argv[argv.length - 1];
Iterable<String> res = argv.length == 1 ? Lists.newArrayList(Config.VARS.keySet()) : (argv.length == 2 ? getVarCompletion(argv[0]) : Lists.newArrayList());
for(String s1 : res) {
if(s1.regionMatches(true, 0, s, 0, s.length()))
list.add(s1);
}
list.addAll(this.completeCommand(packetIn.getMessage()));
List<String> list = this.completeCommand(packetIn.getMessage());
this.entity.connection.sendPacket(new SPacketTabComplete(list.toArray(new String[list.size()])));
}