Using the Godot Editor

From ΔV: Wiki

Ever since GDRE 0.9, it has been economical to use the Godot Editor to run the game to test mods instead of packaging them and launching the standalone game to test.

Mods can currently be run through two methods: placing a mod's zip in a mods folder next to the Godot executable, or manually patching the modloader to load mods from the filesystem. The latter is preferred, as it lets you more effectively modify code without repackaging it as a zip, as a mod loaded from Zip will always override code in the filesystem.

Enabling mods is as simple as setting the areModsEnabled variable to true in the ModLoader.gd file. This lets mods be loaded from a mods folder just fine, however loading mods directly from the editor requires additional patching.

A complete mod loader replacement can be found from a Github page here: https://github.com/rwqfsfasxc100/Delta-V-Useful-Files/blob/main/ModLoader.gd. Alternatively, you can copy-paste the following code to replace the ModLoader.gd file. The array addedMods lists all res:// paths to mods that you want to load. Anything commented out will not be registered. The mods in the file are used purely as an example.

extends Node

var areModsEnabled = true

var addedMods = [
#		"res://ModMenu/ModMain.gd",
#		"res://HevLib/ModMain.gd",
#		"res://No Simulation Hex/ModMain.gd",
#		"res://DerelictDelights/ModMain.gd",
#		"res://IndustriesOfEnceladusRevamp/ModMain.gd",
#		"res://Better Recon Drones/ModMain.gd",
#		"res://NTCED Parts Pack/ModMain.gd",
#		"res://Remove Ring Restrictions/ModMain.gd",
	]

const is_debugged = true

func _init():
	for arg in OS.get_cmdline_args():
		if arg == "--enable-mods":
			areModsEnabled = true

	if not areModsEnabled:
		return 

	Debug.l("ModLoader: Loading mods...")
	_loadMods()
	Debug.l("ModLoader: Done loading mods.")

	Debug.l("ModLoader: Initializing mods...")
	_initMods()
	Debug.l("ModLoader: Done initializing mods.")


var _modZipFiles = []

func _loadMods():
	var gameInstallDirectory = OS.get_executable_path().get_base_dir()
	if OS.get_name() == "OSX":
		gameInstallDirectory = gameInstallDirectory.get_base_dir().get_base_dir().get_base_dir()
	var modPathPrefix = gameInstallDirectory.plus_file("mods")

	var dir = Directory.new()
	if dir.open(modPathPrefix) != OK:
		Debug.l("ModLoader: Can't open mod folder %s." % modPathPrefix)
		return 
	if dir.list_dir_begin() != OK:
		Debug.l("ModLoader: Can't read mod folder %s." % modPathPrefix)
		return 

	while true:
		var fileName = dir.get_next()
		if fileName == "":
			break
		if dir.current_is_dir():
			continue
		var modFSPath = modPathPrefix.plus_file(fileName)
		var modGlobalPath = ProjectSettings.globalize_path(modFSPath)
		if not ProjectSettings.load_resource_pack(modGlobalPath, true):
			Debug.l("ModLoader: %s failed to load." % fileName)
			continue
		_modZipFiles.append(modFSPath)
		Debug.l("ModLoader: %s loaded." % fileName)
	dir.list_dir_end()




func _initMods():
	var initScripts = []
	for modFSPath in _modZipFiles:
		var gdunzip = load("res://vendor/gdunzip.gd").new()
		gdunzip.load(modFSPath)
		for modEntryPath in gdunzip.files:
			var modEntryName = modEntryPath.get_file().to_lower()
			if modEntryName.begins_with("modmain") and modEntryName.ends_with(".gd"):
				var modGlobalPath = "res://" + modEntryPath
				Debug.l("ModLoader: Loading %s" % modGlobalPath)
				var packedScript = ResourceLoader.load(modGlobalPath)
				initScripts.append(packedScript)

	
	for m in addedMods:
		var packedScript = ResourceLoader.load(m)
		initScripts.append(packedScript)

	initScripts.sort_custom(self, "_compareScriptPriority")

	for packedScript in initScripts:
		Debug.l("ModLoader: Running %s" % packedScript.resource_path)
		var scriptInstance = packedScript.new(self)
		add_child(scriptInstance)


func _compareScriptPriority(a, b):
	var aPrio = a.get_script_constant_map().get("MOD_PRIORITY", 0)
	var bPrio = b.get_script_constant_map().get("MOD_PRIORITY", 0)
	if aPrio != bPrio:
		return aPrio < bPrio

	
	var aPath = a.resource_path
	var bPath = b.resource_path
	if aPath != bPath:
		return aPath < bPath

	return false


func installScriptExtension(childScriptPath:String):
	var childScript = ResourceLoader.load(childScriptPath)

	
	
	
	
	
	
	
	childScript.new()

	var parentScript = childScript.get_base_script()
	var parentScriptPath = parentScript.resource_path
	Debug.l("ModLoader: Installing script extension: %s <- %s" % [parentScriptPath, childScriptPath])
	childScript.take_over_path(parentScriptPath)


func addTranslationsFromCSV(csvPath:String):
	var translationCsv = File.new()
	translationCsv.open(csvPath, File.READ)
	var TranslationParsedCsv = {}

	var translations = []

	
	var csvLine = translationCsv.get_csv_line()
	for i in range(1, csvLine.size()):
		var translationObject = Translation.new()
		translationObject.locale = csvLine[i]
		translations.append(translationObject)

	
	while not translationCsv.eof_reached():
		csvLine = translationCsv.get_csv_line()
		if csvLine.size() == 1 and csvLine[0] == "":
			break
		var translationID = csvLine[0]
		for i in range(1, csvLine.size()):
			translations[i - 1].add_message(translationID, csvLine[i])

	translationCsv.close()

	
	for translationObject in translations:
		TranslationServer.add_translation(translationObject)


func appendNodeInScene(modifiedScene, nodeName:String = "", nodeParent = null, instancePath:String = "", isVisible:bool = true):
	var newNode
	if instancePath != "":
		newNode = load(instancePath).instance()
	else :
		newNode = Node.instance()
	if nodeName != "":
		newNode.name = nodeName
	if isVisible == false:
		newNode.visible = false
	if nodeParent != null:
		var tmpNode = modifiedScene.get_node(nodeParent)
		tmpNode.add_child(newNode)
		newNode.set_owner(modifiedScene)
	else :
		modifiedScene.add_child(newNode)
		newNode.set_owner(modifiedScene)


var _savedObjects = []

func saveScene(modifiedScene, scenePath:String):
	var packed_scene = PackedScene.new()
	packed_scene.pack(modifiedScene)
	packed_scene.take_over_path(scenePath)
	_savedObjects.append(packed_scene)