Jump to content

Recommended Posts

Posted
7 hours ago, dragonbane1776 said:

It doesn't appear as Daumbra, it appears as the original NPC name (it might depend on the timing of how quickly you get into the MCM). I'm only on the first body. Every time you summon and then go to reset the tattoos, it creates a new entry. It looks like to patch, would have to tie into the summon script and copy the tattoos onto the new refid and remove the old. The script already does a similar thing for the inventory.

 

I'm thinking looping through the slots and using get_applied_tattoo_in_slot. Then use add_tattoo on the new refid for each slot and remove_tattoos on original refid when loop is done. Doesn't look like that would clear the refid from the JFormDB though, just clear the tattoos from that entry. After a precursory look at JContainers, I'm not seeing a way of removing entries, so I'm unsure on that point currently.

 

Also, not clear yet on how the slots order since neither get_applied_tattoo_in_slot or add_tattoo take the body area. I know there are 6 slots for the body, and 3 each for face, hands, and feet.

 

 

You can get and clear the tattoo arrays of actors with JContainers. In C++ this would look like:

		int applied = JFormDB::getObj(oldActor, ".SlaveTats.applied");
		if (applied == 0)
			return;
		JFormDB::setObj(newActor, ".SlaveTats.applied", applied);
		JFormDB::setObj(oldActor, ".SlaveTats.applied", 0);

 

In Papyrus, I guess, it would be something like this:

		int applied = JFormDB.getObj(oldActor, ".SlaveTats.applied")
		if (applied == 0)
			return
		endif
		JFormDB.setObj(newActor, ".SlaveTats.applied", applied)
		JFormDB.setObj(oldActor, ".SlaveTats.applied", 0)

 

If you don't clear oldActor, both oldActor and newActor would point to the same tattoo array (not advisable, tattoos couldn't be changed independently, but JContainers also has deep and shallow copy functions)

Posted (edited)

why does the pages screen not appear when NG is installed? I have my skee64.ini set to 36 for each part of the body but when NG is installed I only get 6. I'm using a skee64_custom to avoid having it reset everytime I reinstall racemenu. Could that be why maybe?




ScreenShot395.webp.0dc3d71b71a84c3f26f7094390485871.webp

Edited by endmylife23
Posted
2 hours ago, endmylife23 said:

why does the pages screen not appear when NG is installed? I have my skee64.ini set to 36 for each part of the body but when NG is installed I only get 6. I'm using a skee64_custom to avoid having it reset everytime I reinstall racemenu. Could that be why maybe?




ScreenShot395.webp.0dc3d71b71a84c3f26f7094390485871.webp

 

Depends. In Skyrim 1.6.1130/1170, NG gets the skee function addresses by calling SKSE::QueryInterface (skee publishes an interface with the function addresses in newer versions). But the old skee versions for Skyrim 1.4.15 (VR), 1.5.97, 1.6.640, 1.6.659 (GOG) don't do this. In these versions the function adresses are determined by getting the base address of the skee dll and adding version specific offsets to this base address. This cannot work, if you rename the skee dll, because then even getting the base address of the loaded dll fails (because the file name is wrong):

 

					HMODULE skeeBaseAddr = GetModuleHandleA("skeevr.dll");
					if (skeeBaseAddr == NULL) {
						skeeBaseAddr = GetModuleHandleA("skee64.dll");
						logger::info("GetModuleHandleA('skee64.dll') = {}", (uintptr_t)skeeBaseAddr);
					} else {
						logger::info("GetModuleHandleA('skeevr.dll') = {}", (uintptr_t)skeeBaseAddr);
					}
					auto&   skeeOffsets = _offsets640;

					const auto skyrimVer = REL::Module::get().version();

					if (skyrimVer.major() == 1 && skyrimVer.minor() == 6 && skyrimVer.patch() == 640) {
						logger::info("Using NIOverride addresses for Skyrim 1.6.640");

 

So, I guess, not only the MCM, the whole SlaveTatsNG doesn't work in your setup, because it cannot get the NiOverride function addresses.

 

  

Posted (edited)
On 6/9/2025 at 2:24 AM, nopse0 said:
		int applied = JFormDB.getObj(oldActor, ".SlaveTats.applied")
		if (applied == 0)
			return
		endif
		JFormDB.setObj(newActor, ".SlaveTats.applied", applied)
		JFormDB.setObj(oldActor, ".SlaveTats.applied", 0)

 

I got the tattoo records to transfer properly to the new actor, but they are not displaying on screen, nor are they present in the MCM. I verified that the records are on the new actor by using JFormDB.getObj(newActor, ".SlaveTats.applied") and using JValue.writeToFile on the result. Then I checked the resulting file's json contents.

 

I did figure out how to remove oldActor from the MCM target list since oldActor is deleted in the spell process and is no longer a valid target. I added newActor manually to that form list of known targets as well and output that container to a file to verify the form id matched what I was seeing in game and it did.

 

I'm not sure where the issue is at this point. I did try changing cells in game and saved and loaded as well to no effect.

 

Edit: I was able to determine after some more testing utilizing a ConsoleUtil Extended custom console command that the data stored is not retained. I'm not sure if there's some garbage cleanup that is interfering or what's going on.

Edited by dragonbane1776
More information added
Posted
15 hours ago, dragonbane1776 said:

I got the tattoo records to transfer properly to the new actor, but they are not displaying on screen, nor are they present in the MCM. I verified that the records are on the new actor by using JFormDB.getObj(newActor, ".SlaveTats.applied") and using JValue.writeToFile on the result. Then I checked the resulting file's json contents.

 

I did figure out how to remove oldActor from the MCM target list since oldActor is deleted in the spell process and is no longer a valid target. I added newActor manually to that form list of known targets as well and output that container to a file to verify the form id matched what I was seeing in game and it did.

 

I'm not sure where the issue is at this point. I did try changing cells in game and saved and loaded as well to no effect.

 

Edit: I was able to determine after some more testing utilizing a ConsoleUtil Extended custom console command that the data stored is not retained. I'm not sure if there's some garbage cleanup that is interfering or what's going on.

 

I had a look at the code, and know what's missing. Apart from the ".SlaveTats.applied", there also must be a ".SlaveTats.version" for an actor in the JFormDB, otherwise SlaveTats thinks in the "upgrade_tattoos" function that the actor has no tattoos, and sets "SlaveTats.applied" to  a new, empty object:

 

	fail_t upgrade_tattoos(RE::Actor* a_target) 
	{
		if (!a_target) {
			logger::info("a_target is null");
			return true;
		}

		RE::BSFixedString actor_version = JFormDB::getStr(a_target, ".SlaveTats.version");
		RE::BSFixedString code_version = VERSION();

		if (actor_version == code_version)
			return false;

		RE::BSFixedString path;
		int    i;
		int    a_template;
		int    matches;
		int    entry;

		RE::BSFixedString prefix = PREFIX();
		int    prefix_len = (int)prefix.length();

		if (actor_version == "") {
			JFormDB::setObj(a_target, ".SlaveTats.applied", JArray::object());
			actor_version = "1.0.0";

 

So, you have to copy over ".SlaveTats.version" over from oldActor to newActor, like you did for ".SlaveTats.applied".

 

Posted

Thanks. That got me one step closer. I also had to set the int ".SlaveTats.updated" to 1 and call synchronize_tattoos. Everything is working now. I'll get the patch packaged up and sent over to the mod author.

Posted
7 minutes ago, dragonbane1776 said:

Thanks. That got me one step closer. I also had to set the int ".SlaveTats.updated" to 1 and call synchronize_tattoos. Everything is working now. I'll get the patch packaged up and sent over to the mod author.

Such a coincidence, I just had another look at the sources and saw that "updated" thing, too, and just wanted to write an "Edit: ...", when you wrote your mail.

 

If "updated" is not set, you get a:

image.png.f5f5e9eac17171fd5e6a8e94b9d7c884.png

in synchronize_tattoos. Another thing which might be of interest, is ".SlaveTats.activated". That's an array, which contains the activated "tattoo_magic" tattoos. That's all I found in the sources, starting with " ".SlaveTats. ".

Posted

In figuring things out, there were a couple of points where the tattoos weren't present, so I did more debugging. The process actually involved passing through a second dummy actor, which I only passed the data along through. I set the update and synchronized on that body as well. I also moved the code to earlier in the process for the final body so it would be ready when that body appeared. I did discover a quirk at that point. The tattoos vanished later in the process, likely after a spell with a MAGINVReanimate static on it was cast. I'm fairly certain this strips the body of whatever the tattoos use. I couldn't see anything else that looked like it could impact the body in any way. The records were still attached in jformdb, so I just had to set update and call synchronize again after the reanimation finished. 

Posted
2 hours ago, nopse0 said:

Such a coincidence, I just had another look at the sources and saw that "updated" thing, too, and just wanted to write an "Edit: ...", when you wrote your mail.

 

If "updated" is not set, you get a:

image.png.f5f5e9eac17171fd5e6a8e94b9d7c884.png

in synchronize_tattoos. Another thing which might be of interest, is ".SlaveTats.activated". That's an array, which contains the activated "tattoo_magic" tattoos. That's all I found in the sources, starting with " ".SlaveTats. ".

Interesting. I'm not sure what magic tattoos do. Is it something that gets activated in game? I would think having them not active after the npc dies would make sense. The body would need the magic to be reactivated. But if that's only done in MCM, I'd probably tweak my patch to carry them over as well. If I don't carry them over, I should set the object to 0 on the original body so it gets garbage collected.

Posted

I looked at Dibellan Defenders to see how they implemented magic tattoos. I'm not going to carry over the activated tattoos as it may actually interfere with other modders' intentions depending on how they implement things. I'd also have to manually patch for every different magic tattoo as I would need to know the magic effect to also apply and I'm not prepared to do that. It seems better to leave it up to the mod author of magic tattoos to determine if magic needs to be recast on the actor if it gets stripped away, which is exactly what Dibellan Defenders does in their implementation.

Posted

I was wondering where you find the crash log for this mod... for me it just keeps crashing... even if i start a new game it crashes about 2 mins after closing the character creation window... but atleast it does start compared to just crashing during loading of saves

Posted (edited)

For some reason with slavetats overlays on when using Community Shaders my PC constantly have black flickering bug on the areas with overlays. When there's ENB instead of CS the bug is not there, no black flicker. But I can't figure it out what setting is missing in CS or not adjusted well enough. If someone could help me to pinpoint the reason of it I would appreciate that, it's the only reason I can't switch to CS  😭

Edited by Jokekiller
Posted
On 6/11/2025 at 7:12 PM, azunia said:

I was wondering where you find the crash log for this mod... for me it just keeps crashing... even if i start a new game it crashes about 2 mins after closing the character creation window... but atleast it does start compared to just crashing during loading of saves

As normal, in the user "Skyrim Special Edition\SKSE" folder. I guess the NiOverride function addresses are wrong, then the game crashes when the first NiOverride function is called. Using some unusual Skyrim version ? Only the main stream versions 1.4.15 (VR), 1.5.97, 1.6.640, 1.6.659 (GOG), 1.6.1130/1.6.1170 are supported.

Posted
2 hours ago, Jokekiller said:

For some reason with slavetats overlays on when using Community Shaders my PC constantly have black flickering bug on the areas with overlays. When there's ENB instead of CS the bug is not there, no black flicker. But I can't figure it out what setting is missing in CS or not adjusted well enough. If someone could help me to pinpoint the reason of it I would appreciate that, it's the only reason I can't switch to CS  😭

 

And you don't have this flickering when you apply overlays with RaceMenu ? Because SlaveTats simply applies NodeOverrides (texture,color,alpha,etc.) to actors by calling NiOverride f (RaceMenu) functions. And, RaceMenu in turn,  implements this by setting shader properties (texture,color,alpha,etc. are shader properties). I can only imagine that the Community Shaders are different (have different properties or so).

Posted

Holy shit dude, this mod is fast! I was so used to having to wait for original to churn it's stuff out while causing lag spikes, I actually had to check twice once I ran this one. Then I had to rub my eyes in astonishment.

 

Superb work, I regret not having installed it sooner.

Posted

I get a lot of errors "H:\Games\SkyrimSE\Data\Source\Scripts\SlaveTats.psc (6.11): variable SlaveTatsNG is undefined", everything is in the SlaveTats.psc file when trying to install a tattoo
SlaveTats.simple_add_tattoo(Game.GetPlayer(), "Lewd Marks", "059")
If I disable Slave Tats NG, then the compilation is successful. What could be the reason?

Posted
20 hours ago, The_XXI said:

I get a lot of errors "H:\Games\SkyrimSE\Data\Source\Scripts\SlaveTats.psc (6.11): variable SlaveTatsNG is undefined", everything is in the SlaveTats.psc file when trying to install a tattoo
SlaveTats.simple_add_tattoo(Game.GetPlayer(), "Lewd Marks", "059")
If I disable Slave Tats NG, then the compilation is successful. What could be the reason?

 

Are you using a .code-workspace project ? You must add SlaveTatsNG.psc to the sources, it defines the native functions which are called from the patched SlaveTats.psc. It's in scripts/source, not in source/scripts like SlaveTats.psc (I thought this is where sources belong, but nowadays I am not so sure anymore, some people do it this way, some people the other way).

Posted
43 minutes ago, nopse0 said:

 

Are you using a .code-workspace project ? You must add SlaveTatsNG.psc to the sources, it defines the native functions which are called from the patched SlaveTats.psc. It's in scripts/source, not in source/scripts like SlaveTats.psc (I thought this is where sources belong, but nowadays I am not so sure anymore, some people do it this way, some people the other way).

I don't use .code-workspace. You're right, the SlaveTatsNG.psc file was in the wrong folder, thanks for the help.

Posted
On 6/17/2025 at 8:07 PM, nopse0 said:

As normal, in the user "Skyrim Special Edition\SKSE" folder. I guess the NiOverride function addresses are wrong, then the game crashes when the first NiOverride function is called. Using some unusual Skyrim version ? Only the main stream versions 1.4.15 (VR), 1.5.97, 1.6.640, 1.6.659 (GOG), 1.6.1130/1.6.1170 are supported.

 

Sorry, we had this before, me stupid :) Are you using UBE ? UBE comes with a changed, recompiled skee64.dll, the addresses are different to the addresses from the original RaceMenu dll.

Posted
On 6/17/2025 at 8:07 PM, nopse0 said:

As normal, in the user "Skyrim Special Edition\SKSE" folder. I guess the NiOverride function addresses are wrong, then the game crashes when the first NiOverride function is called. Using some unusual Skyrim version ? Only the main stream versions 1.4.15 (VR), 1.5.97, 1.6.640, 1.6.659 (GOG), 1.6.1130/1.6.1170 are supported.

 

Found the location and my version is 1.5.97 ... i got a bunch of mods in but its pretty stable on its own even with so many outdated mods between

 

 

SlaveTatsNG.log

Posted
2 hours ago, azunia said:

 

Found the location and my version is 1.5.97 ... i got a bunch of mods in but its pretty stable on its own even with so many outdated mods between

 

 

SlaveTatsNG.log 5.32 kB · 0 downloads

Are you using UBE ? UBE comes with a different skee64.dll than the normal one, addresses are different, so the program crashes when the first NiOverride call is made. You must use the official latest RaceMenu version for 1.5.97 (v0-4-16 I think), nothing must overwrite this.

 

 

Posted

No UBE in my list and checking the Racemenu version i think mine is v0-4-14.... i do see v0-4-16 in Racemenu's archieve list... should i just try that one instead?

 

And heres my loadorder for if that may help some too.

 

 

loadorder.txt

Posted
2 hours ago, azunia said:

No UBE in my list and checking the Racemenu version i think mine is v0-4-14.... i do see v0-4-16 in Racemenu's archieve list... should i just try that one instead?

 

And heres my loadorder for if that may help some too.

 

 

loadorder.txt 6.62 kB · 0 downloads

 

Yes! Because the function addresses are fully dependent on the version of the skee64.dll (reverse engineered like the Skyrim dll's). If you use v0-4-16, it should work.

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...