schedules and events from jarmod
This commit is contained in:
1 parent
4ec6e0e03e
commit
730446b219
14 files changed
+825
-62
No files matched your search
@@ -46,6 +46,7 @@ public class CarpetServer // static for now - easier to handle all around the co
|
||||
{
|
||||
TickSpeed.tick(server);
|
||||
HUDController.update_hud(server);
|
||||
scriptServer.events.tick();
|
||||
//in case something happens
|
||||
CarpetSettings.impendingFillSkipUpdates = false;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@ package carpet.commands;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.script.CarpetEventServer;
|
||||
import carpet.script.CarpetExpression;
|
||||
import carpet.script.Expression;
|
||||
import carpet.script.ExpressionInspector;
|
||||
@@ -193,9 +194,42 @@ public class ScriptCommand
|
||||
return success?1:0;
|
||||
}));
|
||||
|
||||
LiteralArgumentBuilder<ServerCommandSource> q = literal("event").requires( (player) -> player.hasPermissionLevel(2) ).
|
||||
executes( (cc) -> listEvents(cc.getSource())).
|
||||
then(literal("add_to").
|
||||
then(argument("event", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.events.eventHandlers.keySet() ,bb)).
|
||||
then(argument("call", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(suggestFunctionCalls(cc), bb)).
|
||||
executes( (cc) -> CarpetServer.scriptServer.events.addEvent(
|
||||
StringArgumentType.getString(cc, "event"),
|
||||
null,
|
||||
StringArgumentType.getString(cc, "call")
|
||||
)?1:0)).
|
||||
then(literal("from").
|
||||
then(argument("package", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.modules.keySet(), bb)).
|
||||
then(argument("call", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(suggestFunctionCalls(cc), bb)).
|
||||
executes( (cc) -> CarpetServer.scriptServer.events.addEvent(
|
||||
StringArgumentType.getString(cc, "event"),
|
||||
StringArgumentType.getString(cc, "package"),
|
||||
StringArgumentType.getString(cc, "call")
|
||||
)?1:0)))))).
|
||||
then(literal("remove_from").
|
||||
then(argument("event", StringArgumentType.word()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.events.eventHandlers.keySet() ,bb)).
|
||||
then(argument("call", StringArgumentType.greedyString()).
|
||||
suggests( (cc, bb) -> suggestMatching(CarpetServer.scriptServer.events.eventHandlers.get(StringArgumentType.getString(cc, "event")).callList.stream().map(CarpetEventServer.Callback::toString), bb)).
|
||||
executes( (cc) -> CarpetServer.scriptServer.events.removeEvent(
|
||||
StringArgumentType.getString(cc, "event"),
|
||||
StringArgumentType.getString(cc, "call")
|
||||
)?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));
|
||||
then(b).then(u).then(o).then(l).then(s).then(c).then(h).then(i).then(e).then(t).then(a).then(f).then(q));
|
||||
dispatcher.register(literal("script").
|
||||
requires((player) -> CarpetSettings.getBool("commandScript")).
|
||||
then(literal("in").
|
||||
@@ -222,6 +256,24 @@ public class ScriptCommand
|
||||
ScriptHost host = getHost(c);
|
||||
return host.getPublicFunctions();
|
||||
}
|
||||
private static int listEvents(ServerCommandSource source)
|
||||
{
|
||||
Messenger.m(source, "w Lists ALL event handlers:");
|
||||
for (String event: CarpetServer.scriptServer.events.eventHandlers.keySet())
|
||||
{
|
||||
boolean shownEvent = false;
|
||||
for (CarpetEventServer.Callback c: CarpetServer.scriptServer.events.eventHandlers.get(event).callList)
|
||||
{
|
||||
if (!shownEvent)
|
||||
{
|
||||
Messenger.m(source, "w Handlers for "+event+": ");
|
||||
shownEvent = true;
|
||||
}
|
||||
Messenger.m(source, "w - "+c.udf+(c.host==null?"":" (from "+c.host+")"));
|
||||
}
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
private static int listGlobals(CommandContext<ServerCommandSource> context)
|
||||
{
|
||||
ScriptHost host = getHost(context);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.fakes.MinecraftServerInterface;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.ServerTask;
|
||||
@@ -7,6 +8,9 @@ import net.minecraft.util.NonBlockingThreadExecutor;
|
||||
import net.minecraft.util.SystemUtil;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.function.BooleanSupplier;
|
||||
|
||||
@@ -31,4 +35,13 @@ public abstract class MinecraftServer_scarpetMixin extends NonBlockingThreadExec
|
||||
tick(isAhead);
|
||||
executeTaskQueue();
|
||||
}
|
||||
|
||||
@Inject(method = "tick", at = @At(
|
||||
value = "CONSTANT",
|
||||
args = "stringValue=tallying"
|
||||
))
|
||||
public void tickTasks(BooleanSupplier booleanSupplier_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onTick();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,153 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import carpet.CarpetSettings;
|
||||
import net.minecraft.server.network.ServerPlayNetworkHandler;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.network.packet.ClientCommandC2SPacket;
|
||||
import net.minecraft.server.network.packet.PlayerActionC2SPacket;
|
||||
import net.minecraft.server.network.packet.PlayerInputC2SPacket;
|
||||
import net.minecraft.server.network.packet.PlayerInteractBlockC2SPacket;
|
||||
import net.minecraft.server.network.packet.PlayerInteractEntityC2SPacket;
|
||||
import net.minecraft.server.network.packet.PlayerInteractItemC2SPacket;
|
||||
import net.minecraft.server.network.packet.PlayerMoveC2SPacket;
|
||||
import net.minecraft.util.Hand;
|
||||
import net.minecraft.util.hit.BlockHitResult;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ServerPlayNetworkHandler.class)
|
||||
public class ServerPlayNetworkHandler_scarpetEventsMixin
|
||||
{
|
||||
@Shadow public ServerPlayerEntity player;
|
||||
|
||||
@Inject(method = "onPlayerInput", at = @At(value = "RETURN"))
|
||||
private void checkMoves(PlayerInputC2SPacket p, CallbackInfo ci)
|
||||
{
|
||||
if (p.getSideways() != 0.0F || p.getForward() != 0.0F || p.isJumping() || p.isSneaking())
|
||||
{
|
||||
CarpetServer.scriptServer.events.onMountControls(player, p.getSideways(), p.getForward(), p.isJumping(), p.isSneaking());
|
||||
}
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerMove", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;jump()V"
|
||||
))
|
||||
private void onJump(PlayerMoveC2SPacket playerMoveC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onPlayerJumped(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerAction", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerInteractionManager;method_14263(Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/util/math/Direction;)V"
|
||||
))
|
||||
private void onClicked(PlayerActionC2SPacket packet, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onBlockClicked(player, packet.getPos(), packet.getDirection());
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerInteractBlock", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerInteractionManager;interactBlock(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/world/World;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/Hand;Lnet/minecraft/util/hit/BlockHitResult;)Lnet/minecraft/util/ActionResult;"
|
||||
))
|
||||
private void onBlockInteracted(PlayerInteractBlockC2SPacket playerInteractBlockC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
Hand hand = playerInteractBlockC2SPacket_1.getHand();
|
||||
BlockHitResult hitRes = playerInteractBlockC2SPacket_1.getHitY();
|
||||
CarpetServer.scriptServer.events.onRightClickBlock(player, hand, hitRes );
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerInteractItem", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;updateLastActionTime()V"
|
||||
))
|
||||
private void onItemClicked(PlayerInteractItemC2SPacket playerInteractItemC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onRightClick(player, playerInteractItemC2SPacket_1.getHand());
|
||||
}
|
||||
|
||||
@Inject(method = "onClientCommand", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;setSneaking(Z)V",
|
||||
ordinal = 0
|
||||
))
|
||||
private void onStartSneaking(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onStartSneaking(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onClientCommand", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;setSneaking(Z)V",
|
||||
ordinal = 1
|
||||
))
|
||||
private void onStopSneaking(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onStopSneaking(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onClientCommand", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;setSprinting(Z)V",
|
||||
ordinal = 0
|
||||
))
|
||||
private void onStartSprinting(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onStartSprinting(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onClientCommand", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;setSprinting(Z)V",
|
||||
ordinal = 1
|
||||
))
|
||||
private void onStopSprinting(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onStopSprinting(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onClientCommand", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;isSleeping()Z",
|
||||
shift = At.Shift.BEFORE
|
||||
))
|
||||
private void onWakeUp(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
//weird one - doesn't seem to work, maybe MP
|
||||
CarpetServer.scriptServer.events.onOutOfBed(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onClientCommand", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;isFallFlying()Z",
|
||||
shift = At.Shift.BEFORE
|
||||
))
|
||||
private void onElytraEngage(ClientCommandC2SPacket clientCommandC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onElytraDeploy(player);
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerInteractEntity", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;interact(Lnet/minecraft/entity/Entity;Lnet/minecraft/util/Hand;)Lnet/minecraft/util/ActionResult;"
|
||||
))
|
||||
private void onEntityInteract(PlayerInteractEntityC2SPacket playerInteractEntityC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onEntityInteracted(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()), playerInteractEntityC2SPacket_1.getHand());
|
||||
}
|
||||
|
||||
@Inject(method = "onPlayerInteractEntity", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/server/network/ServerPlayerEntity;attack(Lnet/minecraft/entity/Entity;)V"
|
||||
))
|
||||
private void onEntityAttack(PlayerInteractEntityC2SPacket playerInteractEntityC2SPacket_1, CallbackInfo ci)
|
||||
{
|
||||
//todo add hit and hand in the future
|
||||
CarpetServer.scriptServer.events.onEntityAttacked(player, playerInteractEntityC2SPacket_1.getEntity(player.getServerWorld()));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
package carpet.mixins;
|
||||
|
||||
import carpet.CarpetServer;
|
||||
import net.minecraft.block.BlockState;
|
||||
import net.minecraft.server.network.ServerPlayerEntity;
|
||||
import net.minecraft.server.network.ServerPlayerInteractionManager;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
import org.spongepowered.asm.mixin.injection.callback.LocalCapture;
|
||||
|
||||
@Mixin(ServerPlayerInteractionManager.class)
|
||||
public class ServerPlayerInteractionManager_scarpetEventsMixin
|
||||
{
|
||||
@Shadow public ServerPlayerEntity player;
|
||||
|
||||
@Inject(method = "destroyBlock", locals = LocalCapture.CAPTURE_FAILEXCEPTION, at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/block/Block;onBroken(Lnet/minecraft/world/IWorld;Lnet/minecraft/util/math/BlockPos;Lnet/minecraft/block/BlockState;)V",
|
||||
shift = At.Shift.BEFORE
|
||||
))
|
||||
private void onBlockBroken(BlockPos blockPos_1, CallbackInfoReturnable<Boolean> cir, BlockState blockState_1, boolean boolean_1)
|
||||
{
|
||||
CarpetServer.scriptServer.events.onBlockBroken(player, blockPos_1, blockState_1);
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,13 @@ package carpet.mixins;
|
||||
import carpet.CarpetSettings;
|
||||
import carpet.fakes.WorldInterface;
|
||||
import carpet.utils.SpawnReporter;
|
||||
import net.minecraft.block.Block;
|
||||
import net.minecraft.entity.Entity;
|
||||
import net.minecraft.entity.EntityType;
|
||||
import net.minecraft.entity.mob.MobEntity;
|
||||
import net.minecraft.util.math.BlockPos;
|
||||
import net.minecraft.util.math.BoundingBox;
|
||||
import net.minecraft.util.shape.VoxelShape;
|
||||
import net.minecraft.util.shape.VoxelShapes;
|
||||
import net.minecraft.world.SpawnHelper;
|
||||
import net.minecraft.world.World;
|
||||
@@ -35,13 +37,17 @@ public class SpawnHelperMixin
|
||||
if (CarpetSettings.b_lagFreeSpawning)
|
||||
{
|
||||
BlockPos.Mutable blockpos = new BlockPos.Mutable();
|
||||
for (int x = (int)bb.minX, maxx = (int)Math.ceil(bb.maxX); x < maxx; x++)
|
||||
for (int z = (int)bb.minZ, maxz = (int)Math.ceil(bb.maxZ); z < maxz; z++)
|
||||
for (int y = (int)bb.minY, maxy = (int)Math.ceil(bb.maxY); y < maxy; y++)
|
||||
for (int y = (int)bb.minY, maxy = (int)Math.ceil(bb.maxY); y < maxy; y++)
|
||||
for (int x = (int)bb.minX, maxx = (int)Math.ceil(bb.maxX); x < maxx; x++)
|
||||
for (int z = (int)bb.minZ, maxz = (int)Math.ceil(bb.maxZ); z < maxz; z++)
|
||||
{
|
||||
blockpos.set(x, y, z);
|
||||
if (world.getBlockState(blockpos).getCollisionShape(world, blockpos) != VoxelShapes.empty())
|
||||
return world.doesNotCollide(bb);
|
||||
VoxelShape box = world.getBlockState(blockpos).getCollisionShape(world, blockpos);
|
||||
if ( box == VoxelShapes.empty())
|
||||
continue;
|
||||
if (Block.isShapeFullCube(box))
|
||||
return false;
|
||||
return world.doesNotCollide(bb);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
@@ -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, <N>)</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;
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -48,6 +48,8 @@
|
||||
"FossilFeatureMixin",
|
||||
"BuriedTreasureGeneratorPieceMixin",
|
||||
"GravityStructureProcessorMixin",
|
||||
"ServerPlayNetworkHandler_scarpetEventsMixin",
|
||||
"ServerPlayerInteractionManager_scarpetEventsMixin",
|
||||
|
||||
|
||||
"ServerChunkManagerMixin",
|
||||
|
||||
Reference in new issue
Block a user