nopse0 Posted August 23, 2024 Posted August 23, 2024 (edited) SlaveTatsNG View File SlaveTats as C++/SKSE plugin. This is a one to one conversion of SlaveTats.pex to C++. GitHub: https://github.com/nopse0/SlaveTatsNG/tree/master Advantages: Lightning fast More robust (because when a Papyrus script calls a native function, it is scheduled for execution in the Skyrim Game Main thread, i.e. there are no multithreading problems when multiple Papyrus scripts are adding and removing tattoos at the same time). Fully compatible with SlaveTats, so it can be installed/deinstalled at any time (uses the same JContainer structures and does exactly the same as SlaveTats) Uses CommonLibSSE-NG, so it should run on all major Skyrim versions + Gog (tested on 1.6.1170 and 1.5.97) Requirements: Original Papyrus SlaveTats, if you want to use it's MCM Alternatively, there now is a new CatMenu/ImGui gui (tested on Skyrim 1.6.1170 and 1.5.97). It has the following requirements: CatMenu https://www.nexusmods.com/skyrimspecialedition/mods/65958 (don't forget to copy 'imgui.dll' to the game folder, as described on the CatMenu Nexus page). And very recommended, if you ALT-TAB between Windows and Skyrim: Alt-Tab Stuck Key Fix NG https://www.nexusmods.com/skyrimspecialedition/mods/148466 Disadvantages: No ModEvents are send Patches: I created a few patches for mods, which were directly adding and removing overlays, to use SlaveTats instead, so that what they are doing is synchronized with SlaveTats. Bathing In Skyrim Tweaked v3.4 (17-May-2023) from Monoman1: Spank That Ass v4.8 BETA SE (27-Apr-2021) from Monoman1: Changelog: Spoiler 0.6.3: It is possible now to prevent that node overrides are applied to actors with the help of locks. SlaveTatsNG will honor these locks, and do nothing in synchronize_tattoos if another mod has the actor lock. This mechanism is independent of SlaveTatsNG, and can be used without it to synchronize node override manipulations by multiple mods, see NiNodeOverrideLock.psc. 0.6.4: Cleanup, forgot to implement the synchronize_tattoos function in the MCM test menu 0.6.5: Added a C++ interface, which can be queried via the SKSE messaging functions (merge request from @cybercheese). So, now it's possible to use SlaveTats directly from other SKSE plugins without Papyrus. I created a tiny project, with which I tested the interface: https://github.com/nopse0/SlaveTatsNG-testing Basically, the interface can be queried like this: void messaging_hook([[maybe_unused]] SKSE::MessagingInterface::Message* a_message) { switch (a_message->type) { case SKSE::MessagingInterface::kPostLoad: { const char* slavetatsPlugin = "SlaveTatsNG"; SKSE::GetMessagingInterface()->RegisterListener(slavetatsPlugin, [](SKSE::MessagingInterface::Message* a_msg) { if (a_msg && a_msg->type == SlaveTatsNG::MessageType::Interface) { const SlaveTatsNG::Addresses* iface = SlaveTatsNG::Addresses::from_void(a_msg->data); logger::info("SlaveTatsNG Interface found: address = {}", (void*)iface); logger::info("simple_add_tattoo: address = {}", (void*)iface->simple_add_tattoo); } }); } } } 0.6.7: Use 'slavetats/blank.dds' instead of 'default.dds' for clearing overlay slots 0.6.8: Added an Is3DLoaded() check at the begin of synchronize_tattoos Credits: Many thanks to ponzipyramid for his OverlayManager. I learned a lot from that, i.e. how to use the reflection interface of JContainers and RaceMenu, and without his address tables to cope with different RaceMenu DLL versions, this wouldn't have been possible. 0.6.9: The name of the texture used for clearing unused overlay slots can now be configured, per default SlaveTats's "blank.dds" is used. This can be changed in SKSE/plugin/SlaveTatsNG/SlaveTatsNG.ini: [Config] ### Texture name used for clearing unused overlay slots: ### # SlaveTats empty texture (is used per default) # blankTextureName="Actors\Character\slavetats\blank.dds" # Empty texture from RaceMenu # blankTextureName="actors\character\overlays\default.dds" # Same without path, probably also works # blankTextureName="default.dds" After changing the empty texture name, the game must be saved and restarted to refresh the shaders (everything looks purple at first) 0.6.10: Implemented the missing tattoo_magic functions ("DibellanDefender"). 0.6.11: Removed the "excluded_by" and "requires" checks in the SlaveTats MCM, because dynamically updating the MCM list boxes doesn't work. This does no harm, because applying tattoos which are excluded by another tattoo, or which require another tattoo which isn't present still fail, it's just that all tattoos in the MCM are shown. 0.7.0: synchronize_tattoos was executed concurrently by the Papyrus threads instead of by the Skyrim main thread 0.7.1: Auto 'Add/remove tattoos' when Skyrim is started 0.7.2: 0.7.1 didn't work, rebuilding the SlaveTats cache must be done in 'kPostLoadGame' (and, I guess, the SlaveTatsNG.dll plugin must be loaded after the JContainers64.dll plugin (otherwise JContainers isn't initialized when the cache is rebuild), but, luckily, this is automatically the case, because SKSE plugins are loaded in alphabetical order) 0.7.3: Changed to Colorglass's 'commonlibsse-ng' vcpkg distro (Windows 8 compatibility). 0.7.4: Added a function to get the time elapsed since the game was last saved. This can be used with "Simple Clock on-screen" https://www.nexusmods.com/skyrimspecialedition/mods/89360 to make a "Save game reminder" (always annoying if the game crashes after not having saved for an hour, or so). Simply replace Int[] time = PO3_SKSEFunctions.GetSystemTime() with Int[] time = SlaveTatsNG.get_last_save_time() 0.7.5: RaceMenu addresses are now read from a Json file, instead of being hardcoded 0.8.0: # Changes ## 0.8.0 * The boolean field ``gloss`` in tattoos isn't used anymore, it has been replaced by two new float fields, ``glossiness`` and ``specularstrength``. * Three other new fields have been added to tattoos: ``specularstrength``, ``emissivemult`` and ``glowtexture``. * Besides the old ``apply_overlay`` function in ``SlaveTats.psc``, a new function ``apply_overlay_ex`` has been added to ``SlaveTatsNG.psc``: ``` bool function apply_overlay_ex(Actor target, bool isFemale, string area, int slot, string path, int color, int glow, float glossiness = 0.0, string bump_path = "", float alpha = 1.0, float specular = 0.0, string glow_path = "", float emissive_mult = 1.0) global native ``` It contains the above mentioned ``gloss`` change and the three new fields for the NiOverride parameters ``SpecularStrength``, ``EmissiveMult`` and ``Texture[glow/detail]``. The old Papyrus function in ``SlaveTats.psc`` with boolean ``gloss`` parameter still exists; if ``gloss = true``, it calls ``apply_overlay_ex`` with hardcoded ``glossiness = 5.0`` and ``specularstrength = 5.0`` parameters. ``` bool function apply_overlay(Actor target, bool isFemale, string area, int slot, string path, int color, int glow, bool gloss, string bump = "", float alpha = 1.0) global native ``` Note: ``apply_overlay/apply_overlay_ex`` only apply NiOverride overlays, they don't change the SlaveTats JContainer tattoos, so they shouldn't be called directly. Instead edit the SlaveTats tattoos with JContainer or SlaveTats functions, and then call ``synchronize_tattoos``. * The tattoo version (``.SlaveTats.version``) of actors is changed from ``1.0`` to ``2.0``. 0.8.1: Fixed copy&paste error. Submitter nopse0 Submitted 08/23/24 Category Adult Mods Requirements Skyrim AE Regular Edition Compatible No Install Instructions Edited September 24, 2024 by nopse0 10
Unknown22923 Posted August 23, 2024 Posted August 23, 2024 Was wondering, how would this do with Fast Tats?
nopse0 Posted August 23, 2024 Author Posted August 23, 2024 (edited) I was using Fast Tats, but I had problems. I have 4 mods which add and remove SlaveTats tattoos: Apropos2, Blushing when aroused, Bathing in Skyrim and Spank that Ass (I patched the latter two to use SlaveTats), and after sleeping a few hours, all of them try to do this simultaneously! This often caused CTD's when the overlays are rendered, because Ponzi made the mistake to start a new thread each time an overlay is applied. But even when I fixed this, I still had problems, because the Papyrus Threads of the 4 Mods above and Ponzi's C++ thread all modify the same JContainer JFormDB at the same time concurrently, that totally screws it up. No, I think the only solution is to implement everything what SlaveTats does with native functions, and since native functions are executed by the Skyrim Main thread (except you fork new threads!), everything is single threaded and nicely synchronized. (Ps: and the original SlaveTats is far too slow, if so many tattoos are applied, it takes an hour or so (no lie) until everything is applied). Edited August 23, 2024 by nopse0
Unknown22923 Posted August 23, 2024 Posted August 23, 2024 Ahaa, so this is a alternate to fast tats... gonna test this out as I too also experience random CTD but unsure from what. Thank you for sharing this! Also aren't you are the one that made NiOverride Cleaner on Nexus?
nopse0 Posted August 23, 2024 Author Posted August 23, 2024 Yea, exactly :). A byproduct of the problems with Fast Tats, but it doesn't help against this multithreading problems, sooner or later everything gets screwed up again
Arcane Wanderer Posted August 23, 2024 Posted August 23, 2024 Great! I don't know how many mods need the mod events? If it's an issue, maybe have a miniscule papyrus script to fire the events but use your dll for the heavy lifting? 1
Guest Posted August 23, 2024 Posted August 23, 2024 (edited) 2 hours ago, nopse0 said: I was using Fast Tats, but I had problems. I have 4 mods which add and remove SlaveTats tattoos: Apropos2, Blushing when aroused, Bathing in Skyrim and Spank that Ass (I patched the latter two to use SlaveTats), and after sleeping a few hours, all of them try to do this simultaneously! This often caused CTD's when the overlays are rendered, because Ponzi made the mistake to start a new thread each time an overlay is applied. But even when I fixed this, I still had problems, because the Papyrus Threads of the 4 Mods above and Ponzi's C++ thread all modify the same JContainer JFormDB at the same time concurrently, that totally screws it up. No, I think the only solution is to implement everything what SlaveTats does with native functions, and since native functions are executed by the Skyrim Main thread (except you fork new threads!), everything is single threaded and nicely synchronized. (Ps: and the original SlaveTats is far too slow, if so many tattoos are applied, it takes an hour or so (no lie) until everything is applied). To clarify some things, the concurrency bug causing CTDs in FT is related to multiple threads writing to the same standard hash map not JContainers, which is why crash logs frequently refer to xhash. OM doesn't spawn threads, but rather hooks the one's the engine generates per actor so I call them ActorThreads. I have a fix locally, but I'm also working on wrapping up OM's own Papyrus API which is intended for wider use beyond making ST faster i.e. a Wet Function Redux, BiS, SCOE, and Animated Overlays remake. Managing overlays for all of these mods in the same centralised plugin would speed everything up and reduce cross-mod incompatibility. For any potential users reading this, I would definitely recommend using this instead of Fast Tats until I have those fixes out. Edited August 23, 2024 by ponzipyramid
Herowynne Posted August 23, 2024 Posted August 23, 2024 I see “ae” in this mod’s name. Which game versions is this mod compatible with? Is this mod compatible with SE 1.5.97 ?
nopse0 Posted August 23, 2024 Author Posted August 23, 2024 (edited) On 8/23/2024 at 6:54 AM, ponzipyramid said: To clarify some things, the concurrency bug causing CTDs in FT is related to multiple threads writing to the same standard hash map not JContainers, which is why crash logs frequently refer to xhash. OM doesn't spawn threads, but rather hooks the one's the engine generates per actor so I call them ActorThreads. I have a fix locally, but I'm also working on wrapping up OM's own Papyrus API which is intended for wider use beyond making ST faster i.e. a Wet Function Redux, BiS, SCOE, and Animated Overlays remake. Managing overlays for all of these mods in the same centralised plugin would speed everything up and reduce cross-mod incompatibility. For any potential users reading this, I would definitely recommend using this instead of Fast Tats until I have those fixes out. Hi! Glad to see you are still alive, I thought you quit LL. I think you are wrong, you fork new threads: namespace { constexpr std::string_view PapyrusClass = "OverlayManager"; void SyncContext(RE::StaticFunctionTag*, RE::Actor* a_target, std::string a_context, int a_list, int a_added, int a_removed) { std::thread t1{[=] { ActorManager::SyncContext(a_target, a_context, a_list, a_added, a_removed); }}; t1.detach(); } I also spawn a thread in simple_add_tattoo and simple_remove_tattoo, because otherwise the hardware breakpoints you set with VisualStudio are not caught, and Skyrim exits, but I use t1.join() instead of t1.discard(), so that the function waits until the thread is finished. What you said, is exactly what I think. There is definitely a need for a central, coordinated overlay management. Because even if SlaveTats would be perfect, there are still a lot of mods, which manually manipulate overrides/overlays, e.g. "SOS Pubic hairs", so there is always a chance of CTD. Edited August 24, 2024 by nopse0
nopse0 Posted August 23, 2024 Author Posted August 23, 2024 (edited) 2 hours ago, Herowynne said: I see “ae” in this mod’s name. Which game versions is this mod compatible with? Is this mod compatible with SE 1.5.97 ? I used a powerofthree project as template. It has three targets, buildae, buildse and buildvr. I build the ae version, so it won't run with 1.5.97 Edited August 23, 2024 by nopse0 1
nopse0 Posted August 23, 2024 Author Posted August 23, 2024 Has anybody an idea, how I can fix the mod description ? In the on-screen editor everything looks allright, but when the page is displayed, the spacing is totally wrong.
Unknown22923 Posted August 23, 2024 Posted August 23, 2024 3 hours ago, nopse0 said: Has anybody an idea, how I can fix the mod description ? In the on-screen editor everything looks allright, but when the page is displayed, the spacing is totally wrong. Yee... seems a bit odd, reminds me of that Microsoft word meme where if you move a picture the hole document get an extra chromosome. Could it be one of those cases where you need to "paste as normal text" seem like you got a different grey background, if you copy paste the description that is.
duy123a Posted August 23, 2024 Posted August 23, 2024 8 hours ago, nopse0 said: I used a powerofthree project as template. It has three targets, buildae, buildse and buildvr. I build the ae version, so it won't run with 1.5.97 Can you build for 1.5.97? I want to test it a bit 1
papavitch1 Posted August 23, 2024 Posted August 23, 2024 Sorry do we remove the old slave tats and replace with this or remove some scripts and replace. Just wondering
VeraDra Posted August 23, 2024 Posted August 23, 2024 6 hours ago, duy123a said: Can you build for 1.5.97? I want to test it a bit compile it yourself 1
duy123a Posted August 24, 2024 Posted August 24, 2024 6 hours ago, VeraDra said: compile it yourself Because I can't? Not everyone is developer. That's why I ask him to help me with that. Be nice to everyone and don't be a jerk. 5
40Karats Posted August 24, 2024 Posted August 24, 2024 To be clear, is this a replacer or patch for SlaveTats? Do I need the original and overwrite it? Thanks for the mod
mort65 Posted August 24, 2024 Posted August 24, 2024 (edited) There is no script in the download, only source files. They need to be compiled and overwrite original stave tats scripts. Edited August 24, 2024 by mort65
nopse0 Posted August 24, 2024 Author Posted August 24, 2024 4 hours ago, mort65 said: There is no script in the download, only source files. They need to be compiled and overwrite original stave tats scripts. Sorry, that was a mistake, I forgot to copy the pex scripts. Only the SlaveTats.pex is needed, the others are unchanged I think. The original SlaveTats is still needed, because it has a quest, needed for the MCM. I will also build the SE version, but I don't have SE installed atm., cannot guarantee it works. 3
nopse0 Posted August 24, 2024 Author Posted August 24, 2024 Found two terrible bugs. 'synchronize_tattoos' was hardly working at all. Please upgrade. 3
40Karats Posted August 25, 2024 Posted August 25, 2024 (edited) "More robust (because when a Papyrus script calls a native function, it is scheduled for execution in the Skyrim Game Main thread, i.e. there are no multithreading problems when multiple Papyrus scripts are adding and removing tattoos at the same time)." I'm code illiterate so I'm not sure what problem this is referring to, but I'm using: Bathing in Skyrim (Mono Tweak), Sexlab Cum Overlays Extended (SCOE), SlaveTats+RapeTatsContinued, Spank That Ass, and Wet Function Redux. All these apply racemenu overlays immediately after/during sex at the same time, this combo looks great when they all work but I sometimes find that they override each other. Ie dirt, sweat, or tats fight for the same overlay spots in racemenu. I understand this won't effect external scripts, but could this mod help mitigate the issue at least, with SlaveTat trying to add/overwrite overlays at the same time? (I see that Ponzi is still alive in the comments above, I'm still holding out hope for their overlay manager mod) Edited August 25, 2024 by 40Karats
nopse0 Posted August 25, 2024 Author Posted August 25, 2024 (edited) 4 hours ago, 40Karats said: All these apply racemenu overlays immediately after/during sex at the same time, this combo looks great when they all work but I sometimes find that they override each other. Ie dirt, sweat, or tats fight for the same overlay spots in racemenu. Yes, I think it helps against these racing conditions, because SlaveTats contains code like this: i = SLOTS("Feet"); while (i > 0) { i -= 1; if (JArray::findInt(external_on_feet, i) == -1) { clear_overlay(a_target, isFemale, "Feet", i); } } In the Papyrus version, if a mod adds an external overlay _after_ SlaveTats has calculated the "external_on_feet" array (containing the overlay slot numbers in which external overlays have been applied), it gets removed in this loop (because only the JContainer and NiOverride calls itself are atomic, everything else is executed concurrently). And in the C++ version, the whole function is executed by the Skyrim Main Thread, singlethreaded, nobody can add or remove overlays while this function is running. Edited August 25, 2024 by nopse0
elliesec Posted August 25, 2024 Posted August 25, 2024 The current version (0.1.0) appears to have have a problem with querying tattoos: query_available_tattoos is only ever returning 41 tattoos on my current test setup (I have in excess of 1500 tattoos installed). From what I can tell, the function is only ever returning one tattoo per section/area combination (across all tattoo packs, I have 41 section/area combinations defined - I counted). Applying tattoos from the MCM is also kind of wonky - each section only has one tattoo in it, but I suspect that's just a knock-on effect of the aforementioned issue. If I disable this and revert to vanilla SlaveTats (and wipe the SlaveTats cache), then query_available_tattoos is once again returning thousands of tattoos as expected. The issues from v0.0.2 with tattoo addition do seem to be resolved as far as I can tell now (addition of tattoos would almost always fail).
bruhfrman Posted August 25, 2024 Posted August 25, 2024 Hi does this work for SkyrimVR? If not please build it for VR too!
nopse0 Posted August 25, 2024 Author Posted August 25, 2024 5 hours ago, elliesec said: The current version (0.1.0) appears to have have a problem with querying tattoos: query_available_tattoos is only ever returning 41 tattoos on my current test setup (I have in excess of 1500 tattoos installed). From what I can tell, the function is only ever returning one tattoo per section/area combination (across all tattoo packs, I have 41 section/area combinations defined - I counted). Applying tattoos from the MCM is also kind of wonky - each section only has one tattoo in it, but I suspect that's just a knock-on effect of the aforementioned issue. If I disable this and revert to vanilla SlaveTats (and wipe the SlaveTats cache), then query_available_tattoos is once again returning thousands of tattoos as expected. The issues from v0.0.2 with tattoo addition do seem to be resolved as far as I can tell now (addition of tattoos would almost always fail). I found out what the problem is, JDB::solveObjSetter doesn't work. If I do a JDB::solveObj immediately afterwards, it returns 0 (see screenshot below). So the function acquire_cache always returns the result from JValue::readFromFile, but since it is retained nowhere, it gets garbage collected later on, when it is iterated through. No idea why this doesn't work, is this a JContainer JDB bug ?
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