resources not found in plugin

Answered

I’m developing a gradle based plugin to integrate JmonkeyEngine into IntelliJ. It is a java game engine.

When the game engine starts it loads resources from the resources folder such as models, fonts, etc. When I start the engine in a IntelliJ plugin the resources are not found.

Ive tried including the files as a “fat jar” and even putting the files in my plugin but they are never found. It seems any attempt to get files from a resources folder I never found, even though I can see them in the built /build/lib/plugin.jar.

Is there any reason the engine can’t find it’s own resources that it can normally find when run outside a plugin environment?

I am able to specify classpath locators and filelocators. Is there any classpath or path I can specify so the resources can be found?

I’ve spent 3 days reading through various posts and trying to figure this out. Any advice would be very much appreciated.

8 comments
Comment actions Permalink

How are resources loaded exactly from within the engine? Do they use current class as context?

0
Comment actions Permalink

Hi.

I found a "workaround" after a lot of debugging. I will try to explain as best I can.

Jmonkey has an assetLoader and you can add a "basePath" that you can add to an assetLoader to load models/textures/etc. So in a jar, if your textures are in a folder "/Textures/" you can specify that as a "baseDir" to locate them. But most commonly the baseDir is "/" - and that is the problem.

Normally that "just works" when jmonkey is not being used inside an intellij plugin. But if you specify "/" as the baseDir from within an intellij plugin, for some reason unknown to me, it no longer treats that path as "jar://mypath/myJar.jar!/" and instead becomes a file path "file://mypath/. This means if no folder is specified it won't work, but if i DO specify a folder it works as intended (the path stays "jar://mypath/myJar.jar!/myfolder").

My workaround was to specify a folder and not "/" (e.g. "/folder/") and then prepend "../" to any resource request - which is a little bit hacky, but it works flawlessly.

0
Comment actions Permalink

Hi,

please aware that if you run/debug your plugin in the IntelliJ Plugin environment, getClassLoader().getResource() returns a file URL. (file:/...), if you run normally it returns a jar URL. (jar:file:/..). Plugin environment doesn't create a plugin jar.

Use instead log messages and run plugin in full IntelliJ.

0
Comment actions Permalink

The resources are loaded like so:

if (JmeSystem.isLowPermissions()){
url = ClasspathLocator.class.getResource("/" + name);
}else{
url = Thread.currentThread().getContextClassLoader().getResource(name);
}

 

And by doing that, it does not find any resources. This is becoming a little bit of a headache for me to constantly work around. Is there something I'm missing maybe?

0
Comment actions Permalink

So does the workaround you wrote above work or not? Why do you need to run the game engine _inside_ the plugin's code?

0
Comment actions Permalink

It does work, but every time a classloader is concerned I have to rewrite that part of the code so it uses the plugin classloader instead. So when the engine loads, it detects the operating system to decide which natives to provide. I have to rewrite this part now becuase of the classloader issue.

I mean I can always find ways "around" the issue, I'd just like to know if there is something I don't know of that makes it so I don't have to keep working around the issue.

The engine is a service of the plugin, and I need the engine so I can use it to view models, particles, animations, etc.. They are displayed in a swing panel like below. In the future other plugins will depend on this plugin and use that service, too. I usually start the engine by calling the service in a PreLoadActivity. How would one go about not loading it inside the plugins code?

 

0
Comment actions Permalink

Indeed the plugin CL must be used in this scenario.

PreloadActivity might be replaced with com.intellij.openapi.startup.StartupActivity which can decide whether or not current project requires engine or not (to avoid eager loading of engine)

0
Comment actions Permalink

For anyone experiencing the same problem. I solved it by using the using the Classloader of the thirdparty class containing the code above and setting it on the current thread. Something like the following:

- resource
---- my.properties

 

 

Thread.currentThread().setContextClassLoader(org.your.clazz.ProblemCode.class.getClassLoader());
InputStream resourceStream = Thread.currentThread().getContextClassLoader().getResourceAsStream("my.properties");
0

Please sign in to leave a comment.