Merge pull request #828 from gnembon/unpacker

Unpacker
This commit is contained in:
gnembon authored and GitHub committed 2021-04-23 01:30:29 -03:00
commit 5ec664240f
34 files changed
+1211 -1398

No files matched your search

+23 -2
View File
@@ -29,11 +29,12 @@ Here is the complete list of operators in `scarpet` including control flow opera
are not technically operators, but part of the language, even if they look like them: are not technically operators, but part of the language, even if they look like them:
* Match, Get `~ :` * Match, Get `~ :`
* Unary `+ - !` * Unary `+ - ! ...`
* Exponent `^` * Exponent `^`
* Multiplication `* / %` * Multiplication `* / %`
* Addition `+ -` * Addition `+ -`
* Comparison `== != > >= <= <` * Comparison `> >= <= <`
* Equality `== !=`
* Logical And`&&` * Logical And`&&`
* Logical Or `||` * Logical Or `||`
* Assignment `= += <>` * Assignment `= += <>`
@@ -234,3 +235,23 @@ flips boolean condition of the expression. Equivalent of `bool(expr)==false`
!l() => true !l() => true
!l(null) => false !l(null) => false
</pre> </pre>
### `Unpacking Operator ...`
Unpacks elements of a list of an iterator into a sequence of arguments in a function making so that `fun(...[1, 2, 3])` is
identical with `fun(1, 2, 3)`.
In function signatures it identifies a vararg parameter.
`fun(a, b, ... rest) -> [a, b, rest]; fun(1, 2, 3, 4)` => `[1, 2, [3, 4]]`
Effects of `...` can be surprisingly lasting. It is kept through the use of variables and function calls.
`fun(a, b, ... rest) -> [a, b, ... rest]; fun(1, 2, 3, 4)` => `[1, 2, 3, 4]`
`args() -> ... [1, 2, 3]; sum(a, b, c) -> a+b+c; sum(args())` => `6`
`a = ... [1, 2, 3]; sum(a, b, c) -> a+b+c; sum(a)` => `6`
Unpacking mechanics can be used for list and map constriction, not just for function calls.
`[...range(5), pi, ...range(5,-1,-1)]` => `[0, 1, 2, 3, 4, 3.14159265359, 5, 4, 3, 2, 1, 0]`
`{ ... map(range(5), _ -> _*_ )}` => `{0: 0, 1: 1, 2: 4, 3: 9, 4: 16}`
@@ -134,7 +134,7 @@ public class CarpetScriptHost extends ScriptHost
return host; return host;
} }
private static int execute(CommandContext<ServerCommandSource> ctx, String hostName, FunctionArgument<Value> funcSpec, List<String> paramNames) throws CommandSyntaxException private static int execute(CommandContext<ServerCommandSource> ctx, String hostName, FunctionArgument funcSpec, List<String> paramNames) throws CommandSyntaxException
{ {
CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet command", CarpetProfiler.TYPE.GENERAL); CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet command", CarpetProfiler.TYPE.GENERAL);
CarpetScriptHost cHost = CarpetServer.scriptServer.modules.get(hostName).retrieveOwnForExecution(ctx.getSource()); CarpetScriptHost cHost = CarpetServer.scriptServer.modules.get(hostName).retrieveOwnForExecution(ctx.getSource());
@@ -158,7 +158,7 @@ public class CarpetScriptHost extends ScriptHost
public LiteralArgumentBuilder<ServerCommandSource> addPathToCommand( public LiteralArgumentBuilder<ServerCommandSource> addPathToCommand(
LiteralArgumentBuilder<ServerCommandSource> command, LiteralArgumentBuilder<ServerCommandSource> command,
List<CommandToken> path, List<CommandToken> path,
FunctionArgument<Value> functionSpec FunctionArgument functionSpec
) throws CommandSyntaxException ) throws CommandSyntaxException
{ {
String hostName = main.getName(); String hostName = main.getName();
@@ -180,14 +180,14 @@ public class CarpetScriptHost extends ScriptHost
} }
public LiteralArgumentBuilder<ServerCommandSource> getNewCommandTree( public LiteralArgumentBuilder<ServerCommandSource> getNewCommandTree(
List<Pair<List<CommandToken>,FunctionArgument<Value>>> entries, Function<ServerCommandSource, Boolean> useValidator List<Pair<List<CommandToken>,FunctionArgument>> entries, Function<ServerCommandSource, Boolean> useValidator
) throws CommandSyntaxException ) throws CommandSyntaxException
{ {
String hostName = main.getName(); String hostName = main.getName();
Function<ServerCommandSource, Boolean> configValidator = getCommandConfigPermissions(); Function<ServerCommandSource, Boolean> configValidator = getCommandConfigPermissions();
LiteralArgumentBuilder<ServerCommandSource> command = literal(hostName). LiteralArgumentBuilder<ServerCommandSource> command = literal(hostName).
requires((player) -> CarpetServer.scriptServer.modules.containsKey(hostName) && useValidator.apply(player) && configValidator.apply(player)); requires((player) -> CarpetServer.scriptServer.modules.containsKey(hostName) && useValidator.apply(player) && configValidator.apply(player));
for (Pair<List<CommandToken>,FunctionArgument<Value>> commandData : entries) for (Pair<List<CommandToken>,FunctionArgument> commandData : entries)
{ {
command = this.addPathToCommand(command, commandData.getKey(), commandData.getValue()); command = this.addPathToCommand(command, commandData.getKey(), commandData.getValue());
} }
@@ -547,12 +547,12 @@ public class CarpetScriptHost extends ScriptHost
if (commands == null) return null; if (commands == null) return null;
if (!(commands instanceof MapValue)) if (!(commands instanceof MapValue))
throw CommandArgument.error("'commands' element in config should be a map"); throw CommandArgument.error("'commands' element in config should be a map");
List<Pair<List<CommandToken>,FunctionArgument<Value>>> commandEntries = new ArrayList<>(); List<Pair<List<CommandToken>,FunctionArgument>> commandEntries = new ArrayList<>();
for (Map.Entry<Value, Value> commandsData : ((MapValue)commands).getMap().entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList())) for (Map.Entry<Value, Value> commandsData : ((MapValue)commands).getMap().entrySet().stream().sorted(Map.Entry.comparingByKey()).collect(Collectors.toList()))
{ {
List<CommandToken> elements = CommandToken.parseSpec(commandsData.getKey().getString(), this); List<CommandToken> elements = CommandToken.parseSpec(commandsData.getKey().getString(), this);
FunctionArgument<Value> funSpec = FunctionArgument.fromCommandSpec(this, commandsData.getValue()); FunctionArgument funSpec = FunctionArgument.fromCommandSpec(this, commandsData.getValue());
commandEntries.add(Pair.of(elements, funSpec)); commandEntries.add(Pair.of(elements, funSpec));
} }
commandEntries.sort(new ListComparator<>()); commandEntries.sort(new ListComparator<>());
@@ -806,20 +806,18 @@ public class CarpetScriptHost extends ScriptHost
} }
} }
public Value call(ServerCommandSource source, FunctionValue function, List<Value> suppliedArgs) public Value call(ServerCommandSource source, FunctionValue function, List<Value> argv)
{ {
if (CarpetServer.scriptServer.stopAll) if (CarpetServer.scriptServer.stopAll)
throw new CarpetExpressionException("SCARPET PAUSED", null); throw new CarpetExpressionException("SCARPET PAUSED", null);
List<LazyValue> argv = FunctionValue.lazify(suppliedArgs);
List<String> args = function.getArguments(); List<String> args = function.getArguments();
if (argv.size() != args.size()) if (argv.size() != args.size())
{ {
String error = "Fail: stored function "+function.getPrettyString()+" takes "+args.size()+" arguments, not "+argv.size()+ ":\n"; String error = "Fail: stored function "+function.getPrettyString()+" takes "+args.size()+" arguments, not "+argv.size()+ ":\n";
for (int i = 0; i < max(argv.size(), args.size()); i++) for (int i = 0; i < max(argv.size(), args.size()); i++)
{ {
error += (i<args.size()?args.get(i):"??")+" => "+(i<argv.size()?argv.get(i).evalValue(null).getString():"??")+"\n"; error += (i<args.size()?args.get(i):"??")+" => "+(i<argv.size()?argv.get(i).getString():"??")+"\n";
} }
throw new CarpetExpressionException(error, null); throw new CarpetExpressionException(error, null);
} }
@@ -828,7 +826,7 @@ public class CarpetScriptHost extends ScriptHost
// TODO: this is just for now - invoke would be able to invoke other hosts scripts // TODO: this is just for now - invoke would be able to invoke other hosts scripts
Context context = new CarpetContext(this, source, BlockPos.ORIGIN); Context context = new CarpetContext(this, source, BlockPos.ORIGIN);
return function.getExpression().evalValue( return function.getExpression().evalValue(
() -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv), () -> function.execute(context, Context.VOID, function.getExpression(), function.getToken(), argv),
context, context,
Context.VOID Context.VOID
); );
@@ -857,7 +855,7 @@ public class CarpetScriptHost extends ScriptHost
// TODO: this is just for now - invoke would be able to invoke other hosts scripts // TODO: this is just for now - invoke would be able to invoke other hosts scripts
Context context = new CarpetContext(this, source, pos); Context context = new CarpetContext(this, source, pos);
return fun.getExpression().evalValue( return fun.getExpression().evalValue(
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), FunctionValue.lazify(argv)), () -> fun.execute(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
context, context,
Context.VOID); Context.VOID);
} }
@@ -20,6 +20,8 @@ import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.WorldSavePath; import net.minecraft.util.WorldSavePath;
import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.BlockPos;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import java.io.IOException; import java.io.IOException;
import java.nio.file.FileVisitOption; import java.nio.file.FileVisitOption;
@@ -43,6 +45,7 @@ import static net.minecraft.server.command.CommandManager.literal;
public class CarpetScriptServer public class CarpetScriptServer
{ {
//make static for now, but will change that later: //make static for now, but will change that later:
public static final Logger LOG = LogManager.getLogger("scarpet");
public final MinecraftServer server; public final MinecraftServer server;
public CarpetScriptHost globalHost; public CarpetScriptHost globalHost;
public Map<String, CarpetScriptHost> modules; public Map<String, CarpetScriptHost> modules;
+100 -12
View File
@@ -188,7 +188,7 @@ public class Expression
public void addLazyFunctionWithDelegation(String name, int numpar, public void addLazyFunctionWithDelegation(String name, int numpar,
QuinnFunction<Context, Integer, Expression, Tokenizer.Token, List<LazyValue>, LazyValue> lazyfun) QuinnFunction<Context, Integer, Expression, Tokenizer.Token, List<LazyValue>, LazyValue> lazyfun)
{ {
functions.put(name, new AbstractLazyFunction(numpar) functions.put(name, new AbstractLazyFunction(numpar, name)
{ {
@Override @Override
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lv) public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lv)
@@ -205,6 +205,27 @@ public class Expression
}); });
} }
public void addFunctionWithDelegation(String name, int numpar,
QuinnFunction<Context, Integer, Expression, Tokenizer.Token, List<Value>, Value> fun)
{
functions.put(name, new AbstractLazyFunction(numpar, name)
{
@Override
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lv)
{
try
{
Value res = fun.apply(c, type, e, t, unpackArgs(lv, c, Context.NONE));
return (cc, tt) -> res;
}
catch (RuntimeException exc)
{
throw handleCodeException(c, exc, e, t);
}
}
});
}
public void addLazyBinaryOperator(String surface, int precedence, boolean leftAssoc, public void addLazyBinaryOperator(String surface, int precedence, boolean leftAssoc,
QuadFunction<Context, Integer, LazyValue, LazyValue, LazyValue> lazyfun) QuadFunction<Context, Integer, LazyValue, LazyValue, LazyValue> lazyfun)
{ {
@@ -226,6 +247,28 @@ public class Expression
}); });
} }
public void addBinaryContextOperator(String surface, int precedence, boolean leftAssoc,
QuadFunction<Context, Integer, Value, Value, Value> fun)
{
operators.put(surface, new AbstractLazyOperator(precedence, leftAssoc)
{
@Override
public LazyValue lazyEval(Context c, Integer t, Expression e, Tokenizer.Token token, LazyValue v1, LazyValue v2)
{
try
{
Value.assertNotNull(v1, v2); // does anybody needs those
Value ret = fun.apply(c, t, v1.evalValue(c, Context.NONE), v2.evalValue(c, Context.NONE));
return (cc, tt) -> ret;
}
catch (RuntimeException exc)
{
throw handleCodeException(c, exc, e, token);
}
}
});
}
public static RuntimeException handleCodeException(Context c, RuntimeException exc, Expression e, Tokenizer.Token token) public static RuntimeException handleCodeException(Context c, RuntimeException exc, Expression e, Tokenizer.Token token)
{ {
if (exc instanceof ExitStatement) if (exc instanceof ExitStatement)
@@ -243,7 +286,7 @@ public class Expression
public void addUnaryOperator(String surface, boolean leftAssoc, Function<Value, Value> fun) public void addUnaryOperator(String surface, boolean leftAssoc, Function<Value, Value> fun)
{ {
operators.put(surface+"u", new AbstractUnaryOperator(Operators.precedence.get("unary+-!"), leftAssoc) operators.put(surface+"u", new AbstractUnaryOperator(Operators.precedence.get("unary+-!..."), leftAssoc)
{ {
@Override @Override
public Value evalUnary(Value v1) public Value evalUnary(Value v1)
@@ -269,7 +312,7 @@ public class Expression
public void addUnaryFunction(String name, Function<Value, Value> fun) public void addUnaryFunction(String name, Function<Value, Value> fun)
{ {
functions.put(name, new AbstractFunction(1) functions.put(name, new AbstractFunction(1, name)
{ {
@Override @Override
public Value eval(List<Value> parameters) public Value eval(List<Value> parameters)
@@ -281,7 +324,7 @@ public class Expression
public void addBinaryFunction(String name, BiFunction<Value, Value, Value> fun) public void addBinaryFunction(String name, BiFunction<Value, Value, Value> fun)
{ {
functions.put(name, new AbstractFunction(2) functions.put(name, new AbstractFunction(2, name)
{ {
@Override @Override
public Value eval(List<Value> parameters) public Value eval(List<Value> parameters)
@@ -296,7 +339,7 @@ public class Expression
public void addFunction(String name, Function<List<Value>, Value> fun) public void addFunction(String name, Function<List<Value>, Value> fun)
{ {
functions.put(name, new AbstractFunction(-1) functions.put(name, new AbstractFunction(-1, name)
{ {
@Override @Override
public Value eval(List<Value> parameters) public Value eval(List<Value> parameters)
@@ -327,7 +370,7 @@ public class Expression
public void addLazyFunction(String name, int num_params, TriFunction<Context, Integer, List<LazyValue>, LazyValue> fun) public void addLazyFunction(String name, int num_params, TriFunction<Context, Integer, List<LazyValue>, LazyValue> fun)
{ {
functions.put(name, new AbstractLazyFunction(num_params) functions.put(name, new AbstractLazyFunction(num_params, name)
{ {
@Override @Override
public LazyValue lazyEval(Context c, Integer i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams) public LazyValue lazyEval(Context c, Integer i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
@@ -343,6 +386,47 @@ public class Expression
} }
}); });
} }
public void addContextFunction(String name, int num_params, TriFunction<Context, Integer, List<Value>, Value> fun)
{
functions.put(name, new AbstractLazyFunction(num_params, name)
{
@Override
public LazyValue lazyEval(Context c, Integer i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
try
{
Value ret = fun.apply(c, i, unpackArgs(lazyParams, c, Context.NONE));
return (cc, tt) -> ret;
}
catch (RuntimeException exc)
{
throw handleCodeException(c, exc, e, t);
}
}
});
}
public void addTypedContextFunction(String name, int num_params, int reqType, TriFunction<Context, Integer, List<Value>, Value> fun)
{
functions.put(name, new AbstractLazyFunction(num_params, name)
{
@Override
public LazyValue lazyEval(Context c, Integer i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
try
{
Value ret = fun.apply(c, i, unpackArgs(lazyParams, c, reqType));
return (cc, tt) -> ret;
}
catch (RuntimeException exc)
{
throw handleCodeException(c, exc, e, t);
}
}
});
}
public FunctionValue createUserDefinedFunction(Context context, String name, Expression expr, Tokenizer.Token token, List<String> arguments, String varArgs, List<String> outers, LazyValue code) public FunctionValue createUserDefinedFunction(Context context, String name, Expression expr, Tokenizer.Token token, List<String> arguments, String varArgs, List<String> outers, LazyValue code)
{ {
if (functions.containsKey(name)) if (functions.containsKey(name))
@@ -773,12 +857,16 @@ public class Expression
stack.set(stack.size() - 1, stack.peek() - 2 + 1); stack.set(stack.size() - 1, stack.peek() - 2 + 1);
break; break;
case FUNCTION: case FUNCTION:
ILazyFunction f = functions.get(token.surface);// don't validate global - userdef functions //ILazyFunction f = functions.get(token.surface);// don't validate global - userdef functions
int numParams = stack.pop(); //int numParams = stack.pop();
if (f != null && !f.numParamsVaries() && numParams != f.getNumParams()) //if (f != null && !f.numParamsVaries() && numParams != f.getNumParams())
{ //{
throw new ExpressionException(c, this, token, "Function " + token + " expected " + f.getNumParams() + " parameters, got " + numParams); // throw new ExpressionException(c, this, token, "Function " + token + " expected " + f.getNumParams() + " parameters, got " + numParams);
} //}
stack.pop();
// due to unpacking, all functions can have variable number of arguments
// we will be checking that at runtime.
// TODO try analyze arguments and assess if its possible that they are static
if (stack.size() <= 0) if (stack.size() <= 0)
{ {
throw new ExpressionException(c, this, token, "Too many function calls, maximum scope exceeded"); throw new ExpressionException(c, this, token, "Too many function calls, maximum scope exceeded");
+44 -7
View File
@@ -1,6 +1,10 @@
package carpet.script; package carpet.script;
import carpet.CarpetSettings;
import carpet.script.exception.ExpressionException; import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.value.FunctionUnpackedArgumentsValue;
import carpet.script.value.ListValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import java.util.ArrayList; import java.util.ArrayList;
@@ -60,9 +64,10 @@ public abstract class Fluff
protected String name; protected String name;
int numParams; int numParams;
AbstractLazyFunction(int numParams) AbstractLazyFunction(int numParams, String name)
{ {
this.numParams = numParams; this.numParams = numParams;
this.name = name;
} }
@@ -77,12 +82,42 @@ public abstract class Fluff
public boolean numParamsVaries() { public boolean numParamsVaries() {
return numParams < 0; return numParams < 0;
} }
public static List<Value> unpackLazy(List<LazyValue> lzargs, Context c, int contextType)
{
List<Value> args = new ArrayList<>();
for (LazyValue lv : lzargs)
{
Value arg = lv.evalValue(c, contextType);
if (arg instanceof FunctionUnpackedArgumentsValue)
args.addAll(((ListValue) arg).getItems());
else
args.add(arg);
}
return args;
}
public List<Value> unpackArgs(List<LazyValue> lzargs, Context c, int contextType)
{
List<Value> args = new ArrayList<>();
for (LazyValue lv : lzargs)
{
Value arg = lv.evalValue(c, contextType);
if (arg instanceof FunctionUnpackedArgumentsValue)
args.addAll(((ListValue) arg).getItems());
else
args.add(arg);
}
if (!numParamsVaries() && getNumParams() != args.size())
throw new InternalExpressionException("Function " + getName() + " expected " + getNumParams() + " parameters, got " + args.size());
return args;
}
} }
public abstract static class AbstractFunction extends AbstractLazyFunction implements IFunction public abstract static class AbstractFunction extends AbstractLazyFunction implements IFunction
{ {
AbstractFunction(int numParams) { AbstractFunction(int numParams, String name) {
super(numParams); super(numParams, name);
} }
@Override @Override
@@ -100,10 +135,12 @@ public abstract class Fluff
private List<Value> getParams(Context c) { private List<Value> getParams(Context c) {
if (params == null) { if (params == null) {
params = new ArrayList<>(); // very likely needs to be dynamic, so not static like here, or remember if it was.
for (LazyValue lazyParam : lazyParams) { params = unpackArgs(lazyParams, c, Context.NONE);
params.add(lazyParam.evalValue(c)); // none type default by design }
} else
{
CarpetSettings.LOG.error("How did we get here 1");
} }
return params; return params;
} }
+185 -265
View File
@@ -1,7 +1,6 @@
package carpet.script.api; package carpet.script.api;
import carpet.CarpetServer; import carpet.CarpetServer;
import carpet.CarpetSettings;
import carpet.fakes.MinecraftServerInterface; import carpet.fakes.MinecraftServerInterface;
import carpet.fakes.ServerWorldInterface; import carpet.fakes.ServerWorldInterface;
import carpet.fakes.StatTypeInterface; import carpet.fakes.StatTypeInterface;
@@ -15,7 +14,6 @@ import carpet.script.CarpetScriptHost;
import carpet.script.CarpetScriptServer; import carpet.script.CarpetScriptServer;
import carpet.script.Context; import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.argument.BlockArgument; import carpet.script.argument.BlockArgument;
import carpet.script.argument.FunctionArgument; import carpet.script.argument.FunctionArgument;
import carpet.script.argument.Vector3Argument; import carpet.script.argument.Vector3Argument;
@@ -28,9 +26,9 @@ import carpet.script.utils.InputValidator;
import carpet.script.utils.ScarpetJsonDeserializer; import carpet.script.utils.ScarpetJsonDeserializer;
import carpet.script.utils.ShapeDispatcher; import carpet.script.utils.ShapeDispatcher;
import carpet.script.utils.WorldTools; import carpet.script.utils.WorldTools;
import carpet.script.value.BooleanValue;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
import carpet.script.value.FormattedTextValue; import carpet.script.value.FormattedTextValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.MapValue; import carpet.script.value.MapValue;
import carpet.script.value.NBTSerializableValue; import carpet.script.value.NBTSerializableValue;
@@ -147,16 +145,15 @@ public class Auxiliary {
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunction("sound", -1, (c, t, lv) -> { expression.addContextFunction("sound", -1, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
if (lv.size() == 0) if (lv.size() == 0)
{ {
Value ret = ListValue.wrap(Registry.SOUND_EVENT.getIds().stream().map(ValueConversions::of)); return ListValue.wrap(Registry.SOUND_EVENT.getIds().stream().map(ValueConversions::of));
return (_c, _t) -> ret;
} }
String rawString = lv.get(0).evalValue(c).getString(); String rawString = lv.get(0).getString();
Identifier soundName = new Identifier(rawString); Identifier soundName = new Identifier(rawString);
Vector3Argument locator = Vector3Argument.findIn(cc, lv, 1); Vector3Argument locator = Vector3Argument.findIn(lv, 1);
if (Registry.SOUND_EVENT.get(soundName) == null) if (Registry.SOUND_EVENT.get(soundName) == null)
throw new ThrowStatement(rawString, Throwables.UNKNOWN_SOUND); throw new ThrowStatement(rawString, Throwables.UNKNOWN_SOUND);
float volume = 1.0F; float volume = 1.0F;
@@ -164,13 +161,13 @@ public class Auxiliary {
SoundCategory mixer = SoundCategory.MASTER; SoundCategory mixer = SoundCategory.MASTER;
if (lv.size() > 0+locator.offset) if (lv.size() > 0+locator.offset)
{ {
volume = (float) NumericValue.asNumber(lv.get(0+locator.offset).evalValue(c)).getDouble(); volume = (float) NumericValue.asNumber(lv.get(0+locator.offset)).getDouble();
if (lv.size() > 1+locator.offset) if (lv.size() > 1+locator.offset)
{ {
pitch = (float) NumericValue.asNumber(lv.get(1+locator.offset).evalValue(c)).getDouble(); pitch = (float) NumericValue.asNumber(lv.get(1+locator.offset)).getDouble();
if (lv.size() > 2+locator.offset) if (lv.size() > 2+locator.offset)
{ {
String mixerName = lv.get(2+locator.offset).evalValue(c).getString(); String mixerName = lv.get(2+locator.offset).getString();
mixer = mixerMap.get(mixerName.toLowerCase(Locale.ROOT)); mixer = mixerMap.get(mixerName.toLowerCase(Locale.ROOT));
if (mixer == null) throw new InternalExpressionException(mixerName +" is not a valid mixer name"); if (mixer == null) throw new InternalExpressionException(mixerName +" is not a valid mixer name");
} }
@@ -184,39 +181,33 @@ public class Auxiliary {
count++; count++;
player.networkHandler.sendPacket(new PlaySoundIdS2CPacket(soundName, mixer, vec, volume, pitch)); player.networkHandler.sendPacket(new PlaySoundIdS2CPacket(soundName, mixer, vec, volume, pitch));
} }
int totalPlayed = count; return new NumericValue(count);
return (_c, _t) -> new NumericValue(totalPlayed);
}); });
expression.addLazyFunction("particle", -1, (c, t, lv) -> expression.addContextFunction("particle", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
if (lv.size() == 0) if (lv.size() == 0) return ListValue.wrap(Registry.PARTICLE_TYPE.getIds().stream().map(ValueConversions::of));
{
Value ret = ListValue.wrap(Registry.PARTICLE_TYPE.getIds().stream().map(ValueConversions::of));
return (_c, _t) -> ret;
}
MinecraftServer ms = cc.s.getMinecraftServer(); MinecraftServer ms = cc.s.getMinecraftServer();
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
Vector3Argument locator = Vector3Argument.findIn(cc, lv, 1); Vector3Argument locator = Vector3Argument.findIn(lv, 1);
String particleName = lv.get(0).evalValue(c).getString(); String particleName = lv.get(0).getString();
int count = 10; int count = 10;
double speed = 0; double speed = 0;
float spread = 0.5f; float spread = 0.5f;
ServerPlayerEntity player = null; ServerPlayerEntity player = null;
if (lv.size() > locator.offset) if (lv.size() > locator.offset)
{ {
count = (int) NumericValue.asNumber(lv.get(locator.offset).evalValue(c)).getLong(); count = (int) NumericValue.asNumber(lv.get(locator.offset)).getLong();
if (lv.size() > 1+locator.offset) if (lv.size() > 1+locator.offset)
{ {
spread = (float) NumericValue.asNumber(lv.get(1+locator.offset).evalValue(c)).getDouble(); spread = (float) NumericValue.asNumber(lv.get(1+locator.offset)).getDouble();
if (lv.size() > 2+locator.offset) if (lv.size() > 2+locator.offset)
{ {
speed = NumericValue.asNumber(lv.get(2 + locator.offset).evalValue(c)).getDouble(); speed = NumericValue.asNumber(lv.get(2 + locator.offset)).getDouble();
if (lv.size() > 3 + locator.offset) // should accept entity as well as long as it is player if (lv.size() > 3 + locator.offset) // should accept entity as well as long as it is player
{ {
player = ms.getPlayerManager().getPlayer(lv.get(3 + locator.offset).evalValue(c).getString()); player = ms.getPlayerManager().getPlayer(lv.get(3 + locator.offset).getString());
} }
} }
} }
@@ -238,29 +229,29 @@ public class Auxiliary {
spread, spread, spread, speed); spread, spread, spread, speed);
} }
return (c_, t_) -> Value.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("particle_line", -1, (c, t, lv) -> expression.addContextFunction("particle_line", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
String particleName = lv.get(0).evalValue(c).getString(); String particleName = lv.get(0).getString();
ParticleEffect particle = ShapeDispatcher.getParticleData(particleName); ParticleEffect particle = ShapeDispatcher.getParticleData(particleName);
Vector3Argument pos1 = Vector3Argument.findIn(cc, lv, 1); Vector3Argument pos1 = Vector3Argument.findIn(lv, 1);
Vector3Argument pos2 = Vector3Argument.findIn(cc, lv, pos1.offset); Vector3Argument pos2 = Vector3Argument.findIn(lv, pos1.offset);
double density = 1.0; double density = 1.0;
ServerPlayerEntity player = null; ServerPlayerEntity player = null;
if (lv.size() > pos2.offset+0 ) if (lv.size() > pos2.offset+0 )
{ {
density = NumericValue.asNumber(lv.get(pos2.offset+0).evalValue(c)).getDouble(); density = NumericValue.asNumber(lv.get(pos2.offset+0)).getDouble();
if (density <= 0) if (density <= 0)
{ {
throw new InternalExpressionException("Particle density should be positive"); throw new InternalExpressionException("Particle density should be positive");
} }
if (lv.size() > pos2.offset+1) if (lv.size() > pos2.offset+1)
{ {
Value playerValue = lv.get(pos2.offset+1).evalValue(c); Value playerValue = lv.get(pos2.offset+1);
if (playerValue instanceof EntityValue) if (playerValue instanceof EntityValue)
{ {
Entity e = ((EntityValue) playerValue).getEntity(); Entity e = ((EntityValue) playerValue).getEntity();
@@ -274,34 +265,33 @@ public class Auxiliary {
} }
} }
Value retval = new NumericValue(ShapeDispatcher.drawParticleLine( return new NumericValue(ShapeDispatcher.drawParticleLine(
(player == null)?world.getPlayers(): Collections.singletonList(player), (player == null)?world.getPlayers(): Collections.singletonList(player),
particle, pos1.vec, pos2.vec, density)); particle, pos1.vec, pos2.vec, density
));
return (c_, t_) -> retval;
}); });
expression.addLazyFunction("particle_box", -1, (c, t, lv) -> expression.addContextFunction("particle_box", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
String particleName = lv.get(0).evalValue(c).getString(); String particleName = lv.get(0).getString();
ParticleEffect particle = ShapeDispatcher.getParticleData(particleName); ParticleEffect particle = ShapeDispatcher.getParticleData(particleName);
Vector3Argument pos1 = Vector3Argument.findIn(cc, lv, 1); Vector3Argument pos1 = Vector3Argument.findIn(lv, 1);
Vector3Argument pos2 = Vector3Argument.findIn(cc, lv, pos1.offset); Vector3Argument pos2 = Vector3Argument.findIn(lv, pos1.offset);
double density = 1.0; double density = 1.0;
ServerPlayerEntity player = null; ServerPlayerEntity player = null;
if (lv.size() > pos2.offset+0 ) if (lv.size() > pos2.offset+0 )
{ {
density = NumericValue.asNumber(lv.get(pos2.offset+0).evalValue(c)).getDouble(); density = NumericValue.asNumber(lv.get(pos2.offset+0)).getDouble();
if (density <= 0) if (density <= 0)
{ {
throw new InternalExpressionException("Particle density should be positive"); throw new InternalExpressionException("Particle density should be positive");
} }
if (lv.size() > pos2.offset+1) if (lv.size() > pos2.offset+1)
{ {
Value playerValue = lv.get(pos2.offset+1).evalValue(c); Value playerValue = lv.get(pos2.offset+1);
if (playerValue instanceof EntityValue) if (playerValue instanceof EntityValue)
{ {
Entity e = ((EntityValue) playerValue).getEntity(); Entity e = ((EntityValue) playerValue).getEntity();
@@ -322,13 +312,13 @@ public class Auxiliary {
player==null?world.getPlayers():Collections.singletonList(player), player==null?world.getPlayers():Collections.singletonList(player),
particle, density, from, to particle, density, from, to
); );
return (c_, t_) -> new NumericValue(particleCount); return new NumericValue(particleCount);
}); });
// deprecated // deprecated
expression.alias("particle_rect", "particle_box"); expression.alias("particle_rect", "particle_box");
expression.addLazyFunction("draw_shape", -1, (c, t, lv) -> expression.addContextFunction("draw_shape", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
@@ -337,7 +327,7 @@ public class Auxiliary {
List<Pair<ShapeDispatcher.ExpiringShape, Map<String,Value>>> shapes = new ArrayList<>(); List<Pair<ShapeDispatcher.ExpiringShape, Map<String,Value>>> shapes = new ArrayList<>();
if (lv.size() == 1) // bulk if (lv.size() == 1) // bulk
{ {
Value specLoad = lv.get(0).evalValue(c); Value specLoad = lv.get(0);
if (!(specLoad instanceof ListValue)) throw new InternalExpressionException("In bulk mode - shapes need to be provided as a list of shape specs"); if (!(specLoad instanceof ListValue)) throw new InternalExpressionException("In bulk mode - shapes need to be provided as a list of shape specs");
for (Value list : ((ListValue) specLoad).getItems()) for (Value list : ((ListValue) specLoad).getItems())
{ {
@@ -347,19 +337,17 @@ public class Auxiliary {
} }
else else
{ {
List<Value> params = new ArrayList<>(); shapes.add(ShapeDispatcher.fromFunctionArgs(server, world, lv, player));
for (LazyValue v : lv) params.add(v.evalValue(c));
shapes.add(ShapeDispatcher.fromFunctionArgs(server, world, params, player));
} }
ShapeDispatcher.sendShape( ShapeDispatcher.sendShape(
(player[0]==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player[0]), (player[0]==null)?cc.s.getWorld().getPlayers():Collections.singletonList(player[0]),
shapes shapes
); );
return LazyValue.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("create_marker", -1, (c, t, lv) ->{ expression.addContextFunction("create_marker", -1, (c, t, lv) ->{
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
BlockState targetBlock = null; BlockState targetBlock = null;
Vector3Argument pointLocator; Vector3Argument pointLocator;
@@ -367,16 +355,16 @@ public class Auxiliary {
String name; String name;
try try
{ {
Value nameValue = lv.get(0).evalValue(c); Value nameValue = lv.get(0);
name = nameValue instanceof NullValue ? "" : nameValue.getString(); name = nameValue instanceof NullValue ? "" : nameValue.getString();
pointLocator = Vector3Argument.findIn(cc, lv, 1, true, false); pointLocator = Vector3Argument.findIn(lv, 1, true, false);
if (lv.size()>pointLocator.offset) if (lv.size()>pointLocator.offset)
{ {
BlockArgument blockLocator = BlockArgument.findIn(cc, lv, pointLocator.offset, true, true, false); BlockArgument blockLocator = BlockArgument.findIn(cc, lv, pointLocator.offset, true, true, false);
if (blockLocator.block != null) targetBlock = blockLocator.block.getBlockState(); if (blockLocator.block != null) targetBlock = blockLocator.block.getBlockState();
if (lv.size() > blockLocator.offset) if (lv.size() > blockLocator.offset)
{ {
interactable = lv.get(blockLocator.offset).evalValue(c, Context.BOOLEAN).getBoolean(); interactable = lv.get(blockLocator.offset).getBoolean();
} }
} }
} }
@@ -429,11 +417,10 @@ public class Auxiliary {
armorstand.setInvulnerable(true); armorstand.setInvulnerable(true);
armorstand.getDataTracker().set(ArmorStandEntity.ARMOR_STAND_FLAGS, (byte)(interactable?8 : 16|8)); armorstand.getDataTracker().set(ArmorStandEntity.ARMOR_STAND_FLAGS, (byte)(interactable?8 : 16|8));
cc.s.getWorld().spawnEntity(armorstand); cc.s.getWorld().spawnEntity(armorstand);
EntityValue result = new EntityValue(armorstand); return new EntityValue(armorstand);
return (_c, _t) -> result;
}); });
expression.addLazyFunction("remove_all_markers", 0, (c, t, lv) -> { expression.addContextFunction("remove_all_markers", 0, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
int total = 0; int total = 0;
String markerName = MARKER_STRING+"_"+((cc.host.getName()==null)?"":cc.host.getName()); String markerName = MARKER_STRING+"_"+((cc.host.getName()==null)?"":cc.host.getName());
@@ -442,34 +429,18 @@ public class Auxiliary {
total ++; total ++;
e.remove(); e.remove();
} }
int finalTotal = total; return new NumericValue(total);
return (_cc, _tt) -> new NumericValue(finalTotal);
}); });
expression.addLazyFunction("nbt", 1, (c, t, lv) -> { expression.addUnaryFunction("nbt", NBTSerializableValue::fromValue);
Value ret = NBTSerializableValue.fromValue(lv.get(0).evalValue(c));
return (cc, tt) -> ret;
});
expression.addLazyFunction("escape_nbt", 1, (c, t, lv) -> { expression.addUnaryFunction("escape_nbt", v -> new StringValue(StringTag.escape(v.getString())));
Value v = lv.get(0).evalValue(c);
String string = v.getString();
Value ret = new StringValue(StringTag.escape(string));
return (cc, tt) -> ret;
});
expression.addLazyFunction("parse_nbt", 1, (c, t, lv) -> { expression.addUnaryFunction("parse_nbt", v -> {
Value v = lv.get(0).evalValue(c); if (v instanceof NBTSerializableValue) return ((NBTSerializableValue) v).toValue();
if (v instanceof NBTSerializableValue)
{
Value parsed = ((NBTSerializableValue) v).toValue();
return (cc, tt) -> parsed;
}
NBTSerializableValue ret = NBTSerializableValue.parseString(v.getString(), false); NBTSerializableValue ret = NBTSerializableValue.parseString(v.getString(), false);
if (ret == null) if (ret == null) return Value.NULL;
return LazyValue.NULL; return ret.toValue();
Value parsed = ret.toValue();
return (cc, tt) -> parsed;
}); });
expression.addFunction("tag_matches", (lv) -> { expression.addFunction("tag_matches", (lv) -> {
@@ -482,11 +453,11 @@ public class Auxiliary {
return new NumericValue(NbtHelper.matches(match, source, numParam == 2 || lv.get(2).getBoolean())); return new NumericValue(NbtHelper.matches(match, source, numParam == 2 || lv.get(2).getBoolean()));
}); });
expression.addLazyFunction("encode_nbt", -1, (c, t, lv) -> { expression.addFunction("encode_nbt", lv -> {
int argSize = lv.size(); int argSize = lv.size();
if (argSize==0 || argSize > 2) throw new InternalExpressionException("'encode_nbt' requires 1 or 2 parameters"); if (argSize==0 || argSize > 2) throw new InternalExpressionException("'encode_nbt' requires 1 or 2 parameters");
Value v = lv.get(0).evalValue(c); Value v = lv.get(0);
boolean force = (argSize > 1) && lv.get(1).evalValue(c).getBoolean(); boolean force = (argSize > 1) && lv.get(1).getBoolean();
Tag tag; Tag tag;
try try
{ {
@@ -496,17 +467,16 @@ public class Auxiliary {
{ {
throw new InternalExpressionException("cannot reliably encode to a tag the value of '"+ignored.val.getPrettyString()+"'"); throw new InternalExpressionException("cannot reliably encode to a tag the value of '"+ignored.val.getPrettyString()+"'");
} }
Value tagValue = new NBTSerializableValue(tag); return new NBTSerializableValue(tag);
return (cc, tt) -> tagValue;
}); });
//"overridden" native call that prints to stderr //"overridden" native call that prints to stderr
expression.addLazyFunction("print", -1, (c, t, lv) -> expression.addContextFunction("print", -1, (c, t, lv) ->
{ {
if (lv.size() == 0 || lv.size() > 2) throw new InternalExpressionException("'print' takes one or two arguments"); if (lv.size() == 0 || lv.size() > 2) throw new InternalExpressionException("'print' takes one or two arguments");
ServerCommandSource s = ((CarpetContext)c).s; ServerCommandSource s = ((CarpetContext)c).s;
MinecraftServer server = s.getMinecraftServer(); MinecraftServer server = s.getMinecraftServer();
Value res = lv.get(0).evalValue(c); Value res = lv.get(0);
List<ServerPlayerEntity> targets = null; List<ServerPlayerEntity> targets = null;
if (lv.size() == 2) if (lv.size() == 2)
{ {
@@ -518,7 +488,7 @@ public class Auxiliary {
playerTargets.add(player); playerTargets.add(player);
}); });
targets = playerTargets; targets = playerTargets;
res = lv.get(1).evalValue(c); res = lv.get(1);
} }
Text message = FormattedTextValue.getTextByValue(res); Text message = FormattedTextValue.getTextByValue(res);
if (targets == null) if (targets == null)
@@ -529,12 +499,12 @@ public class Auxiliary {
{ {
targets.forEach(p -> p.getCommandSource().sendFeedback(message, false)); targets.forEach(p -> p.getCommandSource().sendFeedback(message, false));
} }
Value finalRes = res; return res; // pass through for variables
return (_c, _t) -> finalRes; // pass through for variables
}); });
expression.addLazyFunction("display_title", -1, (c, t, lv) -> {
expression.addContextFunction("display_title", -1, (c, t, lv) -> {
if (lv.size() < 2) throw new InternalExpressionException("'display_title' needs at least a target, type and message, and optionally times"); if (lv.size() < 2) throw new InternalExpressionException("'display_title' needs at least a target, type and message, and optionally times");
Value pVal = lv.get(0).evalValue(c); Value pVal = lv.get(0);
if (!(pVal instanceof ListValue)) pVal = ListValue.of(pVal); if (!(pVal instanceof ListValue)) pVal = ListValue.of(pVal);
MinecraftServer server = ((CarpetContext)c).s.getMinecraftServer(); MinecraftServer server = ((CarpetContext)c).s.getMinecraftServer();
Stream<ServerPlayerEntity> targets = ((ListValue) pVal).getItems().stream().map(v -> Stream<ServerPlayerEntity> targets = ((ListValue) pVal).getItems().stream().map(v ->
@@ -544,7 +514,7 @@ public class Auxiliary {
return player; return player;
}); });
TitleS2CPacket.Action action; TitleS2CPacket.Action action;
String actionString = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT); String actionString = lv.get(1).getString().toLowerCase(Locale.ROOT);
switch (actionString) switch (actionString)
{ {
case "title": case "title":
@@ -572,7 +542,7 @@ public class Auxiliary {
boolean soundsTrue = false; boolean soundsTrue = false;
if (lv.size() > 2) if (lv.size() > 2)
{ {
pVal = lv.get(2).evalValue(c); pVal = lv.get(2);
title = FormattedTextValue.getTextByValue(pVal); title = FormattedTextValue.getTextByValue(pVal);
soundsTrue = pVal.getBoolean(); soundsTrue = pVal.getBoolean();
} }
@@ -598,15 +568,15 @@ public class Auxiliary {
total.getAndIncrement(); total.getAndIncrement();
}); });
HUDController.update_hud(((CarpetContext)c).s.getMinecraftServer(), targetList); HUDController.update_hud(((CarpetContext)c).s.getMinecraftServer(), targetList);
Value ret = NumericValue.of(total.get()); return NumericValue.of(total.get());
return (cc, tt) -> ret;
} }
TitleS2CPacket timesPacket; TitleS2CPacket timesPacket;
if (lv.size() > 3) if (lv.size() > 3)
{ {
int in = NumericValue.asNumber(lv.get(3).evalValue(c),"fade in for display_title" ).getInt(); if (lv.size() != 6) throw new InternalExpressionException("'display_title' needs all fade-in, stay and fade-out times");
int stay = NumericValue.asNumber(lv.get(4).evalValue(c),"stay for display_title" ).getInt(); int in = NumericValue.asNumber(lv.get(3),"fade in for display_title" ).getInt();
int out = NumericValue.asNumber(lv.get(5).evalValue(c),"fade out for display_title" ).getInt(); int stay = NumericValue.asNumber(lv.get(4),"stay for display_title" ).getInt();
int out = NumericValue.asNumber(lv.get(5),"fade out for display_title" ).getInt();
timesPacket = new TitleS2CPacket(Action.TIMES, null, in, stay, out); timesPacket = new TitleS2CPacket(Action.TIMES, null, in, stay, out);
} }
else timesPacket = null; else timesPacket = null;
@@ -618,20 +588,17 @@ public class Auxiliary {
p.networkHandler.sendPacket(packet); p.networkHandler.sendPacket(packet);
total.getAndIncrement(); total.getAndIncrement();
}); });
Value ret = NumericValue.of(total.get()); return NumericValue.of(total.get());
return (cc, tt) -> ret;
}); });
expression.addLazyFunction("format", -1, (c, t, lv) -> { expression.addFunction("format", values -> {
if (lv.size() == 0 ) throw new InternalExpressionException("'format' requires at least one component"); if (values.size() == 0 ) throw new InternalExpressionException("'format' requires at least one component");
List<Value> values = lv.stream().map(lazy -> lazy.evalValue(c)).collect(Collectors.toList());
if (values.get(0) instanceof ListValue && values.size()==1) if (values.get(0) instanceof ListValue && values.size()==1)
values = ((ListValue) values.get(0)).getItems(); values = ((ListValue) values.get(0)).getItems();
Value ret = new FormattedTextValue(Messenger.c(values.stream().map(Value::getString).toArray())); return new FormattedTextValue(Messenger.c(values.stream().map(Value::getString).toArray()));
return (cc, tt) -> ret;
}); });
expression.addLazyFunction("run", 1, (c, t, lv) -> { expression.addContextFunction("run", 1, (c, t, lv) -> {
BlockPos target = ((CarpetContext)c).origin; BlockPos target = ((CarpetContext)c).origin;
Vec3d posf = new Vec3d((double)target.getX()+0.5D, target.getY(),(double)target.getZ()+0.5D); Vec3d posf = new Vec3d((double)target.getX()+0.5D, target.getY(),(double)target.getZ()+0.5D);
ServerCommandSource s = ((CarpetContext)c).s; ServerCommandSource s = ((CarpetContext)c).s;
@@ -641,56 +608,48 @@ public class Auxiliary {
List<Text> output = new ArrayList<>(); List<Text> output = new ArrayList<>();
Value retval = new NumericValue(s.getMinecraftServer().getCommandManager().execute( Value retval = new NumericValue(s.getMinecraftServer().getCommandManager().execute(
new SnoopyCommandSource(s, posf, error, output), new SnoopyCommandSource(s, posf, error, output),
lv.get(0).evalValue(c).getString()) lv.get(0).getString())
); );
Value ret = ListValue.of( return ListValue.of(
retval, retval,
ListValue.wrap(output.stream().map(FormattedTextValue::new).collect(Collectors.toList())), ListValue.wrap(output.stream().map(FormattedTextValue::new).collect(Collectors.toList())),
FormattedTextValue.of(error[0]) FormattedTextValue.of(error[0])
); );
return (c_, t_) -> ret;
} }
catch (Exception exc) catch (Exception exc)
{ {
Value ret = ListValue.of(Value.NULL, ListValue.of(), new FormattedTextValue(new LiteralText(exc.getMessage()))); return ListValue.of(Value.NULL, ListValue.of(), new FormattedTextValue(new LiteralText(exc.getMessage())));
return (c_, t_) -> ret;
} }
}); });
expression.addLazyFunction("save", 0, (c, t, lv) -> { expression.addContextFunction("save", 0, (c, t, lv) -> {
ServerCommandSource s = ((CarpetContext)c).s; ServerCommandSource s = ((CarpetContext)c).s;
s.getMinecraftServer().getPlayerManager().saveAllPlayerData(); s.getMinecraftServer().getPlayerManager().saveAllPlayerData();
s.getMinecraftServer().save(true,true,true); s.getMinecraftServer().save(true,true,true);
s.getWorld().getChunkManager().tick(() -> true); s.getWorld().getChunkManager().tick(() -> true);
CarpetSettings.LOG.warn("Saved chunks"); CarpetScriptServer.LOG.warn("Saved chunks");
return (cc, tt) -> Value.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("tick_time", 0, (c, t, lv) -> expression.addContextFunction("tick_time", 0, (c, t, lv) ->
{ new NumericValue(((CarpetContext) c).s.getMinecraftServer().getTicks()));
Value time = new NumericValue(((CarpetContext) c).s.getMinecraftServer().getTicks());
return (cc, tt) -> time;
});
expression.addLazyFunction("world_time", 0, (c, t, lv) -> expression.addContextFunction("world_time", 0, (c, t, lv) ->
{ new NumericValue(((CarpetContext) c).s.getWorld().getTime()));
Value time = new NumericValue(((CarpetContext) c).s.getWorld().getTime());
return (cc, tt) -> time;
});
expression.addLazyFunction("day_time", -1, (c, t, lv) -> expression.addContextFunction("day_time", -1, (c, t, lv) ->
{ {
Value time = new NumericValue(((CarpetContext) c).s.getWorld().getTimeOfDay()); Value time = new NumericValue(((CarpetContext) c).s.getWorld().getTimeOfDay());
if (lv.size() > 0) if (lv.size() > 0)
{ {
long newTime = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong(); long newTime = NumericValue.asNumber(lv.get(0)).getLong();
if (newTime < 0) newTime = 0; if (newTime < 0) newTime = 0;
((CarpetContext) c).s.getWorld().setTimeOfDay(newTime);// setTimeOfDay(newTime); ((CarpetContext) c).s.getWorld().setTimeOfDay(newTime);// setTimeOfDay(newTime);
} }
return (cc, tt) -> time; return time;
}); });
expression.addLazyFunction("last_tick_times", -1, (c, t, lv) -> expression.addContextFunction("last_tick_times", -1, (c, t, lv) ->
{ {
//assuming we are in the tick world section //assuming we are in the tick world section
// might be off one tick when run in the off tasks or asynchronously. // might be off one tick when run in the off tasks or asynchronously.
@@ -701,12 +660,11 @@ public class Auxiliary {
{ {
ticks.add(new NumericValue(((double)tickArray[i % 100])/1000000.0)); ticks.add(new NumericValue(((double)tickArray[i % 100])/1000000.0));
} }
Value ret = ListValue.wrap(ticks); return ListValue.wrap(ticks);
return (cc, tt) -> ret;
}); });
expression.addLazyFunction("game_tick", -1, (c, t, lv) -> { expression.addContextFunction("game_tick", -1, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerCommandSource s = cc.s; ServerCommandSource s = cc.s;
if (!s.getMinecraftServer().isOnThread()) throw new InternalExpressionException("Unable to run ticks from threads"); if (!s.getMinecraftServer().isOnThread()) throw new InternalExpressionException("Unable to run ticks from threads");
@@ -717,7 +675,7 @@ public class Auxiliary {
((MinecraftServerInterface) s.getMinecraftServer()).forceTick(() -> System.nanoTime() - CarpetServer.scriptServer.tickStart < 50000000L); ((MinecraftServerInterface) s.getMinecraftServer()).forceTick(() -> System.nanoTime() - CarpetServer.scriptServer.tickStart < 50000000L);
if (lv.size() > 0) if (lv.size() > 0)
{ {
long ms_total = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong(); long ms_total = NumericValue.asNumber(lv.get(0)).getLong();
long end_expected = CarpetServer.scriptServer.tickStart + ms_total * 1000000L; long end_expected = CarpetServer.scriptServer.tickStart + ms_total * 1000000L;
long wait = end_expected - System.nanoTime(); long wait = end_expected - System.nanoTime();
if (wait > 0L) if (wait > 0L)
@@ -740,17 +698,16 @@ public class Auxiliary {
} }
if(CarpetServer.scriptServer.stopAll) if(CarpetServer.scriptServer.stopAll)
throw new ExitStatement(Value.NULL); throw new ExitStatement(Value.NULL);
return (_c, _t) -> Value.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("seed", -1, (c, t, lv) -> { expression.addContextFunction("seed", -1, (c, t, lv) -> {
ServerCommandSource s = ((CarpetContext)c).s; ServerCommandSource s = ((CarpetContext)c).s;
c.host.issueDeprecation("seed()"); c.host.issueDeprecation("seed()");
Value ret = new NumericValue(s.getWorld().getSeed()); return new NumericValue(s.getWorld().getSeed());
return (cc, tt) -> ret;
}); });
expression.addLazyFunction("relight", -1, (c, t, lv) -> expression.addContextFunction("relight", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
BlockArgument locator = BlockArgument.findIn(cc, lv, 0); BlockArgument locator = BlockArgument.findIn(cc, lv, 0);
@@ -758,21 +715,16 @@ public class Auxiliary {
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
((ThreadedAnvilChunkStorageInterface) world.getChunkManager().threadedAnvilChunkStorage).relightChunk(new ChunkPos(pos)); ((ThreadedAnvilChunkStorageInterface) world.getChunkManager().threadedAnvilChunkStorage).relightChunk(new ChunkPos(pos));
WorldTools.forceChunkUpdate(pos, world); WorldTools.forceChunkUpdate(pos, world);
return LazyValue.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("current_dimension", 0, (c, t, lv) -> { expression.addContextFunction("current_dimension", 0, (c, t, lv) ->
ServerCommandSource s = ((CarpetContext)c).s; ValueConversions.of( ((CarpetContext)c).s.getWorld()));
Value retval = ValueConversions.of(s.getWorld());
return (cc, tt) -> retval;
});
expression.addLazyFunction("view_distance", 0, (c, t, lv) -> { expression.addContextFunction("view_distance", 0, (c, t, lv) ->
ServerCommandSource s = ((CarpetContext)c).s; new NumericValue(((CarpetContext)c).s.getMinecraftServer().getPlayerManager().getViewDistance()));
Value retval = new NumericValue(s.getMinecraftServer().getPlayerManager().getViewDistance());
return (cc, tt) -> retval;
});
// lazy due to passthrough and context changing ability
expression.addLazyFunction("in_dimension", 2, (c, t, lv) -> { expression.addLazyFunction("in_dimension", 2, (c, t, lv) -> {
ServerCommandSource outerSource = ((CarpetContext)c).s; ServerCommandSource outerSource = ((CarpetContext)c).s;
Value dimensionValue = lv.get(0).evalValue(c); Value dimensionValue = lv.get(0).evalValue(c);
@@ -786,7 +738,7 @@ public class Auxiliary {
return (cc, tt) -> retval; return (cc, tt) -> retval;
}); });
expression.addLazyFunction("plop", -1, (c, t, lv) ->{ expression.addContextFunction("plop", -1, (c, t, lv) ->{
if (lv.size() == 0) if (lv.size() == 0)
{ {
Map<Value, Value> plopData = new HashMap<>(); Map<Value, Value> plopData = new HashMap<>();
@@ -807,13 +759,12 @@ public class Auxiliary {
plopData.put(StringValue.of("configured_structures"), plopData.put(StringValue.of("configured_structures"),
ListValue.wrap(registryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_WORLDGEN).getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList())) ListValue.wrap(registryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_WORLDGEN).getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList()))
); );
Value ret = MapValue.wrap(plopData); return MapValue.wrap(plopData);
return (_c, _t) -> ret;
} }
BlockArgument locator = BlockArgument.findIn((CarpetContext)c, lv, 0); BlockArgument locator = BlockArgument.findIn((CarpetContext)c, lv, 0);
if (lv.size() <= locator.offset) if (lv.size() <= locator.offset)
throw new InternalExpressionException("'plop' needs extra argument indicating what to plop"); throw new InternalExpressionException("'plop' needs extra argument indicating what to plop");
String what = lv.get(locator.offset).evalValue(c).getString(); String what = lv.get(locator.offset).getString();
Value [] result = new Value[]{Value.NULL}; Value [] result = new Value[]{Value.NULL};
((CarpetContext)c).s.getMinecraftServer().submitAndJoin( () -> ((CarpetContext)c).s.getMinecraftServer().submitAndJoin( () ->
{ {
@@ -825,71 +776,67 @@ public class Auxiliary {
WorldTools.forceChunkUpdate(locator.block.getPos(), ((CarpetContext) c).s.getWorld()); WorldTools.forceChunkUpdate(locator.block.getPos(), ((CarpetContext) c).s.getWorld());
result[0] = new NumericValue(res); result[0] = new NumericValue(res);
}); });
Value ret = result[0]; // preventing from lazy evaluating of the result in case a future completes later return result[0];
return (_c, _t) -> ret;
}); });
expression.addLazyFunction("schedule", -1, (c, t, lv) -> { expression.addContextFunction("schedule", -1, (c, t, lv) -> {
if (lv.size()<2) if (lv.size()<2)
throw new InternalExpressionException("'schedule' should have at least 2 arguments, delay and call name"); throw new InternalExpressionException("'schedule' should have at least 2 arguments, delay and call name");
long delay = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong(); long delay = NumericValue.asNumber(lv.get(0)).getLong();
FunctionArgument<LazyValue> functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, false);
CarpetServer.scriptServer.events.scheduleCall( CarpetServer.scriptServer.events.scheduleCall(
(CarpetContext) c, (CarpetContext) c,
functionArgument.function, functionArgument.function,
FunctionValue.resolveArgs(functionArgument.args, c, t), functionArgument.checkedArgs(),
delay delay
); );
return (c_, t_) -> Value.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("logger", -1, (c, t, lv) -> expression.addFunction("logger", lv ->
{ {
//CarpetSettings.LOG.error(Registry.ENTITY_TYPE.getIds().stream().sorted().map(ValueConversions::simplify).collect(Collectors.joining("`, `")));
Value res; Value res;
if(lv.size()==1) if(lv.size()==1)
{ {
res = lv.get(0).evalValue(c); res = lv.get(0);
CarpetSettings.LOG.info(res.getString()); CarpetScriptServer.LOG.info(res.getString());
} }
else if(lv.size()==2) else if(lv.size()==2)
{ {
String level = lv.get(0).evalValue(c).getString().toLowerCase(Locale.ROOT); String level = lv.get(0).getString().toLowerCase(Locale.ROOT);
res = lv.get(1).evalValue(c); res = lv.get(1);
switch(level){ switch(level){
case "error": CarpetSettings.LOG.error(res.getString()); break; case "error": CarpetScriptServer.LOG.error(res.getString()); break;
case "warn": CarpetSettings.LOG.warn(res.getString()); break; case "warn": CarpetScriptServer.LOG.warn(res.getString()); break;
case "debug": CarpetSettings.LOG.debug(res.getString()); break; case "debug": CarpetScriptServer.LOG.debug(res.getString()); break;
case "fatal": CarpetSettings.LOG.fatal(res.getString()); break; case "fatal": CarpetScriptServer.LOG.fatal(res.getString()); break;
case "info": CarpetSettings.LOG.info(res.getString()); break; case "info": CarpetScriptServer.LOG.info(res.getString()); break;
default: throw new InternalExpressionException("Unknown log level for 'logger': "+level); default: throw new InternalExpressionException("Unknown log level for 'logger': "+level);
} }
} }
else throw new InternalExpressionException("logger takes 1 or 2 arguments"); else throw new InternalExpressionException("logger takes 1 or 2 arguments");
return (_c, _t) -> res; // pass through for variables return res; // pass through for variables
}); });
expression.addLazyFunction("list_files", 2, (c, t, lv) -> expression.addContextFunction("list_files", 2, (c, t, lv) ->
{ {
FileArgument fdesc = FileArgument.from(lv, c, true, FileArgument.Reason.READ); FileArgument fdesc = FileArgument.from(lv,true, FileArgument.Reason.READ);
Stream<String> files = ((CarpetScriptHost) c.host).listFolder(fdesc); Stream<String> files = ((CarpetScriptHost) c.host).listFolder(fdesc);
if (files == null) return LazyValue.NULL; if (files == null) return Value.NULL;
Value ret = ListValue.wrap(files.map(StringValue::of).collect(Collectors.toList())); return ListValue.wrap(files.map(StringValue::of).collect(Collectors.toList()));
return (cc, tt) -> ret;
}); });
expression.addLazyFunction("read_file", 2, (c, t, lv) -> expression.addContextFunction("read_file", 2, (c, t, lv) ->
{ {
FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.READ); FileArgument fdesc = FileArgument.from(lv,false, FileArgument.Reason.READ);
Value retVal; Value retVal;
if (fdesc.type == FileArgument.Type.NBT) if (fdesc.type == FileArgument.Type.NBT)
{ {
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc); Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc);
if (state == null) return LazyValue.NULL; if (state == null) return Value.NULL;
retVal = new NBTSerializableValue(state); retVal = new NBTSerializableValue(state);
} }
else if (fdesc.type == FileArgument.Type.JSON) else if (fdesc.type == FileArgument.Type.JSON)
@@ -905,25 +852,23 @@ public class Auxiliary {
else else
{ {
List<String> content = ((CarpetScriptHost) c.host).readTextResource(fdesc); List<String> content = ((CarpetScriptHost) c.host).readTextResource(fdesc);
if (content == null) return LazyValue.NULL; if (content == null) return Value.NULL;
retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList())); retVal = ListValue.wrap(content.stream().map(StringValue::new).collect(Collectors.toList()));
} }
return (cc, tt) -> retVal; return retVal;
}); });
expression.addLazyFunction("delete_file", 2, (c, t, lv) -> { expression.addContextFunction("delete_file", 2, (c, t, lv) ->
FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.DELETE); BooleanValue.of(((CarpetScriptHost) c.host).removeResourceFile(FileArgument.from(lv,false, FileArgument.Reason.DELETE))));
return ((CarpetScriptHost) c.host).removeResourceFile(fdesc) ? LazyValue.TRUE : LazyValue.FALSE;
});
expression.addLazyFunction("write_file", -1, (c, t, lv) -> { expression.addContextFunction("write_file", -1, (c, t, lv) -> {
if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments"); if (lv.size() < 3) throw new InternalExpressionException("'write_file' requires three or more arguments");
FileArgument fdesc = FileArgument.from(lv, c, false, FileArgument.Reason.CREATE); FileArgument fdesc = FileArgument.from(lv, false, FileArgument.Reason.CREATE);
boolean success; boolean success;
if (fdesc.type == FileArgument.Type.NBT) if (fdesc.type == FileArgument.Type.NBT)
{ {
Value val = lv.get(2).evalValue(c); Value val = lv.get(2);
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue) NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
? (NBTSerializableValue) val ? (NBTSerializableValue) val
: new NBTSerializableValue(val.getString()); : new NBTSerializableValue(val.getString());
@@ -932,7 +877,7 @@ public class Auxiliary {
} }
else if (fdesc.type == FileArgument.Type.JSON) else if (fdesc.type == FileArgument.Type.JSON)
{ {
List<String> data = Collections.singletonList(GSON.toJson(lv.get(2).evalValue(c).toJson())); List<String> data = Collections.singletonList(GSON.toJson(lv.get(2).toJson()));
((CarpetScriptHost) c.host).removeResourceFile(fdesc); ((CarpetScriptHost) c.host).removeResourceFile(fdesc);
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data); success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data);
} }
@@ -941,7 +886,7 @@ public class Auxiliary {
List<String> data = new ArrayList<>(); List<String> data = new ArrayList<>();
if (lv.size()==3) if (lv.size()==3)
{ {
Value val = lv.get(2).evalValue(c); Value val = lv.get(2);
if (val instanceof ListValue) if (val instanceof ListValue)
{ {
List<Value> lval = ((ListValue) val).getItems(); List<Value> lval = ((ListValue) val).getItems();
@@ -956,166 +901,144 @@ public class Auxiliary {
{ {
for(int i = 2; i < lv.size(); i++) for(int i = 2; i < lv.size(); i++)
{ {
data.add(lv.get(i).evalValue(c).getString()); data.add(lv.get(i).getString());
} }
} }
success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data); success = ((CarpetScriptHost) c.host).appendLogFile(fdesc, data);
} }
return success?LazyValue.TRUE:LazyValue.FALSE; return BooleanValue.of(success);
}); });
expression.addLazyFunction("load_app_data", -1, (c, t, lv) -> expression.addContextFunction("load_app_data", -1, (c, t, lv) ->
{ {
FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.READ); FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.READ);
if (lv.size()>0) if (lv.size()>0)
{ {
c.host.issueDeprecation("load_app_data(...) with arguments"); c.host.issueDeprecation("load_app_data(...) with arguments");
String resource = recognizeResource(lv.get(0).evalValue(c), false); String resource = recognizeResource(lv.get(0), false);
boolean shared = lv.size() > 1 && lv.get(1).evalValue(c).getBoolean(); boolean shared = lv.size() > 1 && lv.get(1).getBoolean();
fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.READ); fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.READ);
} }
Tag state = ((CarpetScriptHost) c.host).readFileTag(fdesc); return NBTSerializableValue.of(((CarpetScriptHost) c.host).readFileTag(fdesc));
if (state == null)
return (cc, tt) -> Value.NULL;
Value retVal = new NBTSerializableValue(state);
return (cc, tt) -> retVal;
}); });
expression.addLazyFunction("store_app_data", -1, (c, t, lv) -> expression.addContextFunction("store_app_data", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
throw new InternalExpressionException("'store_app_data' needs NBT tag and an optional file"); throw new InternalExpressionException("'store_app_data' needs NBT tag and an optional file");
Value val = lv.get(0).evalValue(c); Value val = lv.get(0);
FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.CREATE); FileArgument fdesc = new FileArgument(null, FileArgument.Type.NBT, null, false, false, FileArgument.Reason.CREATE);
if (lv.size()>1) if (lv.size()>1)
{ {
c.host.issueDeprecation("store_app_data(...) with more than one argument"); c.host.issueDeprecation("store_app_data(...) with more than one argument");
String resource = recognizeResource(lv.get(1).evalValue(c), false); String resource = recognizeResource(lv.get(1), false);
boolean shared = lv.size() > 2 && lv.get(2).evalValue(c).getBoolean(); boolean shared = lv.size() > 2 && lv.get(2).getBoolean();
fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.CREATE); fdesc = new FileArgument(resource, FileArgument.Type.NBT, null, false, shared, FileArgument.Reason.CREATE);
} }
NBTSerializableValue tagValue = (val instanceof NBTSerializableValue) NBTSerializableValue tagValue = (val instanceof NBTSerializableValue)
? (NBTSerializableValue) val ? (NBTSerializableValue) val
: new NBTSerializableValue(val.getString()); : new NBTSerializableValue(val.getString());
Tag tag = tagValue.getTag(); return BooleanValue.of(((CarpetScriptHost) c.host).writeTagFile(tagValue.getTag(), fdesc));
boolean success = ((CarpetScriptHost) c.host).writeTagFile(tag, fdesc);
return success?LazyValue.TRUE:LazyValue.FALSE;
}); });
expression.addLazyFunction("statistic", 3, (c, t, lv) -> expression.addContextFunction("statistic", 3, (c, t, lv) ->
{ {
Value playerValue = lv.get(0).evalValue(c);
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerPlayerEntity player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), playerValue); ServerPlayerEntity player = EntityValue.getPlayerByValue(cc.s.getMinecraftServer(), lv.get(0));
if (player == null) return LazyValue.NULL; if (player == null) return Value.NULL;
Identifier category; Identifier category;
Identifier statName; Identifier statName;
try try
{ {
category = new Identifier(lv.get(1).evalValue(c).getString()); category = new Identifier(lv.get(1).getString());
statName = new Identifier(lv.get(2).evalValue(c).getString()); statName = new Identifier(lv.get(2).getString());
} }
catch (InvalidIdentifierException e) catch (InvalidIdentifierException e)
{ {
return LazyValue.NULL; return Value.NULL;
} }
StatType<?> type = Registry.STAT_TYPE.get(category); StatType<?> type = Registry.STAT_TYPE.get(category);
if (type == null) if (type == null) return Value.NULL;
return LazyValue.NULL;
Stat<?> stat = getStat(type, statName); Stat<?> stat = getStat(type, statName);
if (stat == null) if (stat == null) return Value.NULL;
return LazyValue.NULL; return new NumericValue(player.getStatHandler().getStat(stat));
return (_c, _t) -> new NumericValue(player.getStatHandler().getStat(stat));
}); });
//handle_event('event', function...) //handle_event('event', function...)
expression.addLazyFunction("handle_event", -1, (c, t, lv) -> expression.addContextFunction("handle_event", -1, (c, t, lv) ->
{ {
if (lv.size() < 2) if (lv.size() < 2)
throw new InternalExpressionException("'handle_event' requires at least two arguments, event name, and a callback"); throw new InternalExpressionException("'handle_event' requires at least two arguments, event name, and a callback");
String event = lv.get(0).evalValue(c).getString(); String event = lv.get(0).getString();
FunctionArgument<LazyValue> callback = FunctionArgument.findIn(c, expression.module, lv, 1, true, false); FunctionArgument callback = FunctionArgument.findIn(c, expression.module, lv, 1, true, false);
CarpetScriptHost host = ((CarpetScriptHost)c.host); CarpetScriptHost host = ((CarpetScriptHost)c.host);
Value success;
if (callback.function == null) if (callback.function == null)
{ return BooleanValue.of(host.getScriptServer().events.removeBuiltInEvent(event, host));
success = host.getScriptServer().events.removeBuiltInEvent(event, host)?Value.TRUE:Value.FALSE; // args don't need to be checked will be checked at the event
} return BooleanValue.of( host.getScriptServer().events.handleCustomEvent(event, host, callback.function, callback.args ));
else
{
success = host.getScriptServer().events.handleCustomEvent(event, host, callback.function, FunctionValue.resolveArgs(callback.args, c, t) )?Value.TRUE:Value.FALSE;
}
return (cc, tt) -> success;
}); });
//signal_event('event', player or null, args.... ) -> number of apps notified //signal_event('event', player or null, args.... ) -> number of apps notified
expression.addLazyFunction("signal_event", -1, (c, t, lv) -> expression.addContextFunction("signal_event", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
throw new InternalExpressionException("'signal' requires at least one argument"); throw new InternalExpressionException("'signal' requires at least one argument");
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
CarpetScriptServer server = ((CarpetScriptHost)c.host).getScriptServer(); CarpetScriptServer server = ((CarpetScriptHost)c.host).getScriptServer();
String eventName = lv.get(0).evalValue(c).getString(); String eventName = lv.get(0).getString();
// no such event yet // no such event yet
if (CarpetEventServer.Event.getEvent(eventName, server) == null) return LazyValue.NULL; if (CarpetEventServer.Event.getEvent(eventName, server) == null) return Value.NULL;
ServerPlayerEntity player = null; ServerPlayerEntity player = null;
List<Value> args = Collections.emptyList(); List<Value> args = Collections.emptyList();
if (lv.size() > 1) if (lv.size() > 1)
{ {
player = EntityValue.getPlayerByValue(server.server, lv.get(1).evalValue(c)); player = EntityValue.getPlayerByValue(server.server, lv.get(1));
if (lv.size() > 2) if (lv.size() > 2) args = lv.subList(2, lv.size());
{
args = FunctionValue.resolveArgs(lv.subList(2, lv.size()), c, t);
}
} }
int counts = ((CarpetScriptHost)c.host).getScriptServer().events.signalEvent(eventName, cc, player, args); int counts = ((CarpetScriptHost)c.host).getScriptServer().events.signalEvent(eventName, cc, player, args);
if (counts < 0) return LazyValue.NULL; if (counts < 0) return Value.NULL;
Value ret = new NumericValue(counts); return new NumericValue(counts);
return (c_, t_) -> ret;
}); });
// nbt_storage() // nbt_storage()
// nbt_storage(key) // nbt_storage(key)
// nbt_storage(key, nbt) // nbt_storage(key, nbt)
expression.addLazyFunction("nbt_storage", -1, (c, t, lv) -> { expression.addContextFunction("nbt_storage", -1, (c, t, lv) -> {
if (lv.size() > 2) throw new InternalExpressionException("'nbt_storage' requires 0, 1 or 2 arguments."); if (lv.size() > 2) throw new InternalExpressionException("'nbt_storage' requires 0, 1 or 2 arguments.");
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
DataCommandStorage storage = cc.s.getMinecraftServer().getDataCommandStorage(); DataCommandStorage storage = cc.s.getMinecraftServer().getDataCommandStorage();
if (lv.size() == 0) { if (lv.size() == 0)
Value ret = ListValue.wrap(storage.getIds().map(i -> new StringValue(nameFromRegistryId(i))).collect(Collectors.toList())); return ListValue.wrap(storage.getIds().map(i -> new StringValue(nameFromRegistryId(i))).collect(Collectors.toList()));
return (_c, _t) -> ret; String key = lv.get(0).getString();
}
String key = lv.get(0).evalValue(c).getString();
CompoundTag old_nbt = storage.get(new Identifier(key)); CompoundTag old_nbt = storage.get(new Identifier(key));
if (lv.size() == 2) { if (lv.size() == 2) {
Value nbt = lv.get(1).evalValue(c); Value nbt = lv.get(1);
NBTSerializableValue new_nbt = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt NBTSerializableValue new_nbt = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt
: NBTSerializableValue.parseString(nbt.getString(), true); : NBTSerializableValue.parseString(nbt.getString(), true);
storage.set(new Identifier(key), new_nbt.getCompoundTag()); storage.set(new Identifier(key), new_nbt.getCompoundTag());
} }
if (old_nbt == null) return LazyValue.NULL; return NBTSerializableValue.of(old_nbt);
return (_c, _t) -> new NBTSerializableValue(old_nbt);
}); });
// script run create_datapack('foo', {'foo' -> {'bar.json' -> {'c' -> true,'d' -> false,'e' -> {'foo' -> [1,2,3]},'a' -> 'foobar','b' -> 5}}}) // script run create_datapack('foo', {'foo' -> {'bar.json' -> {'c' -> true,'d' -> false,'e' -> {'foo' -> [1,2,3]},'a' -> 'foobar','b' -> 5}}})
expression.addLazyFunction("create_datapack", 2, (c, t, lv) -> { expression.addContextFunction("create_datapack", 2, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
String origName = lv.get(0).evalValue(c).getString(); String origName = lv.get(0).getString();
String name = InputValidator.validateSimpleString(origName, true); String name = InputValidator.validateSimpleString(origName, true);
MinecraftServer server = cc.s.getMinecraftServer(); MinecraftServer server = cc.s.getMinecraftServer();
for (String dpName : server.getDataPackManager().getNames()) for (String dpName : server.getDataPackManager().getNames())
{ {
if (dpName.equalsIgnoreCase("file/"+name+".zip") || if (dpName.equalsIgnoreCase("file/"+name+".zip") ||
dpName.equalsIgnoreCase("file/"+name)) dpName.equalsIgnoreCase("file/"+name))
return LazyValue.NULL; return Value.NULL;
} }
Value dpdata = lv.get(1).evalValue(c); Value dpdata = lv.get(1);
if (!(dpdata instanceof MapValue)) if (!(dpdata instanceof MapValue))
throw new InternalExpressionException("datapack data needs to be a valid map type"); throw new InternalExpressionException("datapack data needs to be a valid map type");
ResourcePackManager packManager = server.getDataPackManager(); ResourcePackManager packManager = server.getDataPackManager();
Path dbFloder = server.getSavePath(WorldSavePath.DATAPACKS); Path dbFloder = server.getSavePath(WorldSavePath.DATAPACKS);
Path packFloder = dbFloder.resolve(name+".zip"); Path packFloder = dbFloder.resolve(name+".zip");
if (Files.exists(packFloder) || Files.exists(dbFloder.resolve(name))) return LazyValue.NULL; if (Files.exists(packFloder) || Files.exists(dbFloder.resolve(name))) return Value.NULL;
Boolean [] successful = new Boolean[]{true}; Boolean [] successful = new Boolean[]{true};
server.submitAndJoin( () -> server.submitAndJoin( () ->
{ {
@@ -1160,10 +1083,10 @@ public class Auxiliary {
} }
}); });
return successful[0]?LazyValue.TRUE:LazyValue.FALSE; return BooleanValue.of(successful[0]);
}); });
expression.addLazyFunction("enable_hidden_dimensions", 0, (c, t, lv) -> { expression.addContextFunction("enable_hidden_dimensions", 0, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
// from minecraft.server.Main.main // from minecraft.server.Main.main
MinecraftServer server = cc.s.getMinecraftServer(); MinecraftServer server = cc.s.getMinecraftServer();
@@ -1183,7 +1106,7 @@ public class Auxiliary {
RegistryOps<Tag> registryOps = RegistryOps.of(NbtOps.INSTANCE, serverRM.getResourceManager(), (DynamicRegistryManager.Impl) server.getRegistryManager()); RegistryOps<Tag> registryOps = RegistryOps.of(NbtOps.INSTANCE, serverRM.getResourceManager(), (DynamicRegistryManager.Impl) server.getRegistryManager());
SaveProperties saveProperties = session.readLevelProperties(registryOps, dataPackSettings2); SaveProperties saveProperties = session.readLevelProperties(registryOps, dataPackSettings2);
if (saveProperties == null) return LazyValue.NULL; if (saveProperties == null) return Value.NULL;
//session.backupLevelDataFile(server.getRegistryManager(), saveProperties); // no need //session.backupLevelDataFile(server.getRegistryManager(), saveProperties); // no need
// MinecraftServer.createWorlds // MinecraftServer.createWorlds
@@ -1208,8 +1131,7 @@ public class Auxiliary {
existing_worlds.put(registryKey2, serverWorld2); existing_worlds.put(registryKey2, serverWorld2);
} }
} }
Value ret = ListValue.wrap(addeds); return ListValue.wrap(addeds);
return (_c, _t) -> ret;
}); });
} }
@@ -1266,8 +1188,6 @@ public class Auxiliary {
} }
} }
private static <T> Stat<T> getStat(StatType<T> type, Identifier id) private static <T> Stat<T> getStat(StatType<T> type, Identifier id)
{ {
T key = type.getRegistry().get(id); T key = type.getRegistry().get(id);
@@ -3,6 +3,7 @@ package carpet.script.api;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.Context; import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.Fluff;
import carpet.script.LazyValue; import carpet.script.LazyValue;
import carpet.script.argument.BlockArgument; import carpet.script.argument.BlockArgument;
import carpet.script.argument.Vector3Argument; import carpet.script.argument.Vector3Argument;
@@ -30,11 +31,14 @@ import static java.lang.Math.min;
public class BlockIterators { public class BlockIterators {
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunction("scan", -1, (c, t, lv) -> // lazy cause of lazy expression
expression.addLazyFunction("scan", -1, (c, t, llv) ->
{ {
if (llv.size() < 3) throw new InternalExpressionException("'scan' needs many more arguments");
List<Value> lv = Fluff.AbstractFunction.unpackLazy(llv.subList(0, llv.size()-1), c, Context.NONE);
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
BlockArgument centerLocator = BlockArgument.findIn(cc, lv, 0); BlockArgument centerLocator = BlockArgument.findIn(cc, lv, 0);
Vector3Argument rangeLocator = Vector3Argument.findIn(cc, lv, centerLocator.offset); Vector3Argument rangeLocator = Vector3Argument.findIn(lv, centerLocator.offset);
BlockPos center = centerLocator.block.getPos(); BlockPos center = centerLocator.block.getPos();
Vec3i range; Vec3i range;
@@ -54,7 +58,7 @@ public class BlockIterators {
Vec3i upperRange = range; Vec3i upperRange = range;
if (lv.size() > rangeLocator.offset+1) // +1 cause we still need the expression if (lv.size() > rangeLocator.offset+1) // +1 cause we still need the expression
{ {
rangeLocator = Vector3Argument.findIn(cc, lv, rangeLocator.offset); rangeLocator = Vector3Argument.findIn(lv, rangeLocator.offset);
if (rangeLocator.fromBlock) if (rangeLocator.fromBlock)
{ {
upperRange = new Vec3i( upperRange = new Vec3i(
@@ -69,11 +73,11 @@ public class BlockIterators {
upperRange = new Vec3i(abs(rangeLocator.vec.x), abs(rangeLocator.vec.y), abs(rangeLocator.vec.z)); upperRange = new Vec3i(abs(rangeLocator.vec.x), abs(rangeLocator.vec.y), abs(rangeLocator.vec.z));
} }
} }
if (lv.size() != rangeLocator.offset+1) if (llv.size() != rangeLocator.offset+1)
{ {
throw new InternalExpressionException("'scan' takes two, or three block positions, and an expression: "+lv.size()+" "+rangeLocator.offset); throw new InternalExpressionException("'scan' takes two, or three block positions, and an expression: "+lv.size()+" "+rangeLocator.offset);
} }
LazyValue expr = lv.get(rangeLocator.offset); LazyValue expr = llv.get(rangeLocator.offset);
int cx = center.getX(); int cx = center.getX();
int cy = center.getY(); int cy = center.getY();
@@ -135,9 +139,12 @@ public class BlockIterators {
return (c_, t_) -> new NumericValue(finalSCount); return (c_, t_) -> new NumericValue(finalSCount);
}); });
expression.addLazyFunction("volume", -1, (c, t, lv) -> // must be lazy
expression.addLazyFunction("volume", -1, (c, t, llv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
if (llv.size() < 3) throw new InternalExpressionException("'volume' needs many more arguments");
List<Value> lv = Fluff.AbstractFunction.unpackLazy(llv.subList(0, llv.size()-1), c, Context.NONE);
BlockArgument pos1Locator = BlockArgument.findIn(cc, lv, 0); BlockArgument pos1Locator = BlockArgument.findIn(cc, lv, 0);
BlockArgument pos2Locator = BlockArgument.findIn(cc, lv, pos1Locator.offset); BlockArgument pos2Locator = BlockArgument.findIn(cc, lv, pos1Locator.offset);
@@ -156,7 +163,7 @@ public class BlockIterators {
int maxx = max(x1, x2); int maxx = max(x1, x2);
int maxy = max(y1, y2); int maxy = max(y1, y2);
int maxz = max(z1, z2); int maxz = max(z1, z2);
LazyValue expr = lv.get(pos2Locator.offset); LazyValue expr = llv.get(pos2Locator.offset);
//saving outer scope //saving outer scope
LazyValue _x = c.getVariable("_x"); LazyValue _x = c.getVariable("_x");
@@ -207,9 +214,8 @@ public class BlockIterators {
return (c_, t_) -> new NumericValue(finalSCount); return (c_, t_) -> new NumericValue(finalSCount);
}); });
expression.addLazyFunction("neighbours", -1, (c, t, lv)-> expression.addContextFunction("neighbours", -1, (c, t, lv)->
{ {
BlockPos center = BlockArgument.findIn((CarpetContext) c, lv,0).block.getPos(); BlockPos center = BlockArgument.findIn((CarpetContext) c, lv,0).block.getPos();
ServerWorld world = ((CarpetContext) c).s.getWorld(); ServerWorld world = ((CarpetContext) c).s.getWorld();
@@ -220,11 +226,10 @@ public class BlockIterators {
neighbours.add(new BlockValue(null, world, center.south())); neighbours.add(new BlockValue(null, world, center.south()));
neighbours.add(new BlockValue(null, world, center.east())); neighbours.add(new BlockValue(null, world, center.east()));
neighbours.add(new BlockValue(null, world, center.west())); neighbours.add(new BlockValue(null, world, center.west()));
Value retval = ListValue.wrap(neighbours); return ListValue.wrap(neighbours);
return (c_, t_) -> retval;
}); });
expression.addLazyFunction("rect", -1, (c, t, lv)-> expression.addContextFunction("rect", -1, (c, t, lv)->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
int cx, cy, cz; int cx, cy, cz;
@@ -237,7 +242,7 @@ public class BlockIterators {
cz = cpos.getZ(); cz = cpos.getZ();
if (lv.size() > cposLocator.offset) if (lv.size() > cposLocator.offset)
{ {
Vector3Argument diffLocator = Vector3Argument.findIn(cc, lv, cposLocator.offset); Vector3Argument diffLocator = Vector3Argument.findIn(lv, cposLocator.offset);
if (diffLocator.fromBlock) if (diffLocator.fromBlock)
{ {
sminx = MathHelper.floor(abs(diffLocator.vec.x - cx)); sminx = MathHelper.floor(abs(diffLocator.vec.x - cx));
@@ -252,7 +257,7 @@ public class BlockIterators {
} }
if (lv.size() > diffLocator.offset) if (lv.size() > diffLocator.offset)
{ {
Vector3Argument posDiff = Vector3Argument.findIn(cc, lv, diffLocator.offset); Vector3Argument posDiff = Vector3Argument.findIn(lv, diffLocator.offset);
if (posDiff.fromBlock) if (posDiff.fromBlock)
{ {
smaxx = MathHelper.floor(abs(posDiff.vec.x - cx)); smaxx = MathHelper.floor(abs(posDiff.vec.x - cx));
@@ -283,7 +288,7 @@ public class BlockIterators {
smaxz = 1; smaxz = 1;
} }
return (c_, t_) -> new LazyListValue() return new LazyListValue()
{ {
final int minx = cx-sminx; final int minx = cx-sminx;
final int miny = cy-sminy; final int miny = cy-sminy;
@@ -348,7 +353,7 @@ public class BlockIterators {
}; };
}); });
expression.addLazyFunction("diamond", -1, (c, t, lv)-> expression.addContextFunction("diamond", -1, (c, t, lv)->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
@@ -377,17 +382,17 @@ public class BlockIterators {
BlockValue.fromCoords(cc, cx, cy, cz+1), BlockValue.fromCoords(cc, cx, cy, cz+1),
BlockValue.fromCoords(cc, cx, cy+1, cz) BlockValue.fromCoords(cc, cx, cy+1, cz)
); );
return (_c, _t ) -> retval; return retval;
} }
else if (lv.size()==1+cposLocator.offset) else if (lv.size()==1+cposLocator.offset)
{ {
width = (int) ((NumericValue) lv.get(cposLocator.offset).evalValue(c)).getLong(); width = (int) ((NumericValue) lv.get(cposLocator.offset)).getLong();
height = 0; height = 0;
} }
else if(lv.size()==2+cposLocator.offset) else if(lv.size()==2+cposLocator.offset)
{ {
width = (int) ((NumericValue) lv.get(cposLocator.offset).evalValue(c)).getLong(); width = (int) ((NumericValue) lv.get(cposLocator.offset)).getLong();
height = (int) ((NumericValue) lv.get(cposLocator.offset+1).evalValue(c)).getLong(); height = (int) ((NumericValue) lv.get(cposLocator.offset+1)).getLong();
} else{ } else{
throw new InternalExpressionException("Incorrect number of arguments for 'diamond'"); throw new InternalExpressionException("Incorrect number of arguments for 'diamond'");
} }
@@ -398,7 +403,7 @@ public class BlockIterators {
} }
if (height == 0) if (height == 0)
{ {
return (c_, t_) -> new LazyListValue() return new LazyListValue()
{ {
int curradius; int curradius;
int curpos; int curpos;
@@ -448,7 +453,7 @@ public class BlockIterators {
} }
else else
{ {
return (c_, t_) -> new LazyListValue() return new LazyListValue()
{ {
int curradius; int curradius;
int curpos; int curpos;
+55 -86
View File
@@ -4,12 +4,10 @@ import carpet.script.CarpetContext;
import carpet.script.CarpetEventServer; import carpet.script.CarpetEventServer;
import carpet.script.CarpetScriptHost; import carpet.script.CarpetScriptHost;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.argument.FunctionArgument; import carpet.script.argument.FunctionArgument;
import carpet.script.argument.Vector3Argument; import carpet.script.argument.Vector3Argument;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.value.EntityValue; import carpet.script.value.EntityValue;
import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.NBTSerializableValue; import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NumericValue; import carpet.script.value.NumericValue;
@@ -43,7 +41,7 @@ import java.util.stream.Collectors;
public class Entities { public class Entities {
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunction("player", -1, (c, t, lv) -> expression.addContextFunction("player", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
{ {
@@ -51,26 +49,15 @@ public class Entities {
if (cc.host.user != null) if (cc.host.user != null)
{ {
ServerPlayerEntity player = cc.s.getMinecraftServer().getPlayerManager().getPlayer(cc.host.user); ServerPlayerEntity player = cc.s.getMinecraftServer().getPlayerManager().getPlayer(cc.host.user);
if (player == null) return LazyValue.NULL; return EntityValue.of(player);
Value ret = new EntityValue(player);
return (_c, _t) -> ret;
} }
Entity callingEntity = cc.s.getEntity(); Entity callingEntity = cc.s.getEntity();
if (callingEntity instanceof PlayerEntity) if (callingEntity instanceof PlayerEntity) return EntityValue.of(callingEntity);
{
Value retval = new EntityValue(callingEntity);
return (_c, _t) -> retval;
}
Vec3d pos = ((CarpetContext)c).s.getPosition(); Vec3d pos = ((CarpetContext)c).s.getPosition();
PlayerEntity closestPlayer = ((CarpetContext)c).s.getWorld().getClosestPlayer(pos.x, pos.y, pos.z, -1.0, EntityPredicates.VALID_ENTITY); PlayerEntity closestPlayer = ((CarpetContext)c).s.getWorld().getClosestPlayer(pos.x, pos.y, pos.z, -1.0, EntityPredicates.VALID_ENTITY);
if (closestPlayer != null) return EntityValue.of(closestPlayer);
{
Value retval = new EntityValue(closestPlayer);
return (_c, _t) -> retval;
}
return (_c, _t) -> Value.NULL;
} }
String playerName = lv.get(0).evalValue(c).getString(); String playerName = lv.get(0).getString();
Value retval = Value.NULL; Value retval = Value.NULL;
if ("all".equalsIgnoreCase(playerName)) if ("all".equalsIgnoreCase(playerName))
{ {
@@ -114,37 +101,36 @@ public class Entities {
if (player != null) if (player != null)
retval = new EntityValue(player); retval = new EntityValue(player);
} }
Value finalVar = retval; return retval;
return (_c, _t) -> finalVar;
}); });
expression.addLazyFunction("spawn", -1, (c, t, lv) -> expression.addContextFunction("spawn", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
if (lv.size() < 2) if (lv.size() < 2)
throw new InternalExpressionException("'spawn' function takes mob name, and position to spawn"); throw new InternalExpressionException("'spawn' function takes mob name, and position to spawn");
String entityString = lv.get(0).evalValue(c).getString(); String entityString = lv.get(0).getString();
Identifier entityId; Identifier entityId;
try try
{ {
entityId = Identifier.fromCommandInput(new StringReader(entityString)); entityId = Identifier.fromCommandInput(new StringReader(entityString));
EntityType<? extends Entity> type = Registry.ENTITY_TYPE.getOrEmpty(entityId).orElse(null); EntityType<? extends Entity> type = Registry.ENTITY_TYPE.getOrEmpty(entityId).orElse(null);
if (type == null || !type.isSummonable()) if (type == null || !type.isSummonable())
return LazyValue.NULL; return Value.NULL;
} }
catch (CommandSyntaxException exception) catch (CommandSyntaxException exception)
{ {
return LazyValue.NULL; return Value.NULL;
} }
Vector3Argument position = Vector3Argument.findIn(cc, lv, 1); Vector3Argument position = Vector3Argument.findIn(lv, 1);
if (position.fromBlock) if (position.fromBlock)
position.vec = position.vec.subtract(0, 0.5, 0); position.vec = position.vec.subtract(0, 0.5, 0);
CompoundTag tag = new CompoundTag(); CompoundTag tag = new CompoundTag();
boolean hasTag = false; boolean hasTag = false;
if (lv.size() > position.offset) if (lv.size() > position.offset)
{ {
Value nbt = lv.get(position.offset).evalValue(c); Value nbt = lv.get(position.offset);
NBTSerializableValue v = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt NBTSerializableValue v = (nbt instanceof NBTSerializableValue) ? (NBTSerializableValue) nbt
: NBTSerializableValue.parseString(nbt.getString(), true); : NBTSerializableValue.parseString(nbt.getString(), true);
hasTag = true; hasTag = true;
@@ -160,51 +146,38 @@ public class Entities {
return !serverWorld.tryLoadEntity(entity_1x) ? null : entity_1x; return !serverWorld.tryLoadEntity(entity_1x) ? null : entity_1x;
}); });
if (entity_1 == null) { if (entity_1 == null) {
return LazyValue.NULL; return Value.NULL;
} else { } else {
if (!hasTag && entity_1 instanceof MobEntity) { if (!hasTag && entity_1 instanceof MobEntity) {
((MobEntity)entity_1).initialize(serverWorld, serverWorld.getLocalDifficulty(entity_1.getBlockPos()), SpawnReason.COMMAND, null, null); ((MobEntity)entity_1).initialize(serverWorld, serverWorld.getLocalDifficulty(entity_1.getBlockPos()), SpawnReason.COMMAND, null, null);
} }
Value res = new EntityValue(entity_1); return new EntityValue(entity_1);
return (_c, _t) -> res;
} }
}); });
expression.addLazyFunction("entity_id", 1, (c, t, lv) -> expression.addContextFunction("entity_id", 1, (c, t, lv) ->
{ {
Value who = lv.get(0).evalValue(c); Value who = lv.get(0);
Entity e;
if (who instanceof NumericValue) if (who instanceof NumericValue)
{ return EntityValue.of(((CarpetContext)c).s.getWorld().getEntityById((int)((NumericValue) who).getLong()));
e = ((CarpetContext)c).s.getWorld().getEntityById((int)((NumericValue) who).getLong()); return EntityValue.of(((CarpetContext)c).s.getWorld().getEntity(UUID.fromString(who.getString())));
}
else
{
e = ((CarpetContext)c).s.getWorld().getEntity(UUID.fromString(who.getString()));
}
if (e==null)
{
return LazyValue.NULL;
}
return (cc, tt) -> new EntityValue(e);
}); });
expression.addLazyFunction("entity_list", 1, (c, t, lv) -> expression.addContextFunction("entity_list", 1, (c, t, lv) ->
{ {
String who = lv.get(0).evalValue(c).getString(); String who = lv.get(0).getString();
ServerCommandSource source = ((CarpetContext)c).s; ServerCommandSource source = ((CarpetContext)c).s;
EntityValue.EntityClassDescriptor eDesc = EntityValue.getEntityDescriptor(who, source.getMinecraftServer()); EntityValue.EntityClassDescriptor eDesc = EntityValue.getEntityDescriptor(who, source.getMinecraftServer());
List<Entity> entityList = source.getWorld().getEntitiesByType(eDesc.directType, eDesc.filteringPredicate); List<Entity> entityList = source.getWorld().getEntitiesByType(eDesc.directType, eDesc.filteringPredicate);
Value retval = ListValue.wrap(entityList.stream().map(EntityValue::new).collect(Collectors.toList())); return ListValue.wrap(entityList.stream().map(EntityValue::new).collect(Collectors.toList()));
return (_c, _t ) -> retval;
}); });
expression.addLazyFunction("entity_area", -1, (c, t, lv) -> expression.addContextFunction("entity_area", -1, (c, t, lv) ->
{ {
if (lv.size()<3) throw new InternalExpressionException("'entity_area' requires entity type, center and range arguments"); if (lv.size()<3) throw new InternalExpressionException("'entity_area' requires entity type, center and range arguments");
String who = lv.get(0).evalValue(c).getString(); String who = lv.get(0).getString();
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
Vector3Argument centerLocator = Vector3Argument.findIn(cc, lv, 1, false, true); Vector3Argument centerLocator = Vector3Argument.findIn(lv, 1, false, true);
Box centerBox; Box centerBox;
if (centerLocator.entity != null) if (centerLocator.entity != null)
@@ -217,90 +190,87 @@ public class Entities {
if (centerLocator.fromBlock) center.add(0.5, 0.5, 0.5); if (centerLocator.fromBlock) center.add(0.5, 0.5, 0.5);
centerBox = new Box(center, center); centerBox = new Box(center, center);
} }
Vector3Argument rangeLocator = Vector3Argument.findIn(cc, lv, centerLocator.offset); Vector3Argument rangeLocator = Vector3Argument.findIn(lv, centerLocator.offset);
if (rangeLocator.fromBlock) if (rangeLocator.fromBlock)
throw new InternalExpressionException("Range of 'entity_area' cannot come from a block argument"); throw new InternalExpressionException("Range of 'entity_area' cannot come from a block argument");
Vec3d range = rangeLocator.vec; Vec3d range = rangeLocator.vec;
Box area = centerBox.expand(range.x, range.y, range.z); Box area = centerBox.expand(range.x, range.y, range.z);
EntityValue.EntityClassDescriptor eDesc = EntityValue.getEntityDescriptor(who, cc.s.getMinecraftServer()); EntityValue.EntityClassDescriptor eDesc = EntityValue.getEntityDescriptor(who, cc.s.getMinecraftServer());
List<? extends Entity> entityList = cc.s.getWorld().getEntitiesByType(eDesc.directType, area,eDesc.filteringPredicate); List<? extends Entity> entityList = cc.s.getWorld().getEntitiesByType(eDesc.directType, area,eDesc.filteringPredicate);
Value retval = ListValue.wrap(entityList.stream().map(EntityValue::new).collect(Collectors.toList())); return ListValue.wrap(entityList.stream().map(EntityValue::new).collect(Collectors.toList()));
return (_c, _t ) -> retval;
}); });
expression.addLazyFunction("entity_selector", -1, (c, t, lv) -> expression.addContextFunction("entity_selector", -1, (c, t, lv) ->
{ {
String selector = lv.get(0).evalValue(c).getString(); String selector = lv.get(0).getString();
List<Value> retlist = new ArrayList<>(); List<Value> retlist = new ArrayList<>();
for (Entity e: EntityValue.getEntitiesFromSelector(((CarpetContext)c).s, selector)) for (Entity e: EntityValue.getEntitiesFromSelector(((CarpetContext)c).s, selector))
{ {
retlist.add(new EntityValue(e)); retlist.add(new EntityValue(e));
} }
return (c_, t_) -> ListValue.wrap(retlist); return ListValue.wrap(retlist);
}); });
expression.addLazyFunction("query", -1, (c, t, lv) -> expression.addContextFunction("query", -1, (c, t, lv) ->
{ {
if (lv.size()<2) if (lv.size()<2)
{ {
throw new InternalExpressionException("'query' takes entity as a first argument, and queried feature as a second"); throw new InternalExpressionException("'query' takes entity as a first argument, and queried feature as a second");
} }
Value v = lv.get(0).evalValue(c); Value v = lv.get(0);
if (!(v instanceof EntityValue)) if (!(v instanceof EntityValue))
throw new InternalExpressionException("First argument to query should be an entity"); throw new InternalExpressionException("First argument to query should be an entity");
String what = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT); String what = lv.get(1).getString().toLowerCase(Locale.ROOT);
if (what.equals("tags")) if (what.equals("tags"))
c.host.issueDeprecation("'tags' for entity querying"); c.host.issueDeprecation("'tags' for entity querying");
Value retval; Value retval;
if (lv.size()==2) if (lv.size()==2)
retval = ((EntityValue) v).get(what, null); retval = ((EntityValue) v).get(what, null);
else if (lv.size()==3) else if (lv.size()==3)
retval = ((EntityValue) v).get(what, lv.get(2).evalValue(c)); retval = ((EntityValue) v).get(what, lv.get(2));
else else
retval = ((EntityValue) v).get(what, ListValue.wrap(lv.subList(2, lv.size()).stream().map((vv) -> vv.evalValue(c)).collect(Collectors.toList()))); retval = ((EntityValue) v).get(what, ListValue.wrap(lv.subList(2, lv.size())));
return (cc, tt) -> retval; return retval;
}); });
// or update // or update
expression.addLazyFunction("modify", -1, (c, t, lv) -> expression.addContextFunction("modify", -1, (c, t, lv) ->
{ {
if (lv.size()<2) if (lv.size()<2)
{ {
throw new InternalExpressionException("'modify' takes entity as a first argument, and queried feature as a second"); throw new InternalExpressionException("'modify' takes entity as a first argument, and queried feature as a second");
} }
Value v = lv.get(0).evalValue(c); Value v = lv.get(0);
if (!(v instanceof EntityValue)) if (!(v instanceof EntityValue))
throw new InternalExpressionException("First argument to modify should be an entity"); throw new InternalExpressionException("First argument to modify should be an entity");
String what = lv.get(1).evalValue(c).getString(); String what = lv.get(1).getString();
if (lv.size()==2) if (lv.size()==2)
((EntityValue) v).set(what, null); ((EntityValue) v).set(what, null);
else if (lv.size()==3) else if (lv.size()==3)
((EntityValue) v).set(what, lv.get(2).evalValue(c)); ((EntityValue) v).set(what, lv.get(2));
else else
((EntityValue) v).set(what, ListValue.wrap(lv.subList(2, lv.size()).stream().map((vv) -> vv.evalValue(c)).collect(Collectors.toList()))); ((EntityValue) v).set(what, ListValue.wrap(lv.subList(2, lv.size())));
return (cc, tt) -> v; return v;
}); });
expression.addLazyFunction("entity_types", -1, (c, t, lv) -> expression.addContextFunction("entity_types", -1, (c, t, lv) ->
{ {
if (lv.size() > 1) throw new InternalExpressionException("'entity_types' requires one or no arguments"); if (lv.size() > 1) throw new InternalExpressionException("'entity_types' requires one or no arguments");
String desc = (lv.size() == 1)?lv.get(0).evalValue(c).getString():"*"; String desc = (lv.size() == 1)?lv.get(0).getString():"*";
Value ret = EntityValue.getEntityDescriptor(desc, ((CarpetContext) c).s.getMinecraftServer()).listValue; return EntityValue.getEntityDescriptor(desc, ((CarpetContext) c).s.getMinecraftServer()).listValue;
return (_c, _t) -> ret;
}); });
expression.addLazyFunction("entity_load_handler", -1, (c, t, lv) -> expression.addContextFunction("entity_load_handler", -1, (c, t, lv) ->
{ {
if (c.host.isPerUser()) throw new InternalExpressionException("'entity_load_handler' can only be called in apps with global scope"); if (c.host.isPerUser()) throw new InternalExpressionException("'entity_load_handler' can only be called in apps with global scope");
if (lv.size() < 2) throw new InternalExpressionException("'entity_load_handler' required the entity type, and a function to call"); if (lv.size() < 2) throw new InternalExpressionException("'entity_load_handler' required the entity type, and a function to call");
Value entityValue = lv.get(0).evalValue(c); Value entityValue = lv.get(0);
List<String> descriptors = (entityValue instanceof ListValue) List<String> descriptors = (entityValue instanceof ListValue)
? ((ListValue) entityValue).getItems().stream().map(Value::getString).collect(Collectors.toList()) ? ((ListValue) entityValue).getItems().stream().map(Value::getString).collect(Collectors.toList())
: Collections.singletonList(entityValue.getString()); : Collections.singletonList(entityValue.getString());
Set<EntityType<? extends Entity>> types = new HashSet<>(); Set<EntityType<? extends Entity>> types = new HashSet<>();
descriptors.forEach(s -> types.addAll(EntityValue.getEntityDescriptor(s, ((CarpetContext) c).s.getMinecraftServer()).typeList)); descriptors.forEach(s -> types.addAll(EntityValue.getEntityDescriptor(s, ((CarpetContext) c).s.getMinecraftServer()).typeList));
FunctionArgument<LazyValue> funArg = FunctionArgument.findIn(c, expression.module, lv, 1, true, false); FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 1, true, false);
CarpetEventServer events = ((CarpetScriptHost)c.host).getScriptServer().events; CarpetEventServer events = ((CarpetScriptHost)c.host).getScriptServer().events;
if (funArg.function == null) if (funArg.function == null)
{ {
@@ -308,27 +278,26 @@ public class Entities {
} }
else else
{ {
types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), c.host, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t))); types.forEach(et -> events.addBuiltInEvent(CarpetEventServer.Event.getEntityLoadEventName(et), c.host, funArg.function, funArg.args));
} }
Value ret = new NumericValue(types.size()); return new NumericValue(types.size());
return (cc, tt) -> ret;
}); });
// or update // or update
expression.addLazyFunction("entity_event", -1, (c, t, lv) -> expression.addContextFunction("entity_event", -1, (c, t, lv) ->
{ {
if (lv.size()<3) if (lv.size()<3)
throw new InternalExpressionException("'entity_event' requires at least 3 arguments, entity, event to be handled, and function name, with optional arguments"); throw new InternalExpressionException("'entity_event' requires at least 3 arguments, entity, event to be handled, and function name, with optional arguments");
Value v = lv.get(0).evalValue(c); Value v = lv.get(0);
if (!(v instanceof EntityValue)) if (!(v instanceof EntityValue))
throw new InternalExpressionException("First argument to entity_event should be an entity"); throw new InternalExpressionException("First argument to entity_event should be an entity");
String what = lv.get(1).evalValue(c).getString(); String what = lv.get(1).getString();
FunctionArgument<LazyValue> funArg = FunctionArgument.findIn(c, expression.module, lv, 2, true, false); FunctionArgument funArg = FunctionArgument.findIn(c, expression.module, lv, 2, true, false);
((EntityValue) v).setEvent((CarpetContext)c, what, funArg.function, FunctionValue.resolveArgs(funArg.args, c, t)); ((EntityValue) v).setEvent((CarpetContext)c, what, funArg.function, funArg.args);
return LazyValue.NULL; return Value.NULL;
}); });
} }
} }
+74 -128
View File
@@ -4,10 +4,10 @@ import carpet.fakes.IngredientInterface;
import carpet.fakes.RecipeManagerInterface; import carpet.fakes.RecipeManagerInterface;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement; import carpet.script.exception.ThrowStatement;
import carpet.script.exception.Throwables; import carpet.script.exception.Throwables;
import carpet.script.value.BooleanValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.NBTSerializableValue; import carpet.script.value.NBTSerializableValue;
import carpet.script.value.NullValue; import carpet.script.value.NullValue;
@@ -49,68 +49,52 @@ import java.util.stream.Collectors;
public class Inventories { public class Inventories {
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunction("stack_limit", 1, (c, t, lv) -> expression.addUnaryFunction("stack_limit", v ->
{ new NumericValue(NBTSerializableValue.parseItem(v.getString()).getItem().getMaxCount()));
ItemStackArgument item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString());
Value res = new NumericValue(item.getItem().getMaxCount());
return (_c, _t) -> res;
});
expression.addLazyFunction("item_category", 1, (c, t, lv) -> expression.addUnaryFunction("item_category", v ->
{ {
ItemStackArgument item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()); ItemStackArgument item = NBTSerializableValue.parseItem(v.getString());
ItemGroup ig = item.getItem().getGroup(); ItemGroup ig = item.getItem().getGroup();
Value res = (ig==null)?Value.NULL:new StringValue(ig.getName()); return (ig==null)?Value.NULL:new StringValue(ig.getName());
return (_c, _t) -> res;
}); });
expression.addLazyFunction("item_list", -1, (c, t, lv) -> expression.addContextFunction("item_list", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
{ return ListValue.wrap(Registry.ITEM.getIds().stream().map(ValueConversions::of).collect(Collectors.toList()));
Value res = ListValue.wrap(Registry.ITEM.getIds().stream().map(ValueConversions::of).collect(Collectors.toList()));
return (cc, tt) -> res;
}
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
TagManager tagManager = cc.s.getMinecraftServer().getTagManager(); TagManager tagManager = cc.s.getMinecraftServer().getTagManager();
String tag = lv.get(0).evalValue(c).getString(); String tag = lv.get(0).getString();
net.minecraft.tag.Tag<Item> itemTag = tagManager.getItems().getTag(new Identifier(tag)); net.minecraft.tag.Tag<Item> itemTag = tagManager.getItems().getTag(new Identifier(tag));
if (itemTag == null) return LazyValue.NULL; if (itemTag == null) return Value.NULL;
Value ret = ListValue.wrap(itemTag.values().stream().map(b -> ValueConversions.of(Registry.ITEM.getId(b))).collect(Collectors.toList())); return ListValue.wrap(itemTag.values().stream().map(b -> ValueConversions.of(Registry.ITEM.getId(b))).collect(Collectors.toList()));
return (_c, _t) -> ret;
}); });
expression.addLazyFunction("item_tags", -1, (c, t, lv) -> expression.addContextFunction("item_tags", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
TagManager tagManager = cc.s.getMinecraftServer().getTagManager(); TagManager tagManager = cc.s.getMinecraftServer().getTagManager();
if (lv.size() == 0) if (lv.size() == 0)
{ return ListValue.wrap(tagManager.getItems().getTagIds().stream().map(ValueConversions::of).collect(Collectors.toList()));
Value ret = ListValue.wrap(tagManager.getItems().getTagIds().stream().map(ValueConversions::of).collect(Collectors.toList())); Item item = NBTSerializableValue.parseItem(lv.get(0).getString()).getItem();
return (_c, _t) -> ret;
}
Item item = NBTSerializableValue.parseItem(lv.get(0).evalValue(c).getString()).getItem();
if (lv.size() == 1) if (lv.size() == 1)
{ return ListValue.wrap(tagManager.getItems().getTags().entrySet().stream().filter(e -> e.getValue().contains(item)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList()));
Value ret = ListValue.wrap(tagManager.getItems().getTags().entrySet().stream().filter(e -> e.getValue().contains(item)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList())); String tag = lv.get(1).getString();
return (_c, _t) -> ret;
}
String tag = lv.get(1).evalValue(c).getString();
net.minecraft.tag.Tag<Item> itemTag = tagManager.getItems().getTag(new Identifier(tag)); net.minecraft.tag.Tag<Item> itemTag = tagManager.getItems().getTag(new Identifier(tag));
if (itemTag == null) return LazyValue.NULL; if (itemTag == null) return Value.NULL;
return item.isIn(itemTag)?LazyValue.TRUE:LazyValue.FALSE; return BooleanValue.of(item.isIn(itemTag));
}); });
expression.addLazyFunction("recipe_data", -1, (c, t, lv) -> expression.addContextFunction("recipe_data", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
if (lv.size() < 1) throw new InternalExpressionException("'recipe_data' requires at least one argument"); if (lv.size() < 1) throw new InternalExpressionException("'recipe_data' requires at least one argument");
String recipeName = lv.get(0).evalValue(c).getString(); String recipeName = lv.get(0).getString();
RecipeType type = RecipeType.CRAFTING; RecipeType type = RecipeType.CRAFTING;
if (lv.size() > 1) if (lv.size() > 1)
{ {
String recipeType = lv.get(1).evalValue(c).getString(); String recipeType = lv.get(1).getString();
try try
{ {
type = Registry.RECIPE_TYPE.get(new Identifier(recipeType)); type = Registry.RECIPE_TYPE.get(new Identifier(recipeType));
@@ -123,7 +107,7 @@ public class Inventories {
List<Recipe<?>> recipes; List<Recipe<?>> recipes;
recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName)); recipes = ((RecipeManagerInterface) cc.s.getMinecraftServer().getRecipeManager()).getAllMatching(type, new Identifier(recipeName));
if (recipes.isEmpty()) if (recipes.isEmpty())
return LazyValue.NULL; return Value.NULL;
List<Value> recipesOutput = new ArrayList<>(); List<Value> recipesOutput = new ArrayList<>();
for (Recipe<?> recipe: recipes) for (Recipe<?> recipe: recipes)
{ {
@@ -143,7 +127,7 @@ public class Inventories {
else else
{ {
List<Value> alternatives = new ArrayList<>(); List<Value> alternatives = new ArrayList<>();
stacks.forEach(col -> col.stream().map(ListValue::fromItemStack).forEach(alternatives::add)); stacks.forEach(col -> col.stream().map(ValueConversions::of).forEach(alternatives::add));
ingredientValue.add(ListValue.wrap(alternatives)); ingredientValue.add(ListValue.wrap(alternatives));
} }
} }
@@ -182,91 +166,75 @@ public class Inventories {
recipeSpec = ListValue.of(new StringValue("custom")); recipeSpec = ListValue.of(new StringValue("custom"));
} }
recipesOutput.add(ListValue.of(ListValue.fromItemStack(result), ListValue.wrap(ingredientValue), recipeSpec)); recipesOutput.add(ListValue.of(ValueConversions.of(result), ListValue.wrap(ingredientValue), recipeSpec));
} }
Value ret = ListValue.wrap(recipesOutput); return ListValue.wrap(recipesOutput);
return (_c, _t) -> ret;
}); });
expression.addLazyFunction("crafting_remaining_item", 1, (c, t, lv) -> expression.addUnaryFunction("crafting_remaining_item", v ->
{ {
String itemStr = lv.get(0).evalValue(c).getString(); String itemStr = v.getString();
Item item; Item item;
Identifier id = new Identifier(itemStr); Identifier id = new Identifier(itemStr);
item = Registry.ITEM.getOrEmpty(id).orElseThrow(() -> new ThrowStatement(itemStr, Throwables.UNKNOWN_ITEM)); item = Registry.ITEM.getOrEmpty(id).orElseThrow(() -> new ThrowStatement(itemStr, Throwables.UNKNOWN_ITEM));
if (!item.hasRecipeRemainder()) return Value.NULL;
if (!item.hasRecipeRemainder()) return LazyValue.NULL; return new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder())));
Value ret = new StringValue(NBTSerializableValue.nameFromRegistryId(Registry.ITEM.getId(item.getRecipeRemainder())));
return (_c, _t ) -> ret;
}); });
expression.addContextFunction("inventory_size", -1, (c, t, lv) ->
expression.addLazyFunction("inventory_size", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL; return new NumericValue(inventoryLocator.inventory.size());
Value res = new NumericValue(inventoryLocator.inventory.size());
return (_c, _t) -> res;
}); });
expression.addLazyFunction("inventory_has_items", -1, (c, t, lv) -> expression.addContextFunction("inventory_has_items", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL; return new NumericValue(!inventoryLocator.inventory.isEmpty());
Value res = new NumericValue(!inventoryLocator.inventory.isEmpty());
return (_c, _t) -> res;
}); });
//inventory_get(<b, e>, <n>) -> item_triple //inventory_get(<b, e>, <n>) -> item_triple
expression.addLazyFunction("inventory_get", -1, (c, t, lv) -> expression.addContextFunction("inventory_get", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL;
if (lv.size() == inventoryLocator.offset) if (lv.size() == inventoryLocator.offset)
{ {
List<Value> fullInventory = new ArrayList<>(); List<Value> fullInventory = new ArrayList<>();
for (int i = 0, maxi = inventoryLocator.inventory.size(); i < maxi; i++) for (int i = 0, maxi = inventoryLocator.inventory.size(); i < maxi; i++)
{ fullInventory.add(ValueConversions.of(inventoryLocator.inventory.getStack(i)));
fullInventory.add(ListValue.fromItemStack(inventoryLocator.inventory.getStack(i))); return ListValue.wrap(fullInventory);
}
Value res = ListValue.wrap(fullInventory);
return (_c, _t) -> res;
} }
int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset)).getLong();
slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory);
if (slot == inventoryLocator.inventory.size()) if (slot == inventoryLocator.inventory.size()) return Value.NULL;
return (_c, _t) -> Value.NULL; return ValueConversions.of(inventoryLocator.inventory.getStack(slot));
Value res = ListValue.fromItemStack(inventoryLocator.inventory.getStack(slot));
return (_c, _t) -> res;
}); });
//inventory_set(<b,e>, <n>, <count>, <item>, <nbt>) //inventory_set(<b,e>, <n>, <count>, <item>, <nbt>)
expression.addLazyFunction("inventory_set", -1, (c, t, lv) -> expression.addContextFunction("inventory_set", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL;
if (lv.size() < inventoryLocator.offset+2) if (lv.size() < inventoryLocator.offset+2)
throw new InternalExpressionException("'inventory_set' requires at least slot number and new stack size, and optional new item"); throw new InternalExpressionException("'inventory_set' requires at least slot number and new stack size, and optional new item");
int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0).evalValue(c)).getLong(); int slot = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+0)).getLong();
slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory);
if (slot == inventoryLocator.inventory.size()) if (slot == inventoryLocator.inventory.size()) return Value.NULL;
return (_c, _t) -> Value.NULL; int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1)).getLong();
int count = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong();
if (count == 0) if (count == 0)
{ {
// clear slot // clear slot
ItemStack removedStack = inventoryLocator.inventory.removeStack(slot); ItemStack removedStack = inventoryLocator.inventory.removeStack(slot);
syncPlayerInventory(inventoryLocator, slot); syncPlayerInventory(inventoryLocator, slot);
//Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares //Value res = ListValue.fromItemStack(removedStack); // that tuple will be read only but cheaper if noone cares
return (_c, _t) -> ListValue.fromItemStack(removedStack); return ValueConversions.of(removedStack);
} }
if (lv.size() < inventoryLocator.offset+3) if (lv.size() < inventoryLocator.offset+3)
{ {
@@ -275,12 +243,12 @@ public class Inventories {
newStack.setCount(count); newStack.setCount(count);
inventoryLocator.inventory.setStack(slot, newStack); inventoryLocator.inventory.setStack(slot, newStack);
syncPlayerInventory(inventoryLocator, slot); syncPlayerInventory(inventoryLocator, slot);
return (_c, _t) -> ListValue.fromItemStack(previousStack); return ValueConversions.of(previousStack);
} }
CompoundTag nbt = null; // skipping one argument CompoundTag nbt = null; // skipping one argument
if (lv.size() > inventoryLocator.offset+3) if (lv.size() > inventoryLocator.offset+3)
{ {
Value nbtValue = lv.get(inventoryLocator.offset+3).evalValue(c); Value nbtValue = lv.get(inventoryLocator.offset+3);
if (nbtValue instanceof NBTSerializableValue) if (nbtValue instanceof NBTSerializableValue)
nbt = ((NBTSerializableValue)nbtValue).getCompoundTag(); nbt = ((NBTSerializableValue)nbtValue).getCompoundTag();
else if (nbtValue instanceof NullValue) else if (nbtValue instanceof NullValue)
@@ -288,11 +256,7 @@ public class Inventories {
else else
nbt = new NBTSerializableValue(nbtValue.getString()).getCompoundTag(); nbt = new NBTSerializableValue(nbtValue.getString()).getCompoundTag();
} }
ItemStackArgument newitem = NBTSerializableValue.parseItem( ItemStackArgument newitem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset+2).getString(), nbt);
lv.get(inventoryLocator.offset+2).evalValue(c).getString(),
nbt
);
ItemStack previousStack = inventoryLocator.inventory.getStack(slot); ItemStack previousStack = inventoryLocator.inventory.getStack(slot);
try try
{ {
@@ -303,62 +267,52 @@ public class Inventories {
{ {
throw new InternalExpressionException(e.getMessage()); throw new InternalExpressionException(e.getMessage());
} }
return (_c, _t) -> ListValue.fromItemStack(previousStack); return ValueConversions.of(previousStack);
}); });
//inventory_find(<b, e>, <item> or null (first empty slot), <start_from=0> ) -> <N> or null //inventory_find(<b, e>, <item> or null (first empty slot), <start_from=0> ) -> <N> or null
expression.addLazyFunction("inventory_find", -1, (c, t, lv) -> expression.addContextFunction("inventory_find", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL;
ItemStackArgument itemArg = null; ItemStackArgument itemArg = null;
if (lv.size() > inventoryLocator.offset) if (lv.size() > inventoryLocator.offset)
{ {
Value secondArg = lv.get(inventoryLocator.offset+0).evalValue(c); Value secondArg = lv.get(inventoryLocator.offset+0);
if (!(secondArg instanceof NullValue)) if (!(secondArg instanceof NullValue))
itemArg = NBTSerializableValue.parseItem(secondArg.getString()); itemArg = NBTSerializableValue.parseItem(secondArg.getString());
} }
int startIndex = 0; int startIndex = 0;
if (lv.size() > inventoryLocator.offset+1) if (lv.size() > inventoryLocator.offset+1)
{ {
startIndex = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); startIndex = (int) NumericValue.asNumber(lv.get(inventoryLocator.offset+1)).getLong();
} }
startIndex = NBTSerializableValue.validateSlot(startIndex, inventoryLocator.inventory); startIndex = NBTSerializableValue.validateSlot(startIndex, inventoryLocator.inventory);
for (int i = startIndex, maxi = inventoryLocator.inventory.size(); i < maxi; i++) for (int i = startIndex, maxi = inventoryLocator.inventory.size(); i < maxi; i++)
{ {
ItemStack stack = inventoryLocator.inventory.getStack(i); ItemStack stack = inventoryLocator.inventory.getStack(i);
if ( (itemArg == null && stack.isEmpty()) || (itemArg != null && itemArg.getItem().equals(stack.getItem())) ) if ( (itemArg == null && stack.isEmpty()) || (itemArg != null && itemArg.getItem().equals(stack.getItem())) )
{ return new NumericValue(i);
Value res = new NumericValue(i);
return (_c, _t) -> res;
}
} }
return (_c, _t) -> Value.NULL; return Value.NULL;
}); });
//inventory_remove(<b, e>, <item>, <amount=1>) -> bool //inventory_remove(<b, e>, <item>, <amount=1>) -> bool
expression.addLazyFunction("inventory_remove", -1, (c, t, lv) -> expression.addContextFunction("inventory_remove", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL;
if (lv.size() <= inventoryLocator.offset) if (lv.size() <= inventoryLocator.offset)
throw new InternalExpressionException("'inventory_remove' requires at least an item to be removed"); throw new InternalExpressionException("'inventory_remove' requires at least an item to be removed");
ItemStackArgument searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset).evalValue(c).getString()); ItemStackArgument searchItem = NBTSerializableValue.parseItem(lv.get(inventoryLocator.offset).getString());
int amount = 1; int amount = 1;
if (lv.size() > inventoryLocator.offset+1) if (lv.size() > inventoryLocator.offset+1)
{ amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1)).getLong();
amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong();
}
// not enough // not enough
if (((amount == 1) && (!inventoryLocator.inventory.containsAny(Sets.newHashSet(searchItem.getItem())))) if (((amount == 1) && (!inventoryLocator.inventory.containsAny(Sets.newHashSet(searchItem.getItem()))))
|| (inventoryLocator.inventory.count(searchItem.getItem()) < amount)) || (inventoryLocator.inventory.count(searchItem.getItem()) < amount)) return Value.FALSE;
{
return (_c, _t) -> Value.FALSE;
}
for (int i = 0, maxi = inventoryLocator.inventory.size(); i < maxi; i++) for (int i = 0, maxi = inventoryLocator.inventory.size(); i < maxi; i++)
{ {
ItemStack stack = inventoryLocator.inventory.getStack(i); ItemStack stack = inventoryLocator.inventory.getStack(i);
@@ -372,7 +326,7 @@ public class Inventories {
stack.setCount(left); stack.setCount(left);
inventoryLocator.inventory.setStack(i, stack); inventoryLocator.inventory.setStack(i, stack);
syncPlayerInventory(inventoryLocator, i); syncPlayerInventory(inventoryLocator, i);
return (_c, _t) -> Value.TRUE; return Value.TRUE;
} }
else else
{ {
@@ -383,37 +337,30 @@ public class Inventories {
} }
if (amount > 0) if (amount > 0)
throw new InternalExpressionException("Something bad happened - cannot pull all items from inventory"); throw new InternalExpressionException("Something bad happened - cannot pull all items from inventory");
return (_c, _t) -> Value.TRUE; return Value.TRUE;
}); });
//inventory_drop(<b, e>, <n>, <amount=1, 0-whatever's there>) -> entity_item (and sets slot) or null if cannot //inventory_drop(<b, e>, <n>, <amount=1, 0-whatever's there>) -> entity_item (and sets slot) or null if cannot
expression.addLazyFunction("drop_item", -1, (c, t, lv) -> expression.addContextFunction("drop_item", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext) c; CarpetContext cc = (CarpetContext) c;
NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0); NBTSerializableValue.InventoryLocator inventoryLocator = NBTSerializableValue.locateInventory(cc, lv, 0);
if (inventoryLocator == null) if (inventoryLocator == null) return Value.NULL;
return (_c, _t) -> Value.NULL;
if (lv.size() == inventoryLocator.offset) if (lv.size() == inventoryLocator.offset)
throw new InternalExpressionException("Slot number is required for inventory_drop"); throw new InternalExpressionException("Slot number is required for inventory_drop");
int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset).evalValue(c)).getLong(); int slot = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset)).getLong();
slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory); slot = NBTSerializableValue.validateSlot(slot, inventoryLocator.inventory);
if (slot == inventoryLocator.inventory.size()) if (slot == inventoryLocator.inventory.size()) return Value.NULL;
return (_c, _t) -> Value.NULL;
int amount = 0; int amount = 0;
if (lv.size() > inventoryLocator.offset+1) if (lv.size() > inventoryLocator.offset+1)
amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1).evalValue(c)).getLong(); amount = (int)NumericValue.asNumber(lv.get(inventoryLocator.offset+1)).getLong();
if (amount < 0) if (amount < 0)
throw new InternalExpressionException("Cannot throw negative number of items"); throw new InternalExpressionException("Cannot throw negative number of items");
ItemStack stack = inventoryLocator.inventory.getStack(slot); ItemStack stack = inventoryLocator.inventory.getStack(slot);
if (stack == null || stack.isEmpty()) if (stack == null || stack.isEmpty()) return Value.ZERO;
return (_c, _t) -> Value.ZERO; if (amount == 0) amount = stack.getCount();
if (amount == 0)
amount = stack.getCount();
ItemStack droppedStack = inventoryLocator.inventory.removeStack(slot, amount); ItemStack droppedStack = inventoryLocator.inventory.removeStack(slot, amount);
if (droppedStack.isEmpty()) if (droppedStack.isEmpty()) return Value.ZERO;
{
return (_c, _t) -> Value.ZERO;
}
Object owner = inventoryLocator.owner; Object owner = inventoryLocator.owner;
ItemEntity item; ItemEntity item;
if (owner instanceof PlayerEntity) if (owner instanceof PlayerEntity)
@@ -438,8 +385,7 @@ public class Inventories {
item.setToDefaultPickupDelay(); item.setToDefaultPickupDelay();
cc.s.getWorld().spawnEntity(item); cc.s.getWorld().spawnEntity(item);
} }
Value res = new NumericValue(item.getStack().getCount()); return new NumericValue(item.getStack().getCount());
return (_c, _t) -> res;
}); });
} }
+14 -20
View File
@@ -25,31 +25,29 @@ public class Monitoring {
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunction("system_info", -1, (c, t, lv) -> expression.addContextFunction("system_info", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
{ {
Value ret = SystemInfo.getAll((CarpetContext) c); return SystemInfo.getAll((CarpetContext) c);
return (cc, tt) -> ret;
} }
if (lv.size() == 1) { if (lv.size() == 1) {
String what = lv.get(0).evalValue(c).getString(); String what = lv.get(0).getString();
Value res = SystemInfo.get(what, (CarpetContext) c); Value res = SystemInfo.get(what, (CarpetContext) c);
if (res == null) throw new InternalExpressionException("Unknown option for 'system_info': " + what); if (res == null) throw new InternalExpressionException("Unknown option for 'system_info': " + what);
return (cc, tt) -> res; return res;
} }
throw new InternalExpressionException("'system_info' requires one or no parameters"); throw new InternalExpressionException("'system_info' requires one or no parameters");
}); });
// game processed snooper functions // game processed snooper functions
expression.addLazyFunction("get_mob_counts", -1, (c, t, lv) -> expression.addContextFunction("get_mob_counts", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerWorld world = cc.s.getWorld(); ServerWorld world = cc.s.getWorld();
SpawnHelper.Info info = world.getChunkManager().getSpawnInfo(); SpawnHelper.Info info = world.getChunkManager().getSpawnInfo();
if (info == null) return LazyValue.NULL; if (info == null) return Value.NULL;
Object2IntMap<SpawnGroup> mobcounts = info.getGroupToCount(); Object2IntMap<SpawnGroup> mobcounts = info.getGroupToCount();
int chunks = ((SpawnHelperInnerInterface)info).cmGetChunkCount(); int chunks = ((SpawnHelperInnerInterface)info).cmGetChunkCount();
Value retVal;
if (lv.size() == 0) if (lv.size() == 0)
{ {
Map<Value, Value> retDict = new HashMap<>(); Map<Value, Value> retDict = new HashMap<>();
@@ -63,19 +61,15 @@ public class Monitoring {
new NumericValue(currentCap)) new NumericValue(currentCap))
); );
} }
retVal = MapValue.wrap(retDict); return MapValue.wrap(retDict);
} }
else String catString = lv.get(0).getString();
{ SpawnGroup cat = SpawnGroup.byName(catString.toLowerCase(Locale.ROOT));
String catString = lv.get(0).evalValue(c).getString(); if (cat == null) throw new InternalExpressionException("Unreconized mob category: "+catString);
SpawnGroup cat = SpawnGroup.byName(catString.toLowerCase(Locale.ROOT)); return ListValue.of(
if (cat == null) throw new InternalExpressionException("Unreconized mob category: "+catString); new NumericValue(mobcounts.getInt(cat)),
retVal = ListValue.of( new NumericValue((int)(cat.getCapacity() * chunks / SpawnReporter.currentMagicNumber()))
new NumericValue(mobcounts.getInt(cat)), );
new NumericValue((int)(cat.getCapacity() * chunks / SpawnReporter.currentMagicNumber()))
);
}
return (_c, _t) -> retVal;
}); });
} }
} }
+149 -241
View File
@@ -64,77 +64,68 @@ public class Scoreboards {
{ {
// scoreboard(player,'objective') // scoreboard(player,'objective')
// scoreboard(player, objective, newValue) // scoreboard(player, objective, newValue)
expression.addLazyFunction("scoreboard", -1, (c, t, lv) -> expression.addContextFunction("scoreboard", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
if (lv.size()==0) if (lv.size()==0)
{ return ListValue.wrap(scoreboard.getObjectiveNames().stream().map(StringValue::new).collect(Collectors.toList()));
Value ret = ListValue.wrap(scoreboard.getObjectiveNames().stream().map(StringValue::new).collect(Collectors.toList())); String objectiveName = lv.get(0).getString();
return (_c, _t) -> ret;
}
String objectiveName = lv.get(0).evalValue(c).getString();
ScoreboardObjective objective = scoreboard.getObjective(objectiveName); ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
if (objective == null) return LazyValue.NULL; if (objective == null) return Value.NULL;
if (lv.size()==1) if (lv.size()==1)
return ListValue.wrap(scoreboard.getAllPlayerScores(objective).stream().map(s -> new StringValue(s.getPlayerName())).collect(Collectors.toList()));
String key = getScoreboardKeyFromValue(lv.get(1));
if(lv.size()==2)
{ {
Value ret = ListValue.wrap(scoreboard.getAllPlayerScores(objective).stream().map(s -> new StringValue(s.getPlayerName())).collect(Collectors.toList())); if(!scoreboard.playerHasObjective(key, objective)) return Value.NULL;
return (_c, _t) -> ret; return NumericValue.of(scoreboard.getPlayerScore(key,objective).getScore());
} }
String key = getScoreboardKeyFromValue(lv.get(1).evalValue(c)); Value value = lv.get(2);
if(lv.size()==2) {
if(scoreboard.playerHasObjective(key, objective)) {
return (_c,_t) -> NumericValue.of(scoreboard.getPlayerScore(key,objective).getScore());
}
return LazyValue.NULL;
}
Value value = lv.get(2).evalValue(c);
if(value.isNull()) { if(value.isNull()) {
ScoreboardPlayerScore score = scoreboard.getPlayerScore(key, objective); ScoreboardPlayerScore score = scoreboard.getPlayerScore(key, objective);
scoreboard.resetPlayerScore(key,objective); scoreboard.resetPlayerScore(key,objective);
return (_c,_t) -> NumericValue.of(score.getScore()); return NumericValue.of(score.getScore());
} }
if (value instanceof NumericValue) { if (value instanceof NumericValue) {
ScoreboardPlayerScore score = scoreboard.getPlayerScore(key, objective); ScoreboardPlayerScore score = scoreboard.getPlayerScore(key, objective);
score.setScore(NumericValue.asNumber(value).getInt()); score.setScore(NumericValue.asNumber(value).getInt());
return (_c,_t) -> NumericValue.of(score.getScore()); return NumericValue.of(score.getScore());
} }
throw new InternalExpressionException("'scoreboard' requires a number or null as the third parameter"); throw new InternalExpressionException("'scoreboard' requires a number or null as the third parameter");
}); });
expression.addLazyFunction("scoreboard_remove", -1, (c, t, lv)-> expression.addContextFunction("scoreboard_remove", -1, (c, t, lv)->
{ {
if (lv.size()==0) throw new InternalExpressionException("'scoreboard_remove' requires at least one parameter"); if (lv.size()==0) throw new InternalExpressionException("'scoreboard_remove' requires at least one parameter");
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
String objectiveName = lv.get(0).evalValue(c).getString(); String objectiveName = lv.get(0).getString();
ScoreboardObjective objective = scoreboard.getObjective(objectiveName); ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
if (objective == null) if (objective == null) return Value.FALSE;
return LazyValue.FALSE;
if (lv.size() == 1) if (lv.size() == 1)
{ {
scoreboard.removeObjective(objective); scoreboard.removeObjective(objective);
return LazyValue.TRUE; return Value.TRUE;
} }
String key = getScoreboardKeyFromValue(lv.get(1).evalValue(c)); String key = getScoreboardKeyFromValue(lv.get(1));
if (!scoreboard.playerHasObjective(key, objective)) return LazyValue.NULL; if (!scoreboard.playerHasObjective(key, objective)) return Value.NULL;
ScoreboardPlayerScore scoreboardPlayerScore = scoreboard.getPlayerScore(key, objective); ScoreboardPlayerScore scoreboardPlayerScore = scoreboard.getPlayerScore(key, objective);
Value previous = new NumericValue(scoreboardPlayerScore.getScore()); Value previous = new NumericValue(scoreboardPlayerScore.getScore());
scoreboard.resetPlayerScore(key, objective); scoreboard.resetPlayerScore(key, objective);
return (c_, t_) -> previous; return previous;
}); });
// objective_add('lvl','level') // objective_add('lvl','level')
// objective_add('counter') // objective_add('counter')
expression.addLazyFunction("scoreboard_add", -1, (c, t, lv)-> expression.addContextFunction("scoreboard_add", -1, (c, t, lv)->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
if (lv.size() == 0 || lv.size()>2) throw new InternalExpressionException("'scoreboard_add' should have one or two parameters"); if (lv.size() == 0 || lv.size()>2) throw new InternalExpressionException("'scoreboard_add' should have one or two parameters");
String objectiveName = lv.get(0).evalValue(c).getString(); String objectiveName = lv.get(0).getString();
ScoreboardCriterion criterion; ScoreboardCriterion criterion;
if (lv.size() == 1 ) if (lv.size() == 1 )
{ {
@@ -142,7 +133,7 @@ public class Scoreboards {
} }
else else
{ {
String critetionName = lv.get(1).evalValue(c).getString(); String critetionName = lv.get(1).getString();
criterion = ScoreboardCriterion.createStatCriterion(critetionName).orElse(null); criterion = ScoreboardCriterion.createStatCriterion(critetionName).orElse(null);
if (criterion==null) if (criterion==null)
{ {
@@ -153,62 +144,62 @@ public class Scoreboards {
ScoreboardObjective objective = scoreboard.getObjective(objectiveName); ScoreboardObjective objective = scoreboard.getObjective(objectiveName);
if (objective != null) { if (objective != null) {
c.host.issueDeprecation("reading or modifying an objective's criterion with scoreboard_add"); c.host.issueDeprecation("reading or modifying an objective's criterion with scoreboard_add");
if(lv.size() == 1) return (_c, _t) -> StringValue.of(objective.getCriterion().getName()); if(lv.size() == 1) return StringValue.of(objective.getCriterion().getName());
if(objective.getCriterion().equals(criterion) || lv.size() == 1) return LazyValue.NULL; if(objective.getCriterion().equals(criterion) || lv.size() == 1) return Value.NULL;
((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().get(objective.getCriterion()).remove(objective); ((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().get(objective.getCriterion()).remove(objective);
((ScoreboardObjective_scarpetMixin) objective).setCriterion(criterion); ((ScoreboardObjective_scarpetMixin) objective).setCriterion(criterion);
(((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().computeIfAbsent(criterion, (criterion1) -> Lists.newArrayList())).add(objective); (((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().computeIfAbsent(criterion, (criterion1) -> Lists.newArrayList())).add(objective);
scoreboard.updateObjective(objective); scoreboard.updateObjective(objective);
return LazyValue.FALSE; return Value.FALSE;
} }
scoreboard.addObjective(objectiveName, criterion, new LiteralText(objectiveName), criterion.getCriterionType()); scoreboard.addObjective(objectiveName, criterion, new LiteralText(objectiveName), criterion.getCriterionType());
return LazyValue.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("scoreboard_property", -1, (c, t, lv) -> expression.addContextFunction("scoreboard_property", -1, (c, t, lv) ->
{ {
if(lv.size() < 2) throw new InternalExpressionException("'scoreboard_property' requires at least two parameters"); if(lv.size() < 2) throw new InternalExpressionException("'scoreboard_property' requires at least two parameters");
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
ScoreboardObjective objective = scoreboard.getObjective(lv.get(0).evalValue(c).getString()); ScoreboardObjective objective = scoreboard.getObjective(lv.get(0).getString());
if(objective == null) return LazyValue.NULL; if(objective == null) return Value.NULL;
boolean modify = lv.size() > 2; boolean modify = lv.size() > 2;
Value setValue = null; Value setValue = null;
if(modify) { if(modify) {
setValue = lv.get(2).evalValue(c); setValue = lv.get(2);
} }
String property = lv.get(1).evalValue(c).getString(); String property = lv.get(1).getString();
switch (property) { switch (property) {
case "criterion": case "criterion":
if(modify) { if(modify) {
ScoreboardCriterion criterion = ScoreboardCriterion.createStatCriterion(setValue.getString()).orElse(null); ScoreboardCriterion criterion = ScoreboardCriterion.createStatCriterion(setValue.getString()).orElse(null);
if (criterion==null) throw new InternalExpressionException("Unknown scoreboard criterion: "+ setValue.getString()); if (criterion==null) throw new InternalExpressionException("Unknown scoreboard criterion: "+ setValue.getString());
if(objective.getCriterion().equals(criterion) || lv.size() == 1) return LazyValue.FALSE; if(objective.getCriterion().equals(criterion) || lv.size() == 1) return Value.FALSE;
((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().get(objective.getCriterion()).remove(objective); ((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().get(objective.getCriterion()).remove(objective);
((ScoreboardObjective_scarpetMixin) objective).setCriterion(criterion); ((ScoreboardObjective_scarpetMixin) objective).setCriterion(criterion);
(((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().computeIfAbsent(criterion, (criterion1) -> Lists.newArrayList())).add(objective); (((Scoreboard_scarpetMixin)scoreboard).getObjectivesByCriterion().computeIfAbsent(criterion, (criterion1) -> Lists.newArrayList())).add(objective);
scoreboard.updateObjective(objective); scoreboard.updateObjective(objective);
return LazyValue.TRUE; return Value.TRUE;
} }
return (_c, _t) -> StringValue.of(objective.getCriterion().getName()); return StringValue.of(objective.getCriterion().getName());
case "display_name": case "display_name":
if(modify) { if(modify) {
Text text = FormattedTextValue.getTextByValue(setValue); Text text = FormattedTextValue.getTextByValue(setValue);
objective.setDisplayName(text); objective.setDisplayName(text);
return LazyValue.TRUE; return Value.TRUE;
} }
return (_c, _t) -> new FormattedTextValue(objective.getDisplayName()); return new FormattedTextValue(objective.getDisplayName());
case "display_slot": case "display_slot":
if(modify) { if(modify) {
int slotId = Scoreboard.getDisplaySlotId(setValue.getString()); int slotId = Scoreboard.getDisplaySlotId(setValue.getString());
if(slotId == -1) throw new InternalExpressionException("Unknown scoreboard display slot: " + setValue.getString()); if(slotId == -1) throw new InternalExpressionException("Unknown scoreboard display slot: " + setValue.getString());
if(objective.equals(scoreboard.getObjectiveForSlot(slotId))) { if(objective.equals(scoreboard.getObjectiveForSlot(slotId))) {
return LazyValue.FALSE; return Value.FALSE;
} }
scoreboard.setObjectiveSlot(slotId,objective); scoreboard.setObjectiveSlot(slotId,objective);
return LazyValue.TRUE; return Value.TRUE;
} }
List<Value> slots = new ArrayList<>(); List<Value> slots = new ArrayList<>();
@@ -218,325 +209,247 @@ public class Scoreboards {
slots.add(StringValue.of(slotName)); slots.add(StringValue.of(slotName));
} }
} }
return (_c, _t) -> ListValue.wrap(slots); return ListValue.wrap(slots);
case "render_type": case "render_type":
if(modify) { if(modify) {
ScoreboardCriterion.RenderType renderType = ScoreboardCriterion.RenderType.getType(setValue.getString().toLowerCase()); ScoreboardCriterion.RenderType renderType = ScoreboardCriterion.RenderType.getType(setValue.getString().toLowerCase());
if(objective.getRenderType().equals(renderType)) return LazyValue.FALSE; if(objective.getRenderType().equals(renderType)) return Value.FALSE;
objective.setRenderType(renderType); objective.setRenderType(renderType);
return LazyValue.TRUE; return Value.TRUE;
} }
return (_c, _t) -> StringValue.of(objective.getRenderType().getName()); return StringValue.of(objective.getRenderType().getName());
default: default:
throw new InternalExpressionException("scoreboard property '" + property + "' is not a valid property"); throw new InternalExpressionException("scoreboard property '" + property + "' is not a valid property");
} }
}); });
expression.addLazyFunction("scoreboard_display", 2, (c, t, lv) -> expression.addContextFunction("scoreboard_display", 2, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); Scoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
String location = lv.get(0).evalValue(c).getString(); String location = lv.get(0).getString();
int slot = Scoreboard.getDisplaySlotId(location); int slot = Scoreboard.getDisplaySlotId(location);
if (slot < 0) throw new InternalExpressionException("Invalid objective slot: "+location); if (slot < 0) throw new InternalExpressionException("Invalid objective slot: "+location);
Value target = lv.get(1).evalValue(c); Value target = lv.get(1);
if (target instanceof NullValue) if (target instanceof NullValue)
{ {
scoreboard.setObjectiveSlot(slot, null); scoreboard.setObjectiveSlot(slot, null);
return (_c, _t) -> new NumericValue(slot); return new NumericValue(slot);
} }
String objectiveString = target.getString(); String objectiveString = target.getString();
ScoreboardObjective objective = scoreboard.getObjective(objectiveString); ScoreboardObjective objective = scoreboard.getObjective(objectiveString);
if (objective == null) return LazyValue.NULL; if (objective == null) return Value.NULL;
scoreboard.setObjectiveSlot(slot, objective); scoreboard.setObjectiveSlot(slot, objective);
return (_c, _t) -> new NumericValue(slot); return new NumericValue(slot);
}); });
expression.addLazyFunction("team_list", -1, (c, t, lv) -> expression.addContextFunction("team_list", -1, (c, t, lv) ->
{ {
if(lv.size() > 1) throw new InternalExpressionException("'team_list' requires zero or one parameters"); if(lv.size() > 1) throw new InternalExpressionException("'team_list' requires zero or one parameters");
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
if(lv.size() == 0) { if(lv.size() == 0)
Value ret = ListValue.wrap(scoreboard.getTeamNames().stream().map(StringValue::of).collect(Collectors.toList())); return ListValue.wrap(scoreboard.getTeamNames().stream().map(StringValue::of).collect(Collectors.toList()));
return (_c, _t) -> ret; if (lv.size() != 1) return Value.NULL;
} else if(lv.size() == 1) { Team team = scoreboard.getTeam(lv.get(0).getString());
Team team = scoreboard.getTeam(lv.get(0).evalValue(c).getString()); if(team == null) return Value.NULL;
if(team == null) return LazyValue.NULL; return ListValue.wrap(team.getPlayerList().stream().map(StringValue::of).collect(Collectors.toList()));
Value ret = ListValue.wrap(team.getPlayerList().stream().map(StringValue::of).collect(Collectors.toList()));
return (_c, _t) -> ret;
} else {
return LazyValue.NULL;
}
}); });
expression.addLazyFunction("team_add", -1, (c, t, lv) -> expression.addContextFunction("team_add", -1, (c, t, lv) ->
{ {
if(!(lv.size() < 3 && lv.size() > 0)) throw new InternalExpressionException("'team_add' requires one or two parameters"); if(!(lv.size() < 3 && lv.size() > 0)) throw new InternalExpressionException("'team_add' requires one or two parameters");
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
String teamName = lv.get(0).evalValue(c).getString(); String teamName = lv.get(0).getString();
if(lv.size() == 1) { if(lv.size() == 1)
if(scoreboard.getTeam(teamName) == null) { {
scoreboard.addTeam(teamName); if (scoreboard.getTeam(teamName) != null) return Value.NULL;
Value ret = new StringValue(teamName); scoreboard.addTeam(teamName);
return (_c, _t) -> ret; return new StringValue(teamName);
} else {
return LazyValue.NULL;
}
} else if(lv.size() == 2) {
Value playerVal = lv.get(1).evalValue(c);
String player = EntityValue.getPlayerNameByValue(playerVal);
if(player == null) return LazyValue.NULL;
Team team = scoreboard.getTeam(teamName);
if(team == null) return LazyValue.NULL;
if(team.isEqual(scoreboard.getPlayerTeam(player))) {
return LazyValue.FALSE;
} else {
scoreboard.addPlayerToTeam(player,scoreboard.getTeam(teamName));
return LazyValue.TRUE;
}
} else {
return LazyValue.NULL;
} }
}); if(lv.size() != 2) return Value.NULL;
Value playerVal = lv.get(1);
expression.addLazyFunction("team_remove", 1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
Value teamVal = lv.get(0).evalValue(c);
String team = teamVal.getString();
if(scoreboard.getTeam(team) != null) {
scoreboard.removeTeam(scoreboard.getTeam(team));
return LazyValue.TRUE;
} else {
return LazyValue.NULL;
}
});
expression.addLazyFunction("team_leave", 1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
Value playerVal = lv.get(0).evalValue(c);
String player = EntityValue.getPlayerNameByValue(playerVal); String player = EntityValue.getPlayerNameByValue(playerVal);
if(player == null) return LazyValue.NULL; if(player == null) return Value.NULL;
Team team = scoreboard.getTeam(teamName);
Value ret = new NumericValue(scoreboard.clearPlayerTeam(player)); if(team == null) return Value.NULL;
return (_c, _t) -> ret; if(team.isEqual(scoreboard.getPlayerTeam(player))) return Value.FALSE;
scoreboard.addPlayerToTeam(player,scoreboard.getTeam(teamName));
return Value.TRUE;
}); });
expression.addLazyFunction("team_property", -1, (c, t, lv) -> expression.addContextFunction("team_remove", 1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
Value teamVal = lv.get(0);
String team = teamVal.getString();
if(scoreboard.getTeam(team) == null) return Value.NULL;
scoreboard.removeTeam(scoreboard.getTeam(team));
return Value.TRUE;
});
expression.addContextFunction("team_leave", 1, (c, t, lv) ->
{
CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
Value playerVal = lv.get(0);
String player = EntityValue.getPlayerNameByValue(playerVal);
if(player == null) return Value.NULL;
return new NumericValue(scoreboard.clearPlayerTeam(player));
});
expression.addContextFunction("team_property", -1, (c, t, lv) ->
{ {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard(); ServerScoreboard scoreboard = cc.s.getMinecraftServer().getScoreboard();
if(lv.size() < 2 || lv.size() > 3) throw new InternalExpressionException("'team_property' requires two or three arguments"); if(lv.size() < 2 || lv.size() > 3) throw new InternalExpressionException("'team_property' requires two or three arguments");
Value teamVal = lv.get(0).evalValue(c); Value teamVal = lv.get(0);
Value propertyVal = lv.get(1).evalValue(c); Value propertyVal = lv.get(1);
Value settingVal = null; Value settingVal = null;
boolean modifying = false; boolean modifying = false;
if(lv.size() == 3) { if(lv.size() == 3)
{
modifying = true; modifying = true;
settingVal = lv.get(2).evalValue(c); settingVal = lv.get(2);
} }
Team team = scoreboard.getTeam(teamVal.getString()); Team team = scoreboard.getTeam(teamVal.getString());
if(team == null) return LazyValue.NULL; if(team == null) return Value.NULL;
if(!(propertyVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the second argument"); if(!(propertyVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the second argument");
switch (propertyVal.getString()) { switch (propertyVal.getString()) {
case "collisionRule": case "collisionRule":
if(!modifying) { if(!modifying) return new StringValue(team.getCollisionRule().name);
Value ret = new StringValue(team.getCollisionRule().name);
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString());
AbstractTeam.CollisionRule collisionRule = AbstractTeam.CollisionRule.getRule(settingVal.getString()); AbstractTeam.CollisionRule collisionRule = AbstractTeam.CollisionRule.getRule(settingVal.getString());
if(collisionRule == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); if(collisionRule == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString());
team.setCollisionRule(collisionRule); team.setCollisionRule(collisionRule);
break; break;
case "color": case "color":
if(!modifying) { if(!modifying) return new StringValue(team.getColor().getName());
Value ret = new StringValue(team.getColor().getName());
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString());
Formatting color = Formatting.byName(settingVal.getString().toUpperCase()); Formatting color = Formatting.byName(settingVal.getString().toUpperCase());
if(color == null || !color.isColor()) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); if(color == null || !color.isColor()) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString());
team.setColor(color); team.setColor(color);
break; break;
case "deathMessageVisibility": case "deathMessageVisibility":
if(!modifying) { if(!modifying) return new StringValue(team.getDeathMessageVisibilityRule().name);
Value ret = new StringValue(team.getDeathMessageVisibilityRule().name);
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString());
AbstractTeam.VisibilityRule deathMessageVisibility = AbstractTeam.VisibilityRule.getRule(settingVal.getString()); AbstractTeam.VisibilityRule deathMessageVisibility = AbstractTeam.VisibilityRule.getRule(settingVal.getString());
if(deathMessageVisibility == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); if(deathMessageVisibility == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString());
team.setDeathMessageVisibilityRule(deathMessageVisibility); team.setDeathMessageVisibilityRule(deathMessageVisibility);
break; break;
case "displayName": case "displayName":
if(!modifying) { if(!modifying) return new FormattedTextValue(team.getDisplayName());
Value ret = new FormattedTextValue(team.getDisplayName());
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string or formatted text as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string or formatted text as the third argument for the property " + propertyVal.getString());
Text displayName; Text displayName;
displayName = FormattedTextValue.getTextByValue(settingVal); displayName = FormattedTextValue.getTextByValue(settingVal);
team.setDisplayName(displayName); team.setDisplayName(displayName);
break; break;
case "friendlyFire": case "friendlyFire":
if(!modifying) { if(!modifying) return new NumericValue(team.isFriendlyFireAllowed());
Value ret = new NumericValue(team.isFriendlyFireAllowed());
return (_c, _t) -> ret;
}
if(!(settingVal instanceof NumericValue)) throw new InternalExpressionException("'team_property' requires a boolean as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof NumericValue)) throw new InternalExpressionException("'team_property' requires a boolean as the third argument for the property " + propertyVal.getString());
boolean friendlyFire = settingVal.getBoolean(); boolean friendlyFire = settingVal.getBoolean();
team.setFriendlyFireAllowed(friendlyFire); team.setFriendlyFireAllowed(friendlyFire);
break; break;
case "nametagVisibility": case "nametagVisibility":
if(!modifying) { if(!modifying) return new StringValue(team.getNameTagVisibilityRule().name);
Value ret = new StringValue(team.getNameTagVisibilityRule().name);
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string as the third argument for the property " + propertyVal.getString());
AbstractTeam.VisibilityRule nametagVisibility = AbstractTeam.VisibilityRule.getRule(settingVal.getString()); AbstractTeam.VisibilityRule nametagVisibility = AbstractTeam.VisibilityRule.getRule(settingVal.getString());
if(nametagVisibility == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString()); if(nametagVisibility == null) throw new InternalExpressionException("Unknown value for property " + propertyVal.getString() + ": " + settingVal.getString());
team.setNameTagVisibilityRule(nametagVisibility); team.setNameTagVisibilityRule(nametagVisibility);
break; break;
case "prefix": case "prefix":
if(!modifying) { if(!modifying) return new FormattedTextValue(team.getPrefix());
Value ret = new FormattedTextValue(team.getPrefix());
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property ' requires a string or formatted text as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property ' requires a string or formatted text as the third argument for the property " + propertyVal.getString());
Text prefix; Text prefix;
prefix = FormattedTextValue.getTextByValue(settingVal); prefix = FormattedTextValue.getTextByValue(settingVal);
team.setPrefix(prefix); team.setPrefix(prefix);
break; break;
case "seeFriendlyInvisibles": case "seeFriendlyInvisibles":
if(!modifying) { if(!modifying) return new NumericValue(team.shouldShowFriendlyInvisibles());
Value ret = new NumericValue(team.shouldShowFriendlyInvisibles());
return (_c, _t) -> ret;
}
if(!(settingVal instanceof NumericValue)) throw new InternalExpressionException("'team_property' requires a boolean as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof NumericValue)) throw new InternalExpressionException("'team_property' requires a boolean as the third argument for the property " + propertyVal.getString());
boolean seeFriendlyInvisibles = settingVal.getBoolean(); boolean seeFriendlyInvisibles = settingVal.getBoolean();
team.setShowFriendlyInvisibles(seeFriendlyInvisibles); team.setShowFriendlyInvisibles(seeFriendlyInvisibles);
break; break;
case "suffix": case "suffix":
if(!modifying) { if(!modifying) return new FormattedTextValue(team.getSuffix());
Value ret = new FormattedTextValue(team.getSuffix());
return (_c, _t) -> ret;
}
if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string or formatted text as the third argument for the property " + propertyVal.getString()); if(!(settingVal instanceof StringValue)) throw new InternalExpressionException("'team_property' requires a string or formatted text as the third argument for the property " + propertyVal.getString());
Text suffix; Text suffix;
suffix = FormattedTextValue.getTextByValue(settingVal); suffix = FormattedTextValue.getTextByValue(settingVal);
team.setSuffix(suffix); team.setSuffix(suffix);
break; break;
default: default:
throw new InternalExpressionException("team property '" + propertyVal.getString() + "' is not a valid property"); throw new InternalExpressionException("team property '" + propertyVal.getString() + "' is not a valid property");
} }
return LazyValue.TRUE; return Value.TRUE;
}); });
expression.addLazyFunction("bossbar", -1, (c, t, lv) -> expression.addContextFunction("bossbar", -1, (c, t, lv) ->
{ {
BossBarManager bossBarManager = ((CarpetContext)c).s.getMinecraftServer().getBossBarManager(); BossBarManager bossBarManager = ((CarpetContext)c).s.getMinecraftServer().getBossBarManager();
if(lv.size() > 3) throw new InternalExpressionException("'bossbar' accepts max three arguments"); if(lv.size() > 3) throw new InternalExpressionException("'bossbar' accepts max three arguments");
if(lv.size() == 0) { if(lv.size() == 0) return ListValue.wrap(bossBarManager.getAll().stream().map(CommandBossBar::getId).map(Identifier::toString).map(StringValue::of).collect(Collectors.toList()));
Value ret = ListValue.wrap(bossBarManager.getAll().stream().map(CommandBossBar::getId).map(Identifier::toString).map(StringValue::of).collect(Collectors.toList()));
return (_c, _t) -> ret;
}
String id = lv.get(0).evalValue(c).getString(); String id = lv.get(0).getString();
Identifier identifier; Identifier identifier;
try { try
{
identifier = new Identifier(id); identifier = new Identifier(id);
} catch (InvalidIdentifierException invalidIdentifierException) { }
return LazyValue.NULL; catch (InvalidIdentifierException invalidIdentifierException)
{
return Value.NULL;
} }
if(lv.size() == 1) { if(lv.size() == 1)
if(bossBarManager.get(identifier) != null) return LazyValue.FALSE; {
Value ret = StringValue.of(bossBarManager.add(identifier,new LiteralText(id)).getId().toString()); if(bossBarManager.get(identifier) != null) return Value.FALSE;
return (_c, _t) -> ret; return StringValue.of(bossBarManager.add(identifier,new LiteralText(id)).getId().toString());
} }
String property = lv.get(1).evalValue(c).getString(); String property = lv.get(1).getString();
CommandBossBar bossBar = bossBarManager.get(identifier); CommandBossBar bossBar = bossBarManager.get(identifier);
if(bossBar == null) return LazyValue.NULL; if(bossBar == null) return Value.NULL;
Value propertyValue = (lv.size() == 3)?lv.get(2).evalValue(c):null; Value propertyValue = (lv.size() == 3)?lv.get(2):null;
switch (property) { switch (property) {
case "color": case "color":
if(propertyValue == null) { if(propertyValue == null) {
BossBar.Color color = (bossBar).getColor(); BossBar.Color color = (bossBar).getColor();
if(color == null) return LazyValue.NULL; if(color == null) return Value.NULL;
return (_c, _t) -> StringValue.of(color.getName()); return StringValue.of(color.getName());
} }
BossBar.Color color = BossBar.Color.byName(propertyValue.getString()); BossBar.Color color = BossBar.Color.byName(propertyValue.getString());
if(color == null) return LazyValue.NULL; if(color == null) return Value.NULL;
bossBar.setColor(BossBar.Color.byName(propertyValue.getString())); bossBar.setColor(BossBar.Color.byName(propertyValue.getString()));
return LazyValue.TRUE; return Value.TRUE;
case "max": case "max":
if(propertyValue == null) return (_c, _t) -> NumericValue.of(bossBar.getMaxValue()); if(propertyValue == null) return NumericValue.of(bossBar.getMaxValue());
if(!(propertyValue instanceof NumericValue)) throw new InternalExpressionException("'bossbar' requires a number as the value for the property " + property); if(!(propertyValue instanceof NumericValue)) throw new InternalExpressionException("'bossbar' requires a number as the value for the property " + property);
bossBar.setMaxValue(((NumericValue) propertyValue).getInt()); bossBar.setMaxValue(((NumericValue) propertyValue).getInt());
return LazyValue.TRUE; return Value.TRUE;
case "name": case "name":
if(propertyValue == null) return (_c, _t) -> new FormattedTextValue(bossBar.getName()); if(propertyValue == null) return new FormattedTextValue(bossBar.getName());
bossBar.setName(FormattedTextValue.getTextByValue(propertyValue)); bossBar.setName(FormattedTextValue.getTextByValue(propertyValue));
return LazyValue.TRUE; return Value.TRUE;
case "add_player": case "add_player":
if(propertyValue == null) throw new InternalExpressionException("Bossbar property " + property + " can't be queried, add a third parameter"); if(propertyValue == null) throw new InternalExpressionException("Bossbar property " + property + " can't be queried, add a third parameter");
@@ -545,27 +458,25 @@ public class Scoreboards {
ServerPlayerEntity player = EntityValue.getPlayerByValue(((CarpetContext)c).s.getMinecraftServer(),propertyValue); ServerPlayerEntity player = EntityValue.getPlayerByValue(((CarpetContext)c).s.getMinecraftServer(),propertyValue);
if(player != null) bossBar.addPlayer(player); if(player != null) bossBar.addPlayer(player);
}); });
return LazyValue.TRUE; return Value.TRUE;
} }
ServerPlayerEntity player = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), propertyValue); ServerPlayerEntity player = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), propertyValue);
if(player != null) { if(player != null) {
bossBar.addPlayer(player); bossBar.addPlayer(player);
return LazyValue.TRUE; return Value.TRUE;
} }
return LazyValue.FALSE; return Value.FALSE;
case "players": case "players":
if(propertyValue == null) { if (propertyValue == null) return ListValue.wrap(bossBar.getPlayers().stream().map(EntityValue::new).collect(Collectors.toList()));
return (_c, _t) -> ListValue.wrap(bossBar.getPlayers().stream().map(EntityValue::new).collect(Collectors.toList())); if(propertyValue instanceof ListValue)
} {
if(propertyValue instanceof ListValue) {
bossBar.clearPlayers(); bossBar.clearPlayers();
((ListValue) propertyValue).getItems().forEach((v) -> { ((ListValue) propertyValue).getItems().forEach((v) -> {
ServerPlayerEntity p = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), v); ServerPlayerEntity p = EntityValue.getPlayerByValue(((CarpetContext) c).s.getMinecraftServer(), v);
if (p != null) bossBar.addPlayer(p); if (p != null) bossBar.addPlayer(p);
}); });
return LazyValue.TRUE; return Value.TRUE;
} }
@@ -573,32 +484,29 @@ public class Scoreboards {
bossBar.clearPlayers(); bossBar.clearPlayers();
if (p != null) { if (p != null) {
bossBar.addPlayer(p); bossBar.addPlayer(p);
return LazyValue.TRUE; return Value.TRUE;
} }
return LazyValue.FALSE; return Value.FALSE;
case "style": case "style":
if(propertyValue == null) { if(propertyValue == null) return StringValue.of(bossBar.getOverlay().getName());
return (_c, _t) -> StringValue.of(bossBar.getOverlay().getName());
}
BossBar.Style style = BossBar.Style.byName(propertyValue.getString()); BossBar.Style style = BossBar.Style.byName(propertyValue.getString());
if(style == null) throw new InternalExpressionException("'" + propertyValue.getString() + "' is not a valid value for property " + property); if(style == null) throw new InternalExpressionException("'" + propertyValue.getString() + "' is not a valid value for property " + property);
bossBar.setOverlay(style); bossBar.setOverlay(style);
return LazyValue.TRUE; return Value.TRUE;
case "value": case "value":
if(propertyValue == null) return (_c, _t) -> NumericValue.of(bossBar.getValue()); if(propertyValue == null) return NumericValue.of(bossBar.getValue());
if(!(propertyValue instanceof NumericValue)) throw new InternalExpressionException("'bossbar' requires a number as the value for the property " + property); if(!(propertyValue instanceof NumericValue)) throw new InternalExpressionException("'bossbar' requires a number as the value for the property " + property);
bossBar.setValue(((NumericValue) propertyValue).getInt()); bossBar.setValue(((NumericValue) propertyValue).getInt());
return LazyValue.TRUE; return Value.TRUE;
case "visible": case "visible":
if(propertyValue == null) return (_c, _t) -> new NumericValue(bossBar.isVisible()); if(propertyValue == null) return new NumericValue(bossBar.isVisible());
bossBar.setVisible(propertyValue.getBoolean()); bossBar.setVisible(propertyValue.getBoolean());
return LazyValue.TRUE; return Value.TRUE;
case "remove": case "remove":
bossBarManager.remove(bossBar); bossBarManager.remove(bossBar);
return LazyValue.TRUE; return Value.TRUE;
default: default:
throw new InternalExpressionException("Unknown bossbar property " + property); throw new InternalExpressionException("Unknown bossbar property " + property);
} }
@@ -15,16 +15,16 @@ public class Threading
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
//"overidden" native call to cancel if on main thread //"overidden" native call to cancel if on main thread
expression.addLazyFunction("task_join", 1, (c, t, lv) -> { expression.addContextFunction("task_join", 1, (c, t, lv) -> {
if (((CarpetContext)c).s.getMinecraftServer().isOnThread()) if (((CarpetContext)c).s.getMinecraftServer().isOnThread())
throw new InternalExpressionException("'task_join' cannot be called from main thread to avoid deadlocks"); throw new InternalExpressionException("'task_join' cannot be called from main thread to avoid deadlocks");
Value v = lv.get(0).evalValue(c); Value v = lv.get(0);
if (!(v instanceof ThreadValue)) if (!(v instanceof ThreadValue))
throw new InternalExpressionException("'task_join' could only be used with a task value"); throw new InternalExpressionException("'task_join' could only be used with a task value");
Value ret = ((ThreadValue) v).join(); return ((ThreadValue) v).join();
return (_c, _t) -> ret;
}); });
// has to be lazy due to deferred execution of the expression
expression.addLazyFunctionWithDelegation("task_dock", 1, (c, t, expr, tok, lv) -> { expression.addLazyFunctionWithDelegation("task_dock", 1, (c, t, expr, tok, lv) -> {
CarpetContext cc = (CarpetContext)c; CarpetContext cc = (CarpetContext)c;
MinecraftServer server = cc.s.getMinecraftServer(); MinecraftServer server = cc.s.getMinecraftServer();
File diff suppressed because it is too large. Load diff
@@ -29,21 +29,22 @@ public class BlockArgument extends Argument
block = b; block = b;
this.replacement = replacement; this.replacement = replacement;
} }
public static BlockArgument findIn(CarpetContext c, List<LazyValue> params, int offset)
public static BlockArgument findIn(CarpetContext c, List<Value> params, int offset)
{ {
return findIn(c, params,offset, false, false, false); return findIn(c, params,offset, false, false, false);
} }
public static BlockArgument findIn(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString) public static BlockArgument findIn(CarpetContext c, List<Value> params, int offset, boolean acceptString)
{ {
return findIn(c, params,offset, acceptString, false, false); return findIn(c, params,offset, acceptString, false, false);
} }
public static BlockArgument findIn(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString, boolean optional, boolean anyString) public static BlockArgument findIn(CarpetContext c, List<Value> params, int offset, boolean acceptString, boolean optional, boolean anyString)
{ {
try try
{ {
Value v1 = params.get(0 + offset).evalValue(c); Value v1 = params.get(0 + offset);
//add conditional from string name //add conditional from string name
if (optional && v1 instanceof NullValue) if (optional && v1 instanceof NullValue)
{ {
@@ -76,8 +77,8 @@ public class BlockArgument extends Argument
1+offset); 1+offset);
} }
int xpos = (int) NumericValue.asNumber(v1).getLong(); int xpos = (int) NumericValue.asNumber(v1).getLong();
int ypos = (int) NumericValue.asNumber( params.get(1 + offset).evalValue(c)).getLong(); int ypos = (int) NumericValue.asNumber( params.get(1 + offset)).getLong();
int zpos = (int) NumericValue.asNumber( params.get(2 + offset).evalValue(c)).getLong(); int zpos = (int) NumericValue.asNumber( params.get(2 + offset)).getLong();
return new BlockArgument( return new BlockArgument(
new BlockValue( new BlockValue(
null, null,
@@ -117,11 +117,11 @@ public class FileArgument
return "path: "+resource+" zip: "+zipContainer+" type: "+type.id+" folder: "+isFolder+" shared: "+isShared+" reason: "+reason.toString(); return "path: "+resource+" zip: "+zipContainer+" type: "+type.id+" folder: "+isFolder+" shared: "+isShared+" reason: "+reason.toString();
} }
public static FileArgument from(List<LazyValue> lv, Context c, boolean isFolder, Reason reason) public static FileArgument from(List<Value> lv, boolean isFolder, Reason reason)
{ {
if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments"); if (lv.size() < 2) throw new InternalExpressionException("File functions require path and type as first two arguments");
Pair<String, String> resource = recognizeResource(lv.get(0).evalValue(c), isFolder); Pair<String, String> resource = recognizeResource(lv.get(0), isFolder);
String origtype = lv.get(1).evalValue(c).getString().toLowerCase(Locale.ROOT); String origtype = lv.get(1).getString().toLowerCase(Locale.ROOT);
boolean shared = origtype.startsWith("shared_"); boolean shared = origtype.startsWith("shared_");
String typeString = shared ? origtype.substring(7) : origtype; //len(shared_) String typeString = shared ? origtype.substring(7) : origtype; //len(shared_)
Type type = Type.of.get(typeString); Type type = Type.of.get(typeString);
@@ -1,6 +1,7 @@
package carpet.script.argument; package carpet.script.argument;
import carpet.script.Context; import carpet.script.Context;
import carpet.script.Fluff;
import carpet.script.LazyValue; import carpet.script.LazyValue;
import carpet.script.ScriptHost; import carpet.script.ScriptHost;
import carpet.script.bundled.Module; import carpet.script.bundled.Module;
@@ -15,12 +16,12 @@ import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.List; import java.util.List;
public class FunctionArgument<T> extends Argument public class FunctionArgument extends Argument
{ {
public FunctionValue function; public FunctionValue function;
public List<T> args; public List<Value> args;
private FunctionArgument(FunctionValue function, int offset, List<T> args) private FunctionArgument(FunctionValue function, int offset, List<Value> args)
{ {
super(offset); super(offset);
this.function = function; this.function = function;
@@ -38,18 +39,18 @@ public class FunctionArgument<T> extends Argument
* if the number of supplied arguments is right * if the number of supplied arguments is right
* @return argument data * @return argument data
*/ */
public static FunctionArgument<LazyValue> findIn( public static FunctionArgument findIn(
Context c, Context c,
Module module, Module module,
List<LazyValue> params, List<Value> params,
int offset, int offset,
boolean allowNone, boolean allowNone,
boolean checkArgs) boolean checkArgs)
{ {
Value functionValue = params.get(offset).evalValue(c); Value functionValue = params.get(offset);
if (functionValue.isNull()) if (functionValue.isNull())
{ {
if (allowNone) return new FunctionArgument<>(null, offset+1, Collections.emptyList()); if (allowNone) return new FunctionArgument(null, offset+1, Collections.emptyList());
throw new InternalExpressionException("function argument cannot be null"); throw new InternalExpressionException("function argument cannot be null");
} }
if (!(functionValue instanceof FunctionValue)) if (!(functionValue instanceof FunctionValue))
@@ -67,12 +68,12 @@ public class FunctionArgument<T> extends Argument
if (extraargs > 0 && fun.getVarArgs() == null) if (extraargs > 0 && fun.getVarArgs() == null)
throw new InternalExpressionException("Function " + fun.getPrettyString() + " requires " + fun.getArguments().size() + " arguments"); throw new InternalExpressionException("Function " + fun.getPrettyString() + " requires " + fun.getArguments().size() + " arguments");
} }
List<LazyValue> lvargs = new ArrayList<>(); List<Value> lvargs = new ArrayList<>();
for (int i = offset+1, mx = params.size(); i < mx; i++) lvargs.add(params.get(i)); for (int i = offset+1, mx = params.size(); i < mx; i++) lvargs.add(params.get(i));
return new FunctionArgument<>(fun, offset + 1 + argsize, lvargs); return new FunctionArgument(fun, offset + 1 + argsize, lvargs);
} }
public static FunctionArgument<Value> fromCommandSpec(ScriptHost host, Value funSpec) throws CommandSyntaxException { public static FunctionArgument fromCommandSpec(ScriptHost host, Value funSpec) throws CommandSyntaxException {
FunctionValue function; FunctionValue function;
List<Value> args = Collections.emptyList(); List<Value> args = Collections.emptyList();
if (!(funSpec instanceof ListValue)) if (!(funSpec instanceof ListValue))
@@ -92,6 +93,11 @@ public class FunctionArgument<T> extends Argument
} }
if (params.size() > 1) args = params.subList(1,params.size()); if (params.size() > 1) args = params.subList(1,params.size());
return new FunctionArgument<>(function, 0, args); return new FunctionArgument(function, 0, args);
}
public List<Value> checkedArgs() {
function.checkArgs(args.size());
return args;
} }
} }
@@ -47,66 +47,12 @@ public class Vector3Argument extends Argument
return this; return this;
} }
public static Vector3Argument findIn(List<Value> params, int offset)
public static Vector3Argument findIn(CarpetContext c, List<LazyValue> params, int offset)
{ {
return findIn(c,params, offset, false, false); return findIn(params, offset, false, false);
} }
public static Vector3Argument findIn(CarpetContext c, List<LazyValue> params, int offset, boolean optionalDirection, boolean optionalEntity) public static Vector3Argument findIn(List<Value> params, int offset, boolean optionalDirection, boolean optionalEntity)
{
try
{
Value v1 = params.get(0 + offset).evalValue(c);
if (v1 instanceof BlockValue)
{
// pos + 0.5v
return (new Vector3Argument(Vec3d.ofCenter(((BlockValue) v1).getPos()), 1+offset)).fromBlock();
}
if (optionalEntity && v1 instanceof EntityValue)
{
Entity e = ((EntityValue) v1).getEntity();
return new Vector3Argument(e.getPos(), 1+offset).withEntity(e);
}
if (v1 instanceof ListValue)
{
List<Value> args = ((ListValue) v1).getItems();
Vec3d pos = new Vec3d(
NumericValue.asNumber(args.get(0)).getDouble(),
NumericValue.asNumber(args.get(1)).getDouble(),
NumericValue.asNumber(args.get(2)).getDouble());
double yaw = 0.0D;
double pitch = 0.0D;
if (args.size()>3 && optionalDirection)
{
yaw = NumericValue.asNumber(args.get(3)).getDouble();
pitch = NumericValue.asNumber(args.get(4)).getDouble();
}
return new Vector3Argument(pos,offset+1, yaw, pitch);
}
Vec3d pos = new Vec3d(
NumericValue.asNumber(v1).getDouble(),
NumericValue.asNumber(params.get(1 + offset).evalValue(c)).getDouble(),
NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble());
double yaw = 0.0D;
double pitch = 0.0D;
int eatenLength = 3;
if (params.size()>3+offset && optionalDirection)
{
yaw = NumericValue.asNumber(params.get(3 + offset).evalValue(c)).getDouble();
pitch = NumericValue.asNumber(params.get(4 + offset).evalValue(c)).getDouble();
eatenLength = 5;
}
return new Vector3Argument(pos,offset+eatenLength, yaw, pitch);
}
catch (IndexOutOfBoundsException e)
{
throw new InternalExpressionException("Position argument should be defined either by three coordinates (a triple or by three arguments), or a positioned block value");
}
}
public static Vector3Argument findIn(List<Value> params, int offset, boolean optionalDirection)
{ {
try try
{ {
@@ -115,6 +61,11 @@ public class Vector3Argument extends Argument
{ {
return (new Vector3Argument(Vec3d.ofCenter(((BlockValue) v1).getPos()), 1+offset)).fromBlock(); return (new Vector3Argument(Vec3d.ofCenter(((BlockValue) v1).getPos()), 1+offset)).fromBlock();
} }
if (optionalEntity && v1 instanceof EntityValue)
{
Entity e = ((EntityValue) v1).getEntity();
return new Vector3Argument(e.getPos(), 1+offset).withEntity(e);
}
if (v1 instanceof ListValue) if (v1 instanceof ListValue)
{ {
List<Value> args = ((ListValue) v1).getItems(); List<Value> args = ((ListValue) v1).getItems();
@@ -291,7 +291,7 @@ public abstract class CommandArgument
protected boolean needsMatching; protected boolean needsMatching;
protected boolean caseSensitive = true; protected boolean caseSensitive = true;
protected SuggestionProvider<ServerCommandSource> suggestionProvider; protected SuggestionProvider<ServerCommandSource> suggestionProvider;
protected FunctionArgument<Value> customSuggester; protected FunctionArgument customSuggester;
protected CommandArgument( protected CommandArgument(
@@ -64,10 +64,10 @@ public class Arithmetic {
expression.addMathematicalUnaryIntFunction("floor", n -> (long)Math.floor(n)); expression.addMathematicalUnaryIntFunction("floor", n -> (long)Math.floor(n));
expression.addMathematicalUnaryIntFunction("ceil", n -> (long)Math.ceil(n)); expression.addMathematicalUnaryIntFunction("ceil", n -> (long)Math.ceil(n));
expression.addLazyFunction("mandelbrot", 3, (c, t, lv) -> { expression.addContextFunction("mandelbrot", 3, (c, t, lv) -> {
double a0 = NumericValue.asNumber(lv.get(0).evalValue(c)).getDouble(); double a0 = NumericValue.asNumber(lv.get(0)).getDouble();
double b0 = NumericValue.asNumber(lv.get(1).evalValue(c)).getDouble(); double b0 = NumericValue.asNumber(lv.get(1)).getDouble();
long maxiter = NumericValue.asNumber(lv.get(2).evalValue(c)).getLong(); long maxiter = NumericValue.asNumber(lv.get(2)).getLong();
double a = 0.0D; double a = 0.0D;
double b = 0.0D; double b = 0.0D;
long iter = 0; long iter = 0;
@@ -79,7 +79,7 @@ public class Arithmetic {
iter++; iter++;
} }
long iFinal = iter; long iFinal = iter;
return (cc, tt) -> new NumericValue(iFinal); return new NumericValue(iFinal);
}); });
expression.addFunction("max", (lv) -> expression.addFunction("max", (lv) ->
@@ -20,6 +20,7 @@ import java.util.stream.Collectors;
public class ControlFlow { public class ControlFlow {
public static void apply(Expression expression) // public just to get the javadoc right public static void apply(Expression expression) // public just to get the javadoc right
{ {
// needs to be lazy cause of custom contextualization
expression.addLazyBinaryOperator(";", Operators.precedence.get("nextop;"), true, (c, t, lv1, lv2) -> expression.addLazyBinaryOperator(";", Operators.precedence.get("nextop;"), true, (c, t, lv1, lv2) ->
{ {
lv1.evalValue(c, Context.VOID); lv1.evalValue(c, Context.VOID);
@@ -27,7 +28,7 @@ public class ControlFlow {
return (cc, tt) -> v2; return (cc, tt) -> v2;
}); });
// if(cond1, expr1, cond2, expr2, ..., ?default) => value // obvious lazy due to conditional evaluation of arguments
expression.addLazyFunction("if", -1, (c, t, lv) -> expression.addLazyFunction("if", -1, (c, t, lv) ->
{ {
if ( lv.size() < 2 ) if ( lv.size() < 2 )
@@ -51,23 +52,24 @@ public class ControlFlow {
expression.addFunction("exit", (lv) -> { throw new ExitStatement(lv.size()==0?Value.NULL:lv.get(0)); }); expression.addFunction("exit", (lv) -> { throw new ExitStatement(lv.size()==0?Value.NULL:lv.get(0)); });
expression.addLazyFunction("throw", -1, (c, t, lv)-> expression.addFunction("throw", lv->
{ {
switch (lv.size()) switch (lv.size())
{ {
case 0: case 0:
throw new ThrowStatement(Value.NULL, Throwables.USER_DEFINED); throw new ThrowStatement(Value.NULL, Throwables.USER_DEFINED);
case 1: case 1:
throw new ThrowStatement(lv.get(0).evalValue(c), Throwables.USER_DEFINED ); throw new ThrowStatement(lv.get(0), Throwables.USER_DEFINED );
case 2: case 2:
throw new ThrowStatement(lv.get(1).evalValue(c), Throwables.getTypeForException(lv.get(0).evalValue(c).getString())); throw new ThrowStatement(lv.get(1), Throwables.getTypeForException(lv.get(0).getString()));
case 3: case 3:
throw new ThrowStatement(lv.get(2).evalValue(c), Throwables.getTypeForException(lv.get(1).evalValue(c).getString()), lv.get(0).evalValue(c).getString()); throw new ThrowStatement(lv.get(2), Throwables.getTypeForException(lv.get(1).getString()), lv.get(0).getString());
default: default:
throw new InternalExpressionException("throw() can't accept more than 3 parameters"); throw new InternalExpressionException("throw() can't accept more than 3 parameters");
} }
}); });
// needs to be lazy since execution of parameters but first one are conditional
expression.addLazyFunction("try", -1, (c, t, lv) -> expression.addLazyFunction("try", -1, (c, t, lv) ->
{ {
if (lv.size()==0) if (lv.size()==0)
@@ -95,6 +95,7 @@ public class DataStructures {
return ListValue.wrap(toSort); return ListValue.wrap(toSort);
}); });
// needs lazy cause sort function is reused
expression.addLazyFunction("sort_key", -1, (c, t, lv) -> //get working with iterators expression.addLazyFunction("sort_key", -1, (c, t, lv) -> //get working with iterators
{ {
if (lv.size() == 0) if (lv.size() == 0)
@@ -121,7 +122,8 @@ public class DataStructures {
}); });
//revering scope //revering scope
c.setVariable("_", __); c.setVariable("_", __);
return (cc, tt) -> ListValue.wrap(toSort); Value ret = ListValue.wrap(toSort);
return (cc, tt) -> ret;
}); });
expression.addFunction("range", (lv) -> expression.addFunction("range", (lv) ->
@@ -147,18 +149,14 @@ public class DataStructures {
: LazyListValue.rangeDouble(from.getDouble(), to.getDouble(), step.getDouble()); : LazyListValue.rangeDouble(from.getDouble(), to.getDouble(), step.getDouble());
}); });
expression.addLazyFunction("m", -1, (c, t, llv) -> expression.addTypedContextFunction("m", -1, Context.MAPDEF, (c, t, lv) ->
{ {
List<Value> lv = new ArrayList<>();
for (LazyValue lazyParam : llv) {
lv.add(lazyParam.evalValue(c, Context.MAPDEF)); // none type default by design
}
Value ret; Value ret;
if (lv.size() == 1 && lv.get(0) instanceof LazyListValue) if (lv.size() == 1 && lv.get(0) instanceof LazyListValue)
ret = new MapValue(((LazyListValue) lv.get(0)).unroll()); ret = new MapValue(((LazyListValue) lv.get(0)).unroll());
else else
ret = new MapValue(lv); ret = new MapValue(lv);
return (cc, tt) -> ret; return ret;
}); });
expression.addUnaryFunction("keys", v -> expression.addUnaryFunction("keys", v ->
@@ -184,41 +182,23 @@ public class DataStructures {
return Value.NULL; return Value.NULL;
}); });
expression.addLazyBinaryOperator(":", Operators.precedence.get("attribute~:"),true, (c, t, container_lv, key_lv) -> expression.addBinaryContextOperator(":", Operators.precedence.get("attribute~:"),true, (c, t, container, address) ->
{ {
Value container = container_lv.evalValue(c);
if (container instanceof LContainerValue) if (container instanceof LContainerValue)
{ {
ContainerValueInterface outerContainer = ((LContainerValue) container).getContainer(); ContainerValueInterface outerContainer = ((LContainerValue) container).getContainer();
if (outerContainer == null) if (outerContainer == null) return LContainerValue.NULL_CONTAINER;
{
Value innerLValue = new LContainerValue(null, null);
return (cc, tt) -> innerLValue;
}
Value innerContainer = outerContainer.get(((LContainerValue) container).getAddress()); Value innerContainer = outerContainer.get(((LContainerValue) container).getAddress());
if (!(innerContainer instanceof ContainerValueInterface)) if (!(innerContainer instanceof ContainerValueInterface)) return LContainerValue.NULL_CONTAINER;
{ return new LContainerValue((ContainerValueInterface) innerContainer, address);
Value innerLValue = new LContainerValue(null, null);
return (cc, tt) -> innerLValue;
}
Value innerLValue = new LContainerValue((ContainerValueInterface) innerContainer, key_lv.evalValue(c));
return (cc, tt) -> innerLValue;
} }
if (!(container instanceof ContainerValueInterface)) if (!(container instanceof ContainerValueInterface))
if (t == Context.LVALUE) return t == Context.LVALUE ? LContainerValue.NULL_CONTAINER : Value.NULL;
return (cc, tt) -> new LContainerValue(null, null); if (t != Context.LVALUE) return ((ContainerValueInterface) container).get(address);
else return new LContainerValue((ContainerValueInterface) container, address);
return (cc, tt) -> Value.NULL;
Value address = key_lv.evalValue(c);
if (t != Context.LVALUE)
{
Value retVal = ((ContainerValueInterface) container).get(address);
return (cc, ct) -> retVal;
}
Value retVal = new LContainerValue((ContainerValueInterface) container, address);
return (cc, ct) -> retVal;
}); });
// lazy cause conditional typing - questionable
expression.addLazyFunction("get", -1, (c, t, lv) -> expression.addLazyFunction("get", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
@@ -227,10 +207,10 @@ public class DataStructures {
{ {
Value v = lv.get(0).evalValue(c, Context.LVALUE); Value v = lv.get(0).evalValue(c, Context.LVALUE);
if (!(v instanceof LContainerValue)) if (!(v instanceof LContainerValue))
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
ContainerValueInterface container = ((LContainerValue) v).getContainer(); ContainerValueInterface container = ((LContainerValue) v).getContainer();
if (container == null) if (container == null)
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
Value ret = container.get(((LContainerValue) v).getAddress()); Value ret = container.get(((LContainerValue) v).getAddress());
return (cc, tt) -> ret; return (cc, tt) -> ret;
} }
@@ -246,6 +226,7 @@ public class DataStructures {
return (cc, tt) -> finalContainer; return (cc, tt) -> finalContainer;
}); });
// same as `get`
expression.addLazyFunction("has", -1, (c, t, lv) -> expression.addLazyFunction("has", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
@@ -254,25 +235,26 @@ public class DataStructures {
{ {
Value v = lv.get(0).evalValue(c, Context.LVALUE); Value v = lv.get(0).evalValue(c, Context.LVALUE);
if (!(v instanceof LContainerValue)) if (!(v instanceof LContainerValue))
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
ContainerValueInterface container = ((LContainerValue) v).getContainer(); ContainerValueInterface container = ((LContainerValue) v).getContainer();
if (container == null) if (container == null)
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
Value ret = new NumericValue(container.has(((LContainerValue) v).getAddress())); Value ret = new NumericValue(container.has(((LContainerValue) v).getAddress()));
return (cc, tt) -> ret; return (cc, tt) -> ret;
} }
Value container = lv.get(0).evalValue(c); Value container = lv.get(0).evalValue(c);
for (int i = 1; i < lv.size()-1; i++) for (int i = 1; i < lv.size()-1; i++)
{ {
if (!(container instanceof ContainerValueInterface)) return (cc, tt) -> Value.NULL; if (!(container instanceof ContainerValueInterface)) return LazyValue.NULL;
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c)); container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
} }
if (!(container instanceof ContainerValueInterface)) if (!(container instanceof ContainerValueInterface))
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
Value ret = new NumericValue(((ContainerValueInterface) container).has(lv.get(lv.size()-1).evalValue(c))); Value ret = new NumericValue(((ContainerValueInterface) container).has(lv.get(lv.size()-1).evalValue(c)));
return (cc, tt) -> ret; return (cc, tt) -> ret;
}); });
// same as `get`
expression.addLazyFunction("put", -1, (c, t, lv) -> expression.addLazyFunction("put", -1, (c, t, lv) ->
{ {
if(lv.size()<2) if(lv.size()<2)
@@ -285,7 +267,7 @@ public class DataStructures {
ContainerValueInterface internalContainer = ((LContainerValue) container).getContainer(); ContainerValueInterface internalContainer = ((LContainerValue) container).getContainer();
if (internalContainer == null) if (internalContainer == null)
{ {
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
} }
Value address = ((LContainerValue) container).getAddress(); Value address = ((LContainerValue) container).getAddress();
Value what = lv.get(1).evalValue(c); Value what = lv.get(1).evalValue(c);
@@ -301,7 +283,7 @@ public class DataStructures {
} }
if (!(container instanceof ContainerValueInterface)) if (!(container instanceof ContainerValueInterface))
{ {
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
} }
Value where = lv.get(1).evalValue(c); Value where = lv.get(1).evalValue(c);
Value what = lv.get(2).evalValue(c); Value what = lv.get(2).evalValue(c);
@@ -311,6 +293,7 @@ public class DataStructures {
return (cc, tt) -> retVal; return (cc, tt) -> retVal;
}); });
// same as `get`
expression.addLazyFunction("delete", -1, (c, t, lv) -> expression.addLazyFunction("delete", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
@@ -319,21 +302,21 @@ public class DataStructures {
{ {
Value v = lv.get(0).evalValue(c, Context.LVALUE); Value v = lv.get(0).evalValue(c, Context.LVALUE);
if (!(v instanceof LContainerValue)) if (!(v instanceof LContainerValue))
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
ContainerValueInterface container = ((LContainerValue) v).getContainer(); ContainerValueInterface container = ((LContainerValue) v).getContainer();
if (container == null) if (container == null)
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
Value ret = new NumericValue(container.delete(((LContainerValue) v).getAddress())); Value ret = new NumericValue(container.delete(((LContainerValue) v).getAddress()));
return (cc, tt) -> ret; return (cc, tt) -> ret;
} }
Value container = lv.get(0).evalValue(c); Value container = lv.get(0).evalValue(c);
for (int i = 1; i < lv.size()-1; i++) for (int i = 1; i < lv.size()-1; i++)
{ {
if (!(container instanceof ContainerValueInterface)) return (cc, tt) -> Value.NULL; if (!(container instanceof ContainerValueInterface)) return LazyValue.NULL;
container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c)); container = ((ContainerValueInterface) container).get(lv.get(i).evalValue(c));
} }
if (!(container instanceof ContainerValueInterface)) if (!(container instanceof ContainerValueInterface))
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
Value ret = new NumericValue(((ContainerValueInterface) container).delete(lv.get(lv.size()-1).evalValue(c))); Value ret = new NumericValue(((ContainerValueInterface) container).delete(lv.get(lv.size()-1).evalValue(c)));
return (cc, tt) -> ret; return (cc, tt) -> ret;
}); });
@@ -2,16 +2,19 @@ package carpet.script.language;
import carpet.script.Context; import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.LazyValue; import carpet.script.Fluff;
import carpet.script.argument.FunctionArgument; import carpet.script.argument.FunctionArgument;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ReturnStatement; import carpet.script.exception.ReturnStatement;
import carpet.script.value.AbstractListValue;
import carpet.script.value.FunctionSignatureValue; import carpet.script.value.FunctionSignatureValue;
import carpet.script.value.FunctionUnpackedArgumentsValue;
import carpet.script.value.FunctionValue; import carpet.script.value.FunctionValue;
import carpet.script.value.FunctionAnnotationValue; import carpet.script.value.FunctionAnnotationValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.StringValue; import carpet.script.value.StringValue;
import carpet.script.value.Value; import carpet.script.value.Value;
import com.google.common.collect.ImmutableList;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@@ -22,20 +25,20 @@ public class Functions {
public static void apply(Expression expression) // public just to get the javadoc right public static void apply(Expression expression) // public just to get the javadoc right
{ {
// artificial construct to handle user defined functions and function definitions // artificial construct to handle user defined functions and function definitions
expression.addLazyFunction("import", -1, (c, t, lv) -> expression.addContextFunction("import", -1, (c, t, lv) ->
{ {
if (lv.size() < 1) throw new InternalExpressionException("'import' needs at least a module name to import, and list of values to import"); if (lv.size() < 1) throw new InternalExpressionException("'import' needs at least a module name to import, and list of values to import");
String moduleName = lv.get(0).evalValue(c).getString(); String moduleName = lv.get(0).getString();
c.host.importModule(c, moduleName); c.host.importModule(c, moduleName);
moduleName = moduleName.toLowerCase(Locale.ROOT); moduleName = moduleName.toLowerCase(Locale.ROOT);
if (lv.size() > 1) if (lv.size() > 1)
c.host.importNames(c, expression.module, moduleName, lv.subList(1, lv.size()).stream().map((l) -> l.evalValue(c).getString()).collect(Collectors.toList())); c.host.importNames(c, expression.module, moduleName, lv.subList(1, lv.size()).stream().map(Value::getString).collect(Collectors.toList()));
if (t == Context.VOID) if (t == Context.VOID)
return LazyValue.NULL; return Value.NULL;
ListValue list = ListValue.wrap(c.host.availableImports(moduleName).map(StringValue::new).collect(Collectors.toList())); return ListValue.wrap(c.host.availableImports(moduleName).map(StringValue::new).collect(Collectors.toList()));
return (cc, tt) -> list;
}); });
// needs to be lazy because of custom context of execution of arguments as a signature
expression.addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) -> expression.addLazyFunctionWithDelegation("call",-1, (c, t, expr, tok, lv) ->
{ // adjust based on c { // adjust based on c
if (lv.size() == 0) if (lv.size() == 0)
@@ -43,7 +46,8 @@ public class Functions {
//lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes //lv.remove(lv.size()-1); // aint gonna cut it // maybe it will because of the eager eval changes
if (t != Context.SIGNATURE) // just call the function if (t != Context.SIGNATURE) // just call the function
{ {
FunctionArgument<LazyValue> functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true); List<Value> args = Fluff.AbstractFunction.unpackLazy(lv, c, Context.NONE);
FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, args, 0, false, true);
FunctionValue fun = functionArgument.function; FunctionValue fun = functionArgument.function;
return fun.callInContext(c, t, functionArgument.args); return fun.callInContext(c, t, functionArgument.args);
} }
@@ -61,7 +65,7 @@ public class Functions {
} }
if (v instanceof FunctionAnnotationValue) if (v instanceof FunctionAnnotationValue)
{ {
if (((FunctionAnnotationValue) v).type == 0) if (((FunctionAnnotationValue) v).type == FunctionAnnotationValue.Type.GLOBAL)
{ {
globals.add(v.boundVariable); globals.add(v.boundVariable);
} }
@@ -81,22 +85,38 @@ public class Functions {
return (cc, tt) -> retval; return (cc, tt) -> retval;
}); });
expression.addLazyFunction("outer", 1, (c, t, lv) -> expression.addContextFunction("outer", 1, (c, t, lv) ->
{ {
if (t != Context.LOCALIZATION) if (t != Context.LOCALIZATION)
throw new InternalExpressionException("Outer scoping of variables is only possible in function signatures."); throw new InternalExpressionException("Outer scoping of variables is only possible in function signatures.");
return (cc, tt) -> new FunctionAnnotationValue(lv.get(0).evalValue(c), 0); return new FunctionAnnotationValue(lv.get(0), FunctionAnnotationValue.Type.GLOBAL);
}); });
expression.addLazyUnaryOperator("...", Operators.precedence.get("def->..."), false, (c, t, lv) -> // lazy because of typed evaluation of the argument
expression.addLazyUnaryOperator("...", Operators.precedence.get("unary+-!..."), false, (c, t, lv) ->
{ {
if (t != Context.LOCALIZATION) if (t == Context.LOCALIZATION)
throw new InternalExpressionException("That functionality has not been implemented yet."); return (cc, tt) -> new FunctionAnnotationValue(lv.evalValue(c), FunctionAnnotationValue.Type.VARARG);
return (cc, tt) -> new FunctionAnnotationValue(lv.evalValue(c), 1);
Value params = lv.evalValue(c, t);
FunctionUnpackedArgumentsValue fuaval;
if (params instanceof ListValue)
{
fuaval = new FunctionUnpackedArgumentsValue(((ListValue) params).getItems());
return (cc, tt) -> fuaval;
}
if (!(params instanceof AbstractListValue))
throw new InternalExpressionException("Unable to unpack a non-list");
fuaval = new FunctionUnpackedArgumentsValue(
ImmutableList.copyOf(((AbstractListValue) params).iterator())
);
return (cc, tt) -> fuaval;
//throw new InternalExpressionException("That functionality has not been implemented yet.");
}); });
//assigns const procedure to the lhs, returning its previous value //assigns const procedure to the lhs, returning its previous value
expression.addLazyBinaryOperatorWithDelegation("->", Operators.precedence.get("def->..."), false, (c, type, e, t, lv1, lv2) -> // must be lazy due to RHS being an expression to save to execute
expression.addLazyBinaryOperatorWithDelegation("->", Operators.precedence.get("def->"), false, (c, type, e, t, lv1, lv2) ->
{ {
if (type == Context.MAPDEF) if (type == Context.MAPDEF)
{ {
@@ -35,6 +35,7 @@ public class Loops {
throw new InternalExpressionException("'continue' can only be called with zero or one argument"); throw new InternalExpressionException("'continue' can only be called with zero or one argument");
}); });
// lazy
expression.addLazyFunction("while", 3, (c, t, lv) -> expression.addLazyFunction("while", 3, (c, t, lv) ->
{ {
long limit = NumericValue.asNumber(lv.get(1).evalValue(c)).getLong(); long limit = NumericValue.asNumber(lv.get(1).evalValue(c)).getLong();
@@ -20,7 +20,7 @@ import java.util.Map;
public class Operators { public class Operators {
public static final Map<String, Integer> precedence = new HashMap<String,Integer>() {{ public static final Map<String, Integer> precedence = new HashMap<String,Integer>() {{
put("attribute~:", 80); put("attribute~:", 80);
put("unary+-!", 60); put("unary+-!...", 60);
put("exponent^", 40); put("exponent^", 40);
put("multiplication*/%", 30); put("multiplication*/%", 30);
put("addition+-", 20); put("addition+-", 20);
@@ -29,7 +29,7 @@ public class Operators {
put("and&&", 5); put("and&&", 5);
put("or||", 4); put("or||", 4);
put("assign=<>", 3); put("assign=<>", 3);
put("def->...", 2); put("def->", 2);
put("nextop;", 1); put("nextop;", 1);
}}; }};
@@ -44,6 +44,7 @@ public class Operators {
expression.addBinaryOperator("^", precedence.get("exponent^"), false, (v1, v2) -> expression.addBinaryOperator("^", precedence.get("exponent^"), false, (v1, v2) ->
new NumericValue(java.lang.Math.pow(NumericValue.asNumber(v1).getDouble(), NumericValue.asNumber(v2).getDouble()))); new NumericValue(java.lang.Math.pow(NumericValue.asNumber(v1).getDouble(), NumericValue.asNumber(v2).getDouble())));
// lazy cause RHS is only conditional
expression.addLazyBinaryOperator("&&", precedence.get("and&&"), false, (c, t, lv1, lv2) -> expression.addLazyBinaryOperator("&&", precedence.get("and&&"), false, (c, t, lv1, lv2) ->
{ {
Value v1 = lv1.evalValue(c, Context.BOOLEAN); Value v1 = lv1.evalValue(c, Context.BOOLEAN);
@@ -51,6 +52,7 @@ public class Operators {
return lv2; return lv2;
}); });
// lazy cause RHS is only conditional
expression.addLazyBinaryOperator("||", precedence.get("or||"), false, (c, t, lv1, lv2) -> expression.addLazyBinaryOperator("||", precedence.get("or||"), false, (c, t, lv1, lv2) ->
{ {
Value v1 = lv1.evalValue(c, Context.BOOLEAN); Value v1 = lv1.evalValue(c, Context.BOOLEAN);
@@ -73,6 +75,7 @@ public class Operators {
expression.addBinaryOperator("!=", precedence.get("equal==!="), false, (v1, v2) -> expression.addBinaryOperator("!=", precedence.get("equal==!="), false, (v1, v2) ->
v1.equals(v2) ? Value.FALSE : Value.TRUE); v1.equals(v2) ? Value.FALSE : Value.TRUE);
// lazy cause of assignment which is non-trivial
expression.addLazyBinaryOperator("=", precedence.get("assign=<>"), false, (c, t, lv1, lv2) -> expression.addLazyBinaryOperator("=", precedence.get("assign=<>"), false, (c, t, lv1, lv2) ->
{ {
Value v1 = lv1.evalValue(c, Context.LVALUE); Value v1 = lv1.evalValue(c, Context.LVALUE);
@@ -111,6 +114,7 @@ public class Operators {
return boundedLHS; return boundedLHS;
}); });
// lazy due to assignment
expression.addLazyBinaryOperator("+=", precedence.get("assign=<>"), false, (c, t, lv1, lv2) -> expression.addLazyBinaryOperator("+=", precedence.get("assign=<>"), false, (c, t, lv1, lv2) ->
{ {
Value v1 = lv1.evalValue(c, Context.LVALUE); Value v1 = lv1.evalValue(c, Context.LVALUE);
@@ -171,10 +175,8 @@ public class Operators {
return boundedLHS; return boundedLHS;
}); });
expression.addLazyBinaryOperator("<>", precedence.get("assign=<>"), false, (c, t, lv1, lv2) -> expression.addBinaryContextOperator("<>", precedence.get("assign=<>"), false, (c, t, v1, v2) ->
{ {
Value v1 = lv1.evalValue(c);
Value v2 = lv2.evalValue(c);
if (v1 instanceof ListValue.ListConstructorValue && v2 instanceof ListValue.ListConstructorValue) if (v1 instanceof ListValue.ListConstructorValue && v2 instanceof ListValue.ListConstructorValue)
{ {
List<Value> ll = ((ListValue)v1).getItems(); List<Value> ll = ((ListValue)v1).getItems();
@@ -196,7 +198,7 @@ public class Operators {
expression.setAnyVariable(c, lname, (cc, tt) -> rval); expression.setAnyVariable(c, lname, (cc, tt) -> rval);
expression.setAnyVariable(c, rname, (cc, tt) -> lval); expression.setAnyVariable(c, rname, (cc, tt) -> lval);
} }
return (cc, tt) -> Value.TRUE; return Value.TRUE;
} }
v1.assertAssignable(); v1.assertAssignable();
v2.assertAssignable(); v2.assertAssignable();
@@ -206,14 +208,17 @@ public class Operators {
Value rval = v1.reboundedTo(rvalvar); Value rval = v1.reboundedTo(rvalvar);
expression.setAnyVariable(c, lvalvar, (cc, tt) -> lval); expression.setAnyVariable(c, lvalvar, (cc, tt) -> lval);
expression.setAnyVariable(c, rvalvar, (cc, tt) -> rval); expression.setAnyVariable(c, rvalvar, (cc, tt) -> rval);
return (cc, tt) -> lval; return lval;
}); });
expression.addUnaryOperator("-", false, v -> NumericValue.asNumber(v).opposite()); expression.addUnaryOperator("-", false, v -> NumericValue.asNumber(v).opposite());
expression.addUnaryOperator("+", false, NumericValue::asNumber); expression.addUnaryOperator("+", false, NumericValue::asNumber);
expression.addLazyUnaryOperator("!", precedence.get("unary+-!"), false, (c, t, lv)-> lv.evalValue(c, Context.BOOLEAN).getBoolean() ? (cc, tt)-> Value.FALSE : (cc, tt) -> Value.TRUE); // might need context boolean // could be non-lazy, but who cares - its a small one.
expression.addLazyUnaryOperator("!", precedence.get("unary+-!..."), false, (c, t, lv) ->
lv.evalValue(c, Context.BOOLEAN).getBoolean() ? (cc, tt)-> Value.FALSE : (cc, tt) -> Value.TRUE
); // might need context boolean
} }
} }
+55 -79
View File
@@ -7,6 +7,7 @@ import carpet.script.ScriptHost;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.utils.PerlinNoiseSampler; import carpet.script.utils.PerlinNoiseSampler;
import carpet.script.utils.SimplexNoiseSampler; import carpet.script.utils.SimplexNoiseSampler;
import carpet.script.value.BooleanValue;
import carpet.script.value.FunctionValue; import carpet.script.value.FunctionValue;
import carpet.script.value.ListValue; import carpet.script.value.ListValue;
import carpet.script.value.NullValue; import carpet.script.value.NullValue;
@@ -37,19 +38,15 @@ public class Sys {
expression.addUnaryFunction("copy", Value::deepcopy); expression.addUnaryFunction("copy", Value::deepcopy);
expression.addLazyFunction("bool", 1, (c, t, lv) -> expression.addTypedContextFunction("bool", 1, Context.BOOLEAN, (c, t, lv) ->
{ {
Value v = lv.get(0).evalValue(c, Context.BOOLEAN); Value v = lv.get(0);
if (v instanceof StringValue) if (v instanceof StringValue)
{ {
String str = v.getString(); String str = v.getString().toLowerCase(Locale.ROOT);
if ("false".equalsIgnoreCase(str) || "null".equalsIgnoreCase(str)) if ("false".equals(str) || "null".equals(str)) return Value.FALSE;
{
return (cc, tt) -> Value.FALSE;
}
} }
Value retval = v.getBoolean()?Value.TRUE:Value.FALSE; return BooleanValue.of(v.getBoolean());
return (cc, tt) -> retval;
}); });
expression.addUnaryFunction("number", v -> expression.addUnaryFunction("number", v ->
@@ -187,45 +184,40 @@ public class Sys {
expression.addUnaryFunction("type", v -> new StringValue(v.getTypeString())); expression.addUnaryFunction("type", v -> new StringValue(v.getTypeString()));
expression.addUnaryFunction("length", v -> new NumericValue(v.length())); expression.addUnaryFunction("length", v -> new NumericValue(v.length()));
expression.addLazyFunction("rand", -1, (c, t, lv) -> expression.addContextFunction("rand", -1, (c, t, lv) ->
{ {
int argsize = lv.size(); int argsize = lv.size();
Random randomizer = Sys.randomizer; Random randomizer = Sys.randomizer;
if (argsize != 1 && argsize != 2) if (argsize != 1 && argsize != 2)
throw new InternalExpressionException("'rand' takes one (range) or two arguments (range and seed)"); throw new InternalExpressionException("'rand' takes one (range) or two arguments (range and seed)");
if (argsize == 2) randomizer = c.host.getRandom(NumericValue.asNumber(lv.get(1).evalValue(c)).getLong()); if (argsize == 2) randomizer = c.host.getRandom(NumericValue.asNumber(lv.get(1)).getLong());
Value argument = lv.get(0).evalValue(c); Value argument = lv.get(0);
if (argument instanceof ListValue) if (argument instanceof ListValue)
{ {
List<Value> list = ((ListValue) argument).getItems(); List<Value> list = ((ListValue) argument).getItems();
Value retval = list.get(randomizer.nextInt(list.size())); return list.get(randomizer.nextInt(list.size()));
return (cc, tt) -> retval;
} }
double value = NumericValue.asNumber(argument).getDouble()*randomizer.nextDouble();
if (t == Context.BOOLEAN) if (t == Context.BOOLEAN)
{ return BooleanValue.of(value >= 1.0D);
double rv = NumericValue.asNumber(argument).getDouble()*randomizer.nextFloat(); return new NumericValue(value);
Value retval = rv<1.0D?Value.FALSE:Value.TRUE;
return (cc, tt) -> retval;
}
Value retval = new NumericValue(NumericValue.asNumber(argument).getDouble()*randomizer.nextDouble());
return (cc, tt) -> retval;
}); });
expression.addLazyFunction("reset_seed", 1, (c, t, lv) -> { expression.addContextFunction("reset_seed", 1, (c, t, lv) -> {
boolean gotIt = c.host.resetRandom(NumericValue.asNumber(lv.get(0).evalValue(c)).getLong()); boolean gotIt = c.host.resetRandom(NumericValue.asNumber(lv.get(0)).getLong());
return gotIt?LazyValue.TRUE:LazyValue.FALSE; return BooleanValue.of(gotIt);
}); });
expression.addLazyFunction("perlin", -1, (c, t, lv) -> expression.addFunction("perlin", lv ->
{ {
PerlinNoiseSampler sampler; PerlinNoiseSampler sampler;
Value x, y, z; Value x, y, z;
if (lv.size() >= 4) if (lv.size() >= 4)
{ {
x = lv.get(0).evalValue(c); x = lv.get(0);
y = lv.get(1).evalValue(c); y = lv.get(1);
z = lv.get(2).evalValue(c); z = lv.get(2);
sampler = PerlinNoiseSampler.getPerlin(NumericValue.asNumber(lv.get(3).evalValue(c)).getLong()); sampler = PerlinNoiseSampler.getPerlin(NumericValue.asNumber(lv.get(3)).getLong());
} }
else else
{ {
@@ -234,12 +226,12 @@ public class Sys {
z = Value.NULL; z = Value.NULL;
if (lv.size() == 0 ) if (lv.size() == 0 )
throw new InternalExpressionException("'perlin' requires at least one dimension to sample from"); throw new InternalExpressionException("'perlin' requires at least one dimension to sample from");
x = NumericValue.asNumber(lv.get(0).evalValue(c)); x = NumericValue.asNumber(lv.get(0));
if (lv.size() > 1) if (lv.size() > 1)
{ {
y = NumericValue.asNumber(lv.get(1).evalValue(c)); y = NumericValue.asNumber(lv.get(1));
if (lv.size() > 2) if (lv.size() > 2)
z = NumericValue.asNumber(lv.get(2).evalValue(c)); z = NumericValue.asNumber(lv.get(2));
} }
} }
@@ -255,21 +247,20 @@ public class Sys {
NumericValue.asNumber(x).getDouble(), NumericValue.asNumber(x).getDouble(),
NumericValue.asNumber(y).getDouble(), NumericValue.asNumber(y).getDouble(),
NumericValue.asNumber(z).getDouble()); NumericValue.asNumber(z).getDouble());
Value ret = new NumericValue(result); return new NumericValue(result);
return (cc, tt) -> ret;
}); });
expression.addLazyFunction("simplex", -1, (c, t, lv) -> expression.addFunction("simplex", lv ->
{ {
SimplexNoiseSampler sampler; SimplexNoiseSampler sampler;
Value x, y, z; Value x, y, z;
if (lv.size() >= 4) if (lv.size() >= 4)
{ {
x = lv.get(0).evalValue(c); x = lv.get(0);
y = lv.get(1).evalValue(c); y = lv.get(1);
z = lv.get(2).evalValue(c); z = lv.get(2);
sampler = SimplexNoiseSampler.getSimplex(NumericValue.asNumber(lv.get(3).evalValue(c)).getLong()); sampler = SimplexNoiseSampler.getSimplex(NumericValue.asNumber(lv.get(3)).getLong());
} }
else else
{ {
@@ -277,10 +268,10 @@ public class Sys {
z = Value.NULL; z = Value.NULL;
if (lv.size() < 2 ) if (lv.size() < 2 )
throw new InternalExpressionException("'simplex' requires at least two dimensions to sample from"); throw new InternalExpressionException("'simplex' requires at least two dimensions to sample from");
x = NumericValue.asNumber(lv.get(0).evalValue(c)); x = NumericValue.asNumber(lv.get(0));
y = NumericValue.asNumber(lv.get(1).evalValue(c)); y = NumericValue.asNumber(lv.get(1));
if (lv.size() > 2) if (lv.size() > 2)
z = NumericValue.asNumber(lv.get(2).evalValue(c)); z = NumericValue.asNumber(lv.get(2));
} }
double result; double result;
@@ -291,8 +282,7 @@ public class Sys {
NumericValue.asNumber(x).getDouble(), NumericValue.asNumber(x).getDouble(),
NumericValue.asNumber(y).getDouble(), NumericValue.asNumber(y).getDouble(),
NumericValue.asNumber(z).getDouble()); NumericValue.asNumber(z).getDouble());
Value ret = new NumericValue(result); return new NumericValue(result);
return (cc, tt) -> ret;
}); });
expression.addUnaryFunction("print", (v) -> expression.addUnaryFunction("print", (v) ->
@@ -301,17 +291,11 @@ public class Sys {
return v; // pass through for variables return v; // pass through for variables
}); });
expression.addLazyFunction("time", 0, (c, t, lv) -> expression.addContextFunction("time", 0, (c, t, lv) ->
{ new NumericValue((System.nanoTime() / 1000.0) / 1000.0));
Value time = new NumericValue((System.nanoTime() / 1000) / 1000.0);
return (cc, tt) -> time;
});
expression.addLazyFunction("unix_time", 0, (c, t, lv) -> expression.addContextFunction("unix_time", 0, (c, t, lv) ->
{ new NumericValue(System.currentTimeMillis()));
Value time = new NumericValue(System.currentTimeMillis());
return (cc, tt) -> time;
});
expression.addFunction("convert_date", lv -> expression.addFunction("convert_date", lv ->
{ {
@@ -324,7 +308,7 @@ public class Sys {
cal.setTimeInMillis(NumericValue.asNumber(value, "timestamp").getLong()); cal.setTimeInMillis(NumericValue.asNumber(value, "timestamp").getLong());
int weekday = cal.get(Calendar.DAY_OF_WEEK)-1; int weekday = cal.get(Calendar.DAY_OF_WEEK)-1;
if (weekday == 0) weekday = 7; if (weekday == 0) weekday = 7;
Value retVal = ListValue.ofNums( return ListValue.ofNums(
cal.get(Calendar.YEAR), cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH)+1, cal.get(Calendar.MONTH)+1,
cal.get(Calendar.DAY_OF_MONTH), cal.get(Calendar.DAY_OF_MONTH),
@@ -335,7 +319,6 @@ public class Sys {
cal.get(Calendar.DAY_OF_YEAR), cal.get(Calendar.DAY_OF_YEAR),
cal.get(Calendar.WEEK_OF_YEAR) cal.get(Calendar.WEEK_OF_YEAR)
); );
return retVal;
} }
else if(value instanceof ListValue) else if(value instanceof ListValue)
{ {
@@ -367,6 +350,7 @@ public class Sys {
return new NumericValue(cal.getTimeInMillis()); return new NumericValue(cal.getTimeInMillis());
}); });
// lazy cause evaluates expression multiple times
expression.addLazyFunction("profile_expr", 1, (c, t, lv) -> expression.addLazyFunction("profile_expr", 1, (c, t, lv) ->
{ {
LazyValue lazy = lv.get(0); LazyValue lazy = lv.get(0);
@@ -381,19 +365,16 @@ public class Sys {
return (cc, tt) -> res; return (cc, tt) -> res;
}); });
expression.addLazyFunction("var", 1, (c, t, lv) -> expression.addContextFunction("var", 1, (c, t, lv) ->
{ expression.getOrSetAnyVariable(c, lv.get(0).getString()).evalValue(c));
String varname = lv.get(0).evalValue(c).getString();
return expression.getOrSetAnyVariable(c, varname);
});
expression.addLazyFunction("undef", 1, (c, t, lv) -> expression.addContextFunction("undef", 1, (c, t, lv) ->
{ {
Value remove = lv.get(0).evalValue(c); Value remove = lv.get(0);
if (remove instanceof FunctionValue) if (remove instanceof FunctionValue)
{ {
c.host.delFunction(expression.module, remove.getString()); c.host.delFunction(expression.module, remove.getString());
return (cc, tt) -> Value.NULL; return Value.NULL;
} }
String varname = remove.getString(); String varname = remove.getString();
boolean isPrefix = varname.endsWith("*"); boolean isPrefix = varname.endsWith("*");
@@ -423,13 +404,13 @@ public class Sys {
c.delVariable(varname); c.delVariable(varname);
} }
} }
return (cc, tt) -> Value.NULL; return Value.NULL;
}); });
//deprecate //deprecate
expression.addLazyFunction("vars", 1, (c, t, lv) -> expression.addContextFunction("vars", 1, (c, t, lv) ->
{ {
String prefix = lv.get(0).evalValue(c).getString(); String prefix = lv.get(0).getString();
List<Value> values = new ArrayList<>(); List<Value> values = new ArrayList<>();
if (prefix.startsWith("global")) if (prefix.startsWith("global"))
{ {
@@ -439,30 +420,25 @@ public class Sys {
{ {
c.getAllVariableNames().stream().filter(s -> s.startsWith(prefix)).forEach(s -> values.add(new StringValue(s))); c.getAllVariableNames().stream().filter(s -> s.startsWith(prefix)).forEach(s -> values.add(new StringValue(s)));
} }
Value retval = ListValue.wrap(values); return ListValue.wrap(values);
return (cc, tt) -> retval;
}); });
// lazy cause default expression may not be executed if not needed
expression.addLazyFunction("system_variable_get", -1, (c, t, lv) -> expression.addLazyFunction("system_variable_get", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched"); if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched");
Value key = lv.get(0).evalValue(c); Value key = lv.get(0).evalValue(c);
if (lv.size() > 1) if (lv.size() > 1) ScriptHost.systemGlobals.computeIfAbsent(key, k -> lv.get(1).evalValue(c));
{
ScriptHost.systemGlobals.computeIfAbsent(key, k -> lv.get(1).evalValue(c));
}
Value res = ScriptHost.systemGlobals.get(key); Value res = ScriptHost.systemGlobals.get(key);
if (res!=null) return (cc, tt) -> res; if (res!=null) return (cc, tt) -> res;
return (cc, tt) -> Value.NULL; return LazyValue.NULL;
}); });
expression.addLazyFunction("system_variable_set", 2, (c, t, lv) -> expression.addBinaryFunction("system_variable_set", (key, value) ->
{ {
Value key = lv.get(0).evalValue(c);
Value value = lv.get(1).evalValue(c);
Value res = ScriptHost.systemGlobals.put(key, value); Value res = ScriptHost.systemGlobals.put(key, value);
if (res!=null) return (cc, tt) -> res; if (res!=null) return res;
return (cc, tt) -> Value.NULL; return Value.NULL;
}); });
} }
} }
@@ -1,11 +1,9 @@
package carpet.script.language; package carpet.script.language;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.LazyValue;
import carpet.script.argument.FunctionArgument; import carpet.script.argument.FunctionArgument;
import carpet.script.exception.ExitStatement; import carpet.script.exception.ExitStatement;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.value.FunctionValue;
import carpet.script.value.NumericValue; import carpet.script.value.NumericValue;
import carpet.script.value.ThreadValue; import carpet.script.value.ThreadValue;
import carpet.script.value.Value; import carpet.script.value.Value;
@@ -14,35 +12,30 @@ public class Threading
{ {
public static void apply(Expression expression) public static void apply(Expression expression)
{ {
expression.addLazyFunctionWithDelegation("task", -1, (c, t, expr, tok, lv) -> expression.addFunctionWithDelegation("task", -1, (c, t, expr, tok, lv) ->
{ {
if (lv.size() == 0) if (lv.size() == 0)
throw new InternalExpressionException("'task' requires at least function to call as a parameter"); throw new InternalExpressionException("'task' requires at least function to call as a parameter");
FunctionArgument<LazyValue> functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true); FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 0, false, true);
ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, FunctionValue.resolveArgs(functionArgument.args, c, t)); ThreadValue thread = new ThreadValue(Value.NULL, functionArgument.function, expr, tok, c, functionArgument.checkedArgs());
Thread.yield(); Thread.yield();
return (cc, tt) -> thread; return thread;
}); });
expression.addLazyFunctionWithDelegation("task_thread", -1, (c, t, expr, tok, lv) -> expression.addFunctionWithDelegation("task_thread", -1, (c, t, expr, tok, lv) ->
{ {
if (lv.size() < 2) if (lv.size() < 2)
throw new InternalExpressionException("'task' requires at least function to call as a parameter"); throw new InternalExpressionException("'task' requires at least function to call as a parameter");
Value queue = lv.get(0).evalValue(c); Value queue = lv.get(0);
FunctionArgument<LazyValue> functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true); FunctionArgument functionArgument = FunctionArgument.findIn(c, expression.module, lv, 1, false, true);
ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, FunctionValue.resolveArgs(functionArgument.args, c, t)); ThreadValue thread = new ThreadValue(queue, functionArgument.function, expr, tok, c, functionArgument.checkedArgs());
Thread.yield(); Thread.yield();
return (cc, tt) -> thread; return thread;
}); });
expression.addLazyFunction("task_count", -1, (c, t, lv) -> expression.addContextFunction("task_count", -1, (c, t, lv) ->
{ (lv.size() > 0)? new NumericValue(c.host.taskCount(lv.get(0))):new NumericValue(c.host.taskCount()));
Value ret = (lv.size() > 0)?
new NumericValue(c.host.taskCount(lv.get(0).evalValue(c))):
new NumericValue(c.host.taskCount());
return (cc, tt) -> ret;
});
expression.addUnaryFunction("task_value", (v) -> expression.addUnaryFunction("task_value", (v) ->
{ {
@@ -72,6 +65,7 @@ public class Threading
return new NumericValue(((ThreadValue) v).isFinished()); return new NumericValue(((ThreadValue) v).isFinished());
}); });
// lazy cause expr is evaluated in the same type
expression.addLazyFunction("synchronize", -1, (c, t, lv) -> expression.addLazyFunction("synchronize", -1, (c, t, lv) ->
{ {
if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize"); if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize");
@@ -89,6 +83,7 @@ public class Threading
} }
}); });
// lazy since exception expression is very conditional
expression.addLazyFunction("sleep", -1, (c, t, lv) -> expression.addLazyFunction("sleep", -1, (c, t, lv) ->
{ {
long time = lv.isEmpty()?0L:NumericValue.asNumber(lv.get(0).evalValue(c)).getLong(); long time = lv.isEmpty()?0L:NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
@@ -1,5 +1,6 @@
package carpet.script.value; package carpet.script.value;
import carpet.CarpetServer;
import carpet.fakes.BrainInterface; import carpet.fakes.BrainInterface;
import carpet.fakes.EntityInterface; import carpet.fakes.EntityInterface;
import carpet.fakes.ItemEntityInterface; import carpet.fakes.ItemEntityInterface;
@@ -13,6 +14,7 @@ import carpet.helpers.Tracer;
import carpet.network.ServerNetworkHandler; import carpet.network.ServerNetworkHandler;
import carpet.patches.EntityPlayerMPFake; import carpet.patches.EntityPlayerMPFake;
import carpet.script.CarpetContext; import carpet.script.CarpetContext;
import carpet.script.CarpetScriptServer;
import carpet.script.EntityEventsGroup; import carpet.script.EntityEventsGroup;
import carpet.script.argument.Vector3Argument; import carpet.script.argument.Vector3Argument;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
@@ -917,9 +919,11 @@ public class EntityValue extends Value
} }
} }
private static void updateVelocity(Entity e) private static void updateVelocity(Entity e, double scale)
{ {
e.velocityModified = true; e.velocityModified = true;
if (Math.abs(scale) > 10000)
CarpetScriptServer.LOG.warn("Moved entity "+e.getEntityName()+" "+e.getName()+" at " +e.getPos()+" extremly fast: "+e.getVelocity());
//((ServerWorld)e.getEntityWorld()).method_14178().sendToNearbyPlayers(e, new EntityVelocityUpdateS2CPacket(e)); //((ServerWorld)e.getEntityWorld()).method_14178().sendToNearbyPlayers(e, new EntityVelocityUpdateS2CPacket(e));
} }
@@ -1051,30 +1055,32 @@ public class EntityValue extends Value
throw new InternalExpressionException("Expected a list of 3 parameters as a second argument"); throw new InternalExpressionException("Expected a list of 3 parameters as a second argument");
} }
List<Value> coords = ((ListValue) v).getItems(); List<Value> coords = ((ListValue) v).getItems();
e.setVelocity( double dx = NumericValue.asNumber(coords.get(0)).getDouble();
NumericValue.asNumber(coords.get(0)).getDouble(), double dy = NumericValue.asNumber(coords.get(0)).getDouble();
NumericValue.asNumber(coords.get(1)).getDouble(), double dz = NumericValue.asNumber(coords.get(2)).getDouble();
NumericValue.asNumber(coords.get(2)).getDouble() e.setVelocity(dx, dy, dz);
); updateVelocity(e, MathHelper.absMax(MathHelper.absMax(dx, dy), dz));
updateVelocity(e);
}); });
put("motion_x", (e, v) -> put("motion_x", (e, v) ->
{ {
Vec3d velocity = e.getVelocity(); Vec3d velocity = e.getVelocity();
e.setVelocity(NumericValue.asNumber(v).getDouble(), velocity.y, velocity.z); double dv = NumericValue.asNumber(v).getDouble();
updateVelocity(e); e.setVelocity(dv, velocity.y, velocity.z);
updateVelocity(e, dv);
}); });
put("motion_y", (e, v) -> put("motion_y", (e, v) ->
{ {
Vec3d velocity = e.getVelocity(); Vec3d velocity = e.getVelocity();
e.setVelocity(velocity.x, NumericValue.asNumber(v).getDouble(), velocity.z); double dv = NumericValue.asNumber(v).getDouble();
updateVelocity(e); e.setVelocity(velocity.x, dv, velocity.z);
updateVelocity(e, dv);
}); });
put("motion_z", (e, v) -> put("motion_z", (e, v) ->
{ {
Vec3d velocity = e.getVelocity(); Vec3d velocity = e.getVelocity();
e.setVelocity(velocity.x, velocity.y, NumericValue.asNumber(v).getDouble()); double dv = NumericValue.asNumber(v).getDouble();
updateVelocity(e); e.setVelocity(velocity.x, velocity.y, dv);
updateVelocity(e, dv);
}); });
put("accelerate", (e, v) -> put("accelerate", (e, v) ->
@@ -1089,7 +1095,7 @@ public class EntityValue extends Value
NumericValue.asNumber(coords.get(1)).getDouble(), NumericValue.asNumber(coords.get(1)).getDouble(),
NumericValue.asNumber(coords.get(2)).getDouble() NumericValue.asNumber(coords.get(2)).getDouble()
); );
updateVelocity(e); updateVelocity(e, e.getVelocity().length());
}); });
put("custom_name", (e, v) -> { put("custom_name", (e, v) -> {
@@ -1208,7 +1214,7 @@ public class EntityValue extends Value
else if (v instanceof ListValue) else if (v instanceof ListValue)
{ {
List<Value> lv = ((ListValue) v).getItems(); List<Value> lv = ((ListValue) v).getItems();
Vector3Argument locator = Vector3Argument.findIn(lv, 0, false); Vector3Argument locator = Vector3Argument.findIn(lv, 0, false, false);
pos = new BlockPos(locator.vec.x, locator.vec.y, locator.vec.z); pos = new BlockPos(locator.vec.x, locator.vec.y, locator.vec.z);
if (lv.size() > locator.offset) if (lv.size() > locator.offset)
{ {
@@ -1237,7 +1243,7 @@ public class EntityValue extends Value
else if (a instanceof ListValue) else if (a instanceof ListValue)
{ {
List<Value> params= ((ListValue) a).getItems(); List<Value> params= ((ListValue) a).getItems();
Vector3Argument blockLocator = Vector3Argument.findIn(params, 0, false); Vector3Argument blockLocator = Vector3Argument.findIn(params, 0, false, false);
BlockPos pos = new BlockPos(blockLocator.vec); BlockPos pos = new BlockPos(blockLocator.vec);
RegistryKey<World> world = spe.getEntityWorld().getRegistryKey(); RegistryKey<World> world = spe.getEntityWorld().getRegistryKey();
float angle = spe.getHeadYaw(); float angle = spe.getHeadYaw();
@@ -5,10 +5,12 @@ import net.minecraft.nbt.Tag;
public class FunctionAnnotationValue extends Value public class FunctionAnnotationValue extends Value
{ {
// 0 global public enum Type
// 1 vararg {
public int type; GLOBAL, VARARG
public FunctionAnnotationValue(Value variable, int type) }
public Type type;
public FunctionAnnotationValue(Value variable, Type type)
{ {
if (variable.boundVariable == null) if (variable.boundVariable == null)
throw new InternalExpressionException("You can only borrow variables from the outer scope"); throw new InternalExpressionException("You can only borrow variables from the outer scope");
@@ -0,0 +1,23 @@
package carpet.script.value;
import java.util.List;
public class FunctionUnpackedArgumentsValue extends ListValue
{
public FunctionUnpackedArgumentsValue(List<Value> list) {
super(list);
}
@Override
public Value clone()
{
return new FunctionUnpackedArgumentsValue(items);
}
@Override
public Value deepcopy()
{
ListValue copy = (ListValue)super.deepcopy();
return new FunctionUnpackedArgumentsValue(copy.items);
}
}
@@ -1,5 +1,6 @@
package carpet.script.value; package carpet.script.value;
import carpet.CarpetSettings;
import carpet.script.Context; import carpet.script.Context;
import carpet.script.Expression; import carpet.script.Expression;
import carpet.script.Fluff; import carpet.script.Fluff;
@@ -11,7 +12,6 @@ import carpet.script.exception.ContinueStatement;
import carpet.script.exception.ExpressionException; import carpet.script.exception.ExpressionException;
import carpet.script.exception.InternalExpressionException; import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ReturnStatement; import carpet.script.exception.ReturnStatement;
import carpet.script.exception.ThrowStatement;
import net.minecraft.nbt.StringTag; import net.minecraft.nbt.StringTag;
import net.minecraft.nbt.Tag; import net.minecraft.nbt.Tag;
@@ -150,11 +150,11 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
return varArgs != null; return varArgs != null;
} }
public LazyValue callInContext(Context c, Integer type, List<LazyValue> lazyParams) public LazyValue callInContext(Context c, Integer type, List<Value> params)
{ {
try try
{ {
return lazyEval(c, type, expression, token, lazyParams); return execute(c, type, expression, token, params);
} }
catch (ExpressionException exc) catch (ExpressionException exc)
{ {
@@ -173,15 +173,50 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
} }
} }
@Override public void checkArgs(int candidates)
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{ {
assertArgsOk(lazyParams, (fixedArgs) ->{ int actual = getArguments().size();
if (candidates < actual)
throw new InternalExpressionException("Function " + getPrettyString() + " requires at least " + actual + " arguments");
if (candidates > actual && getVarArgs() == null)
throw new InternalExpressionException("Function " + getPrettyString() + " requires " + actual + " arguments");
}
public static List<Value> unpackArgs(List<LazyValue> lazyParams, Context c)
{
// TODO we shoudn't need that if all fuctions are not lazy really
List<Value> params = new ArrayList<>();
for (LazyValue lv : lazyParams)
{
Value param = lv.evalValue(c, Context.NONE);
if (param instanceof FunctionUnpackedArgumentsValue)
{
CarpetSettings.LOG.error("How did we get here?");
params.addAll(((ListValue) param).getItems());
}
else
{
params.add(param);
}
}
return params;
}
@Override
public LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams) {
List<Value> resolvedParams = unpackArgs(lazyParams, c);
return execute(c, type, e, t, resolvedParams);
}
public LazyValue execute(Context c, Integer type, Expression e, Tokenizer.Token t, List<Value> params)
{
assertArgsOk(params, (fixedArgs) ->{
if (fixedArgs) // wrong number of args for fixed args if (fixedArgs) // wrong number of args for fixed args
{ {
throw new ExpressionException(c, e, t, throw new ExpressionException(c, e, t,
"Incorrect number of arguments for function "+name+ "Incorrect number of arguments for function "+name+
". Should be "+args.size()+", not "+lazyParams.size()+" like "+args ". Should be "+args.size()+", not "+params.size()+" like "+args
); );
} }
else // too few args for varargs else // too few args for varargs
@@ -190,7 +225,7 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
argList.add("... "+varArgs); argList.add("... "+varArgs);
throw new ExpressionException(c, e, t, throw new ExpressionException(c, e, t,
"Incorrect number of arguments for function "+name+ "Incorrect number of arguments for function "+name+
". Should be at least "+args.size()+", not "+lazyParams.size()+" like "+argList ". Should be at least "+args.size()+", not "+params.size()+" like "+argList
); );
} }
}); });
@@ -200,15 +235,15 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
for (int i=0; i<args.size(); i++) for (int i=0; i<args.size(); i++)
{ {
String arg = args.get(i); String arg = args.get(i);
Value val = lazyParams.get(i).evalValue(c).reboundedTo(arg); // todo check if we need to copy that Value val = params.get(i).reboundedTo(arg); // todo check if we need to copy that
newFrame.setVariable(arg, (cc, tt) -> val); newFrame.setVariable(arg, (cc, tt) -> val);
} }
if (varArgs != null) if (varArgs != null)
{ {
List<Value> extraParams = new ArrayList<>(); List<Value> extraParams = new ArrayList<>();
for (int i = args.size(), mx = lazyParams.size(); i < mx; i++) for (int i = args.size(), mx = params.size(); i < mx; i++)
{ {
extraParams.add(lazyParams.get(i).evalValue(c).reboundedTo(null)); // copy by value I guess extraParams.add(params.get(i).reboundedTo(null)); // copy by value I guess
} }
Value rest = ListValue.wrap(extraParams).bindTo(varArgs); // didn't we just copied that? Value rest = ListValue.wrap(extraParams).bindTo(varArgs); // didn't we just copied that?
newFrame.setVariable(varArgs, (cc, tt) -> rest); newFrame.setVariable(varArgs, (cc, tt) -> rest);
@@ -265,12 +300,6 @@ public class FunctionValue extends Value implements Fluff.ILazyFunction
feedback.accept(false); feedback.accept(false);
} }
} }
public static List<Value> resolveArgs(List<LazyValue> lzargs, Context c, Integer t)
{
List<Value> args = new ArrayList<>(lzargs.size());
lzargs.forEach( v -> args.add( v.evalValue(c, t)));
return args;
}
public static List<LazyValue> lazify(List<Value> args) public static List<LazyValue> lazify(List<Value> args)
{ {
@@ -4,6 +4,7 @@ public class LContainerValue extends FrameworkValue
{ {
private ContainerValueInterface container; private ContainerValueInterface container;
private Value address; private Value address;
public static final LContainerValue NULL_CONTAINER = new LContainerValue(null, null);
public LContainerValue(ContainerValueInterface c, Value v) public LContainerValue(ContainerValueInterface c, Value v)
{ {
@@ -70,7 +70,7 @@ public class ListValue extends AbstractListValue implements ContainerValueInterf
items.addAll(list); items.addAll(list);
} }
private ListValue(List<Value> list) protected ListValue(List<Value> list)
{ {
items = list; items = list;
} }
@@ -81,6 +81,12 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
owned = true; owned = true;
} }
public static Value of(Tag tag)
{
if (tag == null) return Value.NULL;
return new NBTSerializableValue(tag);
}
public NBTSerializableValue(Supplier<Tag> tagSupplier) public NBTSerializableValue(Supplier<Tag> tagSupplier)
{ {
nbtSupplier = tagSupplier; nbtSupplier = tagSupplier;
@@ -178,29 +184,29 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
return inventory; return inventory;
} }
public static InventoryLocator locateInventory(CarpetContext c, List<LazyValue> params, int offset) public static InventoryLocator locateInventory(CarpetContext c, List<Value> params, int offset)
{ {
try try
{ {
Value v1 = params.get(offset).evalValue(c); Value v1 = params.get(offset);
if (v1.isNull()) if (v1.isNull())
{ {
offset ++; offset ++;
v1 = params.get(offset).evalValue(c); v1 = params.get(offset);
} }
else if (v1 instanceof StringValue) else if (v1 instanceof StringValue)
{ {
String strVal = v1.getString().toLowerCase(Locale.ROOT); String strVal = v1.getString().toLowerCase(Locale.ROOT);
if (strVal.equals("enderchest")) if (strVal.equals("enderchest"))
{ {
Value v2 = params.get(1 + offset).evalValue(c); Value v2 = params.get(1 + offset);
ServerPlayerEntity player = EntityValue.getPlayerByValue(c.s.getMinecraftServer(), v2); ServerPlayerEntity player = EntityValue.getPlayerByValue(c.s.getMinecraftServer(), v2);
if (player == null) throw new InternalExpressionException("enderchest inventory requires player argument"); if (player == null) throw new InternalExpressionException("enderchest inventory requires player argument");
return new InventoryLocator(player, player.getBlockPos(), player.getEnderChestInventory(), offset + 2, true); return new InventoryLocator(player, player.getBlockPos(), player.getEnderChestInventory(), offset + 2, true);
} }
if (strVal.equals("equipment")) if (strVal.equals("equipment"))
{ {
Value v2 = params.get(1 + offset).evalValue(c); Value v2 = params.get(1 + offset);
if (!(v2 instanceof EntityValue)) throw new InternalExpressionException("Equipment inventory requires a living entity argument"); if (!(v2 instanceof EntityValue)) throw new InternalExpressionException("Equipment inventory requires a living entity argument");
Entity e = ((EntityValue) v2).getEntity(); Entity e = ((EntityValue) v2).getEntity();
if (!(e instanceof LivingEntity)) throw new InternalExpressionException("Equipment inventory requires a living entity argument"); if (!(e instanceof LivingEntity)) throw new InternalExpressionException("Equipment inventory requires a living entity argument");
@@ -256,8 +262,8 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
} }
BlockPos pos = new BlockPos( BlockPos pos = new BlockPos(
NumericValue.asNumber(v1).getDouble(), NumericValue.asNumber(v1).getDouble(),
NumericValue.asNumber(params.get(1 + offset).evalValue(c)).getDouble(), NumericValue.asNumber(params.get(1 + offset)).getDouble(),
NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble()); NumericValue.asNumber(params.get(2 + offset)).getDouble());
Inventory inv = getInventoryAt(c.s.getWorld(), pos); Inventory inv = getInventoryAt(c.s.getWorld(), pos);
if (inv == null) if (inv == null)
return null; return null;
@@ -35,7 +35,7 @@ public class ThreadValue extends Value
{ {
try try
{ {
return function.lazyEval(ctx, Context.NONE, expr, token, FunctionValue.lazify(args)).evalValue(ctx); return function.execute(ctx, Context.NONE, expr, token, args).evalValue(ctx);
} }
catch (ExitStatement exit) catch (ExitStatement exit)
{ {