@@ -4261,6 +4261,25 @@ No overload found for function 'FPackageName:IsValidLongPackageName'.
42614261 });
42624262
42634263
4264+ // Mark all hooks for this mod as scheduled_for_removal BEFORE closing Lua state
4265+ // This prevents hooks from firing with an invalid Lua state during the window between
4266+ // lua_close and the actual hook unregistration
4267+ for (auto & item : g_hooked_script_function_data)
4268+ {
4269+ if (item->mod == this )
4270+ {
4271+ item->scheduled_for_removal = true ;
4272+ }
4273+ }
4274+
4275+ // Remove any pending game thread actions for this mod BEFORE closing Lua state
4276+ // Otherwise process_event_hook may try to execute actions with an invalid Lua state
4277+ // Note: action.lua points to m_hook_lua (a thread), so compare against that
4278+ // Must be done BEFORE m_hook_lua is set to nullptr
4279+ std::erase_if (m_game_thread_actions, [&](const SimpleLuaAction& action) {
4280+ return action.lua == m_hook_lua;
4281+ });
4282+
42644283 if (m_hook_lua != nullptr )
42654284 {
42664285 m_hook_lua = nullptr ; // lua_newthread results are handled by lua GC
@@ -4276,17 +4295,6 @@ No overload found for function 'FPackageName:IsValidLongPackageName'.
42764295 lua_resetthread (m_main_lua->get_lua_state ());
42774296 }
42784297
4279- // Mark all hooks for this mod as scheduled_for_removal BEFORE closing Lua state
4280- // This prevents hooks from firing with an invalid Lua state during the window between
4281- // lua_close and the actual hook unregistration
4282- for (auto & item : g_hooked_script_function_data)
4283- {
4284- if (item->mod == this )
4285- {
4286- item->scheduled_for_removal = true ;
4287- }
4288- }
4289-
42904298 lua_close (lua ().get_lua_state ());
42914299
42924300 // Unhook all UFunctions for this mod & remove from the map that keeps track of which UFunctions have been hooked
0 commit comments