feat(tools): a ton of experiments for assets & blueprints ... wip

This commit is contained in:
kaosat.dev 2024-05-12 11:05:11 +02:00
parent 310ee194a9
commit 0172bbe511
18 changed files with 442 additions and 40 deletions

View File

@ -226,4 +226,4 @@ Restructuring of storage of components
- [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set - [x] fix weird issue with missing "0" property when adding new entry in empty hashmap => happens only if the values for the "setter" have never been set
- [ ] handle missing types in registry for keys & values - [ ] handle missing types in registry for keys & values
- Add correct upgrade handling from individual component to bevy_components - [ ] Add correct upgrade handling from individual component to bevy_components

View File

@ -150,8 +150,8 @@ class BEVY_COMPONENTS_PT_AdvancedToolsPanel(bpy.types.Panel):
if not object.name in objects_with_invalid_components: if not object.name in objects_with_invalid_components:
objects_with_invalid_components.append(object.name) objects_with_invalid_components.append(object.name)
if not long_name in invalid_component_names: """if not long_name in invalid_component_names:
invalid_component_names.append(custom_property) invalid_component_names.append(custom_property)""" # FIXME
layout.separator() layout.separator()
layout.separator() layout.separator()
original_name = bpy.context.window_manager.bevy_component_rename_helper.original_name original_name = bpy.context.window_manager.bevy_component_rename_helper.original_name

View File

@ -55,4 +55,19 @@
- [ ] remove bulk of tracker related code - [ ] remove bulk of tracker related code
- [ ] clean up - [ ] clean up
- [x] split up change detection in settings to its own panel - [x] split up change detection in settings to its own panel
Change storage of 'blueprint' assets : (from BlueprintsList)
- store at the SCENE level: a list/map of assets
- asset name + asset path
- the asset PATH is determined by the export output folder parameters
- make asset storage generic enough to allow adding additional asset types
- get inspired by bevy_asset_loader ?
Assets:
- [ ] store assets
- [ ] per main scene for level/world assets
- [ ] per blueprint for blueprint in lib scene

View File

@ -11,12 +11,11 @@ bl_info = {
"category": "Import-Export" "category": "Import-Export"
} }
import os import os
from pathlib import Path
import json import json
import bpy import bpy
from bpy.types import Context
from bpy.props import (StringProperty, BoolProperty, IntProperty, PointerProperty) from bpy.props import (StringProperty, BoolProperty, IntProperty, PointerProperty)
import rna_prop_ui
# from .extension import ExampleExtensionProperties, GLTF_PT_UserExtensionPanel, unregister_panel # from .extension import ExampleExtensionProperties, GLTF_PT_UserExtensionPanel, unregister_panel
@ -36,12 +35,20 @@ from .ui.main import (GLTF_PT_auto_export_change_detection, GLTF_PT_auto_export_
GLTF_PT_auto_export_general, GLTF_PT_auto_export_general,
GLTF_PT_auto_export_scenes, GLTF_PT_auto_export_scenes,
GLTF_PT_auto_export_blueprints, GLTF_PT_auto_export_blueprints,
GLTF_PT_auto_export_blueprints_list,
SCENE_UL_GLTF_auto_export, SCENE_UL_GLTF_auto_export,
GLTF_PT_auto_export_SidePanel GLTF_PT_auto_export_SidePanel
) )
from .ui.operators import (OT_OpenFolderbrowser, SCENES_LIST_OT_actions) from .ui.operators import (OT_OpenFolderbrowser, SCENES_LIST_OT_actions)
from .assets.ui import GLTF_PT_auto_export_assets
from .assets.assets_registry import AssetsRegistry
from .assets.operators import OT_add_bevy_asset, OT_remove_bevy_asset
from .blueprints.ui import GLTF_PT_auto_export_blueprints_list
from .blueprints.blueprints_registry import BlueprintsRegistry
from .blueprints.operators import OT_select_blueprint
from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf from .helpers.generate_complete_preferences_dict import generate_complete_preferences_dict_gltf
@ -104,10 +111,8 @@ classes = [
SCENE_UL_GLTF_auto_export, SCENE_UL_GLTF_auto_export,
SCENES_LIST_OT_actions, SCENES_LIST_OT_actions,
OT_OpenFolderbrowser, OT_OpenFolderbrowser,
AutoExportGLTF, AutoExportGLTF,
#AutoExportGltfAddonPreferences,
CollectionToExport, CollectionToExport,
BlueprintsToExport, BlueprintsToExport,
@ -119,8 +124,17 @@ classes = [
GLTF_PT_auto_export_scenes, GLTF_PT_auto_export_scenes,
GLTF_PT_auto_export_blueprints, GLTF_PT_auto_export_blueprints,
GLTF_PT_auto_export_SidePanel, GLTF_PT_auto_export_SidePanel,
GLTF_PT_auto_export_blueprints_list,
AutoExportTracker, AutoExportTracker,
AssetsRegistry,
OT_add_bevy_asset,
OT_remove_bevy_asset,
GLTF_PT_auto_export_assets,
BlueprintsRegistry,
OT_select_blueprint,
GLTF_PT_auto_export_blueprints_list,
] ]
def glTF2_pre_export_callback(data): def glTF2_pre_export_callback(data):

View File

@ -0,0 +1,96 @@
import bpy
import json
import os
import uuid
from pathlib import Path
from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
def get_assets(scene, blueprints_data, addon_prefs):
export_root_folder = getattr(addon_prefs, "export_root_folder")
export_output_folder = getattr(addon_prefs,"export_output_folder")
export_levels_path = getattr(addon_prefs,"export_levels_path")
export_blueprints_path = getattr(addon_prefs, "export_blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
relative_blueprints_path = os.path.relpath(export_blueprints_path, export_root_folder)
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, None)
blueprint_assets_list = []
if blueprint_instance_names_for_scene:
for blueprint_name in blueprint_instance_names_for_scene:
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
if blueprint is not None:
print("BLUEPRINT", blueprint)
blueprint_exported_path = None
if blueprint.local:
blueprint_exported_path = os.path.join(relative_blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else:
# get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None
print("foo", dict(blueprint.collection))
if blueprint_exported_path is not None:
blueprint_assets_list.append({"name": blueprint.name, "path": blueprint_exported_path})
# fetch images/textures
# see https://blender.stackexchange.com/questions/139859/how-to-get-absolute-file-path-for-linked-texture-image
textures = []
for ob in bpy.data.objects:
if ob.type == "MESH":
for mat_slot in ob.material_slots:
if mat_slot.material:
if mat_slot.material.node_tree:
textures.extend([x.image.filepath for x in mat_slot.material.node_tree.nodes if x.type=='TEX_IMAGE'])
print("textures", textures)
assets_list_name = f"assets_{scene.name}"
assets_list_data = {"blueprints": json.dumps(blueprint_assets_list), "sounds":[], "images":[]}
print("blueprint assets", blueprint_assets_list)
# this is where we store the information for all available assets
#
class AssetsRegistry(PropertyGroup):
assets_list = []
asset_name_selector: StringProperty(
name="asset name",
description="name of asset to add",
) # type: ignore
asset_type_selector: EnumProperty(
name="asset type",
description="type of asset to add",
items=(
('MODEL', "Model", ""),
('AUDIO', "Audio", ""),
('IMAGE', "Image", ""),
)
) # type: ignore
asset_path_selector: StringProperty(
name="asset path",
description="path of asset to add",
subtype='FILE_PATH'
) # type: ignore
@classmethod
def register(cls):
bpy.types.WindowManager.assets_registry = PointerProperty(type=AssetsRegistry)
@classmethod
def unregister(cls):
del bpy.types.WindowManager.assets_registry
def add_asset(self, name, type, path, internal): # internal means it cannot be edited by the user, aka auto generated
in_list = [asset for asset in self.assets_list if (asset["path"] == path)]
in_list = len(in_list) > 0
if not in_list:
self.assets_list.append({"name": name, "type": type, "path": path, "internal": internal})
def remove_asset(self, path):
self.assets_list[:] = [asset for asset in self.assets_list if (asset["path"] != path)]

View File

@ -0,0 +1,50 @@
import os
import bpy
from bpy_types import (Operator)
from bpy.props import (StringProperty, EnumProperty)
class OT_add_bevy_asset(Operator):
"""Add asset"""
bl_idname = "bevyassets.add"
bl_label = "Add bevy asset"
bl_options = {"UNDO"}
asset_name: StringProperty(
name="asset name",
description="name of asset to add",
) # type: ignore
asset_type: bpy.types.WindowManager.asset_type_selector = EnumProperty(
items=(
('MODEL', "Model", ""),
('AUDIO', "Audio", ""),
('IMAGE', "Image", ""),
)
) # type: ignore
asset_path: StringProperty(
name="asset path",
description="path of asset to add",
subtype='FILE_PATH'
) # type: ignore
def execute(self, context):
context.window_manager.assets_registry.add_asset(self.asset_name, self.asset_type, self.asset_path, False)
return {'FINISHED'}
class OT_remove_bevy_asset(Operator):
"""Remove asset"""
bl_idname = "bevyassets.remove"
bl_label = "remove bevy asset"
bl_options = {"UNDO"}
asset_path: StringProperty(
name="asset path",
description="path of asset to add",
subtype='FILE_PATH'
) # type: ignore
def execute(self, context):
context.window_manager.assets_registry.remove_asset(self.asset_path)
return {'FINISHED'}

View File

@ -0,0 +1,43 @@
import bpy
class GLTF_PT_auto_export_assets(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Assets"
bl_parent_id = "GLTF_PT_auto_export_SidePanel"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
#if "auto_export_tracker" in context.window_manager:
asset_registry = context.window_manager.assets_registry
row = layout.row()
row.prop(asset_registry, "asset_name_selector", text="")
row.prop(asset_registry, "asset_type_selector", text="")
row.prop(asset_registry, "asset_path_selector", text="")
add_assets = row.operator(operator="bevyassets.add", text="Add asset")
add_assets.asset_name = asset_registry.asset_name_selector
add_assets.asset_type = asset_registry.asset_type_selector
add_assets.asset_path = asset_registry.asset_path_selector
layout.separator()
row = layout.row()
row.label(text="Name")
row.label(text="Type")
row.label(text="Path")
row.label(text="Remove")
for asset in asset_registry.assets_list:
row = layout.row()
row.label(text=asset["name"])
row.label(text=asset["type"])
row.label(text=asset["path"])
if not asset["internal"]:
remove_asset = row.operator(operator="bevyassets.remove", text="remove")
remove_asset.asset_path = asset["path"]
else:
row.label(text="")

View File

@ -74,4 +74,4 @@ def export_gltf (path, export_settings):
settings = {**export_settings, "filepath": path} settings = {**export_settings, "filepath": path}
# print("export settings",settings) # print("export settings",settings)
os.makedirs(os.path.dirname(path), exist_ok=True) os.makedirs(os.path.dirname(path), exist_ok=True)
bpy.ops.export_scene.gltf(**settings) #bpy.ops.export_scene.gltf(**settings)

View File

@ -9,11 +9,6 @@ from ..modules.bevy_dynamic import is_object_dynamic, is_object_static
from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into from ..helpers.helpers_scenes import clear_hollow_scene, copy_hollowed_collection_into
from ..helpers.helpers_blueprints import inject_blueprints_list_into_main_scene, remove_blueprints_list_from_main_scene from ..helpers.helpers_blueprints import inject_blueprints_list_into_main_scene, remove_blueprints_list_from_main_scene
# export all main scenes
def export_main_scenes(scenes, blend_file_path, addon_prefs):
for scene in scenes:
export_main_scene(scene, blend_file_path, addon_prefs)
def export_main_scene(scene, blend_file_path, addon_prefs, blueprints_data): def export_main_scene(scene, blend_file_path, addon_prefs, blueprints_data):
gltf_export_preferences = generate_gltf_export_preferences(addon_prefs) gltf_export_preferences = generate_gltf_export_preferences(addon_prefs)
export_root_folder = getattr(addon_prefs, "export_root_folder") export_root_folder = getattr(addon_prefs, "export_root_folder")
@ -35,8 +30,8 @@ def export_main_scene(scene, blend_file_path, addon_prefs, blueprints_data):
if export_blueprints : if export_blueprints :
gltf_output_path = os.path.join(export_levels_path, scene.name) gltf_output_path = os.path.join(export_levels_path, scene.name)
inject_blueprints_list_into_main_scene(scene, blueprints_data) inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs)
return
if export_separate_dynamic_and_static_objects: if export_separate_dynamic_and_static_objects:
#print("SPLIT STATIC AND DYNAMIC") #print("SPLIT STATIC AND DYNAMIC")
# first export static objects # first export static objects

View File

@ -0,0 +1,49 @@
import bpy
import json
import os
import uuid
from pathlib import Path
from bpy_types import (PropertyGroup)
from bpy.props import (StringProperty, BoolProperty, FloatProperty, FloatVectorProperty, IntProperty, IntVectorProperty, EnumProperty, PointerProperty, CollectionProperty)
# this is where we store the information for all available Blueprints
#
class BlueprintsRegistry(PropertyGroup):
blueprints_data = {}
blueprints_list = []
asset_name_selector: StringProperty(
name="asset name",
description="name of asset to add",
) # type: ignore
asset_type_selector: EnumProperty(
name="asset type",
description="type of asset to add",
items=(
('MODEL', "Model", ""),
('AUDIO', "Audio", ""),
('IMAGE', "Image", ""),
)
) # type: ignore
asset_path_selector: StringProperty(
name="asset path",
description="path of asset to add",
subtype='FILE_PATH'
) # type: ignore
@classmethod
def register(cls):
bpy.types.WindowManager.blueprints_registry = PointerProperty(type=BlueprintsRegistry)
@classmethod
def unregister(cls):
del bpy.types.WindowManager.blueprints_registry
def add_blueprint(self, blueprint):
self.blueprints_list.append(blueprint)

View File

@ -0,0 +1,33 @@
import os
import bpy
from bpy_types import (Operator)
from bpy.props import (StringProperty)
class OT_select_blueprint(Operator):
"""Select blueprint """
bl_idname = "blueprint.select"
bl_label = "Select blueprint"
bl_options = {"UNDO"}
blueprint_collection_name: StringProperty(
name="blueprint collection name",
description="blueprints to select's collection name ",
) # type: ignore
blueprint_scene_name: StringProperty(
name="blueprint scene name",
description="blueprints to select's collection name ",
) # type: ignore
def execute(self, context):
if self.blueprint_collection_name:
collection = bpy.data.collections[self.blueprint_collection_name]
scene = bpy.data.scenes[self.blueprint_scene_name]
if scene:
bpy.ops.object.select_all(action='DESELECT')
bpy.context.window.scene = scene
bpy.context.view_layer.objects.active = None
bpy.context.view_layer.active_layer_collection = bpy.context.view_layer.layer_collection.children[self.blueprint_collection_name]
# bpy.context.view_layer.active_layer_collection = collection
return {'FINISHED'}

View File

@ -0,0 +1,28 @@
import bpy
class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Blueprints"
bl_parent_id = "GLTF_PT_auto_export_SidePanel"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
for blueprint in context.window_manager.blueprints_registry.blueprints_list:
row = layout.row()
row.label(text=blueprint.name)
if blueprint.local:
select_blueprint = row.operator(operator="blueprint.select", text="Select")
select_blueprint.blueprint_collection_name = blueprint.collection.name
select_blueprint.blueprint_scene_name = blueprint.scene.name
else:
row.label(text="External")
for collection in bpy.context.window_manager.exportedCollections:
row = layout.row()
row.label(text=collection.name)

View File

@ -158,6 +158,7 @@ def blueprints_scan(main_scenes, library_scenes, addon_prefs):
blueprint.collection = collection blueprint.collection = collection
blueprint.instances = external_collection_instances[collection.name] if collection.name in external_collection_instances else [] blueprint.instances = external_collection_instances[collection.name] if collection.name in external_collection_instances else []
blueprints[collection.name] = blueprint blueprints[collection.name] = blueprint
#print("EXTERNAL COLLECTION", collection, dict(collection))
# add nested collections to internal/external_collection instances # add nested collections to internal/external_collection instances
# FIXME: inneficient, third loop over all_objects # FIXME: inneficient, third loop over all_objects
@ -280,11 +281,95 @@ def blueprints_scan(main_scenes, library_scenes, addon_prefs):
import json import json
from .object_makers import (make_empty) from .object_makers import (make_empty)
def inject_blueprints_list_into_main_scene(scene, blueprints_data):
# print("injecting assets/blueprints data into scene") def add_scene_property(scene, property_name, property_data):
root_collection = scene.collection root_collection = scene.collection
assets_list = None scene_property = None
for object in scene.objects:
if object.name == property_name:
scene_property = object
break
if scene_property is None:
scene_property = make_empty(property_name, [0,0,0], [0,0,0], [0,0,0], root_collection)
for key in property_data.keys():
scene_property[key] = property_data[key]
def inject_blueprints_list_into_main_scene(scene, blueprints_data, addon_prefs):
export_root_folder = getattr(addon_prefs, "export_root_folder")
export_output_folder = getattr(addon_prefs,"export_output_folder")
export_levels_path = getattr(addon_prefs,"export_levels_path")
export_blueprints_path = getattr(addon_prefs, "export_blueprints_path")
export_gltf_extension = getattr(addon_prefs, "export_gltf_extension")
# print("injecting assets/blueprints data into scene")
assets_list_name = f"assets_list_{scene.name}_components" assets_list_name = f"assets_list_{scene.name}_components"
assets_list_data = {}
# FIXME: temporary hack
for blueprint in blueprints_data.blueprints:
bpy.context.window_manager.blueprints_registry.add_blueprint(blueprint)
blueprint_instance_names_for_scene = blueprints_data.blueprint_instances_per_main_scene.get(scene.name, None)
# find all blueprints used in a scene
blueprints_in_scene = []
if blueprint_instance_names_for_scene: # what are the blueprints used in this scene, inject those into the assets list component
children_per_blueprint = {}
for blueprint_name in blueprint_instance_names_for_scene:
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
if blueprint:
children_per_blueprint[blueprint_name] = blueprint.nested_blueprints
blueprints_in_scene += blueprint.nested_blueprints
assets_list_data["BlueprintsList"] = f"({json.dumps(dict(children_per_blueprint))})"
print(blueprint_instance_names_for_scene)
add_scene_property(scene, assets_list_name, assets_list_data)
relative_blueprints_path = os.path.relpath(export_blueprints_path, export_root_folder)
blueprint_assets_list = []
if blueprint_instance_names_for_scene:
for blueprint_name in blueprint_instance_names_for_scene:
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
if blueprint is not None:
print("BLUEPRINT", blueprint)
blueprint_exported_path = None
if blueprint.local:
blueprint_exported_path = os.path.join(relative_blueprints_path, f"{blueprint.name}{export_gltf_extension}")
else:
# get the injected path of the external blueprints
blueprint_exported_path = blueprint.collection['Export_path'] if 'Export_path' in blueprint.collection else None
print("foo", dict(blueprint.collection))
if blueprint_exported_path is not None:
blueprint_assets_list.append({"name": blueprint.name, "path": blueprint_exported_path, "type": "MODEL", "internal": True})
# fetch images/textures
# see https://blender.stackexchange.com/questions/139859/how-to-get-absolute-file-path-for-linked-texture-image
textures = []
for ob in bpy.data.objects:
if ob.type == "MESH":
for mat_slot in ob.material_slots:
if mat_slot.material:
if mat_slot.material.node_tree:
textures.extend([x.image.filepath for x in mat_slot.material.node_tree.nodes if x.type=='TEX_IMAGE'])
print("textures", textures)
assets_list_name = f"assets_{scene.name}"
assets_list_data = {"blueprints": json.dumps(blueprint_assets_list), "sounds":[], "images":[]}
print("blueprint assets", blueprint_assets_list)
add_scene_property(scene, assets_list_name, assets_list_data)
for blueprint in blueprint_assets_list:
bpy.context.window_manager.assets_registry.add_asset(**blueprint)
'''root_collection = scene.collection
assets_list = None
for object in scene.objects: for object in scene.objects:
if object.name == assets_list_name: if object.name == assets_list_name:
assets_list = object assets_list = object
@ -301,7 +386,7 @@ def inject_blueprints_list_into_main_scene(scene, blueprints_data):
blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None) blueprint = blueprints_data.blueprints_per_name.get(blueprint_name, None)
if blueprint: if blueprint:
children_per_blueprint[blueprint_name] = blueprint.nested_blueprints children_per_blueprint[blueprint_name] = blueprint.nested_blueprints
assets_list["BlueprintsList"] = f"({json.dumps(dict(children_per_blueprint))})" assets_list["BlueprintsList"] = f"({json.dumps(dict(children_per_blueprint))})"'''
def remove_blueprints_list_from_main_scene(scene): def remove_blueprints_list_from_main_scene(scene):
assets_list = None assets_list = None

View File

@ -9,7 +9,7 @@ custom_properties_to_filter_out = ['_combine', 'template', 'components_meta']
def is_component_valid(object, component_name): def is_component_valid(object, component_name):
if "components_meta" in object or hasattr(object, "components_meta"): if "components_meta" in object or hasattr(object, "components_meta"):
target_components_metadata = object.components_meta.components target_components_metadata = object.components_meta.components
component_meta = next(filter(lambda component: component["name"] == component_name, target_components_metadata), None) component_meta = next(filter(lambda component: component["long_name"] == component_name, target_components_metadata), None)
if component_meta != None: if component_meta != None:
return component_meta.enabled and not component_meta.invalid return component_meta.enabled and not component_meta.invalid
return True return True
@ -105,6 +105,7 @@ def duplicate_object(object, parent, combine_mode, destination_collection, bluep
"""we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object""" """we inject the collection/blueprint name, as a component called 'BlueprintName', but we only do this in the empty, not the original object"""
empty_obj['BlueprintName'] = '("'+collection_name+'")' empty_obj['BlueprintName'] = '("'+collection_name+'")'
empty_obj["BlueprintPath"] = ''
empty_obj['SpawnHere'] = '()' empty_obj['SpawnHere'] = '()'
# we also inject a list of all sub blueprints, so that the bevy side can preload them # we also inject a list of all sub blueprints, so that the bevy side can preload them

View File

@ -55,22 +55,6 @@ class GLTF_PT_auto_export_changes_list(bpy.types.Panel):
row = layout.row() row = layout.row()
row.label(text=f' {object_name}') row.label(text=f' {object_name}')
class GLTF_PT_auto_export_blueprints_list(bpy.types.Panel):
bl_space_type = 'VIEW_3D'
bl_region_type = 'UI'
bl_label = "Blueprints"
bl_parent_id = "GLTF_PT_auto_export_SidePanel"
bl_options = {'DEFAULT_CLOSED'}
def draw(self, context):
layout = self.layout
layout.use_property_split = True
layout.use_property_decorate = False # No animation.
for collection in bpy.context.window_manager.exportedCollections:
row = layout.row()
row.label(text=collection.name)
# main ui in the file => export # main ui in the file => export
class GLTF_PT_auto_export_main(bpy.types.Panel): class GLTF_PT_auto_export_main(bpy.types.Panel):
bl_space_type = 'FILE_BROWSER' bl_space_type = 'FILE_BROWSER'

View File

@ -2,6 +2,15 @@
import bpy import bpy
from bpy.types import Operator from bpy.types import Operator
class ASSETS_LIST_OT_actions(Operator):
"""Add / remove etc assets"""
bl_idname = "asset_list.list_action"
bl_label = "Asset Actions"
bl_description = "Move items up and down, add and remove"
bl_options = {'REGISTER'}
class SCENES_LIST_OT_actions(Operator): class SCENES_LIST_OT_actions(Operator):
"""Move items up and down, add and remove""" """Move items up and down, add and remove"""
bl_idname = "scene_list.list_action" bl_idname = "scene_list.list_action"