Jump to content

FNIS for Modders / FNIS 4.0 [WIP]


fore

Recommended Posts

 

Honestly, I have no idea. 

 

Although, why do you want to use a furniture object with 2 markers, instead of 2 different objects? I wouldn't know how to make an NPC access one out of many markers. With a sit target package you only can use the object, without any parameters. Maybe it'S possible to make a new sittarget procedure. But I have no idea. And I don't see a reson to do so. Use 2 markers. Then you automatically have 2 animations. 

 

Well, actually there are furnitures with multiple markers, but they are mostly triggering same idle. Was doing some research today and all I found is that its done via "marker keywords" attached to each marker (in furniture window). Then "keyword" check is set in each related animation on list.

 

The thing I'm not 100% sure yet is if "marker keyword" option adds keyword to affected actor or its just requirement for specific marker activation?

 

The only vanilla furniture using multiple idles that I found so far is "ExecutionerChoppingBlock" and its animations hidden in Action Activate -> Chair -> "Executionee®

 

Is there any particular reason that I don't see?

 

Was thinking of using this function http://www.creationkit.com/IsFurnitureMarkerInUse_-_ObjectReference to check if other markers are "in use" to trigger some effects on one of them.

 

It could be kind of useful, since sex animatins could use method like that (two markers, then triggering animation when both are inUse) or something like interactive ZAZ devices where one actor sits inside when other is doing something else.

Link to comment

 

So I thinkk I ill skip this release, and start working on that missing piece which is the reason why 4.0 is still Beta: extend furniture animations. I now going to extend furnitures to the Sequenced Animations functionality (so you can define furnitures with as many animations and anima Objects as you like; simply say "fu" or "FU" instead of "sa" or "SA").

 

As soon as I have it ready I'll make a "restricted" Beta, to allow modders to switch to the new syntax before I release to final.

 

 

 

that means a chair/furniture can have more different sit animations... for example nomalSit, relaxedSit , upsetsit etc.. as root animations?

 

like:

 

sitonchair----idleenterinstant

              ----idleenter

              ----idle1 +>keywordExtraCondition1

              ----idle2 +>keywordExtraCondition2

              ----idle3 +>keywordExtraCondition3

              ----idle4 +>keywordExtraCondition4

              ----idle5 +>keywordExtraCondition5

                   ..

                   ..

              ----idleN +>keywordExtraConditionN

              ----idleExit

 

or mor like:

 

sitonchair----idleenterinstant

              ----idleenter

              ----idle +> plays sequenced Animations defined in behaviour file

              ----idleExit

 

 

?

Moin

Oli

 

Link to comment

 

 

Honestly, I have no idea. 

 

Although, why do you want to use a furniture object with 2 markers, instead of 2 different objects? I wouldn't know how to make an NPC access one out of many markers. With a sit target package you only can use the object, without any parameters. Maybe it'S possible to make a new sittarget procedure. But I have no idea. And I don't see a reson to do so. Use 2 markers. Then you automatically have 2 animations. 

 

Well, actually there are furnitures with multiple markers, but they are mostly triggering same idle. Was doing some research today and all I found is that its done via "marker keywords" attached to each marker (in furniture window). Then "keyword" check is set in each related animation on list.

 

The thing I'm not 100% sure yet is if "marker keyword" option adds keyword to affected actor or its just requirement for specific marker activation?

 

The only vanilla furniture using multiple idles that I found so far is "ExecutionerChoppingBlock" and its animations hidden in Action Activate -> Chair -> "Executionee®

 

Is there any particular reason that I don't see?

 

Was thinking of using this function http://www.creationkit.com/IsFurnitureMarkerInUse_-_ObjectReference to check if other markers are "in use" to trigger some effects on one of them.

 

It could be kind of useful, since sex animatins could use method like that (two markers, then triggering animation when both are inUse) or something like interactive ZAZ devices where one actor sits inside when other is doing something else.

 

 

These are very interesting findings, and lead us closer to the understanding how furniture REALLY work.

 

The keywords are very convenient to distinguish which furniture is used by a character, but I don't think they are unavoidable. Any query which determines the required animation will help. Important are "Getsitting = <n>" conditions. When "Getsitting = 2", then the Enter animation is played, and from there Getsitting returns 3, and then we can use different Idles in the furniture. The "EnterInstant" AnimEvent sem to be raised when the char already is in a sitting position, so this does nothing but avoid the enter animation.

 

One thing I don't know is, when a furniture has 2 or more markers (like the head chop). What marker will be selected as entry by a char? Certainly one which is not used yet. But others than that I haven't found any parameter to support that. I assume it's simply the (open) entry that is closest to a char. But's that's just an assumption.

 

But from here, the animations which are selected are exclusively determined by the conditions used in the CK idle animations. They are not triggered by the furniture or it's markers.

 

So I think, with the next FNIS version with more than one sit animation you will have 2 choices how to define conditions: either in the CK like today, or with SAE() in scripts. Shoulkd be the same result. Except when using SAE() you don't need to define any CK idles except Enter/EnterInstant/Exit. And even these 3 I'm not sure if we really need them all. Let's see what the tests will unveil. 

 

So remains the question how we can have 2 or more enter animations for one furniture. I don't think we need that. Just use a 0.1 sec idle, and from there jump in the fu sequence to the animation intended for the appropriate char. But if we really should need 2 different enter anims, I think I can add that at a later time. 

 

 

or mor like:

 

sitonchair----idleenterinstant

              ----idleenter

              ----idle +> plays sequenced Animations defined in behaviour file

              ----idleExit

 

I think with the above I have answered your question as well. Yes it will work like in your second list, except that EnterInstant is not an idle, but an AnimEvent, and comes AFTER idleenter (the char can enter instantly, because enter was already played).

 

 

EDIT: And I wanted to mention that sittarget packages are not the only way to use furnitures.

Minin works through a combination of activator and furniture. In one of their scripts, mining animations are started by an Activate().

Link to comment

Well not sure if I understand its mechanism but I think that conditions are checked from top of the list to the bottom (not for sub idles inside block only, but between other "idles groups" as well). Thats why if we set 3 different idle groups with the same keyword as "entry" (like they did with ChoppBlock) its conditions are checked from the first one then if it fits, it plays proper sub-idle and uses appropriate marker.

 

Need confirmation of all of an above^

 

The keywords I was talking about are marker specific keywords that are supposed to segregate appropriate Actors between specific markers. But after doing some tests: removing keywords "isExecutioner" etc. from ChoppingBlock  ("marker keywords"  in furniture window) I couldnt get any other result but always 'sitting' on marker 1 (of 0, 1, 2) - tried activation from different directions.

 

As you can observe on "bench" type of furnitures - ie. WRTempleBench01 (Whiterun) it does for sure support and recognize directional activation of markers (you can decide where to sit). Maybe ChoppingBlock is too small object and its collision mesh of marker 1 is covering whole object? No idea.

 

 

One thing I don't know is, when a furniture has 2 or more markers (like the head chop). What marker will be selected as entry by a char? Certainly one which is not used yet. But others than that I haven't found any parameter to support that. I assume it's simply the (open) entry that is closest to a char. But's that's just an assumption.

 

The way they do it (at least how it was suposed to work) is that they check "isExecutioner" keyword for 1st marker, then "isExecutionerGuard" for other, and if an Actor doesnt have any of these keywords he will be using the last remaining marker. Markers with "isExecutioner" and "isExecutionerGuard" are basically restricted for two specific NPC's. It is how I THINK it works or should work. Because as mentioned above removing these restricting keywords didnt seem to do anything, and is probably being overwritten by ChoppingBlockscript the same way as mining...

 

 

Also tried (using vanilla only anim events):

 

 

sitonchair----idleenterinstant

               ----idleenter

               ----idleCustom (random idle, IdleKneeling for example)

               ----idleExit

 

Enter/Exit working as intended, but idleCustom (it had no conditions declared at all) couldnt be called by console (.playidle idleCustom), but idleExit could - why? Is it how furniture SAs are supposed to work? Why vanilla events (like IdleKeeling, IdleSitCrossLegged etc) couldnt be called, but they use some other vanilla idles in ChoppingBlockscript (and why they do it in furniture?)

Link to comment

 

sitonchair----idleenterinstant

               ----idleenter

               ----idleCustom (random idle, IdleKneeling for example)

               ----idleExit

 

Enter/Exit working as intended, but idleCustom (it had no conditions declared at all) couldnt be called by console (.playidle idleCustom), but idleExit could - why? Is it how furniture SAs are supposed to work? Why vanilla events (like IdleKeeling, IdleSitCrossLegged etc) couldnt be called, but they use some other vanilla idles in ChoppingBlockscript (and why they do it in furniture?)

 

Ok, my mistake - used IdleKneelingEnter AnimEvent (as AnimEvent of idleCustom from an above example) instead of IdleKneeling.

 

- idleCustom (with IdleKneelingEnter event) couldnt be called after already called "idleenter" (with another x-Enter event)

 

- idleCustom (with IdleKneeling event) can be called, but its then sending "OnGetUp" papyrus event, so it practically isnt "sitting" anymore.

 

IdleKneeling event should be considered as furniture type event, why its sending "OnGetUp" event?

An above doesnt change the fact that they play idles manually in ChoppingBlockScript instead of triggering them by furniture? (it means that some events can be called in furniture without sending OnGetUp?)

 

I dont know how vanilla Enter EnterInstant Exit events are structured (it looks like FURNITURE1_Enter.hkx FURNITURE1_Loop.hkx are merged in one event? vanilla kneeling behaves exactly like that, it plays enter then loop), + theres probably some animation variables and params, that I dont understand, controlling all of that.

 

Link to comment

Oh yes. I totally missed those keywords for the markers. That's of course a very good reason.

 

I also have a possible explanation why you see no difference after changing the keywords. Maybe it's the same reason why you cannot switch back the "Opposite Gender Anims" options on some female actors once you have met them. The ExecutionerChoppingBlock furniture has a script. So at least for that reason data has to be stored for this object. Which means the data for this might be stored in your save file. But again, just an assumption.

 

Your console playidle tests will not give you any usable results. Because you can consider it as treat IF something LOOKS LIKE it's working. At least there is no connection to any furniture if you do it via console. Furniture idles have a relatively extensive setup (modifiers, variables setting and testing, ...), and calling something in between will certainly miss all of that. IF you are able to do so. Because most of the times the Loop animation isn't called by a specific AnimEvent, but by a generic "00NextClip". 

 

IdleKneeling is special, because there are 2 3some animations. One furniture anim activated by "IdleKneelingEnter", and a non-furniture animation activated by "IdleKneeling". So both animations have (almost) nothing in commen. However, the non-furniture version belongs to a tree called "IdleStopIdles", which apparently can stop other furniture animations, and therefore send a 00ResetClip which may cause some side effects you have seen.

 

If you are interested understanding what's happening when AnimEvents are called, I really recommend that you download and use CondenseBehavior. It can save you a lot of unnecessary testing. And with all that you know from your tests I have no doubt that you can easily understand it's information. And if not, you can still ask me.  :)

Link to comment

From what I understood so far:

 

- IdleEnterInstant AE is used by some kind of "wildcardTransitions" which are usually NULLed - wtf is that I dont even?

- IdleEnter AE is basically enter + loop animations in one

- IdleExit AE is separate exit animation

 

One question, why do you say that Exit is never used? Its never triggered or its translated from IdleChairExit call to proper event inside behavior file (my guess)?

 

...

"#1834" "hkbStateMachineStateInfo"
                     "enterNotifyEvents"  #1833 
                     "exitNotifyEvents"  #1832 
                     "generator"  #1831 
                     "name" ChairDrinkingIdleVar 
                     "stateId" 1 

                      "#1833" "hkbStateMachineEventPropertyArray"
                       "id" 20 <!-- HeadTrackingOff -->

                      "#1832" "hkbStateMachineEventPropertyArray"
                       "id" 18 <!-- HeadTrackingOn -->

                      "#1831" "hkbClipGenerator"
                       "name" ChairDrinkingIdleVar 
                       "animationName" Animations\male\AnimObjectChairDrinkingIdleVar1.hkx 
                       "triggers"  #1830 

                        "#1830" "hkbClipTriggerArray"
                         "localTime" -0.200000 
                         "id" 91 <!-- ChairNextClip -->
                         "localTime" 1.842000 
                         "id" 20 <!-- HeadTrackingOff -->
                         "localTime" 4.821000 
                         "id" 18 <!-- HeadTrackingOn -->

Could you explain me what triggers what in this example? Is "generator" a trigger or enter/exit NotifyEvents are enabling this state that is then calling "generator" to switch to the next clip via <!-- ChairNextClip --> ? Need help with understanding the structure, this code is so fucked up...

Link to comment

Once you are used to read the most common elements I think you will see that this format is not hard to read, at least from it's basic structure.

 

First of all you really need to straighten out you terminology. AEs are not one or two animations. They are events that are sent at one place, and received at another one of the behavior graph's state machine. They can have 2 different purposes:

  1. move the behavior graph from one state to another, or
  2. inform the engine about certain things  (e.g to equip certain AnimObjects)

Interesting is purpose (1), because a state change will cause a new animation to play. This is done by a "generator" which directly or indirectly will lead to a "clipgenerator" which denominates the animation. So ONE state-changing AE (1) will always cause ONE animation to play.

 

To be sent, AEs are either "triggered" or "notified". "triggers" are events relative to the begin or end of a clip. "notifies" are raised when a state is started or ended. This differentiation is necessary to know, because notified AEs will not show up in OnAnimationEvent().

 

To be received, AEs have to be part of a TransitionInfoArray. This TransitionInfoArray either describes specific "transition", which means it describes which AEs will cause a transition from the current state to another specific state. Mostly used in a sequence of animation files to play the next animation.

Or it can be a "wildcardtransition" which describes which AE will cause a transition to one of the current sub-trees states, independent of the current state. Mostly used to start a new sequence of animation  files.

 

I think this overview answers most of your questions.

And when I said that "Exit is never used" I only referred to the Exit event generated by FNIS by this specific furniture animation. Because you should use "IdleChairExitStart" like most vanilla furniture animations.

 

Edit: Maybe the tree structure is important to understand. 

It starts with a StateMachine (StM). Each StM can have an ARBITRARY number of StateMachineInfos (StMI). Each StMI has a state. States only have to be unique, but only for all direct StMIs of one StM (sub-trees can and will use the same state number). StMIs define "generators", which are either ONE StM (defining a sub-tree), or a ClipGenerator (as leaves). So basically it's

 

StM (root)

  StMI (state 0)

    StM (level 2)

      StMI (state 0)

        ClipGenerator

      StMI (state 1)

        ClipGenerator

      .......

  StMI (state 1)

    StM (level 2)

      StMI (state 0)

        StM (level 3)

      ........

  StMI (state 2)

 .....

 

 

Link to comment

Well, thanks for explaination im in process of understanding it. ;)

 

(read my PM first please)

 

In meanwhile, an offtopic question: what do you know about paired animations?

 

Curious if the reason of everyone not using paired anims is behavior limitation or something else? Are they that much harder to make (2 skeletons in one scene) or what? I found they could be easily called via http://www.creationkit.com/PlayIdleWithTarget_-_Actor

 

I found they are in 0_master.hkx  (unfortunately)

 

 

 

"#0763" "hkbStateMachineStateInfo"
"generator" #0764
"name" Player_HugA
"stateId" 59

"#0764" "hkbStateMachine"
"variableBindingSet" #0772
"name" Player_HugA_Behavior
"startStateId" 0
#0765
"wildcardTransitions" null

"#0772" "hkbVariableBindingSet"
"variableIndex" 51 <!-- bIsSynced -->

"#0765" "hkbStateMachineStateInfo"
"generator" #0766
"name" Player_HugA_DisablePitch
"stateId" 0

"#0766" "hkbStateMachine"
"variableBindingSet" #0771
"name" Player_HugA_H2HSlamA_Behavior
"startStateId" 0
#0767
"wildcardTransitions" null

"#0771" "hkbVariableBindingSet"
"variableIndex" 58 <!-- DisablePitch -->

"#0767" "hkbStateMachineStateInfo"
"generator" #0768
"name" pa_HugA
"stateId" 0

"#0768" "BSSynchronizedClipGenerator"
"name" pa_HugA
"pClipGenerator" #0769
"SyncAnimPrefix" & #9216;
"bSyncClipIgnoreMarkPlacement" false
"bApplyMotionFromRoot" false

"#0769" "hkbClipGenerator"
"name" Paired_HugA
"animationName" Animations\Paired_HugA.hkx
"triggers" #0770

"#0770" "hkbClipTriggerArray"
"localTime" 0.000000
"id" 615 <!-- NPCKillMoveStart -->
"localTime" 3.466667
"id" 156 <!-- NPCpairedStop -->
"localTime" 3.466667
"id" 616 <!-- NPCKillMoveEnd -->
"localTime" 3.466667
"id" 159 <!-- PairEnd -->

 

 

Link to comment

Yes I know paired animation. I invested a lot of time a year ago. And failed at that time like I did with furnitures. Interestingly they have things in common, like one actor walking to the other before the actual animation plays. And I had the same type of failure as with furnitures. But since I founde the furniture problem, I have good hopes I can make the paired as well. BUT...


 


I have never heard that any modder has made a paired animation. The famous Saidenstorm at the Beth forum had claimed he knew, and has given a sketchy breakdown about what to do, but that's it. So I think, before any animator shows me a working replacer paired animation, I don't think I will invest any more into that.


 


But paired animations would really be the hit. I consider furniture animation only a work-around for paired animations in most (sex mod) cases.


Link to comment
  • 2 weeks later...

To everyone interested in the FNIS 4.0 progress:

 

I know I have been very quiet recently, but I can assure you I have spent as much time I could afford.This "full blown" furniture stuff was/is really a tough thing. So many issues, a complicated behavior structure, and many areas in the generator I had to change and even redesign. I also did some optimizations to ease the  mt_behavior size limit a little bit. And not to forget creture stuff that needed some better integration into the whole procedure.

 

But now I can tell that I have the first "full blown" furniture animations created by the generator running. Arbitrary number of single animations per fu, and arbitrary AOs.

 

Of course I need to do a lot of testing now after all those changes, and a few minor things still to fix. But I think I can release a finale beta within 1-2 weeks.

 

Ok, don't panic. I understand that FNIS' beta status has become more and more of an annoyance. So this final beta will only last about 1 more week. To allow modders to switch to the new fu syntax, and give me some time to update documentation (including a better modders' doc), and update the language files with the translators. And fix bugs that modders can find during this time. 1 week only.

 

And then I hope things get REALLY started.  :)

Link to comment

One suggestion I would make is by default always have 2 anim vars on every actor.

 

0.0 = Not Installed

AnimVar FNISversion REAL 4.0
AnimVar FNISCreature REAL 0.0

With this in mind, is it possible to be able to create read only AnimVar's that can only be changed when the behavior file is recreated?

 

Something like.

AnimVarReadOnly MaxNodeScale REAL 3.0
AnimVarReadOnly MinNodeScale REAL 0.1

AnimVarReadOnly FNISversion REAL 4.0
AnimVarReadOnly FNISCreature REAL 0.0
Link to comment

if you want to work through anim vars and not update scripts.

 

Pros

  • Compile it once and if the Anim Vars don't change you're done
  • Version defined in one location. FNIS_FNISBase_List.txt ( or FNIS_FNIS_List.txt? )

Cons

  • Slower
Scriptname FNIS Hidden

float function GetVersion(bool abCreature = false) global
  if abCreature
    return Game.GetPlayer().GetAnimationVariableFloat("FNISCreature")
  else
    return Game.GetPlayer().GetAnimationVariableFloat("FNISversion")
  endIf
endFunction

If you want to avoid using anim vars. Maybe to reduce behavior file bloat?

Pros

  • Faster

Cons

  • FNIS & FNIS Creature would have to have their own copies of the same script though with the chance of a partial reinstall of FNIS leaving the wrong version in the script folder.
  • You'll have to compile new versions with each update to FNIS.
Scriptname FNIS Hidden

float fnisBase = 4.0
float fnisCreature = 0.0

float function GetVersion(bool abCreature = false) global
  if abCreature
    return fnisCreature
  else
    return fnisBase
  endIf
endFunction
Link to comment

 

One suggestion I would make is by default always have 2 anim vars on every actor.

 

0.0 = Not Installed

AnimVar FNISversion REAL 4.0
AnimVar FNISCreature REAL 0.0

With this in mind, is it possible to be able to create read only AnimVar's that can only be changed when the behavior file is recreated?

 

Something like.

AnimVarReadOnly MaxNodeScale REAL 3.0
AnimVarReadOnly MinNodeScale REAL 0.1

AnimVarReadOnly FNISversion REAL 4.0
AnimVarReadOnly FNISCreature REAL 0.0

 

I liked the idea. But I can only realize one part, and it's not as easy to use as it looks like.

 

Keep in mind that Animvars are no FNIS "invention", they are simply translated into Behavior variables. So I have to use what they provide. What I can do is define "AnimVar FNISversion REAL 4.0" right away as part of FNISBase\FNIS_FNISBase_List.txt. This will add this variable to behaviors\FNISBase\FNIS_FNIS_Base_Behavior.hkx and define FNISversion for every character, PC and all NPCs.

 

But to do the same for every creature, I would have to add a mod every creature. 49 mods just to define the version? I don't know if you or your users really want that. Or make a third default mod (FNISCreature) just for characters? Might confuse many.

 

There is also no possible attribute ReadOnly. HBT or the behavior data simply doesn't provide that.

 

A comparison with a REAL version number will work at the most for versions like 4.0, 4.5. You cannot exactly represent 4.1 with a real number. So it's unpredictable if the comparison of 2 real 4.1 numbers, one defined as Animvar in behaviors, and one as papyrus script variable will match. Needs to be tested. But what about 4.1.1?

In other products I have seen solutions with several integers, like VersionMajor, VersionMinor1, VersionMinor2. But is this what you want?

Link to comment

I liked the idea. But I can only realize one part, and it's not as easy to use as it looks like.

 

Keep in mind that Animvars are no FNIS "invention", they are simply translated into Behavior variables. So I have to use what they provide. What I can do is define "AnimVar FNISversion REAL 4.0" right away as part of FNISBase\FNIS_FNISBase_List.txt. This will add this variable to behaviors\FNISBase\FNIS_FNIS_Base_Behavior.hkx and define FNISversion for every character, PC and all NPCs.

 

But to do the same for every creature, I would have to add a mod every creature. 49 mods just to define the version? I don't know if you or your users really want that. Or make a third default mod (FNISCreature) just for characters? Might confuse many.

 

There is also no possible attribute ReadOnly. HBT or the behavior data simply doesn't provide that.

 

A comparison with a REAL version number will work at the most for versions like 4.0, 4.5. You cannot exactly represent 4.1 with a real number. So it's unpredictable if the comparison of 2 real 4.1 numbers, one defined as Animvar in behaviors, and one as papyrus script variable will match. Needs to be tested. But what about 4.1.1?

In other products I have seen solutions with several integers, like VersionMajor, VersionMinor1, VersionMinor2. But is this what you want?

 

If it's available from the player actor that's sufficient I think. Last option would also work. A fourth parameter can be used for bit flags for any yes/no questions about the current build you want to pass on to the modder. 

AnimVar FNISmajor INT32 4
AnimVar FNISminor INT32 0
AnimVar FNISbuild INT32 3
AnimVar FNISflags INT32 2

Then this for scripting

Scriptname FNIS Hidden

; e.g.
;AnimVar FNISmajor INT32 4
;AnimVar FNISminor INT32 0
;AnimVar FNISbuild INT32 3
;AnimVar FNISflags INT32 2

int property ISALPHA = 1 autoreadonly
int property ISBETA  = 2 autoreadonly

; call FNIS.GetVersion()
string function GetVersion() global
	actor   kPlayer = Game.GetPlayer()
	return  kPlayer.GetAnimationVariableInt("FNISmajor") as String \
	+ "." + kPlayer.GetAnimationVariableInt("FNISminor") as String \
	+ "." + kPlayer.GetAnimationVariableInt("FNISbuild") as String
endFunction

; call FNIS.GetMajor()
int function GetMajor() global
	return Game.GetPlayer().GetAnimationVariableInt("FNISmajor")
endFunction

; call FNIS.GetMinor()
int function GetMinor() global
	return Game.GetPlayer().GetAnimationVariableInt("FNISminor")
endFunction

; call FNIS.GetBuild()
int function GetBuild() global
	return Game.GetPlayer().GetAnimationVariableInt("FNISbuild")
endFunction

; call FNIS.GetFlag(FNIS.ISBETA)
Bool function GetFlag( int aiFlag ) global
	return Math.LogicalAnd(Game.GetPlayer().GetAnimationVariableInt("FNISflags"), aiFlag) as Bool
endFunction

FNIS.7z

Link to comment

Crap...

 

Do anim vars persist with the save? If so, the all of the above won't work.

 

You don't change those animvars, so they stay as they are as part of the behavior files. That's not a problem.

 

One problem could be that providing scripts requires an esp/esm. And I don't really want to do that just for versioning.

Link to comment

Silent version. Tested in FNIS 4.0 Beta 3.

 

This will not pollute the Papyrus Log file with errors when the anim var is not found.

Scriptname FNIS Hidden

; silence the Papyrus log =====================================================
bool[] function getPapyrusDebugState() global
	bool[] bDebugState = new bool[3]
	bDebugState[0] = Utility.GetINIBool("bLoadDebugInformation:Papyrus")
	bDebugState[1] = Utility.GetINIBool("bEnableTrace:Papyrus")
	bDebugState[2] = Utility.GetINIBool("bEnableLogging:Papyrus")
	return bDebugState
endFunction

bool[] function getPapyrusDebugSilent() global
	bool[] bDebugState = new bool[3]
	bDebugState[0] = false
	bDebugState[1] = false
	bDebugState[2] = false
	return bDebugState
endFunction

function setPapyrusDebugState( bool[] bDebugState ) global
	Utility.SetINIBool("bLoadDebugInformation:Papyrus", bDebugState[0])
	Utility.SetINIBool("bEnableTrace:Papyrus", bDebugState[1])
	Utility.SetINIBool("bEnableLogging:Papyrus", bDebugState[2])
endFunction

; FNIS Versioning =============================================================
; call FNIS.GetVersion()
string function GetVersion( bool abFailSilent = true ) global
	actor kPlayer      = Game.GetPlayer()
	bool[] bDebugOff   = FNIS.getPapyrusDebugSilent()
	bool[] bDebugState = FNIS.getPapyrusDebugState()

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugOff )
	endIf

	string ret = kPlayer.GetAnimationVariableInt("FNISmajor") as String \
	+ "." + kPlayer.GetAnimationVariableInt("FNISminor") as String \
	+ "." + kPlayer.GetAnimationVariableInt("FNISbuild") as String

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugState )
	endIf
	
	return ret
endFunction

; call FNIS.GetMajor()
int function GetMajor( bool abFailSilent = true ) global
	bool[] bDebugOff   = FNIS.getPapyrusDebugSilent()
	bool[] bDebugState = FNIS.getPapyrusDebugState()

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugOff )
	endIf

	int ret = Game.GetPlayer().GetAnimationVariableInt("FNISmajor")

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugState )
	endIf
	
	return ret
endFunction

; call FNIS.GetMinor()
int function GetMinor( bool abFailSilent = true ) global
	bool[] bDebugOff   = FNIS.getPapyrusDebugSilent()
	bool[] bDebugState = FNIS.getPapyrusDebugState()

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugOff )
	endIf

	int ret = Game.GetPlayer().GetAnimationVariableInt("FNISminor")

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugState )
	endIf
	
	return ret
endFunction

; call FNIS.GetBuild()
int function GetBuild( bool abFailSilent = true ) global
	bool[] bDebugOff   = FNIS.getPapyrusDebugSilent()
	bool[] bDebugState = FNIS.getPapyrusDebugState()

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugOff )
	endIf

	int ret = Game.GetPlayer().GetAnimationVariableInt("FNISbuild")

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugState )
	endIf
	
	return ret
endFunction

; FNIS Version Flags ==========================================================
int property ISALPHA = 1 autoreadonly
int property ISBETA  = 2 autoreadonly

; call FNIS.GetFlag( ([mymod] as FNIS ).ISBETA )
Bool function GetFlag( int aiFlag, bool abFailSilent = true ) global
	bool[] bDebugOff   = FNIS.getPapyrusDebugSilent()
	bool[] bDebugState = FNIS.getPapyrusDebugState()

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugOff )
	endIf

	bool ret = Math.LogicalAnd(Game.GetPlayer().GetAnimationVariableInt("FNISflags"), aiFlag) as Bool

	if abFailSilent
		FNIS.setPapyrusDebugState( bDebugState )
	endIf
	
	return ret
endFunction

BSA in attached 7z

FNIS.7z

Link to comment

Separated Papyrus functions from FNIS.

; call FNIS.GetMajor()
int function GetMajor( bool abFailSilent = true ) global
	bool[] bDebugOff   = Papyrus.getDebugLogSilent()
	bool[] bDebugState = Papyrus.getDebugLogState()

	if abFailSilent
		Papyrus.setDebugLogState( bDebugOff )
	endIf

	int ret = Game.GetPlayer().GetAnimationVariableInt("FNISmajor")

	if abFailSilent
		Papyrus.setDebugLogState( bDebugState )
	endIf
	
	return ret
endFunction

FNIS.7z

Papyrus.7z

Link to comment

Excellent. So let's do it.

 

Now do you want me to pack that with FNIS, or do you want to keep it at LoversLab? Both is ok with me. And both proceedings have advantages. Especially here you can update much faster. I try to reduce the number of FNIS releases as much as I can.

 

But in any case I ask you for a few lines of documententation. Including authorship and link

(if you want me to pack that with FNIS, please do a fuzzy link, like "Lovers-Lab" with explanation to remove the "-". A well-know fellow-modder at Nexus was just banned for one month for distributing an "illegal" link).

If you keep the scripts here I would use this for the modder's doc, which I will distribute as pdf in the future.

 

Link to comment

                I just wanted to take a moment to thank you for making animations in skyrim possible. I don't like to single people out because its impossible to thank everyone for thier contributions, but I'll make an exception in this case. You manged to come up with a way to add animations to skyrim that works and works well so that others can create frameworks and mods around said system. It's one of those background apps like skse that no one really thinks about when there playing there game but without it what there playing would not be possible.

               In the interest of keeping it short I'll just say thanks and creature support has been a long requested feature thank you for bringing it to lovers lab. I'll let you get back on topic.

Link to comment

Excellent. So let's do it.

 

Now do you want me to pack that with FNIS, or do you want to keep it at LoversLab? Both is ok with me. And both proceedings have advantages. Especially here you can update much faster. I try to reduce the number of FNIS releases as much as I can.

 

But in any case I ask you for a few lines of documententation. Including authorship and link

(if you want me to pack that with FNIS, please do a fuzzy link, like "Lovers-Lab" with explanation to remove the "-". A well-know fellow-modder at Nexus was just banned for one month for distributing an "illegal" link).

If you keep the scripts here I would use this for the modder's doc, which I will distribute as pdf in the future.

 

I'll supply a copy without the Papyrus utilities. It's possible that multiple calls to a function that use those utilities in a threaded environment can turn off the papyrus log.

Link to comment

Archived

This topic is now archived and is closed to further replies.

  • Recently Browsing   0 members

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

Important Information

We have placed cookies on your device to help make this website better. You can adjust your cookie settings, otherwise we'll assume you're okay to continue. For more information, see our Privacy Policy & Terms of Use