Jump to content
ℹ️ Intermittent Download History issues ×

[LE] Quick Questions, Quick Answers


Recommended Posts

One method is to use a global variable, but that does require you to run a Get function for the value and a Set function if you wish to change the value mid-game. But may actually be fastest and safest. And easier to troubleshoot or test as you can change the value in the console.

 

One method is similar to what you are already doing but instead of using an array use an Integer property. Let one script store the value while all other scripts access it and/or run functions on that script to change it.

A brief example:

 

 

Quest script:

Int Property SharedVar Auto

;possibly include functions that change the value if desired and call them in the same manner

Other scripts:

QuestScriptName Property QSN Auto
{assign the quest that the script is attached to}

;some event or function
  Int LocalVar = QSN.SharedVar
    ;do whatever needed with the value
    ;you could change the value of the var on the other script from here
    ;but it is probably better to do it from the script holding the var
    ;thus create a function which changes the var on the other script then call that

 

 

There are other possible ways to link scripts at run time without using a property for the script.

GetOwningQuest for aliases and topic info fragments with a bit of casting (similar to what you've already done).

kmyQuest variable for quest stage fragments

probably others...

 

Link to comment
Share on other sites

The global might be an option; I haven't tried that and will check.

 

Properties won't work though; accessing a property via Get/Set functions on the script it belongs to is unacceptably slow. It has a repeating task that it needs to execute multiple times a second, and while individually any one Get/Set is pretty fast right now I need to be able to perform a couple of hundred Gets a second, which chews up the entire runtime allocation and prevents it from iterating, so you see the difficulty.

Edited by foamyesque
Link to comment
Share on other sites

The global might be an option; I haven't tried that and will check.

 

Properties won't work though; accessing a property via Get/Set functions on the script it belongs to is unacceptably slow. It has a repeating task that it needs to execute multiple times a second, and while individually any one Get/Set is pretty fast right now I need to be able to perform a couple of hundred Gets a second, which chews up the entire runtime allocation and prevents it from iterating, so you see the difficulty.

If you've got something that actually needs to run hundreds of times a second you should probably reconsider what you're doing. But if speed in accessing a variable from mulitple places is what you need then you definitely want to use a global variable. The GetValue and SetValue on global variables are highly optimized by the game and almost as fast as accessing a local variable. But you do need to use the GetValue() and SetValue() methods to access and change the values. Don't use GetValueInt, SetValueInt, or the Value property since those "convenience" functions introduce an additional function call.

 

 

GlobalVariable Property myVar Auto

Function BadExamples()
{These are all bad examples if speed matters.}
    if myVar.Value == 1.0
       myVar.Value = 2.0
    endif

    int val = myVar.GetValueInt()
    myVar.SetValueInt(42)
EndFunction

Function GoodExamples()
{These will do the same thing as the code above but run much faster.}
    if myVar.GetValue() == 1.0
        myVar.SetValue(2.0)
    endif

    int val = myVar.GetValue() as int
    myVar.SetValue(42)
EndFunction

 

 

Link to comment
Share on other sites

If you've got something that actually needs to run hundreds of times a second you should probably reconsider what you're doing.

 

Man, you're telling me. It isn't, really, that I have something that needs to run hundreds of times a second; more that I have a hundred things that would be each trying to run it a couple of times a second. What I'd love would be a way to reduce the number of scripts running... but I've not found any way to do so. Perils of a spell that needs to look at everything you can steal. :v

 

Edit:

 

Actually, some related optimization questions:

 

1. Fastest way to determine the type of an ObjectRef or Form (ie. Actor, ActorBase, Weapon, Container, etc)?

2. Fastest way to iterate through a container's inventory?

3. Fastest way to figure out how much an item is actually worth why is this function nonexistent everywhere aieee

Edited by foamyesque
Link to comment
Share on other sites

Hi, have a quick question I'm hoping someone can answer. When I'm creating a Fomod installer that has patching options, what is the etiquette on including the mod that I am patching's information or preview picture?
Link to comment
Share on other sites

 

1. Fastest way to determine the type of an ObjectRef or Form (ie. Actor, ActorBase, Weapon, Container, etc)?

2. Fastest way to iterate through a container's inventory?

3. Fastest way to figure out how much an item is actually worth why is this function nonexistent everywhere aieee

 

 

1. item.GetType()

2. Look at example in https://www.creationkit.com/index.php?title=GetNumItems_-_ObjectReference

3. item.GetGoldValue()

Link to comment
Share on other sites

 

 

1. Fastest way to determine the type of an ObjectRef or Form (ie. Actor, ActorBase, Weapon, Container, etc)?

2. Fastest way to iterate through a container's inventory?

3. Fastest way to figure out how much an item is actually worth why is this function nonexistent everywhere aieee

 

 

1. item.GetType()

2. Look at example in https://www.creationkit.com/index.php?title=GetNumItems_-_ObjectReference

3. item.GetGoldValue()

 

 

1. You're sure GetType is faster than e.g. casting?

2. Already doing that and it's slow as hell. :(

3. Doesn't deal with items improved by smithing or those with enchantments.

Link to comment
Share on other sites

 

1. You're sure GetType is faster than e.g. casting?

2. Already doing that and it's slow as hell. :sad:

3. Doesn't deal with items improved by smithing or those with enchantments.

 

 

1. GetType is extremely slow compared to casting to a Papyrus type. The only reason it can be better is that there are some results from GetType that don't have a matching Papyrus type. Using a whole series of "ref as Armor", "ref as Weapon", etc. checks will still be faster than a single GetType and then checking the value of the number returned (because the "as" operator runs just as fast as comparing two numbers).

 

2. This classic version of inventory walking always takes at least one frame per item (and the version on the CK Wiki always takes two because of the use of GetType).

 

 

    Int iFormIndex = akContainer.GetNumItems()
    While iFormIndex > 0
        iFormIndex -= 1
        Form kForm = akContainer.GetNthForm(iFormIndex)
        If kForm as Ingredient
            kForm.SetWeight(afWeight)
        EndIf
    EndWhile

 

 

 

Later versions of SKSE added a GetContainerForms() function that is much, much faster but has never been documented on the CK Wiki. It would be used like this:

Function ReweighIngredientsIn(ObjectReference akContainer, Float afWeight) Global
	Form[] item = akContainer.GetContainerForms()
	Int i = item.length
	While i > 0
		i -= 1
		If item[i] as ingredient
			item[i].SetWeight(afWeight)
		EndIf
	EndWhile
EndFunction

That version only uses one frame to get the array if items and then you can walk through that array very quickly. It will still need one frame per item for any functions you need to call but there's minimal overhead for the loop itself. In that specific example it will be one frame per ingredient. All non-ingredients will likely be processed in a fraction of a frame. If you called it on a container with no ingredients it would probably finish in just two frames, one for the GetContainerForms call and one for all of the other code.

 

 

3. I don't know if the SKSE team were ever fully convinced we know the real formula used to determine the value of improved and enchanted items or they simply didn't see a pressing need to implement it, but you're right that there's no simple way to get that value. And if you're trying to calculate it yourself in Papyrus it will be slow, there's no way around that.

 

And you didn't ask but the best way to grab nearby references in cells is to use a quest with aliases conditioned to fill with various times. That's far faster and more efficient than the SKSE functions you can use to traverse items in the game world.

Link to comment
Share on other sites

 

 

1. You're sure GetType is faster than e.g. casting?

2. Already doing that and it's slow as hell. :sad:

3. Doesn't deal with items improved by smithing or those with enchantments.

 

 

1. GetType is extremely slow compared to casting to a Papyrus type. The only reason it can be better is that there are some results from GetType that don't have a matching Papyrus type. Using a whole series of "ref as Armor", "ref as Weapon", etc. checks will still be faster than a single GetType and then checking the value of the number returned (because the "as" operator runs just as fast as comparing two numbers).

 

2. This classic version of inventory walking always takes at least one frame per item (and the version on the CK Wiki always takes two because of the use of GetType).

 

 

    Int iFormIndex = akContainer.GetNumItems()
    While iFormIndex > 0
        iFormIndex -= 1
        Form kForm = akContainer.GetNthForm(iFormIndex)
        If kForm as Ingredient
            kForm.SetWeight(afWeight)
        EndIf
    EndWhile

 

 

 

Later versions of SKSE added a GetContainerForms() function that is much, much faster but has never been documented on the CK Wiki. It would be used like this:

Function ReweighIngredientsIn(ObjectReference akContainer, Float afWeight) Global
	Form[] item = akContainer.GetContainerForms()
	Int i = item.length
	While i > 0
		i -= 1
		If item[i] as ingredient
			item[i].SetWeight(afWeight)
		EndIf
	EndWhile
EndFunction

That version only uses one frame to get the array if items and then you can walk through that array very quickly. It will still need one frame per item for any functions you need to call but there's minimal overhead for the loop itself. In that specific example it will be one frame per ingredient. All non-ingredients will likely be processed in a fraction of a frame. If you called it on a container with no ingredients it would probably finish in just two frames, one for the GetContainerForms call and one for all of the other code.

 

 

3. I don't know if the SKSE team were ever fully convinced we know the real formula used to determine the value of improved and enchanted items or they simply didn't see a pressing need to implement it, but you're right that there's no simple way to get that value. And if you're trying to calculate it yourself in Papyrus it will be slow, there's no way around that.

 

And you didn't ask but the best way to grab nearby references in cells is to use a quest with aliases conditioned to fill with various times. That's far faster and more efficient than the SKSE functions you can use to traverse items in the game world.

 

 

Excellent. GetContainerForms looks like precisely what I needed!

 

As far as enchanting goes, I believe -- and this was years ago when I was first looking-- that there's a UESP page with details on the enchantment data structure, which seems to include an explicit enchantment cost field, here:

 

http://en.uesp.net/wiki/Tes5Mod:Mod_File_Format/ENCH

 

The auto-calc'd formula also there is correct, but incomplete. The full cost of an enchantment for ordinary weapons and armour is calculated by using that formula on each of its effects, and then:

 

If it's the costliest effect:

1. Multiplying the cost of the effect by 8 and adding the capacity value * 0.12,

Otherwise:

2. Multiplying the cost of the effect by 100

 

And then summing the costs of all the effects. Not sure if it works on staves; I'm coming back to this project after a couple of years of hiatus and I don't recall if I'd checked it for them.

 

I'd even accept how dang slow running all that math in Papyrus is if it weren't for the fact that any NON-auto-calc enchantments completely bust it and there's no way I've ever found to figure out which is which :sad:

 

 

And yeah, search quests blow away any other way to find things that I've discovered. I have mine down to a third of a second for a loop, most of which I believe is start and stop overhead. If I can figure out why I'm getting alias collisions inserting what it finds I'll probably set it to find more things per cycle to amortize that (instead of the current 5).

Edited by foamyesque
Link to comment
Share on other sites

Need some math help..

Skyrim calculates perk spell damage as Base Damage + Multiplier(The multiplier is a percent of the base and the product is then added to the base).

For example, Flames is 10 with 25% perk, and 12 with 50% perk. All calculated from the base.

However, when I add a mod that adds 75%, this should boost Flames to 14(75% of 8 is 6. 8+6 = 14), but instead it raises to 21. I can't figure out how the engine is getting 21.. Unless my math is wrong.

Link to comment
Share on other sites

  • Recently Browsing   0 members

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