schedules and events from jarmod

This commit is contained in:
gnembon committed 2019-06-02 01:54:22 -03:00
1 parent 4ec6e0e03e
commit 730446b219
14 files changed
+825 -62

No files matched your search

@@ -0,0 +1,340 @@
package carpet.script;
import carpet.CarpetServer;
import carpet.script.value.BlockValue;
import carpet.script.value.EntityValue;
import carpet.script.value.ListValue;
import carpet.script.value.NumericValue;
import carpet.script.value.StringValue;
import net.minecraft.block.BlockState;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Hand;
import net.minecraft.util.hit.BlockHitResult;
import net.minecraft.util.math.BlockPos;
import net.minecraft.util.math.Direction;
import net.minecraft.util.math.Vec3d;
import net.minecraft.util.registry.Registry;
import net.minecraft.world.World;
import net.minecraft.world.dimension.DimensionType;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.function.Supplier;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CarpetEventServer
{
public static class Callback
{
public String host;
public String udf;
public Callback(String host, String udf)
{
this.host = host;
this.udf = udf;
}
@Override
public String toString()
{
return udf+((host==null)?"":"(from "+host+")");
}
}
public static class ScheduledCall extends Callback
{
public List<LazyValue> args;
public ServerCommandSource context_source;
public BlockPos context_origin;
public long dueTime;
public ScheduledCall(CarpetContext context, String udf, List<LazyValue> args, long dueTime)
{
super(context.host.getName(), udf);
this.args = args;
this.context_source = context.s;
this.context_origin = context.origin;
this.dueTime = dueTime;
}
public void execute()
{
CarpetServer.scriptServer.runas(context_origin, context_source, host, udf, args);
}
}
public static class CallbackList
{
public List<Callback> callList;
public int reqArgs;
public CallbackList(int reqArgs)
{
this.callList = new ArrayList<>();
this.reqArgs = reqArgs;
}
public void call(Supplier<List<LazyValue>> argumentSupplier, Supplier<ServerCommandSource> cmdSourceSupplier)
{
if (callList.size() > 0)
{
List<LazyValue> argv = argumentSupplier.get(); // empty for onTickDone
ServerCommandSource source = cmdSourceSupplier.get();
assert argv.size() == reqArgs;
callList.removeIf(call -> !CarpetServer.scriptServer.runas(source, call.host, call.udf, argv)); // this actually does the calls
}
}
public boolean addEventCall(String hostName, String funName)
{
ScriptHost host = CarpetServer.scriptServer.getHostByName(hostName);
if (host == null)
{
// impossible call to add
return false;
}
UserDefinedFunction udf = host.globalFunctions.get(funName);
if (udf == null || udf.getArguments().size() != reqArgs)
{
// call won't match arguments
return false;
}
//all clear
//remove duplicates
removeEventCall(hostName, funName);
callList.add(new Callback(hostName, funName));
return true;
}
public void removeEventCall(String hostName, String callName)
{
callList.removeIf((c)-> c.udf.equalsIgnoreCase(callName) && ( hostName == null || c.host.equalsIgnoreCase(hostName) ) );
}
}
public Map<String, CallbackList> eventHandlers = new HashMap<>();
public List<ScheduledCall> scheduledCalls = new LinkedList<>();
public void tick()
{
Iterator<ScheduledCall> eventIterator = scheduledCalls.iterator();
List<ScheduledCall> currentCalls = new ArrayList<>();
while(eventIterator.hasNext())
{
ScheduledCall call = eventIterator.next();
call.dueTime--;
if (call.dueTime <= 0)
{
currentCalls.add(call);
eventIterator.remove();
}
}
for (ScheduledCall call: currentCalls)
{
call.execute();
}
}
public void scheduleCall(CarpetContext context, String function, List<LazyValue> args, long due)
{
scheduledCalls.add(new ScheduledCall(context, function, args, due));
}
public CarpetEventServer()
{
eventHandlers.put("tick",new CallbackList(0));
eventHandlers.put("tick_nether",new CallbackList(0));
eventHandlers.put("tick_ender",new CallbackList(0));
eventHandlers.put("player_jumps",new CallbackList(1));
eventHandlers.put("player_deploys_elytra",new CallbackList(1));
eventHandlers.put("player_wakes_up",new CallbackList(1));
eventHandlers.put("player_rides",new CallbackList(5));
eventHandlers.put("player_uses_item",new CallbackList(3));
eventHandlers.put("player_clicks_block",new CallbackList(3));
eventHandlers.put("player_right_clicks_block",new CallbackList(6));
eventHandlers.put("player_breaks_block",new CallbackList(2));
eventHandlers.put("player_interacts_with_entity",new CallbackList(3));
eventHandlers.put("player_attacks_entity",new CallbackList(2));
eventHandlers.put("player_starts_sneaking",new CallbackList(1));
eventHandlers.put("player_stops_sneaking",new CallbackList(1));
eventHandlers.put("player_starts_sprinting",new CallbackList(1));
eventHandlers.put("player_stops_sprinting",new CallbackList(1));
}
public boolean addEvent(String event, String host, String funName)
{
if (!eventHandlers.containsKey(event))
{
return false;
}
return eventHandlers.get(event).addEventCall(host, funName);
}
public boolean removeEvent(String event, String funName)
{
if (!eventHandlers.containsKey(event))
return false;
Callback callback= decodeCallback(funName);
eventHandlers.get(event).removeEventCall(callback.host, callback.udf);
return true;
}
private Callback decodeCallback(String funName)
{
Pattern find = Pattern.compile("(\\w+)\\(from (\\w+)\\)");
Matcher matcher = find.matcher(funName);
if(matcher.matches())
{
return new Callback(matcher.group(2), matcher.group(1));
}
return new Callback(null, funName);
}
public void onTick()
{
eventHandlers.get("tick").call(Collections::emptyList, CarpetServer.minecraft_server::getCommandSource);
eventHandlers.get("tick_nether").call(Collections::emptyList, () ->
CarpetServer.minecraft_server.getCommandSource().withWorld(CarpetServer.minecraft_server.getWorld(DimensionType.THE_NETHER)));
eventHandlers.get("tick_ender").call(Collections::emptyList, () ->
CarpetServer.minecraft_server.getCommandSource().withWorld(CarpetServer.minecraft_server.getWorld(DimensionType.THE_END)));
}
public void onPlayerJumped(PlayerEntity player)
{
eventHandlers.get("player_jumps").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
public void onElytraDeploy(ServerPlayerEntity player)
{
eventHandlers.get("player_deploys_elytra").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
public void onOutOfBed(ServerPlayerEntity player)
{
eventHandlers.get("player_wakes_up").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
public void onMountControls(PlayerEntity player, float strafeSpeed, float forwardSpeed, boolean jumping, boolean sneaking)
{
eventHandlers.get("player_rides").call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new NumericValue(forwardSpeed)),
((c, t) -> new NumericValue(strafeSpeed)),
((c, t) -> new NumericValue(jumping)),
((c, t) -> new NumericValue(sneaking))
), player::getCommandSource);
}
public void onRightClick(ServerPlayerEntity player, Hand enumhand)
{
eventHandlers.get("player_uses_item").call( () ->
{
ItemStack itemstack = player.getStackInHand(enumhand);
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.of(
new StringValue(Registry.ITEM.getId(itemstack.getItem()).getPath()),
new NumericValue(itemstack.getAmount()),
new StringValue(itemstack.toTag(new CompoundTag()).toString())
)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand"))
);
}, player::getCommandSource);
}
public void onBlockClicked(ServerPlayerEntity player, BlockPos blockpos, Direction facing)
{
eventHandlers.get("player_clicks_block").call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new BlockValue(null, player.world, blockpos)),
((c, t) -> new StringValue(facing.getName()))
), player::getCommandSource);
}
public void onRightClickBlock(ServerPlayerEntity player, Hand enumhand, BlockHitResult hitRes)//ItemStack itemstack, Hand enumhand, BlockPos blockpos, Direction enumfacing, Vec3d vec3d)
{
eventHandlers.get("player_right_clicks_block").call( () ->
{
ItemStack itemstack = player.getStackInHand(enumhand);
BlockPos blockpos = hitRes.getBlockPos();
Direction enumfacing = hitRes.getSide();
Vec3d vec3d = hitRes.getPos().subtract(blockpos.getX(), blockpos.getY(), blockpos.getZ());
return Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> ListValue.of(
new StringValue(Registry.ITEM.getId(itemstack.getItem()).getPath()),
new NumericValue(itemstack.getAmount()),
new StringValue(itemstack.toTag(new CompoundTag()).toString())
)),
((c, t) -> new StringValue(enumhand == Hand.MAIN_HAND ? "mainhand" : "offhand")),
((c, t) -> new BlockValue(null, player.world, blockpos)),
((c, t) -> new StringValue(enumfacing.getName())),
((c, t) -> ListValue.of(
new NumericValue(vec3d.x),
new NumericValue(vec3d.y),
new NumericValue(vec3d.z)
))
);
}, player::getCommandSource);
}
public void onBlockBroken(PlayerEntity player, BlockPos pos, BlockState previousBS)
{
eventHandlers.get("player_breaks_block").call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new BlockValue(previousBS, player.getEntityWorld(), pos))
), player::getCommandSource);
}
public void onEntityInteracted(ServerPlayerEntity player, Entity entity, Hand enumhand)
{
eventHandlers.get("player_interacts_with_entity").call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new EntityValue(entity)),
((c, t) -> new StringValue(enumhand==Hand.MAIN_HAND?"mainhand":"offhand"))
), player::getCommandSource);
}
public void onEntityAttacked(ServerPlayerEntity player, Entity entity)
{
eventHandlers.get("player_attacks_entity").call( () -> Arrays.asList(
((c, t) -> new EntityValue(player)),
((c, t) -> new EntityValue(entity))
), player::getCommandSource);
}
public void onStartSneaking(PlayerEntity player)
{
eventHandlers.get("player_starts_sneaking").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
public void onStopSneaking(PlayerEntity player)
{
eventHandlers.get("player_stops_sneaking").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
public void onStartSprinting(PlayerEntity player)
{
eventHandlers.get("player_starts_sprinting").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
public void onStopSprinting(PlayerEntity player)
{
eventHandlers.get("player_stops_sprinting").call( () -> Arrays.asList(((c, t) -> new EntityValue(player))), player::getCommandSource);
}
}
+124 -34
View File
@@ -21,11 +21,16 @@ import com.mojang.brigadier.StringReader;
import com.mojang.brigadier.exceptions.CommandSyntaxException;
import net.minecraft.block.Block;
import net.minecraft.block.BlockState;
import net.minecraft.block.Blocks;
import net.minecraft.block.entity.BlockEntity;
import net.minecraft.enchantment.Enchantments;
import net.minecraft.entity.EntityType;
import net.minecraft.item.Items;
import net.minecraft.server.command.ServerCommandSource;
import net.minecraft.command.arguments.ParticleArgumentType;
import net.minecraft.entity.Entity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.client.network.packet.PlaySoundIdS2CPacket;
import net.minecraft.particle.ParticleEffect;
import net.minecraft.block.BlockPlacementEnvironment;
@@ -44,6 +49,8 @@ import net.minecraft.world.LightType;
import net.minecraft.world.World;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.world.Heightmap;
import net.minecraft.world.loot.context.LootContext;
import net.minecraft.world.loot.context.LootContextParameters;
import org.apache.commons.lang3.tuple.Pair;
import java.util.ArrayList;
@@ -302,6 +309,12 @@ public class CarpetExpression
* <p>Causes a block to tick at position.</p>
* <h3><code>random_tick(pos)</code></h3>
* <p>Causes a random tick at position.</p>
* <h3><code>destroy(pos), destroy(pos, -1), destroy(pos, &lt;N&gt;)</code></h3>
* <p>Destroys the block like it was harvest by a player. Add -1 for silk touch, and positive number for fortune level.</p>
* <h3><code>harvest(player, pos)</code></h3>
* <p>Causes a block to be harvested by a specified player entity. Honors player item enchantments, as well as damages the
* tool if applicable. If the entity is not a valid player, no block gets destroyed.</p>
*
*
* <h2>Block and World querying</h2>
*
@@ -518,13 +531,7 @@ public class CarpetExpression
{
throw new InternalExpressionException("Block requires at least one parameter");
}
if (lv.size() == 1)
{
Value retval = BlockValue.fromCommandExpression(lv.get(0).evalValue(cc).getString());
return (c_, t_) -> retval;
//return new BlockValue(Registry.field_212618_g.get(new Identifier(lv.get(0).getString())).getDefaultState(), origin);
}
Value retval = BlockValue.fromParams(cc, lv, 0).block;
Value retval = BlockValue.fromParams(cc, lv, 0, true).block;
return (c_, t_) -> retval;
});
@@ -681,36 +688,95 @@ public class CarpetExpression
World world = cc.s.getWorld();
if (lv.size() < 2 || lv.size() % 2 == 1)
throw new InternalExpressionException("set block should have at least 2 params and odd attributes");
BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0);
Value blockArg = lv.get(locator.offset).evalValue(cc);
BlockValue bv = ((blockArg instanceof BlockValue)) ? (BlockValue) blockArg : BlockValue.fromString(blockArg.getString());
if (bv == BlockValue.NULL)
throw new InternalExpressionException("block to set to should be a valid block");
BlockState bs = bv.getBlockState();
BlockState targetBlockState = world.getBlockState(locator.block.getPos());
if (lv.size()==1+locator.offset && !(blockArg instanceof BlockValue)) // no reqs for properties
if (targetBlockState.getBlock() == bs.getBlock())
return (c_, t_) -> Value.FALSE;
StateFactory<Block, BlockState> states = bs.getBlock().getStateFactory();
for (int i = 1+locator.offset; i < lv.size(); i += 2)
BlockValue.LocatorResult targetLocator = BlockValue.fromParams(cc, lv, 0);
BlockValue.LocatorResult sourceLocator = BlockValue.fromParams(cc, lv, targetLocator.offset, true);
BlockState sourceBlockState = sourceLocator.block.getBlockState();
BlockState targetBlockState = world.getBlockState(targetLocator.block.getPos());
if (sourceLocator.offset < lv.size())
{
String paramString = lv.get(i).evalValue(c).getString();
Property<?> property = states.getProperty(paramString);
if (property == null)
throw new InternalExpressionException("property " + paramString + " doesn't apply to " + blockArg.getString());
String paramValue = lv.get(i + 1).evalValue(c).getString();
bs = setProperty(property, paramString, paramValue, bs);
StateFactory<Block, BlockState> states = sourceBlockState.getBlock().getStateFactory();
for (int i = sourceLocator.offset; i < lv.size(); i += 2)
{
String paramString = lv.get(i).evalValue(c).getString();
Property<?> property = states.getProperty(paramString);
if (property == null)
throw new InternalExpressionException("property " + paramString + " doesn't apply to " + sourceLocator.block.getString());
String paramValue = lv.get(i + 1).evalValue(c).getString();
sourceBlockState = setProperty(property, paramString, paramValue, sourceBlockState);
}
}
cc.s.getWorld().setBlockState(locator.block.getPos(), bs, 2 | (CarpetSettings.getBool("fillUpdates") ? 0 : 1024));
Value retval = new BlockValue(bs, world, locator.block.getPos());
if (sourceBlockState == targetBlockState)
return (c_, t_) -> Value.FALSE;
if (!CarpetSettings.b_fillUpdates) CarpetSettings.impendingFillSkipUpdates = true;
cc.s.getWorld().setBlockState(targetLocator.block.getPos(), sourceBlockState, 2);
CarpetSettings.impendingFillSkipUpdates = false;
Value retval = new BlockValue(sourceBlockState, world, targetLocator.block.getPos());
return (c_, t_) -> retval;
});
this.expr.addLazyFunction("destroy", -1, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c;
ServerWorld world = cc.s.getWorld();
BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 0);
BlockState state = locator.block.getBlockState();
if (state.isAir())
return (c_, t_) -> Value.FALSE;
BlockPos where = locator.block.getPos();
BlockEntity be = world.getBlockEntity(where);
long how = 0;
if (lv.size() > locator.offset)
how = NumericValue.asNumber(lv.get(locator.offset).evalValue(cc)).getLong();
world.clearBlockState(where, false);
world.playLevelEvent(null, 2001, where, Block.getRawIdFromState(state));
if (how < 0)
{
Block.dropStack(world, where, new ItemStack(state.getBlock()));
}
else
{
ItemStack tool = new ItemStack(Items.DIAMOND_PICKAXE, 1);
tool.addEnchantment(Enchantments.FORTUNE,(int)how);
LootContext.Builder lootContext$Builder_1 = (new LootContext.Builder(world)).
setRandom(world.random).
put(LootContextParameters.POSITION, where).
put(LootContextParameters.BLOCK_STATE, state).
putNullable(LootContextParameters.BLOCK_ENTITY, be).
putNullable(LootContextParameters.THIS_ENTITY, cc.s.getEntity()).
put(LootContextParameters.TOOL, tool);
state.getDroppedStacks(lootContext$Builder_1).forEach((stack) -> Block.dropStack(world, where, stack));
//Block.dropStacks(state, world, where, be, cc.s.getEntity(), tool );
}
return (c_, t_) -> Value.TRUE;
});
this.expr.addLazyFunction("harvest", -1, (c, t, lv) -> {
CarpetContext cc = (CarpetContext)c;
World world = cc.s.getWorld();
Value entityValue = lv.get(0).evalValue(cc);
if (!(entityValue instanceof EntityValue))
return (c_, t_) -> Value.FALSE;
Entity e = ((EntityValue) entityValue).getEntity();
if (!(e instanceof PlayerEntity))
return (c_, t_) -> Value.FALSE;
PlayerEntity player = (PlayerEntity)e;
BlockValue.LocatorResult locator = BlockValue.fromParams(cc, lv, 1);
BlockState state = locator.block.getBlockState();
BlockPos where = locator.block.getPos();
BlockEntity be = world.getBlockEntity(where);
world.clearBlockState(where, false);
ItemStack itemstack2 = player.getMainHandStack();
itemstack2.onBlockBroken(player.world, state, where, player);
ItemStack itemstack1 = itemstack2.isEmpty() ? ItemStack.EMPTY : itemstack2.copy();
state.getBlock().afterBreak(world, player, where,state, be, itemstack1);
world.playLevelEvent(null, 2001, where, Block.getRawIdFromState(state));
return (c_, t_) -> Value.TRUE;
});
this.expr.addLazyFunction("blocks_movement", -1, (c, t, lv) ->
booleanStateTest(c, "blocks_movement", lv, (s, p) ->
!s.canPlaceAtSide(((CarpetContext) c).s.getWorld(), p, BlockPlacementEnvironment.LAND)));
@@ -891,7 +957,7 @@ public class CarpetExpression
* <p>Returns triple of short name, stack count, and NBT of item held in <code>slot</code>.
* Available options for <code>slot</code> are:</p>
* <ul>
* <li><code>main</code></li>
* <li><code>mainhand</code></li>
* <li><code>offhand</code></li>
* <li><code>head</code></li>
* <li><code>chest</code></li>
@@ -1573,6 +1639,9 @@ public class CarpetExpression
* </pre>
* <h3><code>current_dimension()</code></h3>
* <p>Returns current dimension that scripts run in.</p>
* <h3><code>schedule(delay, function, args...)</code></h3>
* <p>Schedules a user defined function to run with a specified <code>delay</code> ticks of delay.
* Scheduled functions run at the end of the tick, and they will run in order they were scheduled.</p>
* <h3><code>plop(pos, what)</code></h3>
* <p>Plops a structure or a feature at a given <code>pos</code>, so block, triple position coordinates
* or a list of coordinates. To <code>what</code> gets plopped and exactly where it often depends on the
@@ -1816,7 +1885,7 @@ public class CarpetExpression
}
else
{
Messenger.m(s, "w ");
Messenger.m(s, "w "+ lv.get(0).evalValue(c).getString());
}
return lv.get(0); // pass through for variables
});
@@ -1885,6 +1954,27 @@ public class CarpetExpression
return (c_, t_) -> Value.NULL;
return (c_, t_) -> new NumericValue(res);
});
this.expr.addLazyFunction("schedule", -1, (c, t, lv) -> {
if (lv.size()<2)
throw new InternalExpressionException("schedule should have at least 2 arguments, delay and call name");
Long delay = NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
String funname = lv.get(1).evalValue(c).getString();
CarpetContext cc = (CarpetContext)c;
if (!cc.host.globalFunctions.containsKey(funname))
throw new InternalExpressionException("function "+funname+" is not defined");
List<LazyValue> args = new ArrayList<>();
for (int i=2; i < lv.size(); i++)
{
Value arg = lv.get(i).evalValue(cc);
args.add( (_c, _t) -> arg);
}
if (cc.host.globalFunctions.get(funname).getArguments().size() != args.size())
throw new InternalExpressionException("function "+funname+" takes "+
cc.host.globalFunctions.get(funname).getArguments().size()+" arguments, "+args.size()+" provided.");
CarpetServer.scriptServer.events.scheduleCall(cc, funname, args, delay);
return (c_, t_) -> Value.TRUE;
});
}
/**
@@ -7,6 +7,7 @@ import carpet.script.bundled.FileModule;
import carpet.script.bundled.ModuleInterface;
import carpet.script.exception.CarpetExpressionException;
import carpet.script.exception.ExpressionException;
import carpet.script.exception.InvalidCallbackException;
import carpet.script.value.Value;
import carpet.utils.Messenger;
import com.mojang.brigadier.arguments.StringArgumentType;
@@ -36,6 +37,7 @@ public class CarpetScriptServer
long tickStart;
public boolean stopAll;
Set<String> holyMoly;
public CarpetEventServer events;
public static List<ModuleInterface> bundledModuleData = new ArrayList<ModuleInterface>(){{
add(new CameraPathModule());
@@ -43,7 +45,8 @@ public class CarpetScriptServer
public CarpetScriptServer()
{
globalHost = createMinecraftScriptHost("");
globalHost = createMinecraftScriptHost(null);
events = new CarpetEventServer();
modules = new HashMap<>();
tickStart = 0L;
stopAll = false;
@@ -102,6 +105,13 @@ public class CarpetScriptServer
return moduleNames;
}
public ScriptHost getHostByName(String name)
{
if (name == null)
return globalHost;
return modules.get(name);
}
private static ScriptHost createMinecraftScriptHost(String name)
{
@@ -146,11 +156,31 @@ public class CarpetScriptServer
}
modules.put(name, newHost);
addEvents(source, name);
addCommand(source, name);
return true;
}
public void addEvents(ServerCommandSource source, String hostName)
{
ScriptHost host = modules.get(hostName);
if (host == null)
{
return;
}
for (String fun : host.globalFunctions.keySet())
{
if (!fun.startsWith("__on_"))
continue;
String event = fun.replaceFirst("__on_","");
if (!events.eventHandlers.containsKey(event))
continue;
events.addEvent(event, hostName, fun);
}
}
public void addCommand(ServerCommandSource source, String hostName)
{
@@ -278,4 +308,25 @@ public class CarpetScriptServer
Messenger.m(source, "w Removed host "+name);
return true;
}
public boolean runas(ServerCommandSource source, String hostname, String udf_name, List<LazyValue> argv)
{
return runas(BlockPos.ORIGIN, source, hostname, udf_name, argv);
}
public boolean runas(BlockPos origin, ServerCommandSource source, String hostname, String udf_name, List<LazyValue> argv)
{
ScriptHost host = globalHost;
if (hostname != null)
host = modules.get(hostname);
try
{
host.callUDF(origin, source, host.globalFunctions.get(udf_name), argv);
}
catch (NullPointerException | InvalidCallbackException npe)
{
return false;
}
return true;
}
}
+28 -1
View File
@@ -1,7 +1,9 @@
package carpet.script;
import carpet.CarpetServer;
import carpet.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;
@@ -28,7 +30,7 @@ public class ScriptHost
private String name;
public String getName() {return name;}
public ScriptHost(String name)
ScriptHost(String name)
{
this.name = name;
globalVariables.put("euler", (c, t) -> Expression.euler);
@@ -155,4 +157,29 @@ public class ScriptHost
return e.getMessage();
}
}
public void callUDF(BlockPos pos, ServerCommandSource source, UserDefinedFunction acf, List<LazyValue> argv) throws InvalidCallbackException
{
if (CarpetServer.scriptServer.stopAll)
return;
List<String> args = acf.getArguments();
if (argv.size() != args.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);
Expression.evalValue(
() -> acf.lazyEval(context, Context.VOID, acf.expression, acf.token, argv),
context,
Context.VOID);
}
catch (ExpressionException e)
{
CarpetSettings.LOG.error("Callback failed: "+e.getMessage());
}
}
}
@@ -0,0 +1,5 @@
package carpet.script.exception;
public class InvalidCallbackException extends Exception
{
}
@@ -33,26 +33,8 @@ public class BlockValue extends Value
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)
public static BlockValue fromString(String str)
{
try
{
@@ -62,6 +44,8 @@ public class BlockValue extends Value
if (blockstateparser.getBlockState() != null)
{
bv = new BlockValue(blockstateparser.getBlockState(), null, null);
if (bvCache.size()>10000)
bvCache.clear();
bvCache.put(str, bv);
return bv;
}
@@ -110,10 +94,20 @@ public class BlockValue extends Value
}
public static LocatorResult fromParams(CarpetContext c, List<LazyValue> params, int offset)
{
return fromParams(c, params,offset, false);
}
public static LocatorResult fromParams(CarpetContext c, List<LazyValue> params, int offset, boolean acceptString)
{
try
{
Value v1 = params.get(0 + offset).evalValue(c);
//add conditional from string name
if (acceptString && v1 instanceof StringValue)
{
return new LocatorResult(fromString(v1.getString()), 1+offset);
}
if (v1 instanceof BlockValue)
{
return new LocatorResult(((BlockValue) v1), 1+offset);
@@ -131,7 +131,7 @@ public class EntityValue extends Value
return featureAccessors.get(what).apply(entity, arg);
}
private static Map<String, EquipmentSlot> inventorySlots = new HashMap<String, EquipmentSlot>(){{
put("main", EquipmentSlot.MAINHAND);
put("mainhand", EquipmentSlot.MAINHAND);
put("offhand", EquipmentSlot.OFFHAND);
put("head", EquipmentSlot.HEAD);
put("chest", EquipmentSlot.CHEST);