dullman Posted January 19, 2024 Posted January 19, 2024 Hello I wanted to ask about all techniques used by extensible frameworks since I'm currently trying to implement some mod that would be easy to extend by mods that I would create in future, means it would not be a hard dependency, also add a possibility to inference with every aspect of my mod. What I mean by that just take a look for handlers that I created for mod ; Handlers ; Registering as cow handlers String beforeRegisterAsCowHandler = "beforeRegisterAsCow" String afterRegisterAsCowHandler = "afterRegisterAsCow" ; Changing morphs on breasts handlers String beforeBreastResizeHandler = "beforeBreastResize" String getMaxMorphValueHandler = "getMaxMorphValue" String getMinMorphValueHandler = "getMinMorphValue" String afterBreastResizehandler = "afterBreastResize" String getMorphLevelFromMilkLevelHandler = "getMorphLevelFromMilkLevel" ; Calculate milk production handlers String beforeCalculateIncreaseInMilkAmountHandler = "beforeCalculateIncreaseInMilkAmount" String maxAmountOfMilkCalcHandler = "maxAmountOfMilkCalc" String productionRateCalcHandler = "productionRateCalc" String initialTempProductionRateCalcHandler = "initialTempProductionRateCalc" String totalAmountOfbeingHungryOrThirstyHandler "totalAmountOfbeingHungryOrThirsty" String tempProductionRateCalcHandler = "tempProductionRateCalc" String increaseInTempProductionRateCalcHandler = "increaseInTempProductionRateCalcH" String producedMilkCalcHandler = "producedMilkCalc" String idealMilkAmountCalcHandler = "idealMilkAmountCalc" String overLimitMilkCalcHandler = "overLimitMilkCalc" String totalMilkAmountCalcHandler = "totalMilkAmountCalc" String tempMilkProductionRateCalcHandler = "tempMilkProductionRateCalc" String afterCalculateIncreaseInMilkAmountHandler = "afterCalculateIncreaseInMilkAmount" as you see each mod can register in some required mod to manage extensible framework a handler for those "events" I mean in reality it would be a function named like handler with Func suffix, which got a prevValue (a returned value from previous handlers) and standard set of parameters which can be extended by custom parameters existing on client form (yeah I know here might be a problem but since for now at least it compile, but as checking if it's really working I will wait until I have a running instance of skyrim se). So my question is how other frameworks resolved need for being extensible other than creating custom dll?
traison Posted January 19, 2024 Posted January 19, 2024 Typically what you see in framework type mods is that they provide a script that has global functions in it. These global functions can be used without having a reference to an instance of that script i.e. you can call <scriptname>.<functionname>() instead of having to get a reference to the Quest (or other object) form and cast it to a script type. These global functions do the Quest casting if needed, allowing for easier use of a framework's features. Generally I would avoid overusing this. You wouldn't want to expose all your Quest script functions through a system like this, or any high-traffic functions for that matter. Every call will again retrieve the form reference (if its needed for what the function does). It would result in some rather bloated code. Another thing is mod events. This is one of the only truly optional interfaces that I can think of that really makes a mod dependency optional. If a mod event is sent but there's no one to receive it, it is simply discarded. With global functions you still have a hard depdency. Another optional interface is those provided by StorageUtil, but there is no built in messaging system in that. What I personally do is a combination of mod events and what I call a linker "library". The linker library is a script with global functions, but instead of working like a proxy for Quest functions, it has functions that return references to the Quest objects. This linker library does not create an optional dependency (as it will fail without the linker), but it does allow me to be both lazy and efficient at the same time: MyModMain main = MyModLinker.GetMain() If (main) main.DoThings() main.DoMoreThings() main.DoEvenMoreThings() main.DoAllTheThings() EndIf Reference material can be found in SexLabUtil.psc for instance.
dullman Posted January 19, 2024 Author Posted January 19, 2024 1 hour ago, traison said: Typically what you see in framework type mods is that they provide a script that has global functions in it. These global functions can be used without having a reference to an instance of that script i.e. you can call <scriptname>.<functionname>() instead of having to get a reference to the Quest (or other object) form and cast it to a script type. These global functions do the Quest casting if needed, allowing for easier use of a framework's features. Generally I would avoid overusing this. You wouldn't want to expose all your Quest script functions through a system like this, or any high-traffic functions for that matter. Every call will again retrieve the form reference (if its needed for what the function does). It would result in some rather bloated code. Another thing is mod events. This is one of the only truly optional interfaces that I can think of that really makes a mod dependency optional. If a mod event is sent but there's no one to receive it, it is simply discarded. With global functions you still have a hard depdency. Another optional interface is those provided by StorageUtil, but there is no built in messaging system in that. What I personally do is a combination of mod events and what I call a linker "library". The linker library is a script with global functions, but instead of working like a proxy for Quest functions, it has functions that return references to the Quest objects. This linker library does not create an optional dependency (as it will fail without the linker), but it does allow me to be both lazy and efficient at the same time: MyModMain main = MyModLinker.GetMain() If (main) main.DoThings() main.DoMoreThings() main.DoEvenMoreThings() main.DoAllTheThings() EndIf Reference material can be found in SexLabUtil.psc for instance. yeah I also thought about mod events even tried to work with them but from my understanding it's really hard for them to influence result of event (since basically event is send after calculation completed). As for current I just write some code and probably when all basic dependencies are online I would test how much slower is skyrim with it if we get only main lib and around 100 hundred listeners if it really slow then I just don't publish a mod until I find a way to be acceptable for perfomance side
traison Posted January 19, 2024 Posted January 19, 2024 (edited) I overlooked the fact that if you reverse my linker library idea, you can use it to make a true optional dependency. Not sure why I didn't think of this when I created the design document for my own mods. Example of what I do: Common Module: -- CommonScript -- CommonLinker ---- void* GetCommonScript Feature Module1: -- FeatureScript ---- CommonLinker.GetCommonScript() Example of the reverse with true optional dependencies: Common Module: -- CommonScript Feature Module1: -- FeatureScript ---- FeatureLinker.GetCommonScript() -- FeatureLinker ---- void* GetCommonScript Edited January 19, 2024 by traison
dullman Posted January 21, 2024 Author Posted January 21, 2024 On 1/19/2024 at 4:24 PM, traison said: I overlooked the fact that if you reverse my linker library idea, you can use it to make a true optional dependency. Not sure why I didn't think of this when I created the design document for my own mods. Example of what I do: Common Module: -- CommonScript -- CommonLinker ---- void* GetCommonScript Feature Module1: -- FeatureScript ---- CommonLinker.GetCommonScript() Example of the reverse with true optional dependencies: Common Module: -- CommonScript Feature Module1: -- FeatureScript ---- FeatureLinker.GetCommonScript() -- FeatureLinker ---- void* GetCommonScript The concept is working nearly fine I'm by myself get also this idea although later so you are inventor But there is one problem we should have a handler Interface with predefined handlers that both Common Module and Feature Module knows about it so it's has a small dependency between them, but as long we install this common interface we can practically cover all cases that need to be done by sending announcer/register message through ModEvent and call handlers from feature Modules on requested part of code. As for currently my code is at start of sixth refactor every time I write a half of new feature I got a better Idea for this (now it was an idea for plugin manager following your shared idea although as I first it read I didn't imagine how to use it properly in papyrus)
Recommended Posts
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 accountSign in
Already have an account? Sign in here.
Sign In Now