scarpet v1.2
This commit is contained in:
1 parent
723f863d98
commit
885f579d6c
34 files changed
+8786
-18
No files matched your search
@@ -1,24 +1,23 @@
|
||||
package carpet;
|
||||
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
import carpet.commands.CameraModeCommand;
|
||||
import carpet.commands.CarpetCommand;
|
||||
import carpet.commands.CounterCommand;
|
||||
//import carpet.commands.DistanceCommand;
|
||||
import carpet.commands.DistanceCommand;
|
||||
import carpet.commands.DrawCommand;
|
||||
//import carpet.commands.ScriptCommand;
|
||||
//import carpet.commands.InfoCommand;
|
||||
import carpet.commands.InfoCommand;
|
||||
import carpet.commands.LogCommand;
|
||||
import carpet.commands.PerimeterInfoCommand;
|
||||
import carpet.commands.PlayerCommand;
|
||||
import carpet.commands.ScriptCommand;
|
||||
import carpet.commands.SpawnCommand;
|
||||
import carpet.commands.LogCommand;
|
||||
import carpet.commands.TestCommand;
|
||||
import carpet.commands.TickCommand;
|
||||
//import carpet.script.ExpressionInspector;
|
||||
|
||||
import java.util.Random;
|
||||
|
||||
//import carpet.helpers.TickSpeed;
|
||||
import carpet.helpers.TickSpeed;
|
||||
import carpet.logging.LoggerRegistry;
|
||||
import carpet.script.CarpetScriptServer;
|
||||
import carpet.utils.HUDController;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
@@ -28,6 +27,7 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
{
|
||||
public static final Random rand = new Random((int)((2>>16)*Math.random()));
|
||||
public static MinecraftServer minecraft_server;
|
||||
public static CarpetScriptServer scriptServer;
|
||||
public static void init(MinecraftServer server) //aka constructor of this static singleton class
|
||||
{
|
||||
CarpetServer.minecraft_server = server;
|
||||
@@ -35,7 +35,7 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
public static void onServerLoaded(MinecraftServer server)
|
||||
{
|
||||
CarpetSettings.apply_settings_from_conf(server);
|
||||
//ExpressionInspector.CarpetExpression_resetExpressionEngine();
|
||||
scriptServer = new CarpetScriptServer();
|
||||
}
|
||||
// Separate from onServerLoaded, because a server can be loaded multiple times in singleplayer
|
||||
public static void onGameStarted() {
|
||||
@@ -44,7 +44,7 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
|
||||
public static void tick(MinecraftServer server)
|
||||
{
|
||||
//TickSpeed.tick(server);
|
||||
TickSpeed.tick(server);
|
||||
HUDController.update_hud(server);
|
||||
}
|
||||
|
||||
@@ -57,13 +57,13 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
SpawnCommand.register(dispatcher);
|
||||
PlayerCommand.register(dispatcher);
|
||||
CameraModeCommand.register(dispatcher);
|
||||
//InfoCommand.register(dispatcher);
|
||||
//DistanceCommand.register(dispatcher);
|
||||
InfoCommand.register(dispatcher);
|
||||
DistanceCommand.register(dispatcher);
|
||||
PerimeterInfoCommand.register(dispatcher);
|
||||
DrawCommand.register(dispatcher);
|
||||
//ScriptCommand.register(dispatcher);
|
||||
ScriptCommand.register(dispatcher);
|
||||
|
||||
TestCommand.register(dispatcher);
|
||||
//TestCommand.register(dispatcher);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -198,7 +198,7 @@ public class CarpetSettings
|
||||
}
|
||||
}
|
||||
|
||||
private static void notifyPlayersCommandsChanged()
|
||||
public static void notifyPlayersCommandsChanged()
|
||||
{
|
||||
if (CarpetServer.minecraft_server == null || CarpetServer.minecraft_server.getPlayerManager() == null)
|
||||
{
|
||||
|
||||
@@ -0,0 +1,491 @@
|
||||
package carpet.commands;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.script.CarpetExpression;
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.ExpressionInspector;
|
||||
import carpet.script.ScriptHost;
|
||||
import carpet.script.Tokenizer;
|
||||
import carpet.script.exception.CarpetExpressionException;
|
||||
import carpet.utils.Messenger;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.pattern.CachedBlockPosition;
|
||||
import net.minecraft.command.arguments.BlockPosArgumentType;
|
||||
import net.minecraft.command.arguments.BlockPredicateArgumentType;
|
||||
import net.minecraft.command.arguments.BlockStateArgument;
|
||||
import net.minecraft.command.arguments.BlockStateArgumentType;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.block.entity.BlockEntity;
|
||||
import net.minecraft.util.Clearable;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.server.world.ServerWorld;
|
||||
import net.minecraft.util.math.MutableIntBoundingBox;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.math.Vec3i;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
import static net.minecraft.server.command.CommandSource.suggestMatching;
|
||||
|
||||
public class ScriptCommand
|
||||
{
|
||||
public static void register(CommandDispatcher<ServerCommandSource> dispatcher)
|
||||
{
|
||||
LiteralArgumentBuilder<ServerCommandSource> b = literal("globals").
|
||||
executes(ScriptCommand::listGlobals);
|
||||
LiteralArgumentBuilder<ServerCommandSource> o = literal("stop").
|
||||
executes( (cc) -> { CarpetServer.scriptServer.stopAll = true; return 1;});
|
||||
LiteralArgumentBuilder<ServerCommandSource> u = literal("resume").
|
||||
executes( (cc) -> { CarpetServer.scriptServer.stopAll = false; return 1;});
|
||||
LiteralArgumentBuilder<ServerCommandSource> l = literal("run").
|
||||
requires((player) -> player.hasPermissionLevel(2)).
|
||||
then(argument("expr", StringArgumentType.greedyString()).
|
||||
executes((cc) -> compute(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "expr"))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> s = literal("invoke").
|
||||
then(argument("call", StringArgumentType.word()).suggests( (cc, bb)->suggestMatching(suggestFunctionCalls(cc),bb)).
|
||||
executes( (cc) -> invoke(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "call"),
|
||||
null,
|
||||
null,
|
||||
""
|
||||
)).
|
||||
then(argument("arguments", StringArgumentType.greedyString()).
|
||||
executes( (cc) -> invoke(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "call"),
|
||||
null,
|
||||
null,
|
||||
StringArgumentType.getString(cc, "arguments")
|
||||
))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> c = literal("invokepoint").
|
||||
then(argument("call", StringArgumentType.word()).suggests( (cc, bb)->suggestMatching(suggestFunctionCalls(cc),bb)).
|
||||
then(argument("origin", BlockPosArgumentType.create()).
|
||||
executes( (cc) -> invoke(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "call"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
null,
|
||||
""
|
||||
)).
|
||||
then(argument("arguments", StringArgumentType.greedyString()).
|
||||
executes( (cc) -> invoke(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "call"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
null,
|
||||
StringArgumentType.getString(cc, "arguments")
|
||||
)))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> h = literal("invokearea").
|
||||
then(argument("call", StringArgumentType.word()).suggests( (cc, bb)->suggestMatching(suggestFunctionCalls(cc),bb)).
|
||||
then(argument("from", BlockPosArgumentType.create()).
|
||||
then(argument("to", BlockPosArgumentType.create()).
|
||||
executes( (cc) -> invoke(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "call"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
""
|
||||
)).
|
||||
then(argument("arguments", StringArgumentType.greedyString()).
|
||||
executes( (cc) -> invoke(
|
||||
cc,
|
||||
StringArgumentType.getString(cc, "call"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
StringArgumentType.getString(cc, "arguments")
|
||||
))))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> i = literal("scan").requires((player) -> player.hasPermissionLevel(2)).
|
||||
then(argument("origin", BlockPosArgumentType.create()).
|
||||
then(argument("from", BlockPosArgumentType.create()).
|
||||
then(argument("to", BlockPosArgumentType.create()).
|
||||
then(argument("expr", StringArgumentType.greedyString()).
|
||||
executes( (cc) -> scriptScan(
|
||||
cc,
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
StringArgumentType.getString(cc, "expr")
|
||||
))))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> e = literal("fill").requires((player) -> player.hasPermissionLevel(2)).
|
||||
then(argument("origin", BlockPosArgumentType.create()).
|
||||
then(argument("from", BlockPosArgumentType.create()).
|
||||
then(argument("to", BlockPosArgumentType.create()).
|
||||
then(argument("expr", StringArgumentType.string()).
|
||||
then(argument("block", BlockStateArgumentType.create()).
|
||||
executes((cc) -> scriptFill(
|
||||
cc,
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
StringArgumentType.getString(cc, "expr"),
|
||||
BlockStateArgumentType.getBlockState(cc, "block"),
|
||||
null, "solid"
|
||||
)).
|
||||
then(literal("replace").
|
||||
then(argument("filter", BlockPredicateArgumentType.create())
|
||||
.executes((cc) -> scriptFill(
|
||||
cc,
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
StringArgumentType.getString(cc, "expr"),
|
||||
BlockStateArgumentType.getBlockState(cc, "block"),
|
||||
BlockPredicateArgumentType.getBlockPredicate(cc, "filter"),
|
||||
"solid"
|
||||
)))))))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> t = literal("outline").requires((player) -> player.hasPermissionLevel(2)).
|
||||
then(argument("origin", BlockPosArgumentType.create()).
|
||||
then(argument("from", BlockPosArgumentType.create()).
|
||||
then(argument("to", BlockPosArgumentType.create()).
|
||||
then(argument("expr", StringArgumentType.string()).
|
||||
then(argument("block", BlockStateArgumentType.create()).
|
||||
executes((cc) -> scriptFill(
|
||||
cc,
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
StringArgumentType.getString(cc, "expr"),
|
||||
BlockStateArgumentType.getBlockState(cc, "block"),
|
||||
null, "outline"
|
||||
)).
|
||||
then(literal("replace").
|
||||
then(argument("filter", BlockPredicateArgumentType.create())
|
||||
.executes((cc) -> scriptFill(
|
||||
cc,
|
||||
BlockPosArgumentType.getBlockPos(cc, "origin"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "from"),
|
||||
BlockPosArgumentType.getBlockPos(cc, "to"),
|
||||
StringArgumentType.getString(cc, "expr"),
|
||||
BlockStateArgumentType.getBlockState(cc, "block"),
|
||||
BlockPredicateArgumentType.getBlockPredicate(cc, "filter"),
|
||||
"outline"
|
||||
)))))))));
|
||||
LiteralArgumentBuilder<ServerCommandSource> a = literal("load").requires( (player) -> player.hasPermissionLevel(2) ).
|
||||
then(argument("package", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.listAvailableModules(),bb)).
|
||||
executes((cc) ->
|
||||
{
|
||||
boolean success = CarpetServer.scriptServer.addScriptHost(cc.getSource(), StringArgumentType.getString(cc, "package"));
|
||||
Messenger.m(cc.getSource(), success?"w Successfully added a module":"r Failed to add a module");
|
||||
return success?1:0;
|
||||
})
|
||||
);
|
||||
LiteralArgumentBuilder<ServerCommandSource> f = literal("unload").requires( (player) -> player.hasPermissionLevel(2) ).
|
||||
then(argument("package", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.modules.keySet(),bb)).
|
||||
executes((cc) ->
|
||||
{
|
||||
boolean success =CarpetServer.scriptServer.removeScriptHost(StringArgumentType.getString(cc, "package"));
|
||||
Messenger.m(cc.getSource(), success?"w Successfully added a module":"r Failed to add a module");
|
||||
return success?1:0;
|
||||
}));
|
||||
|
||||
dispatcher.register(literal("script").
|
||||
requires((player) -> CarpetSettings.getBool("commandScript")).
|
||||
then(b).then(u).then(o).then(l).then(s).then(c).then(h).then(i).then(e).then(t).then(a).then(f));
|
||||
dispatcher.register(literal("script").
|
||||
requires((player) -> CarpetSettings.getBool("commandScript")).
|
||||
then(literal("in").
|
||||
then(argument("package", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.modules.keySet(), bb)).
|
||||
then(b).then(u).then(o).then(l).then(s).then(c).then(h).then(i).then(e).then(t))));
|
||||
}
|
||||
private static ScriptHost getHost(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
try
|
||||
{
|
||||
String name = StringArgumentType.getString(context, "package").toLowerCase(Locale.ROOT);
|
||||
return CarpetServer.scriptServer.modules.getOrDefault(name, CarpetServer.scriptServer.globalHost);
|
||||
|
||||
}
|
||||
catch (IllegalArgumentException ignored)
|
||||
{
|
||||
return CarpetServer.scriptServer.globalHost;
|
||||
}
|
||||
}
|
||||
private static Collection<String> suggestFunctionCalls(CommandContext<ServerCommandSource> c)
|
||||
{
|
||||
ServerCommandSource s = c.getSource();
|
||||
ScriptHost host = getHost(c);
|
||||
return host.getPublicFunctions();
|
||||
}
|
||||
private static int listGlobals(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
ScriptHost host = getHost(context);
|
||||
ServerCommandSource source = context.getSource();
|
||||
|
||||
Messenger.m(source, "w Global functions"+((host == CarpetServer.scriptServer.globalHost)?":":" in "+host.getName()+":"));
|
||||
for (String fname : host.getAvailableFunctions())
|
||||
{
|
||||
Expression expr = host.getExpressionForFunction(fname);
|
||||
Tokenizer.Token tok = host.getTokenForFunction(fname);
|
||||
List<String> snippet = ExpressionInspector.Expression_getExpressionSnippet(tok, expr);
|
||||
Messenger.m(source, "w Function "+fname+" defined at: line "+(tok.lineno+1)+" pos "+(tok.linepos+1));
|
||||
for (String snippetLine: snippet)
|
||||
{
|
||||
Messenger.m(source, "li "+snippetLine);
|
||||
}
|
||||
Messenger.m(source, "gi ----------------");
|
||||
}
|
||||
//Messenger.m(source, "w "+code);
|
||||
Messenger.m(source, "w Global Variables:");
|
||||
|
||||
for (String vname : host.globalVariables.keySet())
|
||||
{
|
||||
Messenger.m(source, "w Variable "+vname+": ", "wb "+ host.globalVariables.get(vname).evalValue(null).getPrettyString());
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
public static void handleCall(ServerCommandSource source, Supplier<String> call)
|
||||
{
|
||||
try
|
||||
{
|
||||
CarpetServer.scriptServer.setChatErrorSnooper(source);
|
||||
long start = System.nanoTime();
|
||||
String result = call.get();
|
||||
long time = ((System.nanoTime()-start)/1000);
|
||||
String metric = "\u00B5s";
|
||||
if (time > 5000)
|
||||
{
|
||||
time /= 1000;
|
||||
metric = "ms";
|
||||
}
|
||||
if (time > 10000)
|
||||
{
|
||||
time /= 1000;
|
||||
metric = "s";
|
||||
}
|
||||
Messenger.m(source, "wi = ", "wb "+result, "gi ("+time+metric+")");
|
||||
}
|
||||
catch (CarpetExpressionException e)
|
||||
{
|
||||
Messenger.m(source, "r Exception white evaluating expression at "+new BlockPos(source.getPosition())+": "+e.getMessage());
|
||||
}
|
||||
CarpetServer.scriptServer.resetErrorSnooper();
|
||||
}
|
||||
|
||||
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args)
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
ScriptHost host = getHost(context);
|
||||
if (call.startsWith("__"))
|
||||
{
|
||||
Messenger.m(source, "r Hidden functions are only callable in scripts");
|
||||
return 0;
|
||||
}
|
||||
List<Integer> positions = new ArrayList<>();
|
||||
if (pos1 != null)
|
||||
{
|
||||
positions.add(pos1.getX());
|
||||
positions.add(pos1.getY());
|
||||
positions.add(pos1.getZ());
|
||||
}
|
||||
if (pos2 != null)
|
||||
{
|
||||
positions.add(pos2.getX());
|
||||
positions.add(pos2.getY());
|
||||
positions.add(pos2.getZ());
|
||||
}
|
||||
//if (!(args.trim().isEmpty()))
|
||||
// arguments.addAll(Arrays.asList(args.trim().split("\\s+")));
|
||||
handleCall(source, () -> host.call(source, call, positions, args));
|
||||
return 1;
|
||||
}
|
||||
|
||||
|
||||
private static int compute(CommandContext<ServerCommandSource> context, String expr)
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
ScriptHost host = getHost(context);
|
||||
handleCall(source, () -> {
|
||||
CarpetExpression ex = new CarpetExpression(expr, source, new BlockPos(0, 0, 0));
|
||||
return ex.scriptRunCommand(host, new BlockPos(source.getPosition()));
|
||||
});
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int scriptScan(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr)
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
ScriptHost host = getHost(context);
|
||||
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
|
||||
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
|
||||
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
|
||||
if (int_1 > CarpetSettings.getInt("fillLimit"))
|
||||
{
|
||||
Messenger.m(source, "r too many blocks to evaluate: " + int_1);
|
||||
return 1;
|
||||
}
|
||||
int successCount = 0;
|
||||
try
|
||||
{
|
||||
for (int x = area.minX; x <= area.maxX; x++)
|
||||
{
|
||||
for (int y = area.minY; y <= area.maxY; y++)
|
||||
{
|
||||
for (int z = area.minZ; z <= area.maxZ; z++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cexpr.fillAndScanCommand(host, x, y, z)) successCount++;
|
||||
}
|
||||
catch (ArithmeticException ignored)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (CarpetExpressionException exc)
|
||||
{
|
||||
Messenger.m(source, "r Error while processing command: "+exc);
|
||||
return 0;
|
||||
}
|
||||
Messenger.m(source, "w Expression successful in " + successCount + " out of " + int_1 + " blocks");
|
||||
return successCount;
|
||||
|
||||
}
|
||||
|
||||
|
||||
private static int scriptFill(CommandContext<ServerCommandSource> context, BlockPos origin, BlockPos a, BlockPos b, String expr,
|
||||
BlockStateArgument block, Predicate<CachedBlockPosition> replacement, String mode)
|
||||
{
|
||||
ServerCommandSource source = context.getSource();
|
||||
ScriptHost host = getHost(context);
|
||||
MutableIntBoundingBox area = new MutableIntBoundingBox(a, b);
|
||||
CarpetExpression cexpr = new CarpetExpression(expr, source, origin);
|
||||
int int_1 = area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ();
|
||||
if (int_1 > CarpetSettings.getInt("fillLimit"))
|
||||
{
|
||||
Messenger.m(source, "r too many blocks to evaluate: "+ int_1);
|
||||
return 1;
|
||||
}
|
||||
|
||||
boolean[][][] volume = new boolean[area.getBlockCountX()][area.getBlockCountY()][area.getBlockCountZ()];
|
||||
|
||||
BlockPos.Mutable mbpos = new BlockPos.Mutable(origin);
|
||||
ServerWorld world = source.getWorld();
|
||||
|
||||
|
||||
for (int x = area.minX; x <= area.maxX; x++)
|
||||
{
|
||||
for (int y = area.minY; y <= area.maxY; y++)
|
||||
{
|
||||
for (int z = area.minZ; z <= area.maxZ; z++)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cexpr.fillAndScanCommand(host, x, y, z))
|
||||
{
|
||||
volume[x-area.minX][y-area.minY][z-area.minZ]=true;
|
||||
}
|
||||
}
|
||||
catch (CarpetExpressionException e)
|
||||
{
|
||||
Messenger.m(source, "r Exception while filling the area:\n","l "+e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
catch (ArithmeticException e)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
final int maxx = area.getBlockCountX()-1;
|
||||
final int maxy = area.getBlockCountY()-1;
|
||||
final int maxz = area.getBlockCountZ()-1;
|
||||
if ("outline".equalsIgnoreCase(mode))
|
||||
{
|
||||
boolean[][][] newVolume = new boolean[area.getBlockCountX()][area.getBlockCountY()][area.getBlockCountZ()];
|
||||
for (int x = 0; x <= maxx; x++)
|
||||
{
|
||||
for (int y = 0; y <= maxy; y++)
|
||||
{
|
||||
for (int z = 0; z <= maxz; z++)
|
||||
{
|
||||
if (volume[x][y][z])
|
||||
{
|
||||
if ( ( (x != 0 && !volume[x-1][y ][z ]) ||
|
||||
(x != maxx && !volume[x+1][y ][z ]) ||
|
||||
(y != 0 && !volume[x ][y-1][z ]) ||
|
||||
(y != maxy && !volume[x ][y+1][z ]) ||
|
||||
(z != 0 && !volume[x ][y ][z-1]) ||
|
||||
(z != maxz && !volume[x ][y ][z+1])
|
||||
))
|
||||
{
|
||||
newVolume[x][y][z] = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
volume = newVolume;
|
||||
}
|
||||
int affected = 0;
|
||||
for (int x = 0; x <= maxx; x++)
|
||||
{
|
||||
for (int y = 0; y <= maxy; y++)
|
||||
{
|
||||
for (int z = 0; z <= maxz; z++)
|
||||
{
|
||||
if (volume[x][y][z])
|
||||
{
|
||||
mbpos.set(x+area.minX, y+area.minY, z+area.minZ);
|
||||
if (replacement == null || replacement.test(
|
||||
new CachedBlockPosition( world, mbpos, true)))
|
||||
{
|
||||
BlockEntity tileentity = world.getBlockEntity(mbpos);
|
||||
Clearable.clear(tileentity);
|
||||
|
||||
if (block.setBlockState(
|
||||
world,
|
||||
mbpos,
|
||||
2 | (CarpetSettings.getBool("fillUpdates") ?0:1024)
|
||||
))
|
||||
{
|
||||
++affected;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if (CarpetSettings.getBool("fillUpdates") && block != null)
|
||||
{
|
||||
for (int x = 0; x <= maxx; x++)
|
||||
{
|
||||
for (int y = 0; y <= maxy; y++)
|
||||
{
|
||||
for (int z = 0; z <= maxz; z++)
|
||||
{
|
||||
if (volume[x][y][z])
|
||||
{
|
||||
mbpos.set(x+area.minX, y+area.minY, z+area.minZ);
|
||||
Block blokc = world.getBlockState(mbpos).getBlock();
|
||||
world.updateNeighbors(mbpos, blokc);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Messenger.m(source, "gi Affected "+affected+" blocks in "+area.getBlockCountX() * area.getBlockCountY() * area.getBlockCountZ()+" block volume");
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package carpet.fakes;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
public interface MinecraftServerInterface
|
||||
{
|
||||
void forceTick(BooleanSupplier sup);
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.fakes.MinecraftServerInterface;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.util.SystemUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@Mixin(MinecraftServer.class)
|
||||
public abstract class MinecraftServer_scarpetMixin implements MinecraftServerInterface
|
||||
{
|
||||
@Shadow protected abstract void tick(BooleanSupplier booleanSupplier_1);
|
||||
|
||||
@Shadow private long timeReference;
|
||||
|
||||
@Shadow private long field_4557;
|
||||
|
||||
@Override
|
||||
public void forceTick(BooleanSupplier isAhead)
|
||||
{
|
||||
timeReference = field_4557 = SystemUtil.getMeasuringTimeMs();
|
||||
tick(isAhead);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package carpet.script;
|
||||
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
public class CarpetContext extends Context
|
||||
{
|
||||
public ServerCommandSource s;
|
||||
public BlockPos origin;
|
||||
public CarpetContext(ScriptHost host, ServerCommandSource source, BlockPos origin)
|
||||
{
|
||||
super(host);
|
||||
s = source;
|
||||
this.origin = origin;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Context recreate()
|
||||
{
|
||||
return new CarpetContext(this.host, this.s, this.origin);
|
||||
}
|
||||
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,260 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.script.bundled.CameraPathModule;
|
||||
import carpet.script.bundled.FileModule;
|
||||
import carpet.script.bundled.ModuleInterface;
|
||||
import carpet.script.exception.CarpetExpressionException;
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.value.Value;
|
||||
import carpet.utils.Messenger;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.io.File;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
|
||||
import static net.minecraft.server.command.CommandManager.argument;
|
||||
import static net.minecraft.server.command.CommandManager.literal;
|
||||
|
||||
public class CarpetScriptServer
|
||||
{
|
||||
//make static for now, but will change that later:
|
||||
public ScriptHost globalHost;
|
||||
public Map<String, ScriptHost> modules;
|
||||
long tickStart;
|
||||
public boolean stopAll;
|
||||
|
||||
public static List<ModuleInterface> bundledModuleData = new ArrayList<ModuleInterface>(){{
|
||||
add(new CameraPathModule());
|
||||
}};
|
||||
|
||||
public CarpetScriptServer()
|
||||
{
|
||||
globalHost = createMinecraftScriptHost("");
|
||||
modules = new HashMap<>();
|
||||
tickStart = 0L;
|
||||
stopAll = false;
|
||||
resetErrorSnooper();
|
||||
}
|
||||
|
||||
ModuleInterface getModule(String name)
|
||||
{
|
||||
for (ModuleInterface moduleData : bundledModuleData)
|
||||
{
|
||||
if (moduleData.getName().equalsIgnoreCase(name))
|
||||
{
|
||||
return moduleData;
|
||||
}
|
||||
}
|
||||
|
||||
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts");
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles == null)
|
||||
return null;
|
||||
for (File script : listOfFiles)
|
||||
{
|
||||
if (script.getName().equalsIgnoreCase(name+".sc"))
|
||||
{
|
||||
return new FileModule(script);
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public List<String> listAvailableModules()
|
||||
{
|
||||
List<String> moduleNames = new ArrayList<>();
|
||||
for (ModuleInterface mi: bundledModuleData)
|
||||
{
|
||||
if (!modules.containsKey(mi.getName()))
|
||||
moduleNames.add(mi.getName());
|
||||
}
|
||||
File folder = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts");
|
||||
File[] listOfFiles = folder.listFiles();
|
||||
if (listOfFiles == null)
|
||||
return moduleNames;
|
||||
for (File script : listOfFiles)
|
||||
{
|
||||
if (script.getName().endsWith(".sc"))
|
||||
{
|
||||
String name = script.getName().replaceFirst("\\.sc","").toLowerCase(Locale.ROOT);
|
||||
if (!modules.containsKey(name))
|
||||
moduleNames.add(name);
|
||||
}
|
||||
}
|
||||
return moduleNames;
|
||||
}
|
||||
|
||||
|
||||
private static ScriptHost createMinecraftScriptHost(String name)
|
||||
{
|
||||
ScriptHost host = new ScriptHost(name);
|
||||
host.globalVariables.put("_x", (c, t) -> Value.ZERO);
|
||||
host.globalVariables.put("_y", (c, t) -> Value.ZERO);
|
||||
host.globalVariables.put("_z", (c, t) -> Value.ZERO);
|
||||
return host;
|
||||
}
|
||||
|
||||
public boolean addScriptHost(ServerCommandSource source, String name)
|
||||
{
|
||||
name = name.toLowerCase(Locale.ROOT);
|
||||
ScriptHost newHost = createMinecraftScriptHost(name);
|
||||
ModuleInterface module = getModule(name);
|
||||
if (module == null)
|
||||
{
|
||||
Messenger.m(source, "r Unable to load the package - not found");
|
||||
return false;
|
||||
}
|
||||
String code = module.getCode();
|
||||
if (code == null)
|
||||
{
|
||||
Messenger.m(source, "r Unable to load the package - not found");
|
||||
return false;
|
||||
}
|
||||
// parse code and convert to expression
|
||||
// fill functions etc.
|
||||
// possibly add a command
|
||||
try
|
||||
{
|
||||
setChatErrorSnooper(source);
|
||||
CarpetExpression ex = new CarpetExpression(module.getCode(), source, new BlockPos(0, 0, 0));
|
||||
ex.scriptRunCommand(newHost, new BlockPos(source.getPosition()));
|
||||
}
|
||||
catch (CarpetExpressionException e)
|
||||
{
|
||||
Messenger.m(source, "r Exception white evaluating expression at "+new BlockPos(source.getPosition())+": "+e.getMessage());
|
||||
resetErrorSnooper();
|
||||
return false;
|
||||
}
|
||||
modules.put(name, newHost);
|
||||
|
||||
addCommand(name);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
public void addCommand(String hostName)
|
||||
{
|
||||
ScriptHost host = modules.get(hostName);
|
||||
if (host == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
if (!host.globalFunctions.containsKey("__command"))
|
||||
{
|
||||
return;
|
||||
}
|
||||
LiteralArgumentBuilder<ServerCommandSource> command = literal(hostName).
|
||||
requires((player) -> modules.containsKey(hostName)).
|
||||
executes( (c) ->
|
||||
{
|
||||
Messenger.m(c.getSource(), "gi "+modules.get(hostName).call(c.getSource(),"__command", null, ""));
|
||||
return 1;
|
||||
});
|
||||
|
||||
for (String function : host.getPublicFunctions())
|
||||
{
|
||||
command = command.
|
||||
then(literal(function).
|
||||
requires((player) -> modules.containsKey(hostName) && modules.get(hostName).getPublicFunctions().contains(function)).
|
||||
executes( (c) -> {
|
||||
Messenger.m(
|
||||
c.getSource(),
|
||||
"gi "+modules.get(hostName).call(
|
||||
c.getSource(),
|
||||
function,
|
||||
null,
|
||||
""
|
||||
)
|
||||
);
|
||||
return 1;
|
||||
}).
|
||||
then(argument("args...", StringArgumentType.greedyString()).
|
||||
executes( (c) -> {
|
||||
Messenger.m(
|
||||
c.getSource(),
|
||||
"gi "+modules.get(hostName).call(
|
||||
c.getSource(),
|
||||
function,
|
||||
null,
|
||||
StringArgumentType.getString(c, "args...")
|
||||
)
|
||||
);
|
||||
return 1;
|
||||
})));
|
||||
}
|
||||
CarpetServer.minecraft_server.getCommandManager().getDispatcher().register(command);
|
||||
CarpetSettings.notifyPlayersCommandsChanged();
|
||||
}
|
||||
|
||||
public void setChatErrorSnooper(ServerCommandSource source)
|
||||
{
|
||||
ExpressionException.errorSnooper = (expr, token, message) ->
|
||||
{
|
||||
try
|
||||
{
|
||||
source.getPlayer();
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
String[] lines = expr.getCodeString().split("\n");
|
||||
|
||||
String shebang = message;
|
||||
|
||||
if (lines.length > 1)
|
||||
{
|
||||
shebang += " at line "+(token.lineno+1)+", pos "+(token.linepos+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
shebang += " at pos "+(token.pos+1);
|
||||
}
|
||||
if (expr.getName() != null)
|
||||
{
|
||||
shebang += " in "+expr.getName()+"";
|
||||
}
|
||||
Messenger.m(source, "r "+shebang);
|
||||
|
||||
if (lines.length > 1 && token.lineno > 0)
|
||||
{
|
||||
Messenger.m(source, "l "+lines[token.lineno-1]);
|
||||
}
|
||||
Messenger.m(source, "l "+lines[token.lineno].substring(0, token.linepos), "r HERE>> ", "l "+
|
||||
lines[token.lineno].substring(token.linepos));
|
||||
|
||||
if (lines.length > 1 && token.lineno < lines.length-1)
|
||||
{
|
||||
Messenger.m(source, "l "+lines[token.lineno+1]);
|
||||
}
|
||||
return new ArrayList<>();
|
||||
};
|
||||
}
|
||||
public void resetErrorSnooper()
|
||||
{
|
||||
ExpressionException.errorSnooper=null;
|
||||
}
|
||||
|
||||
public boolean removeScriptHost(String name)
|
||||
{
|
||||
name = name.toLowerCase(Locale.ROOT);
|
||||
if (!modules.containsKey(name))
|
||||
return false;
|
||||
// stop all events associated with name
|
||||
modules.remove(name);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,90 @@
|
||||
package carpet.script;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class Context
|
||||
{
|
||||
static final int NONE = 0;
|
||||
static final int VOID = 1;
|
||||
static final int BOOLEAN = 2;
|
||||
static final int NUMBER = 3;
|
||||
static final int STRING = 4;
|
||||
static final int LIST = 5;
|
||||
static final int ITERATOR = 6;
|
||||
static final int SIGNATURE = 7;
|
||||
static final int LOCALIZATION = 8;
|
||||
|
||||
private Map<String, LazyValue> variables = new HashMap<>();
|
||||
|
||||
protected ScriptHost host;
|
||||
|
||||
Context(ScriptHost host)
|
||||
{
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
|
||||
LazyValue getVariable(String name)
|
||||
{
|
||||
if (variables.containsKey(name))
|
||||
{
|
||||
return variables.get(name);
|
||||
}
|
||||
return host.globalVariables.get(name);
|
||||
}
|
||||
|
||||
void setVariable(String name, LazyValue lv)
|
||||
{
|
||||
if (name.startsWith("global_"))
|
||||
{
|
||||
host.globalVariables.put(name, lv);
|
||||
return;
|
||||
}
|
||||
variables.put(name, lv);
|
||||
}
|
||||
|
||||
|
||||
boolean isAVariable(String name)
|
||||
{
|
||||
return variables.containsKey(name) || host.globalVariables.containsKey(name);
|
||||
}
|
||||
|
||||
|
||||
void delVariable(String variable)
|
||||
{
|
||||
if (variable.startsWith("global_"))
|
||||
{
|
||||
host.globalVariables.remove(variable);
|
||||
return;
|
||||
}
|
||||
variables.remove(variable);
|
||||
}
|
||||
void clearAll(String variable)
|
||||
{
|
||||
if (variable.startsWith("global_"))
|
||||
{
|
||||
host.globalVariables.remove(variable);
|
||||
return;
|
||||
}
|
||||
variables.remove(variable);
|
||||
}
|
||||
|
||||
public Context with(String variable, LazyValue lv)
|
||||
{
|
||||
variables.put(variable, lv);
|
||||
return this;
|
||||
}
|
||||
|
||||
public Set<String> getAllVariableNames()
|
||||
{
|
||||
return variables.keySet();
|
||||
}
|
||||
|
||||
public Context recreate()
|
||||
{
|
||||
return new Context(this.host);
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,20 @@
|
||||
package carpet.script;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* sole purpose of this package is to provide public access to package-private methods of Expression and CarpetExpression
|
||||
* classes so they don't leave garbage in javadocs
|
||||
*/
|
||||
public class ExpressionInspector
|
||||
{
|
||||
public static List<String> Expression_getExpressionSnippet(Tokenizer.Token token, Expression expr)
|
||||
{
|
||||
return Expression.getExpressionSnippet(token, expr);
|
||||
}
|
||||
|
||||
public static String Expression_getName(Expression e)
|
||||
{
|
||||
return e.getName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,195 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import carpet.script.value.Value;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class Fluff
|
||||
{
|
||||
@FunctionalInterface
|
||||
public interface TriFunction<A, B, C, R> { R apply(A a, B b, C c); }
|
||||
|
||||
@FunctionalInterface
|
||||
public interface QuadFunction<A, B, C, D, R> { R apply(A a, B b, C c, D d);}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface QuinnFunction<A, B, C, D, E, R> { R apply(A a, B b, C c, D d, E e);}
|
||||
|
||||
@FunctionalInterface
|
||||
public interface SexFunction<A, B, C, D, E, F, R> { R apply(A a, B b, C c, D d, E e, F f);}
|
||||
|
||||
public interface ILazyFunction
|
||||
{
|
||||
int getNumParams();
|
||||
|
||||
boolean numParamsVaries();
|
||||
|
||||
LazyValue lazyEval(Context c, Integer type, Expression expr, Tokenizer.Token token, List<LazyValue> lazyParams);
|
||||
// lazy function has a chance to change execution based on contxt
|
||||
}
|
||||
|
||||
public interface IFunction extends ILazyFunction
|
||||
{
|
||||
Value eval(List<Value> parameters);
|
||||
}
|
||||
|
||||
public interface ILazyOperator
|
||||
{
|
||||
int getPrecedence();
|
||||
|
||||
boolean isLeftAssoc();
|
||||
|
||||
LazyValue lazyEval(Context c, Integer type, Expression e, Tokenizer.Token t, LazyValue v1, LazyValue v2);
|
||||
}
|
||||
|
||||
public interface IOperator extends ILazyOperator
|
||||
{
|
||||
Value eval(Value v1, Value v2);
|
||||
}
|
||||
|
||||
public abstract static class AbstractLazyFunction implements ILazyFunction
|
||||
{
|
||||
protected String name;
|
||||
int numParams;
|
||||
|
||||
AbstractLazyFunction(int numParams)
|
||||
{
|
||||
this.numParams = numParams;
|
||||
}
|
||||
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
public int getNumParams() {
|
||||
return numParams;
|
||||
}
|
||||
|
||||
public boolean numParamsVaries() {
|
||||
return numParams < 0;
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class AbstractFunction extends AbstractLazyFunction implements IFunction
|
||||
{
|
||||
AbstractFunction(int numParams) {
|
||||
super(numParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyValue lazyEval(Context cc, Integer type, Expression e, Tokenizer.Token t, final List<LazyValue> lazyParams)
|
||||
{
|
||||
try
|
||||
{
|
||||
return new LazyValue()
|
||||
{ // eager evaluation always ignores the required type and evals params by none default
|
||||
private List<Value> params;
|
||||
|
||||
public Value evalValue(Context c, Integer type) {
|
||||
return AbstractFunction.this.eval(getParams(c));
|
||||
}
|
||||
|
||||
private List<Value> getParams(Context c) {
|
||||
if (params == null) {
|
||||
params = new ArrayList<>();
|
||||
for (LazyValue lazyParam : lazyParams) {
|
||||
params.add(lazyParam.evalValue(c)); // none type default by design
|
||||
}
|
||||
}
|
||||
return params;
|
||||
}
|
||||
};
|
||||
}
|
||||
catch (InternalExpressionException exc)
|
||||
{
|
||||
throw new ExpressionException(e, t, exc.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class AbstractLazyOperator implements ILazyOperator
|
||||
{
|
||||
int precedence;
|
||||
|
||||
boolean leftAssoc;
|
||||
|
||||
AbstractLazyOperator(int precedence, boolean leftAssoc) {
|
||||
this.precedence = precedence;
|
||||
this.leftAssoc = leftAssoc;
|
||||
}
|
||||
|
||||
public int getPrecedence() {
|
||||
return precedence;
|
||||
}
|
||||
|
||||
public boolean isLeftAssoc() {
|
||||
return leftAssoc;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public abstract static class AbstractOperator extends AbstractLazyOperator implements IOperator
|
||||
{
|
||||
|
||||
AbstractOperator(int precedence, boolean leftAssoc) {
|
||||
super(precedence, leftAssoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyValue lazyEval(Context c_ignored, Integer type, Expression e, Tokenizer.Token t, final LazyValue v1, final LazyValue v2)
|
||||
{
|
||||
try
|
||||
{
|
||||
return (c, type_ignored) -> AbstractOperator.this.eval(v1.evalValue(c), v2.evalValue(c));
|
||||
}
|
||||
catch (InternalExpressionException exc)
|
||||
{
|
||||
throw new ExpressionException(e, t, exc.getMessage());
|
||||
}
|
||||
catch (ArithmeticException exc)
|
||||
{
|
||||
throw new ExpressionException(e, t, "Your math is wrong, "+exc.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public abstract static class AbstractUnaryOperator extends AbstractOperator
|
||||
{
|
||||
AbstractUnaryOperator(int precedence, boolean leftAssoc) {
|
||||
super(precedence, leftAssoc);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LazyValue lazyEval(Context cc, Integer type, Expression e, Tokenizer.Token t, final LazyValue v1, final LazyValue v2)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (v2 != null)
|
||||
{
|
||||
throw new ExpressionException(e, t, "Did not expect a second parameter for unary operator");
|
||||
}
|
||||
return (c, ignored_type) -> AbstractUnaryOperator.this.evalUnary(v1.evalValue(c));
|
||||
}
|
||||
catch (InternalExpressionException exc) // might not actually throw it
|
||||
{
|
||||
throw new ExpressionException(e, t, exc.getMessage());
|
||||
}
|
||||
catch (ArithmeticException exc)
|
||||
{
|
||||
throw new ExpressionException(e, t, "Your math is wrong, "+exc.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value eval(Value v1, Value v2)
|
||||
{
|
||||
throw new ExpressionException("Shouldn't end up here");
|
||||
}
|
||||
|
||||
public abstract Value evalUnary(Value v1);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.script.value.Value;
|
||||
|
||||
/** LazyNumber interface created for lazily evaluated functions */
|
||||
@FunctionalInterface
|
||||
public interface LazyValue
|
||||
{
|
||||
LazyValue FALSE = (c, t) -> Value.FALSE;
|
||||
LazyValue TRUE = (c, t) -> Value.TRUE;
|
||||
LazyValue NULL = (c, t) -> Value.NULL;
|
||||
LazyValue ZERO = (c, t) -> Value.ZERO;
|
||||
/**
|
||||
* The Value representation of the left parenthesis, used for parsing
|
||||
* varying numbers of function parameters.
|
||||
*/
|
||||
LazyValue PARAMS_START = (c, t) -> null;
|
||||
|
||||
Value evalValue(Context c, Integer type);
|
||||
|
||||
default Value evalValue(Context c){
|
||||
return evalValue(c, 0);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.value.NumericValue;
|
||||
import carpet.script.value.StringValue;
|
||||
import carpet.script.value.Value;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
|
||||
import java.math.BigInteger;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Map;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.Math.max;
|
||||
|
||||
public class ScriptHost
|
||||
{
|
||||
|
||||
public final Map<String, UserDefinedFunction> globalFunctions = new HashMap<>();
|
||||
|
||||
public final Map<String, LazyValue> globalVariables = new HashMap<>();
|
||||
|
||||
private String name;
|
||||
public String getName() {return name;}
|
||||
|
||||
public ScriptHost(String name)
|
||||
{
|
||||
this.name = name;
|
||||
globalVariables.put("euler", (c, t) -> Expression.euler);
|
||||
globalVariables.put("pi", (c, t) -> Expression.PI);
|
||||
globalVariables.put("null", (c, t) -> Value.NULL);
|
||||
globalVariables.put("true", (c, t) -> Value.TRUE);
|
||||
globalVariables.put("false", (c, t) -> Value.FALSE);
|
||||
|
||||
//special variables for second order functions so we don't need to check them all the time
|
||||
globalVariables.put("_", (c, t) -> Value.ZERO);
|
||||
globalVariables.put("_i", (c, t) -> Value.ZERO);
|
||||
globalVariables.put("_a", (c, t) -> Value.ZERO);
|
||||
}
|
||||
public Expression getExpressionForFunction(String name)
|
||||
{
|
||||
return globalFunctions.get(name).getExpression();
|
||||
}
|
||||
public Tokenizer.Token getTokenForFunction(String name)
|
||||
{
|
||||
return globalFunctions.get(name).getToken();
|
||||
}
|
||||
|
||||
public List<String> getPublicFunctions()
|
||||
{
|
||||
return globalFunctions.keySet().stream().filter((str) -> !str.startsWith("_")).collect(Collectors.toList());
|
||||
}
|
||||
public List<String> getAvailableFunctions()
|
||||
{
|
||||
return globalFunctions.keySet().stream().filter((str) -> !str.startsWith("__")).collect(Collectors.toList());
|
||||
}
|
||||
|
||||
public String call(ServerCommandSource source, String call, List<Integer> coords, String arg)
|
||||
{
|
||||
if (CarpetServer.scriptServer.stopAll)
|
||||
return "SCRIPTING PAUSED";
|
||||
UserDefinedFunction acf = globalFunctions.get(call);
|
||||
if (acf == null)
|
||||
return "UNDEFINED";
|
||||
List<LazyValue> argv = new ArrayList<>();
|
||||
if (coords != null)
|
||||
for (Integer i: coords)
|
||||
argv.add( (c, t) -> new NumericValue(i));
|
||||
String sign = "";
|
||||
for (Tokenizer.Token tok : Tokenizer.simplepass(arg))
|
||||
{
|
||||
switch (tok.type)
|
||||
{
|
||||
case VARIABLE:
|
||||
if (globalVariables.containsKey(tok.surface.toLowerCase(Locale.ROOT)))
|
||||
{
|
||||
argv.add(globalVariables.get(tok.surface.toLowerCase(Locale.ROOT)));
|
||||
break;
|
||||
}
|
||||
case STRINGPARAM:
|
||||
argv.add((c, t) -> new StringValue(tok.surface));
|
||||
sign = "";
|
||||
break;
|
||||
|
||||
case LITERAL:
|
||||
try
|
||||
{
|
||||
String finalSign = sign;
|
||||
argv.add((c, t) ->new NumericValue(finalSign+tok.surface));
|
||||
sign = "";
|
||||
}
|
||||
catch (NumberFormatException exception)
|
||||
{
|
||||
return "Fail: "+sign+tok.surface+" seems like a number but it is not a number. Use quotes to ensure its a string";
|
||||
}
|
||||
break;
|
||||
case HEX_LITERAL:
|
||||
try
|
||||
{
|
||||
String finalSign = sign;
|
||||
argv.add((c, t) -> new NumericValue(new BigInteger(finalSign+tok.surface.substring(2), 16).doubleValue()));
|
||||
sign = "";
|
||||
}
|
||||
catch (NumberFormatException exception)
|
||||
{
|
||||
return "Fail: "+sign+tok.surface+" seems like a number but it is not a number. Use quotes to ensure its a string";
|
||||
}
|
||||
break;
|
||||
case OPERATOR:
|
||||
case UNARY_OPERATOR:
|
||||
if ((tok.surface.equals("-") || tok.surface.equals("-u")) && sign.isEmpty())
|
||||
{
|
||||
sign = "-";
|
||||
}
|
||||
else
|
||||
{
|
||||
return "Fail: operators, like " + tok.surface + " are not allowed in invoke";
|
||||
}
|
||||
break;
|
||||
case FUNCTION:
|
||||
return "Fail: passing functions like "+tok.surface+"() to invoke is not allowed";
|
||||
case OPEN_PAREN:
|
||||
case COMMA:
|
||||
case CLOSE_PAREN:
|
||||
return "Fail: "+tok.surface+" is not allowed in invoke";
|
||||
}
|
||||
}
|
||||
List<String> args = acf.getArguments();
|
||||
if (argv.size() != args.size())
|
||||
{
|
||||
String error = "Fail: stored function "+call+" takes "+args.size()+" arguments, not "+argv.size()+ ":\n";
|
||||
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";
|
||||
}
|
||||
return error;
|
||||
}
|
||||
try
|
||||
{
|
||||
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
|
||||
Context context = new CarpetContext(this, source, BlockPos.ORIGIN);
|
||||
return Expression.evalValue(
|
||||
() -> acf.lazyEval(context, Context.VOID, acf.expression, acf.token, argv),
|
||||
context,
|
||||
Context.VOID
|
||||
).getString();
|
||||
}
|
||||
catch (ExpressionException e)
|
||||
{
|
||||
return e.getMessage();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,314 @@
|
||||
package carpet.script;
|
||||
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
/**
|
||||
* Expression tokenizer that allows to iterate over a {@link String}
|
||||
* expression token by token. Blank characters will be skipped.
|
||||
*/
|
||||
public class Tokenizer implements Iterator<Tokenizer.Token>
|
||||
{
|
||||
|
||||
/** What character to use for decimal separators. */
|
||||
private static final char decimalSeparator = '.';
|
||||
/** What character to use for minus sign (negative values). */
|
||||
private static final char minusSign = '-';
|
||||
/** Actual position in expression string. */
|
||||
private int pos = 0;
|
||||
private int lineno = 0;
|
||||
private int linepos = 0;
|
||||
|
||||
|
||||
/** The original input expression. */
|
||||
private String input;
|
||||
/** The previous token or <code>null</code> if none. */
|
||||
private Token previousToken;
|
||||
|
||||
private Expression expression;
|
||||
|
||||
Tokenizer(Expression expr, String input)
|
||||
{
|
||||
this.input = input;
|
||||
this.expression = expr;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return (pos < input.length());
|
||||
}
|
||||
|
||||
/**
|
||||
* Peek at the next character, without advancing the iterator.
|
||||
*
|
||||
* @return The next character or character 0, if at end of string.
|
||||
*/
|
||||
private char peekNextChar()
|
||||
{
|
||||
return (pos < (input.length() - 1)) ? input.charAt(pos + 1) : 0;
|
||||
}
|
||||
|
||||
private boolean isHexDigit(char ch)
|
||||
{
|
||||
return ch == 'x' || ch == 'X' || (ch >= '0' && ch <= '9') || (ch >= 'a' && ch <= 'f')
|
||||
|| (ch >= 'A' && ch <= 'F');
|
||||
}
|
||||
|
||||
public static List<Token> simplepass(String input)
|
||||
{
|
||||
Tokenizer tok = new Tokenizer(null, input);
|
||||
List<Token> res = new ArrayList<>();
|
||||
while (tok.hasNext()) res.add(tok.next());
|
||||
return res;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Token next()
|
||||
{
|
||||
Token token = new Token();
|
||||
|
||||
if (pos >= input.length())
|
||||
{
|
||||
return previousToken = null;
|
||||
}
|
||||
char ch = input.charAt(pos);
|
||||
while (Character.isWhitespace(ch) && pos < input.length())
|
||||
{
|
||||
linepos++;
|
||||
if (ch=='\n')
|
||||
{
|
||||
lineno++;
|
||||
linepos = 0;
|
||||
}
|
||||
ch = input.charAt(++pos);
|
||||
}
|
||||
token.pos = pos;
|
||||
token.lineno = lineno;
|
||||
token.linepos = linepos;
|
||||
|
||||
boolean isHex = false;
|
||||
|
||||
if (Character.isDigit(ch) || (ch == decimalSeparator && Character.isDigit(peekNextChar())))
|
||||
{
|
||||
if (ch == '0' && (peekNextChar() == 'x' || peekNextChar() == 'X'))
|
||||
isHex = true;
|
||||
while ((isHex
|
||||
&& isHexDigit(
|
||||
ch))
|
||||
|| (Character.isDigit(ch) || ch == decimalSeparator || ch == 'e' || ch == 'E'
|
||||
|| (ch == minusSign && token.length() > 0
|
||||
&& ('e' == token.charAt(token.length() - 1)
|
||||
|| 'E' == token.charAt(token.length() - 1)))
|
||||
|| (ch == '+' && token.length() > 0
|
||||
&& ('e' == token.charAt(token.length() - 1)
|
||||
|| 'E' == token.charAt(token.length() - 1))))
|
||||
&& (pos < input.length()))
|
||||
{
|
||||
token.append(input.charAt(pos++));
|
||||
linepos++;
|
||||
ch = pos == input.length() ? 0 : input.charAt(pos);
|
||||
}
|
||||
token.type = isHex ? Token.TokenType.HEX_LITERAL : Token.TokenType.LITERAL;
|
||||
}
|
||||
else if (ch == '\'')
|
||||
{
|
||||
pos++;
|
||||
linepos++;
|
||||
if (pos == input.length())
|
||||
{
|
||||
token.type = Token.TokenType.STRINGPARAM;
|
||||
if (expression != null)
|
||||
throw new ExpressionException(this.expression, token, "Program truncated");
|
||||
}
|
||||
ch = input.charAt(pos);
|
||||
while (ch != '\'')
|
||||
{
|
||||
if (ch == '\\')
|
||||
{
|
||||
pos++;
|
||||
linepos++;
|
||||
if (pos == input.length())
|
||||
{
|
||||
token.type = Token.TokenType.STRINGPARAM;
|
||||
if (expression != null)
|
||||
throw new ExpressionException(this.expression, token, "Program truncated");
|
||||
}
|
||||
}
|
||||
token.append(input.charAt(pos++));
|
||||
linepos++;
|
||||
ch = pos == input.length() ? 0 : input.charAt(pos);
|
||||
}
|
||||
pos++;
|
||||
linepos++;
|
||||
token.type = Token.TokenType.STRINGPARAM;
|
||||
}
|
||||
else if (Character.isLetter(ch) || "_".indexOf(ch) >= 0)
|
||||
{
|
||||
while ((Character.isLetter(ch) || Character.isDigit(ch) || "_".indexOf(ch) >= 0
|
||||
|| token.length() == 0 && "_".indexOf(ch) >= 0) && (pos < input.length()))
|
||||
{
|
||||
token.append(input.charAt(pos++));
|
||||
linepos++;
|
||||
ch = pos == input.length() ? 0 : input.charAt(pos);
|
||||
}
|
||||
// Remove optional white spaces after function or variable name
|
||||
if (Character.isWhitespace(ch))
|
||||
{
|
||||
while (Character.isWhitespace(ch) && pos < input.length())
|
||||
{
|
||||
ch = input.charAt(pos++);
|
||||
linepos++;
|
||||
if (ch=='\n')
|
||||
{
|
||||
lineno++;
|
||||
linepos = 0;
|
||||
}
|
||||
}
|
||||
pos--;
|
||||
linepos--;
|
||||
}
|
||||
token.type = ch == '(' ? Token.TokenType.FUNCTION : Token.TokenType.VARIABLE;
|
||||
}
|
||||
else if (ch == '(' || ch == ')' || ch == ',')
|
||||
{
|
||||
if (ch == '(')
|
||||
{
|
||||
token.type = Token.TokenType.OPEN_PAREN;
|
||||
}
|
||||
else if (ch == ')')
|
||||
{
|
||||
token.type = Token.TokenType.CLOSE_PAREN;
|
||||
}
|
||||
else
|
||||
{
|
||||
token.type = Token.TokenType.COMMA;
|
||||
}
|
||||
token.append(ch);
|
||||
pos++;
|
||||
linepos++;
|
||||
if (expression != null && previousToken != null && previousToken.type == Token.TokenType.OPERATOR && (ch == ')' || ch == ',') )
|
||||
{
|
||||
if (previousToken.surface.equalsIgnoreCase(";"))
|
||||
throw new ExpressionException(this.expression, previousToken,
|
||||
"Cannot have semicolon at the end of the expression");
|
||||
throw new ExpressionException(this.expression, previousToken,
|
||||
"Can't have operator "+previousToken.surface+" at the end of a subexpression");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
String greedyMatch = "";
|
||||
int initialPos = pos;
|
||||
int initialLinePos = linepos;
|
||||
ch = input.charAt(pos);
|
||||
int validOperatorSeenUntil = -1;
|
||||
while (!Character.isLetter(ch) && !Character.isDigit(ch) && "_".indexOf(ch) < 0
|
||||
&& !Character.isWhitespace(ch) && ch != '(' && ch != ')' && ch != ','
|
||||
&& (pos < input.length()))
|
||||
{
|
||||
greedyMatch += ch;
|
||||
pos++;
|
||||
linepos++;
|
||||
if (Expression.none.isAnOperator(greedyMatch))
|
||||
{
|
||||
validOperatorSeenUntil = pos;
|
||||
}
|
||||
ch = pos == input.length() ? 0 : input.charAt(pos);
|
||||
}
|
||||
if (validOperatorSeenUntil != -1)
|
||||
{
|
||||
token.append(input.substring(initialPos, validOperatorSeenUntil));
|
||||
pos = validOperatorSeenUntil;
|
||||
linepos = initialLinePos+validOperatorSeenUntil-initialPos;
|
||||
}
|
||||
else
|
||||
{
|
||||
token.append(greedyMatch);
|
||||
}
|
||||
|
||||
if (previousToken == null || previousToken.type == Token.TokenType.OPERATOR
|
||||
|| previousToken.type == Token.TokenType.OPEN_PAREN || previousToken.type == Token.TokenType.COMMA)
|
||||
{
|
||||
token.surface += "u";
|
||||
token.type = Token.TokenType.UNARY_OPERATOR;
|
||||
}
|
||||
else
|
||||
{
|
||||
token.type = Token.TokenType.OPERATOR;
|
||||
}
|
||||
}
|
||||
if (expression != null && previousToken != null &&
|
||||
(
|
||||
token.type == Token.TokenType.LITERAL ||
|
||||
token.type == Token.TokenType.HEX_LITERAL ||
|
||||
token.type == Token.TokenType.VARIABLE ||
|
||||
token.type == Token.TokenType.STRINGPARAM ||
|
||||
token.type == Token.TokenType.FUNCTION
|
||||
) &&(
|
||||
previousToken.type == Token.TokenType.VARIABLE ||
|
||||
previousToken.type == Token.TokenType.FUNCTION ||
|
||||
previousToken.type == Token.TokenType.LITERAL ||
|
||||
previousToken.type == Token.TokenType.CLOSE_PAREN ||
|
||||
previousToken.type == Token.TokenType.HEX_LITERAL ||
|
||||
previousToken.type == Token.TokenType.STRINGPARAM
|
||||
)
|
||||
)
|
||||
{
|
||||
throw new ExpressionException(this.expression, previousToken, "'"+token.surface +"' is not allowed after '"+previousToken.surface+"'");
|
||||
}
|
||||
return previousToken = token;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void remove()
|
||||
{
|
||||
throw new InternalExpressionException("remove() not supported");
|
||||
}
|
||||
|
||||
public static class Token
|
||||
{
|
||||
enum TokenType
|
||||
{
|
||||
VARIABLE, FUNCTION, LITERAL, OPERATOR, UNARY_OPERATOR,
|
||||
OPEN_PAREN, COMMA, CLOSE_PAREN, HEX_LITERAL, STRINGPARAM
|
||||
}
|
||||
public String surface = "";
|
||||
public TokenType type;
|
||||
public int pos;
|
||||
public int linepos;
|
||||
public int lineno;
|
||||
|
||||
public void append(char c)
|
||||
{
|
||||
surface += c;
|
||||
}
|
||||
|
||||
public void append(String s)
|
||||
{
|
||||
surface += s;
|
||||
}
|
||||
|
||||
public char charAt(int pos)
|
||||
{
|
||||
return surface.charAt(pos);
|
||||
}
|
||||
|
||||
public int length()
|
||||
{
|
||||
return surface.length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toString()
|
||||
{
|
||||
return surface;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package carpet.script;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public abstract class UserDefinedFunction extends Fluff.AbstractLazyFunction implements Fluff.ILazyFunction
|
||||
{
|
||||
protected List<String> arguments;
|
||||
protected Expression expression;
|
||||
protected Tokenizer.Token token;
|
||||
UserDefinedFunction(List<String> args, Expression expr, Tokenizer.Token t)
|
||||
{
|
||||
super(args.size());
|
||||
arguments = args;
|
||||
expression = expr;
|
||||
token = t;
|
||||
}
|
||||
public List<String> getArguments()
|
||||
{
|
||||
return arguments;
|
||||
}
|
||||
public Expression getExpression()
|
||||
{
|
||||
return expression;
|
||||
}
|
||||
public Tokenizer.Token getToken()
|
||||
{
|
||||
return token;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,311 @@
|
||||
package carpet.script.bundled;
|
||||
|
||||
public class CameraPathModule implements ModuleInterface
|
||||
{
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return "camera";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode()
|
||||
{
|
||||
return "$ __command() ->\n" +
|
||||
"$ (\n" +
|
||||
"$ print('Camera path module.');\n" +
|
||||
"$ print('-------------------');\n" +
|
||||
"$ print(' \"/camera start\" - set the starting point');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/camera add <N>\" - add another point <N> frames later');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/camera select_interpolation < linear | gauss_? >\"');\n" +
|
||||
"$ print(' Select interpolation between points:');\n" +
|
||||
"$ print(' - linear: straight paths between points.');\n" +
|
||||
"$ print(' - gauss_auto: automatic smooth transitions.');\n" +
|
||||
"$ print(' - gauss_<number>: custom fixed variance ');\n" +
|
||||
"$ print(' (in points) for special effects.');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/camera repeat <N> <last_delay>\" - ');\n" +
|
||||
"$ print(' Repeat existing points configuration n-times');\n" +
|
||||
"$ print(' using <last_delay> points to link path ends');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/camera speed <factor> - ');\n" +
|
||||
"$ print(' Change number of frames between points');\n" +
|
||||
"$ print(' from 25 -> 4 times faster (less points),');\n" +
|
||||
"$ print(' to 400 -> 4 times slower (more points)');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/camera play <fps>: run a path with a player');\n" +
|
||||
"$ print(' <fps> needs to be multiples of 20, (20 tps)');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/camera show\": shows current path for a moment');\n" +
|
||||
"$ print('');\n" +
|
||||
"$ print(' \"/script in camera invoke _show_path_tick <particle> <ppt>\":');\n" +
|
||||
"$ print(' place this in a repeating commandblock');\n" +
|
||||
"$ print(' to display path continuously');\n" +
|
||||
"$ print(' with set particle and number of particles per tick');\n" +
|
||||
"$ print(' example: \\'dust 0.9 0.1 0.1 1\\' 100 ');\n" +
|
||||
"$ ''\n" +
|
||||
"$ );\n" +
|
||||
"$ start() -> \n" +
|
||||
"$(\n" +
|
||||
"$ p = player();\n" +
|
||||
"$ global_points = l(l(l(p~'x',p~'y',p~'z',p~'pitch',p~'yaw'),0,'sharp'));\n" +
|
||||
"$ undef('global_path_precalculated');\n" +
|
||||
"$ str('Started path at %.1f %.1f %.1f', p~'x', p~'y', p~'z')\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ add(delay) -> \n" +
|
||||
"$( \n" +
|
||||
"$ p = player(); \n" +
|
||||
"$ mode = 'sharp';\n" +
|
||||
"$ 'mode is currently unused, run_path does always sharp, gauss interpolator is always smooth';\n" +
|
||||
"$ ' but this option could be used could be used at some point by more robust interpolators';\n" +
|
||||
"$ vector = l(p~'x',p~'y',p~'z', p~'pitch', p~'yaw');\n" +
|
||||
"$ __add_path_segment(vector, delay, mode);\n" +
|
||||
"$ str('Added point %d: %.1f %.1f %.1f', length(global_points), p~'x', p~'y', p~'z')\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ __add_path_segment(vector, duration, mode) -> \n" +
|
||||
"$(\n" +
|
||||
"$ undef('global_path_precalculated');\n" +
|
||||
"$ if ( (l('sharp','smooth') ~ mode) == null, exit('use smooth or sharp point')); \n" +
|
||||
"$ if(!global_points, exit('Cannot add point to path that didn\\'t started yet!'));\n" +
|
||||
"$ l(v, end_time, m) = element(global_points, -1);\n" +
|
||||
"$ put(vector,-1, __adjusted_rot(element(v, -1), element(vector, -1)));\n" +
|
||||
"$ global_points += l(vector, end_time+duration, mode)\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$'adjusts current rotation so we don\\'t spin around like crazy';\n" +
|
||||
"$ __adjusted_rot(previous_rot, current_rot) -> \n" +
|
||||
"$(\n" +
|
||||
"$ while( abs(previous_rot-current_rot) > 180, 1000,\n" +
|
||||
"$ current_rot += if(previous_rot < current_rot, -360, 360)\n" +
|
||||
"$ );\n" +
|
||||
"$ current_rot\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$\n" +
|
||||
"$ repeat(times, last_section_duration) -> \n" +
|
||||
"$(\n" +
|
||||
"$ undef('global_path_precalculated');\n" +
|
||||
"$ positions = map(global_points, k = element(_, 0));\n" +
|
||||
"$ modes = map(global_points, element(_, -1));\n" +
|
||||
"$ durations = map(global_points, element(element(global_points, _i+1), 1)-element(_, 1));\n" +
|
||||
"$ put(durations, -1, last_section_duration);\n" +
|
||||
"$ loop(times,\n" +
|
||||
"$ loop( length(positions),\n" +
|
||||
"$ __add_path_segment(element(positions, _), element(durations, _), element(modes, _))\n" +
|
||||
"$ )\n" +
|
||||
"$ );\n" +
|
||||
"$ str('Add %d points %d times', length(positions), times)\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ speed(percentage) ->\n" +
|
||||
"$(\n" +
|
||||
"$ undef('global_path_precalculated');\n" +
|
||||
"$ if (percentage < 25 || percentage > 400, \n" +
|
||||
"$ exit('path speed can only be speed, or slowed down 4 times. Recall command for larger changes')\n" +
|
||||
"$ );\n" +
|
||||
"$ ratio = percentage/100;\n" +
|
||||
"$ previous_path_length = element(element(global_points, -1),1);\n" +
|
||||
"$ for(global_points, put(_, 1, element(_, 1)*ratio ) );\n" +
|
||||
"$ undef('global_path_precalculated');\n" +
|
||||
"$ str('path %d from %d to %d ticks',\n" +
|
||||
"$ if(ratio<1,'shortened','extended'),\n" +
|
||||
"$ previous_path_length,\n" +
|
||||
"$ element(element(global_points, -1),1)\n" +
|
||||
"$ )\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ select_interpolation(method) ->\n" +
|
||||
"$(\n" +
|
||||
"$ undef('global_path_precalculated');\n" +
|
||||
"$ __prepare_path_if_needed() -> __prepare_path_if_needed_generic();\n" +
|
||||
"$ 'each supported method needs to specify its __find_position_for_point to trace the path';\n" +
|
||||
"$ 'accepting segment number, and position in the segment';\n" +
|
||||
"$ 'or optionally __prepare_path_if_needed, if path is inefficient to compute point by point';\n" +
|
||||
"$ if (\n" +
|
||||
"$ method == 'linear',\n" +
|
||||
"$ (\n" +
|
||||
"$ __find_position_for_point(s, p) -> __find_position_for_linear(s, p)\n" +
|
||||
"$ ),\n" +
|
||||
"$ method ~ '^gauss_',\n" +
|
||||
"$ (\n" +
|
||||
"$ type = method - 'gauss_';\n" +
|
||||
"$ global_interpol_option = if(type=='auto',0,number(type));\n" +
|
||||
"$ __find_position_for_point(s, p) -> __find_position_for_gauss(s, p)\n" +
|
||||
"$ ),\n" +
|
||||
"$ method ~ '^bungee_',\n" +
|
||||
"$ (\n" +
|
||||
"$ exit('unsupported / planned');\n" +
|
||||
"$ type = method - 'bungee_';\n" +
|
||||
"$ global_interpol_option = if(type=='auto',80,number(type));\n" +
|
||||
"$ __prepare_path_if_needed() -> __prepare_path_if_needed_bungee()\n" +
|
||||
"$ ),\n" +
|
||||
"$ \n" +
|
||||
"$ exit('Choose one of the following methods: linear, gauss:auto, gauss:<deviation>')\n" +
|
||||
"$ );\n" +
|
||||
"$ 'Ok'\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ select_interpolation('linear');\n" +
|
||||
"$\n" +
|
||||
"$ __assert_valid_for_motion() ->\n" +
|
||||
"$(\n" +
|
||||
"$ if(!global_points, exit('Path not defined yet'));\n" +
|
||||
"$ if(length(global_points)<2, exit('Path not complete - add more points'));\n" +
|
||||
"$ null \n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ __get_path_at(segment, start, index) ->\n" +
|
||||
"$(\n" +
|
||||
"$ v = element(global_path_precalculated, start+index);\n" +
|
||||
"$ if(v == null,\n" +
|
||||
"$ v = __find_position_for_point(segment, index);\n" +
|
||||
"$ put(global_path_precalculated, start+index, v)\n" +
|
||||
" );\n" +
|
||||
" v\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ __invalidate_points_cache() -> global_path_precalculated = map(range(element(element(global_points, -1),1)), null);\n" +
|
||||
"$\n" +
|
||||
"$ show() -> \n" +
|
||||
"$(\n" +
|
||||
"$ loop(100,\n" +
|
||||
"$ _show_path_tick('dust 0.9 0.1 0.1 1', 100);\n" +
|
||||
"$ game_tick(50)\n" +
|
||||
"$ );\n" +
|
||||
"$ 'Done!'\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$\n" +
|
||||
"$ play(fps) -> \n" +
|
||||
"$(\n" +
|
||||
"$ p = player();\n" +
|
||||
"$ __assert_valid_for_motion();\n" +
|
||||
"$ __prepare_path_if_needed();\n" +
|
||||
"$ loop( length(global_points)-1,\n" +
|
||||
"$ segment = _;\n" +
|
||||
"$ start = element(element(global_points, segment),1);\n" +
|
||||
"$ end = element(element(global_points, segment+1),1);\n" +
|
||||
"$ loop(end-start,\n" +
|
||||
"$ v = __get_path_at(segment, start, _);\n" +
|
||||
"$ modify(p, 'pos', slice(v,0,3));\n" +
|
||||
"$ modify(p, 'pitch', element(v,3));\n" +
|
||||
"$ modify(p, 'yaw', element(v,4));\n" +
|
||||
"$ game_tick(1000/fps)\n" +
|
||||
"$ )\n" +
|
||||
"$ );\n" +
|
||||
"$ game_tick(1000);\n" +
|
||||
"$ 'Done!'\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ _show_path_tick(particle_type, total) -> (\n" +
|
||||
"$ __assert_valid_for_motion();\n" +
|
||||
"$ __prepare_path_if_needed();\n" +
|
||||
"$ loop(total,\n" +
|
||||
"$ segment = floor(rand(length(global_points)-1));\n" +
|
||||
"$ start = element(element(global_points, segment),1);\n" +
|
||||
"$ end = element(element(global_points, segment+1),1);\n" +
|
||||
"$ index = floor(rand(end-start));\n" +
|
||||
"$ l(x, y, z) = slice(__get_path_at(segment, start, index), 0, 3);\n" +
|
||||
"$ particle(particle_type, x, y, z, 1, 0, 0)\n" +
|
||||
"$ );\n" +
|
||||
"$ null\n" +
|
||||
"$);\n" +
|
||||
"$\n" +
|
||||
"$ __prepare_path_if_needed_generic() ->\n" +
|
||||
"$(\n" +
|
||||
"$ if(!global_path_precalculated, __invalidate_points_cache())\n" +
|
||||
");\n" +
|
||||
"\n" +
|
||||
"__find_position_for_linear(segment, point) ->\n" +
|
||||
"(\n" +
|
||||
"$ l(va, start, mode_a) = element(global_points,segment);\n" +
|
||||
"$ l(vb, end, mode_b) = element(global_points,segment+1);\n" +
|
||||
"$ section = end-start;\n" +
|
||||
"$ dt = point/section;\n" +
|
||||
"$ dt*vb+(1-dt)*va\n" +
|
||||
");\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"$'(1/sqrt(2*pi*d*d))*euler^(-((x-miu)^2)/(2*d*d)) ';\n" +
|
||||
"$ 'but we will be normalizing anyways, so who cares';\n" +
|
||||
"$ __norm_prob(x, miu, d) -> euler^(-((x-miu)^2)/(2*d*d));\n" +
|
||||
"$\n" +
|
||||
"$ __find_position_for_gauss(from_index, point) -> \n" +
|
||||
"$(\n" +
|
||||
"$ dev = global_interpol_option;\n" +
|
||||
"$ components = l();\n" +
|
||||
"$ path_point = element(element(global_points, from_index),1);\n" +
|
||||
"$ \n" +
|
||||
"$ try(\n" +
|
||||
"$ for(range(from_index+1, length(global_points)),\n" +
|
||||
"$ l(v,ptime,mode) = element(global_points, _);\n" +
|
||||
"$ dev = if (global_interpol_option > 0, global_interpol_option, \n" +
|
||||
"$ devs = l();\n" +
|
||||
"$ if (_+1 < length(global_points), devs += element(element(global_points, _+1),1)-ptime);\n" +
|
||||
"$ if (_-1 >= 0, devs += ptime-element(element(global_points, _-1),1));\n" +
|
||||
"$ 0.6*reduce(devs, _a+_, 0)/length(devs)\n" +
|
||||
"$ );\n" +
|
||||
"$ impact = __norm_prob(path_point+point, ptime, dev);\n" +
|
||||
"$ if(rtotal && impact < 0.000001*rtotal, throw(null));\n" +
|
||||
"$ components += l(v, impact);\n" +
|
||||
"$ rtotal += impact\n" +
|
||||
"$ )\n" +
|
||||
"$ ,null\n" +
|
||||
"$ );\n" +
|
||||
"$ try(\n" +
|
||||
"$ for(range(from_index, -1, -1),\n" +
|
||||
"$ l(v,ptime,mode) = element(global_points, _);\n" +
|
||||
"$ dev = if (global_interpol_option > 0, global_interpol_option, \n" +
|
||||
"$ devs = l();\n" +
|
||||
"$ if (_+1 < length(global_points), devs += element(element(global_points, _+1),1)-ptime);\n" +
|
||||
"$ if (_-1 >= 0, devs += ptime-element(element(global_points, _-1),1));\n" +
|
||||
"$ 0.6*reduce(devs, _a+_, 0)/length(devs)\n" +
|
||||
"$ );\n" +
|
||||
"$ impact = __norm_prob(path_point+point, ptime, dev);\n" +
|
||||
"$ if(ltotal && impact < 0.000001*ltotal, throw(null));\n" +
|
||||
"$ components += l(v, impact);\n" +
|
||||
"$ ltotal += impact\n" +
|
||||
"$ )\n" +
|
||||
"$ ,null\n" +
|
||||
"$ );\n" +
|
||||
"$ total = rtotal+ltotal;\n" +
|
||||
"$ reduce(components, _a+element(_,0)*(element(_,1)/total), l(0,0,0,0,0))\n" +
|
||||
"$);\n" +
|
||||
"\n" +
|
||||
"\n" +
|
||||
"$ __prepare_path_if_needed_bungee(fps) ->\n" +
|
||||
"$(\n" +
|
||||
"$ exit('not ready!');\n" +
|
||||
"$ if(!global_points, exit('Cannot show path that doesn\\'t exist'));\n" +
|
||||
"$ if(length(global_points)<2, exit('Path not complete - add more points'));\n" +
|
||||
"$ v = element(element(global_points, 0),0);\n" +
|
||||
"$ modify(p, 'pos', slice(v,0,3));\n" +
|
||||
"$ modify(p, 'pitch', element(v,3));\n" +
|
||||
"$ modify(p, 'yaw', element(v,4));\n" +
|
||||
"$ current_target = element(element(global_points, 1),0);\n" +
|
||||
"$ current_hook = 1;\n" +
|
||||
"$ loop(length(global_points)-1, \n" +
|
||||
"$ current_base = _;\n" +
|
||||
"$ l(va, start, mode_a) = element(global_points,_);\n" +
|
||||
"$ l(vb, end, mode_b) = element(global_points,_+1);\n" +
|
||||
"$ section = end-start;\n" +
|
||||
"$ loop(section,\n" +
|
||||
"$ dt = _/section;\n" +
|
||||
"\n" +
|
||||
"$ v = dt*vb+(1-dt)*va;\n" +
|
||||
"$ modify(p, 'pos', slice(v,0,3));\n" +
|
||||
"$ modify(p, 'pitch', element(v,3));\n" +
|
||||
"$ modify(p, 'yaw', element(v,4));\n" +
|
||||
"$ game_tick(1000/fps)\n" +
|
||||
"$ )\n" +
|
||||
"$ );\n" +
|
||||
"$ game_tick(1000);\n" +
|
||||
"$ 'Done!'\n" +
|
||||
"$)\n" +
|
||||
"$";
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
package carpet.script.bundled;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileReader;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.Locale;
|
||||
|
||||
public class FileModule implements ModuleInterface
|
||||
{
|
||||
private String name;
|
||||
private String code;
|
||||
public FileModule(File sourceFile)
|
||||
{
|
||||
try
|
||||
{
|
||||
name = sourceFile.getName().replaceFirst("\\.sc","").toLowerCase(Locale.ROOT);
|
||||
code = new String(Files.readAllBytes(sourceFile.toPath()));
|
||||
}
|
||||
catch ( IOException e)
|
||||
{
|
||||
name = null;
|
||||
code = null;
|
||||
}
|
||||
}
|
||||
public FileModule fromName(String name)
|
||||
{
|
||||
File sourceFile = CarpetServer.minecraft_server.getLevelStorage().resolveFile(
|
||||
CarpetServer.minecraft_server.getLevelName(), "scripts/"+name+".sc");
|
||||
return new FileModule(sourceFile);
|
||||
}
|
||||
@Override
|
||||
public String getName()
|
||||
{
|
||||
return name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCode()
|
||||
{
|
||||
return code;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package carpet.script.bundled;
|
||||
|
||||
public interface ModuleInterface
|
||||
{
|
||||
String getName();
|
||||
String getCode();
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package carpet.script.exception;
|
||||
|
||||
public class CarpetExpressionException extends ExpressionException
|
||||
{
|
||||
public CarpetExpressionException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
package carpet.script.exception;
|
||||
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.Fluff;
|
||||
import carpet.script.Tokenizer;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static carpet.script.ExpressionInspector.Expression_getExpressionSnippet;
|
||||
import static carpet.script.ExpressionInspector.Expression_getName;
|
||||
|
||||
/* The expression evaluators exception class. */
|
||||
public class ExpressionException extends RuntimeException
|
||||
{
|
||||
public ExpressionException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
|
||||
private static Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorMaker = (expr, token, errmessage) ->
|
||||
{
|
||||
|
||||
List<String> snippet = Expression_getExpressionSnippet(token, expr);
|
||||
List<String> errMsg = new ArrayList<>(snippet);
|
||||
if (snippet.size() != 1)
|
||||
{
|
||||
errmessage+= " at line "+(token.lineno+1)+", pos "+(token.linepos+1);
|
||||
}
|
||||
else
|
||||
{
|
||||
errmessage += " at pos "+(token.pos+1);
|
||||
}
|
||||
if (Expression_getName(expr) != null)
|
||||
{
|
||||
errmessage += " ("+Expression_getName(expr)+")";
|
||||
}
|
||||
errMsg.add(errmessage);
|
||||
return errMsg;
|
||||
};
|
||||
public static Fluff.TriFunction<Expression, Tokenizer.Token, String, List<String>> errorSnooper = null;
|
||||
|
||||
static String makeMessage(Expression e, Tokenizer.Token t, String message) throws ExpressionException
|
||||
{
|
||||
if (errorSnooper != null)
|
||||
{
|
||||
List<String> alternative = errorSnooper.apply(e, t, message);
|
||||
if (alternative!= null)
|
||||
{
|
||||
return String.join("\n", alternative);
|
||||
}
|
||||
}
|
||||
return String.join("\n", errorMaker.apply(e, t, message));
|
||||
}
|
||||
|
||||
public ExpressionException(Expression e, Tokenizer.Token t, String message)
|
||||
{
|
||||
super(makeMessage(e, t, message));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package carpet.script.exception;
|
||||
|
||||
/* The internal expression evaluators exception class. */
|
||||
public class InternalExpressionException extends ExpressionException
|
||||
{
|
||||
public InternalExpressionException(String message)
|
||||
{
|
||||
super(message);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,220 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.CarpetContext;
|
||||
import carpet.script.LazyValue;
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.command.arguments.BlockArgumentParser;
|
||||
import net.minecraft.block.Blocks;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.world.World;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class BlockValue extends Value
|
||||
{
|
||||
public static final BlockValue AIR = new BlockValue(Blocks.AIR.getDefaultState(), null, BlockPos.ORIGIN);
|
||||
public static final BlockValue NULL = new BlockValue(null, null, null);
|
||||
private BlockState blockState;
|
||||
private BlockPos pos;
|
||||
private World world;
|
||||
|
||||
public static BlockValue fromCoords(CarpetContext c, int x, int y, int z)
|
||||
{
|
||||
BlockPos pos = locateBlockPos(c, x,y,z);
|
||||
return new BlockValue(null, c.s.getWorld(), pos);
|
||||
}
|
||||
|
||||
public static BlockValue fromString(String str)
|
||||
{
|
||||
try
|
||||
{
|
||||
Identifier blockId = Identifier.fromCommandInput(new StringReader(str));
|
||||
if (Registry.BLOCK.containsId(blockId))
|
||||
{
|
||||
|
||||
Block block = Registry.BLOCK.get(blockId);
|
||||
return new BlockValue(block.getDefaultState(), null, null);
|
||||
}
|
||||
}
|
||||
catch (CommandSyntaxException ignored)
|
||||
{
|
||||
}
|
||||
throw new InternalExpressionException("Unknown block: "+str);
|
||||
}
|
||||
|
||||
private static Map<String, BlockValue> bvCache= new HashMap<>();
|
||||
public static BlockValue fromCommandExpression(String str)
|
||||
{
|
||||
try
|
||||
{
|
||||
BlockValue bv = bvCache.get(str);
|
||||
if (bv != null) return bv;
|
||||
BlockArgumentParser blockstateparser = (new BlockArgumentParser(new StringReader(str), false)).parse(true);
|
||||
if (blockstateparser.getBlockState() != null)
|
||||
{
|
||||
bv = new BlockValue(blockstateparser.getBlockState(), null, null);
|
||||
bvCache.put(str, bv);
|
||||
return bv;
|
||||
}
|
||||
}
|
||||
catch (CommandSyntaxException ignored)
|
||||
{
|
||||
}
|
||||
throw new InternalExpressionException("Cannot parse block: "+str);
|
||||
}
|
||||
|
||||
public static VectorLocator locateVec(CarpetContext c, List<LazyValue> params, int offset)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset).evalValue(c);
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return new VectorLocator(new Vec3d(((BlockValue) v1).getPos()).add(0.5,0.5,0.5), 1+offset);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
return new VectorLocator( new Vec3d(
|
||||
NumericValue.asNumber(args.get(0)).getDouble(),
|
||||
NumericValue.asNumber(args.get(1)).getDouble(),
|
||||
NumericValue.asNumber(args.get(2)).getDouble()),
|
||||
offset+1
|
||||
);
|
||||
}
|
||||
return new VectorLocator( new Vec3d(
|
||||
NumericValue.asNumber(v1).getDouble(),
|
||||
NumericValue.asNumber(params.get(1 + offset).evalValue(c)).getDouble(),
|
||||
NumericValue.asNumber(params.get(2 + offset).evalValue(c)).getDouble()),
|
||||
offset+3
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Position should be defined either by three coordinates, or a block value");
|
||||
}
|
||||
}
|
||||
|
||||
public static BlockPos locateBlockPos(CarpetContext c, int xpos, int ypos, int zpos)
|
||||
{
|
||||
return new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos);
|
||||
}
|
||||
|
||||
public static LocatorResult fromParams(CarpetContext c, List<LazyValue> params, int offset)
|
||||
{
|
||||
try
|
||||
{
|
||||
Value v1 = params.get(0 + offset).evalValue(c);
|
||||
if (v1 instanceof BlockValue)
|
||||
{
|
||||
return new LocatorResult(((BlockValue) v1), 1+offset);
|
||||
}
|
||||
if (v1 instanceof ListValue)
|
||||
{
|
||||
List<Value> args = ((ListValue) v1).getItems();
|
||||
int xpos = (int) NumericValue.asNumber(args.get(0)).getLong();
|
||||
int ypos = (int) NumericValue.asNumber(args.get(1)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber(args.get(2)).getLong();
|
||||
return new LocatorResult(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
1+offset);
|
||||
}
|
||||
int xpos = (int) NumericValue.asNumber(v1).getLong();
|
||||
int ypos = (int) NumericValue.asNumber( params.get(1 + offset).evalValue(c)).getLong();
|
||||
int zpos = (int) NumericValue.asNumber( params.get(2 + offset).evalValue(c)).getLong();
|
||||
return new LocatorResult(
|
||||
new BlockValue(
|
||||
null,
|
||||
c.s.getWorld(),
|
||||
new BlockPos(c.origin.getX() + xpos, c.origin.getY() + ypos, c.origin.getZ() + zpos)
|
||||
),
|
||||
3+offset
|
||||
);
|
||||
}
|
||||
catch (IndexOutOfBoundsException e)
|
||||
{
|
||||
throw new InternalExpressionException("Position should be defined either by three coordinates, or a block value");
|
||||
}
|
||||
}
|
||||
|
||||
public BlockState getBlockState()
|
||||
{
|
||||
if (blockState != null)
|
||||
{
|
||||
return blockState;
|
||||
}
|
||||
if (world != null && pos != null)
|
||||
{
|
||||
blockState = world.getBlockState(pos);
|
||||
return blockState;
|
||||
}
|
||||
throw new InternalExpressionException("Attemted to fetch blockstate without world or stored blockstate");
|
||||
}
|
||||
|
||||
public BlockValue(BlockState state, World world, BlockPos position)
|
||||
{
|
||||
this.world = world;
|
||||
blockState = state;
|
||||
pos = position;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return Registry.BLOCK.getId(getBlockState().getBlock()).getPath();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return this != NULL && !getBlockState().isAir();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
return new BlockValue(blockState, world, pos);
|
||||
}
|
||||
|
||||
public BlockPos getPos()
|
||||
{
|
||||
return pos;
|
||||
}
|
||||
|
||||
|
||||
public static class LocatorResult
|
||||
{
|
||||
public BlockValue block;
|
||||
public int offset;
|
||||
LocatorResult(BlockValue b, int o)
|
||||
{
|
||||
block = b;
|
||||
offset = o;
|
||||
}
|
||||
}
|
||||
|
||||
public static class VectorLocator
|
||||
{
|
||||
public Vec3d vec;
|
||||
public int offset;
|
||||
VectorLocator(Vec3d v, int o)
|
||||
{
|
||||
vec = v;
|
||||
offset = o;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,587 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import net.minecraft.entity.*;
|
||||
import net.minecraft.entity.effect.StatusEffect;
|
||||
import net.minecraft.entity.effect.StatusEffectInstance;
|
||||
import net.minecraft.nbt.Tag;
|
||||
import net.minecraft.server.command.ServerCommandSource;
|
||||
import net.minecraft.command.EntitySelector;
|
||||
import net.minecraft.command.EntitySelectorReader;
|
||||
import net.minecraft.command.arguments.NbtPathArgumentType;
|
||||
import net.minecraft.entity.mob.MobEntityWithAi; // EntityCreature;
|
||||
import net.minecraft.entity.mob.MobEntity; //LivingEntity;
|
||||
import net.minecraft.entity.ai.goal.Goal;
|
||||
import net.minecraft.entity.ai.goal.GoToWalkTargetGoal;
|
||||
import net.minecraft.entity.player.PlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.item.ItemStack;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.client.network.packet.EntityVelocityUpdateS2CPacket;
|
||||
import net.minecraft.potion.Potion;
|
||||
import net.minecraft.predicate.entity.EntityPredicates;
|
||||
import net.minecraft.util.Identifier;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.Vec3d;
|
||||
import net.minecraft.util.registry.Registry;
|
||||
import net.minecraft.network.chat.TextComponent;
|
||||
import org.apache.commons.lang3.tuple.Pair;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.BiFunction;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class EntityValue extends Value
|
||||
{
|
||||
private Entity entity;
|
||||
|
||||
public EntityValue(Entity e)
|
||||
{
|
||||
entity = e;
|
||||
}
|
||||
|
||||
private static Map<String, EntitySelector> selectorCache = new HashMap<>();
|
||||
public static Collection<? extends Entity > getEntitiesFromSelector(ServerCommandSource source, String selector)
|
||||
{
|
||||
try
|
||||
{
|
||||
EntitySelector entitySelector = selectorCache.get(selector);
|
||||
if (entitySelector != null)
|
||||
{
|
||||
return entitySelector.getEntities(source);
|
||||
}
|
||||
entitySelector = new EntitySelectorReader(new StringReader(selector), true).build();
|
||||
selectorCache.put(selector, entitySelector);
|
||||
return entitySelector.getEntities(source);
|
||||
}
|
||||
catch (CommandSyntaxException e)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot select entities from "+selector);
|
||||
}
|
||||
}
|
||||
|
||||
public Entity getEntity()
|
||||
{
|
||||
return entity;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return entity.getDisplayName().getString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Value v)
|
||||
{
|
||||
if (v instanceof EntityValue)
|
||||
{
|
||||
return entity.getEntityId()==((EntityValue) v).entity.getEntityId();
|
||||
}
|
||||
return super.equals(v);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(Value v)
|
||||
{
|
||||
String what = v.getString();
|
||||
return this.get(what, null);
|
||||
}
|
||||
|
||||
public static Pair<EntityType<?>, Predicate<? super Entity>> getPredicate(String who)
|
||||
{
|
||||
Pair<EntityType<?>, Predicate<? super Entity>> res = entityPredicates.get(who);
|
||||
if (res != null) return res;
|
||||
return res; //TODO add more here like search by tags, or type
|
||||
//if (who.startsWith('tag:'))
|
||||
}
|
||||
private static Map<String, Pair<EntityType<?>, Predicate<? super Entity>>> entityPredicates =
|
||||
new HashMap<String, Pair<EntityType<?>, Predicate<? super Entity>>>()
|
||||
{{
|
||||
put("*", Pair.of(null, EntityPredicates.VALID_ENTITY));
|
||||
put("living", Pair.of(null, (e) -> e instanceof LivingEntity && e.isAlive()));
|
||||
put("items", Pair.of(EntityType.ITEM, EntityPredicates.VALID_ENTITY));
|
||||
put("players", Pair.of(EntityType.PLAYER, EntityPredicates.VALID_ENTITY));
|
||||
put("!players", Pair.of(null, (e) -> !(e instanceof PlayerEntity) ));
|
||||
}};
|
||||
public Value get(String what, Value arg)
|
||||
{
|
||||
if (!(featureAccessors.containsKey(what)))
|
||||
throw new InternalExpressionException("unknown feature of entity: "+what);
|
||||
return featureAccessors.get(what).apply(entity, arg);
|
||||
}
|
||||
private static Map<String, EquipmentSlot> inventorySlots = new HashMap<String, EquipmentSlot>(){{
|
||||
put("main", EquipmentSlot.MAINHAND);
|
||||
put("offhand", EquipmentSlot.OFFHAND);
|
||||
put("head", EquipmentSlot.HEAD);
|
||||
put("chest", EquipmentSlot.CHEST);
|
||||
put("legs", EquipmentSlot.LEGS);
|
||||
put("feet", EquipmentSlot.FEET);
|
||||
}};
|
||||
private static Map<String, BiFunction<Entity, Value, Value>> featureAccessors = new HashMap<String, BiFunction<Entity, Value, Value>>() {{
|
||||
put("removed", (entity, arg) -> new NumericValue(entity.removed));
|
||||
put("uuid",(e, a) -> new StringValue(e.getUuidAsString()));
|
||||
put("id",(e, a) -> new NumericValue(e.getEntityId()));
|
||||
put("pos", (e, a) -> ListValue.of(new NumericValue(e.x), new NumericValue(e.y), new NumericValue(e.z)));
|
||||
put("x", (e, a) -> new NumericValue(e.x));
|
||||
put("y", (e, a) -> new NumericValue(e.y));
|
||||
put("z", (e, a) -> new NumericValue(e.z));
|
||||
put("motion", (e, a) ->
|
||||
{
|
||||
Vec3d velocity = e.getVelocity();
|
||||
return ListValue.of(new NumericValue(velocity.x), new NumericValue(velocity.y), new NumericValue(velocity.z));
|
||||
});
|
||||
put("motion_x", (e, a) -> new NumericValue(e.getVelocity().x));
|
||||
put("motion_y", (e, a) -> new NumericValue(e.getVelocity().y));
|
||||
put("motion_z", (e, a) -> new NumericValue(e.getVelocity().z));
|
||||
put("name", (e, a) -> new StringValue(e.getDisplayName().getString()));
|
||||
put("custom_name", (e, a) -> e.hasCustomName()?new StringValue(e.getCustomName().getString()):Value.NULL);
|
||||
put("type", (e, a) -> new StringValue(Registry.ENTITY_TYPE.getId(e.getType()).toString().replaceFirst("minecraft:","")));
|
||||
put("is_riding", (e, a) -> new NumericValue(e.hasVehicle()));
|
||||
put("is_ridden", (e, a) -> new NumericValue(e.hasPassengers()));
|
||||
put("passengers", (e, a) -> ListValue.wrap(e.getPassengerList().stream().map(EntityValue::new).collect(Collectors.toList())));
|
||||
put("mount", (e, a) -> (e.getVehicle()!=null)?new EntityValue(e.getVehicle()):Value.NULL);
|
||||
put("tags", (e, a) -> ListValue.wrap(e.getScoreboardTags().stream().map(StringValue::new).collect(Collectors.toList())));
|
||||
put("has_tag", (e, a) -> new NumericValue(e.getScoreboardTags().contains(a.getString())));
|
||||
put("yaw", (e, a)-> new NumericValue(e.yaw));
|
||||
put("pitch", (e, a)-> new NumericValue(e.pitch));
|
||||
put("is_burning", (e, a) -> new NumericValue(e.isOnFire()));
|
||||
//put("fire", (e, a) -> new NumericValue(e.getFire())); needs mixing
|
||||
put("silent", (e, a)-> new NumericValue(e.isSilent()));
|
||||
put("gravity", (e, a) -> new NumericValue(!e.hasNoGravity()));
|
||||
put("immune_to_fire", (e, a) -> new NumericValue(e.isFireImmune()));
|
||||
|
||||
put("invulnerable", (e, a) -> new NumericValue(e.isInvulnerable()));
|
||||
put("dimension", (e, a) -> new StringValue(e.dimension.toString().replaceFirst("minecraft:","")));
|
||||
put("height", (e, a) -> new NumericValue(e.getSize(EntityPose.STANDING).height));
|
||||
put("width", (e, a) -> new NumericValue(e.getSize(EntityPose.STANDING).width));
|
||||
put("eye_height", (e, a) -> new NumericValue(e.getEyeHeight(EntityPose.STANDING)));
|
||||
put("age", (e, a) -> new NumericValue(e.age));
|
||||
put("item", (e, a) -> (e instanceof ItemEntity)?new StringValue(((ItemEntity) e).getStack().getDisplayName().getString()):Value.NULL);
|
||||
put("count", (e, a) -> (e instanceof ItemEntity)?new NumericValue(((ItemEntity) e).getStack().getAmount()):Value.NULL);
|
||||
// ItemEntity -> despawn timer via ssGetAge
|
||||
put("is_baby", (e, a) -> (e instanceof LivingEntity)?new NumericValue(((LivingEntity) e).isBaby()):Value.NULL);
|
||||
put("target", (e, a) -> {
|
||||
if (e instanceof MobEntity)
|
||||
{
|
||||
LivingEntity target = ((MobEntity) e).getTarget(); // there is also getAttacking in living....
|
||||
if (target != null)
|
||||
{
|
||||
return new EntityValue(target);
|
||||
}
|
||||
}
|
||||
return Value.NULL;
|
||||
});
|
||||
/*put("home", (e, a) -> {
|
||||
if (e instanceof MobEntityWithAi)
|
||||
{
|
||||
return ((MobEntityWithAi) e).has hasHome()?new BlockValue(null, e.getEntityWorld(), ((MobEntityWithAi) e).getHomePosition()):Value.FALSE;
|
||||
}
|
||||
return Value.NULL;
|
||||
});*/
|
||||
put("sneaking", (e, a) -> e.isSneaking()?Value.TRUE:Value.FALSE);
|
||||
put("sprinting", (e, a) -> e.isSprinting()?Value.TRUE:Value.FALSE);
|
||||
put("swimming", (e, a) -> e.isSwimming()?Value.TRUE:Value.FALSE);
|
||||
/*put("jumping", (e, a) -> {
|
||||
if (e instanceof LivingEntity)
|
||||
{
|
||||
return ((LivingEntity) e).getJumping()?Value.TRUE:Value.FALSE;
|
||||
}
|
||||
return Value.NULL;
|
||||
});*/ //needs mixing
|
||||
put("gamemode", (e, a) -> {
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
{
|
||||
return new StringValue(((ServerPlayerEntity) e).interactionManager.getGameMode().getName());
|
||||
}
|
||||
return Value.NULL;
|
||||
});
|
||||
put("gamemode_id", (e, a) -> {
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
{
|
||||
return new NumericValue(((ServerPlayerEntity) e).interactionManager.getGameMode().getId());
|
||||
}
|
||||
return Value.NULL;
|
||||
});
|
||||
//spectating_entity
|
||||
// isGlowing
|
||||
put("effect", (e, a) ->
|
||||
{
|
||||
if (!(e instanceof LivingEntity))
|
||||
{
|
||||
return Value.NULL;
|
||||
}
|
||||
if (a == null)
|
||||
{
|
||||
List<Value> effects = new ArrayList<>();
|
||||
for (StatusEffectInstance p : ((LivingEntity) e).getStatusEffects())
|
||||
{
|
||||
effects.add(ListValue.of(
|
||||
new StringValue(p.getTranslationKey().replaceFirst("^effect\\.minecraft\\.", "")),
|
||||
new NumericValue(p.getAmplifier()),
|
||||
new NumericValue(p.getDuration())
|
||||
));
|
||||
}
|
||||
return ListValue.wrap(effects);
|
||||
}
|
||||
String effectName = a.getString();
|
||||
StatusEffect potion = Registry.STATUS_EFFECT.get(new Identifier(effectName));
|
||||
if (potion == null)
|
||||
throw new InternalExpressionException("No such an effect: "+effectName);
|
||||
if (!((LivingEntity) e).hasStatusEffect(potion))
|
||||
return Value.NULL;
|
||||
StatusEffectInstance pe = ((LivingEntity) e).getStatusEffect(potion);
|
||||
return ListValue.of( new NumericValue(pe.getAmplifier()), new NumericValue(pe.getDuration()) );
|
||||
});
|
||||
put("health", (e, a) ->
|
||||
{
|
||||
if (e instanceof LivingEntity)
|
||||
{
|
||||
return new NumericValue(((LivingEntity) e).getHealth());
|
||||
}
|
||||
//if (e instanceof ItemEntity)
|
||||
//{
|
||||
// e.h consider making item health public
|
||||
//}
|
||||
return Value.NULL;
|
||||
});
|
||||
put("holds", (e, a) -> {
|
||||
EquipmentSlot where = EquipmentSlot.MAINHAND;
|
||||
if (a != null)
|
||||
where = inventorySlots.get(a.getString());
|
||||
if (where == null)
|
||||
throw new InternalExpressionException("Unknown inventory slot: "+a.getString());
|
||||
if (e instanceof LivingEntity)
|
||||
{
|
||||
ItemStack itemstack = ((LivingEntity)e).getEquippedStack(where);
|
||||
if (!itemstack.isEmpty())
|
||||
{
|
||||
return ListValue.of(
|
||||
new StringValue(Registry.ITEM.getId(itemstack.getItem()).getPath()),
|
||||
new NumericValue(itemstack.getAmount()),
|
||||
new StringValue(itemstack.toTag(new CompoundTag()).toString())
|
||||
);
|
||||
}
|
||||
}
|
||||
return Value.NULL;
|
||||
|
||||
});
|
||||
|
||||
put("nbt",(e, a) -> {
|
||||
CompoundTag nbttagcompound = e.toTag((new CompoundTag()));
|
||||
if (a==null)
|
||||
return new StringValue(nbttagcompound.toString());
|
||||
NbtPathArgumentType.NbtPath path;
|
||||
try
|
||||
{
|
||||
path = NbtPathArgumentType.create().method_9362(new StringReader(a.getString()));
|
||||
}
|
||||
catch (CommandSyntaxException exc)
|
||||
{
|
||||
throw new InternalExpressionException("Incorrect path: "+a.getString());
|
||||
}
|
||||
String res = null;
|
||||
try
|
||||
{
|
||||
List<Tag> tags = path.get(nbttagcompound);
|
||||
if (tags.size()==0)
|
||||
return Value.NULL;
|
||||
if (tags.size()==1)
|
||||
return new StringValue(tags.get(0).toTextComponent().getString());
|
||||
return ListValue.wrap(tags.stream().map((t) -> new StringValue(t.toTextComponent().getString())).collect(Collectors.toList()));
|
||||
}
|
||||
catch (CommandSyntaxException ignored) { }
|
||||
return new StringValue(res);
|
||||
});
|
||||
}};
|
||||
private static <Req extends Entity> Req assertEntityArgType(Class<Req> klass, Value arg)
|
||||
{
|
||||
if (!(arg instanceof EntityValue))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
Entity e = ((EntityValue) arg).getEntity();
|
||||
if (!(klass.isAssignableFrom(e.getClass())))
|
||||
{
|
||||
return null;
|
||||
}
|
||||
return (Req)e;
|
||||
}
|
||||
|
||||
public void set(String what, Value toWhat)
|
||||
{
|
||||
if (!(featureModifiers.containsKey(what)))
|
||||
throw new InternalExpressionException("unknown action on entity: " + what);
|
||||
featureModifiers.get(what).accept(entity, toWhat);
|
||||
}
|
||||
|
||||
private static Map<String, BiConsumer<Entity, Value>> featureModifiers = new HashMap<String, BiConsumer<Entity, Value>>() {{
|
||||
put("remove", (entity, value) -> entity.remove());
|
||||
put("health", (e, v) -> { if (e instanceof LivingEntity) ((LivingEntity) e).setHealth((float) NumericValue.asNumber(v).getDouble()); });
|
||||
put("kill", (e, v) -> e.kill());
|
||||
put("pos", (e, v) ->
|
||||
{
|
||||
if (!(v instanceof ListValue))
|
||||
{
|
||||
throw new InternalExpressionException("expected a list of 3 parameters as second argument");
|
||||
}
|
||||
List<Value> coords = ((ListValue) v).getItems();
|
||||
e.x = NumericValue.asNumber(coords.get(0)).getDouble();
|
||||
e.y = NumericValue.asNumber(coords.get(1)).getDouble();
|
||||
e.z = NumericValue.asNumber(coords.get(2)).getDouble();
|
||||
e.setPosition(e.x, e.y, e.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
put("x", (e, v) ->
|
||||
{
|
||||
e.x = NumericValue.asNumber(v).getDouble();
|
||||
e.setPosition(e.x, e.y, e.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
put("y", (e, v) ->
|
||||
{
|
||||
e.y = NumericValue.asNumber(v).getDouble();
|
||||
e.setPosition(e.x, e.y, e.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
put("z", (e, v) ->
|
||||
{
|
||||
e.z = NumericValue.asNumber(v).getDouble();
|
||||
e.setPosition(e.x, e.y, e.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
put("pitch", (e, v) ->
|
||||
{
|
||||
e.pitch = (float) NumericValue.asNumber(v).getDouble();
|
||||
e.prevPitch = e.pitch;
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
put("yaw", (e, v) ->
|
||||
{
|
||||
e.yaw = (float) NumericValue.asNumber(v).getDouble();
|
||||
e.prevYaw = e.yaw;
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
//"look"
|
||||
//"turn"
|
||||
//"nod"
|
||||
|
||||
put("move", (e, v) ->
|
||||
{
|
||||
if (!(v instanceof ListValue))
|
||||
{
|
||||
throw new InternalExpressionException("expected a list of 3 parameters as second argument");
|
||||
}
|
||||
List<Value> coords = ((ListValue) v).getItems();
|
||||
e.x += NumericValue.asNumber(coords.get(0)).getDouble();
|
||||
e.y += NumericValue.asNumber(coords.get(1)).getDouble();
|
||||
e.z += NumericValue.asNumber(coords.get(2)).getDouble();
|
||||
e.setPosition(e.x, e.y, e.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.requestTeleport(e.y, e.y, e.z, e.yaw, e.pitch);
|
||||
});
|
||||
|
||||
put("motion", (e, v) ->
|
||||
{
|
||||
if (!(v instanceof ListValue))
|
||||
{
|
||||
throw new InternalExpressionException("expected a list of 3 parameters as second argument");
|
||||
}
|
||||
List<Value> coords = ((ListValue) v).getItems();
|
||||
e.setVelocity(
|
||||
NumericValue.asNumber(coords.get(0)).getDouble(),
|
||||
NumericValue.asNumber(coords.get(1)).getDouble(),
|
||||
NumericValue.asNumber(coords.get(2)).getDouble()
|
||||
);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(e));
|
||||
});
|
||||
put("motion_x", (e, v) ->
|
||||
{
|
||||
Vec3d velocity = e.getVelocity();
|
||||
e.setVelocity(NumericValue.asNumber(v).getDouble(), velocity.y, velocity.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(e));
|
||||
});
|
||||
put("motion_y", (e, v) ->
|
||||
{
|
||||
Vec3d velocity = e.getVelocity();
|
||||
e.setVelocity(velocity.x, NumericValue.asNumber(v).getDouble(), velocity.z);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(e));
|
||||
});
|
||||
put("motion_z", (e, v) ->
|
||||
{
|
||||
Vec3d velocity = e.getVelocity();
|
||||
e.setVelocity(velocity.x, velocity.y, NumericValue.asNumber(v).getDouble());
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(e));
|
||||
});
|
||||
|
||||
put("accelerate", (e, v) ->
|
||||
{
|
||||
if (!(v instanceof ListValue))
|
||||
{
|
||||
throw new InternalExpressionException("expected a list of 3 parameters as second argument");
|
||||
}
|
||||
List<Value> coords = ((ListValue) v).getItems();
|
||||
e.addVelocity(
|
||||
NumericValue.asNumber(coords.get(0)).getDouble(),
|
||||
NumericValue.asNumber(coords.get(1)).getDouble(),
|
||||
NumericValue.asNumber(coords.get(2)).getDouble()
|
||||
);
|
||||
if (e instanceof ServerPlayerEntity)
|
||||
((ServerPlayerEntity)e).networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(e));
|
||||
|
||||
});
|
||||
put("custom_name", (e, v) -> {
|
||||
String name = v.getString();
|
||||
if (name.isEmpty())
|
||||
e.setCustomName(null);
|
||||
e.setCustomName(new TextComponent(v.getString()));
|
||||
});
|
||||
put("dismount", (e, v) -> e.stopRiding() );
|
||||
put("mount", (e, v) -> {
|
||||
if (v instanceof EntityValue)
|
||||
{
|
||||
e.startRiding(((EntityValue) v).getEntity(),true);
|
||||
}
|
||||
});
|
||||
put("drop_passengers", (e, v) -> e.removeAllPassengers());
|
||||
put("mount_passengers", (e, v) -> {
|
||||
if (v==null)
|
||||
throw new InternalExpressionException("mount_passengers needs entities to ride");
|
||||
if (v instanceof EntityValue)
|
||||
((EntityValue) v).getEntity().startRiding(e);
|
||||
else if (v instanceof ListValue)
|
||||
for (Value element : ((ListValue) v).getItems())
|
||||
if (element instanceof EntityValue)
|
||||
((EntityValue) element).getEntity().startRiding(e);
|
||||
});
|
||||
put("tag", (e, v) -> {
|
||||
if (v==null)
|
||||
throw new InternalExpressionException("tag requires parameters");
|
||||
if (v instanceof ListValue)
|
||||
for (Value element : ((ListValue) v).getItems()) e.addScoreboardTag(element.getString());
|
||||
else
|
||||
e.addScoreboardTag(v.getString());
|
||||
});
|
||||
put("clear_tag", (e, v) -> {
|
||||
if (v==null)
|
||||
throw new InternalExpressionException("clear_tag requires parameters");
|
||||
if (v instanceof ListValue)
|
||||
for (Value element : ((ListValue) v).getItems()) e.removeScoreboardTag(element.getString());
|
||||
else
|
||||
e.removeScoreboardTag(v.getString());
|
||||
});
|
||||
//put("target", (e, v) -> {
|
||||
// // attacks indefinitely - might need to do it through tasks
|
||||
// if (e instanceof MobEntity)
|
||||
// {
|
||||
// LivingEntity elb = assertEntityArgType(LivingEntity.class, v);
|
||||
// ((MobEntity) e).setAttackTarget(elb);
|
||||
// }
|
||||
//});
|
||||
put("talk", (e, v) -> {
|
||||
// attacks indefinitely
|
||||
if (e instanceof MobEntity)
|
||||
{
|
||||
((MobEntity) e).playAmbientSound();
|
||||
}
|
||||
});
|
||||
/*
|
||||
put("home", (e, v) -> {
|
||||
if (!(e instanceof MobEntityWithAi))
|
||||
return;
|
||||
MobEntityWithAi ec = (MobEntityWithAi)e;
|
||||
if (v == null)
|
||||
throw new InternalExpressionException("home requires at least one position argument, and optional distance, or null to cancel");
|
||||
if (v instanceof NullValue)
|
||||
{
|
||||
ec.detachHome();
|
||||
ec.getAI(false).removeTask(ec.temporaryTasks.get("home"));
|
||||
ec.temporaryTasks.remove("home");
|
||||
return;
|
||||
}
|
||||
|
||||
BlockPos pos;
|
||||
int distance = 16;
|
||||
|
||||
if (v instanceof BlockValue)
|
||||
{
|
||||
pos = ((BlockValue) v).getPos();
|
||||
if (pos == null) throw new InternalExpressionException("block is not positioned in the world");
|
||||
}
|
||||
else if (v instanceof ListValue)
|
||||
{
|
||||
List<Value> lv = ((ListValue) v).getItems();
|
||||
if (lv.get(0) instanceof BlockValue)
|
||||
{
|
||||
pos = ((BlockValue) lv.get(0)).getPos();
|
||||
if (lv.size()>1)
|
||||
{
|
||||
distance = (int) NumericValue.asNumber(lv.get(1)).getLong();
|
||||
}
|
||||
}
|
||||
else if (lv.size()>=3)
|
||||
{
|
||||
pos = new BlockPos(NumericValue.asNumber(lv.get(0)).getLong(),
|
||||
NumericValue.asNumber(lv.get(1)).getLong(),
|
||||
NumericValue.asNumber(lv.get(2)).getLong());
|
||||
if (lv.size()>3)
|
||||
{
|
||||
distance = (int) NumericValue.asNumber(lv.get(4)).getLong();
|
||||
}
|
||||
}
|
||||
else throw new InternalExpressionException("home requires at least one position argument, and optional distance");
|
||||
|
||||
}
|
||||
else throw new InternalExpressionException("home requires at least one position argument, and optional distance");
|
||||
|
||||
ec.setHomePosAndDistance(pos, distance);
|
||||
if (!ec.temporaryTasks.containsKey("home"))
|
||||
{
|
||||
Goal task = new GoToWalkTargetGoal(ec, 1.0D);
|
||||
ec.temporaryTasks.put("home", task);
|
||||
ec.getAI(false).addTask(10, task);
|
||||
}
|
||||
});*/ //requires mixing
|
||||
|
||||
// gamemode
|
||||
// spectate
|
||||
// "fire"
|
||||
// "extinguish"
|
||||
// "silent"
|
||||
// "gravity"
|
||||
// "invulnerable"
|
||||
// "dimension"
|
||||
// "item"
|
||||
// "count",
|
||||
// "age",
|
||||
// "effect_"name
|
||||
// "hold"
|
||||
// "hold_offhand"
|
||||
// "jump"
|
||||
// "nbt" <-big one, for now use run('data merge entity ...
|
||||
}};
|
||||
}
|
||||
@@ -0,0 +1,48 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.ExpressionException;
|
||||
import carpet.script.value.Value;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class FunctionSignatureValue extends Value
|
||||
{
|
||||
private String identifier;
|
||||
private List<String> arguments;
|
||||
private List<String> globals;
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
throw new ExpressionException("Function "+identifier+" is not defined yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
throw new ExpressionException("Function "+identifier+" is not defined yet");
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
throw new ExpressionException("Function "+identifier+" is not defined yet");
|
||||
}
|
||||
public FunctionSignatureValue(String name, List<String> args, List<String> globals)
|
||||
{
|
||||
this.identifier = name;
|
||||
this.arguments = args;
|
||||
this.globals = globals;
|
||||
}
|
||||
public String getName()
|
||||
{
|
||||
return identifier;
|
||||
}
|
||||
public List<String> getArgs()
|
||||
{
|
||||
return arguments;
|
||||
}
|
||||
public List<String> getGlobals() {return globals;}
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.value.Value;
|
||||
|
||||
public class GlobalValue extends Value
|
||||
{
|
||||
public GlobalValue(Value variable)
|
||||
{
|
||||
variable.assertAssignable();
|
||||
this.boundVariable = variable.boundVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return boundVariable;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,103 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
|
||||
public abstract class LazyListValue extends ListValue implements Iterator<Value>
|
||||
{
|
||||
public static LazyListValue range(long from, long to, long step)
|
||||
{
|
||||
return new LazyListValue()
|
||||
{
|
||||
{
|
||||
if (step == 0)
|
||||
throw new InternalExpressionException("range will never end with zero step");
|
||||
this.current = from;
|
||||
this.limit = to;
|
||||
this.stepp = step;
|
||||
}
|
||||
private long current;
|
||||
private long limit;
|
||||
private long stepp;
|
||||
@Override
|
||||
public Value next()
|
||||
{
|
||||
Value val = new NumericValue(current);
|
||||
current += stepp;
|
||||
return val;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasNext()
|
||||
{
|
||||
return stepp > 0?(current < limit):(current > limit);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public LazyListValue()
|
||||
{
|
||||
super(Collections.emptyList());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return "[...]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return hasNext();
|
||||
}
|
||||
public abstract boolean hasNext();
|
||||
|
||||
public abstract Value next();
|
||||
|
||||
@Override
|
||||
public Iterator<Value> iterator() {return this;}
|
||||
|
||||
public List<Value> unroll()
|
||||
{
|
||||
List<Value> result = new ArrayList<>();
|
||||
this.forEachRemaining(result::add);
|
||||
return result;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long from, long to)
|
||||
{
|
||||
if (to < 0) to = Integer.MAX_VALUE;
|
||||
if (from < 0) from = 0;
|
||||
if (from > to)
|
||||
return ListValue.of();
|
||||
List<Value> result = new ArrayList<>();
|
||||
int i;
|
||||
for (i = 0; i < from; i++)
|
||||
{
|
||||
if (hasNext())
|
||||
next();
|
||||
else
|
||||
return ListValue.wrap(result);
|
||||
}
|
||||
for (i = (int)from; i < to; i++)
|
||||
{
|
||||
if (hasNext())
|
||||
result.add(next());
|
||||
else
|
||||
return ListValue.wrap(result);
|
||||
}
|
||||
return ListValue.wrap(result);
|
||||
}
|
||||
@Override
|
||||
public Value add(Value other)
|
||||
{
|
||||
throw new InternalExpressionException("Cannot add to iterators");
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,297 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collection;
|
||||
import java.util.Iterator;
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
public class ListValue extends Value
|
||||
{
|
||||
protected List<Value> items;
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return "["+items.stream().map(Value::getString).collect(Collectors.joining(", "))+"]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
if (items.size()<8)
|
||||
return "["+items.stream().map(Value::getPrettyString).collect(Collectors.joining(", "))+"]";
|
||||
return "["+items.get(0).getPrettyString()+", "+items.get(1).getPrettyString()+", ..., "+
|
||||
items.get(items.size()-2).getPrettyString()+", "+items.get(items.size()-1).getPrettyString()+"]";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
return !items.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
return new ListValue(items);
|
||||
}
|
||||
public ListValue(Collection<? extends Value> list)
|
||||
{
|
||||
items = new ArrayList<>();
|
||||
items.addAll(list);
|
||||
}
|
||||
public static ListValue wrap(List<Value> list)
|
||||
{
|
||||
ListValue created = new ListValue();
|
||||
created.items = list;
|
||||
return created;
|
||||
}
|
||||
public static ListValue of(Value ... list)
|
||||
{
|
||||
return ListValue.wrap(Arrays.asList(list));
|
||||
}
|
||||
|
||||
private ListValue()
|
||||
{
|
||||
items = new ArrayList<>();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value other) {
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).add(other_list.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Cannot subtract two lists of uneven sizes");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
{
|
||||
output.items.add(v.add(other));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
public void append(Value v)
|
||||
{
|
||||
items.add(v);
|
||||
}
|
||||
public Value subtract(Value other)
|
||||
{
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).subtract(other_list.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Cannot subtract two lists of uneven sizes");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
{
|
||||
output.items.add(v.subtract(other));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
public void subtractFrom(Value v) // if I ever do -= then it wouod remove items
|
||||
{
|
||||
throw new UnsupportedOperationException(); // TODO
|
||||
}
|
||||
|
||||
|
||||
public Value multiply(Value other)
|
||||
{
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).multiply(other_list.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Cannot subtract two lists of uneven sizes");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
{
|
||||
output.items.add(v.multiply(other));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
public Value divide(Value other)
|
||||
{
|
||||
ListValue output = new ListValue();
|
||||
if (other instanceof ListValue)
|
||||
{
|
||||
List<Value> other_list = ((ListValue) other).items;
|
||||
if (other_list.size() == items.size())
|
||||
{
|
||||
for(int i = 0, size = items.size(); i < size; i++)
|
||||
{
|
||||
output.items.add(items.get(i).divide(other_list.get(i)));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw new InternalExpressionException("Cannot subtract two lists of uneven sizes");
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
for (Value v : items)
|
||||
{
|
||||
output.items.add(v.divide(other));
|
||||
}
|
||||
}
|
||||
return output;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
{
|
||||
if (o instanceof ListValue)
|
||||
{
|
||||
ListValue ol = (ListValue)o;
|
||||
int this_size = this.getItems().size();
|
||||
int o_size = ol.getItems().size();
|
||||
if (this_size != o_size)
|
||||
{
|
||||
return this_size - o_size;
|
||||
}
|
||||
if (this_size == 0)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
for (int i = 0; i < this_size; i++)
|
||||
{
|
||||
int res = this.items.get(i).compareTo(ol.items.get(i));
|
||||
if (res != 0)
|
||||
{
|
||||
return res;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
return super.compareTo(o);
|
||||
}
|
||||
|
||||
public List<Value> getItems()
|
||||
{
|
||||
return items;
|
||||
}
|
||||
|
||||
public Iterator<Value> iterator()
|
||||
{
|
||||
return items.iterator();
|
||||
}
|
||||
public void fatality()
|
||||
{
|
||||
}
|
||||
|
||||
public void extend(List<Value> subList)
|
||||
{
|
||||
for (Value v: subList)
|
||||
items.add(v);
|
||||
}
|
||||
|
||||
public void addAtIndex(int index, List<Value> subList)
|
||||
{
|
||||
int numitems = items.size();
|
||||
long range = abs(index)/numitems;
|
||||
index += (range+2)*numitems;
|
||||
index = index % numitems;
|
||||
for (Value v: subList)
|
||||
{
|
||||
if (index < numitems)
|
||||
{
|
||||
items.set(index, v);
|
||||
}
|
||||
else
|
||||
{
|
||||
items.add(v);
|
||||
}
|
||||
index++;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public static class ListConstructorValue extends ListValue
|
||||
{
|
||||
public ListConstructorValue(Collection<? extends Value> list)
|
||||
{
|
||||
super(list);
|
||||
}
|
||||
}
|
||||
public int length()
|
||||
{
|
||||
return items.size();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value in(Value value1)
|
||||
{
|
||||
for (int i = 0; i < items.size(); i++)
|
||||
{
|
||||
Value v = items.get(i);
|
||||
if (v.equals(value1))
|
||||
{
|
||||
return new NumericValue(i);
|
||||
}
|
||||
}
|
||||
return Value.NULL;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value slice(long from, long to)
|
||||
{
|
||||
List<Value> items = getItems();
|
||||
int size = items.size();
|
||||
if (to < 0 || to > size) to = size;
|
||||
if (from < 0 || from > size) from = size;
|
||||
if (from > to)
|
||||
return ListValue.of();
|
||||
return new ListValue(getItems().subList((int)from, (int) to));
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readNumber()
|
||||
{
|
||||
return (double)items.size();
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
@@ -0,0 +1,41 @@
|
||||
package carpet.script.value;
|
||||
|
||||
public class NullValue extends NumericValue // TODO check nonsingleton code
|
||||
{
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
return "null";
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
return new NullValue();
|
||||
}
|
||||
public NullValue() {super(0.0D);}
|
||||
|
||||
@Override
|
||||
public boolean equals(final Value o)
|
||||
{
|
||||
return o instanceof NullValue;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
{
|
||||
return o instanceof NullValue ? 0 : -1;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,170 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
import org.apache.commons.lang3.StringUtils;
|
||||
|
||||
import java.math.BigDecimal;
|
||||
|
||||
import static java.lang.Math.abs;
|
||||
|
||||
public class NumericValue extends Value
|
||||
{
|
||||
private Double value;
|
||||
final static double epsilon = 1024*Double.MIN_VALUE;
|
||||
|
||||
public static NumericValue asNumber(Value v1)
|
||||
{
|
||||
if (!(v1 instanceof NumericValue))
|
||||
throw new InternalExpressionException("Operand has to be of a numeric type");
|
||||
return ((NumericValue) v1);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public String getString()
|
||||
{
|
||||
try
|
||||
{
|
||||
return BigDecimal.valueOf(value).stripTrailingZeros().toPlainString();
|
||||
}
|
||||
catch (NumberFormatException exc)
|
||||
{
|
||||
throw new ArithmeticException("Incorrect number format for "+value);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getPrettyString()
|
||||
{
|
||||
if (getDouble() == (double)getLong())
|
||||
{
|
||||
return Long.toString(getLong());
|
||||
}
|
||||
else
|
||||
{
|
||||
return String.format("%.3f..", getDouble());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean()
|
||||
{
|
||||
return value != null && abs(value) > epsilon;
|
||||
}
|
||||
public double getDouble()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
public long getLong()
|
||||
{
|
||||
return (long)(value+epsilon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value add(Value v)
|
||||
{ // TODO test if definintn add(NumericVlaue) woud solve the casting
|
||||
if (v instanceof NumericValue)
|
||||
{
|
||||
return new NumericValue(getDouble() + ((NumericValue) v).getDouble() );
|
||||
}
|
||||
return super.add(v);
|
||||
}
|
||||
public Value subtract(Value v) { // TODO test if definintn add(NumericVlaue) woud solve the casting
|
||||
if (v instanceof NumericValue)
|
||||
{
|
||||
return new NumericValue(getDouble() - (((NumericValue) v).getDouble()));
|
||||
}
|
||||
return super.subtract(v);
|
||||
}
|
||||
public Value multiply(Value v)
|
||||
{
|
||||
if (v instanceof NumericValue)
|
||||
{
|
||||
return new NumericValue(getDouble() * ((NumericValue) v).getDouble() );
|
||||
}
|
||||
if (v instanceof ListValue)
|
||||
{
|
||||
return v.multiply(this);
|
||||
}
|
||||
return new StringValue(StringUtils.repeat(v.getString(), (int) getLong()));
|
||||
}
|
||||
public Value divide(Value v)
|
||||
{
|
||||
if (v instanceof NumericValue)
|
||||
{
|
||||
return new NumericValue(getDouble() / ((NumericValue) v).getDouble() );
|
||||
}
|
||||
return super.divide(v);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
return new NumericValue(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(Value o)
|
||||
{
|
||||
if (o instanceof NullValue)
|
||||
{
|
||||
return -o.compareTo(this);
|
||||
}
|
||||
if (o instanceof NumericValue)
|
||||
{
|
||||
return value.compareTo(((NumericValue) o).getDouble());
|
||||
}
|
||||
return super.compareTo(o);
|
||||
}
|
||||
@Override
|
||||
public boolean equals(Value o)
|
||||
{
|
||||
if (o instanceof NullValue)
|
||||
{
|
||||
return o.equals(this);
|
||||
}
|
||||
if (o instanceof NumericValue)
|
||||
{
|
||||
return !this.subtract(o).getBoolean();
|
||||
}
|
||||
return super.equals(o);
|
||||
}
|
||||
|
||||
public NumericValue(double value)
|
||||
{
|
||||
this.value = value;
|
||||
}
|
||||
public NumericValue(String value)
|
||||
{
|
||||
this(new BigDecimal(value).doubleValue());
|
||||
}
|
||||
public NumericValue(long value)
|
||||
{
|
||||
this.value = (double)value;
|
||||
}
|
||||
public NumericValue(boolean boolval)
|
||||
{
|
||||
this(boolval?1.0D:0.0D);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int length()
|
||||
{
|
||||
return Integer.toString(value.intValue()).length();
|
||||
}
|
||||
|
||||
@Override
|
||||
public double readNumber()
|
||||
{
|
||||
return value;
|
||||
}
|
||||
|
||||
@Override
|
||||
public long readInteger()
|
||||
{
|
||||
return getLong();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package carpet.script.value;
|
||||
|
||||
public class StringValue extends Value
|
||||
{
|
||||
private String str;
|
||||
|
||||
@Override
|
||||
public String getString() {
|
||||
return str;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBoolean() {
|
||||
return str != null && !str.isEmpty();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Value clone()
|
||||
{
|
||||
return new StringValue(str);
|
||||
}
|
||||
|
||||
public StringValue(String str)
|
||||
{
|
||||
this.str = str;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,175 @@
|
||||
package carpet.script.value;
|
||||
|
||||
import carpet.script.exception.InternalExpressionException;
|
||||
|
||||
import java.util.regex.Matcher;
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public abstract class Value implements Comparable<Value>, Cloneable
|
||||
{
|
||||
public static Value FALSE = new NumericValue(0);
|
||||
public static Value TRUE = new NumericValue(1);
|
||||
public static Value ZERO = FALSE;
|
||||
public static Value NULL = new NullValue();
|
||||
|
||||
public String boundVariable;
|
||||
|
||||
public static <T> T assertNotNull(T t)
|
||||
{
|
||||
if (t == null)
|
||||
throw new InternalExpressionException("Operand may not be null");
|
||||
return t;
|
||||
}
|
||||
|
||||
public static <T> void assertNotNull(T t1, T t2)
|
||||
{
|
||||
if (t1 == null)
|
||||
throw new InternalExpressionException("First operand may not be null");
|
||||
if (t2 == null)
|
||||
throw new InternalExpressionException("Second operand may not be null");
|
||||
}
|
||||
|
||||
public boolean isBound()
|
||||
{
|
||||
return boundVariable != null;
|
||||
}
|
||||
public String getVariable()
|
||||
{
|
||||
return boundVariable;
|
||||
}
|
||||
public Value reboundedTo(String var)
|
||||
{
|
||||
Value copy = null;
|
||||
try
|
||||
{
|
||||
copy = (Value)clone();
|
||||
}
|
||||
catch (CloneNotSupportedException e)
|
||||
{
|
||||
// should not happen
|
||||
e.printStackTrace();
|
||||
}
|
||||
copy.boundVariable = var;
|
||||
return copy;
|
||||
}
|
||||
public Value bindTo(String var)
|
||||
{
|
||||
this.boundVariable = var;
|
||||
return this;
|
||||
}
|
||||
|
||||
public abstract String getString();
|
||||
|
||||
public String getPrettyString()
|
||||
{
|
||||
return getString();
|
||||
}
|
||||
|
||||
|
||||
public abstract boolean getBoolean();
|
||||
|
||||
public Value add(Value o) {
|
||||
String lstr = this.getString();
|
||||
if (lstr == null) // null
|
||||
return new StringValue(o.getString());
|
||||
String rstr = o.getString();
|
||||
if (rstr == null)
|
||||
{
|
||||
return new StringValue(lstr);
|
||||
}
|
||||
return new StringValue(lstr+rstr);
|
||||
}
|
||||
public Value subtract(Value v)
|
||||
{
|
||||
return new StringValue(this.getString().replace(v.getString(),""));
|
||||
}
|
||||
public Value multiply(Value v)
|
||||
{
|
||||
if (v instanceof NumericValue || v instanceof ListValue)
|
||||
{
|
||||
return v.multiply(this);
|
||||
}
|
||||
return new StringValue(this.getString()+"."+v.getString());
|
||||
}
|
||||
public Value divide(Value v)
|
||||
{
|
||||
if (v instanceof NumericValue)
|
||||
{
|
||||
String lstr = getString();
|
||||
return new StringValue(lstr.substring(0, (int)(lstr.length()/ ((NumericValue) v).getDouble())));
|
||||
}
|
||||
return new StringValue(getString()+"/"+v.getString());
|
||||
}
|
||||
|
||||
public Value()
|
||||
{
|
||||
this.boundVariable = null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int compareTo(final Value o)
|
||||
{
|
||||
if (o instanceof NumericValue || o instanceof ListValue)
|
||||
{
|
||||
return -o.compareTo(this);
|
||||
}
|
||||
return getString().compareTo(o.getString());
|
||||
}
|
||||
public boolean equals(final Value o)
|
||||
{
|
||||
return this.compareTo(o)==0;
|
||||
}
|
||||
|
||||
public void assertAssignable()
|
||||
{
|
||||
if (boundVariable == null || boundVariable.startsWith("_"))
|
||||
{
|
||||
if (boundVariable != null)
|
||||
{
|
||||
throw new InternalExpressionException(boundVariable+ " cannot be assigned a new value");
|
||||
}
|
||||
throw new InternalExpressionException(getString()+ " is not a variable");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
public Value in(Value value1)
|
||||
{
|
||||
final Pattern p = Pattern.compile(value1.getString());
|
||||
final Matcher m = p.matcher(this.getString());
|
||||
return m.find()?new StringValue(m.group()):Value.NULL;
|
||||
}
|
||||
public int length()
|
||||
{
|
||||
return getString().length();
|
||||
}
|
||||
|
||||
public Value slice(long from, long to)
|
||||
{
|
||||
String value = this.getString();
|
||||
int size = value.length();
|
||||
if (to > size) to = -1;
|
||||
if (from < 0) from = 0;
|
||||
if (from > size) from = size;
|
||||
if (to>=0)
|
||||
return new StringValue(value.substring((int)from, (int)to));
|
||||
return new StringValue(value.substring((int)from));
|
||||
}
|
||||
public double readNumber()
|
||||
{
|
||||
String s = getString();
|
||||
try
|
||||
{
|
||||
return Double.valueOf(s);
|
||||
}
|
||||
catch (NumberFormatException e)
|
||||
{
|
||||
return Double.NaN;
|
||||
}
|
||||
}
|
||||
|
||||
public long readInteger()
|
||||
{
|
||||
return (long)readNumber();
|
||||
}
|
||||
}
|
||||
@@ -170,7 +170,7 @@ public class BlockInfo
|
||||
//lst.add(Messenger.s(String.format(" - Full block: %s", block.isShapeFullCube()))); // isFullCube() )));
|
||||
lst.add(Messenger.s(String.format(" - Normal cube: %s", state.isSimpleFullBlock(world, pos)))); //isNormalCube())));
|
||||
lst.add(Messenger.s(String.format(" - Is liquid: %s", material.isLiquid())));
|
||||
lst.add(Messenger.s(String.format(" - Is solid: %s", material.isSolid())));
|
||||
lst.add(Messenger.s(String.format(" - Is solid: %s", state.isFullBoundsCubeForCulling())));
|
||||
lst.add(Messenger.s(""));
|
||||
lst.add(Messenger.s(String.format(" - Light in: %d, above: %d", world.getLightLevel(pos), world.getLightLevel(pos.up()))));
|
||||
lst.add(Messenger.s(String.format(" - Brightness in: %.2f, above: %.2f", world.getBrightness(pos), world.getBrightness(pos.up()))));
|
||||
|
||||
@@ -6,6 +6,7 @@
|
||||
"CommandManagerMixin",
|
||||
"MinecraftServer_coreMixin",
|
||||
"MinecraftServer_tickspeedMixin",
|
||||
"MinecraftServer_scarpetMixin",
|
||||
"PlayerListHeaderS2CPacketMixin",
|
||||
"WeightedPickerEntryMixin",
|
||||
"ExperienceOrbEntityMixin",
|
||||
|
||||
Reference in new issue
Block a user