Merge branch 'master' into future
This commit is contained in:
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()
|
||||
|
||||
Reference in new issue
Block a user