Jump to content

Event/Function to detect WHEN an alias is filled?


Hoamaii

Recommended Posts

Er... I'm trying to find world position of an alias when it is filled (from a FormList) to be able to locate other surrounding references.

 

I ran this OnInit():

 

MyAlias = GetReference()

float AliasPosX = MyAlias.GetPositonX()

... then Y and Z and angles and so on...

 

I get tons of errors in my logs saying:

"Error, cannot get position X on a None Object, aborting function (...) Warning: Assigning None to a non-object variable" etc.

 

YET when calling "Game.FindClosestReferenceOfType(...)" in the same OnInit() block too, Debug tells me the game does find the custom reference I'm looking for.

 

How is it possible that a function to locate my alias aborts and a few lines further another function uses these aborted variables to actually locate another Object within the boundaries of these none-variables?!..

 

Maybe OnInit() is too early? Or the Alias is filled while OnInit() is running?

 

If so, is there a function to actually detect when my alias is filled and run GetPosition() without getting my logs bloated with aborted functions? (...aborted functions that apparently worked anyway... :blink:)

 

Thanks! :)

Link to comment
Share on other sites

Thanks DarthWayne, yeah it struck me this morning when I woke up - in my previous versions, I started OnInit() with:

 

If Ref()

; run my functions

EndIf

 

When I modified the script, I stupidly forgot it... :rolleyes:

 

Still my question remains about onInit() in Alias scripts: when does onInit() run exactly? When the quest starts, even if all aliases have not been filled? or when the alias has been resolved?

 

Testing with Debug makes me think it runs on starting the quest. If so, onInit() is not the place I can retrieve the position variables I need.

 

How could I detect when an alias is filled without polling with "RegisterForSingleUpdate()"?

Link to comment
Share on other sites

Alias are filled when the quest starts. I never used OnInit with an alias, but my guess would be that the events fire when the event of the reference fires.

 

If you want to make sure, that a function is called directly after the alias has been filled and you are filling them with a specific reference, you could fill them manually:

 

1. Add properties containing the references to your quest script

2. Mark the aliases as optional and don't fill them in the quest window

3. Fill the Aliases using "alias.forceRefTo(reference)" in your startup stage

4. execute your function afterwards

Link to comment
Share on other sites

OnInit() fires when you first install the mod even if the quest hasn't started yet and again when the quest does actually start, (possibly when you start a new game? I havn't tried that though.) The only way to get it to fire again is Stop() and Start() the quest again.

 

Forcing an alias into a running quest with ForceRefTo() won't fire it to my knowledge, at least its never worked for me which makes sense since its only supposed to fire On Initialisation.

Edited by soupdragon1234
Link to comment
Share on other sites

@ DarthWayne,

 

Thanks for the suggestion but the FormList I use to fill my aliases lists dozens of forms and I need the aliases to fill with whatever form the game finds around - even if it's 10 refs of the same form. Using ForceRefTo(Ref) in a start up stage would sort of defeat that, wouldn't it?

 

@ SoupDragon, thanks for the info, I didn't know that onInit() fired even if the quest had not started but it makes sense that aliases scripts behave like any other script I guess.

 

 

In this case, my aliases are furniture forms - so what you guys are telling me is that there is no way for me to know when an alias has been filled other than calling "OnActivate" (for instance) in the Alias script and hoping that some actor around may (or may not) activate it so that I can finally have GetPositionX() running?

 

Either that or having "RegisterForUpdate()" looping from the moment OnInit() fired until my alias is actually filled?

Link to comment
Share on other sites

It's best to ignore the OnInit function for the aliases themselves. It only fires once and probably before the alias is filled. But that doesn't mean all is hopeless. You can create your own initialization function and call it when the alias is filled. (Technically you can still use OnInit and just call it like any other function.)

 

Aliases only get filled in one of two ways:

 

1. Auto-fill on quest start

 

In this case the quest script OnInit block runs after all of the aliases have been filled. So just use a little loop and cycle through all of the quests aliases and calling your initialization function on each. (You'll still have to check to see if the alias has actually been filled.)

 

2. Filled by script with ForceRefTo

 

Assuming it's your code that's doing the filling, you can simply call your initialization function right after you fill the ref.

 

The only problem case is if some other mod fills the reference via a script and then doesn't call your initialization function. (I haven't tried it but you might be able to override the ForceRefTo function to capture even that case.)

Link to comment
Share on other sites

Thanks, Cdcooley :)

 

So far, I've tested my mod along with other mods loaded which use ForceRefTo() on the same forms I do and my aliases scripts run fine even though I don't use ForceRefTo(), so I guess I'm safe on that matter. (perhaps checking "allow reserved" helps here?)

 

I still have a question about what you're saying though, if you can bear with me (French here, sometimes I still don't get the "scripting" language as clearly as it may sound to English native speakers, sorry):

 

When you say "auto-fill", you mean no specific reference is set up in the alias tab, right? The quest fills the aliases with the first matching refs it finds? That'd be the case I'm in with this, using 'Find Matching Reference In Loaded Area' + 'Closest'. And when you say 'quest script', you mean the script attached to the quest itself (in the 'script' tab), not the Alias script, right?

 

So if I understand you correctly, you're saying that the quest script only runs onInit() when ALL the aliases have been filled? That notion troubles me a bit, I have about 20 or 25 aliases in my radiant quest and in many cases, the game may only find 4 or 5 of them in the loaded area, thus never actually fill all 20 or 25 aliases. That'd mean in this example, my quest script would never run?

 

I'm still having trouble grasping when OnInit() runs really. My understanding is that all scripts initialize when they first start running in game, whether or not you use onInit(). Yet, with CK edited refs it seems to fire as soon as you first load the game, with placed refs it fires the 1st time that ref is loaded in game, with quests with auto-filled aliases you're saying it fires only once all aliases are filled... So that'd mean in the type of quests I'm working on, Alias scripts would run before the quest script even though the quest has obviously started already as soon as it filled the 1st alias?..

 

I'm sorry if I may sound obtuse, I'm not, really (at least I don't think I am ;)) and in truth I'm actually more concerned with my aliases scripts that the quest script anyway, it's just that, well, if someone takes some of his time to answer some questions I ask, the least I can do is listen carefully and fully understand what he's saying... Well, I understand what you're saying I think, it's just that it raises more questions :confused:

 

And now I feel stupid 'cause I realize by asking more questions, I'm taking more of your time... Er... sorry. :rolleyes:

Link to comment
Share on other sites

I don't think the problem is in the English to French translation. It's the "code" to English that's the problem. :smile:

I used auto-fill to mean any time the quest aliases are filled by the game itself as the quest starts (based on any conditions set in the CK). In other words, any time you aren't using ForceRefTo() from some script.

 

There are some other things that happen (like setting quest stages) but here's how I understand the sequence of events related to quests and scripts.

  • The quest gets loaded - its script gets an OnInit event.
  • The quest begins to start.
  • Aliases get loaded - each alias script gets an OnInit event (some aliases get filled as they are loaded)
  • The rest of the aliases get filled (if possible)
  • The quest itself gets another OnInit event
  • The quest is now running.

Every script in the game gets initialized (and the OnInit event code is run if it exists) as soon as that object is first processed by the game. The scripts on aliases get the OnInit event before the alias gets filled in many cases. If the alias creates the reference then it seems the script is run after the reference is created. And if the alias references a specific (already persistent) object in the game I think it will be filled before the script is run too. But in the other cases the OnInit for the alias script gets called before the reference is found.

For quests the OnInit happens when the game first loads the quest which is usually before any of the aliases are filled. But quest scripts are the only ones that I know of that can get the OnInit event multiple times. Every time you restart the quest the OnInit event in the quest's main script will get called again. The quest's OnInit event will run when all of the aliases have been filled or have had a chance to be filled. If some of the aliases are optional then that won't keep the quest's script from getting the OnInit event. But there won't be any aliases that get filled after that OnInit event unless you stop and restart the quest (and you would get a new OnInit if you did that anyway).

So if you're using SKSE you can use something like this from the quest's main script to force all of the alias scripts to re-run their OnInit event.

Event OnInit()
	int idx  = GetNumAliases()
	While idx > 0
		idx -= 1
		ReferenceAlias nthAlias = GetNthAlias(idx) as ReferenceAlias
		If nthAlias
			nthAlias.OnInit()
		EndIf
	EndWhile
EndEvent

You'll still need to check in each of the alias OnInit() events if the reference is actually filled.

If you're not using SKSE then you can simply create properties in the quest's main script and use them to call the alias script OnInit().

ReferenceAlias Property Alias_1 Auto
ReferenceAlias Property Alias_2 Auto
ReferenceAlias Property Alias_3 Auto
ReferenceAlias Property Alias_4 Auto
ReferenceAlias Property Alias_5 Auto

Event OnInit()
	Alias_1.OnInit()
	Alias_2.OnInit()
	Alias_3.OnInit()
	Alias_4.OnInit()
	Alias_5.OnInit()
EndEvent

I hope that helps.

Link to comment
Share on other sites

Yeah, that helps a lot putting things at the right place in my head. + It makes perfect sense and that's super clear, thanks A LOT, Cdcooley, I really appreciate you lending me some of your time here :D

 

Plus the tip to force aliases' scripts to rerun OnInit() is very interesting - I had no idea you could do that. I knew that it runs again whenever the quest stops and starts again (thank Papyrus for Debug - it's great to keep track of what's going on) and in fact I use these reruns to actualize some variables from one instance of the quest to another - another reason why I was so focused on the onInit() event. I already know know where I'll be using that tip and for what. Thank you!

 

Yeah, I use SKSE, it's a great tool, with so many new functions it makes (almost) everything possible.

 

I'm trying to learn how to use arrays too, spent 2 hours reading the wiki's pages about it a couple of days ago and studying other guys' scripts. I need to learn how to write more compact code, I never copy-paste from anybody else' s script, I like to write my owns, that's the only way to know what you're doing. But I sure do appreciate the help I'm getting in the forum.

 

Kudos for your time, cdcooley, and thanks again. Cheers from Paris!

Link to comment
Share on other sites

  • Recently Browsing   0 members

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