Jump to content

SexLab Framework Development


Recommended Posts

Ashal,

 

I know you're not necessarily an animator, and maybe I'm talking 100% out of my ass, but as I was recently getting around to adding creature support for my own mod, I started looking at the creature animations for the first time.

 

I noticed that several of the "sentient man-sized humanoid" animations have the same 3 (missionary/doggy/holding), such as Draugr/Falmer/Troll/etc.  It seems that they use the same base animation, just replace the actor with [insert appropriate monster].

 

But what I noticed was that those particular animations were actually very nice, animating both the aggressor and the victim quite nicely.  Which led me to wondering if it is possible to take those 3 animations and make them available as part of the regular animations (for Player and/or NPC use).

Link to comment

Ok here is the example plugin. Added a spell that sets fly cam for 6 seconds as example mod to show how to use script. I only tested it few times, hopefully no problems although I'm not sure if this is thread safe to call TFC function from scripting thread.

 

Edit: oh PS in game open console type "help tfc 4" and add the spell to yur player. I didn't make a quest for it.

 

Edit2: I haven't tested yet, are the first person stuff on development branch like joy of perspective? So you can see yourself and look around.

tfcexample.zip

Link to comment

Ok here is the example plugin. Added a spell that sets fly cam for 6 seconds as example mod to show how to use script. I only tested it few times, hopefully no problems although I'm not sure if this is thread safe to call TFC function from scripting thread.

 

Awesome, thanks for the giving it a shot, I'll be sure to put it through it's paces and make use of it.

 

If you're willing to do more and take requests; in addition to TFC could you do SUCSM as well? That way the fly camera could be slowed down to useable speeds by default in addition to toggled?

 

And if you're feeling particularly up for a challenge, some functions to get/set the rotation of NiNodes would help tremendously in the 1st person animation implementation. Digging through PapyrusNetImmerse.cpp and in NiTypes.h to see where the NetImmerse papyrus functions get the X,Y,Z coordinates of  nodes I found this:

// 34
class NiTransform
{
public:
	NiMatrix33	rot;	// 00
	NiPoint3	pos;	// 24
	float		scale;	// 30
}; 

pos is where SKSE is pulling positions from, which leads me to assume rot would be the rotation information, but that's as far as I was able to get in my incredibly limited (read: basically nonexistant) C skills.

Link to comment

Edit2: I haven't tested yet, are the first person stuff on development branch like joy of perspective? So you can see yourself and look around.

 

It's basically a "faked" version of that, since there is no way add custom first person animations except as replacers.

 

So to get around the lack of first person animations, it clones the player and inserts them in the players place during animation, and then shrinks the player down and continually moves the player to the coordinates of the clones NiNode "NPCEyeBone" on their skeleton to keep the player at the clones eye level. However that only moves them to the clones head, still rotated as if standing straight up, not with the angle of the clones head, leading it to look really weird in spots where you would expect the camera to be oriented in a specific way. I confirmed that manually editing the first person skeleton.nif's rotation worked for rotating the first person camera in game, just no way to do that repeatedly in Papyrus; hence the above request.

Link to comment

Alright I'll see what I can do about those two things, more interested in 1st person stuff but SUCSM should be easy enough. This first person mode emulation sounds really complicated. :s If I could somehow access NPCEyeBone in C I could just make it so that game sets camera position to that every frame and disable the effect when camera gets close to player then player fades out. No need for 1st person animations and should work, but I'm not sure how to even start. :D

Link to comment

Alright I'll see what I can do about those two things, more interested in 1st person stuff but SUCSM should be easy enough. This first person mode emulation sounds really complicated. :s If I could somehow access NPCEyeBone in C I could just make it so that game sets camera position to that every frame and disable the effect when camera gets close to player then player fades out. No need for 1st person animations and should work, but I'm not sure how to even start. :D

 

It's not NPCEyeBone that gets rotated in order to rotate the actor. When I tested it manually editing the skeleton, the node rotated was "NPC Rotate [Rot ]" the space in [Rot_] included. This was is in /data/meshes/actors/character/_1stperson/skeleton.nif.

 

I would assume it doable without targeting a specific node like that though, I'd suggest looking at SKSE's existing NetImmerse Papyrus script, which will resolve any given node of an actor's 3rd or 1st person skeleton.

 

In Papyrus:

float Function GetNodePositionX(ObjectReference ref, string node, bool firstPerson) native global

In SKSE PapyrusNetImmerse.cpp

	NiAVObject * ResolveNode(TESObjectREFR * obj, BSFixedString nodeName, bool firstPerson)
	{
		if(!obj) return NULL;

		NiAVObject	* result = obj->GetNiNode();

		// special-case for the player, switch between first/third-person
		PlayerCharacter * player = DYNAMIC_CAST(obj, TESObjectREFR, PlayerCharacter);
		if(player && player->loadedState)
			result = firstPerson ? player->firstPersonSkeleton : player->loadedState->node;

		// name lookup
		if(nodeName.data[0] && result)
			result = result->GetObjectByName(&nodeName.data);

		return result;
	}
	
	float GetNodePositionX(StaticFunctionTag* base, TESObjectREFR * obj, BSFixedString nodeName, bool firstPerson)
	{
		NiAVObject	* object = ResolveNode(obj, nodeName, firstPerson);

		return object ? object->m_worldTransform.pos.x : 0;
	}

This is all sticking with my current papyrus based implementation for it though, where I have to update the players position a LOT in order to keep the movement looking smooth, making it pretty CPU intensive. 

 

If you were able to go beyond that and come up with a way to actually manipulate the free camera's position + rotation for example, that would very likely perform and look a hell of a lot better than all the nonsense I'm doing now with cloning the player. I have absolutely zero idea on how feasible that actually is though.

Link to comment

 

 

 

And what are you defining as "up to date version"?

 

 

V1.24?

It worked fine when i was updating from the older Version, then i had to reinstall skyrim because a mod that i was testing screwed up my game, and they never worked properly eversince.

 

 

1.24 isn't the newest development version, it's the newest release version. Note that this is the development thread, not the release thread.

 

 

 

Ashal,

 

I know you're not necessarily an animator, and maybe I'm talking 100% out of my ass, but as I was recently getting around to adding creature support for my own mod, I started looking at the creature animations for the first time.

 

I noticed that several of the "sentient man-sized humanoid" animations have the same 3 (missionary/doggy/holding), such as Draugr/Falmer/Troll/etc.  It seems that they use the same base animation, just replace the actor with [insert appropriate monster].

 

But what I noticed was that those particular animations were actually very nice, animating both the aggressor and the victim quite nicely.  Which led me to wondering if it is possible to take those 3 animations and make them available as part of the regular animations (for Player and/or NPC use).

 

As I understand it, the animations are made with specific skeletons, in this case the skeletons are creature specific. I would assume the animator animated it once, then just swapped out the skeletons for different creatures and exported the animation files again. In which case, Gone may be willing to export  those animations using the human skeleton for all positions, would have to ask him. 

 

But I'm no animator, I could equally be talking out my ass here.

Link to comment

 

As I understand it, the animations are made with specific skeletons, in this case the skeletons are creature specific. I would assume the animator animated it once, then just swapped out the skeletons for different creatures and exported the animation files again. In which case, Gone may be willing to export  those animations using the human skeleton for all positions, would have to ask him. 

 

But I'm no animator, I could equally be talking out my ass here.

Fair enough!

 

I did just that in the http://www.loverslab.com/topic/20589-bestiality-animations-pack/page-15 :)

Link to comment

I could use some advice from any modder - I'm going to release a new version of my mod today or tomorrow with one of the new additions being an orgy spell that animates up to nine targets. The problem is that SexLab will not grab actors into the scene (i'm guessing due to validateActor) if they are in the middle of some idle animation like eating bread or clapping to a bard, which tends to end with SexLab dragging only half of the actors into one of the three animated groups. The next version of SexLab will probably have this spell work better since the three separate animations would probably start fewer seconds apart from one another.

 

So the solution I thought of is before I register the actors into actor lists, to put them into a quest AliasRef and a new faction with the SexLabDoNothing package attached to it. But I don't know how to assign an actor into the first empty AliasRef slot. Can anyone offer some info on how I could do that?

Link to comment

ReferenceAlias Property ref1 Auto

ReferenceAlias Property ref2 Auto

ReferenceAlias Property ref3 Auto

ReferenceAlias Property ref4 Auto

 

if(!ref1.GetReference())

ref1.ForceRefTo(akTarget)

elseif(!ref2.GetReference())

ref2.ForceRefTo(akTarget)

elseif(!ref3.GetReference())

....

 

You could also put the references into array for convenience if you like.

 

 

 

 

Ashal: the rotation is saved as a matrix consisting on 9 float values, do you know how to use it?

Link to comment

ReferenceAlias Property ref1 Auto

ReferenceAlias Property ref2 Auto

ReferenceAlias Property ref3 Auto

ReferenceAlias Property ref4 Auto

 

if(!ref1.GetReference())

ref1.ForceRefTo(akTarget)

elseif(!ref2.GetReference())

ref2.ForceRefTo(akTarget)

elseif(!ref3.GetReference())

Will try that. Thanks!

Link to comment

I have another request: When you send the animation change event, we currently don't have a possibility to check if the animation is going forward or backwards. As of now that makes it impossible to sync concurrently running sex scenes.

 

As far as I have seen you already have the functionality to send optional parameters. My suggestion is to change the SendThreadEvent()-call from the function ChangeAnimation() in ThreadController to

 

 

If(backwards)
    SendThreadEvent("AnimationChange", -1)
Else
    SendThreadEvent("AnimationChange", 1)
EndIf
Link to comment

Ashal: the rotation is saved as a matrix consisting on 9 float values, do you know how to use it?

 

I'm not sure how that would convert into the xyz angles they use in game, but I'd have to play around with the numbers in game to see how they react to know for sure.

 

I assume it's a 3x3 rotation matrix which should be able to convert into euler angles pitch/bank/heading (x/y/z), which is what Skyrim uses at a surface level. The conversion would be best done in C though, as it would be exponentially faster than me doing it in Papyrus.

 

I have another request: When you send the animation change event, we currently don't have a possibility to check if the animation is going forward or backwards. As of now that makes it impossible to sync concurrently running sex scenes.

 

As far as I have seen you already have the functionality to send optional parameters. My suggestion is to change the SendThreadEvent()-call from the function ChangeAnimation() in ThreadController to

If(backwards)
    SendThreadEvent("AnimationChange", -1)
Else
    SendThreadEvent("AnimationChange", 1)
EndIf

For code simplicity sake, I'd probably make it

SendThreadEvent("AnimationChange", (backwards as int))

that way it would send 0 for forward and 1 for backward.

 

Alternatively I could do this:

 SendThreadEvent("AnimationChange", aid)

sending the actual index id of the animation, which Controller.SetAnimation(int animid) will take as an argument.

Link to comment

Ok here is the example plugin. Added a spell that sets fly cam for 6 seconds as example mod to show how to use script. I only tested it few times, hopefully no problems although I'm not sure if this is thread safe to call TFC function from scripting thread.

 

Edit: oh PS in game open console type "help tfc 4" and add the spell to yur player. I didn't make a quest for it.

 

Edit2: I haven't tested yet, are the first person stuff on development branch like joy of perspective? So you can see yourself and look around.

 

 

Just implemented the TFC stuff in the latest push to the development branch. It's all working fantastically, thanks again.

 

Though if you'll permit my being incredibly picky over keeping naming schemes consistent across the framework, I recompiled the plugin from the source you included:

  • Renamed the plugin to SexLabPlugin.dll
  • Renamed the function to ToggleFreeCamera()
  • Bound it to the script SexLabUtil

Assuming You're okay with me altering it some like that, if not I can change it all back to how you had it.

 

Also added an additional global helper function to help with it's usage, allowing the camera to be set directly as enabled or disabled.

scriptname SexLabUtil hidden

function ToggleFreeCamera(bool stopTime = false) global native
	
function EnableFreeCamera(bool enabling = true) global
	bool InFreeCamera = Game.GetCameraState() == 3
	if (enabling && !InFreeCamera) || (!enabling && InFreeCamera)
		ToggleFreeCamera()
	endIf
endFunction
Link to comment

Alright I'll rename next release like you have, I added a lot more stuff. There is a problem with the rotation thing right now, I don't know how to make papyrus arrays in C, so it's necessary to call the function 9 times, not sure how to get around this. At first lets test like this and later you will write some code in papyrus to handle the matrix stuff and I'll convert to C maybe it will be possible to reduce this amount then. Actually I don't like this high speed changing of camera stuff from papyrus anyway, this should be in C. :D

 

Does objectreference form ID change when you modify mod load order or remove / add some mods?

Link to comment

Alright I'll rename next release like you have, I added a lot more stuff. There is a problem with the rotation thing right now, I don't know how to make papyrus arrays in C, so it's necessary to call the function 9 times, not sure how to get around this. At first lets test like this and later you will write some code in papyrus to handle the matrix stuff and I'll convert to C maybe it will be possible to reduce this amount then. Actually I don't like this high speed changing of camera stuff from papyrus anyway, this should be in C. :D

 

As far as I know you can't return an array. Papyrus based functions can and do, but no native functions do.

 

There is no native form[] items = ActorRef.GetAllItems() for example. There's not a single native function that returns as an array, and all the Papyrus and SKSE native functions that return lists of stuff, work as get Nth item functions like this:

; // Get number of items they have and loop through each one
int i = ActorRef.GetNumItems()
while i
	i -= 1
	form item = ActorRef.GetNthForm(i)
	; // Do stuff to item here
endWhile

So copying what previous SKSE functions have done, something like this for getting the rotation matrix would probably be best:

; // @param int n = matrix rot[n] to get
; // @param ObjectReference ref = the actor/object whose NiNode we want to look at
; // @param string node = the name of the NiNode to get the rotation for
; // @param bool firstPerson = whether to get the NiNode from the first person skeleton or not
; // @return float = the nth index value of the rotation matrix array
float function GetNthNodeRotationMatrix(int n, ObjectReference ref, string node, bool firstPerson) native global


; // @param int n = matrix rot[n] to be changed
; // @param ObjectReference ref = the actor/object whose NiNode we want to look at
; // @param string node = the name of the NiNode to get the rotation for
; // @param bool firstPerson = whether to get the NiNode from the first person skeleton or not
; // @param float value = value of the new rot[n]
; // @return void
function SetNthNodeRotationMatrix(int n, ObjectReference ref, string node, bool firstPerson, float value) native global

If you can do a Get and a Set version of that, I'll play around with the matrix numbers in Papyrus and see what works in game, then you can see about making C based versions of that.

Link to comment

Yeah that's how I made it so far, do you know if objectreference form ID is modified when changing plugin load order or installing / removing some plugins? I asked in previous post with edit but it's on last page now :P

 

Or maybe there is another way to keep track of object reference via some unique ID. I need it for one part of code you didn't ask for or has nothing to do with anything :D

Link to comment

Yeah that's how I made it so far, do you know if objectreference form ID is modified when changing plugin load order or installing / removing some plugins? I asked in previous post with edit but it's on last page now :P

 

Or maybe there is another way to keep track of object reference via some unique ID. I need it for one part of code you didn't ask for or has nothing to do with anything :D

 

The first 2 characters in the hex form id denote the load order.

 

so 0A00D67 is form 00D67 in the 10th loaded mod after Skyrim.esm.

 

I'm not sure how it handles the form id's from there in the event of load order changes, I'm fairly certain the save files compensate for it somehow though.

 

Only other unique ID would be Editor ID's, which wouldn't track well for ObjectReferences, since those would in most cases point to the base objects they spawned from.

Link to comment

Wait but how do I differentiate references then?

 

For example lets say there is a sword in mod 8 with ID = D67, can there be a bread in mod 7 with same ID (D67)? If yes then exchanging mod orders would cause the IDs to swap? If no then how do mods go together that have the same ref ID of object in editor but don't know about each other.

Link to comment

Wait but how do I differentiate references then?

 

For example lets say there is a sword in mod 8 with ID = D67, can there be a bread in mod 7 with same ID (D67)? If yes then exchanging mod orders would cause the IDs to swap? If no then how do mods go together that have the same ref ID of object in editor but don't know about each other.

 

I could be wrong here, but I don't think they track like that in game. This is as I understand it:

 

The sword be a 0800D67 Weapon form and the bread would be a 0700D67 Potion form, neither the sword or bread exist anywhere in the world.

 

But once they are spawned into a cell, they are no longer  a Weapon or Potion form of that id, they become a ObjectReference instead which reference those original forms as parents, inheriting all their information so the game knows what the object reference is, but they have their own unique form ids like FF003D3 and FF00A21 for example. So anytime you edited 0700D67 you would be editing ALL bread in the world, if you wanted to edit just the single bread object you were given, you would edit the object reference pointing at FF00A21.

 

These ObjectReference IDs are independent of load order, and tracked by your save file. This is where save bloat tends to happen, a dirty mod spawns a bunch of items and doesn't clean them up, leaving your save file tracking tons of FFxxxxxx references it's never going to use.

 

So in this case, changing the sword and breads load order, their base id's would change, but their ObjectReference ID's would remain unchanged.

Link to comment

Ok I wrote some more stuff but I didn't test!

 

Added:

set speed of flycam (tested)

 

set node position (dunno what a node even is, so not tested any of this)

get/set node rotation

 

set/get infinite amount of int, float, string, list of int, list of float, list of string on any object reference or globally which can be accessed by any mods and are saved to save game file - only tested set string on NPC, save game, loaded game and string was still on NPC, everything else didn't test, I calculated that setting an int on 1000 different objects takes around 30 kb of room in savegame file max unless you set name of value really long. I know you probably don't need this in sexlab but I think it will be useful for other mods like procreation that saves data dynamically on NPC or to connect mods with each other so that they aren't required but work together if both exist. For example sexlab submit could check if NPC has "IsPuppet" == 1 then maybe +100% chance to speech success, but if my mod (puppet master) isn't even installed this does nothing extra and doesn't add any requirements. Before you release next version we can see which ones to put in sexlab plugin and which ones separate but for now it's easier for me if all is in same dll and script. :)

 

If someone could test these it would be good, test node because I don't know how and test the data stuff because I'm lazy. :blush:

 

Edit: node rotation index = 0 to 8 (included)

slplugin.zip

Link to comment

Ok I wrote some more stuff but I didn't test!

 

Added:

set speed of flycam (tested)

 

set node position (dunno what a node even is, so not tested any of this)

get/set node rotation

 

set/get infinite amount of int, float, string, list of int, list of float, list of string on any object reference or globally which can be accessed by any mods and are saved to save game file - only tested set string on NPC, save game, loaded game and string was still on NPC, everything else didn't test, I calculated that setting an int on 1000 different objects takes around 30 kb of room in savegame file max unless you set name of value really long. I know you probably don't need this in sexlab but I think it will be useful for other mods like procreation that saves data dynamically on NPC or to connect mods with each other so that they aren't required but work together if both exist. For example sexlab submit could check if NPC has "IsPuppet" == 1 then maybe +100% chance to speech success, but if my mod (puppet master) isn't even installed this does nothing extra and doesn't add any requirements. Before you release next version we can see which ones to put in sexlab plugin and which ones separate but for now it's easier for me if all is in same dll and script. :)

 

If someone could test these it would be good, test node because I don't know how and test the data stuff because I'm lazy. :blush:

 

Edit: node rotation index = 0 to 8 (included)

 

The storage functions could be game changing for a lot of stuff if they work as intended. I know I at least could rewrite heavy sections of SexLab to make use of it. I'd be concerned about what sort of effects it might have with load order changing, or how the stored variables are handled on deleted references. So will do some extensive testing on it first, but awesome nonetheless.

 

Do you know how it will handle deleted objects at all? Like say I store a string on an ObjectReference with formID of FF00A4F, I later disable and delete that reference, so FF00A4F now points at nothing, Skyrim's garbage collector comes along and frees up that address for new objects, since the original is now gone. If a new object is spawned and it claims the now empty address of FF00A4F, it's an entirely new and different object, will it still have that string?

 

Where does it store the variables on an object?

 

Link to comment

Yes, I thought about that as well but didn't find a solution for now. I don't actually save the values on the objects, but in a separate location where key of map is the form ID. So I don't know how to handle the deletion, will need to think about this a little while.

Link to comment

Yes, I thought about that as well but didn't find a solution for now. I don't actually save the values on the objects, but in a separate location where key of map is the form ID. So I don't know how to handle the deletion, will need to think about this a little while.

 

Probably not a perfect solution, but in addition to using FormID as the storage key, in a separate much simpler list also store something else semi-unique to that ObjectReference, like the name of the object or the EditorID. Then whenever accessing the storage, validate that the form id's stored identifier hasn't changed, and if it has changed then clear out it's storage.

Link to comment

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 account

Sign in

Already have an account? Sign in here.

Sign In Now
  • 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