Random object from my mod has wrong load order index!? (Also

Post » Tue Nov 20, 2012 5:22 am

So, one of my quests has had issues for a while where for some of my testers, a certain script wasn't firing. It would happen. I'd release a new version, it would suddenly work for some of them, and it's been going on and off for a few months now. It's a simple script on an object that advances a quest stage when the player picks the object up off a dead body.

I started wondering what exactly was failing, as the script was written just fine and should always work, and then one of my testers took this screenshot: http://i1118.photobucket.com/albums/k609/AlexanderJVelicky/2012102200005.jpg

Notice anything? Everything from the quest, all aliases, have a load-order-index of 07. Except one. The Lexicon (The object who's script is failing randomly) has a load order index of FF... What?

Now I went ingame and looked at it, and it was that way for me too. Then I looked at it was that way for every single created-in alias in my entire mod. Is this normal? Is FF the engine reserved index or something, and it's created by the engine so it does that?

If it is normal, does anyone else know what might be causing this issue? Here's the script:

Scriptname FSKR_FSMQ01LexiconSCRIPT extends ObjectReferenceQuest Property FSMQ01  AutoObjectReference Property PlayerRef AutoEvent OnContainerChanged(ObjectReference akNewContainer, ObjectReference akOldContainer)If (akNewContainer == PlayerRef) && (FSMQ01.GetStage() < 10)  If FSMQ01.IsObjectiveDisplayed(5)   FSMQ01.SetObjectiveCompleted(5)  EndIf  FSMQ01.SetObjectiveDisplayed(10)  If (FSMQ01.GetStage() == 5)   FSMQ01.SetStage(10)  Else   FSMQ01.SetStage(11)  EndIfEndIfEndEvent

Now I can't figure out why it randomly wont work for them... I saw the FF thing in the screenshot and thought that was surely it, but now it seems to be a normal thing?

Any ideas?
AJV
User avatar
Ann Church
 
Posts: 3450
Joined: Sat Jul 29, 2006 7:41 pm

Post » Tue Nov 20, 2012 7:24 am

Instead of PlayerRef use Game.GetPlayer() it's a shortcut for pointing to the player.

(akNewContainer == Game.GetPlayer())

Another error might be the quest not starting at all, how are you starting the quest? If the quest fails to start your first IF will never fire.

EDIT: forget the quest part, the image shows "Running"
User avatar
Gemma Archer
 
Posts: 3492
Joined: Sun Jul 16, 2006 12:02 am

Post » Tue Nov 20, 2012 12:23 am

Instead of PlayerRef use Game.GetPlayer() it's a shortcut for pointing to the player.

Using a PlayerRef property is about 1000x faster than resolving Game.GetPlayer(). See here: http://www.gamesas.com/topic/1383987-performance-characteristics-of-papyrus-functions-and-operations/

Alex - I will check my RefIDs for my Aliases when I get home. That seems odd. That shouldn't happen by default because that means that ReferenceAliases with the same FormID in the lower bits would be mutually exclusive.

I'm sure you've already tried this, but does this happen on a new game as well?

Edit: I confused FormID with RefID above. So really the game should be smart enough to assign unique RefIDs regardless. I don't think that's a vector for problems. I'll still check my mods when I get home.
User avatar
Code Affinity
 
Posts: 3325
Joined: Wed Jun 13, 2007 11:11 am

Post » Mon Nov 19, 2012 10:45 pm

Using a PlayerRef property is about 1000x faster than resolving Game.GetPlayer(). See here: http://www.gamesas.com/topic/1383987-performance-characteristics-of-papyrus-functions-and-operations/
It does not matter.
It's not that Game.GetPlayer() takes 1k more CPU time, it's just that your script is suspended (is sleeping in the waiting queue) until the next frame. Does it matter here? Not at all, the stage will just be updated one frame later. So why bother with an alias and such? It confuses the code for no benefit, and increases the chance of a bug (alias not assigned in CK or called from OnInit when it's not updated yet). This is objectively bad practice.
Papyrus has real performance and concurrency problems but 90% of what I read on those forums should have better been never written. Not necessarily their fault: papyrus is a very unusual architecture and one does not suspect it unless he investigated it. This is also a very difficult platform that looks simple.
User avatar
jessica breen
 
Posts: 3524
Joined: Thu Aug 03, 2006 1:04 am

Post » Tue Nov 20, 2012 9:09 am

It does not matter.
It's not that Game.GetPlayer() takes 1k more CPU time, it's just that your script is suspended (is sleeping in the waiting queue) until the next frame. Does it matter here? Not at all, the stage will just be updated one frame later. So why bother with an alias and such? It confuses the code for no benefit, and increases the chance of a bug (alias not assigned in CK or called from OnInit when it's not updated yet). This is objectively bad practice.
Papyrus has real performance and concurrency problems but 90% of what I read on those forums should have better been never written. Not necessarily their fault: papyrus is a very unusual architecture and one does not suspect it unless he investigated it. This is also a very difficult platform that looks simple.

I'm not sure what you're talking about.

PlayerRef is a property, not an alias. The property is filled at compile-time (in the CK). It has nothing to do with an OnInit() block on any object. The PlayerRef property is already resolved to the Player Reference when the game is loaded. I think you may be confusing Reference Aliases with Properties.

If you don't mind, please point out specifically what you read on that thread that "should have never been written". I'm always trying to improve.

Also let's take this to PMs if you care to continue this, since I don't want to derail Alex's thread with a code best practices discussion.
User avatar
Ella Loapaga
 
Posts: 3376
Joined: Fri Mar 09, 2007 2:45 pm

Post » Tue Nov 20, 2012 6:06 am

Indeed. Thank you.

So did your alias's do this Chesko? It seems normal... But it doesn't explain why my script wont fire randomly for some testers in random versions. (Even where it wasn't touched at all)
User avatar
Gavin boyce
 
Posts: 3436
Joined: Sat Jul 28, 2007 11:19 pm

Post » Tue Nov 20, 2012 6:02 am

I'm not home yet.

Can you reproduce the problem? If so, can you plug in a check in your code to check for the validity of PlayerRef, FSMQ01, and the quest stages you expect (i.e., something like this:

if FSMQ01    debug.notification("FSMQ01 = " + FSMQ01)else    debug.notification("FSMQ01 is none!")endif


Also, check what your quest stage is each step of the way?

Does your Papyrus log come back with anything, like an aborted function call due to a "none" object?

Also, can you change the type of PlayerRef from ObjectReference to Actor? They should be anologous, and I don't think it matters, I've just always used Actor type.
User avatar
Krystal Wilson
 
Posts: 3450
Joined: Wed Jan 17, 2007 9:40 am

Post » Mon Nov 19, 2012 10:53 pm

It's reproducable in random versions for random testers. I've never had it once, a few of my testers had it like 6 months ago but it stopped, and now like 3 of my testers have it in the latest version, but didn't the version before.

I'll have to add some debug stuff to see if things are failing for them for some reason.

My quest's stage does not change. It's either 0 before AND after, or 5 before AND after (Depending on how they started the quest). So the SetStage/obj stuff simply isn't firing.

And I just set up the PlayerRef thing to optimize on Friday, even with Game.GetPlayer() it did this. And doesn't it have to be an ObjRef since that's what the event checks for? I could make it actor but wouldn't I pointlessly have to do a cast so the types are compatable?

And I'm :blush: not sure how to check the papyrus log, actually... I've never dealt with it. But again I'm not having issues with this, my testers are. So they'd have to check theirs.
User avatar
john page
 
Posts: 3401
Joined: Thu May 31, 2007 10:52 pm

Post » Mon Nov 19, 2012 7:12 pm

And I just set up the PlayerRef thing to optimize on Friday, even with Game.GetPlayer() it did this. And doesn't it have to be an ObjRef since that's what the event checks for? I could make it actor but wouldn't I pointlessly have to do a cast so the types are compatable?

Nope. Actors extend ObjectReference. To put another way, an Actor "is an" ObjectReference. They implement all ObjectReference member methods, plus all of the methods for Actors. Either way it doesn't really matter that much I guess. Actor is just more specific. You could also say that PlayerRef is also of type Form, but that's as generic as you can get in this framework.

And I'm :blush: not sure how to check the papyrus log, actually... I've never dealt with it. But again I'm not having issues with this, my testers are. So they'd have to check theirs.

Have them try to reproduce it http://www.creationkit.com/FAQ:_My_Script_Doesn%27t_Work!#My_Script_compiles.2C_but_doesn.27t_work.21_How_can_I_debug_this.3F. Look for errors originating from your objects and scripts.

My quest's stage does not change. It's either 0 before AND after, or 5 before AND after (Depending on how they started the quest). So the SetStage/obj stuff simply isn't firing.

I know what you think it should be, and aught to be, but just to rule it out we still need to verify. :cool: In the end it might have nothing to do with your script, but at least then you'd know for sure. And due to Papyrus possibly losing track of something, what the game thinks and what Papyrus thinks might not always be the same.
User avatar
koumba
 
Posts: 3394
Joined: Thu Mar 22, 2007 8:39 pm

Post » Mon Nov 19, 2012 8:56 pm

Is it possible that sometimes there is more than one instance of the item on that dead body? Because in such a case the OnContainerChanged event may not be fired.

Also a puzzling bit from the wiki:
Once an object has been added to a container it is no longer valid to call functions on it. Functions on self will fail to run with an error.
I guess this is supposed to be true only after OnContainerChanged completed but could it be possible that sometimes the underlying instance becomes invalid before the OnContainerChanged event ends? Since the function calls many native functions (about one frame each) and is ran while the loot menu is displayed (scripts are typically slowed down at this time), there may be a race condition. Just an idea, but I would try to cache the value of the properties in local variables at the beginning of the function with the hope that "self" will no longer be required after that (a delusive hope probably). Or try to update the displayed objective in the stage's fragment instead, to shorten OnContainerChanged.

Anyway I would first look at the logs before I tried random changes like those. I would also test whether leaving the loot menu opened a long time makes a difference.
User avatar
Yvonne Gruening
 
Posts: 3503
Joined: Mon Apr 23, 2007 7:31 pm

Post » Mon Nov 19, 2012 11:29 pm

What? You lost me. :P

I don't call self during the script. The item gets moved, all that I watch for is to ensure that if the quest is below a stage, it sets a stage. OnContainerChanged does fire when the alias is first created, but fails.

And no there shouldn't ever be more than one, and my testers have never reported multiple. It's a simply create-in alias. :/

I've passed on the instructions Chesko, so hopefully they can try it out and get me some interesting results... I did try that If test, for me personally it just says:

FSMQ01 = [Quest
PlayerRef = [Actor

So I assume that's good to go for me? I'll see this weekend what it says for my testers.
User avatar
Emerald Dreams
 
Posts: 3376
Joined: Sun Jan 07, 2007 2:52 pm

Post » Tue Nov 20, 2012 1:32 am

I'm curious to know how this script is tied to the object reference. Did place the object in the CK, and then attach the script to the instance? Did you do it via quest?
Don't forget: A quest that is not running will appear to be in stage zero. but unitl you actually type 'setstage myquest 0' or activate it some other way, it's not actually running

ALSO: What command did they type to get that info in the screenshot?
User avatar
Assumptah George
 
Posts: 3373
Joined: Wed Sep 13, 2006 9:43 am

Post » Mon Nov 19, 2012 8:16 pm

The FF means it's dynamically created, like as a created ReferenceAlias or with PlaceAtMe. FF range forms are stored in your save, the last plugin (of sorts) loaded.

PlayerREF property, usually, you'd want as an Actor property rather than an ObjectReference so you can use all the Actor functions w/o casting As Actor.
User avatar
Eileen Müller
 
Posts: 3366
Joined: Fri Apr 13, 2007 9:06 am

Post » Mon Nov 19, 2012 10:58 pm

I suggested the use of Game.GetPlayer() because:

1-That's what you see in the wiki
2-That's what you see in scripts
3-The less auto properties the better (according to the wiki)

Anyway, I have another suggestion, quests "don't like" external scripts, can't you just set stage in that script and do the rest inside QUEST STAGE fragments? You should try that.
User avatar
Sheeva
 
Posts: 3353
Joined: Sat Nov 11, 2006 2:46 am

Post » Tue Nov 20, 2012 7:48 am

What? You lost me. :P I don't call self during the script.
Yes you do. ;)
Anytime you perform an internal call or access an internal variable ("internal" means here "that belongs to self"), you do use self implictly:
* Getting an internal variable is getting the value stored at self's address + some offset.
* Accessing an internal function implictly passes self as the first argument.
This is not true for local variables though (variables declared in functions), they're declared "on the stack".

Anyway your first priority is to get some logs. ;)
User avatar
BlackaneseB
 
Posts: 3431
Joined: Sat Sep 23, 2006 1:21 am

Post » Tue Nov 20, 2012 3:54 am

I suggested the use of Game.GetPlayer() because:

1-That's what you see in the wiki
2-That's what you see in scripts
3-The less auto properties the better (according to the wiki)


3-This is correct but the problem with properties is that they cause the object you are pointing at to be flagged as permanently persistent (always loaded in memory). But the players reference is always loaded in memory anyway since it is the player that is interacting with the world all the time.
User avatar
Allison Sizemore
 
Posts: 3492
Joined: Wed Jul 19, 2006 6:09 am

Post » Tue Nov 20, 2012 11:20 am

Indeed, but to be honest I'm not arguing what is better, I will keep using GetPlayer not because I think it's better but because I'm used to it, and if it was worst Bethesda themselves wouldn't use it.
User avatar
Andrea P
 
Posts: 3400
Joined: Mon Feb 12, 2007 7:45 am

Post » Tue Nov 20, 2012 5:41 am

It would be awesome if Smk dropped in right now and settled this once and for all, because I'd really like to use the best one... :P
User avatar
Niisha
 
Posts: 3393
Joined: Fri Sep 15, 2006 2:54 am

Post » Mon Nov 19, 2012 10:14 pm

It would be awesome if Smk dropped in right now and settled this once and for all, because I'd really like to use the best one... :tongue:

Don't think is that important to be honest :)

Did you try this already:

Anyway, I have another suggestion, quests "don't like" external scripts, can't you just set stage in that script and do the rest inside QUEST STAGE fragments? You should try that.
User avatar
Ernesto Salinas
 
Posts: 3399
Joined: Sat Nov 03, 2007 2:19 pm

Post » Tue Nov 20, 2012 8:19 am

Well I have 20+ quests that all use external scripts just fine, why would this one suddenly not like it. :/ Plus all I do other than setting the stage in this script, is setting the objective. So if it doesn't like that, wouldn't it still set the stage at least?

Anywho, I'm waiting for my testers to get me some of those logs... Hopefully they'll be helpful.
User avatar
Nomee
 
Posts: 3382
Joined: Thu May 24, 2007 5:18 pm

Post » Mon Nov 19, 2012 10:54 pm

It would be awesome if Smk dropped in right now and settled this once and for all, because I'd really like to use the best one... :tongue:
If you have a performance problem because your script needs to answer fast and is slowed down by repeated calls to Game.GetPlayer(), you need to cache its value in a property, a field or a local variable.
Otherwise just do what's cleaner and easier. Imho this means using Game.GetPlayer() directly.
This is as simple as that.
User avatar
Tiffany Holmes
 
Posts: 3351
Joined: Sun Sep 10, 2006 2:28 am

Post » Tue Nov 20, 2012 3:00 am

There is no "right" one :smile: GetPlayer() is slower, but a property takes up some amount of memory (even if empty). Is your script running too slowly or causing other scripts to run slowly? Then use the http://www.creationkit.com/StartStackProfiling_-_Debug http://www.creationkit.com/StartObjectProfiling_-_Form http://www.creationkit.com/StartScriptProfiling_-_Debug http://www.creationkit.com/DumpPapyrusStacks to measure your script. In most cases the problem is going to stem from a bad algorithm (like polling rather then using events) rather then using GetPlayer vs a property.

Or to more succintly summarize, there are the http://blogs.msdn.com/b/audiofool/archive/2007/06/14/the-rules-of-code-optimization.aspx:
  • Don't
  • Don't yet
  • Profile first
User avatar
A Dardzz
 
Posts: 3370
Joined: Sat Jan 27, 2007 6:26 pm

Post » Mon Nov 19, 2012 8:09 pm

It's as if he knows I mentioned him. :blink:

Thanks SMK! So basically, I'll use Getplayer() in simpler scripts, like where it's only used once, so that the properties aren't taking up memory. (Since I don't need a quick dialogue fragment to run super duper fast) But if I have a complex script where it's used multiple times, I'll use a property.

And yeah I literally just added the property vs the function, so that's not the cause. I don't think it's speed related, as it's very consistent for working/failing, just not for who or what version. The script has never once failed for me. Ever. And every version I release of my mod to my testers, it randomly changes who has it work and who has it fail. At once point or another, every single person has had it both work and fail (Except me).

So I guess I'll wait for the logs on those who it's failing for? Then we can see what kind of errors they're getting...
User avatar
OnlyDumazzapplyhere
 
Posts: 3445
Joined: Wed Jan 24, 2007 12:43 am

Post » Tue Nov 20, 2012 1:51 am

Okay so one of my testers enabled logging and played through the 'broken' part of the quests where the script wouldn't fire. It generated an ~8mb log file, is there something in perticular he needs to look for in all that? Is a file that big normal?
User avatar
Adrian Morales
 
Posts: 3474
Joined: Fri Aug 10, 2007 3:19 am

Post » Tue Nov 20, 2012 6:11 am

Okay so one of my testers enabled logging and played through the 'broken' part of the quests where the script wouldn't fire. It generated an ~8mb log file, is there something in perticular he needs to look for in all that? Is a file that big normal?
If it's a one hour log, it's not surprising: errors are common, both from mods and the game itself. If it's over a ten mins log, then there is a problem.
Here is how to deal with it: find the first error that does not come from your mod. Hit Ctrl+shift+f (or +h) in a good text editor like notepad++ to use "replace all" and replace it by nothing. Then do the same with the next error. Etcetera until you only have errors from your mod, or until you know there is no error from you. Make a backup first.
User avatar
Lilit Ager
 
Posts: 3444
Joined: Thu Nov 23, 2006 9:06 pm

Next

Return to V - Skyrim