Separate ScriptHost from CarpetScriptHost
This commit is contained in:
1 parent
bd61340e46
commit
9e529fe967
5 files changed
+290
-256
No files matched your search
@@ -1,6 +1,7 @@
|
|||||||
package carpet.commands;
|
package carpet.commands;
|
||||||
|
|
||||||
import carpet.CarpetServer;
|
import carpet.CarpetServer;
|
||||||
|
import carpet.script.CarpetScriptHost;
|
||||||
import carpet.settings.CarpetSettings;
|
import carpet.settings.CarpetSettings;
|
||||||
import carpet.script.CarpetEventServer;
|
import carpet.script.CarpetEventServer;
|
||||||
import carpet.script.CarpetExpression;
|
import carpet.script.CarpetExpression;
|
||||||
@@ -273,12 +274,12 @@ public class ScriptCommand
|
|||||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.modules.keySet(), bb)).
|
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))));
|
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)
|
private static CarpetScriptHost getHost(CommandContext<ServerCommandSource> context)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
String name = StringArgumentType.getString(context, "app").toLowerCase(Locale.ROOT);
|
String name = StringArgumentType.getString(context, "app").toLowerCase(Locale.ROOT);
|
||||||
ScriptHost parentHost = CarpetServer.scriptServer.modules.getOrDefault(name, CarpetServer.scriptServer.globalHost);
|
CarpetScriptHost parentHost = CarpetServer.scriptServer.modules.getOrDefault(name, CarpetServer.scriptServer.globalHost);
|
||||||
return parentHost.retrieveForExecution(context.getSource());
|
return parentHost.retrieveForExecution(context.getSource());
|
||||||
}
|
}
|
||||||
catch (IllegalArgumentException ignored)
|
catch (IllegalArgumentException ignored)
|
||||||
@@ -370,7 +371,7 @@ public class ScriptCommand
|
|||||||
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args)
|
private static int invoke(CommandContext<ServerCommandSource> context, String call, BlockPos pos1, BlockPos pos2, String args)
|
||||||
{
|
{
|
||||||
ServerCommandSource source = context.getSource();
|
ServerCommandSource source = context.getSource();
|
||||||
ScriptHost host = getHost(context);
|
CarpetScriptHost host = getHost(context);
|
||||||
if (call.startsWith("__"))
|
if (call.startsWith("__"))
|
||||||
{
|
{
|
||||||
Messenger.m(source, "r Hidden functions are only callable in scripts");
|
Messenger.m(source, "r Hidden functions are only callable in scripts");
|
||||||
|
|||||||
@@ -3048,7 +3048,7 @@ public class CarpetExpression
|
|||||||
throw new InternalExpressionException("Cannot use "+file+" as resource name - must have some letters and numbers");
|
throw new InternalExpressionException("Cannot use "+file+" as resource name - must have some letters and numbers");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Tag state = ((CarpetContext)c).host.getGlobalState(file);
|
Tag state = ((CarpetScriptHost)((CarpetContext)c).host).getGlobalState(file);
|
||||||
if (state == null)
|
if (state == null)
|
||||||
return (cc, tt) -> Value.NULL;
|
return (cc, tt) -> Value.NULL;
|
||||||
Value retVal = new NBTSerializableValue(state);
|
Value retVal = new NBTSerializableValue(state);
|
||||||
@@ -3074,7 +3074,7 @@ public class CarpetExpression
|
|||||||
? (NBTSerializableValue) val
|
? (NBTSerializableValue) val
|
||||||
: new NBTSerializableValue(val.getString());
|
: new NBTSerializableValue(val.getString());
|
||||||
Tag tag = tagValue.getTag();
|
Tag tag = tagValue.getTag();
|
||||||
((CarpetContext)c).host.setGlobalState(tag, file);
|
((CarpetScriptHost)((CarpetContext)c).host).setGlobalState(tag, file);
|
||||||
return (cc, tt) -> Value.NULL;
|
return (cc, tt) -> Value.NULL;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,267 @@
|
|||||||
|
package carpet.script;
|
||||||
|
|
||||||
|
import carpet.CarpetServer;
|
||||||
|
import carpet.script.bundled.ModuleInterface;
|
||||||
|
import carpet.script.exception.ExpressionException;
|
||||||
|
import carpet.script.exception.InvalidCallbackException;
|
||||||
|
import carpet.script.value.FunctionValue;
|
||||||
|
import carpet.script.value.NumericValue;
|
||||||
|
import carpet.script.value.StringValue;
|
||||||
|
import carpet.script.value.Value;
|
||||||
|
import carpet.settings.CarpetSettings;
|
||||||
|
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||||
|
import net.minecraft.entity.Entity;
|
||||||
|
import net.minecraft.entity.EntityType;
|
||||||
|
import net.minecraft.nbt.Tag;
|
||||||
|
import net.minecraft.server.command.ServerCommandSource;
|
||||||
|
import net.minecraft.server.network.ServerPlayerEntity;
|
||||||
|
import net.minecraft.server.world.ServerWorld;
|
||||||
|
import net.minecraft.util.math.BlockPos;
|
||||||
|
|
||||||
|
import java.math.BigInteger;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Locale;
|
||||||
|
|
||||||
|
import static java.lang.Math.max;
|
||||||
|
|
||||||
|
public class CarpetScriptHost extends ScriptHost
|
||||||
|
{
|
||||||
|
private CarpetScriptServer scriptServer;
|
||||||
|
|
||||||
|
private Tag globalState;
|
||||||
|
private int saveTimeout;
|
||||||
|
|
||||||
|
CarpetScriptHost(CarpetScriptServer server, String name, ModuleInterface code, boolean perUser, ScriptHost parent)
|
||||||
|
{
|
||||||
|
super(name, code, perUser, parent);
|
||||||
|
this.saveTimeout = 0;
|
||||||
|
this.scriptServer = server;
|
||||||
|
if (parent == null && name != null)
|
||||||
|
globalState = loadState();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected ScriptHost duplicate()
|
||||||
|
{
|
||||||
|
return new CarpetScriptHost(scriptServer, this.getName(), myCode, false, this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void addUserDefinedFunction(String funName, FunctionValue function)
|
||||||
|
{
|
||||||
|
super.addUserDefinedFunction(funName, function);
|
||||||
|
// mcarpet
|
||||||
|
if (funName.startsWith("__on_"))
|
||||||
|
{
|
||||||
|
// this is nasty, we have the host and function, yet we add it via names, but hey - works for now
|
||||||
|
String event = funName.replaceFirst("__on_","");
|
||||||
|
if (CarpetEventServer.Event.byName.containsKey(event))
|
||||||
|
scriptServer.events.addEventDirectly(event, this, function);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public CarpetScriptHost retrieveForExecution(ServerCommandSource source)
|
||||||
|
{
|
||||||
|
if (!perUser)
|
||||||
|
return this;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
ServerPlayerEntity player = source.getPlayer();
|
||||||
|
return (CarpetScriptHost) retrieveForExecution(player.getName().getString());
|
||||||
|
}
|
||||||
|
catch (CommandSyntaxException e)
|
||||||
|
{
|
||||||
|
return (CarpetScriptHost) retrieveForExecution((String)null);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public String call(ServerCommandSource source, String call, List<Integer> coords, String arg)
|
||||||
|
{
|
||||||
|
if (CarpetServer.scriptServer.stopAll)
|
||||||
|
return "SCARPET PAUSED";
|
||||||
|
FunctionValue function = globalFunctions.get(call);
|
||||||
|
if (function == 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:
|
||||||
|
case MARKER:
|
||||||
|
return "Fail: "+tok.surface+" is not allowed in invoke";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
List<String> args = function.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(
|
||||||
|
() -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv),
|
||||||
|
context,
|
||||||
|
Context.VOID
|
||||||
|
).getString();
|
||||||
|
}
|
||||||
|
catch (ExpressionException e)
|
||||||
|
{
|
||||||
|
return e.getMessage();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Value callUDF(BlockPos pos, ServerCommandSource source, FunctionValue fun, List<LazyValue> argv) throws InvalidCallbackException
|
||||||
|
{
|
||||||
|
if (CarpetServer.scriptServer.stopAll)
|
||||||
|
return Value.NULL;
|
||||||
|
if (argv.size() != fun.getArguments().size())
|
||||||
|
{
|
||||||
|
throw new InvalidCallbackException();
|
||||||
|
}
|
||||||
|
try
|
||||||
|
{
|
||||||
|
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
|
||||||
|
Context context = new CarpetContext(this, source, pos);
|
||||||
|
return Expression.evalValue(
|
||||||
|
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
|
||||||
|
context,
|
||||||
|
Context.VOID);
|
||||||
|
}
|
||||||
|
catch (ExpressionException e)
|
||||||
|
{
|
||||||
|
CarpetSettings.LOG.error("Callback failed: "+e.getMessage());
|
||||||
|
}
|
||||||
|
return Value.NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClose()
|
||||||
|
{
|
||||||
|
super.onClose();
|
||||||
|
if (this.saveTimeout > 0)
|
||||||
|
dumpState();
|
||||||
|
String markerName = ExpressionInspector.MARKER_STRING+"_"+((getName()==null)?"":getName());
|
||||||
|
for (ServerWorld world : CarpetServer.minecraft_server.getWorlds())
|
||||||
|
{
|
||||||
|
for (Entity e : world.getEntities(EntityType.ARMOR_STAND, (as) -> as.getScoreboardTags().contains(markerName)))
|
||||||
|
{
|
||||||
|
e.remove();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void dumpState()
|
||||||
|
{
|
||||||
|
myCode.saveData(null, globalState);
|
||||||
|
}
|
||||||
|
|
||||||
|
private Tag loadState()
|
||||||
|
{
|
||||||
|
return myCode.getData(null);
|
||||||
|
}
|
||||||
|
|
||||||
|
public Tag getGlobalState(String file)
|
||||||
|
{
|
||||||
|
if (getName() == null || myCode.isInternal()) return null;
|
||||||
|
if (file != null)
|
||||||
|
myCode.getData(file);
|
||||||
|
if (parent == null)
|
||||||
|
return globalState;
|
||||||
|
return ((CarpetScriptHost)parent).globalState;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setGlobalState(Tag tag, String file)
|
||||||
|
{
|
||||||
|
if (getName() == null || myCode.isInternal()) return;
|
||||||
|
|
||||||
|
if (file!= null)
|
||||||
|
{
|
||||||
|
myCode.saveData(file, tag);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
CarpetScriptHost responsibleHost = (parent != null)?(CarpetScriptHost) parent:this;
|
||||||
|
responsibleHost.globalState = tag;
|
||||||
|
if (responsibleHost.saveTimeout == 0)
|
||||||
|
{
|
||||||
|
responsibleHost.dumpState();
|
||||||
|
responsibleHost.saveTimeout = 200;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick()
|
||||||
|
{
|
||||||
|
if (this.saveTimeout > 0)
|
||||||
|
{
|
||||||
|
this.saveTimeout --;
|
||||||
|
if (this.saveTimeout == 0)
|
||||||
|
{
|
||||||
|
dumpState();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@@ -36,8 +36,8 @@ import static net.minecraft.server.command.CommandManager.literal;
|
|||||||
public class CarpetScriptServer
|
public class CarpetScriptServer
|
||||||
{
|
{
|
||||||
//make static for now, but will change that later:
|
//make static for now, but will change that later:
|
||||||
public ScriptHost globalHost;
|
public CarpetScriptHost globalHost;
|
||||||
public Map<String, ScriptHost> modules;
|
public Map<String, CarpetScriptHost> modules;
|
||||||
long tickStart;
|
long tickStart;
|
||||||
public boolean stopAll;
|
public boolean stopAll;
|
||||||
Set<String> holyMoly;
|
Set<String> holyMoly;
|
||||||
@@ -129,9 +129,9 @@ public class CarpetScriptServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
private ScriptHost createMinecraftScriptHost(String name, ModuleInterface module, boolean perPlayer, ServerCommandSource source)
|
private CarpetScriptHost createMinecraftScriptHost(String name, ModuleInterface module, boolean perPlayer, ServerCommandSource source)
|
||||||
{
|
{
|
||||||
ScriptHost host = new ScriptHost(this, name, module, perPlayer, null );
|
CarpetScriptHost host = new CarpetScriptHost(this, name, module, perPlayer, null );
|
||||||
host.globalVariables.put("_x", (c, t) -> Value.ZERO);
|
host.globalVariables.put("_x", (c, t) -> Value.ZERO);
|
||||||
host.globalVariables.put("_y", (c, t) -> Value.ZERO);
|
host.globalVariables.put("_y", (c, t) -> Value.ZERO);
|
||||||
host.globalVariables.put("_z", (c, t) -> Value.ZERO);
|
host.globalVariables.put("_z", (c, t) -> Value.ZERO);
|
||||||
@@ -166,7 +166,7 @@ public class CarpetScriptServer
|
|||||||
//TODO add per player modules to support player actions better on a server
|
//TODO add per player modules to support player actions better on a server
|
||||||
name = name.toLowerCase(Locale.ROOT);
|
name = name.toLowerCase(Locale.ROOT);
|
||||||
ModuleInterface module = getModule(name);
|
ModuleInterface module = getModule(name);
|
||||||
ScriptHost newHost = createMinecraftScriptHost(name, module, perPlayer, source);
|
CarpetScriptHost newHost = createMinecraftScriptHost(name, module, perPlayer, source);
|
||||||
if (newHost == null)
|
if (newHost == null)
|
||||||
{
|
{
|
||||||
Messenger.m(source, "r Failed to add "+name+" app");
|
Messenger.m(source, "r Failed to add "+name+" app");
|
||||||
@@ -200,7 +200,7 @@ public class CarpetScriptServer
|
|||||||
|
|
||||||
private boolean addConfig(ServerCommandSource source, String hostName)
|
private boolean addConfig(ServerCommandSource source, String hostName)
|
||||||
{
|
{
|
||||||
ScriptHost host = modules.get(hostName);
|
CarpetScriptHost host = modules.get(hostName);
|
||||||
if (host == null || !host.globalFunctions.containsKey("__config"))
|
if (host == null || !host.globalFunctions.containsKey("__config"))
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@@ -374,7 +374,7 @@ public class CarpetScriptServer
|
|||||||
|
|
||||||
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, FunctionValue udf, List<LazyValue> argv)
|
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, FunctionValue udf, List<LazyValue> argv)
|
||||||
{
|
{
|
||||||
ScriptHost host = globalHost;
|
CarpetScriptHost host = globalHost;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (hostname != null)
|
if (hostname != null)
|
||||||
@@ -391,7 +391,7 @@ public class CarpetScriptServer
|
|||||||
public void tick()
|
public void tick()
|
||||||
{
|
{
|
||||||
events.tick();
|
events.tick();
|
||||||
for (ScriptHost host : modules.values())
|
for (CarpetScriptHost host : modules.values())
|
||||||
{
|
{
|
||||||
host.tick();
|
host.tick();
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,55 +1,30 @@
|
|||||||
package carpet.script;
|
package carpet.script;
|
||||||
|
|
||||||
import carpet.CarpetServer;
|
|
||||||
import carpet.script.bundled.ModuleInterface;
|
import carpet.script.bundled.ModuleInterface;
|
||||||
import carpet.script.value.FunctionValue;
|
import carpet.script.value.FunctionValue;
|
||||||
import carpet.settings.CarpetSettings;
|
|
||||||
import carpet.script.exception.ExpressionException;
|
|
||||||
import carpet.script.exception.InvalidCallbackException;
|
|
||||||
import carpet.script.value.NumericValue;
|
|
||||||
import carpet.script.value.StringValue;
|
|
||||||
import carpet.script.value.Value;
|
import carpet.script.value.Value;
|
||||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
|
||||||
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap;
|
||||||
import net.minecraft.entity.Entity;
|
|
||||||
import net.minecraft.entity.EntityType;
|
|
||||||
import net.minecraft.nbt.Tag;
|
|
||||||
import net.minecraft.server.command.ServerCommandSource;
|
|
||||||
import net.minecraft.server.network.ServerPlayerEntity;
|
|
||||||
import net.minecraft.server.world.ServerWorld;
|
|
||||||
import net.minecraft.util.math.BlockPos;
|
|
||||||
|
|
||||||
import java.math.BigInteger;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Locale;
|
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.stream.Collectors;
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import static java.lang.Math.max;
|
|
||||||
|
|
||||||
public class ScriptHost
|
public class ScriptHost
|
||||||
{
|
{
|
||||||
private final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
|
private final Map<String, ScriptHost> userHosts = new Object2ObjectOpenHashMap<>();
|
||||||
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
|
public Map<String, FunctionValue> globalFunctions = new Object2ObjectOpenHashMap<>();
|
||||||
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
|
public Map<String, LazyValue> globalVariables = new Object2ObjectOpenHashMap<>();
|
||||||
|
|
||||||
private Tag globalState;
|
protected ScriptHost parent;
|
||||||
private int saveTimeout;
|
protected boolean perUser;
|
||||||
|
|
||||||
private ScriptHost parent;
|
|
||||||
|
|
||||||
private String name;
|
private String name;
|
||||||
public String getName() {return name;}
|
public String getName() {return name;}
|
||||||
|
|
||||||
private final ModuleInterface myCode;
|
protected final ModuleInterface myCode;
|
||||||
private boolean perUser;
|
|
||||||
|
|
||||||
private CarpetScriptServer scriptServer;
|
ScriptHost(String name, ModuleInterface code, boolean perUser, ScriptHost parent)
|
||||||
|
|
||||||
ScriptHost(CarpetScriptServer server, String name, ModuleInterface code, boolean perUser, ScriptHost parent)
|
|
||||||
{
|
{
|
||||||
this.saveTimeout = 0;
|
|
||||||
this.parent = parent;
|
this.parent = parent;
|
||||||
this.name = name;
|
this.name = name;
|
||||||
this.myCode = code;
|
this.myCode = code;
|
||||||
@@ -64,55 +39,30 @@ public class ScriptHost
|
|||||||
globalVariables.put("_", (c, t) -> Value.ZERO);
|
globalVariables.put("_", (c, t) -> Value.ZERO);
|
||||||
globalVariables.put("_i", (c, t) -> Value.ZERO);
|
globalVariables.put("_i", (c, t) -> Value.ZERO);
|
||||||
globalVariables.put("_a", (c, t) -> Value.ZERO);
|
globalVariables.put("_a", (c, t) -> Value.ZERO);
|
||||||
|
|
||||||
if (parent == null && name != null)
|
|
||||||
globalState = loadState();
|
|
||||||
|
|
||||||
this.scriptServer = server;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public void addUserDefinedFunction(String funName, FunctionValue function)
|
public void addUserDefinedFunction(String funName, FunctionValue function)
|
||||||
{
|
{
|
||||||
// generic
|
|
||||||
globalFunctions.put(funName, function);
|
globalFunctions.put(funName, function);
|
||||||
// mcarpet
|
|
||||||
if (funName.startsWith("__on_"))
|
|
||||||
{
|
|
||||||
// this is nasty, we have the host and function, yet we add it via names, but hey - works for now
|
|
||||||
String event = funName.replaceFirst("__on_","");
|
|
||||||
if (CarpetEventServer.Event.byName.containsKey(event))
|
|
||||||
scriptServer.events.addEventDirectly(event, this, function);
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private ScriptHost retrieveForExecution(String /*Nullable*/ user)
|
public ScriptHost retrieveForExecution(String /*Nullable*/ user)
|
||||||
{
|
{
|
||||||
if (!perUser)
|
if (!perUser)
|
||||||
return this;
|
return this;
|
||||||
ScriptHost userHost = userHosts.get(user);
|
ScriptHost userHost = userHosts.get(user);
|
||||||
if (userHost != null)
|
if (userHost != null)
|
||||||
return userHost;
|
return userHost;
|
||||||
userHost = new ScriptHost(this.scriptServer, this.name, myCode, false, this);
|
userHost = this.duplicate();
|
||||||
userHost.globalVariables.putAll(this.globalVariables);
|
userHost.globalVariables.putAll(this.globalVariables);
|
||||||
userHost.globalFunctions.putAll(this.globalFunctions);
|
userHost.globalFunctions.putAll(this.globalFunctions);
|
||||||
userHosts.put(user, userHost);
|
userHosts.put(user, userHost);
|
||||||
return userHost;
|
return userHost;
|
||||||
}
|
}
|
||||||
|
|
||||||
public ScriptHost retrieveForExecution(ServerCommandSource source)
|
protected ScriptHost duplicate()
|
||||||
{
|
{
|
||||||
if (!perUser)
|
return new ScriptHost(this.name, myCode, false, this);
|
||||||
return this;
|
|
||||||
try
|
|
||||||
{
|
|
||||||
ServerPlayerEntity player = source.getPlayer();
|
|
||||||
return retrieveForExecution(player.getName().getString());
|
|
||||||
}
|
|
||||||
catch (CommandSyntaxException e)
|
|
||||||
{
|
|
||||||
return retrieveForExecution((String)null);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public Expression getExpressionForFunction(String name)
|
public Expression getExpressionForFunction(String name)
|
||||||
@@ -133,191 +83,7 @@ public class ScriptHost
|
|||||||
return globalFunctions.keySet().stream().filter((str) -> all || !str.startsWith("__")).collect(Collectors.toList());
|
return globalFunctions.keySet().stream().filter((str) -> all || !str.startsWith("__")).collect(Collectors.toList());
|
||||||
}
|
}
|
||||||
|
|
||||||
public String call(ServerCommandSource source, String call, List<Integer> coords, String arg)
|
public void onClose() { }
|
||||||
{
|
|
||||||
if (CarpetServer.scriptServer.stopAll)
|
|
||||||
return "SCARPET PAUSED";
|
|
||||||
FunctionValue function = globalFunctions.get(call);
|
|
||||||
if (function == 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:
|
|
||||||
case MARKER:
|
|
||||||
return "Fail: "+tok.surface+" is not allowed in invoke";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
List<String> args = function.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(
|
|
||||||
() -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv),
|
|
||||||
context,
|
|
||||||
Context.VOID
|
|
||||||
).getString();
|
|
||||||
}
|
|
||||||
catch (ExpressionException e)
|
|
||||||
{
|
|
||||||
return e.getMessage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public Value callUDF(BlockPos pos, ServerCommandSource source, FunctionValue fun, List<LazyValue> argv) throws InvalidCallbackException
|
|
||||||
{
|
|
||||||
if (CarpetServer.scriptServer.stopAll)
|
|
||||||
return Value.NULL;
|
|
||||||
if (argv.size() != fun.getArguments().size())
|
|
||||||
{
|
|
||||||
throw new InvalidCallbackException();
|
|
||||||
}
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
|
|
||||||
Context context = new CarpetContext(this, source, pos);
|
|
||||||
return Expression.evalValue(
|
|
||||||
() -> fun.lazyEval(context, Context.VOID, fun.getExpression(), fun.getToken(), argv),
|
|
||||||
context,
|
|
||||||
Context.VOID);
|
|
||||||
}
|
|
||||||
catch (ExpressionException e)
|
|
||||||
{
|
|
||||||
CarpetSettings.LOG.error("Callback failed: "+e.getMessage());
|
|
||||||
}
|
|
||||||
return Value.NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void dumpState()
|
|
||||||
{
|
|
||||||
myCode.saveData(null, globalState);
|
|
||||||
}
|
|
||||||
|
|
||||||
private Tag loadState()
|
|
||||||
{
|
|
||||||
return myCode.getData(null);
|
|
||||||
}
|
|
||||||
|
|
||||||
public Tag getGlobalState(String file)
|
|
||||||
{
|
|
||||||
if (name == null || myCode.isInternal()) return null;
|
|
||||||
if (file != null)
|
|
||||||
myCode.getData(file);
|
|
||||||
if (parent == null)
|
|
||||||
return globalState;
|
|
||||||
return parent.globalState;
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setGlobalState(Tag tag, String file)
|
|
||||||
{
|
|
||||||
if (name == null || myCode.isInternal()) return;
|
|
||||||
|
|
||||||
if (file!= null)
|
|
||||||
{
|
|
||||||
myCode.saveData(file, tag);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
ScriptHost responsibleHost = (parent != null)?parent:this;
|
|
||||||
responsibleHost.globalState = tag;
|
|
||||||
if (responsibleHost.saveTimeout == 0)
|
|
||||||
{
|
|
||||||
responsibleHost.dumpState();
|
|
||||||
responsibleHost.saveTimeout = 200;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void tick()
|
|
||||||
{
|
|
||||||
if (this.saveTimeout > 0)
|
|
||||||
{
|
|
||||||
this.saveTimeout --;
|
|
||||||
if (this.saveTimeout == 0)
|
|
||||||
{
|
|
||||||
dumpState();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void onClose()
|
|
||||||
{
|
|
||||||
if (this.saveTimeout > 0)
|
|
||||||
dumpState();
|
|
||||||
String markerName = ExpressionInspector.MARKER_STRING+"_"+((getName()==null)?"":getName());
|
|
||||||
for (ServerWorld world : CarpetServer.minecraft_server.getWorlds())
|
|
||||||
{
|
|
||||||
for (Entity e : world.getEntities(EntityType.ARMOR_STAND, (as) -> as.getScoreboardTags().contains(markerName)))
|
|
||||||
{
|
|
||||||
e.remove();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setPerPlayer(boolean isPerUser)
|
public void setPerPlayer(boolean isPerUser)
|
||||||
{
|
{
|
||||||
|
|||||||
Reference in new issue
Block a user