Jump to content

[LE] Multiple mods with soft dependency to the same resource


bcsp

Recommended Posts

Hi all,
I posted this over on LL but I feel the need to post it here as well to 'cover more ground'.
There appears to be an issue with Bethesdas/SKSEs code when 2 mods make a soft dependency check to the same resource but that resource is not installed. To demonstrate I've created 3 tiny mods. One 'master' mod that contains the resource we want to access and two 'soft link' mods that try to access a function in the master mod.
Test yourself with mod organizer.
1. Install and enable all mods
2. Start a new game, save and reload it. Quit and check your logs. Both mods should be running ok.
3. Disable the master mod in the left hand side of MO (IE. remove the scripts). Start a new game and save a reload. Quit and check your log. Only one mod will be running even though they are essentially identical.
Here's the code:
Master:
Scriptname _TM_MasterScript extends Quest  

String Function _TM_MasterFunction()
	Return "Master String"
EndFunction

SoftLink Mod A

Scriptname _TM_SoftLinkA_Script extends ReferenceAlias

Event OnInit()
	RegisterForSingleUpdate(1.0)
EndEvent

Event OnPlayerLoadGame()
	_TM_MasterScript Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as _TM_MasterScript
	If Master
		Debug.MessageBox("_TM_: Soft Link A - " + Master._TM_MasterFunction())
		Debug.Trace("_TM_: Soft Link A - " + Master._TM_MasterFunction())
	Else
		Debug.MessageBox("_TM_: Soft Link A - Master esp not found")
		Debug.Trace("_TM_: Soft Link A - Master esp not found")
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link A: Mod A running ok")
	RegisterForSingleUpdate(1.0)
EndEvent

SoftLink Mod B

Scriptname _TM_SoftLinkB_Script extends ReferenceAlias  

Event OnInit()
	RegisterForSingleUpdate(1.0)
EndEvent

Event OnPlayerLoadGame()
	_TM_MasterScript Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as _TM_MasterScript
	If Master
		Debug.MessageBox("_TM_: Soft Link B - " + Master._TM_MasterFunction())
		Debug.Trace("_TM_: Soft Link B - " + Master._TM_MasterFunction())
	Else
		Debug.MessageBox("_TM_: Soft Link B - Master esp not found")
		Debug.Trace("_TM_: Soft Link B - Master esp not found")
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link B: Mod B running ok")
	RegisterForSingleUpdate(1.0)
EndEvent
Here's a papyrus log with all mods active and installed:
The same is true if the masters scripts are installed but the esp is not active.

Line 814: [09/01/2018 - 11:10:07AM] _TM_: Soft Link B: Mod B running ok
Line 815: [09/01/2018 - 11:10:07AM] _TM_: Soft Link A: Mod A running ok
Line 1258: [09/01/2018 - 11:10:08AM] _TM_: Soft Link B: Mod B running ok
Line 1259: [09/01/2018 - 11:10:08AM] _TM_: Soft Link A: Mod A running ok
Line 1321: [09/01/2018 - 11:10:10AM] _TM_: Soft Link B: Mod B running ok
Line 1322: [09/01/2018 - 11:10:10AM] _TM_: Soft Link A: Mod A running ok
Line 1383: [09/01/2018 - 11:10:11AM] _TM_: Soft Link B: Mod B running ok
Line 1384: [09/01/2018 - 11:10:11AM] _TM_: Soft Link A: Mod A running ok
Line 1524: [09/01/2018 - 11:10:12AM] _TM_: Soft Link A: Mod A running ok
Line 1525: [09/01/2018 - 11:10:12AM] _TM_: Soft Link B: Mod B running ok
Line 1580: [09/01/2018 - 11:10:13AM] _TM_: Soft Link B: Mod B running ok
Line 1581: [09/01/2018 - 11:10:13AM] _TM_: Soft Link A: Mod A running ok
Line 1897: [09/01/2018 - 11:10:16AM] _TM_: Soft Link B - Master String
Line 1898: [09/01/2018 - 11:10:16AM] _TM_: Soft Link A - Master String
Line 2597: [09/01/2018 - 11:10:18AM] _TM_: Soft Link B: Mod B running ok
Line 2637: [09/01/2018 - 11:10:19AM] _TM_: Soft Link A: Mod A running ok
Line 2639: [09/01/2018 - 11:10:19AM] _TM_: Soft Link B: Mod B running ok
Line 2700: [09/01/2018 - 11:10:20AM] _TM_: Soft Link A: Mod A running ok
Line 2714: [09/01/2018 - 11:10:20AM] _TM_: Soft Link B: Mod B running ok
Line 2844: [09/01/2018 - 11:10:21AM] _TM_: Soft Link A: Mod A running ok
Line 2863: [09/01/2018 - 11:10:21AM] _TM_: Soft Link B: Mod B running ok

Here's a papyrus log when the master is not installed but both soft link mods are installed:

Line 30: [09/01/2018 - 11:12:46AM] Cannot open store for class "_tm_masterscript", missing file?
Line 31: [09/01/2018 - 11:12:46AM] Error: Unable to link types associated with function "OnPlayerLoadGame" in state "" on object "_TM_SoftLinkB_Script".
Line 1614: [09/01/2018 - 11:13:08AM] _TM_: Soft Link A: Mod A running ok
Line 1687: [09/01/2018 - 11:13:09AM] _TM_: Soft Link A: Mod A running ok
Line 1735: [09/01/2018 - 11:13:11AM] _TM_: Soft Link A: Mod A running ok
Line 1788: [09/01/2018 - 11:13:12AM] _TM_: Soft Link A: Mod A running ok
Line 1857: [09/01/2018 - 11:13:13AM] _TM_: Soft Link A: Mod A running ok
Line 1911: [09/01/2018 - 11:13:14AM] _TM_: Soft Link A: Mod A running ok
Line 2046: [09/01/2018 - 11:13:17AM] warning: Unable to get type _TM_SoftLinkB_Script referenced by the save game. Objects of this type will not be loaded.
Line 2048: [09/01/2018 - 11:13:17AM] warning: Could not find type _TM_SoftLinkB_Script in the type table in save
Line 2070: [09/01/2018 - 11:13:17AM] ERROR: File "_TM_Master.esp" does not exist or is not currently loaded.
Line 2073: [alias PlayerAlias on quest _TM_SoftLinkA_Quest (41000D62)]._TM_SoftLinkA_Script.OnPlayerLoadGame() - "_TM_SoftLinkA_Script.psc" Line 8
Line 2073: [alias PlayerAlias on quest _TM_SoftLinkA_Quest (41000D62)]._TM_SoftLinkA_Script.OnPlayerLoadGame() - "_TM_SoftLinkA_Script.psc" Line 8
Line 2073: [alias PlayerAlias on quest _TM_SoftLinkA_Quest (41000D62)]._TM_SoftLinkA_Script.OnPlayerLoadGame() - "_TM_SoftLinkA_Script.psc" Line 8
Line 2109: [09/01/2018 - 11:13:17AM] _TM_: Soft Link A - Master esp not found
Line 2513: [09/01/2018 - 11:13:19AM] _TM_: Soft Link A: Mod A running ok
Line 2774: [09/01/2018 - 11:13:20AM] _TM_: Soft Link A: Mod A running ok
Line 2819: [09/01/2018 - 11:13:21AM] _TM_: Soft Link A: Mod A running ok
Line 2901: [09/01/2018 - 11:13:22AM] _TM_: Soft Link A: Mod A running ok

The first mod in the load order 'wins' and continues running as expected. The mod lower in the load order has it's scripts dumped and stops working entirely.
I'm a guy that likes to bring mods together where I can and have mods as more than 'a collection of islands' but with this issue I not only need to account for my own mod but every other mod and load order out there and it's just too much hassle.
So questions:
1. First. Is my implementation ok? Maybe I've got something wrong.
2. Why the heck does this happen and what exactly is causing it?
Not being able to upload 7z files is a bit of a PITA. Here's the thread on LL if people are allergic to filedropper: https://www.loverslab.com/topic/106848-multiple-mods-with-soft-dependency-to-the-same-resource/
Edited by bcsp
Link to comment
Share on other sites

You don't need separate mods to trigger that case. That same basic thing happens even if it's just two different scripts in the same mod.

 

Basically it's always unsafe to use an external, potentially non-existent script as a variable type in any script. If that external script doesn't exist the game will almost always flag that as a critical error and refuse to process that script.

 

I'm surprised that your Mod A script is running because from my experience it should be having the same problem as Mod B. From your case I now assume that in some situations the very first script which tries to reference the non-existent script can continue to work (because whatever tagging that blocks the scripts happens after it had already started running). Or alternately it's because you skip straight to the OnUpodate from the OnInit block and you loaded Mod A for the first time in that test case?

 

You could try this variation to see if it makes a different (but I doubt it).

Scriptname _TM_SoftLinkB_Script extends ReferenceAlias  

Event OnInit()
	OnPlayerLoadGame()
EndEvent

Event OnPlayerLoadGame()
	Quest Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as Quest
	If Master
		Debug.MessageBox("_TM_: Soft Link B - " + (Master as _TM_MasterScript)._TM_MasterFunction())
		Debug.Trace("_TM_: Soft Link B - " + (Master as _TM_MasterScript)._TM_MasterFunction())
	Else
		Debug.MessageBox("_TM_: Soft Link B - Master esp not found")
		Debug.Trace("_TM_: Soft Link B - Master esp not found")
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link B: Mod B running ok")
	RegisterForSingleUpdate(1.0)
EndEvent

In my own mods I avoid referencing external scripts (from other mods) by their unique name whenever possible. In the rare cases where I can't do that I always keep things related to that other mod's script isolated into a unique script in my mod and then handle the "fallback" case if the mod isn't loaded in a completely different script.

 

So to implement your idea I would have used a pair of scripts on that object:

Scriptname _TM_SoftLinkAMasterFound_Script extends ReferenceAlias

Event OnInit()
	OnPlayerLoadGame()
EndEvent

Event OnPlayerLoadGame()
	_TM_MasterScript Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as _TM_MasterScript
	If Master
		Debug.MessageBox("_TM_: Soft Link A - " + Master._TM_MasterFunction())
		Debug.Trace("_TM_: Soft Link A - " + Master._TM_MasterFunction())
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link A: Mod A running ok and Master is loaded")
	RegisterForSingleUpdate(1.0)
EndEvent
Scriptname _TM_SoftLinkAMasterMissing_Script extends ReferenceAlias

Event OnInit()
	OnPlayerLoadGame()
EndEvent

Event OnPlayerLoadGame()
	Quest Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as Quest
	If !Master
		Debug.MessageBox("_TM_: Soft Link A - Master esp not found")
		Debug.Trace("_TM_: Soft Link A - Master esp not found")
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link A: Mod A running but Master not loaded")
	RegisterForSingleUpdate(1.0)
EndEvent

Of course, I would always avoid OnUpdate checks whenever possible, but the same logic applies if you're adding checks for any other type of event.

Link to comment
Share on other sites

 

Thank you for taking the time to reply.

 

Ok, the fact that it was working for one mod but not both mods was really throwing me off. I'm trying to get my head around what you've said. So based on my new-found understanding:

 

I can run preliminary checks if mods exist with Game.GetFormFromFile(x) as any built in type - Quest, Actor, etc- from the main 'bulk' of a script without causing it to stop.

But if I want to access a script attached to the object then the attempt to access the external script should be isolated into a script of it's own. Each soft dependency that tries to access an external script would each need their own separated script. If there was say 2 external functions I wanted to use from the same mod they could both be put into the same isolated script. IE. One isolated script per external mod.

 

Here's a modified version I came up with:

 

Master (Not changed):

Scriptname _TM_MasterScript extends Quest  

String Function _TM_MasterFunction()
	Return "Master String"
EndFunction

SoftLink Mod A:

Scriptname _TM_SoftLinkA_Script extends ReferenceAlias

_TM_SoftLinkMaster Property SoftLinkMaster Auto

Event OnInit()
	RegisterForSingleUpdate(1.0)
EndEvent

Event OnPlayerLoadGame()
	Quest Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as Quest
	If Master
		Debug.MessageBox("_TM_: Soft Link A - " + SoftLinkMaster.GetString(Master))
		Debug.Trace("_TM_: Soft Link A - " + SoftLinkMaster.GetString(Master))
	Else
		Debug.MessageBox("_TM_: Soft Link A - Master esp not found")
		Debug.Trace("_TM_: Soft Link A - Master esp not found")
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link A: Mod A running ok")
	RegisterForSingleUpdate(1.0)
EndEvent

SoftLink Mod B:

Scriptname _TM_SoftLinkB_Script extends ReferenceAlias  

_TM_SoftLinkMaster Property SoftLinkMaster Auto

Event OnInit()
	RegisterForSingleUpdate(1.0)
EndEvent

Event OnPlayerLoadGame()
	Quest Master = Game.GetFormFromFile(0x00000d62, "_TM_Master.esp") as Quest
	If Master
		Debug.MessageBox("_TM_: Soft Link B - " + SoftLinkMaster.GetString(Master))
		Debug.Trace("_TM_: Soft Link B - " + SoftLinkMaster.GetString(Master))
	Else
		Debug.MessageBox("_TM_: Soft Link B - Master esp not found")
		Debug.Trace("_TM_: Soft Link B - Master esp not found")
	EndIf
EndEvent

Event OnUpdate()
	Debug.Trace("_TM_: Soft Link B: Mod B running ok")
	RegisterForSingleUpdate(1.0)
EndEvent

Interface Script. Both mod A & B use this:

ScriptName _TM_SoftLinkMaster extends Quest

String Function GetString(Quest Master)
	_TM_MasterScript MasterScript = Master as _TM_MasterScript
	Return MasterScript._TM_MasterFunction()
EndFunction

Seems to work fine. The updates from both mods continue ok with and without the master mod installed.

Logs:

With Master mod installed:

 

 

Line 803: [09/03/2018 - 04:24:38PM] _TM_: Soft Link A: Mod A running ok
Line 805: [09/03/2018 - 04:24:38PM] _TM_: Soft Link B: Mod B running ok
Line 1260: [09/03/2018 - 04:24:39PM] _TM_: Soft Link A: Mod A running ok
Line 1261: [09/03/2018 - 04:24:39PM] _TM_: Soft Link B: Mod B running ok
Line 1336: [09/03/2018 - 04:24:40PM] _TM_: Soft Link A: Mod A running ok
Line 1337: [09/03/2018 - 04:24:40PM] _TM_: Soft Link B: Mod B running ok
Line 1392: [09/03/2018 - 04:24:41PM] _TM_: Soft Link A: Mod A running ok
Line 1393: [09/03/2018 - 04:24:41PM] _TM_: Soft Link B: Mod B running ok
Line 1530: [09/03/2018 - 04:24:42PM] _TM_: Soft Link A: Mod A running ok
Line 1531: [09/03/2018 - 04:24:42PM] _TM_: Soft Link B: Mod B running ok
Line 1588: [09/03/2018 - 04:24:43PM] _TM_: Soft Link B: Mod B running ok
Line 1590: [09/03/2018 - 04:24:43PM] _TM_: Soft Link A: Mod A running ok
Line 2217: [09/03/2018 - 04:24:49PM] _TM_: Soft Link A - Master String
Line 2218: [09/03/2018 - 04:24:49PM] _TM_: Soft Link B - Master String
Line 2502: [09/03/2018 - 04:24:50PM] _TM_: Soft Link B: Mod B running ok
Line 2503: [09/03/2018 - 04:24:50PM] _TM_: Soft Link A: Mod A running ok
Line 2570: [09/03/2018 - 04:24:51PM] _TM_: Soft Link B: Mod B running ok
Line 2571: [09/03/2018 - 04:24:51PM] _TM_: Soft Link A: Mod A running ok
Line 2628: [09/03/2018 - 04:24:52PM] _TM_: Soft Link B: Mod B running ok
Line 2629: [09/03/2018 - 04:24:52PM] _TM_: Soft Link A: Mod A running ok

Without master mod installed:

 

 

Line 30: [09/03/2018 - 04:05:23PM] Cannot open store for class "_tm_masterscript", missing file?
Line 988: [09/03/2018 - 04:06:26PM] _TM_: Soft Link B: Mod B running ok
Line 990: [09/03/2018 - 04:06:26PM] _TM_: Soft Link A: Mod A running ok
Line 1655: [09/03/2018 - 04:06:27PM] _TM_: Soft Link A: Mod A running ok
Line 1656: [09/03/2018 - 04:06:27PM] _TM_: Soft Link B: Mod B running ok
Line 1903: [09/03/2018 - 04:06:28PM] _TM_: Soft Link A: Mod A running ok
Line 1904: [09/03/2018 - 04:06:28PM] _TM_: Soft Link B: Mod B running ok
Line 2017: [09/03/2018 - 04:06:29PM] _TM_: Soft Link A: Mod A running ok
Line 2019: [09/03/2018 - 04:06:29PM] _TM_: Soft Link B: Mod B running ok
Line 2090: [09/03/2018 - 04:06:30PM] _TM_: Soft Link B: Mod B running ok
Line 2091: [09/03/2018 - 04:06:30PM] _TM_: Soft Link A: Mod A running ok
Line 2137: [09/03/2018 - 04:06:31PM] _TM_: Soft Link A: Mod A running ok
Line 2139: [09/03/2018 - 04:06:31PM] _TM_: Soft Link B: Mod B running ok
Line 2341: [09/03/2018 - 04:06:36PM] ERROR: File "_TM_Master.esp" does not exist or is not currently loaded.
Line 2344: [alias PlayerAlias on quest _TM_SoftLinkB_Quest (42000D62)]._TM_SoftLinkB_Script.OnPlayerLoadGame() - "_TM_SoftLinkB_Script.psc" Line 10
Line 2344: [alias PlayerAlias on quest _TM_SoftLinkB_Quest (42000D62)]._TM_SoftLinkB_Script.OnPlayerLoadGame() - "_TM_SoftLinkB_Script.psc" Line 10
Line 2344: [alias PlayerAlias on quest _TM_SoftLinkB_Quest (42000D62)]._TM_SoftLinkB_Script.OnPlayerLoadGame() - "_TM_SoftLinkB_Script.psc" Line 10
Line 2345: [09/03/2018 - 04:06:36PM] ERROR: File "_TM_Master.esp" does not exist or is not currently loaded.
Line 2348: [alias PlayerAlias on quest _TM_SoftLinkA_Quest (41000D62)]._TM_SoftLinkA_Script.OnPlayerLoadGame() - "_TM_SoftLinkA_Script.psc" Line 10
Line 2348: [alias PlayerAlias on quest _TM_SoftLinkA_Quest (41000D62)]._TM_SoftLinkA_Script.OnPlayerLoadGame() - "_TM_SoftLinkA_Script.psc" Line 10
Line 2348: [alias PlayerAlias on quest _TM_SoftLinkA_Quest (41000D62)]._TM_SoftLinkA_Script.OnPlayerLoadGame() - "_TM_SoftLinkA_Script.psc" Line 10
Line 2384: [09/03/2018 - 04:06:36PM] _TM_: Soft Link B - Master esp not found
Line 2385: [09/03/2018 - 04:06:36PM] _TM_: Soft Link A - Master esp not found
Line 3043: [09/03/2018 - 04:06:39PM] _TM_: Soft Link A: Mod A running ok
Line 3044: [09/03/2018 - 04:06:39PM] _TM_: Soft Link B: Mod B running ok
Line 3113: [09/03/2018 - 04:06:40PM] _TM_: Soft Link A: Mod A running ok
Line 3114: [09/03/2018 - 04:06:40PM] _TM_: Soft Link B: Mod B running ok
Line 3315: [09/03/2018 - 04:06:41PM] _TM_: Soft Link B: Mod B running ok
Line 3316: [09/03/2018 - 04:06:41PM] _TM_: Soft Link A: Mod A running ok
Line 3512: [09/03/2018 - 04:06:42PM] _TM_: Soft Link B: Mod B running ok
Line 3513: [09/03/2018 - 04:06:42PM] _TM_: Soft Link A: Mod A running ok

 

 

 

It also appears to work if the master mod was not initially installed but then is installed mid-game which is great.

Does this look ok to you? Thanks again for the help. I really appreciate it.

Link to comment
Share on other sites

Yes, that's actuall what I usually implement when I run into these situations but it somehow seemed more complicated to explain doing it that way working from your example. So I'm glad you not only realized that would work but posted the example I couldn't quite create when I responded.

 

And I agree it's a very quirky thing that isn't well documented. Hopefully other people will find this thread in the future when they run into this problem.

Link to comment
Share on other sites

  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...