Required reading: API Rundown: the basics & OSex's Animation labeling and tagging system explained & JContainers API
In OStim 1.0, there was no way to perform a "lookup" to get animation data. If you wanted a random blowjob animation to play, you had to have the animation itself hardcoded into an addon.
In OStim 2.0, a useful new script called ODatabase is included. It uses JContainers' JArrays to store JMaps, with each JMap containing animation data.
Why do we need to use Jcontainers instead of normal papyrus arrays? Well for starters, papyrus arrays are limited to 128 objects, and OSex has far more animations than that. Papyrus also doesn't have anything like a "dictionary", but that's exactly what a JMap is, which is super helpful for storing animation data.
Quick note: JArrays are called OArrays in the OStim source code, and JMaps are called OMaps. They're the exact same thing, so whenever you see OMap or OArray, it's the exact same thing as a JMap and a JArray, just a different name.
To start working with ODatabase, simply call getODatabase() from the main OStim script.
Let's look at what information ODatabase stores about each animation in OSex. Here is an animation pulled from the database
-------------------------------------------------------------------------
Name: Money Shot | Jerk
Scene ID: BB|Sy6!KNy9|HhPo|MoShoPo
Number of actors: 2
Position Data: Sy6!KNy9
Source Module: BB
Animation Class: HhPo
Animation ID 0: 0SxBB_HhPo-MoShoPo_S0
Animation ID 1: 0SxBB_HhPo-MoShoPo_S1
Animation ID 2: 0SxBB_HhPo-MoShoPo_S2
Animation ID 3: 0SxBB_HhPo-MoShoPo_S3
Animation ID 4: 0SxBB_HhPo-MoShoPo_S4
Animation ID 5: 0SxBB_HhPo-MoShoPo_S5
Is Aggressive: TRUE
Is Transitory Animation: False| Transitory animations are the "traveling" animations. If an animation is neither transitory nor a Hub, it is a sexual animation
Is Hub Animation: False| hub animations are non-sexual animations where the characters stand around, like the very first animation OSex starts in
Main controlling actor: 0| 0 = dom actor is doing most of the work, 1 = sub actor is doing most of the work (like in a blowjob)
Minimum Speed: 0
Maximum Speed: 5
Has Idle Speed: False| if the slowest speed is called "Idle"
-------------------------------------------------------------------------
The above is an OMap of a single animation. If we call Odatabase.getDatabaseOArray(), we get an OArray containing EVERY OSex animation installed in the game.
To sort through the massive JArray, ODatabase gives you a number of tools to narrow our search down. Essentially, to find a specific animation, we will start with the OArray containing every animation in the game, and then run a search on it with an Odatabase tool to return a smaller array closer to what we're looking for, and repeat this as many times as needed. See below!
Can you think of a better way to do the above function? We could also take the list of all sexual animations, make one copy that is the animations filtered by the BJ class, then make another copy which is all animations filtered by the ApPJ class, then merge the two OArrays and pick a random one.
It's a bit complicated, but quite powerful. Another example:
Essentially, you always start by running ODatabase.getDatabaseOArray() to get the OArray containing all of the animations, and then run filters on that until you get what you need. See OAiScript for these types of examples. To see all of the tools ODatabase gives you, open up Odatabasescript and start reading!
2 more notes: the database is written to disk and unloaded from memory when an animation is not running to save space. You can read the database file at ~\Documents\My Games\Skyrim Special Edition\JCUser\ODatabase.json
If you ever have to read data from the database while no animation is running, please run ODatabase.unload() when you're done. If you leave the database in memory, and the user saves, it will keep ~200 kbs of data to their SKSE cosave until they eventually start another scene and let the database unload. Having 200 extra kbs in your cosave isn't a huge deal, but it may slow down save times by about 1 second.
0 comments