Merge branch 'master' into 1.17

# Conflicts:
#	src/main/java/carpet/script/api/Auxiliary.java
#	src/main/java/carpet/script/api/Entities.java
#	src/main/java/carpet/script/api/Inventories.java
#	src/main/java/carpet/script/api/Scoreboards.java
#	src/main/java/carpet/script/api/WorldAccess.java
#	src/main/java/carpet/script/value/FunctionValue.java
#	src/main/java/carpet/script/value/NBTSerializableValue.java
This commit is contained in:
gnembon committed 2021-04-23 01:46:11 -03:00
commit 5e3812e1f0
35 files changed
+1250 -1416

No files matched your search

+39 -17
View File
@@ -1890,6 +1890,30 @@ conflicts and ambiguities between different paths of execution. While ambiguous
and they tend to execute correctly, the suggestion support works really poorly in these situations and scarpet and they tend to execute correctly, the suggestion support works really poorly in these situations and scarpet
will warn and prevent such apps from loading with an error message. If `allow_command_conflicts` is specified and will warn and prevent such apps from loading with an error message. If `allow_command_conflicts` is specified and
`true`, then scarpet will load all provided commands regardless. `true`, then scarpet will load all provided commands regardless.
* `'requires'` - defines either a map of mod dependencies in Fabric's mod.json style, or a function to be executed. If it's a map, it will only
allow the app to load if all of the mods specified in the map meet the version criteria. If it's a function, it will prevent the app from
loading if the function does not execute to `false`, displaying whatever is returned to the user.
Available prefixes for the version comparison are `>=`, `<=`, `>`, `<`, `~`, `^` and `=` (default if none specified), based in the spec
at [NPM docs about SemVer ranges](https://docs.npmjs.com/cli/v6/using-npm/semver#ranges)
```
__config() -> {
'requires' -> {
'carpet' -> '>=1.4.33', // Will require Carpet with a version >= 1.4.32
'minecraft' -> '>=1.16', // Will require Minecraft with a version >= 1.16
'chat-up' -> '*' // Will require any version of the chat-up mod
}
}
```
```
__config() -> {
'requires' -> _() -> (
d = convert_date(unix_time());
if(d:6 == 5 && d:2 == 13,
'Its Friday, 13th' // Will throw this if Friday 13th, will load else since `if` function returns `null` by default
)
}
```
* `'command_permission'` - indicates a custom permission to run the command. It can either be a number indicating * `'command_permission'` - indicates a custom permission to run the command. It can either be a number indicating
permission level (from 1 to 4) or a string value, one of: `'all'` (default), `'ops'` (default opped player with permission level of 2), permission level (from 1 to 4) or a string value, one of: `'all'` (default), `'ops'` (default opped player with permission level of 2),
`'server'` - command accessible only through the server console and commandblocks, but not in chat, `'players'` - opposite `'server'` - command accessible only through the server console and commandblocks, but not in chat, `'players'` - opposite
@@ -2120,7 +2144,8 @@ if a player is in the other dimension, calls to entities and blocks around that
Moreover, running commandblocks in the spawn chunks would mean that commands will always refer to the overworld Moreover, running commandblocks in the spawn chunks would mean that commands will always refer to the overworld
blocks and entities. In case you would want to run commands across all dimensions, just run three of them, blocks and entities. In case you would want to run commands across all dimensions, just run three of them,
using `/execute in overworld/the_nether/the_end run script run ...` and query players using `player('*')`, using `/execute in overworld/the_nether/the_end run script run ...` and query players using `player('*')`,
which only returns players in current dimension, or use `in_dimension(expr)` function.# Blocks / World API which only returns players in current dimension, or use `in_dimension(expr)` function.
# Blocks / World API
## Specifying blocks ## Specifying blocks
@@ -3058,20 +3083,8 @@ living entities based on their spawn group. Negative descriptor resolves to all
category. category.
* All entity tags including those provided with datapacks. Built-in entity tags include: `skeletons`, `raiders`, * All entity tags including those provided with datapacks. Built-in entity tags include: `skeletons`, `raiders`,
`beehive_inhabitors` (bee, duh), `arrows` and `impact_projectiles`. `beehive_inhabitors` (bee, duh), `arrows` and `impact_projectiles`.
* Any of the following standard entity types (equivalent to selection from `/summon` vanilla command: * Any of the standard entity types, equivalent to selection from `/summon` vanilla command, which is one of the options returned
`area_effect_cloud`, `armor_stand`, `arrow`, `bat`, `bee`, `blaze`, `boat`, `cat`, `cave_spider`, `chest_minecart`, by `entity_types()`, except for `'fishing_bobber'` and `'player'`.
`chicken`, `cod`, `command_block_minecart`, `cow`, `creeper`, `dolphin`, `donkey`, `dragon_fireball`, `drowned`,
`egg`, `elder_guardian`, `end_crystal`, `ender_dragon`, `ender_pearl`, `enderman`, `endermite`, `evoker`,
`evoker_fangs`, `experience_bottle`, `experience_orb`, `eye_of_ender`, `falling_block`, `fireball`, `firework_rocket`,
`fishing_bobber`, `fox`, `furnace_minecart`, `ghast`, `giant`, `guardian`, `hoglin`, `hopper_minecart`, `horse`,
`husk`, `illusioner`, `iron_golem`, `item`, `item_frame`, `leash_knot`, `lightning_bolt`, `llama`, `llama_spit`,
`magma_cube`, `minecart`, `mooshroom`, `mule`, `ocelot`, `painting`, `panda`, `parrot`, `phantom`, `pig`, `piglin`,
`piglin_brute`, `pillager`, `player`, `polar_bear`, `potion`, `pufferfish`, `rabbit`, `ravager`, `salmon`, `sheep`,
`shulker`, `shulker_bullet`, `silverfish`, `skeleton`, `skeleton_horse`, `slime`, `small_fireball`, `snow_golem`,
`snowball`, `spawner_minecart`, `spectral_arrow`, `spider`, `squid`, `stray`, `strider`, `tnt`, `tnt_minecart`,
`trader_llama`, `trident`, `tropical_fish`, `turtle`, `vex`, `villager`, `vindicator`, `wandering_trader`, `witch`,
`wither`, `wither_skeleton`, `wither_skull`, `wolf`, `zoglin`, `zombie`, `zombie_horse`, `zombie_villager`,
`zombified_piglin`
All categories can be preceded with `'!'` which will fetch all entities (unless otherwise noted) that are valid (health > 0) but not All categories can be preceded with `'!'` which will fetch all entities (unless otherwise noted) that are valid (health > 0) but not
belonging to that group. belonging to that group.
@@ -4910,7 +4923,7 @@ Example usages:
// not a problem in apps // not a problem in apps
</pre> </pre>
### `display_title(players, type, title?, fadeInTicks?, stayTicks?, fadeOutTicks),` ### `display_title(players, type, text?, fadeInTicks?, stayTicks?, fadeOutTicks),`
Sends the player (or players if `players` is a list) a title of a specific type, with optionally some times. Sends the player (or players if `players` is a list) a title of a specific type, with optionally some times.
* `players` is either an online player or a list of players. When sending a single player, it will throw if the player is invalid or offline. * `players` is either an online player or a list of players. When sending a single player, it will throw if the player is invalid or offline.
@@ -4922,9 +4935,17 @@ Sends the player (or players if `players` is a list) a title of a specific type,
Executing with those will set the times to the specified ones. Executing with those will set the times to the specified ones.
Note that `actionbar` type doesn't support changing times (vanilla bug, see [MC-106167](https://bugs.mojang.com/browse/MC-106167)). Note that `actionbar` type doesn't support changing times (vanilla bug, see [MC-106167](https://bugs.mojang.com/browse/MC-106167)).
### `display_title(players, 'player_list_header', text)`
### `display_title(players, 'player_list_footer', text)`
Changes the header or footer of the player list for the specified targets.
If `text` is `null` or an empty string it will remove the header or footer for the specified targets.
In case the player has Carpet loggers running, the footer specified by Scarpet will appear above the loggers.
### `logger(msg), logger(type, msg)` ### `logger(msg), logger(type, msg)`
Prints the message to system logs, and not to chat. By default prints an info, unless you specify otherwise in the `type` parameter. Prints the message to system logs, and not to chat.
By default prints an info, unless you specify otherwise in the `type` parameter.
Available output types: Available output types:
@@ -5321,6 +5342,7 @@ Available options in the scarpet app space:
* `server_banned_players` - list of banned player names * `server_banned_players` - list of banned player names
* `server_banned_ips` - list of banned IP addresses * `server_banned_ips` - list of banned IP addresses
* `server_dev_environment` - boolean indicating whether this server is in a development environment. * `server_dev_environment` - boolean indicating whether this server is in a development environment.
* `server_mods` - map with all loaded mods mapped to their versions as strings
System related properties System related properties
* `java_max_memory` - maximum allowed memory accessible by JVM * `java_max_memory` - maximum allowed memory accessible by JVM
+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;
} }
+184 -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;
@@ -155,16 +153,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;
@@ -172,13 +169,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");
} }
@@ -192,39 +189,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());
} }
} }
} }
@@ -246,29 +237,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();
@@ -282,34 +273,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();
@@ -330,13 +320,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();
@@ -345,7 +335,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())
{ {
@@ -355,19 +345,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;
@@ -375,16 +363,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();
} }
} }
} }
@@ -437,11 +425,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());
@@ -450,34 +437,18 @@ public class Auxiliary {
total ++; total ++;
e.discard(); // discard // remove(); e.discard(); // discard // 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(NbtString.escape(v.getString())));
Value v = lv.get(0).evalValue(c);
String string = v.getString();
Value ret = new StringValue(NbtString.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) -> {
@@ -490,11 +461,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();
NbtElement tag; NbtElement tag;
try try
{ {
@@ -504,17 +475,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)
{ {
@@ -526,7 +496,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)
@@ -537,13 +507,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 ->
@@ -554,7 +523,7 @@ public class Auxiliary {
}); });
Function<Text, Packet<?>> packetGetter = null; Function<Text, Packet<?>> packetGetter = null;
//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":
@@ -594,7 +563,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();
} }
@@ -620,15 +589,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;
} }
TitleFadeS2CPacket timesPacket; // TimesPacket TitleFadeS2CPacket timesPacket; // 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 TitleFadeS2CPacket(in, stay, out); timesPacket = new TitleFadeS2CPacket(in, stay, out);
//timesPacket = new TitleS2CPacket(Action.TIMES, null, in, stay, out); //timesPacket = new TitleS2CPacket(Action.TIMES, null, in, stay, out);
} }
@@ -642,20 +611,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;
@@ -665,56 +631,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.
@@ -725,12 +683,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");
@@ -741,7 +698,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)
@@ -764,17 +721,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);
@@ -782,21 +738,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);
@@ -810,7 +761,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<>();
@@ -831,13 +782,12 @@ public class Auxiliary {
plopData.put(StringValue.of("configured_structures"), plopData.put(StringValue.of("configured_structures"),
ListValue.wrap(registryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_KEY).getIds().stream().sorted().map(ValueConversions::of).collect(Collectors.toList())) ListValue.wrap(registryManager.get(Registry.CONFIGURED_STRUCTURE_FEATURE_KEY).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( () ->
{ {
@@ -849,71 +799,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)
{ {
NbtElement state = ((CarpetScriptHost) c.host).readFileTag(fdesc); NbtElement 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)
@@ -929,25 +875,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());
@@ -956,7 +900,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);
} }
@@ -965,7 +909,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();
@@ -980,166 +924,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);
} }
NbtElement 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());
NbtElement 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();
NbtCompound old_nbt = storage.get(new Identifier(key)); NbtCompound 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( () ->
{ {
@@ -1184,10 +1106,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();
@@ -1207,7 +1129,7 @@ public class Auxiliary {
RegistryOps<NbtElement> registryOps = RegistryOps.of(NbtOps.INSTANCE, serverRM.getResourceManager(), (DynamicRegistryManager.Impl) server.getRegistryManager()); RegistryOps<NbtElement> 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
@@ -1232,8 +1154,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;
}); });
} }
@@ -1290,8 +1211,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);
NbtCompound tag = new NbtCompound(); NbtCompound tag = new NbtCompound();
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<? extends Entity> entityList = source.getWorld().getEntitiesByType(eDesc.directType, eDesc.filteringPredicate); List<? extends 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;
}); });
} }
} }
+75 -129
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;
@@ -50,68 +50,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.getOrCreateTagGroup(Registry.ITEM_KEY).getTag(new Identifier(tag)); net.minecraft.tag.Tag<Item> itemTag = tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).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.getOrCreateTagGroup(Registry.ITEM_KEY).getTagIds().stream().map(ValueConversions::of).collect(Collectors.toList()));
Value ret = ListValue.wrap(tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).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.getOrCreateTagGroup(Registry.ITEM_KEY).getTags().entrySet().stream().filter(e -> e.getValue().contains(item)).map(e -> ValueConversions.of(e.getKey())).collect(Collectors.toList()));
Value ret = ListValue.wrap(tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).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; net.minecraft.tag.Tag<Item> itemTag = tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).getTag(new Identifier(tag));
} if (itemTag == null) return Value.NULL;
String tag = lv.get(1).evalValue(c).getString(); return BooleanValue.of(itemTag.contains(item));
Tag<Item> itemTag = tagManager.getOrCreateTagGroup(Registry.ITEM_KEY).getTag(new Identifier(tag));
if (itemTag == null) return LazyValue.NULL;
return itemTag.contains(item)?LazyValue.TRUE:LazyValue.FALSE;
}); });
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));
@@ -124,7 +108,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)
{ {
@@ -144,7 +128,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));
} }
} }
@@ -183,91 +167,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)
{ {
@@ -276,12 +244,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);
} }
NbtCompound nbt = null; // skipping one argument NbtCompound 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)
@@ -289,11 +257,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
{ {
@@ -304,62 +268,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);
@@ -373,7 +327,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
{ {
@@ -384,37 +338,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)
@@ -439,8 +386,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.getOrCreateStatCriterion(critetionName).orElse(null); criterion = ScoreboardCriterion.getOrCreateStatCriterion(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.getDefaultRenderType()); scoreboard.addObjective(objectiveName, criterion, new LiteralText(objectiveName), criterion.getDefaultRenderType());
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.getOrCreateStatCriterion(setValue.getString()).orElse(null); ScoreboardCriterion criterion = ScoreboardCriterion.getOrCreateStatCriterion(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.getStyle().getName());
return (_c, _t) -> StringValue.of(bossBar.getStyle().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.setStyle(style); bossBar.setStyle(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;
@@ -933,9 +935,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));
} }
@@ -1067,30 +1071,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) ->
@@ -1105,7 +1111,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) -> {
@@ -1224,7 +1230,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)
{ {
@@ -1253,7 +1259,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.NbtElement;
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.NbtString; import net.minecraft.nbt.NbtString;
import net.minecraft.nbt.NbtElement; import net.minecraft.nbt.NbtElement;
@@ -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;
} }
@@ -83,6 +83,12 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
owned = true; owned = true;
} }
public static Value of(NbtElement tag)
{
if (tag == null) return Value.NULL;
return new NBTSerializableValue(tag);
}
public NBTSerializableValue(Supplier<NbtElement> tagSupplier) public NBTSerializableValue(Supplier<NbtElement> tagSupplier)
{ {
nbtSupplier = tagSupplier; nbtSupplier = tagSupplier;
@@ -180,29 +186,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");
@@ -258,8 +264,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)
{ {