When one installs a plugin from the library, the dialogue lets one choose where the plugin will go. This means res://addons is not guaranteed to be the path.
Now, if you are writing a plugin and you need to load("res://addons/myfoo/something") to get a resource ready, you can’t know where the plugin is, afaict.
I was using preload('something') which does accept relative paths, but am running into troubles with exporting the game. (long story).
Is there any way to obtain the directory of where a plugin is installed?
class_name Globs extends Object
# This const was great but...
# const PREF_AVOID_SCENE = preload("src/dabs/pref_avoid.tscn")
# ... it forces user to include the pref_avoid.tscn in the final build.
# So I needed a way to step around that issue, hence the getter
static var PREF_AVOID_SCENE:
get:
if not Engine.is_editor_hint():
return null
# TODO This absolute path will break the plugin should the user
# install to some other directory
return load("res://addons/dabber/src/dabs/pref_avoid.tscn")
I use it in other files as:
var s = Globs.PREF_AVOID_SCENE # etc.
So, Globs is like a namespace to that file and PREF_AVOID_SCENE has to be static (to avoid an instance).
The wrinkle: It won’t let me access get_script() from within a static getter (or func)!
There’s absolutely gotta be a simpler way to do this but I was thinking maybe you could use ProjectSettings.get_global_class_list() which returns an Array[Dictionary] and the dictionaries include the name and path of each global class.
So I thought you could cycle through all those dictionaries until you find one where if dictionary[“class”] == “Globs” then get dictionary[“path”].get_base_dir() to get the plugin directory. Or something like that maybe?
static var DEFAULT_SPHERE:
get:
if not Engine.is_editor_hint():
return null
var path := _get_plugin_dir()
if not path: return null
# And here I can use the path to find a resource relative to it!
return load("%s/assets/default_mesh.tres" % path)
static func _get_plugin_dir() -> String:
# ProjectSettings.get_setting returns a PackedStringArray hence cast ↓
var all:Array = ProjectSettings.get_setting("editor_plugins/enabled") as Array
# if missing, well, shizz?
if not all: return ""
var seek = all.filter(func(s): return "dabber" in s)
# if not in there, the plugin is turned off.
if not seek: return ""
# e.g. "res://addons/dabber/plugin.cfg"
var pth : String = seek[0]
pth = pth.get_base_dir()
return pth
If the plugin is disabled, one may still want to obtain the path, so try this:
class_name dabGlobals extends Object
static var DEFAULT_SPHERE:
get:
if not Engine.is_editor_hint(): return null
var p = _get_class_dir("dabGlobals")
# p → res://addons/dabber
if not p: return null
return load("%s/assets/default_mesh.tres" % p)
# This one works whether the plugin is on or off!
static func _get_class_dir(classname:StringName)->String:
var a = ProjectSettings.get_global_class_list()
var find = a.filter(func(d): return classname == d["class"])
var ret : String = ""
if not find.is_empty():
ret = find[0]["path"].get_base_dir()
return ret