Compare commits

...

11 Commits

Author SHA1 Message Date
37cfed489c Merge branch '204-animation-doesn-t-sync-for-gpencil-materials' into 'develop'
Resolve "Animation doesn't sync for materials"

See merge request slumber/multi-user!128
2021-06-22 12:10:23 +00:00
9003abcd18 feat: notes for furtur improvements 2021-06-22 14:06:19 +02:00
a199e0df00 feat: apply bl_apply_child member to force dependencies reloading
fix: node_tree animation dependencies
2021-06-22 11:36:51 +02:00
3774419b7e fix: force push is now pushing the whole node data instead of delta 2021-06-22 10:41:36 +02:00
3e552cb406 feat: gpencil materials animation support 2021-06-22 10:39:40 +02:00
9f381b44c8 fix: material animation support 2021-06-21 18:58:16 +02:00
ad795caed5 fix: only apply repository heads on connection 2021-06-21 18:38:43 +02:00
504dd77405 fix: scene cleaning 2021-06-21 17:10:05 +02:00
82022c9e4d clean: only log ignored update in debug logging level 2021-06-18 15:45:51 +02:00
d81b4dc014 feat: enable delta back for all datablocks execpt gpencil, files and images 2021-06-18 15:30:39 +02:00
63affa079f Merge branch '199-filter-correctly-distant-updates-in-the-depsgraph-handler' into 'develop'
Resolve "Filter correctly distant updates in the depsgraph handler"

See merge request slumber/multi-user!126
2021-06-18 13:12:15 +00:00
22 changed files with 85 additions and 26 deletions

View File

@ -219,7 +219,7 @@ def load_fcurve(fcurve_data, fcurve):
def dump_animation_data(datablock):
animation_data = {}
if has_action(datablock):
animation_data['action'] = datablock.animation_data.action.name
animation_data['action'] = datablock.animation_data.action.uuid
if has_driver(datablock):
animation_data['drivers'] = []
for driver in datablock.animation_data.drivers:
@ -241,8 +241,10 @@ def load_animation_data(animation_data, datablock):
for driver in animation_data['drivers']:
load_driver(datablock, driver)
if 'action' in animation_data:
datablock.animation_data.action = bpy.data.actions[animation_data['action']]
action = animation_data.get('action')
if action:
action = resolve_datablock_from_uuid(action, bpy.data.actions)
datablock.animation_data.action = action
elif datablock.animation_data.action:
datablock.animation_data.action = None
@ -259,6 +261,8 @@ def resolve_animation_dependencies(datablock):
class BlAction(ReplicatedDatablock):
use_delta = True
bl_id = "actions"
bl_class = bpy.types.Action
bl_check_common = False

View File

@ -37,6 +37,8 @@ def get_roll(bone: bpy.types.Bone) -> float:
class BlArmature(ReplicatedDatablock):
use_delta = True
bl_id = "armatures"
bl_class = bpy.types.Armature
bl_check_common = False

View File

@ -26,6 +26,8 @@ from .bl_action import dump_animation_data, load_animation_data, resolve_animati
class BlCamera(ReplicatedDatablock):
use_delta = True
bl_id = "cameras"
bl_class = bpy.types.Camera
bl_check_common = False

View File

@ -137,6 +137,8 @@ SPLINE_METADATA = [
class BlCurve(ReplicatedDatablock):
use_delta = True
bl_id = "curves"
bl_class = bpy.types.Curve
bl_check_common = False

View File

@ -29,6 +29,8 @@ POINT = ['co', 'weight_softbody', 'co_deform']
class BlLattice(ReplicatedDatablock):
use_delta = True
bl_id = "lattices"
bl_class = bpy.types.Lattice
bl_check_common = False

View File

@ -26,6 +26,8 @@ from .bl_action import dump_animation_data, load_animation_data, resolve_animati
class BlLight(ReplicatedDatablock):
use_delta = True
bl_id = "lights"
bl_class = bpy.types.Light
bl_check_common = False

View File

@ -25,6 +25,8 @@ from replication.protocol import ReplicatedDatablock
from .bl_datablock import resolve_datablock_from_uuid
class BlLightprobe(ReplicatedDatablock):
use_delta = True
bl_id = "lightprobes"
bl_class = bpy.types.LightProbe
bl_check_common = False

View File

@ -397,11 +397,14 @@ def load_materials_slots(src_materials: list, dst_materials: bpy.types.bpy_prop_
class BlMaterial(ReplicatedDatablock):
use_delta = True
bl_id = "materials"
bl_class = bpy.types.Material
bl_check_common = False
bl_icon = 'MATERIAL_DATA'
bl_reload_parent = False
bl_reload_child = True
@staticmethod
def construct(data: dict) -> object:
@ -409,8 +412,6 @@ class BlMaterial(ReplicatedDatablock):
@staticmethod
def load(data: dict, datablock: object):
load_animation_data(data.get('animation_data'), datablock)
loader = Loader()
is_grease_pencil = data.get('is_grease_pencil')
@ -427,6 +428,8 @@ class BlMaterial(ReplicatedDatablock):
datablock.use_nodes = True
load_node_tree(data['node_tree'], datablock.node_tree)
load_animation_data(data.get('nodes_animation_data'), datablock.node_tree)
load_animation_data(data.get('animation_data'), datablock)
@staticmethod
def dump(datablock: object) -> dict:
@ -494,8 +497,10 @@ class BlMaterial(ReplicatedDatablock):
data['grease_pencil'] = gp_mat_dumper.dump(datablock.grease_pencil)
elif datablock.use_nodes:
data['node_tree'] = dump_node_tree(datablock.node_tree)
data['nodes_animation_data'] = dump_animation_data(datablock.node_tree)
data['animation_data'] = dump_animation_data(datablock)
return data
@staticmethod
@ -509,7 +514,7 @@ class BlMaterial(ReplicatedDatablock):
if datablock.use_nodes:
deps.extend(get_node_tree_dependencies(datablock.node_tree))
deps.extend(resolve_animation_dependencies(datablock.node_tree))
deps.extend(resolve_animation_dependencies(datablock))
return deps

View File

@ -55,6 +55,8 @@ POLYGON = [
]
class BlMesh(ReplicatedDatablock):
use_delta = True
bl_id = "meshes"
bl_class = bpy.types.Mesh
bl_check_common = False

View File

@ -65,6 +65,8 @@ def load_metaball_elements(elements_data, elements):
class BlMetaball(ReplicatedDatablock):
use_delta = True
bl_id = "metaballs"
bl_class = bpy.types.MetaBall
bl_check_common = False

View File

@ -28,6 +28,8 @@ from .bl_datablock import resolve_datablock_from_uuid
from .bl_action import dump_animation_data, load_animation_data, resolve_animation_dependencies
class BlNodeGroup(ReplicatedDatablock):
use_delta = True
bl_id = "node_groups"
bl_class = bpy.types.NodeTree
bl_check_common = False

View File

@ -493,6 +493,8 @@ def load_modifiers_custom_data(dumped_modifiers: dict, modifiers: bpy.types.bpy_
class BlObject(ReplicatedDatablock):
use_delta = True
bl_id = "objects"
bl_class = bpy.types.Object
bl_check_common = False

View File

@ -41,6 +41,8 @@ IGNORED_ATTR = [
]
class BlParticle(ReplicatedDatablock):
use_delta = True
bl_id = "particles"
bl_class = bpy.types.ParticleSettings
bl_icon = "PARTICLES"

View File

@ -25,6 +25,8 @@ from .bl_datablock import resolve_datablock_from_uuid
from .bl_action import dump_animation_data, load_animation_data, resolve_animation_dependencies
class BlSpeaker(ReplicatedDatablock):
use_delta = True
bl_id = "speakers"
bl_class = bpy.types.Speaker
bl_check_common = False

View File

@ -26,6 +26,8 @@ from .bl_action import dump_animation_data, load_animation_data, resolve_animati
import bpy.types as T
class BlTexture(ReplicatedDatablock):
use_delta = True
bl_id = "textures"
bl_class = bpy.types.Texture
bl_check_common = False

View File

@ -27,6 +27,8 @@ from .bl_material import dump_materials_slots, load_materials_slots
from .bl_action import dump_animation_data, load_animation_data, resolve_animation_dependencies
class BlVolume(ReplicatedDatablock):
use_delta = True
bl_id = "volumes"
bl_class = bpy.types.Volume
bl_check_common = False

View File

@ -30,6 +30,8 @@ from .bl_action import dump_animation_data, load_animation_data, resolve_animati
class BlWorld(ReplicatedDatablock):
use_delta = True
bl_id = "worlds"
bl_class = bpy.types.World
bl_check_common = True

View File

@ -75,7 +75,7 @@ def on_scene_update(scene):
if distant_update:
for u in distant_update:
shared_data.session.applied_updates.remove(u)
logging.info(f"Ignoring distant update of {dependency_updates[0].id.name}")
logging.debug(f"Ignoring distant update of {dependency_updates[0].id.name}")
return
update_external_dependencies()

View File

@ -100,7 +100,7 @@ def initialize_session():
# Step 2: Load nodes
logging.info("Applying nodes")
for node in session.repository.index_sorted:
for node in session.repository.heads:
porcelain.apply(session.repository, node)
logging.info("Registering timers")
@ -604,9 +604,9 @@ class SessionApply(bpy.types.Operator):
node_ref = session.repository.graph.get(self.target)
porcelain.apply(session.repository,
self.target,
force=True,
force_dependencies=self.reset_dependencies)
force=True)
impl = session.repository.rdp.get_implementation(node_ref.instance)
# NOTE: find another way to handle child and parent automatic reloading
if impl.bl_reload_parent:
for parent in session.repository.graph.get_parents(self.target):
logging.debug(f"Refresh parent {parent}")
@ -614,6 +614,11 @@ class SessionApply(bpy.types.Operator):
porcelain.apply(session.repository,
parent.uuid,
force=True)
if hasattr(impl, 'bl_reload_child') and impl.bl_reload_child:
for dep in node_ref.dependencies:
porcelain.apply(session.repository,
dep,
force=True)
except Exception as e:
self.report({'ERROR'}, repr(e))
traceback.print_exc()
@ -637,7 +642,7 @@ class SessionCommit(bpy.types.Operator):
def execute(self, context):
try:
porcelain.commit(session.repository, self.target)
porcelain.push(session.repository, 'origin', self.target)
porcelain.push(session.repository, 'origin', self.target, force=True)
return {"FINISHED"}
except Exception as e:
self.report({'ERROR'}, repr(e))

View File

@ -129,6 +129,11 @@ class ApplyTimer(Timer):
porcelain.apply(session.repository,
parent.uuid,
force=True)
if hasattr(impl, 'bl_reload_child') and impl.bl_reload_child:
for dep in node_ref.dependencies:
porcelain.apply(session.repository,
dep,
force=True)
class DynamicRightSelectTimer(Timer):

View File

@ -38,6 +38,14 @@ from replication.constants import (STATE_ACTIVE, STATE_AUTH,
STATE_LOBBY,
CONNECTING)
CLEARED_DATABLOCKS = ['actions', 'armatures', 'cache_files', 'cameras',
'collections', 'curves', 'filepath', 'fonts',
'grease_pencils', 'images', 'lattices', 'libraries',
'lightprobes', 'lights', 'linestyles', 'masks',
'materials', 'meshes', 'metaballs', 'movieclips',
'node_groups', 'objects', 'paint_curves', 'particles',
'scenes', 'shape_keys', 'sounds', 'speakers', 'texts',
'textures', 'volumes', 'worlds']
def find_from_attr(attr_name, attr_value, list):
for item in list:
@ -101,23 +109,25 @@ def get_state_str(state):
def clean_scene():
to_delete = [f for f in dir(bpy.data) if f not in ['brushes', 'palettes']]
for type_name in to_delete:
try:
sub_collection_to_avoid = [bpy.data.linestyles['LineStyle'], bpy.data.materials['Dots Stroke']]
type_collection = getattr(bpy.data, type_name)
items_to_remove = [i for i in type_collection if i not in sub_collection_to_avoid]
for item in items_to_remove:
try:
type_collection.remove(item)
except:
continue
except:
continue
for type_name in CLEARED_DATABLOCKS:
sub_collection_to_avoid = [
bpy.data.linestyles.get('LineStyle'),
bpy.data.materials.get('Dots Stroke')
]
type_collection = getattr(bpy.data, type_name)
items_to_remove = [i for i in type_collection if i not in sub_collection_to_avoid]
for item in items_to_remove:
try:
type_collection.remove(item)
logging.info(item.name)
except:
continue
# Clear sequencer
bpy.context.scene.sequence_editor_clear()
def get_selected_objects(scene, active_view_layer):
return [obj.uuid for obj in scene.objects if obj.select_get(view_layer=active_view_layer)]