Jump to content

Overhauling the weapon rack scripts


Sclerocephalus

Recommended Posts

Here's my v3.2 log from a run through the Helgen intro (latest USKP 2.0 beta, fresh game):

[10/20/2013 - 08:38:44PM] WeaponRackLog log opened (PC)
[10/20/2013 - 08:38:44PM] [WeaponRackTriggerSCRIPT < (000B16A6)>]OnCellAttach : [WeaponRackActivateScript < (000B16A7)>] registered for single update.
[10/20/2013 - 08:38:44PM] [WeaponRackTriggerSCRIPT < (00035A54)>]OnCellAttach : [WeaponRackActivateScript < (00035A4B)>] registered for single update.
[10/20/2013 - 08:38:44PM] [WeaponRackTriggerSCRIPT < (0009348D)>]OnCellAttach : [WeaponRackActivateScript < (00093626)>] registered for single update.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: OnUpdate event received.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: OnUpdate event received.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: OnUpdate event received.
[10/20/2013 - 08:38:44PM] [WeaponRackTriggerSCRIPT < (000B16A6)>]OnLoad : AlreadyInit = True; Registration of activator skipped.
[10/20/2013 - 08:38:44PM] [WeaponRackTriggerSCRIPT < (0009348D)>]OnLoad : AlreadyInit = True; Registration of activator skipped.
[10/20/2013 - 08:38:44PM] [WeaponRackTriggerSCRIPT < (00035A54)>]OnLoad : AlreadyInit = True; Registration of activator skipped.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Started running InitActivator().
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Started running InitActivator().
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Started running InitActivator().
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Trigger Marker [WeaponRackTriggerSCRIPT < (000B16A6)>] in 'activator busy' state.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Trigger Marker [WeaponRackTriggerSCRIPT < (0009348D)>] in 'activator busy' state.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Trigger Marker [WeaponRackTriggerSCRIPT < (00035A54)>] in 'activator busy' state.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Checking whether starting item is in same cell.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Checking whether starting item is in same cell.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Checking whether starting item is in same cell.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Starting item is in same cell.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Beginning to handle starting item.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Starting item is in same cell.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Beginning to handle starting item.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Starting item is in same cell.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Beginning to handle starting item.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Placed Item = [WEAPON < (00012EB7)>]; Ref = [ObjectReference < (0009362D)>]
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Trigger Marker [WeaponRackTriggerSCRIPT < (0009348D)>] in empty state.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Placed Item = [WEAPON < (00012EB7)>]; Ref = [ObjectReference < (00035A50)>]
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Trigger Marker [WeaponRackTriggerSCRIPT < (00035A54)>] in empty state.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>]: Starting item [WEAPON < (00012EB7)>] placed on trigger [WeaponRackTriggerSCRIPT < (0009348D)>].
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>]: Starting item [WEAPON < (00012EB7)>] placed on trigger [WeaponRackTriggerSCRIPT < (00035A54)>].
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Placed Item = [WEAPON < (00013982)>]; Ref = [ObjectReference < (000B16AA)>]
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Trigger Marker [WeaponRackTriggerSCRIPT < (000B16A6)>] in empty state.
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00093626)>] disabled on cell attach; PlacedItemInit = True; TOC = 1
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>]: Starting item [WEAPON < (00013982)>] placed on trigger [WeaponRackTriggerSCRIPT < (000B16A6)>].
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (00035A4B)>] disabled on cell attach; PlacedItemInit = True; TOC = 1
[10/20/2013 - 08:38:44PM] [WeaponRackActivateScript < (000B16A7)>] disabled on cell attach; PlacedItemInit = True; TOC = 1
[10/20/2013 - 08:39:35PM] [WeaponRackActivateScript < (00035A4B)>]; Leaving Item = [WEAPON < (00012EB7)>]; Ref = [ObjectReference < (00035A50)>]
[10/20/2013 - 08:39:35PM] [WeaponRackActivateScript < (00035A4B)>]; Mounted Item = [WEAPON < (00012EB7)>]; Ref = [ObjectReference < (00035A50)>]
[10/20/2013 - 08:39:35PM] [WeaponRackActivateScript < (00035A4B)>]; Starting Item = [WEAPON < (00012EB7)>]; Ref = [ObjectReference < (00035A50)>]
[10/20/2013 - 08:39:35PM] [WeaponRackActivateScript < (00035A4B)>] enabled; TOC = 0; StartingItemHasBeenGrabbed = True.

Everything works as expected and also no messages on the papyrus log. All triggers still get their OnCellAttach event before their OnLoad event though.

Link to comment
Share on other sites

Usually, the canonical method would be a simple semaphore instead of the states and OnUpdate:

 

Bool Property Inactive  Auto

 

bool wasInactive = Inactive

Inactive = false

if !wasInactive

...

 

Or whatever. That would keep the code from running twice.

 

Sorry to ask quite frankly, but I'm wondering a little whether you actually read what I'm posting. No matter if you don't, but you could say so at least, since it always costs me some time to briefly summarize the most important facts without going too much into lengthy details.

 

About two pages or so back, I have been explaining why I'm using states in the activator script and what they are intended to do. A short reminder, so you won't have to search for it:

 

The 'Inactive' state on the activator script is used to keep misconfigured activators and out-of-place activator scripts permanently inoperative. The OnLoad event is used to catch them. Neither the state nor the OnLoad event have anything to do with the initialization, and they do also not prevent any code from running twice.

Link to comment
Share on other sites

Sorry to ask quite frankly, ....

 

The 'Inactive' state on the activator script is used to keep misconfigured activators and out-of-place activator scripts permanently inoperative. The OnLoad event is used to catch them. Neither the state nor the OnLoad event have anything to do with the initialization, and they do also not prevent any code from running twice.

I have read every post in this topic. I will not pretend to remember them all individually, but I'm pretty sure I replied to that particular post.

 

It seemed/seems to me you are using OnLoad for something entirely unrelated to loading. Just because it was a predefined event in place that could be used. I wasn't sure that was a good idea at the time, and am now even more sure....

 

 

There is a contradictory statement in one of DayDreamer's previous posts:

No, there isn't -- it is self consistent. It is contradicted by log entries showing OnLoad coming before OnCellAttach. But I have no idea how those entries were generated.

 

In my personal experience, OnLoad always follows OnCellAttach, at least in interior cells (in exterior cells, I have also seen them firing in the opposite order on very few occasions). Now, when I look at that log though, those triggers' OnLoad and OnCellAttach events are completely disordered. Some have OnLoad before OnCellAttach, some have it after OnCellAttach (thus, DayDreamer is always right), and there are also a few with an OnCellAttach event, but no OnLoad event. There's something wrong here.

I've seen everything under the sun in exteriors. I've had to add interceptions for OnLoad, OnUnload, and OnCellDetach to my scripts, because they happen to the driver even with the player sitting next to the driver. Followers fade and disappear, like they are distant objects.

Generally, OnCellAttach -> OnLoad -> OnCellLoad. But the game engine is very inconsistent in practice.

Pick one. Use that. I recommended OnCellAttach, because as I said earlier, it is more reliable than OnLoad. This is what I meant by reliable!

 

Why OnLoad()?

I've been removing all my cart OnLoad() and OnCellLoad() events and replacing them with OnCellAttach() -- the load events don't seem very reliable. I've found through extensive debug.log'ing that OnCellAttach() always runs first, then OnLoad(), then OnCellLoad(). But the latter two don't always run (presumably the stuff is cached).

Link to comment
Share on other sites

Out of testing experience for versions 2.5/2.6, the states take effect within less than 0.1 seconds. This is vital for the whole weapon rack stuff to work.

 

 

EDIT:

You can grab the v3.1 debugging versions here (they're not explicitely mentioned on the download page, but they are there):

http://www.afkmods.com/index.php?/files/file/843-extended-racks/

As to 0.1 seconds: it's probably 0.01667 -- that is, the frame rate (1/60 seconds). The problem with that is during that frame rate break, all other threads instances attempting to access the same object's script fragment are allowed in.

 

EDIT: http://www.creationkit.com/Threading_Notes_%28Papyrus%29 and http://www.creationkit.com/Category:Non-delayed_Native_Function

 

The advantage to using the semaphore method is that it's non-interrupting -- or at least as non-interrupting as Papyrus can be.

 

(I've found and posted a section of code where the developers actually tested for None -- with a comment saying "; stupid failsafe" -- and it still failed with None on the very next line! Rarely, but they knew it happens and I verified it happens. And re-wrote the code so it doesn't happen.)

 

As to the scripts: Thanks! It was an edit, so I didn't see it in my following email, and it wasn't there at the time I clicked on the unread message! I'll take a look.

Link to comment
Share on other sites

I have read every post in this topic.

 

In this case, I will be happy to continue to provide you with the required information.

 

It seemed/seems to me you are using OnLoad for something entirely unrelated to loading. Just because it was a predefined event in place that could be used. I wasn't sure that was a good idea at the time, and am now even more sure....

 

I'm using it primarily because I have no need to handle this event in the activator script. If at all, the activator script would use OnCellAttach (as in all pre-3.1 versions) but never OnLoad. On the other hand, using OnLoad in 'Inactive' state to return to the active state makes sure that the respective activator becomes operative immediately after the respective modder made all the necessary modifications (Note: you can't get a borked activator to run from within the game, but have to modify its setup either in the CK or in TES5Edit, which requires quitting the game to desktop. In a subsequent reload, OnLoad will fire more or less immediately).

 

I understand that this is not a solution you would favour, so there won't be any need to insist on it. What I have implemented so far is the result of extensive testing, usually of various possible solutions for every individual problem - although I have to admit that I didn't spend overly much time on the scripts, only around 1,400 hours so far (including the test runs). Thus, somebody with enough time on his hands could probably come up with a better solution.

 

 No, there isn't -- it is self consistent. It is contradicted by log entries showing OnLoad coming before OnCellAttach. But I have no idea how those entries were generated.

I've seen everything under the sun in exteriors. I've had to add interceptions for OnLoad, OnUnload, and OnCellDetach to my scripts, because they happen to the driver even with the player sitting next to the driver. Followers fade and disappear, like they are distant objects.

Generally, OnCellAttach -> OnLoad -> OnCellLoad. But the game engine is very inconsistent in practice.

 

I cannot speak about exterior cells, but in interiors, OnLoad always follows OnCellAttach. It still does on my PC even with the latest USKP beta and I have never seen occurring them out of order. Objects loading before a cell attaches will have no valid reference until cell attach, and are therefore unlikely to have been intended by Bethesda to ocur at all. I have no idea why this happens, but it is most likely one of the reason for the tons of papyrus errors about scripts running on a none reference.

 

Though, what is also evident from Arthmoor's log is that the activators always load last, sometimes with a tremendous delay (in one case from that log, it was 6 seconds!, i.e. update event received after 7 seconds minus 1 second for the delay). That's why I suspect that this problem is related to modern graphics cards: the engine shovels everything that needs to be rendered (i.e. not the activators, because they are editor markers and excluded from rendering) to the graphics card and this completes the task before the Skyrim engine can even say "ouch" when it gets aware that everything has been rendered while it is still trying to complete the cell attach procedure.

 

 

Pick one. Use that. I recommended OnCellAttach, because as I said earlier, it is more reliable than OnLoad. This is what I meant by reliable!

 

I need them both. I have explained here why:

 

http://www.afkmods.com/index.php?/topic/3669-overhauling-the-weapon-rack-scripts/?p=147669

 

OnLoad is the only event that fires when a rack is enabled while the player is in the same cell. OnCellAttach will not fire again (this fires already when the player enters the cell, irrespective of whether the rack is enabled or not). OnLoad alone won't do it though, because the scripts must run on every cell attach (otherwise, the pre-placed items fall off the racks because the havok settings do not last on linked references beyond cell detach).

 

With the vanilla scripts running, any rack constructed in a Hearthfires home could be used at once - with the downside of the racks not working properly anyway because the scripts were horribly buggy. Nonetheless, I can't excuse the missing functionality with a bug fix. The goal of a fix is to retain the functionality while correcting the errors. Anything else is not an appropriate solution.

Link to comment
Share on other sites

(... In a subsequent reload, OnLoad will fire more or less immediately).

I'm trying not to quibble too much, as it appears that you are taking offense.

In 1.8, OnCellLoad happened on reloading the saved game. In 1.9, it does not. I don't have logged instrumentation comparisons for OnLoad, but I can assure you that in exteriors in 1.9, OnLoad does not fire on reload.

Be assured that I understood your desire for using OnLoad in HF homes.

But not for using it to disable non-functioning racks.

... somebody with enough time on his hands could probably come up with a better solution.

We all respect and appreciate the time you've put into this! It's not more time, but experience with multi-threaded operating systems. (As you may already know, my own code is in many/most desktop and phone operating systems.)

Sadly, the Bethesda game engine is like a distant vision of a proper compiler and scheduler seen from afar by somebody who heard off-hand that they might be useful. There are serious bugs and quirks. We're all struggling here together....

Objects loading before a cell attaches will have no valid reference until cell attach, and are therefore unlikely to have been intended by Bethesda to ocur at all. I have no idea why this happens, but it is most likely one of the reason for the tons of papyrus errors about scripts running on a none reference.

Agreed.

Though, what is also evident from Arthmoor's log is that the activators always load last, sometimes with a tremendous delay (in one case from that log, it was 6 seconds!, i.e. update event received after 7 seconds minus 1 second for the delay). That's why I suspect that this problem is related to modern graphics cards: the engine shovels everything that needs to be rendered (i.e. not the activators, because they are editor markers and excluded from rendering) to the graphics card and this completes the task before the Skyrim engine can even say "ouch" when it gets aware that everything has been rendered while it is still trying to complete the cell attach procedure.

Thank you for that insight. How does the latest version take that into account?
Link to comment
Share on other sites

But not for using it to disable non-functioning racks.

 

But that's another OnLoad event on a different script ...

 

 

t's not more time, but experience with multi-threaded operating systems. (As you may already know, my own code is in many/most desktop and phone operating systems.)

 

My code was in the controlling software of a lab-built packed-column supercritical fluid chromatograph, which we have been operating many years before the first commercial instruments appeared on the market. While few people actually know what a pSFC is and even less understand how it is working, this has been quite a challenge, as it required independent real-time control of several high pressure valves, a high precision pump and a temperature-programmed housing to maintain fluid densities within a gradient. While I decided for a different career, I nonetheless had programming classes at university for two years (just for fun in my spare time).

 

 

How does the latest version take that into account?

 

Simple. It basically disables the trigger's functionality until the activator script has confirmed that it needs it. Event-handling by the trigger has been the source of most glitches in the vanilla scripts anyway (e.g. OnTriggerEnter and OnTriggerLeave never firing in any particular order, the temporary loss of an object's 3D while performing a MoveToNode command (sic!) and the "fake" OnTriggerLeave and OnTriggerEnter events resulting thereof, etc., etc. etc.). Thus, many of the tasks the trigger has been overloaded with in the vanilla script have been removed from the trigger script and implemented in the activator script since version 1.0 already. The only task for which it is needed is to detect (and react) when an item has been grabbed from a rack, which means that it can be safely left in a state of inactivity as long as a rack is empty. Whether or not this is the case is evaluated by the activator while running its initialization procedure. Thus, the "activator busy" state has been made the trigger's default state. It can now load at any time before the activator, but will be unable to do anything unwanted.

 

By the way, your canonical method failed, but I have to admit that you had no chance to foresee this (so I'm not going to get angry this time ... ;) ):

  • It works as expected when OnCellAttach fires before OnLoad (which means that the script runs on a valid reference)
  • It does not work, when the trigger loads before cell attach: in this case, any modifications to the values of the script's properties remain without effect (that's obviously one of the implications of not having a valid reference or a parent cell, respectively). Interestingly though, the script passed an "If (Self != None)" check ...

 

EDIT:

Thus, v3.3 is not final, as I will have to transfer the check from the trigger script to the activator script.

Link to comment
Share on other sites

ARRRTHMOOOOOR !!!!! What did you do in the beta update ?????

 

With the very latest 2.0 update, I am now finally getting OnLoad events in interior cells before cell attach. This never, never, never happened before. I have been to the Warmaiden's about 10-15 times with the earlier beta active and could never reproduce this, and now everyfing is thucked up ...

 

Good news is that I don't need anybody else for testing ..

Link to comment
Share on other sites

Didn't do anything other than drop the 3.1 files in that you gave us, then compiled the scripts as I always do.

Link to comment
Share on other sites

you do miss things...ive heard ;)

 

Yes, this happens occasionally. Anything particular I should have thought at ?

Link to comment
Share on other sites

Didn't do anything other than drop the 3.1 files in that you gave us, then compiled the scripts as I always do.

 

I wasn't talking about the scripts. They had no chance to react at something like triggers that start running their scripts before the cell attaches. That should not hapen to any object, as it will only cause tons of trouble (see my comments in previous posts).

 

v3.4 is final (get it while it's steaming ...)

 

Have repeatedly entered and left the Warmaiden's about 30 times. Most of the time, I still get OnCellAttach before OnLoad for all triggers, but sometimes, the events are completely disordered. Nonetheless, irrespective of this nuisance, all triggers do behave now as expected, and I also got no error messages on the papyrus log. This will work now even if the trigger loads an hour before the activator.

 

EDIT:

Also included some minor modifications that make the preplaced weapons stop flickering when the player enters a cell.

 

EDIT2:

And yes, the trigger script does now really contain an "If (Self != None) ..." check for double safety.

Link to comment
Share on other sites

Well you'll be pleased to note that 3.4 passed the test. No weapons falling off of anywhere. No log message mentioning racks. So I think this has got it now.

Link to comment
Share on other sites

Let us not celebrate just yet :P

 

Got a bunch of this when I walked into Honeyside:

[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C28)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C28)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C27)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C27)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C26)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C26)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C25)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C25)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C1E)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C1E)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C1B)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C1B)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] Error: Cannot call IsDisabled() on a None object, aborting function call
stack:
    [ (00102C18)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
[10/21/2013 - 12:20:11AM] warning: Assigning None to a non-object variable named "::temp1"
stack:
    [ (00102C18)].BYOHDivertPrefabsScript.OnCellAttach() - "BYOHDivertPrefabsScript.psc" Line 7
Link to comment
Share on other sites

I look forward to the new beta so that I can see the code too. :)

 

You can grab the debugging version scripts at the usual place.

Link to comment
Share on other sites

 

Let us not celebrate just yet :P

 

Got a bunch of this when I walked into Honeyside:

 

[horrible spam omitted]

 

 

:wallbash:  Why, Bethesda, why ...

 

Line 7 checks for linked references, which are now missing because (as it turned out) these are the links which I removed. Thus, they were not the result of a stupid mistake, but of a deliberate act of ignorance.

 

Before going into details, I should make clear that the links have to stay removed, as otherwise all racks will be permanently inoperative from the moment of their acquisition.

 

The concept behind BYOHDivertPrefabsScript is pretty simple:

(1) All player home weapon racks and bookshelves that need to be removed to make place for a child's bedroom got this script attached.

(2) When the player buys the child's bedroom, BYOHDivertPrefabsScript moves all player items from the affected racks/shelves into a safe storage and then disables the racks/shelves.

(3) Before (2) is carried out, the script has to check whether the player actually owns the racks/shelves already, i.e. whether the home decorations they form part of have already been bought. To accomplish this, all racks/shelves have been linked to their respective player home decoration enable markers. That's the infamous link which is now missing from the Honeyside racks.

 

But why did they have to run the script on the activators ? Why not on the triggers ? They could have linked the triggers to everything without complications ... Only God and Bethesda know why they chose the activators. They had a 50/50 chance of doing things right, but they bombed it ...

 

For weapon racks, there's fortunately a much easier way to check whether the player actually owns them: just check the enable state of the triggers. Thus, line 7 has to be modified as follows (and the WRackTrigger keyword added as a script property):

OLD: bool shouldBeDisabled = Self.GetLinkedRef().IsDisabled()

NEW: bool shouldBeDisabled = Self.GetLinkedRef(WRackTrigger).IsDisabled()

Then, the script will work again without modifying anything else.

Link to comment
Share on other sites

Apologies if this has been reported already, I scanned through this thread and didn't see these particular error messages.

 

I recently built Lakeside Manor and started putting my artifacts up on the weapon racks, and ever since then my script log has been filled with this set of error messages, repeated several times a second non-stop during every session:

[10/21/2013 - 09:03:10AM] Warning: Assigning None to a non-object variable named "::temp24"
stack:
	[ (03009658)].WeaponRackActivateScript.PlaceItem() - "WeaponRackActivateSCRIPT.psc" Line 268
	[ (03009658)].WeaponRackActivateScript.HandlePlayerItem() - "WeaponRackActivateSCRIPT.psc" Line 329
	[ (03009658)].WeaponRackActivateScript.RunPlayerActivation() - "WeaponRackActivateSCRIPT.psc" Line 188
	[ (03009658)].WeaponRackActivateScript.OnActivate() - "WeaponRackActivateSCRIPT.psc" Line 84
[10/21/2013 - 09:03:10AM] Error: Unable to call Is3DLoaded - no native object bound to the script object, or object is of incorrect type
stack:
	[None].defaultDisableHavokOnLoad.Is3DLoaded() - "<native>" Line ?
	[ (03009658)].WeaponRackActivateScript.PlaceItem() - "WeaponRackActivateSCRIPT.psc" Line 268
	[ (03009658)].WeaponRackActivateScript.HandlePlayerItem() - "WeaponRackActivateSCRIPT.psc" Line 329
	[ (03009658)].WeaponRackActivateScript.RunPlayerActivation() - "WeaponRackActivateSCRIPT.psc" Line 188
	[ (03009658)].WeaponRackActivateScript.OnActivate() - "WeaponRackActivateSCRIPT.psc" Line 84

I unpacked the USKP .bsa to look at the script, and the problem arises right at the top of PlaceItem():

Function PlaceItem (ObjectReference ItemToPlace, ObjectReference TriggerMarker)
;This function grabs the specified item and places it on the rack

; 	Wait to make sure the item is loaded before proceeding, in order to prevent an "Object has no 3D" error when its motion type is set below:
	While !ItemToPlace.Is3DLoaded()
		Utility.Wait (0.1)
	EndWhile

That loop needs some kind of failsafe, because in my game, ItemToPlace has become None and that loop is just going on forever and ever spewing errors into the log. If I had to guess I'd say it was originally a threading problem -- maybe I tried to place an item and then picked it up out of the air again while PlaceItem() was still Wait()ing.

 

I don't remember any particular weapon rack oddities except that I tried placing Auriel's Bow, or maybe it was Zephyr, and it just clattered to the ground because of course bows don't go on racks. I also haven't been able to track down what 03009658 is; based on my load order 03 ought to be HearthFires.esm, but I've been poking through the CK and I can't actually find a form with that ID.

 

Anyway, in order to rescue my save I think I'm going to try adding my own None-check in that loop and recompiling to see if it'll a) toss out that stack so it stops looping in my save, and b) not do this to me again. Unless one of you folks has a better suggestion?

 

EDIT: I should have known it wouldn't be that easy. After modifying the script I now get this on load:

[10/21/2013 - 10:55:53AM] Warning: Function WeaponRackActivateScript..PlaceItem in stack frame 3 in stack 4277881 differs from the in-game resource files - using version from save

and the same for ~80 more threads, which then carry right on spewing errors. Is there some way to force-kill these threads or is my save game now totally hosed because of this infinite loop?

Edited by taleden
Link to comment
Share on other sites

That loop needs some kind of failsafe, because in my game, ItemToPlace has become none.

 

It doesn't. I has a failsafe - actually, it even has three (two, see edit below) of them:

 

The PlaceItem function can be accessed in two ways. It is either called by HandleStartingItem, when pre-placed weapons are handled, or by HandlePlayerItem, when the player's item is placed.

(1) Before HandleStartingItem is called the script makes sure that the pre-placed item loads, by calling LoadsInSameCell (this function is at the bottom of the script) from the InitActivator function.

(2) The player's item is dropped from the player's inventory into the cell. Those items always load.

 

EDIT: sorry, the following only applies to the forthcoming USKP v2.0 (where your problems with Zephyr will be gone - although you won't still be able to put in on a rack, due to a post 1.9 patch engine issue)

(3) Some items dropped from the players inventory do not return a valid reference from DropObject and would fail in the following steps (after the 3D check). To make sure that this won't happen, the player's item undergoes extended testing (which is why an external quest script is called).

 

 

I recently built Lakeside Manor and started putting my artifacts up on the weapon racks, and ever since then my script log has been filled with this set of error messages, repeated several times a second non-stop during every session:

Error: Unable to call Is3DLoaded - no native object bound to the script object, or object is of incorrect type
stack:
	[None].defaultDisableHavokOnLoad.Is3DLoaded() - "<native>" Line ?
	[ (03009658)].WeaponRackActivateScript.PlaceItem() - "WeaponRackActivateSCRIPT.psc" Line 268
	[ (03009658)].WeaponRackActivateScript.HandlePlayerItem() - "WeaponRackActivateSCRIPT.psc" Line 329
	[ (03009658)].WeaponRackActivateScript.RunPlayerActivation() - "WeaponRackActivateSCRIPT.psc" Line 188
	[ (03009658)].WeaponRackActivateScript.OnActivate() - "WeaponRackActivateSCRIPT.psc" Line 84

 

 

You simply are misreading the log:

 

(1) The message is very clear: "no native object bound to the script object", which means that the script, or a function within the script (whatever is specified in the first line of the stack) is running on nothing.

 

(2) The first line of the stack is very clear as well:

 

[None].defaultDisableHavokOnLoad.Is3DLoaded() - "<native>" Line ?

 

The expression in the square brackets is ALWAYS the reference of the object on which the specified script, function or command is running. It never refers to any result obtained while the specified command is carried out (in fact, the specified command, function, script is never carried out when an error occurs).

 

Papyrus simply tries to tell you that it can't run the Is3DLoaded check on a "none" reference (and in fact, pretty much every command fails when attempting at running it on a "none" reference).

 

If it would hook up in an infinite loop, the log would never tell you anything about this. Why should it ? By definition, an infinite loop is a loop with no progress, and this also includes errors. Unless something within the loop is wrong (the loop would obviously cease to be an infinite loop then), there is no reason for papyrus to terminate it. How should the engine know that this was not intended by whoever wrote the script ?

 

Anyway, to come back to the actual problem: What you've got here is a corrupted stack. In simple words, the engine lost the reference of the object on which it was supposed to run the commands. This usually happens when there is a high workload on the engine. The weapon rack scripts are known to reveal this issue, because they all start running at the same time (two scripts per rack!) when the player enters a cell. Consider the Warmaiden's for example, where 20 scripts will start running. Some modders have stretched this to the limits by filling player homes with racks to the brim, but even then, it's not the racks that are the culprit, because the engine is actually capable of handling this.

 

Also, it's almost always the 3D check which appears on the log, but this is only because this is the first command in that function. If you add a number of irrelevant commands before the 3D check, it will be those that are blamed by the papyrus log, but they aren't the culprit either.

 

The most frequuent reason for corrupted stacks are inappropriate edits of the Skyrim.ini file.

Check the following link and when this applies to your game, revert the edit to its default value:

http://www.creationkit.com/INI_Settings_%28Papyrus%29#iMaxAllocatedMemoryBytes

Link to comment
Share on other sites

[None].defaultDisableHavokOnLoad.Is3DLoaded() - "<native>" Line ?

Any chance the shit hit the fan because it has that disable havok script on it?

Link to comment
Share on other sites

Any chance the shit hit the fan because it has that disable havok script on it?

 

Unlikely. If this was the reason, it would have refused to cooperate in the HandlePlayerItem function already (i.e. from the moment when it was first handled).

 

 

God Dammit !!!

scriptName defaultDisableHavokOnLoad extends ObjectReference

EVENT onCellAttach()
	if (beenSimmed == FALSE && Self.Is3DLoaded())
		setMotionType(Motion_Keyframed, TRUE)
; 		;debug.trace("havok disabled on: " + self)
	endif
endEVENT

EVENT onLoad()
	if (beenSimmed == FALSE && Self.Is3DLoaded())
		setMotionType(Motion_Keyframed, TRUE)
; 		;debug.trace("havok disabled on: " + self)
	endif
endEVENT

I still don't see how this relates to the reference being lost, but this script will start doing counter-productive stuff for sure once the player item is dropped from inventory ...

Link to comment
Share on other sites

It doesn't. I has a failsafe - actually, it even has three (two, see edit below) of them:

 

The PlaceItem function can be accessed in two ways. It is either called by HandleStartingItem, when pre-placed weapons are handled, or by HandlePlayerItem, when the player's item is placed.

(1) Before HandleStartingItem is called the script makes sure that the pre-placed item loads, by calling LoadsInSameCell (this function is at the bottom of the script) from the InitActivator function.

(2) The player's item is dropped from the player's inventory into the cell. Those items always load.

 

Yes, I agree that all callers of PlaceItem() validate their reference first, so that PlaceItem() is not called with None as an argument. But supposing ItemToPlace.Is3DLoaded() returns false once, PlaceItem() goes into Wait(0.1) during which time anything could happen. Is it possible that the object reference is becoming invalid during that time, so when the script returns, now ItemToPlace throws the "no native object bound to the script" error, and thereafter evaluates as None? Were that to happen, are you sure the entire stack would error out and be destroyed, or would the While loop just continue to run forever? Because what I'm seeing in my logs (hundreds and hundreds of copies of those errors I posted) suggests the latter.

 

You simply are misreading the log:

 

(1) The message is very clear: "no native object bound to the script object", which means that the script, or a function within the script (whatever is specified in the first line of the stack) is running on nothing.

 

(2) The first line of the stack is very clear as well:

 

[None].defaultDisableHavokOnLoad.Is3DLoaded() - "<native>" Line ?

 

The expression in the square brackets is ALWAYS the reference of the object on which the specified script, function or command is running. It never refers to any result obtained while the specified command is carried out (in fact, the specified command, function, script is never carried out when an error occurs).

 

Papyrus simply tries to tell you that it can't run the Is3DLoaded check on a "none" reference (and in fact, pretty much every command fails when attempting at running it on a "none" reference).

 

Yes, now look at the second line of the stack:

[ (03009658)].WeaponRackActivateScript.PlaceItem() - "WeaponRackActivateSCRIPT.psc" Line 268

Line 268 of the script is, unsurprisingly, "While !ItemToPlace.Is3DLoaded()" inside PlaceItem(). So the other failsafes you mentioned have no prevented PlaceItem() from somehow having ItemToPlace==None.

 

If it would hook up in an infinite loop, the log would never tell you anything about this. Why should it ? By definition, an infinite loop is a loop with no progress, and this also includes errors. Unless something within the loop is wrong (the loop would obviously cease to be an infinite loop then), there is no reason for papyrus to terminate it.

 

This is the key point. When ItemToPlace becomes None inside PlaceItem(), the engine throws "no native object ..." -- but does it abort the loop? Does it destroy the whole stack? Or does it soldier on as best it can, by trying to evluate <None>.Is3DLoaded(), yielding the second error, and then making the whole loop boil down to "While !None" ? If the stack were being aborted as a result of the None reference, why do I see those errors repeated many times per second in my log, for hours on end, even while I am nowhere near the weapon rack in question?

 

Anyway, to come back to the actual problem: What you've got here is a corrupted stack. In simple words, the engine lost the reference of the object on which it was supposed to run the commands. This usually happens when there is a high workload on the engine. The weapon rack scripts are known to reveal this issue, because they all start running at the same time (two scripts per rack!) when the player enters a cell. Consider the Warmaiden's for example, where 20 scripts will start running. Some modders have stretched this to the limits by filling player homes with racks to the brim, but even then, it's not the racks that are the culprit, because the engine is actually capable of handling this.

 

Also, it's almost always the 3D check which appears on the log, but this is only because this is the first command in that function. If you add a number of irrelevant commands before the 3D check, it will be those that are blamed by the papyrus log, but they aren't the culprit either.

 

Sure, I'll buy that, but "a high workload on the engine" is not exactly a super rare edge case for Skyrim. It's going to happen sometimes, so when it does, shouldn't the script fail as gracefully as possible rather than getting stuck and contributing to even higher engine workload? Note also this did not happen in some noob modder's Hall of One Million Weapon Racks, this was in Lakeside Manor of the official Hearthfires DLC. I know that DLC is a pretty amateur job, but still.

 

The most frequuent reason for corrupted stacks are inappropriate edits of the Skyrim.ini file.

Check the following link and when this applies to your game, revert the edit to its default value:

http://www.creationkit.com/INI_Settings_%28Papyrus%29#iMaxAllocatedMemoryBytes

 

This is not to blame in my case; I have no such INI edits. I can confirm this by the first lines in my papyrus log:

[10/21/2013 - 02:14:53PM] Papyrus log opened (PC)
[10/21/2013 - 02:14:53PM] Update budget: 1.200000ms (Extra tasklet budget: 1.200000ms, Load screen budget: 500.000000ms)
[10/21/2013 - 02:14:53PM] Memory page: 128 (min) 512 (max) 76800 (max total)
 
Those are vanilla settings so far as I am aware.
Link to comment
Share on other sites

Unlikely. If this was the reason, it would have refused to cooperate in the HandlePlayerItem function already (i.e. from the moment when it was first handled).

 

 

God Dammit !!!

scriptName defaultDisableHavokOnLoad extends ObjectReference

EVENT onCellAttach()
	if (beenSimmed == FALSE && Self.Is3DLoaded())
		setMotionType(Motion_Keyframed, TRUE)
; 		;debug.trace("havok disabled on: " + self)
	endif
endEVENT

EVENT onLoad()
	if (beenSimmed == FALSE && Self.Is3DLoaded())
		setMotionType(Motion_Keyframed, TRUE)
; 		;debug.trace("havok disabled on: " + self)
	endif
endEVENT

I still don't see how this relates to the reference being lost, but this script will start doing counter-productive stuff for sure once the player item is dropped from inventory ...

So this may apply to any item which is first found by the player in a physics-defying position. As I recall, Zephyr is first found balanced on the tip of a log hanging over a chasm, and Auriel's Bow is first revealed hovering in mid-air over a water basin. In both cases, if physics were initially enabled on the items, they would immediately fall down; in the case of Zephyr, that would prevent the player even being able to get it.

 

EDIT: Are you sure this is misfiring? Reading the rest of that script, shouldn't beenSimmed==TRUE by the time the player could possibly try to put it on a weapon rack?

Link to comment
Share on other sites

So this may apply to any item which is first found by the player in a physics-defying position. As I recall, Zephyr is first found balanced on the tip of a log hanging over a chasm, and Auriel's Bow is first revealed hovering in mid-air over a water basin. In both cases, if physics were initially enabled on the items, they would immediately fall down; in the case of Zephyr, that would prevent the player even being able to get it.

 

 No, no, no ...

 

This is in fact a lot more complicated. Zephyr is one of those cases where the engine opposes to dropping it from the player's inventory and returns a "transient reference" instead (also termed "IxxCyy reference" in various threads on this forum). You can read more on those references here:

http://www.afkmods.com/index.php?/topic/3757-skyrim-object-references-of-the-type-item-xx-in-container-yy/

 

 

EDIT: Are you sure this is misfiring? Reading the rest of that script, shouldn't beenSimmed==TRUE by the time the player could possibly try to put it on a weapon rack?

 

Most of the time, it should be false (default settings of the "havokOnActivate" and "havokOnZKey" properties are "false", meaning that it won't start havoking when grabbed by the player).

Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
×
×
  • Create New...