Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
47 changes: 17 additions & 30 deletions build.gradle
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,6 @@ plugins {
id 'net.darkhax.curseforgegradle' version '1.0.8'
id 'com.github.kt3k.coveralls' version '2.12.0'
id 'com.diffplug.spotless' version '6.25.0'
id 'com.github.johnrengelman.shadow' version '8.1.1'
id 'com.modrinth.minotaur' version '2.+'
}

Expand Down Expand Up @@ -89,6 +88,7 @@ sourceSets.main.resources { srcDir 'src/generated/resources' }

configurations {
modLib
graaldeps
implementation.extendsFrom modLib
}

Expand Down Expand Up @@ -142,13 +142,13 @@ dependencies {
}

// https://mvnrepository.com/artifact/org.graalvm.sdk/graal-sdk
modLib "org.graalvm.sdk:graal-sdk:${project.graal_version}"
shadow "org.graalvm.sdk:graal-sdk:${project.graal_version}"
compileOnly(testImplementation("org.graalvm.sdk:graal-sdk:${project.graal_version}"))
graaldeps "org.graalvm.sdk:graal-sdk:${project.graal_version}"
// https://mvnrepository.com/artifact/org.graalvm.js/js
modLib ("org.graalvm.js:js:${project.graal_version}") {
compileOnly(testImplementation("org.graalvm.js:js:${project.graal_version}") {
exclude group: 'com.ibm.icu', module: 'icu4j'
}
shadow "org.graalvm.js:js:${project.graal_version}"
})
graaldeps "org.graalvm.js:js:${project.graal_version}"


// Project lombok
Expand Down Expand Up @@ -257,26 +257,8 @@ task javadocJar(type: Jar, dependsOn: javadoc) {
from javadoc.destinationDir
}

shadowJar {
mergeServiceFiles() // To fix graal issue: https://github.com/oracle/graaljs/issues/125
configurations = [project.configurations.shadow]
archiveClassifier.set(''); // Replace the default JAR
// To avoid clashes with other mods
relocate 'org.graalvm', 'org.cyclops.integratedscripting.vendors.org.graalvm'
relocate 'com.ibm', 'org.cyclops.integratedscripting.vendors.com.ibm'
// Relocate everything from com.oracle, except for com.oracle.truffle, as this is defined in a native lib, which can not be relocated
// relocate 'com.oracle', 'org.cyclops.integratedscripting.vendors.com.oracle'
relocate 'com.oracle.js', 'org.cyclops.integratedscripting.vendors.com.oracle.js'
relocate 'com.oracle.svm', 'org.cyclops.integratedscripting.vendors.com.oracle.svm'
// relocate 'com.oracle.truffle', 'org.cyclops.integratedscripting.vendors.com.oracle.truffle' // Relocation of this fails for com.oracle.truffle.runtime.ModulesSupport at runtime
}
assemble.dependsOn shadowJar
jar {
shadowJar {}
}

artifacts {
archives shadowJar
archives jar
archives deobfJar
archives sourcesJar
archives javadocJar
Expand Down Expand Up @@ -304,19 +286,24 @@ processResources {
'commoncapabilities_version' : commoncapabilities_version,
'commoncapabilities_version_semver' : commoncapabilities_version.replaceAll("-.*\$", ""),
'integrateddynamics_version' : integrateddynamics_version,
'integrateddynamics_version_semver' : integrateddynamics_version.replaceAll("-.*\$", "")
'integrateddynamics_version_semver' : integrateddynamics_version.replaceAll("-.*\$", ""),
'graaldeps' : configurations.graaldeps.files.findAll { it.name.endsWith(".jar") }.collect { "\"META-INF/graaldeps/${it.name}\"" }.join(", ")
]

filesMatching(['pack.mcmeta', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', 'mixins.*.json']) {
filesMatching(['pack.mcmeta', 'META-INF/mods.toml', 'META-INF/neoforge.mods.toml', 'mixins.*.json', 'graaldeps.json']) {
expand expandProps
}
from(configurations.graaldeps.files) {
include("*.jar")
into "META-INF/graaldeps"
}
inputs.properties(expandProps)
}

task publishCurseForge(type: TaskPublishCurseForge) {
dependsOn(tasks.jar)
apiToken = secrets.curseforgeKey;
def mainFile = upload(project.curseforge_project_id, shadowJar)
def mainFile = upload(project.curseforge_project_id, jar)
mainFile.releaseType = secrets.build_number.equals("RELEASE") ? Constants.RELEASE_TYPE_RELEASE : Constants.RELEASE_TYPE_BETA
mainFile.changelogType = "text"
mainFile.changelog = secrets.changelog
Expand All @@ -334,7 +321,7 @@ modrinth {
versionNumber = project.minecraft_version + '-' + project.version
versionName = "${project.version} for NeoForge ${project.minecraft_version}"
versionType = secrets.build_number.equals("RELEASE") ? "release" : "beta"
uploadFile = shadowJar
uploadFile = jar
gameVersions = [ project.minecraft_version ]
changelog = provider { secrets.changelog }

Expand Down Expand Up @@ -371,7 +358,7 @@ publishing {

publications { PublicationContainer publicationContainer ->
publicationContainer.register("maven", MavenPublication) { MavenPublication publication ->
publication.artifacts = [shadowJar, javadocJar, deobfJar, sourcesJar]
publication.artifacts = [jar, javadocJar, deobfJar, sourcesJar]
publication.artifactId = project.archivesBaseName.toLowerCase() // GH can't handle uppercase...
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
package org.cyclops.integratedscripting;

import com.google.gson.JsonElement;
import com.google.gson.JsonObject;
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
import lombok.SneakyThrows;
import net.minecraft.commands.CommandBuildContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.commands.Commands;
import net.minecraft.util.GsonHelper;
import net.minecraft.world.item.CreativeModeTab;
import net.minecraft.world.item.ItemStack;
import net.neoforged.api.distmarker.Dist;
Expand All @@ -13,11 +17,13 @@
import net.neoforged.fml.common.Mod;
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
import net.neoforged.fml.event.lifecycle.FMLLoadCompleteEvent;
import net.neoforged.fml.loading.FMLLoader;
import net.neoforged.neoforge.common.NeoForge;
import net.neoforged.neoforge.event.server.ServerStartedEvent;
import net.neoforged.neoforge.event.server.ServerStoppingEvent;
import net.neoforged.neoforge.event.tick.ServerTickEvent;
import net.neoforged.neoforge.registries.NewRegistryEvent;
import org.apache.commons.io.function.IOStream;
import org.apache.logging.log4j.Level;
import org.cyclops.cyclopscore.config.ConfigHandler;
import org.cyclops.cyclopscore.helper.MinecraftHelpers;
Expand Down Expand Up @@ -49,6 +55,16 @@
import org.cyclops.integratedscripting.part.PartTypes;
import org.cyclops.integratedscripting.proxy.ClientProxy;
import org.cyclops.integratedscripting.proxy.CommonProxy;
import org.graalvm.polyglot.Context;

import java.io.InputStream;
import java.io.InputStreamReader;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashSet;
import java.util.Set;
import java.util.stream.Stream;

/**
* The main mod class of this mod.
Expand All @@ -57,14 +73,15 @@
*/
@Mod(Reference.MOD_ID)
public class IntegratedScripting extends ModBaseVersionable<IntegratedScripting> {

public static IntegratedScripting _instance;

public ScriptingData scriptingData;

public IntegratedScripting(IEventBus modEventBus) {
super(Reference.MOD_ID, (instance) -> _instance = instance, modEventBus);

loadGraal();

getRegistryManager().addRegistry(IValueTranslatorRegistry.class, ValueTranslatorRegistry.getInstance());
getRegistryManager().addRegistry(ILanguageHandlerRegistry.class, LanguageHandlerRegistry.getInstance());

Expand Down Expand Up @@ -191,4 +208,47 @@ public static void clog(Level level, String message) {
IntegratedScripting._instance.getLoggerHelper().log(level, message);
}

@SneakyThrows
private static void loadGraal() {
JsonObject jo;
Path tmp = FMLLoader.getGamePath().resolve("config").resolve("integratedscripting-tmp");
Files.createDirectories(tmp);
Set<Path> outFiles = new HashSet<>();
try (InputStream is = IntegratedScripting.class.getResourceAsStream("/graaldeps.json")) {
assert is != null;
jo = GsonHelper.parse(new InputStreamReader(is));
for (JsonElement path : jo.get("paths").getAsJsonArray()) {
// extract to temp dir
String pathAsString = "/" + path.getAsString();
Path outFile = tmp.resolve(pathAsString.substring(pathAsString.lastIndexOf('/') + 1));
outFiles.add(outFile);
try (InputStream jarStream = IntegratedScripting.class.getResourceAsStream(pathAsString)) {
assert jarStream != null;
Files.copy(jarStream, outFile, StandardCopyOption.REPLACE_EXISTING);
}
}
}

try (Stream<Path> files = Files.list(tmp)) {
IOStream.adapt(files).filter(file -> !outFiles.contains(file)).forEach(Files::deleteIfExists);
}

for (Path outFile : outFiles) {
UnsafeHelper.addToFallbackClassloader(outFile);
}

System.out.println(outFiles.size() + " Graal dependencies loaded");
ClassLoader f = UnsafeHelper.makeFallbackClassloader();
ClassLoader p = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(f);
try {
Context.Builder build = Context.newBuilder("js");
Context con = build.build();
con.eval("js", "console.log('js pre-loaded.')");
con.close();
} finally {
Thread.currentThread().setContextClassLoader(p);
}
}

}
107 changes: 107 additions & 0 deletions src/main/java/org/cyclops/integratedscripting/UnsafeHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
package org.cyclops.integratedscripting;

import cpw.mods.cl.ModuleClassLoader;
import lombok.SneakyThrows;
import sun.misc.Unsafe;

import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.net.URL;
import java.net.URLClassLoader;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;

/**
* @author Wagyourtail
*/
public class UnsafeHelper {
private static final Unsafe UNSAFE = getUnsafe();
private static final MethodHandles.Lookup IMPL_LOOKUP = UnsafeHelper.getImplLookup();

private static final MethodHandle getFallbackClassLoader;
private static final MethodHandle setFallbackClassLoader;

static {
try {
getFallbackClassLoader = IMPL_LOOKUP.findGetter(ModuleClassLoader.class, "fallbackClassLoader", ClassLoader.class);
setFallbackClassLoader = IMPL_LOOKUP.findSetter(ModuleClassLoader.class, "fallbackClassLoader", ClassLoader.class);
} catch (Exception e) {
throw new RuntimeException(e);
}
}

private static Unsafe getUnsafe() {
try {
Field f = Unsafe.class.getDeclaredField("theUnsafe");
f.setAccessible(true);
return (Unsafe) f.get(null);
} catch (IllegalAccessException | NoSuchFieldException e) {
throw new UnsupportedOperationException("Unable to get Unsafe instance", e);
}
}

private static MethodHandles.Lookup getImplLookup() {
try {
// ensure lookup is initialized
MethodHandles.Lookup lookup = MethodHandles.lookup();
// get the impl_lookup field
Field implLookupField = MethodHandles.Lookup.class.getDeclaredField("IMPL_LOOKUP");
Unsafe unsafe = getUnsafe();
MethodHandles.Lookup IMPL_LOOKUP;
IMPL_LOOKUP = (MethodHandles.Lookup) unsafe.getObject(MethodHandles.Lookup.class, unsafe.staticFieldOffset(implLookupField));
if (IMPL_LOOKUP != null) return IMPL_LOOKUP;
throw new NullPointerException();
} catch (Throwable e) {
try {
// try to create a new lookup
Constructor<MethodHandles.Lookup> constructor = MethodHandles.Lookup.class.getDeclaredConstructor(Class.class, int.class);
constructor.setAccessible(true);
return constructor.newInstance(Object.class, -1);
} catch (Throwable e2) {
e.addSuppressed(e2);
}
throw new UnsupportedOperationException("Unable to get MethodHandles.Lookup.IMPL_LOOKUP", e);
}
}

@SneakyThrows
public static void addToFallbackClassloader(Path path) {
UnsafeFallbackClassLoader u = makeFallbackClassloader();
u.addURL(path.toUri().toURL());
}

@SneakyThrows
public static UnsafeFallbackClassLoader makeFallbackClassloader() {
List<ClassLoader> loaders = new ArrayList<>();
ClassLoader l = UnsafeHelper.class.getClassLoader();
if (!(l instanceof ModuleClassLoader)) {
return new UnsafeFallbackClassLoader(l);
}
while (l instanceof ModuleClassLoader) {
loaders.add(l);
l = (ClassLoader) getFallbackClassLoader.invokeExact((ModuleClassLoader) l);
}
if (l instanceof UnsafeFallbackClassLoader) {
return (UnsafeFallbackClassLoader) l;
}
UnsafeFallbackClassLoader u = new UnsafeFallbackClassLoader(l);
setFallbackClassLoader.invokeExact((ModuleClassLoader) loaders.getLast(), (ClassLoader) u);
return u;
}

public static class UnsafeFallbackClassLoader extends URLClassLoader {
public UnsafeFallbackClassLoader(ClassLoader parent) {
super(new URL[0], parent);
}

@Override
public void addURL(URL url) {
super.addURL(url);
}

}

}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import org.cyclops.integrateddynamics.core.evaluate.operator.Operators;
import org.cyclops.integrateddynamics.core.evaluate.variable.ValueTypeOperator;
import org.cyclops.integratedscripting.GeneralConfig;
import org.cyclops.integratedscripting.UnsafeHelper;
import org.cyclops.integratedscripting.api.evaluate.translation.IEvaluationExceptionFactory;
import org.cyclops.integratedscripting.evaluate.translation.ValueTranslators;
import org.graalvm.polyglot.Context;
Expand All @@ -26,10 +27,18 @@
*/
public class ScriptHelpers {

private static final Engine ENGINE = Engine
.newBuilder()
.option("engine.WarnInterpreterOnly", "false")
.build();
private static final Engine ENGINE;
static {
ClassLoader c = Thread.currentThread().getContextClassLoader();
Thread.currentThread().setContextClassLoader(UnsafeHelper.makeFallbackClassloader());
try {
ENGINE = Engine.newBuilder()
.option("engine.WarnInterpreterOnly", "false")
.build();
} finally {
Thread.currentThread().setContextClassLoader(c);
}
}

public static Context createBaseContext(@Nullable Function<Context.Builder, Context.Builder> contextBuilderModifier) {
Context.Builder contextBuilder = Context
Expand Down
3 changes: 3 additions & 0 deletions src/main/resources/graaldeps.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
{
"paths": [$graaldeps]
}
Loading