@@ -27,6 +27,7 @@ static bool print_flags = true;
2727static bool overlay_culling_fix = true ;
2828static bool IS_LOADING_GAME = false ;
2929static bool force_decal = true ;
30+ static bool mu_normal_setskin_workaround = false ;
3031RE::TESObjectREFR* GetUserDataFixed (RE::NiAVObject* obj) {
3132 auto * userData = REL::RelocateMember<RE::TESObjectREFR*>(obj, 0x0F8 , 0x110 );
3233 if (userData) {
@@ -39,10 +40,27 @@ RE::TESObjectREFR* GetUserDataFixed(RE::NiAVObject* obj) {
3940}
4041auto task_pool_ptr = (bool (*)(void )) nullptr ;
4142std::recursive_mutex morph_task_mutex;
43+ std::recursive_mutex qupdatenormalmap_lock;
4244std::recursive_mutex loading_game_mutex;
4345std::recursive_mutex custom_main_task_pool_lock;
4446std::queue<std::function<void ()>> custom_main_task_pool;
4547auto original_process_task = (void (*)(void * main, void * arg2, void * arg3, void * arg4)) nullptr ;
48+ auto qupdatenormalmap = (void (*)(void * arg1, RE::Actor* actor, int armor_slot_bit)) nullptr ;
49+ auto original_setskin = (void (*)(RE::TESActorBase* actorbase, RE::TESObjectARMO* skin)) nullptr ;
50+ static void setskin_hook (RE::TESActorBase* actorbase, RE::TESObjectARMO* skin) {
51+ if (original_setskin && qupdatenormalmap) {
52+ original_setskin (actorbase, skin);
53+ std::lock_guard l (qupdatenormalmap_lock);
54+ auto actor_forms = RE::TESDataHandler::GetSingleton ()->GetFormArray <RE::Actor>();
55+ for (auto * actor:actor_forms) {
56+ if (actor && actor->GetActorBase ()==actorbase) {
57+ qupdatenormalmap (nullptr , actor, 0xffffffff );
58+ }
59+ }
60+
61+ }
62+ }
63+
4664static void ProcessMainTasks (void * main, void * arg2, void * arg3, void * arg4) {
4765 original_process_task (main, arg2, arg3, arg4);
4866 while (true ) {
@@ -379,11 +397,18 @@ namespace plugin {
379397 }
380398 }
381399 }
400+ if (qupdatenormalmap) {
401+ if (auto actor = reference->As <RE::Actor>()) {
402+ std::lock_guard l (qupdatenormalmap_lock);
403+ qupdatenormalmap (nullptr , actor, 0xFFFFFFFF );
404+ }
405+ }
382406 } else {
383407 logger::error (" not reversing overlays because 3D is not loaded or ref count too low" );
384408 }
385409 }
386410 }
411+
387412 });
388413 }
389414
@@ -858,7 +883,7 @@ namespace plugin {
858883 }
859884 }
860885 // actor->Update3DModel();
861- //
886+ //
862887 // actor->Update3DPosition(true);
863888 }
864889 }
@@ -877,15 +902,13 @@ namespace plugin {
877902 }
878903 static auto UpdateWorldDataTaskHook = (void (*)(uint64_t * TaskObj)) nullptr ;
879904 static void UpdateWorldDataTask_fn (uint64_t * TaskObj) {
880-
881905 auto obj = (RE::NiAVObject*) (TaskObj[1 ]);
882906 RE::NiUpdateData data;
883907 data.time = 0 ;
884908 data.flags .set (RE::NiUpdateData::Flag::kDirty );
885909 data.flags .set (RE::NiUpdateData::Flag::kDisableCollision );
886910 obj->UpdateWorldData (&data);
887911 UpdateWorldDataTaskHook (TaskObj);
888-
889912 }
890913#ifdef PARALLEL_MORPH_WORKAROUND
891914
@@ -1192,7 +1215,7 @@ namespace plugin {
11921215 static bool skip_load = false ;
11931216 static bool vr_esl = true ;
11941217 static bool do_samrim_name_fix = false ;
1195-
1218+
11961219 auto LoadMainMenuOrig = (void (*)(uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4)) 0x0 ;
11971220 static void LoadMainMenuHook (uint64_t arg1, uint64_t arg2, uint64_t arg3, uint64_t arg4) {
11981221 {
@@ -1208,7 +1231,7 @@ namespace plugin {
12081231 ini[" OverlayFix" ][" reverse" ] = " default" ;
12091232 ini[" OverlayFix" ][" skipload" ] = " false" ;
12101233 ini[" OverlayFix" ][" nocull" ] = " default" ;
1211- ini[" OverlayFix" ][" forcedecal" ] = " true" ;
1234+ ini[" OverlayFix" ][" forcedecal" ] = " true" ;
12121235 ini[" OverlayFix" ][" hideunusedoverlays" ] = " default" ;
12131236 ini[" OverlayFix" ][" savedanger" ] = " default" ;
12141237 ini[" OverlayFix" ][" vresl" ] = " default" ;
@@ -1218,14 +1241,15 @@ namespace plugin {
12181241 ini[" OverlayFix" ][" taskdelaycount" ] = " 60" ;
12191242 ini[" OverlayFix" ][" taskdelaymilliseconds" ] = " 4" ;
12201243 ini[" OverlayFix" ][" ragdollfix" ] = " false" ;
1244+ ini[" OverlayFix" ][" mu_normal_setskin_workaround" ] = " false" ;
12211245 spdlog::set_level (spdlog::level::info);
12221246 file.read (ini);
12231247 if (!ini[" OverlayFix" ].has (" version" )) {
12241248 ini[" OverlayFix" ][" version" ] = " 1" ;
12251249 ini[" OverlayFix" ][" reverse" ] = " default" ;
12261250 ini[" OverlayFix" ][" skipload" ] = " false" ;
12271251 ini[" OverlayFix" ][" nocull" ] = " default" ;
1228- ini[" OverlayFix" ][" forcedecal" ] = " true" ;
1252+ ini[" OverlayFix" ][" forcedecal" ] = " true" ;
12291253 ini[" OverlayFix" ][" hideunusedoverlays" ] = " default" ;
12301254 ini[" OverlayFix" ][" savedanger" ] = " default" ;
12311255 ini[" OverlayFix" ][" vresl" ] = " default" ;
@@ -1235,6 +1259,7 @@ namespace plugin {
12351259 ini[" OverlayFix" ][" taskdelaycount" ] = " 60" ;
12361260 ini[" OverlayFix" ][" taskdelaymilliseconds" ] = " 4" ;
12371261 ini[" OverlayFix" ][" ragdollfix" ] = " false" ;
1262+ ini[" OverlayFix" ][" mu_normal_setskin_workaround" ] = " false" ;
12381263 }
12391264 if (atoi (ini[" OverlayFix" ][" taskdelaycount" ].c_str ()) > 0 ) {
12401265 delay_count = atoi (ini[" OverlayFix" ][" taskdelaycount" ].c_str ());
@@ -1243,8 +1268,11 @@ namespace plugin {
12431268 millisecond_delay = atoi (ini[" OverlayFix" ][" taskdelaymilliseconds" ].c_str ());
12441269 }
12451270 file.generate (ini);
1246- if (ini[" OverlayFix" ][" forcedecal" ]==" false" ) {
1247- force_decal=false ;
1271+ if (ini[" OverlayFix" ][" forcedecal" ] == " false" ) {
1272+ force_decal = false ;
1273+ }
1274+ if (ini[" OverlayFix" ][" mu_normal_setskin_workaround" ] == " true" ) {
1275+ mu_normal_setskin_workaround = true ;
12481276 }
12491277 if (ini[" OverlayFix" ][" hideunusedoverlays" ] == " false" ) {
12501278 do_hide_unused_overlays = false ;
@@ -1346,8 +1374,7 @@ namespace plugin {
13461374
13471375#endif
13481376 if (do_ragdoll_fix) {
1349- UpdateWorldDataTaskHook = (void (*)(uint64_t * TaskObj))(
1350- (uint64_t ) skee64_info.lpBaseOfDll + 0x129680 );
1377+ UpdateWorldDataTaskHook = (void (*)(uint64_t * TaskObj))((uint64_t ) skee64_info.lpBaseOfDll + 0x129680 );
13511378 DetourTransactionBegin ();
13521379 DetourUpdateThread (GetCurrentThread ());
13531380 DetourAttach (&(PVOID&) UpdateWorldDataTaskHook, &UpdateWorldDataTask_fn);
@@ -2271,6 +2298,54 @@ namespace plugin {
22712298 DetourAttach (&(PVOID&) original_process_task, &ProcessMainTasks);
22722299 DetourTransactionCommit ();
22732300 }
2301+ if (mu_normal_setskin_workaround) {
2302+ {
2303+ if (auto VM = RE::BSScript::Internal::VirtualMachine::GetSingleton ()) {
2304+ RE::BSTSmartPointer<RE::BSScript::ObjectTypeInfo> classInfoPtr = nullptr ;
2305+ VM->GetScriptObjectType1 (" MuDynamicNormalMap" , classInfoPtr);
2306+ if (classInfoPtr) {
2307+ auto func_count = classInfoPtr->GetNumGlobalFuncs ();
2308+ auto func_iter = classInfoPtr->GetGlobalFuncIter ();
2309+ for (uint64_t i = 0 ; i < func_count; i = i + 1 ) {
2310+ if (auto func_ptr = (func_iter + i)) {
2311+ if (auto func = func_ptr->func ) {
2312+ if (func->GetName () == RE::BSFixedString (" QUpdateNormalmap" ) && func->GetIsNative ()) {
2313+ qupdatenormalmap = (void (*)(void * arg1, RE::Actor* actor, int armor_slot_bit)) *
2314+ (uint64_t *) ((uint64_t ) func.get () + 0x50 );
2315+ }
2316+ }
2317+ }
2318+ }
2319+ }
2320+ }
2321+ }
2322+ {
2323+ if (auto VM = RE::BSScript::Internal::VirtualMachine::GetSingleton ()) {
2324+ RE::BSTSmartPointer<RE::BSScript::ObjectTypeInfo> classInfoPtr = nullptr ;
2325+ VM->GetScriptObjectType1 (" ActorBase" , classInfoPtr);
2326+ if (classInfoPtr) {
2327+ auto func_count = classInfoPtr->GetNumMemberFuncs ();
2328+ auto func_iter = classInfoPtr->GetMemberFuncIter ();
2329+ for (uint64_t i = 0 ; i < func_count; i = i + 1 ) {
2330+ if (auto func_ptr = (func_iter + i)) {
2331+ if (auto func = func_ptr->func ) {
2332+ if (func->GetName () == RE::BSFixedString (" SetSkin" ) && func->GetIsNative ()) {
2333+ original_setskin = (void (*)(RE::TESActorBase* actorbase, RE::TESObjectARMO* skin)) *
2334+ (uint64_t *) ((uint64_t ) func.get () + 0x50 );
2335+ }
2336+ }
2337+ }
2338+ }
2339+ }
2340+ if (original_setskin) {
2341+ DetourTransactionBegin ();
2342+ DetourUpdateThread (GetCurrentThread ());
2343+ DetourAttach (&(PVOID&) original_setskin, &setskin_hook);
2344+ DetourTransactionCommit ();
2345+ }
2346+ }
2347+ }
2348+ }
22742349 logger::info (" onPostPostLoad()" );
22752350 }
22762351
0 commit comments