Tutorial Request: How to make a script to cache actor values

Post » Tue Sep 23, 2014 11:57 pm

I've been working on a Skyrim mod and the biggest problem is that the multithreaded Papyrus object locking model is completely hostile to my mod because my scripts need to invoke a lot of GetActorValue and HasPerk functions on the player character. These functions require scripts to "wait" for the right to lock the player character (obviously being spam-requested from many other scripts), even for reading. (I can't see why there isn't an option to read with no object lock and accept potentially outdated data. This type of advanced lock handling is standard in most databases, where you can read with a lock and guarantee up-to-date results, or read with no lock for a "best effort" result instead)

Lousy architecture complaints aside: I have already requested "BatchGetAV" and "BatchHasPerk" functions for SKSE and received no real useful replies.

It looks like the proper way to implement this is to create a script object that "shadows"/caches the player character's actor values - maintains last known actor values and perks, and updates them on certain events. However, I have been unable to find a conclusive complete tutorial. I'm requesting a tutorial on how to do this to be posted here, or at least, a link to a tutorial that is known to work.

----------------------

Here's a general idea of how the actor value caching script would work:
-Script runs continuously in the background. It would be attached to the player character somehow and receive events from the player character (Looking for advice on this)
-It has several event handlers, such as OnLevelUp, OnItemEquipped, OnItemUnequipped, etc.
-The script maintains player perks, skill levels, resistances, etc
-Various events cause updates on some variables.
-Other scripts must be able to read variables out of the cache script.
User avatar
quinnnn
 
Posts: 3503
Joined: Sat Mar 03, 2007 1:11 pm

Post » Wed Sep 24, 2014 2:30 am

what do you mean "lock the player", getting an av or querying a perk's not locking anything whatsoever...?

but if you really insist on caching values, just make a quest with a player alias, have that do your av reading and just mirror them into script's own variables (properties). not that i saw any point in doing this, but... ;-)

for your "batchGetAV" request, i neither use nor support skse, but if i may make an assumption: there's a ZILLION of av's (ever checked av list on ck wiki??), a function like that would just be shoveling around tons of data 99% of which you'd most likely never need, use or care about (let alone questions like how to determine what value goes with which av)

if you really mean to batch though, you can make a string form list with all av names and a function that "While"s through that.

...and about that always running script, papyrus is event driven, there's no running continuously in background anyway. you'd need to do your thing on any relevant event.

edit: ...or constantly keep sending it update events, but that's, well, not exactly efficient :-)

User avatar
sam smith
 
Posts: 3386
Joined: Sun Aug 05, 2007 3:55 am

Post » Tue Sep 23, 2014 7:24 pm

Skyrim's Papyrus scripting engine is built for multithreading, so threads and scripts need to get a lock on an object before reading/writing it. Here's an example:

Suppose there are 2 scripts/threads/programs using the same set of shared variables. One wants to write to a variable at the same time another wants to read the variable. Depending on who writes/reads first, the result of the read may be different.

With Papyrus, before reading from an object, a script must request a lock. My guess is that objects can't be written to until every reading lock is invalidated.

My current Skyrim mod's biggest problem has been heavy use of GetAV and HasPerk on the player character, so whenever another script is writing to the player character, it holds up almost every script in my mod.

I'm currently building a quest with a script to "cache" player character data so my mod scripts can read data from that instead. This removes the need to wait for a read lock on the player character - instead, read locks are now the cache script's problem. Note that the "quest" isn't really a quest and is more like a background service.

Other open questions that have yet to be answered:

For a quest Reference alias on the player character: should I use "Specific Reference" or "Unique Actor"? Unique Actor requires a "Persist Location" (poorly documented) and I'm not certain if it can be used on the player character properly.
"Specific Reference" has no persist location restriction, however it means that its referenced object is always loaded in memory even when the quest is not running. However, I can't think of any reason why the player character shouldn't be loaded in memory, so my guess is that this would be a non-issue.

How do I get variables from the quest script while it's running?
User avatar
Breanna Van Dijk
 
Posts: 3384
Joined: Mon Mar 12, 2007 2:18 pm

Post » Tue Sep 23, 2014 1:43 pm

for npc's, ref has proved more reliable than unique actor for me. not sure if it makes a big dif for pc, but i still always use ref

if you want to access them from another script, you just need a property to your ref alias script,

like

YourRefAliasSCRIPT Property Whatever Auto

and fill with your ref alias.

you can then simply access the variables (which need to be _properties_ for this) by Whatever.MyVariable

and if you also want to be able to change them from the other script, both the original variable properties and the ref alias script itself have to be flagged "conditional"

...and if they are conditional already, you can also access them from condition items (GetVMscriptVariable)

User avatar
Amy Siebenhaar
 
Posts: 3426
Joined: Fri Aug 10, 2007 1:51 am


Return to V - Skyrim