Skyrim Special Edition
0 of 0

File information

Last updated

Original upload

Created by

Acro

Uploaded by

Acro748

Virus scan

Safe to use

About this mod

Facial expression framework to extends the facial expression system to more facial expressions
Supports console commands and papyrus scripts similar to MFG

Requirements
Permissions and credits
Changelogs
Donations
Description

This mod is a framework that only extends facial expressions
so doesn't include all the extra facial expression morph files needed for it
but for example file that modders can refer to, support some extra facial expressions for vanilla race's
(sorry, i can't make the facial expression of vanilla race well)

also support extra facial expression tri file for the elin race

available for both player and NPC



Not a replacement for MFG mods!!

The mfg mods are for bug fix and better use of vanilla's facial expression function
This mod extends to use a new kind of facial expression that is not in vanilla's facial expression
So can be used with mfg mods and is not a replacement for mfg







How to set facial expression morph with console commands?
mfee <category number> <morph number> <value 0~100>

e.g.
mfee 0(mood) 5(MoodFlabbergasted) 80
mfee 7(tongue) 0(tongueOut) 40
mfee 0 3 100

to reset
mfee r
mfee reset

to reset category
mfee 2(ears) r
mfee 0 r
mfee 4 reset

to help print
mfee
- Categories will be printed

mfee 0
- morphs of mood category will be printed



Can I use it with MFG console commands/papyrus scripts?
- sure, it's similar to mfg, but it's a separate system from mfg
so you can use it together



How to use papyrus scripts?
please refer to MuFacialExpressionExtended.psc file in scripts/source folder
you can use it like this
MuFacialExpressionExtended.SetExpressionByNumber(Game.GetPlayer(), 0, 4, 80); set 80% of MoodTemptation in the mood category
for more info, please look at the for modder section



Can I add another tri file for facial expressions?
sure, please refer to for modder section


Support morph name / categories
Spoiler:  
Show

The categories support list :
0. Mood
1. Misc
2. Ears
3. Tail
4. Face
5. Eyes
6. Brows
7. Mouth
8. Tongue


The facial morph name list of Mood category : 
0. MoodAhegao
1. MoodAhegao2
2. MoodSulky
3. MoodLaugh
4. MoodFlabbergasted
5. MoodTemptation


The facial morph name list of Misc category : 


The facial morph name list of Ears category : 
0. EarsFront
1. EarsBack
2. EarsIn
3. EarsOut


The facial morph name list of Tail category : 
0. TailUpTailDown
1. TailLeftTailRight

The facial morph name list of Face category : 
0. FaceInflateCheeks


The facial morph name list of Eyes category : 
0. EyesIn
1. EyesOut
2. EyesSurprise
3. EyesShock


The facial morph name list of Brows category : 


The facial morph name list of Mouth category : 
0. MouthLaugh
1. MouthTemptation
2. MouthSmacklips
3. MouthFlabbergasted
4. MouthCry
5. MouthCat
6. MouthClench
7. MouthClenchLip
8. MouthPucker
9. MouthUpperUp
10. MouthBow


The facial morph name list of Tongue category : 
0. TongueOut
1. TongueUp
2. TongueDown
3. TongueLeft
4. TongueRight
5. TongueTwistLeft
6. TongueTwistRight

If you want to add another morph name with fixed number, please feel free to suggest on the forum




FAQ

Set the facial expression but doesn't work
- if the morph match to the facial expression is not exist in the tri file then it will not work

Set the facial expression, but doesn't work but player does
- the NPC is using an independent base facial expression trip file  if vertex count and vertex order in the mesh are the same, create an ini file to skse\plugins\MuFacialExpressionExtended folder to link it

Does this affect the save file?
- everything is not saved so if there's an facial expression that needs to be remained  you must re-run the function after the game loaded
  Also you can install and delete freely


Installation

1. install requirements
2. install the main file
- if you are playing the elin race then install the option file



Requirements

SKSE64 or SKSEVR
Address Library for SKSE Plugins (for SSE/AE)
VR Address Library for SKSEVR (for VR)



Compatibility

Support SE v1.5.97
Support AE all versions (if you have a problem with v1.6.1130 ~ v1.6.1170, install the latest Address library)

not verified for VR v1.4.15


For Modder

To link morph tri file and morph name in MFEE
Spoiler:  
Show

Make morph name in MFEE and morph name in tri file the same

e.g.
To add a new morph for MouthLaugh facial expressions to the tri file
create morph with the same morph name (MouthLaugh) and add it to the tri file
letter case is not important
it recognize them all in lowercase



To add morph file (tri) on MFEE
Spoiler:  
Show

1. Create ini file with any name in skse\plugins\MuFacialExpressionExtended folder
2. fill out the following form
ExtensionFile = <Headpart's facial expression tri file path>, <Extra facial expression tri file>, <Extra facial expression tri file2>, <Extra facial expression tri file3>...

<Headpart's facial expression tri file path> is .tri file of facial expressions linked to head part
<Extra facial expression tri file> is the facial expression tri file you want to add

data\meshes is the root location
so you have to fill out paths without data\meshes

also you can add multiple files by adding , or by adding multiple lines

e.g. 
to add new morph file to vanilla race head mesh

vanilla race's facial expression tri file of head mesh is data\meshes\actors\character\character assets\femalehead.tri
so fill out actors\character\character assets\femalehead.tri on <Headpart's facial expression tri file path>

new facial expression tri file is data\meshes\newmorphfile\abc.tri
so fill out newmorphfile\abc.tri on <Extra facial expression tri file>

then it's fill out like this

ExtensionFile = actors\character\character assets\femalehead.tri, newmorphfile\abc.tri


If you want to add and use anothermorphfile\dec.tri file and newmorphfile\abc.tri files together to the head mesh

ExtensionFile = actors\character\character assets\femalehead.tri, newmorphfile\abc.tri, anothermorphfile\dec.tri

or

ExtensionFile = actors\character\character assets\femalehead.tri, newmorphfile\abc.tri
ExtensionFile = actors\character\character assets\femalehead.tri, anothermorphfile\dec.tri

or

a.ini file
ExtensionFile = actors\character\character assets\femalehead.tri, newmorphfile\abc.tri

b.ini file
ExtensionFile = actors\character\character assets\femalehead.tri, anothermorphfile\dec.tri



To add new morph name / new category
Spoiler:  
Show

1. create ini file with any name in skse\plugins\MuFacialExpressionExtended\Morphs folder
2. fill out following form

<category name>|<morph name>

<category name>
 is the category name you want to add morph or the category you want to create
<morph name> is the morph name you want to add to the category
also separate the two with "|"

e.g.
Mood|ABCMood
Mood|VerySad
NewFacialCategory|NewCategoryMorph
letter case is not important
it recognize them all in lowercase



Description of the papyrus script functions
Spoiler:  
Show


int function GetVersion() global native
returns the API version of MFEE.dll
currently the latest version is 3


bool function RegisterNewMorphData(string a_morphBasePath, string a_morphPath) global native
add a new facial expression tri file to the head part
it's same as ini files in skse\plugins\MuFacialExpressionExtended folder
so data\meshes is root

returns false if fails and returns true if successful


bool function RegisterNewMorphNameOnCategory(string a_morphCategory, string a_morphName) global native
add new morph name on the category or add a new category name with morph name
it's same as ini files in skse\plugins\MuFacialExpressionExtended\morphs folder

returns false if fails and returns true if successful


string[] function GetExpressionCategories() global native
returns string array for categories name


int function GetExpressionCategoriesSize() global native
returns categories count


string function GetExpressionCategoryByNumber(int a_categoryNumber) global native
returns category name that matches number


string function GetExpressionCategoryByMorphName(string a_morphName) global native
returns category name that morph name exists


int function GetExpressionCategoryNumber(string a_morphCategory) global native
returns category number that matches category name


bool function IsValidExpressionCategory(string a_morphCategory) global native
returns false if invalid category and returns true if valid category


string[] function GetExpressionMorphNames(string a_morphCategory) global native
returns string array for morph names in the category name


int function GetExpressionMorphNamesSize(string a_morphCategory) global native
returns morph name count in the category name


string[] function GetExpressionMorphNamesByNumber(int a_categoryNumber) global nativereturns string array for morph names in the category number


string function GetExpressionMorphNameByNumber(string a_morphCategory, int a_morphNumber) global native
returns morph name that matches morph number in the category name


string function GetExpressionMorphNameByNumbers(int a_categoryNumber, int a_morphNumber) global native
returns morph name that matches morph number in the category number


int function GetExpressionMorphNameNumber(string a_morphName) global native
returns number that matches the morph name


bool function IsValidExpressionMorphName(string a_morphName) global native
returns false if invalid morph name and true if valid morph name


int function GetExpressionValueByName(actor a_actor, string a_morphName) global native
returns value of the morph name


int function GetExpressionValueByNumber(actor a_actor, int a_categoryNumber, int a_morphNumber) global native
returns value of the morph number in the category


function SetExpressionByName(actor a_actor, string a_morphName, int a_value) global native
set morph value of the morph name


function SetExpressionByCategory(actor a_actor, string a_morphCategory, int a_morphNumber, int a_value) global native
set morph value of the morph number in the category name


function SetExpressionByNumber(actor a_actor, int a_categoryNumber, int a_morphNumber, int a_value) global native
set morph value of the morph number in the category number


function RevertExpression(actor a_actor, string a_morphCategory = "") global native
revert/reset all morph value to 0 or revert/reset all morph value to 0 in the category name


function UpdateExpression(actor a_actor) global native
instant update facial expressions
you don't need to use it in general
this is just in case

function InitialMorphData(actor a_actor) global native
If the tri file of headpart is changed due to the replacement of the headpart or a new headpart is added
update the morph data so that mfee can work in the new headpart
All morph values are initialize after this so have to done again




To update tri file and config files in the real-time
Spoiler:  
Show

1. open the console
2. enter "mfee debug reload"
DO NOT USE it often in gameplay
it's experimental and please use only when testing mod



To instant update the actor's facial morph by console
Spoiler:  
Show

1. open the console
2. click the actor you want to update
3. enter "mfee debug update"
usually you don't need to use it
this is just in case



To use API for skse plugin modders
Spoiler:  
Show

Download "Modder Resource" in misc section
and include the Interface.h file in your source code

commonlib-ng is used as follows
#include "interface.h"

MFEE::InterfaceManager manager;
MFEE::IFacialExpressionExtended* mfee = manager.GetInterface(); //get interface from mfee.dll

if (!mfee) //check that the mfee interface is valid
return;
if (mfee->GetVersion() != 3) //check mfee interface version
return;
if (!mfee->IsValidExpressionCategory("mood")) //check that there is mood category, letter case doesn't matter
return;

std::vector<std::string> morphNames = mfee->GetExpressionMorphNames("mood"); //get morph names in mood category
std::vector<std::string> foundmorphName;

for (std::string morphName : morphNames)
{
if (morphName.contains("ahegao")) //find morph name that conatains "ahegao"
foundmorphName.push_back(morphName); //found MoodAhegao and MoodAhegao2
}

for (std::string morphName : foundmorphName)
{
mfee->SetExpressionByName(RE::PlayerCharacter::GetSingleton(), morphName, 50); //set MoodAhegao and MoodAhegao2 to 50
}
also you can rename interface.h file name

for Regular SKSE not commonlib, you should implement using the same message function of skse plugin's instead of InterfaceManager in Interface.h

for functions, refer to the papyrus section abovethe name and function are the same


Credit

CommonlibSSE-NG