Skip to content

Commit

Permalink
Add global and value-local functions
Browse files Browse the repository at this point in the history
  • Loading branch information
rubensworks committed Sep 23, 2023
1 parent 8104dc1 commit 7e3f118
Show file tree
Hide file tree
Showing 7 changed files with 163 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,15 @@
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.nbt.ByteArrayTag;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.Items;
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueObjectTypeItemStack;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeBoolean;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeInteger;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeList;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeNbt;
import org.cyclops.integratedscripting.evaluate.ScriptHelpers;
import org.cyclops.integratedscripting.evaluate.translation.ValueTranslators;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
Expand All @@ -37,8 +41,18 @@ public int run(CommandContext<CommandSourceStack> commandContext) throws Command
}

try {
Source source = Source.newBuilder("js", "function testFunction(a, b, c, d) { console.log('Args: ' + JSON.stringify(a) + JSON.stringify(b) + JSON.stringify(c) + JSON.stringify(d)); console.log(typeof d); return 10; }", "src.js").build();
try (Context context = Context.newBuilder().engine(ENGINE).allowAllAccess(true).build()) {
Source source = Source.newBuilder("js", """
function testFunction(a, b, c, d, e, f) {
console.log('Args: ' + JSON.stringify(a) + JSON.stringify(b) + JSON.stringify(c) + JSON.stringify(d));
console.log(typeof d);
console.log(JSON.stringify(e));
console.log(Object.keys(idContext.ops));
console.log(idContext.ops.itemstackStackable(e));
console.log(f.block().isPlantable());
console.log(f.block().stepSound());
return 10;
}""", "src.js").build();
try (Context context = ScriptHelpers.createPopulatedContext()) {
// long timeStart = System.currentTimeMillis();
// for (int i = 0; i < 100; i++) {
// context.eval(source);
Expand All @@ -64,7 +78,9 @@ public int run(CommandContext<CommandSourceStack> commandContext) throws Command
ValueTypeInteger.ValueInteger.of(10),
ValueTypeBoolean.ValueBoolean.of(true)
)),
ValueTranslators.REGISTRY.translateToGraal(context, ValueTypeNbt.ValueNbt.of(new ByteArrayTag(new byte[]{1, 2, 3})))
ValueTranslators.REGISTRY.translateToGraal(context, ValueTypeNbt.ValueNbt.of(new ByteArrayTag(new byte[]{1, 2, 3}))),
ValueTranslators.REGISTRY.translateToGraal(context, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.STONE))),
ValueTranslators.REGISTRY.translateToGraal(context, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ACACIA_SAPLING)))
);
System.out.println(ValueTranslators.REGISTRY.translateFromGraal(context, ret).toString()); // TODO
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
package org.cyclops.integratedscripting.evaluate;

import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
import org.cyclops.integrateddynamics.api.evaluate.operator.IOperator;
import org.cyclops.integrateddynamics.core.evaluate.operator.Operators;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeOperator;
import org.cyclops.integratedscripting.evaluate.translation.ValueTranslators;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Value;

import java.util.Map;

/**
* @author rubensworks
*/
public class ScriptHelpers {

public static Context createBaseContext() {
Engine engine = Engine
.newBuilder()
.option("engine.WarnInterpreterOnly", "false")
.build();
return Context
.newBuilder()
.engine(engine)
.allowAllAccess(true)
.build();
}

public static Context createPopulatedContext() throws EvaluationException {
Context context = createBaseContext();

// Create idContext field with ops
Value idContext = context.eval("js", "new Object()");
Value ops = context.eval("js", "new Object()");
for (Map.Entry<String, IOperator> entry : Operators.REGISTRY.getGlobalInteractOperators().entrySet()) {
ops.putMember(entry.getKey(), ValueTranslators.REGISTRY.translateToGraal(context, ValueTypeOperator.ValueOperator.of(entry.getValue())));
}
idContext.putMember("ops", ops);
context.getBindings("js").putMember("idContext", idContext);

return context;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
public class ValueTranslators {

public static final IValueTranslatorRegistry REGISTRY = constructRegistry();
public static ValueTranslatorNbt TRANSLATOR_NBT;

private static IValueTranslatorRegistry constructRegistry() {
// This also allows this registry to be used outside of a minecraft environment.
Expand Down Expand Up @@ -40,7 +41,7 @@ public static void load() {
REGISTRY.register(new ValueTranslatorObjectAdapter<>("id_recipe", ValueTypes.OBJECT_RECIPE));

// NBT has last priority
REGISTRY.register(new ValueTranslatorNbt());
REGISTRY.register(TRANSLATOR_NBT = new ValueTranslatorNbt());
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.List;

Expand Down Expand Up @@ -83,12 +84,7 @@ public Value translateTag(Context context, Tag tag) throws EvaluationException {
return context.asValue(list);
}
case Tag.TAG_COMPOUND -> {
CompoundTag compoundTag = (CompoundTag) tag;
Value map = context.eval("js", "new Object()");
for (String key : compoundTag.getAllKeys()) {
map.putMember(key, translateTag(context, compoundTag.get(key)));
}
return map;
return translateCompoundTag(context, (CompoundTag) tag, null);
}
case Tag.TAG_INT_ARRAY -> {
return context.asValue(((IntArrayTag) tag).getAsIntArray());
Expand All @@ -100,6 +96,16 @@ public Value translateTag(Context context, Tag tag) throws EvaluationException {
}
}

public Value translateCompoundTag(Context context, CompoundTag tag, @Nullable ValueTranslatorObjectAdapter.IInstanceConstructor instanceConstructor) throws EvaluationException {
Value instance = instanceConstructor == null ?
context.eval("js", "new Object()") :
instanceConstructor.construct(context);
for (String key : tag.getAllKeys()) {
instance.putMember(key, translateTag(context, tag.get(key)));
}
return instance;
}

@Override
public ValueTypeNbt.ValueNbt translateFromGraal(Context context, Value value) throws EvaluationException {
if (value.getMemberKeys().equals(Sets.newHashSet("nbt_end"))) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,22 @@
import net.minecraft.nbt.CompoundTag;
import net.minecraft.nbt.Tag;
import org.cyclops.integrateddynamics.api.evaluate.EvaluationException;
import org.cyclops.integrateddynamics.api.evaluate.operator.IOperator;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValue;
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueType;
import org.cyclops.integrateddynamics.core.evaluate.operator.CurriedOperator;
import org.cyclops.integrateddynamics.core.evaluate.operator.Operators;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueObjectTypeBase;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeNbt;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeOperator;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypes;
import org.cyclops.integrateddynamics.core.evaluate.variable.Variable;
import org.cyclops.integratedscripting.evaluate.translation.IValueTranslator;
import org.cyclops.integratedscripting.evaluate.translation.ValueTranslators;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Value;

import java.util.Map;
import java.util.Set;

/**
Expand Down Expand Up @@ -50,7 +57,25 @@ public Value translateToGraal(Context context, V value) throws EvaluationExcepti
CompoundTag tag = new CompoundTag();
Tag subTag = this.valueType.serialize(value);
tag.put(this.key, subTag);
return ValueTranslators.REGISTRY.translateToGraal(context, ValueTypeNbt.ValueNbt.of(tag));

// Create prototype containing value-specific functions
IInstanceConstructor instanceConstructor = (subContext) -> {
Value prototype = subContext.eval("js", "new Object()");
for (IValueType<?> valueType : ValueTypes.REGISTRY.getValueTypes()) {
if (valueType.correspondsTo(value.getType())) {
Map<String, IOperator> scopedOperators = Operators.REGISTRY.getScopedInteractOperators().get(valueType);
if (scopedOperators != null) {
for (Map.Entry<String, IOperator> entry : scopedOperators.entrySet()) {
IOperator curriedOperator = new CurriedOperator(entry.getValue(), new Variable<>(value));
prototype.putMember(entry.getKey(), ValueTranslators.REGISTRY.translateToGraal(subContext, ValueTypeOperator.ValueOperator.of(curriedOperator)));
}
}
}
}
return subContext.getBindings("js").getMember("Object").invokeMember("create", prototype);
};

return ValueTranslators.TRANSLATOR_NBT.translateCompoundTag(context, tag, instanceConstructor);
}

@Override
Expand All @@ -64,4 +89,8 @@ public V translateFromGraal(Context context, Value value) throws EvaluationExcep
public Tag translateToNbt(Context context, V value) throws EvaluationException {
throw new UnsupportedOperationException("translateToNbt is not supported");
}

public static interface IInstanceConstructor {
public Value construct(Context context) throws EvaluationException;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ public static interface JavaRunnableFromGraal {

public static class GraalOperator extends OperatorBase {
protected GraalOperator(IValueType[] inputTypes, IFunction function) {
super("GRAAL", "GRAAL", inputTypes, ValueTypes.CATEGORY_ANY, function, null);
super("GRAAL", "GRAAL", "GRAAL", null, false, inputTypes, ValueTypes.CATEGORY_ANY, function, null);
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@
import org.cyclops.integrateddynamics.api.evaluate.variable.IValueTypeListProxy;
import org.cyclops.integrateddynamics.core.evaluate.operator.Operators;
import org.cyclops.integrateddynamics.core.evaluate.variable.*;
import org.cyclops.integratedscripting.evaluate.ScriptHelpers;
import org.graalvm.polyglot.Context;
import org.graalvm.polyglot.Engine;
import org.graalvm.polyglot.Source;
import org.graalvm.polyglot.Value;
import org.jetbrains.annotations.NotNull;
Expand All @@ -46,7 +46,6 @@ public class ValueTranslatorsJavaScriptTests {
Registry.ITEM.unfreeze();
}

private static Engine ENGINE = null;
private static Context CTX = null;

@BeforeClass
Expand All @@ -55,10 +54,11 @@ public static void beforeAll() {
Operators.load();
ValueTranslators.load();

ENGINE = Engine.newBuilder()
.option("engine.WarnInterpreterOnly", "false")
.build();
CTX = Context.newBuilder().engine(ENGINE).allowAllAccess(true).build();
try {
CTX = ScriptHelpers.createPopulatedContext();
} catch (EvaluationException e) {
e.printStackTrace();
}
}

public static Value getJsValue(String jsString) {
Expand Down Expand Up @@ -379,6 +379,12 @@ public void testObjectBlockUnknown() throws EvaluationException {
assertThat(ValueTranslators.REGISTRY.translateFromGraal(CTX, getJsValue("exports = { id_block: { Name: 'minecraft:unknown_thing' } }")), equalTo(ValueObjectTypeBlock.ValueBlock.of(Blocks.AIR.defaultBlockState())));
}

@Test
public void testObjectBlockMethods() throws EvaluationException {
assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeBlock.ValueBlock.of(Blocks.GLASS.defaultBlockState())).invokeMember("isOpaque").asBoolean(), is(false));
assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeBlock.ValueBlock.of(Blocks.STONE.defaultBlockState())).invokeMember("isOpaque").asBoolean(), is(true));
}

@Test
public void testObjectItem() throws EvaluationException {
assertThat(ValueTranslators.REGISTRY.translateFromGraal(CTX, getJsValue("exports = { id_item: { id: 'minecraft:arrow', Count: 1 } }")), equalTo(ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ARROW))));
Expand All @@ -392,6 +398,18 @@ public void testObjectItem() throws EvaluationException {
assertThat(translated.getMember("id_item").getMember("Count").asInt(), equalTo(1));
}

@Test
public void testObjectItemMethods() throws EvaluationException {
assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ARROW))).invokeMember("canBurn").asBoolean(), is(false));

assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ACACIA_SAPLING))).invokeMember("block").invokeMember("isPlantable").asBoolean(), is(true));

assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ACACIA_SAPLING, 1)))
.invokeMember("equals", ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ACACIA_SAPLING, 2)))).asBoolean(), is(false));
assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ACACIA_SAPLING, 1)))
.invokeMember("equals", ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ACACIA_SAPLING, 1)))).asBoolean(), is(true));
}

@Test
public void testObjectFluid() throws EvaluationException {
assertThat(ValueTranslators.REGISTRY.translateFromGraal(CTX, getJsValue("exports = { id_fluid: { FluidName: 'minecraft:water', Amount: 1000 } }")), equalTo(ValueObjectTypeFluidStack.ValueFluidStack.of(new FluidStack(Fluids.WATER, 1000))));
Expand All @@ -405,6 +423,35 @@ public void testObjectFluid() throws EvaluationException {
assertThat(translated.getMember("id_fluid").getMember("Amount").asInt(), equalTo(1000));
}

@Test
public void testObjectFluidMethods() throws EvaluationException {
assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeFluidStack.ValueFluidStack.of(new FluidStack(Fluids.WATER, 1000))).invokeMember("amount").asInt(), is(1000));
assertThat(ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeFluidStack.ValueFluidStack.of(new FluidStack(Fluids.WATER, 123))).invokeMember("amount").asInt(), is(123));
}

// Entity, ingredients, and recipe are not easily testable

@Test
public void testGlobalFunctions() throws EvaluationException {
Value ops = CTX.getBindings("js").getMember("idContext").getMember("ops");

assertThat(
ops.invokeMember("itemstackSize", ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ARROW, 10)))).asInt(),
equalTo(10)
);

assertThat(
ops.invokeMember("anyEquals",
ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ARROW, 10))),
ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeItemStack.ValueItemStack.of(new ItemStack(Items.ARROW, 20)))
).asBoolean(),
equalTo(false)
);

assertThat(
ops.invokeMember("fluidstackAmount", ValueTranslators.REGISTRY.translateToGraal(CTX, ValueObjectTypeFluidStack.ValueFluidStack.of(new FluidStack(Fluids.WATER, 1000)))).asInt(),
equalTo(1000)
);
}

}

0 comments on commit 7e3f118

Please sign in to comment.