Skip to content

Commit c5b87af

Browse files
committed
Add executeas() to change player/label context when running a closure
1 parent bcf6ac3 commit c5b87af

2 files changed

Lines changed: 84 additions & 0 deletions

File tree

src/main/java/com/laytonsmith/core/functions/DataHandling.java

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
package com.laytonsmith.core.functions;
22

33
import com.laytonsmith.PureUtilities.Version;
4+
import com.laytonsmith.abstraction.MCCommandSender;
45
import com.laytonsmith.annotations.api;
56
import com.laytonsmith.annotations.breakable;
67
import com.laytonsmith.annotations.core;
@@ -3217,6 +3218,79 @@ public CHVersion since() {
32173218
}
32183219
}
32193220

3221+
@api
3222+
@seealso({com.laytonsmith.tools.docgen.templates.Closures.class})
3223+
public static class executeas extends AbstractFunction {
3224+
3225+
@Override
3226+
public String getName() {
3227+
return "executeas";
3228+
}
3229+
3230+
@Override
3231+
public Integer[] numArgs() {
3232+
return new Integer[]{Integer.MAX_VALUE};
3233+
}
3234+
3235+
@Override
3236+
public String docs() {
3237+
return "mixed {player, label, [values...,] closure} Executes the given closure in the context of a given"
3238+
+ " player. A closure that runs player(), for instance, would return the specified player's name."
3239+
+ " The label argument sets the permission label that this closure will use. If null is given,"
3240+
+ " the current label will be used, like with execute().";
3241+
}
3242+
3243+
@Override
3244+
public Class<? extends CREThrowable>[] thrown() {
3245+
return new Class[]{CRECastException.class};
3246+
}
3247+
3248+
@Override
3249+
public Boolean runAsync() {
3250+
return null;
3251+
}
3252+
3253+
@Override
3254+
public boolean isRestricted() {
3255+
return true;
3256+
}
3257+
3258+
@Override
3259+
public Construct exec(Target t, Environment environment, Construct... args) throws ConfigRuntimeException {
3260+
if(!(args[args.length - 1] instanceof CClosure)) {
3261+
throw new CRECastException("Only a closure (created from the closure function) can be sent to executeas()", t);
3262+
}
3263+
Construct[] vals = new Construct[args.length - 3];
3264+
System.arraycopy(args, 2, vals, 0, args.length - 3);
3265+
CClosure closure = (CClosure) args[args.length - 1];
3266+
CommandHelperEnvironment cEnv = closure.getEnv().getEnv(CommandHelperEnvironment.class);
3267+
GlobalEnv gEnv = closure.getEnv().getEnv(GlobalEnv.class);
3268+
3269+
MCCommandSender originalSender = cEnv.GetCommandSender();
3270+
cEnv.SetCommandSender(Static.GetCommandSender(args[0].val(), t));
3271+
3272+
String originalLabel = gEnv.GetLabel();
3273+
if(!(args[1] instanceof CNull)) {
3274+
gEnv.SetLabel(args[1].val());
3275+
}
3276+
3277+
try {
3278+
closure.execute(vals);
3279+
} catch (FunctionReturnException e) {
3280+
return e.getReturn();
3281+
} finally {
3282+
cEnv.SetCommandSender(originalSender);
3283+
gEnv.SetLabel(originalLabel);
3284+
}
3285+
return CVoid.VOID;
3286+
}
3287+
3288+
@Override
3289+
public CHVersion since() {
3290+
return CHVersion.V3_3_2;
3291+
}
3292+
}
3293+
32203294
@api
32213295
public static class _boolean extends AbstractFunction implements Optimizable {
32223296

src/test/java/com/laytonsmith/core/functions/DataHandlingTest.java

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@ public static void tearDownClass() throws Exception {
4949
public void setUp() {
5050
fakePlayer = StaticTest.GetOnlinePlayer();
5151
fakeServer = StaticTest.GetFakeServer();
52+
when(fakeServer.getPlayer(fakePlayer.getName())).thenReturn(fakePlayer);
5253
env.getEnv(CommandHelperEnvironment.class).SetPlayer(fakePlayer);
5354
}
5455

@@ -475,6 +476,15 @@ public void testClosure9() throws Exception {
475476
verify(fakePlayer).sendMessage("{Hello World}");
476477
}
477478

479+
@Test(timeout = 10000)
480+
public void testClosure10() throws Exception {
481+
SRun("@a = closure(msg('yes'));"
482+
+ "@b = closure(msg('no'));"
483+
+ "executeas('" + fakePlayer.getName() + "', null, @a);"
484+
+ "execute(@b);", fakeServer.getConsole());
485+
verify(fakePlayer).sendMessage("yes");
486+
}
487+
478488
@Test(timeout = 10000)
479489
public void testWhile() throws Exception {
480490
SRun("assign(@i, 2) while(@i > 0, @i-- msg('hi'))", fakePlayer);

0 commit comments

Comments
 (0)