Compare commits
3 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| d78c42b02f | |||
| 8cb40b2d60 | |||
| 57fdd492ef |
+359
-1
File diff suppressed because it is too large
Load Diff
+125
-1
@@ -28,7 +28,7 @@ from . import bl_types, environment, addon_updater_ops, presence, ui
|
||||
from .utils import get_preferences, get_expanded_icon
|
||||
from replication.constants import RP_COMMON
|
||||
from replication.interface import session
|
||||
|
||||
from numpy import interp
|
||||
# From https://stackoverflow.com/a/106223
|
||||
IP_REGEX = re.compile("^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$")
|
||||
HOSTNAME_REGEX = re.compile("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$")
|
||||
@@ -93,6 +93,88 @@ def set_log_level(self, value):
|
||||
def get_log_level(self):
|
||||
return logging.getLogger().level
|
||||
|
||||
def set_active_replay(self, value):
|
||||
files_count = len(bpy.context.window_manager.session.replay_files)
|
||||
|
||||
if files_count == 0:
|
||||
return
|
||||
|
||||
max_index = files_count-1
|
||||
|
||||
if value > max_index:
|
||||
value = max_index
|
||||
|
||||
if hasattr(self, 'active_replay_file'):
|
||||
self["active_replay_file"] = value
|
||||
else:
|
||||
self.active_replay_file = value
|
||||
|
||||
if bpy.context.window_manager.session.replay_mode == 'MANUAL':
|
||||
bpy.ops.session.load(
|
||||
filepath=bpy.context.window_manager.session.replay_files[value].name,
|
||||
draw_users=True,
|
||||
replay=True)
|
||||
|
||||
def get_active_replay(self):
|
||||
return self.get('active_replay_file', 0)
|
||||
|
||||
|
||||
def set_replay_persistent_collection(self, value):
|
||||
if hasattr(self, 'replay_persistent_collection'):
|
||||
self["replay_persistent_collection"] = value
|
||||
else:
|
||||
self.replay_persistent_collection = value
|
||||
|
||||
collection = bpy.data.collections.get("multiuser_timelapse", None)
|
||||
|
||||
if collection is None and value:
|
||||
collection = bpy.data.collections.new('multiuser_timelapse')
|
||||
cam = bpy.data.cameras.get('multiuser_timelapse_cam', bpy.data.cameras.new('multiuser_timelapse_cam'))
|
||||
cam_obj = bpy.data.objects.get('multiuser_timelapse_cam_obj', bpy.data.objects.new('multiuser_timelapse_cam_obj', cam))
|
||||
curve = bpy.data.curves.get('multiuser_timelapse_path', bpy.data.curves.new('multiuser_timelapse_path', 'CURVE'))
|
||||
curve_obj = bpy.data.objects.get('multiuser_timelapse_path_obj', bpy.data.objects.new('multiuser_timelapse_path_obj', curve))
|
||||
|
||||
if cam_obj.name not in collection.objects:
|
||||
collection.objects.link(cam_obj)
|
||||
if curve_obj.name not in collection.objects:
|
||||
collection.objects.link(curve_obj)
|
||||
|
||||
bpy.context.scene.collection.children.link(collection)
|
||||
elif collection and not value:
|
||||
for o in collection.objects:
|
||||
bpy.data.objects.remove(o)
|
||||
bpy.data.collections.remove(collection)
|
||||
|
||||
def get_replay_persistent_collection(self):
|
||||
return self.get('replay_persistent_collection', False)
|
||||
|
||||
def set_replay_duration(self, value):
|
||||
if hasattr(self, 'replay_duration'):
|
||||
self["replay_duration"] = value
|
||||
else:
|
||||
self.replay_duration = value
|
||||
|
||||
# Update the animation fcurve
|
||||
replay_action = bpy.data.actions.get('replay_action')
|
||||
replay_fcurve = None
|
||||
|
||||
for fcurve in replay_action.fcurves:
|
||||
if fcurve.data_path == 'active_replay_file':
|
||||
replay_fcurve = fcurve
|
||||
|
||||
if replay_fcurve:
|
||||
for p in reversed(replay_fcurve.keyframe_points):
|
||||
replay_fcurve.keyframe_points.remove(p, fast=True)
|
||||
|
||||
bpy.context.scene.frame_end = value
|
||||
files_count = len(bpy.context.window_manager.session.replay_files)-1
|
||||
for index in range(0, files_count):
|
||||
frame = interp(index,[0, files_count],[bpy.context.scene.frame_start, value])
|
||||
replay_fcurve.keyframe_points.insert(frame, index)
|
||||
|
||||
def get_replay_duration(self):
|
||||
return self.get('replay_duration', 10)
|
||||
|
||||
|
||||
class ReplicatedDatablock(bpy.types.PropertyGroup):
|
||||
type_name: bpy.props.StringProperty()
|
||||
@@ -530,6 +612,37 @@ class SessionProps(bpy.types.PropertyGroup):
|
||||
is_host: bpy.props.BoolProperty(
|
||||
default=False
|
||||
)
|
||||
replay_files: bpy.props.CollectionProperty(
|
||||
name='File paths',
|
||||
type=bpy.types.OperatorFileListElement
|
||||
)
|
||||
replay_persistent_collection: bpy.props.BoolProperty(
|
||||
name="replay_persistent_collection",
|
||||
description='Enable a collection that persist accross frames loading',
|
||||
get=get_replay_persistent_collection,
|
||||
set=set_replay_persistent_collection,
|
||||
)
|
||||
replay_mode: bpy.props.EnumProperty(
|
||||
name='replay method',
|
||||
description='Replay in keyframe (timeline) or manually',
|
||||
items={
|
||||
('TIMELINE', 'TIMELINE', 'Replay from the timeline.'),
|
||||
('MANUAL', 'MANUAL', 'Replay manually, from the replay frame widget.')},
|
||||
default='TIMELINE')
|
||||
replay_duration: bpy.props.IntProperty(
|
||||
name='replay interval',
|
||||
default=250,
|
||||
min=10,
|
||||
set=set_replay_duration,
|
||||
get=get_replay_duration,
|
||||
)
|
||||
replay_frame_current: bpy.props.IntProperty(
|
||||
name='replay_frame_current',
|
||||
)
|
||||
replay_camera: bpy.props.PointerProperty(
|
||||
name='Replay camera',
|
||||
type=bpy.types.Object
|
||||
)
|
||||
|
||||
|
||||
classes = (
|
||||
@@ -552,9 +665,20 @@ def register():
|
||||
logging.debug('Generating bl_types preferences')
|
||||
prefs.generate_supported_types()
|
||||
|
||||
bpy.types.Scene.active_replay_file = bpy.props.IntProperty(
|
||||
name="active_replay_file",
|
||||
default=0,
|
||||
min=0,
|
||||
description='Active snapshot',
|
||||
set=set_active_replay,
|
||||
get=get_active_replay,
|
||||
options={'ANIMATABLE'}
|
||||
)
|
||||
|
||||
def unregister():
|
||||
from bpy.utils import unregister_class
|
||||
|
||||
for cls in reversed(classes):
|
||||
unregister_class(cls)
|
||||
|
||||
del bpy.types.Scene.active_replay_file
|
||||
|
||||
@@ -615,6 +615,39 @@ class VIEW3D_PT_overlay_session(bpy.types.Panel):
|
||||
row.active = settings.presence_show_user
|
||||
row.prop(settings, "presence_show_far_user")
|
||||
|
||||
class SESSION_PT_replay(bpy.types.Panel):
|
||||
bl_idname = "MULTIUSER_REPLAY_PT_panel"
|
||||
bl_label = "Replay"
|
||||
bl_space_type = 'VIEW_3D'
|
||||
bl_region_type = 'UI'
|
||||
bl_parent_id = 'MULTIUSER_SETTINGS_PT_panel'
|
||||
bl_options = {'DEFAULT_CLOSED'}
|
||||
|
||||
@classmethod
|
||||
def poll(cls, context):
|
||||
return context.window_manager.session.replay_files
|
||||
|
||||
def draw_header(self, context):
|
||||
self.layout.label(text="", icon='RECOVER_LAST')
|
||||
|
||||
def draw(self, context):
|
||||
layout = self.layout
|
||||
settings = context.window_manager.session
|
||||
row= layout.row()
|
||||
row.prop(settings,'replay_mode', toggle=True, expand=True)
|
||||
row= layout.row()
|
||||
if settings.replay_mode == 'MANUAL':
|
||||
row.prop(bpy.context.scene, 'active_replay_file', text="Snapshot index")
|
||||
else:
|
||||
row.prop(settings, 'replay_duration', text="Replay Duration")
|
||||
row= layout.row()
|
||||
row.prop(settings, 'replay_persistent_collection', text="persistent collection", toggle=True, icon='OUTLINER_COLLECTION')
|
||||
|
||||
if settings.replay_persistent_collection:
|
||||
row= layout.row()
|
||||
row.prop(settings, 'replay_camera', text="", icon='VIEW_CAMERA')
|
||||
|
||||
|
||||
classes = (
|
||||
SESSION_UL_users,
|
||||
SESSION_PT_settings,
|
||||
@@ -624,6 +657,7 @@ classes = (
|
||||
SESSION_PT_advanced_settings,
|
||||
SESSION_PT_user,
|
||||
SESSION_PT_repository,
|
||||
SESSION_PT_replay,
|
||||
VIEW3D_PT_overlay_session,
|
||||
)
|
||||
|
||||
|
||||
@@ -100,18 +100,6 @@ def get_state_str(state):
|
||||
return state_str
|
||||
|
||||
|
||||
def clean_scene():
|
||||
for type_name in dir(bpy.data):
|
||||
try:
|
||||
type_collection = getattr(bpy.data, type_name)
|
||||
for item in type_collection:
|
||||
type_collection.remove(item)
|
||||
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)]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user