В некоторых случаях, необходимо обеспечить, чтобы аддон всегда загружался при запуске Blender последним, после того, как будут загружены все остальные аддоны. Это может понадобиться, если аддон конфликтует с какими-то другими аддонами или использует функционал из других аддонов, который должен быть доступен уже при старте аддона.
При запуске Blender аддоны загружаются по порядку, в соответствии со списком bpy.context.preferences.addons, порядок расположения аддонов в котором определяется тем, в каком порядке их активировал пользователь.
Можно указать необходимый порядок активации аддона в инструкции по его установке, или же, воспользовавшись тем, что список аддонов уже доступен нам при загрузке, дописать в функции register аддона необходимый нам функционал.
Для примера напишем классы для двух простейших аддонов: First и Second.
Класс аддона First:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import bpy bl_info = { 'name': 'FIRST', 'category': 'All', 'version': (0, 0, 1), 'blender': (3, 4, 0), } class FIRST_OT_main(bpy.types.Operator): bl_idname = 'first.main' bl_label = 'First main OP' bl_options = {"REGISTER"} def execute(self, context): print('FIRST ADD-ON OPERATOR EXECUTE') return {"FINISHED"} def register(): print('FIRST add-on loaded') bpy.utils.register_class(FIRST_OT_main) def unregister(): bpy.utils.unregister_class(FIRST_OT_main) if __name__ == '__main__': register() |
Класс аддона Second
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 |
import bpy bl_info = { 'name': 'SECOND', 'category': 'All', 'version': (0, 0, 1), 'blender': (3, 4, 0), } class SECOND_OT_main(bpy.types.Operator): bl_idname = 'second.main' bl_label = 'Second main OP' bl_options = {"REGISTER"} def execute(self, context): print('SECOND ADD-ON OPERATOR EXECUTE') return {"FINISHED"} def register(): print('SECOND add-on loaded') bpy.utils.register_class(SECOND_OT_main) def unregister(): bpy.utils.unregister_class(SECOND_OT_main) if __name__ == '__main__': register() |
Обратите внимание на вызов команды print в функции register аддонов. С ее помощью мы будем отслеживать реальный порядок загрузки аддонов.
Сохраним классы в отдельные файлы .py и установим из этих файлов аддоны в Blender. Сначала установим аддон “Second” а после него – аддон “First”. Сохраним пользовательские настройки.
Просмотрев список bpy.context.preferences.addons:
1 2 3 4 5 6 |
for addon in bpy.context.preferences.addons: print(addon) # ... # <bpy_struct, Addon("second_addon") at 0x0000014EEE7283A8> # <bpy_struct, Addon("first_addon") at 0x0000014EEE729128> |
Мы видим, что наши аддоны будут загружены последними по порядку, сначала “Second” и следом за ним “First”.
Мы можем убедиться в этом, запустив Blender из системной консоли, чтобы видеть вывод сообщений из функций аддонов register.
Внесем изменения в аддон “Second” так, чтобы он всегда загружался последним.
Манипуляции с загрузкой аддона мы можем производить внутри его функции register.
Добавим в код функции register аддона “Second” проверку, не находится ли аддон на последнем месте в списке bpy.context.preferences.addons.
1 2 3 4 |
def register(): if bpy.context.preferences.addons[-1].module == __name__: print('SECOND add-on loaded after all other add-ons') bpy.utils.register_class(SECOND_OT_main) |
Если находится, значит все работает так как нам нужно, т.е. аддон загружается последним и мы можем регистрировать его классы как обычно.
Добавим так же в условие else – сюда мы попадаем, если Blender уже загружает аддон, но после него в списке bpy.context.preferences.addons есть еще аддоны.
1 2 3 4 5 6 7 8 9 10 11 12 13 |
def register(): if bpy.context.preferences.addons[-1].module == __name__: print('SECOND add-on loaded after all other add-ons ->> OK') bpy.utils.register_class(SECOND_OT_main) else: print('SECOND add-on loaded from the exist place in the bpy.context.preferences.addons list ->> SKIPPING') # remove from existed place addon_prefs_ptp = bpy.context.preferences.addons.get(__name__) addon_prefs_ptp_module = addon_prefs_ptp.module bpy.context.preferences.addons.remove(addon_prefs_ptp) # and add to the last place addon_prefs_new_ptp = bpy.context.preferences.addons.new() addon_prefs_new_ptp.module = addon_prefs_ptp_module |
В этом случае мы получаем указатель на аддон в списке bpy.context.preferences.addons и через него удаляем аддон с текущего места в списке.
После чего добавляем в список указатель на новый аддон, он добавится в конец списка, и присваиваем ему имя нашего аддона.
Когда Blender дойдет до конца списка, а последним элементом списка снова будет указатель на наш аддон “Second”, он попытается зарегистрировать его снова и так как на этот раз аддон регистрируется с последнего места в списке, его регистрация пройдет успешно.
Для того чтобы аддон не выпадал в ошибку при вызове функции unregister, добавим дополнительную переменную second_registered в которой будем отмечать действительно ли аддон зарегистрирован или его регистрация перенесена на последнее место в списке аддонов.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
second_registered = False def register(): if bpy.context.preferences.addons[-1].module == __name__: print('SECOND add-on loaded after all other add-ons ->> OK') bpy.utils.register_class(SECOND_OT_main) # mark as registered global second_registered second_registered = True else: print('SECOND add-on loaded from the exist place in the bpy.context.preferences.addons list ->> SKIPPING') # remove from existed place addon_prefs_ptp = bpy.context.preferences.addons.get(__name__) addon_prefs_ptp_module = addon_prefs_ptp.module bpy.context.preferences.addons.remove(addon_prefs_ptp) # and add to the last place addon_prefs_new_ptp = bpy.context.preferences.addons.new() addon_prefs_new_ptp.module = addon_prefs_ptp_module def unregister(): global second_registered if second_registered: bpy.utils.unregister_class(SECOND_OT_main) second_registered = False |
Переустановим наши аддоны, опять в порядке сначала “Second”, потом – “First”.
Теперь если мы запустим Blender из консоли, мы увидим следующий вывод:
Blender сначала попытается зарегистрировать аддон “Second” с текущего места, регистрация пропускается, а аддон переносится на последнее место в списке. Затем регистрируется аддон “First”. После чего производится повторная регистрация аддона “Second”, уже последним по порядку.