Hoamaii Posted June 18, 2016 Share Posted June 18, 2016 Hi guys, I'm working on a new mod where I've created some custom functions which are used by several scripts, all attached to forms (items, activators, armors, magiceffects, etc.), none to a quest, the only quest which will be running at all times with the mod is the MCM config quest. For the moment, as all scripts are in progress, I've repeated each custom function in each script - but I was wondering which is faster in game, defining custom functions in only one script then calling them from other scripts, or defining them in each separate script? The 1st solution makes shorter scripts of course but anyone knows if it actually makes a difference in game? Also, since I don't have a quest running at all time where I could define these custom functions, I was wondering which form I should attach the script to define them and be sure they get called alright by other scripts? Probably not armor nor item - would the script run when they're in a container? Probably not magiceffect - the script wouldn't run when the effect is not active, right? Can this be done out of a quest? Many thanks in advance for your advices :) Link to comment Share on other sites More sharing options...
IsharaMeradin Posted June 18, 2016 Share Posted June 18, 2016 If you do put your custom functions on a "library" script, attach that script to your MCM quest. Since the MCM quest will be active the entire time, it is a good place to put such functions. As far as which method is faster in processing, I couldn't really tell you. Link to comment Share on other sites More sharing options...
Hoamaii Posted June 18, 2016 Author Share Posted June 18, 2016 Wow, thanks for the quick reply, IsharaMeradin - I was wondering whether I could do that. We're talking about attaching that script to the MCM quest itself, right, not to the playerAlias? Link to comment Share on other sites More sharing options...
Surilindur Posted June 18, 2016 Share Posted June 18, 2016 (edited) Have you tried, instead of adding your functions in scripts in-game, making them into a function library? If your functions allow that. For example, if you have two scripts:_prefix_ActorScript_prefix_ObjectReferenceScriptAnd those two scripts need the same function:int BrilliantCustomFunction(int a, int b)You can make a third script, and place that function in it:_prefix_FunctionLibraryTo use that BrilliantCustomFunction from your other scripts, you would need to do two things:tag BrilliantCustomFunction as a Global one, so it can be used by the other scriptsmake sure the folder that _prefix_FunctionLibrary is inside is imported when you compileSo that you would have this inside _prefix_FunctionLibrary.psc ScriptName _prefix_FunctionLibrary Extends Form ; <-- for example form int Function BrilliantCustomFunction(int a, int b) Global Return (a + b) EndFunctionAnd you could use it in your other scripts like this: ScriptName _prefix_ActorScript Extends Actor Event OnInit() int i = _prefix_FunctionLibrary.BrilliantCustomFunction(1, 2) Debug.MessageBox("Output: " + i) EndEventAnd it should work. The best part is - if I remember correctly - that you would not even need to have the library script attached to an object. Like this:_prefix_ActorScript <-- Attached to an object in the game_prefix_ObjectReferenceScript <-- Attached to an object in the game_prefix_FunctionLibrary <-- Placed inside the scripts folder, not necessarily attached to anything in-gameMaybe something like that could work? I could not find a proper tutorial on how to do libraries, but I think I have run into one at some point. A little Googling might lead you to a proper tutorial. Edit: Whoo-ops. Got ninja'd. :ninja: If you make a normal script, and have it extend Quest (or something similar), you could attach it to the quest itself, in addition to your MCM script. Papyrus allows for multiple scripts to be attached to the same object. Edit 2: Whooo-oops the Second. So function libraries still need to be attached to something... ? :facepalm: Just a minute, need to check... Edit 3: Ah. Apparently not. So there you go. In case your functions allow it, you can make an external library out of them, that you do not need to attach to an in-game object at all. :sweat: Edited June 18, 2016 by Contrathetix Link to comment Share on other sites More sharing options...
IsharaMeradin Posted June 18, 2016 Share Posted June 18, 2016 Wow, thanks for the quick reply, IsharaMeradin - I was wondering whether I could do that. We're talking about attaching that script to the MCM quest itself, right, not to the playerAlias?Yes, to the quest itself. And you can do a global library as Contrathetix mentioned. However, I would not suggest that method unless you are planning to make a mod that is intended to lay a foundation that other mod authors could hook into and utilize. Link to comment Share on other sites More sharing options...
Surilindur Posted June 18, 2016 Share Posted June 18, 2016 I would also prefer a script on the MCM quest to a global library, as IsharaMeradin said. That was just an idea for any future needs, if you plan to make something bigger. The global library stuff is not too prevalent in the Wiki, or at least I have not run into it, so I thought it would be nice to bring it up. However, in this case, do as IsharaMeradin tells you. :) Link to comment Share on other sites More sharing options...
cdcooley Posted June 18, 2016 Share Posted June 18, 2016 Short answer: It depends. I need more details about the functions to give good advice. Long answer: You can use global functions, functions on some shared object (like the quest), functions in each script, or create a script that can be used as a base and extended by other scripts. If all of your scripts are on objects that are extending the same class (like ObjectReference) then inheritance is probably the best option. Performance and what is best depends on what those functions do. If they need to reference or run functions on the objects they're already attached to then you want to keep them in those scripts or use inheritance. If they are primarily trying to act on some other object then they'll perform best if attached to that object. (But don't attach scripts directly to the player even if that's the object you use most often.) If they manipulate or compare lots of things or act primarily on the player placing them in a common script might be good. But if you place such a function in the quest script and it needs to be called by multiple objects at the same time you might run into problems as they various script fight over which gets priority. Global functions aren't used much because if they need to access other objects they still have to get locks on each object which generally makes them slower than the other options (although the function on the quest script can have the same problem). Link to comment Share on other sites More sharing options...
Hoamaii Posted June 19, 2016 Author Share Posted June 19, 2016 Thanks guys for the detailed inputs, it does help a lot :smile: Never tried to do a global library, though I've taken a real good look at the way Chesko does it - and never tried to create scripts that extend other scripts either (though I assume it only implies to change the "extends" part of the scriptname). I don't think I need to create a global function, because I don't plan to extend this mod much atm. But the thing I can't really attach them to the objectReferences or forms that these functions will affect. One function for instance is used to recalculate the weight of a piece of armor (a bag) which, depending on its form, its biped slot, the number of cloud chests it's linked to and the items these chests store will change every time the player uses that bag. I can't attach these functions to the chests (objectReferences in this case) nor the armor forms because the whole idea is to let the player pick which cloud chests or which slot he/she wants to use or not, among other things. These functions have quite a few variables (they're probably slow too even though I use arrays) but I have no other choice than casting them on scripts which are not attached to the objects they affect. The way I've designed this, they should not be called simultaneously by several objects - they can be called in several different ways, by player using an object or casting a spell, but never (I hope) at the same time - thanks for mentioning it cdcooley, I hadn't thought of that. I guess my best bet at the moment is attaching them to a quest then? I have only tested it on a small scale at the moment - it works fine, but I fear they may run pretty slow when they'll have to run on hundreds of stored items... Link to comment Share on other sites More sharing options...
cdcooley Posted June 19, 2016 Share Posted June 19, 2016 Just avoid doing things that require iterating through all items in those containers whenever possible. For example, use GetTotalItemWeight() on a container to get the combined weight of everything in it. If you do need to iterate through the items in a container use loops with the new GetContainerForms function. float Function GetTotalItemGoldValue(ObjectReference SomeContainer) if !SomeContainer return 0.0 endif float gold = 0.0 Form[] itemList = SomeContainer.GetContainerForms() int i = itemList.Length while i > 0 i -= 1 gold += itemList[i].GetGoldValue() * SomeContainer.GetItemCount(itemList[i]) endwhile return gold EndFunction That will get their combined gold value and only require two function calls per item (and only one of those will have to get a lock on the container). The older method of using GetNthForm should be avoided since it's an extra function call every time through the loop. And since inventory is time critical avoid function calls when possible. Never use the convenience functions and use type casts to filter out things that aren't interesting if you can. For example, to remove all bows and arrows from the player's inventory you need to cast the base from to a Weapon type anyway (to see if it's a bow) so use that to your speed advantage. (GetType is much slower than a cast and the core type of all inventory items can be found with casts.) Function RemovePlayerBows(ObjectReference holder) Form[] itemList = PlayerRef.GetContainerForms() ; Actor property PlayerRef int i = itemList.Length while i > 0 i -= 1 Weapon item = itemList[i] as Weapon if item && item.HasKeyword(WeapTypeBow) ; Keyword property WeapTypeBow PlayerRef.RemoveItem(item, PlayerRef.GetItemCount(item), true, holder) elseif itemList[i] as ammo PlayerRef.RemoveItem(itemList[i], PlayerRef.GetItemCount(itemList[i]), true, holder) endif endwhile EndFunction No functions are needed in the loop unless the item is a weapon or ammo (so you can filter through hundreds of non-weapons in a single frame) and the functions accessing the player only have to run if the item is a bow or arrow. Unless the player has a very unusual number of bow/arrow types (and other weapons) that should complete in under a half of a second. Basically one frame per per weapon plus two more frames per bow/arrow type. Link to comment Share on other sites More sharing options...
Surilindur Posted June 19, 2016 Share Posted June 19, 2016 Thank you, cdcooley, for the explanation. I never thought about issues with multiple objects calling the same function at the same time. Something to keep in mind. Every day one learns something new. :) Also, there is a tiny little typo in the examples, where i -= 0 should be i -= 1. Link to comment Share on other sites More sharing options...
Recommended Posts