Merge branch 'master' into future

This commit is contained in:
gnembon committed 2021-09-08 16:22:44 -03:00
commit 9dad47d7a0
14 files changed
+199 -114

No files matched your search

@@ -6,6 +6,7 @@ import carpet.helpers.TickSpeed;
import carpet.script.exception.IntegrityException;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.InvalidCallbackException;
import carpet.script.utils.GlocalFlag;
import carpet.script.value.BlockValue;
import carpet.script.value.BooleanValue;
import carpet.script.value.EntityValue;
@@ -73,8 +74,7 @@ public class CarpetEventServer
public final CarpetScriptServer scriptServer;
private static final List<Value> NOARGS = Collections.emptyList();
public final Map<String, Event> customEvents = new HashMap<>();
public GlocalFlag handleEvents = new GlocalFlag(true);
public enum CallbackResult
{
@@ -194,31 +194,33 @@ public class CarpetEventServer
*/
public void call(Supplier<List<Value>> argumentSupplier, Supplier<ServerCommandSource> cmdSourceSupplier)
{
if (callList.size() > 0)
if (callList.size() > 0 && CarpetServer.scriptServer != null)
{
CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet events", CarpetProfiler.TYPE.GENERAL);
List<Value> argv = argumentSupplier.get(); // empty for onTickDone
ServerCommandSource source;
try
{
source = cmdSourceSupplier.get();
}
catch (NullPointerException noReference) // todo figure out what happens when closing.
{
return;
}
String nameCheck = perPlayerDistribution?source.getName():null;
assert argv.size() == reqArgs;
List<Callback> fails = new ArrayList<>();
for (Callback call: callList)
{
// supressing calls where target player hosts simply don't match
// handling global hosts with player targets is left to when the host is resolved (few calls deeper).
if (nameCheck != null && call.optionalTarget != null && !nameCheck.equals(call.optionalTarget)) continue;
if (call.execute(source, argv) == CallbackResult.FAIL) fails.add(call);
}
for (Callback call : fails) callList.remove(call);
CarpetProfiler.end_current_section(currentSection);
CarpetServer.scriptServer.events.handleEvents.runIfEnabled( () -> {
CarpetProfiler.ProfilerToken currentSection = CarpetProfiler.start_section(null, "Scarpet events", CarpetProfiler.TYPE.GENERAL);
List<Value> argv = argumentSupplier.get(); // empty for onTickDone
ServerCommandSource source;
try
{
source = cmdSourceSupplier.get();
}
catch (NullPointerException noReference) // todo figure out what happens when closing.
{
return;
}
String nameCheck = perPlayerDistribution ? source.getName() : null;
assert argv.size() == reqArgs;
List<Callback> fails = new ArrayList<>();
for (Callback call : callList)
{
// supressing calls where target player hosts simply don't match
// handling global hosts with player targets is left to when the host is resolved (few calls deeper).
if (nameCheck != null && call.optionalTarget != null && !nameCheck.equals(call.optionalTarget)) continue;
if (call.execute(source, argv) == CallbackResult.FAIL) fails.add(call);
}
for (Callback call : fails) callList.remove(call);
CarpetProfiler.end_current_section(currentSection);
});
}
}
@@ -72,7 +72,7 @@ public class CarpetExpression
Value playerValue = new EntityValue(e).bindTo("p");
context.with("p", (cc, tt) -> playerValue);
}
return this.expr.eval(context).getBoolean();
return CarpetServer.scriptServer.events.handleEvents.getWhileDisabled(()-> this.expr.eval(context).getBoolean());
}
catch (ExpressionException e)
{
@@ -109,7 +109,7 @@ public class CarpetExpression
Value playerValue = new EntityValue(e).bindTo("p");
context.with("p", (cc, tt) -> playerValue);
}
return this.expr.eval(context);
return CarpetServer.scriptServer.events.handleEvents.getWhileDisabled(()-> this.expr.eval(context));
}
catch (ExpressionException e)
{
@@ -710,7 +710,7 @@ public class CarpetScriptHost extends ScriptHost
{
try
{
return call(source, function, args);
return scriptServer.events.handleEvents.getWhileDisabled(() -> call(source, function, args));
}
catch (CarpetExpressionException exc)
{
@@ -815,11 +815,11 @@ public class CarpetScriptHost extends ScriptHost
// TODO: this is just for now - invoke would be able to invoke other hosts scripts
assertAppIntegrity(function.getModule());
Context context = new CarpetContext(this, source, BlockPos.ORIGIN);
return function.getExpression().evalValue(
return scriptServer.events.handleEvents.getWhileDisabled(() -> function.getExpression().evalValue(
() -> function.lazyEval(context, Context.VOID, function.getExpression(), function.getToken(), argv),
context,
Context.VOID
);
));
}
catch (ExpressionException e)
{
@@ -891,6 +891,7 @@ public class CarpetScriptHost extends ScriptHost
{
ServerPlayerEntity player = (user==null)?null:scriptServer.server.getPlayerManager().getPlayer(user);
ServerCommandSource source = (player != null)?player.getCommandSource():scriptServer.server.getCommandSource();
return scriptServer.events.handleEvents.getWhileDisabled(()->{
try
{
return callUDF(BlockPos.ORIGIN, source, fun, arguments);
@@ -899,6 +900,7 @@ public class CarpetScriptHost extends ScriptHost
{
return Value.NULL;
}
});
}
@@ -375,7 +375,7 @@ public class CarpetScriptServer
{
CarpetProfiler.ProfilerToken token;
token = CarpetProfiler.start_section(null, "Scarpet schedule", CarpetProfiler.TYPE.GENERAL);
events.tick();
events.handleEvents.getWhileDisabled( () -> {events.tick(); return null;});
CarpetProfiler.end_current_section(token);
token = CarpetProfiler.start_section(null, "Scarpet app data", CarpetProfiler.TYPE.GENERAL);
for (CarpetScriptHost host : modules.values())
@@ -489,6 +489,39 @@ public class Expression
return false;
}
@Override
public LazyValue lazyEval(Context c, Context.Type i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
ILazyFunction.checkInterrupts();
if (num_params >= 0 && lazyParams.size() != num_params)
throw new InternalExpressionException("'"+name+"' requires "+num_params+" parameters, "+lazyParams.size()+" provided.");
try
{
return fun.apply(c, i, lazyParams);
}
catch (RuntimeException exc)
{
throw handleCodeException(c, exc, e, t);
}
}
});
}
public void addLazyFunction(String name, TriFunction<Context, Context.Type, List<LazyValue>, LazyValue> fun)
{
functions.put(name, new AbstractLazyFunction(-1, name)
{
@Override
public boolean pure() {
return false;
}
@Override
public boolean transitive() {
return false;
}
@Override
public LazyValue lazyEval(Context c, Context.Type i, Expression e, Tokenizer.Token t, List<LazyValue> lazyParams)
{
@@ -1216,6 +1249,7 @@ public class Expression
if (arg.op instanceof LazyValue.ContextFreeLazyValue) continue;
return optimized;
}
// a few exceptions which we don't implement in the framework for simplicity for now
if (!operation.pure())
{
if (symbol.equals("->") && expectedType == Context.Type.MAPDEF)
@@ -1226,6 +1260,14 @@ public class Expression
return optimized;
}
}
if (operation.pure())
{
// element access with constant elements will always resolve the same way.
if (symbol.equals(":") && expectedType == Context.Type.LVALUE)
{
expectedType = Context.Type.NONE;
}
}
List<LazyValue> args = new ArrayList<>(node.args.size());
for (ExpressionNode arg : node.args) {
try {
@@ -32,7 +32,7 @@ public class BlockIterators {
public static void apply(Expression expression)
{
// lazy cause of lazy expression
expression.addLazyFunction("scan", -1, (c, t, llv) ->
expression.addLazyFunction("scan", (c, t, llv) ->
{
if (llv.size() < 3) throw new InternalExpressionException("'scan' needs many more arguments");
List<Value> lv = Fluff.AbstractFunction.unpackLazy(llv.subList(0, llv.size()-1), c, Context.NONE);
@@ -140,7 +140,7 @@ public class BlockIterators {
});
// must be lazy
expression.addLazyFunction("volume", -1, (c, t, llv) ->
expression.addLazyFunction("volume", (c, t, llv) ->
{
CarpetContext cc = (CarpetContext)c;
if (llv.size() < 3) throw new InternalExpressionException("'volume' needs many more arguments");
@@ -219,46 +219,6 @@ public class WorldAccess {
return bs;
}
private static boolean tryBreakBlock_copy_from_ServerPlayerInteractionManager(ServerPlayerEntity player, BlockPos blockPos_1)
{
//this could be done little better, by hooking up event handling not in try_break_block but wherever its called
// so we can safely call it here
// but that would do for now.
BlockState blockState_1 = player.world.getBlockState(blockPos_1);
if (!player.getMainHandStack().getItem().canMine(blockState_1, player.world, blockPos_1, player)) {
return false;
} else {
BlockEntity blockEntity_1 = player.world.getBlockEntity(blockPos_1);
Block block_1 = blockState_1.getBlock();
if ((block_1 instanceof CommandBlock || block_1 instanceof StructureBlock || block_1 instanceof JigsawBlock) && !player.isCreativeLevelTwoOp()) {
player.world.updateListeners(blockPos_1, blockState_1, blockState_1, 3);
return false;
} else if (player.isBlockBreakingRestricted(player.world, blockPos_1, player.interactionManager.getGameMode())) {
return false;
} else {
block_1.onBreak(player.world, blockPos_1, blockState_1, player);
boolean boolean_1 = player.world.removeBlock(blockPos_1, false);
if (boolean_1) {
block_1.onBroken(player.world, blockPos_1, blockState_1);
}
if (player.isCreative()) {
return true;
} else {
ItemStack itemStack_1 = player.getMainHandStack();
boolean boolean_2 = player.canHarvest(blockState_1);
itemStack_1.postMine(player.world, blockState_1, blockPos_1, player);
if (boolean_1 && boolean_2) {
ItemStack itemStack_2 = itemStack_1.isEmpty() ? ItemStack.EMPTY : itemStack_1.copy();
block_1.afterBreak(player.world, player, blockPos_1, blockState_1, blockEntity_1, itemStack_2);
}
return true;
}
}
}
}
private static void BooYah(ChunkGenerator generator)
{
synchronized (generator)
@@ -928,7 +888,7 @@ public class WorldAccess {
Block block = state.getBlock();
boolean success = false;
if (!((block == Blocks.BEDROCK || block == Blocks.BARRIER) && player.interactionManager.isSurvivalLike()))
success = tryBreakBlock_copy_from_ServerPlayerInteractionManager(player, where);
success = player.interactionManager.tryBreakBlock(where);
if (success)
world.syncWorldEvent(null, 2001, where, Block.getRawIdFromState(state));
return BooleanValue.of(success);
@@ -38,7 +38,7 @@ public class ControlFlow {
// obvious lazy due to conditional evaluation of arguments
expression.addLazyFunction("if", -1, (c, t, lv) ->
expression.addLazyFunction("if", (c, t, lv) ->
{
if ( lv.size() < 2 )
throw new InternalExpressionException("'if' statement needs to have at least one condition and one case");
@@ -79,7 +79,7 @@ public class ControlFlow {
});
// needs to be lazy since execution of parameters but first one are conditional
expression.addLazyFunction("try", -1, (c, t, lv) ->
expression.addLazyFunction("try", (c, t, lv) ->
{
if (lv.size()==0)
throw new InternalExpressionException("'try' needs at least an expression block, and either a catch_epr, or a number of pairs of filters and catch_expr");
@@ -104,7 +104,7 @@ public class DataStructures {
});
// needs lazy cause sort function is reused
expression.addLazyFunction("sort_key", -1, (c, t, lv) -> //get working with iterators
expression.addLazyFunction("sort_key", (c, t, lv) -> //get working with iterators
{
if (lv.size() == 0)
throw new InternalExpressionException("First argument for 'sort_key' should be a List");
@@ -207,7 +207,7 @@ public class DataStructures {
});
// lazy cause conditional typing - questionable
expression.addLazyFunction("get", -1, (c, t, lv) ->
expression.addLazyFunction("get", (c, t, lv) ->
{
if (lv.size() == 0)
throw new InternalExpressionException("'get' requires parameters");
@@ -235,7 +235,7 @@ public class DataStructures {
});
// same as `get`
expression.addLazyFunction("has", -1, (c, t, lv) ->
expression.addLazyFunction("has", (c, t, lv) ->
{
if (lv.size() == 0)
throw new InternalExpressionException("'has' requires parameters");
@@ -263,7 +263,7 @@ public class DataStructures {
});
// same as `get`
expression.addLazyFunction("put", -1, (c, t, lv) ->
expression.addLazyFunction("put", (c, t, lv) ->
{
if(lv.size()<2)
{
@@ -302,7 +302,7 @@ public class DataStructures {
});
// same as `get`
expression.addLazyFunction("delete", -1, (c, t, lv) ->
expression.addLazyFunction("delete", (c, t, lv) ->
{
if (lv.size() == 0)
throw new InternalExpressionException("'delete' requires parameters");
@@ -423,7 +423,7 @@ public class Sys {
});
// lazy cause default expression may not be executed if not needed
expression.addLazyFunction("system_variable_get", -1, (c, t, lv) ->
expression.addLazyFunction("system_variable_get", (c, t, lv) ->
{
if (lv.size() == 0) throw new InternalExpressionException("'system_variable_get' expects at least a key to be fetched");
Value key = lv.get(0).evalValue(c);
@@ -67,7 +67,7 @@ public class Threading
});
// lazy cause expr is evaluated in the same type
expression.addLazyFunction("synchronize", -1, (c, t, lv) ->
expression.addLazyFunction("synchronize", (c, t, lv) ->
{
if (lv.size() == 0) throw new InternalExpressionException("'synchronize' require at least an expression to synchronize");
Value lockValue = Value.NULL;
@@ -85,7 +85,7 @@ public class Threading
});
// lazy since exception expression is very conditional
expression.addLazyFunction("sleep", -1, (c, t, lv) ->
expression.addLazyFunction("sleep", (c, t, lv) ->
{
long time = lv.isEmpty()?0L:NumericValue.asNumber(lv.get(0).evalValue(c)).getLong();
boolean interrupted = false;
@@ -0,0 +1,68 @@
package carpet.script.utils;
import java.util.function.Supplier;
public class GlocalFlag extends ThreadLocal<Boolean>
{
private final boolean initial;
public GlocalFlag(boolean initial)
{
this.initial = initial;
}
@Override
public Boolean initialValue()
{
return initial;
}
/**
* Allows to thread-safely wrap a call while disabling a global flag and setting it back up right after.
* @param action - callback to invoke when the wrapping is all setup
* @param <T> - returned value of that action, whatever that might be
* @return result of the action
*/
public <T> T getWhileDisabled(Supplier<T> action)
{
return whileValueReturn(!initial, action);
}
private <T> T whileValueReturn(boolean what, Supplier<T> action)
{
T result;
boolean previous;
synchronized (this)
{
previous = get();
set(what);
}
try
{
result = action.get();
}
finally
{
set(previous);
}
return result;
}
public boolean runIfEnabled(Runnable action)
{
synchronized (this)
{
if (get() != initial) return false;
set(!initial);
}
try
{
action.run();
}
finally
{
set(initial);
}
return true;
}
}
@@ -1088,7 +1088,7 @@ public class EntityValue extends Value
}
List<Value> coords = ((ListValue) v).getItems();
double dx = NumericValue.asNumber(coords.get(0)).getDouble();
double dy = NumericValue.asNumber(coords.get(0)).getDouble();
double dy = NumericValue.asNumber(coords.get(1)).getDouble();
double dz = NumericValue.asNumber(coords.get(2)).getDouble();
e.setVelocity(dx, dy, dz);
updateVelocity(e, MathHelper.absMax(MathHelper.absMax(dx, dy), dz));
@@ -2,7 +2,6 @@ package carpet.script.value;
import carpet.fakes.InventoryBearerInterface;
import carpet.script.CarpetContext;
import carpet.script.LazyValue;
import carpet.script.exception.InternalExpressionException;
import carpet.script.exception.ThrowStatement;
import carpet.script.exception.Throwables;
@@ -21,16 +20,16 @@ import net.minecraft.command.argument.NbtPathArgumentType;
import net.minecraft.entity.Entity;
import net.minecraft.entity.InventoryOwner;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.passive.MerchantEntity;
import net.minecraft.entity.passive.VillagerEntity;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.inventory.Inventory;
import net.minecraft.item.ItemStack;
import net.minecraft.nbt.AbstractNbtList;
import net.minecraft.nbt.AbstractNbtNumber;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.nbt.NbtInt;
import net.minecraft.nbt.NbtList;
import net.minecraft.nbt.NbtLong;
import net.minecraft.nbt.NbtNull;
import net.minecraft.nbt.StringNbtReader;
import net.minecraft.nbt.NbtString;
import net.minecraft.nbt.NbtElement;
@@ -326,31 +325,32 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
return slot;
}
private static Value decodeSimpleTag(NbtElement t)
{
if (t instanceof AbstractNbtNumber)
{
if (t instanceof NbtLong || t instanceof NbtInt) // short and byte will never exceed float's precision, even int won't
{
return NumericValue.of(((AbstractNbtNumber) t).longValue());
}
return NumericValue.of(((AbstractNbtNumber) t).numberValue());
}
if (t instanceof NbtString)
return StringValue.of(t.asString());
if (t instanceof NbtNull)
return Value.NULL;
throw new InternalExpressionException("How did we get here: Unknown nbt element class: "+t.getNbtType().getCrashReportName());
}
private static Value decodeTag(NbtElement t)
{
if (t instanceof NbtCompound)
if (t instanceof NbtCompound || t instanceof AbstractNbtList)
return new NBTSerializableValue(() -> t);
if (t instanceof AbstractNbtNumber)
return new NumericValue(((AbstractNbtNumber) t).doubleValue());
// more can be done here
return new StringValue(t.asString());
return decodeSimpleTag(t);
}
public Value toValue()
{
return decodeTagDeep(this.getTag());
}
public static Value fromValue(Value v)
{
if (v instanceof NBTSerializableValue)
return v;
if (v instanceof NullValue)
return Value.NULL;
return NBTSerializableValue.parseString(v.getString(), true);
}
private static Value decodeTagDeep(NbtElement t)
{
if (t instanceof NbtCompound)
@@ -373,10 +373,21 @@ public class NBTSerializableValue extends Value implements ContainerValueInterfa
}
return ListValue.wrap(elems);
}
if (t instanceof AbstractNbtNumber)
return new NumericValue(((AbstractNbtNumber) t).doubleValue());
// more can be done here
return new StringValue(t.asString());
return decodeSimpleTag(t);
}
public Value toValue()
{
return decodeTagDeep(this.getTag());
}
public static Value fromValue(Value v)
{
if (v instanceof NBTSerializableValue)
return v;
if (v instanceof NullValue)
return Value.NULL;
return NBTSerializableValue.parseString(v.getString(), true);
}
public NbtElement getTag()