Asset Pipeline v2 #145

Closed
Nick Alberelli wants to merge 431 commits from (deleted):feature/asset-pipeline-v2 into main

When changing the target branch, be careful to rebase the branch in your fork to match. See documentation.
3 changed files with 268 additions and 161 deletions
Showing only changes of commit 311c6649a6 - Show all commits

View File

@ -3,20 +3,21 @@ import bpy
import os import os
from pathlib import Path from pathlib import Path
from .merge.publish import ( from .merge.publish import (
find_sync_target,
find_all_published,
get_next_published_file, get_next_published_file,
) )
from .merge.naming import get_task_layer_col_name from .merge.naming import get_task_layer_col_name
from .merge.other_ids import init_other_ids
from .merge.core import (
ownership_get,
ownership_set,
get_invalid_objects,
merge_task_layer,
)
from .merge.transfer_data.transfer_ui import draw_transfer_data from .merge.transfer_data.transfer_ui import draw_transfer_data
from . import constants from . import constants
from .sync import (
sync_poll,
sync_invoke,
sync_draw,
sync_execute_update_ownership,
sync_execute_prepare_sync,
sync_execute_pull,
sync_execute_push,
)
class ASSETPIPE_OT_create_new_asset(bpy.types.Operator): class ASSETPIPE_OT_create_new_asset(bpy.types.Operator):
@ -107,11 +108,10 @@ class ASSETPIPE_OT_create_new_asset(bpy.types.Operator):
return {'FINISHED'} return {'FINISHED'}
class ASSETPIPE_OT_sync_with_publish(bpy.types.Operator): class ASSETPIPE_OT_update_ownership(bpy.types.Operator):
bl_idname = "assetpipe.sync_with_publish" bl_idname = "assetpipe.update_ownership"
bl_label = "Sync with Publish" bl_label = "Update Onwership"
bl_description = """'Push'band or 'Pull' data from Published file. Will prompt with a list of new data found before pushing bl_description = """""" # TODO Add description
During 'Push' current blender session will revert to the last saved file and clear the current undo history"""
_temp_transfer_data = None _temp_transfer_data = None
_invalid_objs = [] _invalid_objs = []
@ -123,161 +123,114 @@ class ASSETPIPE_OT_sync_with_publish(bpy.types.Operator):
description="Show New Transfer Data", description="Show New Transfer Data",
) )
save: bpy.props.BoolProperty(
name="Save Current File",
default=True,
description="Save the Current File (after pulling if enabled) before Pushing to Publish",
)
pull: bpy.props.BoolProperty(
name="Pull before Pushing",
default=False,
description="Pull in any new data from the Published file before Pushing",
)
push: bpy.props.BoolProperty(
name="Push", default=False, description="Push any new data to Published file"
)
def invoke(self, context: bpy.types.Context, event: bpy.types.Event): def invoke(self, context: bpy.types.Context, event: bpy.types.Event):
self._temp_transfer_data = context.scene.asset_pipeline.temp_transfer_data sync_invoke(self, context)
self._temp_transfer_data.clear()
self._invalid_objs.clear()
local_col = context.scene.asset_pipeline.asset_collection
if not local_col:
self.report({'ERROR'}, "Top level collection could not be found")
return {'CANCELLED'}
task_layer_key = context.scene.asset_pipeline.task_layer_name
if task_layer_key == "NONE":
self.report({'ERROR'}, "Current File Name doesn't contain valid task layer")
return {'CANCELLED'}
ownership_get(local_col, context.scene)
# TODO Remove Invalid Objs Explicitly, some will be auto removed but not all
self._invalid_objs = get_invalid_objects(local_col, context.scene)
self._other_ids = init_other_ids(context.scene)
# Default behaviour is to pull before pushing
if self.push:
self.pull = True
return context.window_manager.invoke_props_dialog(self, width=400) return context.window_manager.invoke_props_dialog(self, width=400)
def draw(self, context: bpy.types.Context): def draw(self, context: bpy.types.Context):
layout = self.layout sync_draw(self, context)
row = layout.row() def execute(self, context: bpy.types.Context):
if self.push: sync_execute_update_ownership(self, context)
row.prop(self, "pull") return {'FINISHED'}
row.prop(self, "save")
if len(self._invalid_objs) != 0:
box = layout.box()
box.alert = True
box.label(text="Sync will clear Invalid Objects:", icon="ERROR")
for obj in self._invalid_objs:
box.label(text=obj.name, icon="OBJECT_DATA")
if len(self._other_ids) != 0: class ASSETPIPE_OT_sync_pull(bpy.types.Operator):
box = layout.box() bl_idname = "assetpipe.sync_pull"
box.label(text="New 'Other IDs' found") bl_label = "Pull from Publish"
for id in self._other_ids: bl_description = """""" # TODO Add description
box.label(text=id.name)
if len(self._temp_transfer_data) == 0: _temp_transfer_data = None
layout.label(text="No New Transfer Data found") _invalid_objs = []
else: _other_ids = []
layout.label(text="New Transfer Data will be Pushed to Publish") _temp_dir: Path = None
row = layout.row() _current_file: Path = None
row.prop(self, "expand", text="", icon="COLLAPSEMENU", toggle=False) _task_layer_key: str = ""
row.label(text="Show New Transfer Data") _sync_target: Path = None
objs = [
transfer_data_item.obj for transfer_data_item in self._temp_transfer_data
]
if not self.expand: expand: bpy.props.BoolProperty(
return name="Show New Transfer Data",
default=False,
description="Show New Transfer Data",
)
for obj in set(objs): @classmethod
obj_ownership = [ def poll(cls, context: bpy.types.Context) -> bool:
transfer_data_item if any([img.is_dirty for img in bpy.data.images]):
for transfer_data_item in self._temp_transfer_data cls.poll_message_set("Please save unsaved Images")
if transfer_data_item.obj == obj return False
] if bpy.data.is_dirty:
box = layout.box() cls.poll_message_set("Please save current .blend file")
box.label(text=obj.name, icon="OBJECT_DATA") return False
draw_transfer_data(obj_ownership, box) return True
def invoke(self, context: bpy.types.Context, event: bpy.types.Event):
sync_invoke(self, context)
return context.window_manager.invoke_props_dialog(self, width=400)
def draw(self, context: bpy.types.Context):
sync_draw(self, context)
def execute(self, context: bpy.types.Context): def execute(self, context: bpy.types.Context):
# Find current task Layer # Find current task Layer
temp_transfer_data = context.scene.asset_pipeline.temp_transfer_data sync_execute_update_ownership(self, context)
ownership_set(temp_transfer_data) sync_execute_prepare_sync(self, context)
current_file = Path(bpy.data.filepath) sync_execute_pull(self, context)
temp_dir = Path(bpy.app.tempdir).parent return {'FINISHED'}
task_layer_key = context.scene.asset_pipeline.task_layer_name
if task_layer_key == "NONE":
self.report({'ERROR'}, "Current File Name doesn't contain valid task layer")
return {'CANCELLED'}
sync_target = find_sync_target(current_file)
if not sync_target.exists(): class ASSETPIPE_OT_sync_push(bpy.types.Operator):
self.report({'ERROR'}, "Sync Target could not be determined") bl_idname = "assetpipe.sync_push"
return {'CANCELLED'} bl_label = "Push from Publish"
bl_description = """""" # TODO Add description
_temp_transfer_data = None
_invalid_objs = []
_other_ids = []
_temp_dir: Path = None
_current_file: Path = None
_task_layer_key: str = ""
_sync_target: Path = None
expand: bpy.props.BoolProperty(
name="Show New Transfer Data",
default=False,
description="Show New Transfer Data",
)
pull: bpy.props.BoolProperty(
name="Pull before Pushing",
default=True,
description="Pull in any new data from the Published file before Pushing",
)
@classmethod
def poll(cls, context: bpy.types.Context) -> bool:
if any([img.is_dirty for img in bpy.data.images]):
cls.poll_message_set("Please save unsaved Images")
return False
if bpy.data.is_dirty:
cls.poll_message_set("Please save current .blend file")
return False
return True
def invoke(self, context: bpy.types.Context, event: bpy.types.Event):
sync_invoke(self, context)
return context.window_manager.invoke_props_dialog(self, width=400)
def draw(self, context: bpy.types.Context):
self.layout.prop(self, "pull")
sync_draw(self, context)
def execute(self, context: bpy.types.Context):
# Find current task Layer
sync_execute_update_ownership(self, context)
sync_execute_prepare_sync(self, context)
if self.pull: if self.pull:
temp_file = temp_dir.joinpath( sync_execute_pull(self, context)
current_file.name.replace(".blend", "") + "_Asset_Pipe_Backup.blend" bpy.ops.wm.save_mainfile(filepath=self._current_file.__str__())
)
bpy.ops.wm.save_as_mainfile(filepath=temp_file.__str__(), copy=True)
error_msg = merge_task_layer(
context,
local_tls=[task_layer_key],
external_file=sync_target,
)
if error_msg: sync_execute_push(self, context)
bpy.ops.wm.open_mainfile(filepath=temp_file.__str__())
bpy.ops.wm.save_as_mainfile(filepath=current_file.__str__())
self.report({'ERROR'}, error_msg)
return {'CANCELLED'}
if self.save:
bpy.ops.wm.save_as_mainfile(filepath=current_file.__str__())
if not self.push:
return {'FINISHED'}
push_targets = find_all_published(current_file, constants.ACTIVE_PUBLISH_KEY)
if sync_target not in push_targets:
push_targets.append(sync_target)
for file in push_targets:
file_path = file.__str__()
bpy.ops.wm.open_mainfile(filepath=file_path)
# SKIP DEPRECIATED FILES
if context.scene.asset_pipeline.is_depreciated:
continue
local_tls = [
task_layer
for task_layer in constants.TASK_LAYER_TYPES.keys()
if task_layer != task_layer_key
]
error_msg = merge_task_layer(
context,
local_tls=local_tls,
external_file=current_file,
)
if error_msg:
bpy.ops.wm.open_mainfile(filepath=current_file.__str__())
self.report({'ERROR'}, error_msg)
return {'CANCELLED'}
bpy.ops.wm.save_as_mainfile(filepath=file_path)
bpy.ops.wm.open_mainfile(filepath=current_file.__str__())
return {'FINISHED'} return {'FINISHED'}
@ -312,7 +265,9 @@ class ASSETPIPE_OT_publish_new_version(bpy.types.Operator):
classes = ( classes = (
ASSETPIPE_OT_sync_with_publish, ASSETPIPE_OT_update_ownership,
ASSETPIPE_OT_sync_push,
ASSETPIPE_OT_sync_pull,
ASSETPIPE_OT_publish_new_version, ASSETPIPE_OT_publish_new_version,
ASSETPIPE_OT_create_new_asset, ASSETPIPE_OT_create_new_asset,
) )

View File

@ -0,0 +1,156 @@
import bpy
from pathlib import Path
from .merge.publish import (
find_sync_target,
find_all_published,
)
from .merge.other_ids import init_other_ids
from .merge.core import (
ownership_get,
ownership_set,
get_invalid_objects,
merge_task_layer,
)
from .merge.transfer_data.transfer_ui import draw_transfer_data
from . import constants
def sync_poll(cls, context):
if any([img.is_dirty for img in bpy.data.images]):
cls.poll_message_set("Please save unsaved Images")
return False
if bpy.data.is_dirty:
cls.poll_message_set("Please save current .blend file")
return False
return True
def sync_invoke(self, context):
self._temp_transfer_data = context.scene.asset_pipeline.temp_transfer_data
self._temp_transfer_data.clear()
self._invalid_objs.clear()
local_col = context.scene.asset_pipeline.asset_collection
if not local_col:
self.report({'ERROR'}, "Top level collection could not be found")
return {'CANCELLED'}
task_layer_key = context.scene.asset_pipeline.task_layer_name
if task_layer_key == "NONE":
self.report({'ERROR'}, "Current File Name doesn't contain valid task layer")
return {'CANCELLED'}
ownership_get(local_col, context.scene)
# TODO Remove Invalid Objs Explicitly, some will be auto removed but not all
self._invalid_objs = get_invalid_objects(local_col, context.scene)
self._other_ids = init_other_ids(context.scene)
def sync_draw(self, context):
layout = self.layout
row = layout.row()
if len(self._invalid_objs) != 0:
box = layout.box()
box.alert = True
box.label(text="Sync will clear Invalid Objects:", icon="ERROR")
for obj in self._invalid_objs:
box.label(text=obj.name, icon="OBJECT_DATA")
if len(self._other_ids) != 0:
box = layout.box()
box.label(text="New 'Other IDs' found")
for id in self._other_ids:
box.label(text=id.name)
if len(self._temp_transfer_data) == 0:
layout.label(text="No New Transfer Data found")
else:
layout.label(text="New Transfer Data will be Pushed to Publish")
row = layout.row()
row.prop(self, "expand", text="", icon="COLLAPSEMENU", toggle=False)
row.label(text="Show New Transfer Data")
objs = [transfer_data_item.obj for transfer_data_item in self._temp_transfer_data]
if not self.expand:
return
for obj in set(objs):
obj_ownership = [
transfer_data_item
for transfer_data_item in self._temp_transfer_data
if transfer_data_item.obj == obj
]
box = layout.box()
box.label(text=obj.name, icon="OBJECT_DATA")
draw_transfer_data(obj_ownership, box)
def sync_execute_update_ownership(self, context):
temp_transfer_data = context.scene.asset_pipeline.temp_transfer_data
ownership_set(temp_transfer_data)
def sync_execute_prepare_sync(self, context):
self._current_file = Path(bpy.data.filepath)
self._temp_dir = Path(bpy.app.tempdir).parent
self._task_layer_key = context.scene.asset_pipeline.task_layer_name
if self._task_layer_key == "NONE":
self.report({'ERROR'}, "Current File Name doesn't contain valid task layer")
return {'CANCELLED'}
self._sync_target = find_sync_target(self._current_file)
if not self._sync_target.exists():
self.report({'ERROR'}, "Sync Target could not be determined")
return {'CANCELLED'}
def sync_execute_pull(self, context):
temp_file = self._temp_dir.joinpath(
self._current_file.name.replace(".blend", "") + "_Asset_Pipe_Backup.blend"
)
bpy.ops.wm.save_as_mainfile(filepath=temp_file.__str__(), copy=True)
error_msg = merge_task_layer(
context,
local_tls=[self._task_layer_key],
external_file=self._sync_target,
)
if error_msg:
bpy.ops.wm.open_mainfile(filepath=temp_file.__str__())
bpy.ops.wm.save_as_mainfile(filepath=self._current_file.__str__())
self.report({'ERROR'}, error_msg)
return {'CANCELLED'}
def sync_execute_push(self, context):
push_targets = find_all_published(self._current_file, constants.ACTIVE_PUBLISH_KEY)
if self._sync_target not in push_targets:
push_targets.append(self._sync_target)
for file in push_targets:
file_path = file.__str__()
bpy.ops.wm.open_mainfile(filepath=file_path)
# SKIP DEPRECIATED FILES
if context.scene.asset_pipeline.is_depreciated:
continue
local_tls = [
task_layer
for task_layer in constants.TASK_LAYER_TYPES.keys()
if task_layer != self._task_layer_key
]
error_msg = merge_task_layer(
context,
local_tls=local_tls,
external_file=self._current_file,
)
if error_msg:
bpy.ops.wm.open_mainfile(filepath=self._current_file.__str__())
self.report({'ERROR'}, error_msg)
return {'CANCELLED'}
bpy.ops.wm.save_as_mainfile(filepath=file_path)
bpy.ops.wm.open_mainfile(filepath=self._current_file.__str__())

View File

@ -29,15 +29,11 @@ class ASSETPIPE_sync(bpy.types.Panel):
layout.prop(asset_pipe, "asset_collection", text="Asset") layout.prop(asset_pipe, "asset_collection", text="Asset")
layout.label(text="Test UI") layout.label(text="Test UI")
# layout.operator( layout.operator("assetpipe.update_ownership", text="Update Ownership")
# "assetpipe.sync_with_publish", text="Update Ownership" layout.operator("assetpipe.sync_push", text="Push to Publish", icon="TRIA_UP")
# ).pull = False
layout.operator( layout.operator(
"assetpipe.sync_with_publish", text="Push to Publish", icon="TRIA_UP" "assetpipe.sync_pull", text="Pull from Publish", icon="TRIA_DOWN"
).push = True )
layout.operator(
"assetpipe.sync_with_publish", text="Pull from Publish", icon="TRIA_DOWN"
).pull = True
layout.operator("assetpipe.publish_new_version", icon="PLUS") layout.operator("assetpipe.publish_new_version", icon="PLUS")
if asset_pipe.is_asset_pipeline_file and asset_pipe.task_layer_name == "NONE": if asset_pipe.is_asset_pipeline_file and asset_pipe.task_layer_name == "NONE":