2026-02-16
This commit is contained in:
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"last_check": "2025-12-29 12:28:02.952580",
|
||||
"last_check": "2026-02-12 10:41:20.508861",
|
||||
"backup_date": "December-11-2025",
|
||||
"update_ready": false,
|
||||
"ignore": false,
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
# ***** END GPL LICENCE BLOCK *****
|
||||
|
||||
import bpy
|
||||
from . import Tools
|
||||
|
||||
class GizmoSizeUp(bpy.types.Operator):
|
||||
"""Share keyframes between all the selected objects and bones"""
|
||||
@@ -144,7 +145,8 @@ class SwitchBoneCollectionsVisibility(bpy.types.Operator):
|
||||
start = 'pose.bones["'
|
||||
end = '"]'
|
||||
#get all the animated bones from the fcurves
|
||||
for fcu in obj.animation_data.action.fcurves:
|
||||
fcurves = Tools.get_fcurves(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
start_index = fcu.data_path.find(start)
|
||||
end_index = fcu.data_path.find(end)
|
||||
#if it's not a posebone fcurve then skip
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
+289
-189
@@ -8,6 +8,7 @@ from mathutils import Vector
|
||||
# import math
|
||||
from math import pi
|
||||
from . import emp
|
||||
from . import TempCtrls
|
||||
# import time
|
||||
from bpy.app.handlers import persistent
|
||||
from bpy_extras import anim_utils
|
||||
@@ -68,17 +69,21 @@ def draw_text_callback_px(self, context):
|
||||
font_id = 0 # XXX, need to find out how best to get this.
|
||||
#fade in
|
||||
factor = 0.5
|
||||
if not self.fade_out_start:
|
||||
alpha = (self.timer.time_duration / self.fade_duration) * factor if not self.no_timer else factor
|
||||
else:
|
||||
timer = self.timer.time_duration - self.fade_out_start
|
||||
alpha = (1 * factor) - ((timer / self.fade_duration ) * factor)
|
||||
try:
|
||||
if not self.fade_out_start:
|
||||
alpha = (self.timer.time_duration / self.fade_duration) * factor if not self.no_timer else factor
|
||||
else:
|
||||
timer = self.timer.time_duration - self.fade_out_start
|
||||
alpha = (1 * factor) - ((timer / self.fade_duration ) * factor)
|
||||
except ReferenceError:
|
||||
return
|
||||
|
||||
as_height = asset_shelf_height(context)
|
||||
# draw some text
|
||||
blf.position(font_id, 70, 45 + as_height, 0)
|
||||
blf.position(font_id, 70, 50 + as_height, 0)
|
||||
blf.size(font_id, self.size)
|
||||
blf.color(0, 1, 1, 0, alpha)
|
||||
|
||||
blf.draw(font_id, self.text)
|
||||
|
||||
class Markers_Retimer(bpy.types.Operator):
|
||||
@@ -188,8 +193,8 @@ class Markers_Retimer(bpy.types.Operator):
|
||||
if strip.mute:
|
||||
continue
|
||||
# actions.add(strip.action)
|
||||
all_fcurves.add(get_fcurves_channelbag(obj, strip.action))
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
all_fcurves.add(get_fcurves(obj, strip.action))
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
if fcurves not in all_fcurves:
|
||||
all_fcurves.add(fcurves)
|
||||
# actions.add(obj.animation_data.action)
|
||||
@@ -352,19 +357,23 @@ class Markers_Retimer(bpy.types.Operator):
|
||||
self.report({'ERROR'}, str(e) + '. Quitting RetimerMarkers')
|
||||
return {'CANCELLED'}
|
||||
|
||||
def init_frame_start_marker(self, scene, name = "Frame_Start"):
|
||||
def init_frame_start_marker(self, scene, name = "Frame Start"):
|
||||
'''Create the start frame marker'''
|
||||
self.frame_start_marker = scene.timeline_markers.new(name, frame = self.frame_start)
|
||||
self.frame_start_marker[ "Frame_Start"] = True
|
||||
self.frame_start_marker.select = False
|
||||
self.frame_start_marker_name = name
|
||||
if name in scene.timeline_markers:
|
||||
self.frame_start_marker = scene.timeline_markers[name]
|
||||
else:
|
||||
self.frame_start_marker = scene.timeline_markers.new(name, frame = self.frame_start)
|
||||
self.frame_start_marker.select = False
|
||||
|
||||
def init_frame_end_marker(self, scene, name = "Frame_End"):
|
||||
def init_frame_end_marker(self, scene, name = "Frame End"):
|
||||
'''Create the start frame marker'''
|
||||
self.frame_end_marker = scene.timeline_markers.new(name, frame = self.frame_end)
|
||||
self.frame_end_marker["Frame_End"] = True
|
||||
self.frame_end_marker.select = False
|
||||
self.frame_end_marker_name = name
|
||||
if name in scene.timeline_markers:
|
||||
self.frame_end_marker = scene.timeline_markers[name]
|
||||
else:
|
||||
self.frame_end_marker = scene.timeline_markers.new(name, frame = self.frame_end)
|
||||
self.frame_end_marker.select = False
|
||||
|
||||
def check_removed_markers(self, scene):
|
||||
#check if markers are gone in case of undo or if removed
|
||||
@@ -507,7 +516,7 @@ class Markers_BakeRange(bpy.types.Operator):
|
||||
atb.bake_frame_range = False
|
||||
return {'CANCELLED'}
|
||||
|
||||
scene.animtoolbox.bake_frame_range = True
|
||||
atb.bake_frame_range = True
|
||||
|
||||
self.frame_start = atb.bake_frame_start
|
||||
self.frame_end = atb.bake_frame_end
|
||||
@@ -640,15 +649,23 @@ def update_cursor_matrix(context):
|
||||
item_matrix = item.id_data.matrix_world @ item.matrix
|
||||
else:
|
||||
item_matrix = item.matrix_world
|
||||
|
||||
#apply the new cursor position based on previous cursor
|
||||
relative_matrix = Matrix(item['relative_cursor'])
|
||||
cursor.matrix = item_matrix @ relative_matrix.inverted()
|
||||
|
||||
if bpy.app.version < (5, 0, 0):
|
||||
relative_matrix = Matrix(item['relative_cursor'])
|
||||
else:
|
||||
# Since Blender 5 I need to reshape the array into a matrix using numpy
|
||||
matrix_4x4 = np.array(item['relative_cursor']).reshape(4, 4).T
|
||||
relative_matrix = Matrix(matrix_4x4)
|
||||
|
||||
cursor.matrix = item_matrix @ relative_matrix.inverted()
|
||||
cursor_matrix = cursor.matrix
|
||||
|
||||
def assign_relative_matrix(context, items):
|
||||
def assign_relative_matrix(context, items, prop = 'relative_cursor'):
|
||||
'''get the cursor relative matrices either from object or bones'''
|
||||
|
||||
global last_matrices
|
||||
if 'last_matrices' not in globals():
|
||||
last_matrices = []
|
||||
|
||||
cursor_matrix = context.scene.cursor.matrix
|
||||
matrix_avg = get_matrix_avg(items)
|
||||
|
||||
@@ -664,9 +681,9 @@ def assign_relative_matrix(context, items):
|
||||
|
||||
item_matrix = matrix_avg if len(items) > 1 else item_matrix
|
||||
matrix_dist = cursor_matrix.inverted() @ item_matrix
|
||||
item['relative_cursor'] = matrix_dist
|
||||
item[prop] = matrix_dist
|
||||
|
||||
return last_matrices
|
||||
return matrix_dist
|
||||
|
||||
def assign_relative_cursor_prop(context):
|
||||
'''Updating the matrix property of the cursor distance on the bone'''
|
||||
@@ -762,6 +779,7 @@ class Keyframe_Offset(bpy.types.Operator):
|
||||
|
||||
def invoke(self, context, event):
|
||||
self.mouse_x = event.mouse_x
|
||||
self.initial_offset = context.scene.animtoolbox.keyframes_offset
|
||||
# self.mouse_y = event.mouse_y
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
@@ -779,8 +797,11 @@ class Keyframe_Offset(bpy.types.Operator):
|
||||
self.mouse_x = event.mouse_x
|
||||
|
||||
scene.animtoolbox.keyframes_offset += value*0.01
|
||||
|
||||
if event.type in {'ESC'} or event.value == 'RELEASE': # Cancel
|
||||
if event.type in {'ESC', 'RIGHTMOUSE'} and event.value == 'RELEASE': # Cancel
|
||||
scene.animtoolbox.keyframes_offset = self.initial_offset
|
||||
return {'CANCELLED'}
|
||||
|
||||
if event.value == 'RELEASE' and event.type == 'LEFTMOUSE':
|
||||
self.execute(context)
|
||||
return {'FINISHED'}
|
||||
return {'RUNNING_MODAL'}
|
||||
@@ -838,7 +859,7 @@ def remove_offset_property(context):
|
||||
|
||||
def add_offset(obj, offset, prev_offset, bone_id = None):
|
||||
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
|
||||
for fcu in fcurves:
|
||||
if bone_id is not None:
|
||||
@@ -876,83 +897,71 @@ def add_offset(obj, offset, prev_offset, bone_id = None):
|
||||
fcu.keyframe_points.foreach_set('handle_left', updated_left_handle)
|
||||
fcu.keyframe_points.foreach_set('handle_right', updated_right_handle)
|
||||
fcu.update()
|
||||
|
||||
def add_keyframe(bone):
|
||||
|
||||
def get_locked_fcus(obj, locked_fcus = None):
|
||||
# Locked fcus might have been already created, if it's not None it was already not checked
|
||||
if locked_fcus is not None:
|
||||
return locked_fcus
|
||||
locked_fcus = set()
|
||||
if not obj.animation_data:
|
||||
return locked_fcus
|
||||
if not obj.animation_data.action:
|
||||
return locked_fcus
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
locked_fcus = {(fcu.data_path, fcu.array_index) for fcu in fcurves if fcu.lock}
|
||||
return locked_fcus
|
||||
|
||||
def add_keyframe(bone, locked_fcus = None):
|
||||
|
||||
obj = bone.id_data
|
||||
|
||||
if bone.rotation_mode == 'QUATERNION':
|
||||
rotation = 'rotation_quaternion'
|
||||
elif bone.rotation_mode == 'AXIS_ANGLE':
|
||||
rotation = 'rotation_axis_angle'
|
||||
else:
|
||||
rotation = 'rotation_euler'
|
||||
rotation = 'rotation_euler' if len(bone.rotation_mode) == 3 else 'rotation_' + bone.rotation_mode.lower()
|
||||
|
||||
# rotation = 'rotation_quaternion' if bone.rotation_mode == 'QUATERNION' else 'rotation_euler'
|
||||
transforms = ['location', rotation, 'scale']
|
||||
path = bone.path_from_id() if obj.mode == 'POSE' else ''
|
||||
groups = dict()
|
||||
#find fcurves that are locked to exclude them
|
||||
excluded_fcus = {}
|
||||
if obj.animation_data:
|
||||
if obj.animation_data.action:
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
if path not in fcu.data_path or not fcu.lock:
|
||||
continue
|
||||
groups.update({(fcu.data_path, fcu.array_index ): fcu.group.name})
|
||||
if fcu.data_path in excluded_fcus:
|
||||
excluded_fcus[fcu.data_path].append(fcu.array_index)
|
||||
else:
|
||||
excluded_fcus.update({fcu.data_path : [fcu.array_index]})
|
||||
|
||||
path = bone.path_from_id() + '.' if obj.mode == 'POSE' else ''
|
||||
|
||||
locked_fcus = get_locked_fcus(obj, locked_fcus)
|
||||
|
||||
#insert keyframe only to channels that are not excluded
|
||||
for transform in transforms:
|
||||
#path = bone.path_from_id() + '.' + transform
|
||||
path = bone.path_from_id() + '.' + transform if obj.mode == 'POSE' else transform
|
||||
# if path not in excluded_fcus:
|
||||
# bone.keyframe_insert(transform)
|
||||
# continue
|
||||
data_path = path + transform
|
||||
length = len(getattr(bone, transform))
|
||||
for i in range(length):
|
||||
if path in excluded_fcus:
|
||||
if i in excluded_fcus[path]:
|
||||
continue
|
||||
if (path, i) in groups:
|
||||
group_name = groups[(path, i)]
|
||||
else:
|
||||
group_name = bone.name
|
||||
|
||||
bone.keyframe_insert(transform, index = i, group = group_name, frame = bpy.context.scene.frame_current_final)
|
||||
|
||||
def get_fcu_inbetweens(bone, frame, fcu_inbetweens):
|
||||
|
||||
for i in range(length):
|
||||
# Check if this channel being filtered
|
||||
if TempCtrls.filter_transform(transform, i):
|
||||
continue
|
||||
# Skip if the fcurve was locked
|
||||
if (data_path, i) in locked_fcus:
|
||||
continue
|
||||
|
||||
bone.keyframe_insert(transform, index = i, group = bone.name, frame = bpy.context.scene.frame_current_final)
|
||||
|
||||
def get_fcu_inbetweens(bone, frame, fcu_inbetweens, inbetweens):
|
||||
obj = bone.id_data
|
||||
|
||||
if bone.rotation_mode == 'QUATERNION':
|
||||
rotation = 'rotation_quaternion'
|
||||
elif bone.rotation_mode == 'AXIS_ANGLE':
|
||||
rotation = 'rotation_axis_angle'
|
||||
else:
|
||||
rotation = 'rotation_euler'
|
||||
|
||||
rot_channel = rot_mode_to_channel(bone.rotation_mode)
|
||||
|
||||
# rotation = 'rotation_quaternion' if bone.rotation_mode == 'QUATERNION' else 'rotation_euler'
|
||||
transforms = ['location', rotation, 'scale']
|
||||
# fcurves = obj.animation_data.action.fcurves
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
transforms = ['location', rot_channel, 'scale']
|
||||
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
|
||||
#insert keyframe only to channels that are not excluded
|
||||
location, rotation, scale = bone.matrix_basis.decompose()
|
||||
for transform in transforms:
|
||||
path = bone.path_from_id() + '.' + transform if obj.mode == 'POSE' else transform
|
||||
length = len(getattr(bone, transform))
|
||||
|
||||
for i in range(length):
|
||||
fcu = fcurves.find(data_path = path, index = i)
|
||||
if not fcu:
|
||||
continue
|
||||
if fcu.lock:
|
||||
continue
|
||||
if not inbetweens:
|
||||
# If there is no inbetweens then we just want to store the fcurves for auto handles
|
||||
fcu_inbetweens[fcu] = None
|
||||
continue
|
||||
|
||||
if 'rotation' in transform:
|
||||
if transform == 'rotation_euler':
|
||||
coords = bone.matrix_basis.to_euler(bone.rotation_mode)
|
||||
@@ -960,7 +969,7 @@ def get_fcu_inbetweens(bone, frame, fcu_inbetweens):
|
||||
coords = rotation
|
||||
else:
|
||||
coords = locals()[transform]
|
||||
|
||||
|
||||
if fcu in fcu_inbetweens:
|
||||
fcu_inbetweens[fcu].update({frame : coords[i]})
|
||||
else:
|
||||
@@ -987,8 +996,10 @@ def add_inbetween_key(self, context):
|
||||
#strip = anim_data.nla_tracks[obj.als.layer_index].strips[0]
|
||||
#frame = round(bake_ops.frame_evaluation(context.scene.frame_current, strip), 3)
|
||||
frame = context.scene.frame_current
|
||||
paths = [bone.path_from_id() for bone in context.selected_pose_bones]
|
||||
fcurves = get_fcurves_channelbag(obj, anim_data.action)
|
||||
if obj.mode == 'POSE':
|
||||
paths = [bone.path_from_id() for bone in context.selected_pose_bones]
|
||||
|
||||
fcurves = get_fcurves(obj, anim_data.action)
|
||||
for fcu in fcurves:
|
||||
#filter selected bones
|
||||
if obj.mode == 'POSE': #apply only to selected bones
|
||||
@@ -1059,10 +1070,8 @@ def add_inbetween_worldmatrix(self, context):
|
||||
if action is None:
|
||||
self['inbetween_worldmatrix'] = 0.0
|
||||
return
|
||||
# frame = round(context.scene.frame_current, 2)
|
||||
|
||||
if not self.inbetween_worldmatrix:
|
||||
# scene.frame_set(frame)
|
||||
return
|
||||
|
||||
if obj.mode == 'POSE' and not context.selected_pose_bones:
|
||||
@@ -1073,37 +1082,38 @@ def add_inbetween_worldmatrix(self, context):
|
||||
|
||||
def get_matrix_other(self, context):
|
||||
'''Get the matrix from the other frame, either previous or the next'''
|
||||
|
||||
#get all the list of the frames from the different channels for each bone
|
||||
#rest of the code is only for posebones
|
||||
#creating a new dict to avoid frame_set at the same frame multiple times. It will get the matrix of multiple bones from each frame
|
||||
#This is done just to avoid extra scene evaluation using frame_set
|
||||
#adding the bone to the new flipped dict key using the frame number
|
||||
|
||||
scene = context.scene
|
||||
prev_frame_bones = dict()
|
||||
next_frame_bones = dict()
|
||||
for item, frames in self.items_frames.items():
|
||||
#get the next and previous frames
|
||||
next_frames = [frame for frame in frames if frame > self.frame]
|
||||
if next_frames:
|
||||
next_frame = next_frames[0]
|
||||
|
||||
next_frame = next_frames[0]
|
||||
#the bones that are on the next frame
|
||||
if next_frame in next_frame_bones:
|
||||
next_frame_bones[next_frame].append(item)
|
||||
else:
|
||||
next_frame_bones.update({next_frame : [item]})
|
||||
|
||||
prev_frames = [frame for frame in frames if frame < self.frame]
|
||||
if prev_frames:
|
||||
prev_frame = prev_frames[-1]
|
||||
if not prev_frame and not next_frame:
|
||||
|
||||
prev_frame = prev_frames[-1]
|
||||
if prev_frame in prev_frame_bones:
|
||||
prev_frame_bones[prev_frame].append(item)
|
||||
else:
|
||||
prev_frame_bones.update({prev_frame : [item]})
|
||||
|
||||
if not prev_frames and not next_frames:
|
||||
continue
|
||||
|
||||
#get all the list of the frames from the different channels for each bone
|
||||
#rest of the code is only for posebones
|
||||
#creating a new dict to avoid frame_set at the same frame multiple times. It will get the matrix of multiple bones from each frame
|
||||
#This is done just to avoid extra scene evaluation using frame_set
|
||||
#adding the bone to the new flipped dict key using the frame number
|
||||
prev_frame_bones = dict()
|
||||
if prev_frame in prev_frame_bones:
|
||||
prev_frame_bones[prev_frame].append(item)
|
||||
else:
|
||||
prev_frame_bones.update({prev_frame : [item]})
|
||||
|
||||
#the bones that are on the next frame
|
||||
next_frame_bones = dict()
|
||||
if next_frame in next_frame_bones:
|
||||
next_frame_bones[next_frame].append(item)
|
||||
else:
|
||||
next_frame_bones.update({next_frame : [item]})
|
||||
|
||||
#if item.id_data.mode == 'POSE':
|
||||
|
||||
@@ -1154,7 +1164,7 @@ class InbetweenWorldMatrix(bpy.types.Operator):
|
||||
|
||||
bone = None
|
||||
|
||||
fcurves = get_fcurves_channelbag(obj, action)
|
||||
fcurves = get_fcurves(obj, action)
|
||||
for fcu in fcurves:
|
||||
#filter selected bones
|
||||
if obj.mode == 'POSE': #apply only to selected bones
|
||||
@@ -1188,7 +1198,6 @@ class InbetweenWorldMatrix(bpy.types.Operator):
|
||||
self.items_frames.update({bone : frames})
|
||||
|
||||
get_matrix_other(self, context)
|
||||
|
||||
context.window_manager.modal_handler_add(self)
|
||||
return {'RUNNING_MODAL'}
|
||||
|
||||
@@ -1205,6 +1214,20 @@ class InbetweenWorldMatrix(bpy.types.Operator):
|
||||
#modal is being cancelled because of undo issue with the modal running through the property
|
||||
return {'FINISHED'}
|
||||
|
||||
if event.type in {'ESC', 'RIGHTMOUSE'} and event.value == 'RELEASE': # Cancel
|
||||
# Revert to the original matrix
|
||||
for bone, matrix in self.items_matrix_org.items():
|
||||
if bone.id_data.mode == 'POSE':
|
||||
bone.matrix = matrix
|
||||
else:
|
||||
bone.matrix_world = matrix
|
||||
|
||||
# if scene.tool_settings.use_keyframe_insert_auto:
|
||||
# add_keyframe(bone)
|
||||
context.window_manager.atb_ui['is_dragging'] = False
|
||||
self.atb['inbetween_worldmatrix'] = 0
|
||||
return {'CANCELLED'}
|
||||
|
||||
if event.value == 'RELEASE': # Stop the modal on next frame. Don't block the event since we want to exit the field dragging
|
||||
self.stop = True
|
||||
|
||||
@@ -1227,8 +1250,8 @@ class InbetweenWorldMatrix(bpy.types.Operator):
|
||||
else:
|
||||
bone.matrix_world = matrix
|
||||
|
||||
if scene.tool_settings.use_keyframe_insert_auto:
|
||||
add_keyframe(bone)
|
||||
# if scene.tool_settings.use_keyframe_insert_auto:
|
||||
# add_keyframe(bone)
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
@@ -1296,18 +1319,19 @@ class BlendToMirroModal(bpy.types.Operator):
|
||||
if self.stop:
|
||||
context.window_manager.atb_ui['is_dragging'] = False
|
||||
for bone in context.selected_pose_bones:
|
||||
if scene.tool_settings.use_keyframe_insert_auto:
|
||||
if scene.tool_settings.use_keyframe_insert_auto and self.finish == {'FINISHED'}:
|
||||
add_keyframe(bone)
|
||||
if 'matrix' in bone:
|
||||
del bone['matrix']
|
||||
self.ui['blend_mirror'] = 0
|
||||
redraw_areas(['PROPERTIES'])
|
||||
#modal is being cancelled because of undo issue with the modal running through the property
|
||||
return {'FINISHED'}
|
||||
return self.finish
|
||||
|
||||
if event.value == 'RELEASE': # Stop the modal on next frame. Don't block the event since we want to exit the field dragging
|
||||
self.stop = True
|
||||
|
||||
self.finish = {'CANCELLED'} if event.type in {'ESC', 'RIGHTMOUSE'} else {'FINISHED'}
|
||||
|
||||
for bone in context.selected_pose_bones:
|
||||
mirror_bone = find_mirror_bone(bone)
|
||||
if mirror_bone is None:
|
||||
@@ -1315,7 +1339,10 @@ class BlendToMirroModal(bpy.types.Operator):
|
||||
mirror_bone_matrix = mirror_bone.matrix_basis.copy()
|
||||
mirror_plane = Matrix.Scale(-1, 4, (1, 0, 0))
|
||||
mirrored_matrix = mirror_plane @ mirror_bone_matrix @ mirror_plane
|
||||
matrix = Matrix(bone['matrix']).lerp(mirrored_matrix, self.ui.blend_mirror)
|
||||
|
||||
bone_matrix = bone['matrix'] if bpy.app.version < (5, 0, 0) else np.array(bone['matrix']).reshape(4, 4).T
|
||||
|
||||
matrix = Matrix(bone_matrix).lerp(mirrored_matrix, self.ui.blend_mirror)
|
||||
matrix = filter_matrix_properties(context, bone.matrix_basis, matrix)
|
||||
bone.matrix_basis = matrix
|
||||
|
||||
@@ -1357,7 +1384,7 @@ class SelectKeyframesOffset(bpy.types.Operator):
|
||||
if 'keyframes_offset' in bone:
|
||||
#check if there are bones with an offset
|
||||
posemode = True
|
||||
obj.data.bones[bone.name].select = True
|
||||
TempCtrls.posebone_select(bone, True)
|
||||
if posemode and obj.mode != 'POSE':
|
||||
context.view_layer.objects.active = obj
|
||||
bpy.ops.object.mode_set(mode = 'POSE')
|
||||
@@ -1365,6 +1392,25 @@ class SelectKeyframesOffset(bpy.types.Operator):
|
||||
return {'FINISHED'}
|
||||
|
||||
def get_frame_range(context, obj):
|
||||
|
||||
def selected_frame_range(frame_range):
|
||||
smartframes = set()
|
||||
|
||||
if obj.mode == 'POSE':
|
||||
bones_paths = [bone.path_from_id() for bone in context.selected_pose_bones if bone.name in obj.pose.bones]
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
|
||||
for fcu in fcurves:
|
||||
path = fcu.data_path.split('"].')[0] + '"]'
|
||||
if obj.mode == 'POSE' and path not in bones_paths:
|
||||
continue
|
||||
for keyframe in fcu.keyframe_points:
|
||||
smartframes.add(round(keyframe.co[0], 2))
|
||||
if keyframe.select_control_point:
|
||||
frame_range.append(round(keyframe.co[0], 2))
|
||||
|
||||
return smartframes
|
||||
|
||||
#get the frame range
|
||||
frame_range = []
|
||||
inbetweens = []
|
||||
@@ -1377,27 +1423,21 @@ def get_frame_range(context, obj):
|
||||
if atb.bake_frame_start > atb.bake_frame_end:
|
||||
atb.bake_frame_start = atb.bake_frame_end
|
||||
frame_range = list(range(atb.bake_frame_start, atb.bake_frame_end+1))
|
||||
|
||||
elif atb.range_type == 'SELECTED':
|
||||
if obj.mode == 'POSE':
|
||||
bones_paths = [bone.path_from_id() for bone in context.selected_pose_bones]
|
||||
if obj.animation_data is None:
|
||||
return frame_range
|
||||
if obj.animation_data.action is None:
|
||||
return frame_range
|
||||
|
||||
smartframes = set()
|
||||
|
||||
elif obj.animation_data is None:
|
||||
return frame_range, inbetweens
|
||||
elif obj.animation_data.action is None:
|
||||
return frame_range, inbetweens
|
||||
|
||||
elif atb.range_type == 'SELECTED_RANGE':
|
||||
# Create a list of a keyframes between the first selected keyframes and the last selected one
|
||||
selected_frame_range(frame_range)
|
||||
if frame_range:
|
||||
frame_range = list(range(int(min(frame_range)), int(max(frame_range))+1))
|
||||
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
path = fcu.data_path.split('"].')[0] + '"]'
|
||||
if obj.mode == 'POSE' and path not in bones_paths:
|
||||
continue
|
||||
for keyframe in fcu.keyframe_points:
|
||||
smartframes.add(round(keyframe.co[0], 2))
|
||||
if keyframe.select_control_point:
|
||||
frame_range.append(round(keyframe.co[0], 2))
|
||||
|
||||
elif atb.range_type == 'SELECTED':
|
||||
|
||||
smartframes = selected_frame_range(frame_range)
|
||||
smartframes = sorted(smartframes)
|
||||
frame_range = sorted(set(frame_range))
|
||||
|
||||
@@ -1422,6 +1462,7 @@ def get_frame_range(context, obj):
|
||||
|
||||
def notification_invoke(self, context, text = 'Copy Matrix', size = 20.0):
|
||||
'''get ready and lauch the notification'''
|
||||
|
||||
wm = context.window_manager
|
||||
self.timer = wm.event_timer_add(0.1, window=context.window)
|
||||
self.no_timer = False
|
||||
@@ -1432,16 +1473,21 @@ def notification_invoke(self, context, text = 'Copy Matrix', size = 20.0):
|
||||
self.fade_out_start = 0
|
||||
self.draw_handle = bpy.types.SpaceView3D.draw_handler_add(draw_text_callback_px, (self, context), 'WINDOW', 'POST_PIXEL')
|
||||
redraw_areas(['VIEW_3D'])
|
||||
|
||||
|
||||
def update_notification(self, context, event, esc = False, fade_out = True):
|
||||
'''notify with a modal operator that the matrix was being copied'''
|
||||
|
||||
if not hasattr(self, 'draw_handle'):
|
||||
return {'FINISHED'}
|
||||
|
||||
#Quit from the notification
|
||||
if event.type in {'ESC'} or esc:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(self.draw_handle, 'WINDOW')
|
||||
context.area.tag_redraw()
|
||||
|
||||
if context.area is not None:
|
||||
context.area.tag_redraw()
|
||||
elif hasattr(self, 'area'):
|
||||
self.area.tag_redraw()
|
||||
|
||||
context.window_manager.event_timer_remove(self.timer)
|
||||
del self.draw_handle
|
||||
return {'FINISHED'}
|
||||
@@ -1470,6 +1516,14 @@ def update_notification(self, context, event, esc = False, fade_out = True):
|
||||
|
||||
return {'PASS_THROUGH'}
|
||||
|
||||
def compatible_rotation(bone, bones_prevrot):
|
||||
'''Make sure the bone is not flipping and is compatible with previous frame rotation'''
|
||||
rotation_channel = rot_mode_to_channel(bone.rotation_mode)
|
||||
if bone in bones_prevrot:
|
||||
rot = getattr(bone, rotation_channel)
|
||||
rot.make_compatible(bones_prevrot[bone])
|
||||
bones_prevrot[bone] = getattr(bone, rotation_channel).copy()
|
||||
|
||||
class CopyMatrix(bpy.types.Operator):
|
||||
"""Copy the matrix of the selection and store it"""
|
||||
bl_idname = "anim.copy_matrix"
|
||||
@@ -1546,6 +1600,7 @@ class PasteMatrix(bpy.types.Operator):
|
||||
frame_current_final = scene.frame_current_final
|
||||
|
||||
bones_matrices = dict()
|
||||
bones_prevrot = dict()
|
||||
constrained = set()
|
||||
#constraint evaluation is
|
||||
# con.target.matrix_world.copy() @ con.inverse_matrix @ basis
|
||||
@@ -1564,6 +1619,11 @@ class PasteMatrix(bpy.types.Operator):
|
||||
for obj in context.selected_objects:
|
||||
frame_range, inbetweens = get_frame_range(context, obj)
|
||||
fcu_inbetweens = dict()
|
||||
|
||||
# Checking for locked fcurves before iterating
|
||||
locked_fcus = get_locked_fcus(obj)
|
||||
|
||||
|
||||
for frame in sorted(frame_range + inbetweens):
|
||||
scene.frame_set(int(frame), subframe = frame % 1)
|
||||
if obj.mode == 'POSE':
|
||||
@@ -1588,7 +1648,7 @@ class PasteMatrix(bpy.types.Operator):
|
||||
|
||||
#adding the keyframes
|
||||
for bone in bones_matrices.keys():
|
||||
paste_keyframes_get_inbetweens(scene, bone, inbetweens, frame, frame_range, fcu_inbetweens)
|
||||
paste_keyframes_get_inbetweens(scene, bone, inbetweens, frame, frame_range, fcu_inbetweens, locked_fcus, bones_prevrot)
|
||||
|
||||
else:
|
||||
target = obj
|
||||
@@ -1603,10 +1663,13 @@ class PasteMatrix(bpy.types.Operator):
|
||||
matrix_copied = reverse_constraint_offset(target.matrix_world, matrix_copied)
|
||||
target.matrix_world = filter_matrix_properties(context, target.matrix_world, matrix_copied)
|
||||
|
||||
paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens)
|
||||
paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens, locked_fcus, bones_prevrot)
|
||||
|
||||
if inbetweens and len(frame_range) > 1:
|
||||
add_interpolations(fcu_inbetweens.keys(), fcu_inbetweens, frames = frame_range[:-1])
|
||||
if len(frame_range) > 1:
|
||||
if inbetweens:
|
||||
add_interpolations(fcu_inbetweens.keys(), fcu_inbetweens, frames = frame_range[:-1])
|
||||
else:
|
||||
set_auto_handles(fcu_inbetweens.keys(), frame_range)
|
||||
|
||||
if context.scene.frame_current_final != frame_current_final:
|
||||
scene.frame_current = int(frame_current_final)
|
||||
@@ -1678,7 +1741,8 @@ class CopyRelativeMatrix(bpy.types.Operator):
|
||||
if obj.type == 'ARMATURE':
|
||||
#Get the distance from the selected bones
|
||||
for bone_relative in obj.pose.bones:
|
||||
if not bone_relative.bone.select:
|
||||
selected = bone_relative.bone.select if bpy.app.version < (5, 0, 0) else bone_relative.select
|
||||
if not selected:
|
||||
continue
|
||||
if bone_relative == source_active:
|
||||
continue
|
||||
@@ -1704,14 +1768,18 @@ class CopyRelativeMatrix(bpy.types.Operator):
|
||||
|
||||
return {'FINISHED'}
|
||||
|
||||
def paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens):
|
||||
def paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens, locked_fcus, bones_prevrot):
|
||||
|
||||
#Make sure the rotation is compatible with the previous rotation
|
||||
compatible_rotation(target, bones_prevrot)
|
||||
|
||||
#if autokey is turned on then add a keyframe
|
||||
if (scene.tool_settings.use_keyframe_insert_auto or scene.animtoolbox.range_type != 'CURRENT') and 'target' in locals():
|
||||
if frame not in inbetweens:
|
||||
add_keyframe(target)
|
||||
add_keyframe(target, locked_fcus)
|
||||
#store the inbetween values
|
||||
elif len(frame_range) > 1:
|
||||
fcu_inbetweens = get_fcu_inbetweens(target, frame, fcu_inbetweens)
|
||||
if len(frame_range) > 1:
|
||||
fcu_inbetweens = get_fcu_inbetweens(target, frame, fcu_inbetweens, inbetweens)
|
||||
|
||||
def reverse_bone_constraints(context, bone, matrix_copied):
|
||||
|
||||
@@ -1865,6 +1933,8 @@ class PasteRelativeMatrix(bpy.types.Operator):
|
||||
source_bone = None
|
||||
source_obj = None
|
||||
bones_matrices = dict()
|
||||
# Store previous rotations to be compared and avoid flips
|
||||
bones_prevrot = dict()
|
||||
constrained = set()
|
||||
#get the source matrix
|
||||
if 'source_rig_name' in globals():
|
||||
@@ -1890,6 +1960,8 @@ class PasteRelativeMatrix(bpy.types.Operator):
|
||||
frame_range, inbetweens = get_frame_range(context, obj)
|
||||
fcu_inbetweens = dict()
|
||||
|
||||
# Checking for locked fcurves before iterating
|
||||
locked_fcus = get_locked_fcus(obj)
|
||||
|
||||
for frame in sorted(frame_range+inbetweens):
|
||||
scene.frame_set(int(frame))
|
||||
@@ -1925,7 +1997,7 @@ class PasteRelativeMatrix(bpy.types.Operator):
|
||||
paste_bones_matrices(bones_matrices, constrained)
|
||||
|
||||
for bone in bones_matrices.keys():
|
||||
paste_keyframes_get_inbetweens(scene, bone, inbetweens, frame, frame_range, fcu_inbetweens)
|
||||
paste_keyframes_get_inbetweens(scene, bone, inbetweens, frame, frame_range, fcu_inbetweens, locked_fcus, bones_prevrot)
|
||||
|
||||
else:
|
||||
target = obj
|
||||
@@ -1950,11 +2022,14 @@ class PasteRelativeMatrix(bpy.types.Operator):
|
||||
matrix_new = reverse_constraint_offset(target.matrix_world, matrix_new)
|
||||
target.matrix_world = filter_matrix_properties(context, target.matrix_world, matrix_new)
|
||||
|
||||
paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens)
|
||||
|
||||
if inbetweens and len(frame_range) > 1:
|
||||
add_interpolations(fcu_inbetweens.keys(), fcu_inbetweens, frames = frame_range[:-1])
|
||||
paste_keyframes_get_inbetweens(scene, target, inbetweens, frame, frame_range, fcu_inbetweens, locked_fcus, bones_prevrot)
|
||||
|
||||
if len(frame_range) > 1:
|
||||
if inbetweens:
|
||||
add_interpolations(fcu_inbetweens.keys(), fcu_inbetweens, frames = frame_range[:-1])
|
||||
else:
|
||||
set_auto_handles(fcu_inbetweens.keys(), frame_range)
|
||||
|
||||
#return to the original frame in case of using frame range
|
||||
if context.scene.frame_current != frame_current:
|
||||
scene.frame_current = frame_current
|
||||
@@ -2005,8 +2080,7 @@ def sharekeys_add_missing_fcurves(obj, attr_index, fcurves):
|
||||
action = obj.id_data.animation_data.action
|
||||
|
||||
#Get the container, either action of channelbag because of adding groups
|
||||
fcurves_container = get_fcurves_container(obj, action)
|
||||
|
||||
channelbag = get_channelbag(obj.id_data, action)
|
||||
if 'rotation' in attr:
|
||||
#converting the rotation depending on the rotation mode
|
||||
mode = 'euler' if len(obj.rotation_mode) == 3 else obj.rotation_mode.lower()
|
||||
@@ -2019,14 +2093,14 @@ def sharekeys_add_missing_fcurves(obj, attr_index, fcurves):
|
||||
continue
|
||||
elif rot != 'rotation_euler' and (path, 3) not in datapaths_arrays:
|
||||
#adding an extra curve for quaternion or axis_angle
|
||||
extra_fcu = fcurves_container.fcurves.new(data_path = path, index = 3, action_group = group)
|
||||
extra_fcu = channelbag.fcurves.new(data_path = path, index = 3, action_group = group)
|
||||
fcurves.append(extra_fcu)
|
||||
datapaths_arrays.add((extra_fcu.data_path, extra_fcu.array_index))
|
||||
|
||||
if (path, index) in datapaths_arrays:
|
||||
continue
|
||||
|
||||
fcu = fcurves_container.fcurves.new(data_path = path, index = index)
|
||||
fcu = channelbag.fcurves.new(data_path = path, index = index)
|
||||
add_group_to_fcurve(obj.id_data, fcu, group)
|
||||
fcurves.append(fcu)
|
||||
datapaths_arrays.add((fcu.data_path, fcu.array_index))
|
||||
@@ -2102,7 +2176,7 @@ class ShareKeys(bpy.types.Operator):
|
||||
def get_fcurves_set(self, obj_actions):
|
||||
fcurves = set()
|
||||
for obj, action in obj_actions.items():
|
||||
fcurves = fcurves.union(set(get_fcurves_channelbag(obj, action)))
|
||||
fcurves = fcurves.union(set(get_fcurves(obj, action)))
|
||||
return fcurves
|
||||
|
||||
def add_get_action(self, obj):
|
||||
@@ -2141,7 +2215,7 @@ class ShareKeys(bpy.types.Operator):
|
||||
continue
|
||||
#if there is no animation data or an action then create it
|
||||
action = self.add_get_action(obj)
|
||||
fcurves = get_fcurves_channelbag(obj, action)
|
||||
fcurves = get_fcurves(obj, action)
|
||||
frames, attr_index_obj = get_fcurves_frames([obj], fcurves, all_fcurves, frames, attr_index_obj)
|
||||
|
||||
if obj.data.animation_data is None:
|
||||
@@ -2150,7 +2224,7 @@ class ShareKeys(bpy.types.Operator):
|
||||
continue
|
||||
#add the type of object if the data is also animated
|
||||
actions_data_types.add(obj.type)
|
||||
fcurves = get_fcurves_channelbag(obj.data, obj.data.animation_data.action)
|
||||
fcurves = get_fcurves(obj.data, obj.data.animation_data.action)
|
||||
frames, attr_index_obj = get_fcurves_frames([obj], fcurves, all_fcurves, frames, attr_index_obj)
|
||||
|
||||
#Getting all the available transforms and array index
|
||||
@@ -2333,6 +2407,15 @@ def add_inbetweens(smartframes):
|
||||
# all_frames = sorted(self.frames + self.inbetweens)
|
||||
return inbetweens
|
||||
|
||||
def set_auto_handles(fcurves, frame_range):
|
||||
|
||||
for fcu in fcurves:
|
||||
for keyframe in fcu.keyframe_points:
|
||||
if keyframe.co[0] in frame_range:
|
||||
keyframe.handle_right_type = 'AUTO'
|
||||
keyframe.handle_left_type = 'AUTO'
|
||||
fcu.update()
|
||||
|
||||
def add_interpolations(fcurves, fcu_inbetweens, frames = None):
|
||||
|
||||
inbetweens = sorted(set([frame for inbetweens in fcu_inbetweens.values() for frame in inbetweens.keys()]))
|
||||
@@ -2419,7 +2502,7 @@ class FindRotationMode(bpy.types.Operator):
|
||||
rot_mode = posebone.rotation_mode
|
||||
obj = posebone.id_data
|
||||
# fcurves = obj.animation_data.action.fcurves
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
new_rot_eulers = []
|
||||
|
||||
#get the values from the original rotation
|
||||
@@ -2533,7 +2616,7 @@ class ConvertRotationMode(bpy.types.Operator):
|
||||
def switch_rot_mode_keyframes(self, obj, posebone):
|
||||
# Switching any rotation mode keyframes to the new rotation mode value using to_rot_mode_index
|
||||
bone_path = posebone.path_from_id() + '.' if type(posebone) == bpy.types.PoseBone else ''
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
fcurves = get_fcurves(obj, obj.animation_data.action)
|
||||
fcu_rotation_mode = fcurves.find(data_path = bone_path + 'rotation_mode', index = 0)
|
||||
if fcu_rotation_mode:
|
||||
for keyframe in fcu_rotation_mode.keyframe_points:
|
||||
@@ -2556,7 +2639,7 @@ class ConvertRotationMode(bpy.types.Operator):
|
||||
obj = posebone.id_data
|
||||
# fcurves = obj.animation_data.action.fcurves
|
||||
action = obj.animation_data.action
|
||||
fcurves = get_fcurves_channelbag(obj, action)
|
||||
fcurves = get_fcurves(obj, action)
|
||||
fcu_inbetweens = dict()
|
||||
fcu_keyframes = dict()
|
||||
#get the transform from the original rot mode
|
||||
@@ -2858,6 +2941,10 @@ def get_obj_slot(obj, action):
|
||||
if obj in slot.users():
|
||||
return slot
|
||||
|
||||
# If no slot with the users was found then get the next available slot
|
||||
if obj.animation_data.action_suitable_slots:
|
||||
return next(iter(obj.animation_data.action_suitable_slots))
|
||||
|
||||
return None
|
||||
|
||||
def get_all_fcurves(action):
|
||||
@@ -2868,21 +2955,48 @@ def get_all_fcurves(action):
|
||||
for strip in layer.strips:
|
||||
for channelbag in strip.channelbags:
|
||||
yield from channelbag.fcurves
|
||||
|
||||
def get_fcurves(obj, action: bpy.types.Action):
|
||||
|
||||
if hasattr(action, 'layers'):
|
||||
channelbag = get_channelbag(obj, action)
|
||||
|
||||
return channelbag.fcurves
|
||||
|
||||
# action.fcurves not available anymore from Blender 5.0
|
||||
if hasattr(action, 'fcurves'):
|
||||
return action.fcurves
|
||||
|
||||
def get_fcurves_channelbag(obj, action: bpy.types.Action):
|
||||
return []
|
||||
|
||||
def get_channelbag(obj, action: bpy.types.Action):
|
||||
'''Getting the container of the fcurves, either the action or channelbag
|
||||
Using this when adding a new group to the action'''
|
||||
|
||||
if hasattr(action, 'layers'):
|
||||
slot = get_obj_slot(obj, action)
|
||||
if not slot:
|
||||
return action.fcurves
|
||||
channelbag = anim_utils.action_get_channelbag_for_slot(action, slot)
|
||||
if channelbag:
|
||||
return channelbag.fcurves
|
||||
|
||||
return action.fcurves
|
||||
channelbag = None
|
||||
if slot:
|
||||
channelbag = anim_utils.action_get_channelbag_for_slot(action, slot)
|
||||
else:
|
||||
# If a signed slot was not found then add a new one
|
||||
slot = add_action_slot(obj, action)
|
||||
obj.animation_data.action_slot = slot
|
||||
channelbag = anim_utils.action_get_channelbag_for_slot(action, slot)
|
||||
|
||||
if channelbag is None:
|
||||
# action_ensure_channelbag_for_slot works only from Blender 5
|
||||
if hasattr(anim_utils, 'action_ensure_channelbag_for_slot'):
|
||||
channelbag = anim_utils.action_ensure_channelbag_for_slot(action, slot)
|
||||
else:
|
||||
channelbag = add_channelbag(obj, action)
|
||||
|
||||
return channelbag
|
||||
else:
|
||||
return action
|
||||
|
||||
def add_channelbag(obj, action):
|
||||
|
||||
'''Old might need to remove'''
|
||||
if not hasattr(action, 'layers'):
|
||||
return
|
||||
slot = get_obj_slot(obj, action)
|
||||
@@ -2904,26 +3018,12 @@ def add_channelbag(obj, action):
|
||||
|
||||
return channelbag
|
||||
|
||||
def get_fcurves_container(obj: bpy.types.Object, action: bpy.types.Action):
|
||||
'''Getting the container of the fcurves, either the action or channelbag
|
||||
Using this when adding a new group to the action'''
|
||||
|
||||
if hasattr(action, 'layers'):
|
||||
slot = get_obj_slot(obj, action)
|
||||
if not slot:
|
||||
return action
|
||||
channelbag = anim_utils.action_get_channelbag_for_slot(action, slot)
|
||||
return channelbag
|
||||
|
||||
else:
|
||||
return action
|
||||
|
||||
def add_group_to_fcurve(obj, fcu, groupname):
|
||||
'''Add an fcurve group based on the fcurve container, either action or channelbag'''
|
||||
|
||||
action = fcu.id_data
|
||||
#get the container which is either a channelbag or a group
|
||||
fcu_container = get_fcurves_container(obj, action)
|
||||
fcu_container = get_channelbag(obj, action)
|
||||
group = fcu_container.groups.get(groupname)
|
||||
if group is None:
|
||||
group = fcu_container.groups.new(groupname)
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
bl_info = {
|
||||
"name": "AnimToolBox",
|
||||
"author": "Tal Hershkovich",
|
||||
"version" : (0, 0, 8),
|
||||
"version" : (0, 2, 3),
|
||||
"blender" : (3, 2, 0),
|
||||
"location": "View3D - Properties - Animation Panel",
|
||||
"description": "A set of animation tools",
|
||||
@@ -119,6 +119,11 @@ class TempCtrlsSceneSettings(bpy.types.PropertyGroup):
|
||||
add_ik_ctrl: bpy.props.BoolProperty(name = 'Add an Extra IK Ctrl Bone', description = "Adds an extra bone ctrl as the ik ctrl", default = False, update = TempCtrls.add_ik_prop)
|
||||
pole_target: bpy.props.BoolProperty(name = 'Add Pole Target', description = "Adding Pole Target to the IK Chain", default = True, update = TempCtrls.pole_prop)
|
||||
pole_offset: bpy.props.FloatProperty(name="Offset", description="Offset the bone in the axis direction", default=1.0, update = TempCtrls.pole_offset)
|
||||
pole_axis: bpy.props.EnumProperty(name = 'Axis Direction', description="Which direction should the pole bone point", default = 4, update = TempCtrls.update_axis_prop,
|
||||
items = [('+X', '+X','Target Bone the +X Axis', 0), ('+Y', '+Y', 'Target Bone the +Y Axis', 1),
|
||||
('-X', '-X','Target Bone the -X Axis', 2), ('-Y', '-Y', 'Target Bone the -Y Axis', 3),
|
||||
('AUTO', 'Auto','Select pole bone direction based on the current pose', 4)])
|
||||
|
||||
child: bpy.props.BoolProperty(name = 'Add extra child Ctrls', description = "Add an child control for an overlay control", default = False, update = TempCtrls.child_prop)
|
||||
orientation: bpy.props.BoolProperty(name = 'Use World Space Orientation', description = "Orient the bones to world space instead of to the original bones", default = True)
|
||||
|
||||
@@ -252,8 +257,9 @@ class AnimToolBoxGlobalSettings(bpy.types.PropertyGroup):
|
||||
#Copy/Pase Matrix
|
||||
range_type: bpy.props.EnumProperty(name = 'Paste to Frames', description="Paste to current frame or a range of frames.", update = Tools.bake_range_type,
|
||||
items = [('CURRENT', 'Current Frame','Paste Matrix to only current frame', 0),
|
||||
('SELECTED', 'Selected Keyframe','Paste Matrix to only selected keyframes', 1),
|
||||
('RANGE', 'Frame Range','Paste Matrix to a Frame Range', 2)])
|
||||
('SELECTED', 'Selected Keyframes','Paste Matrix only to the selected keyframes', 1),
|
||||
('RANGE', 'Frame Range','Paste Matrix to a Custom Frame Range', 2),
|
||||
('SELECTED_RANGE', 'Selected Keyframes Range','Paste Matrix to every frame within a selected keyframe range', 3)])
|
||||
bake_frame_start: bpy.props.IntProperty(name = "Bake Frame Start", description = "Define the start frame to paste the matrix", min = 0, update = Tools.bake_frame_start_limit)
|
||||
bake_frame_end: bpy.props.IntProperty(name = "Bake Frame End", description = "Define the end frame to paste the matrix", min = 0, update = Tools.bake_frame_end_limit)
|
||||
|
||||
@@ -298,6 +304,11 @@ class AnimToolBoxPreferences(bpy.types.AddonPreferences):
|
||||
mp_handle_selection_color: bpy.props.FloatVectorProperty(name="Handles Selection", subtype='COLOR', default=(0.8, 0.65, 0.6, 0.8), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_key_selection_color: bpy.props.FloatVectorProperty(name="Keyframe Selection", subtype='COLOR', default=(0.8, 0.8, 0.6, 0.8), size=4, min=0.0, max=1.0, description="Keyframe selection color")
|
||||
|
||||
# Motion Path brush colors
|
||||
mp_brush_disabled: bpy.props.FloatVectorProperty(name="Disabled", subtype='COLOR', default=(0.7, 0.7, 0.9, 0.75), size=4, min=0.0, max=1.0, description="Brush is disabled and have no influence")
|
||||
mp_brush_hover: bpy.props.FloatVectorProperty(name="Hover", subtype='COLOR', default=(0.8, 0.7, 0.2, 0.8), size=4, min=0.0, max=1.0, description="Brush is hovering and can be activated")
|
||||
mp_brush_active: bpy.props.FloatVectorProperty(name="Active", subtype='COLOR', default=(1.0, 1.0, 1.0, 0.9), size=4, min=0.0, max=1.0, description="Brush is activated")
|
||||
|
||||
# addon updater preferences from `__init__`, be sure to copy all of them
|
||||
auto_check_update: bpy.props.BoolProperty(
|
||||
name = "Auto-check for Update",
|
||||
@@ -371,6 +382,12 @@ class AnimToolBoxPreferences(bpy.types.AddonPreferences):
|
||||
row.prop(self, 'mp_hover_color')
|
||||
row.prop(self, 'mp_key_selection_color')
|
||||
row.prop(self, 'mp_handle_selection_color')
|
||||
col = box.row()
|
||||
col.label(text = 'Brush Colors')
|
||||
row = box.row()
|
||||
row.prop(self, 'mp_brush_disabled')
|
||||
row.prop(self, 'mp_brush_hover')
|
||||
row.prop(self, 'mp_brush_active')
|
||||
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
@@ -392,6 +409,8 @@ def loadanimtoolbox_pre(self, context):
|
||||
if 'mp_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('mp_dh')
|
||||
emp.remove_draw_circle()
|
||||
|
||||
bpy.context.scene.emp.selected_keyframes = '{}'
|
||||
|
||||
if 'markers_retimer_dh' in dns:
|
||||
@@ -401,20 +420,38 @@ def loadanimtoolbox_pre(self, context):
|
||||
#remove the motion path app handler if it's still inside
|
||||
if emp.mp_value_update in bpy.app.handlers.depsgraph_update_post:
|
||||
bpy.app.handlers.depsgraph_update_post.remove(emp.mp_value_update)
|
||||
if emp.mp_frame_change in bpy.app.handlers.frame_change_post:
|
||||
bpy.app.handlers.frame_change_post.remove(emp.mp_frame_change)
|
||||
if emp.mp_undo_update in bpy.app.handlers.undo_pre:
|
||||
bpy.app.handlers.undo_pre.remove(emp.mp_undo_update)
|
||||
|
||||
@persistent
|
||||
def loadanimtoolbox_post(self, context):
|
||||
scene = bpy.context.scene
|
||||
|
||||
def remove_markers(prop, marker_type, names):
|
||||
'''Remove Frame Range or Bake Range Markers if they were turned on'''
|
||||
if not getattr(prop, marker_type):
|
||||
return
|
||||
setattr(prop, marker_type, False)
|
||||
for marker_name in names:
|
||||
if marker_name in scene.timeline_markers:
|
||||
scene.timeline_markers.remove(scene.timeline_markers[marker_name])
|
||||
|
||||
dns = bpy.app.driver_namespace
|
||||
if scene.animtoolbox.isolate_pose_mode:
|
||||
if Display.isolate_pose_mode not in bpy.app.handlers.depsgraph_update_pre:
|
||||
bpy.app.handlers.depsgraph_update_pre.append(Display.isolate_pose_mode)
|
||||
|
||||
if scene.emp.motion_path:
|
||||
# In case motion path was active in the last save, make sure atb mp name property
|
||||
# Is not included inside the bones, for a proper cleanup
|
||||
for obj in bpy.context.view_layer.objects:
|
||||
if "atb_mp_name" in obj:
|
||||
del obj["atb_mp_name"]
|
||||
if obj.type == 'ARMATURE':
|
||||
for pbone in obj.pose.bones:
|
||||
if "atb_mp_name" in pbone:
|
||||
del pbone["atb_mp_name"]
|
||||
|
||||
scene.emp.motion_path = False
|
||||
bpy.context.workspace.status_text_set(None)
|
||||
if 'mp_dh' in dns:
|
||||
@@ -424,6 +461,10 @@ def loadanimtoolbox_post(self, context):
|
||||
# Because it is used for undo
|
||||
bpy.context.scene.emp.selected_keyframes = '{}'
|
||||
|
||||
remove_markers(scene.animtoolbox, 'marker_frame_range', {'Frame Start', 'Frame End'})
|
||||
remove_markers(scene.animtoolbox, 'bake_frame_range', {'Bake Start', 'Bake End'})
|
||||
remove_markers(scene.emp, 'marker_frame_range', {'MotionPath Start', 'MotionPath End'})
|
||||
|
||||
Tools.selection_order(self, context)
|
||||
|
||||
classes = (TempCtrlsItems, TempCtrlsOrgIds, TempCtrlsObjectSetups, TempCtrlsSceneSettings,TempCtrlsBoneSettings, MultikeyProperties,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"last_check": "2025-09-23 10:58:29.201165",
|
||||
"backup_date": "September-23-2025",
|
||||
"last_check": "2026-02-09 15:54:54.419194",
|
||||
"backup_date": "February-9-2026",
|
||||
"update_ready": false,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1803,7 +1803,7 @@ def reorder_bones_matrices(bones_matrices, constrained):
|
||||
|
||||
return re_bones_matrices
|
||||
|
||||
def paste_bone_matrix(bone, matrix_copied, constrained, x_filter = True):
|
||||
def paste_bone_matrix(bone, matrix_copied, constrained, bones = {}, x_filter = True):
|
||||
#running again separatly in case the bones are in a hierarchy and influencing each other
|
||||
# for bone, matrix_copied in bones_matrices.items():
|
||||
# Determine whether to use bone.matrix or bone.matrix_world
|
||||
@@ -1818,10 +1818,14 @@ def paste_bone_matrix(bone, matrix_copied, constrained, x_filter = True):
|
||||
if x_filter : matrix_copied = filter_matrix_properties(context, getattr(bone, matrix_attr), matrix_copied)
|
||||
# bone.matrix = bone.id_data.matrix_world.inverted() @ matrix_copied
|
||||
setattr(bone, matrix_attr, matrix_copied) # bone.id_data.matrix_world.inverted() @
|
||||
|
||||
children = set(bone.children_recursive).intersection(bones)
|
||||
if children or bone in constrained:
|
||||
# print(f'found children {[child.name for child in children]} in bone {bone.name}' )
|
||||
context.view_layer.update()
|
||||
#Check if the bone has constrainsts on it that need extra iteration
|
||||
if bone not in constrained:
|
||||
# filter_matrix_properties(context, bone.matrix, matrix_copied)
|
||||
return
|
||||
context.view_layer.update()
|
||||
|
||||
matrix_copied = reverse_bone_constraints(context, bone, matrix_copied)
|
||||
if x_filter : matrix_copied = filter_matrix_properties(context, bone.matrix, matrix_copied)
|
||||
@@ -1832,8 +1836,12 @@ def paste_bone_matrix(bone, matrix_copied, constrained, x_filter = True):
|
||||
|
||||
def paste_bones_matrices(bones_matrices, constrained, x_filter = True):
|
||||
#running again separatly in case the bones are in a hierarchy and influencing each other
|
||||
pasted_bones = set()
|
||||
for bone, matrix_copied in bones_matrices.items():
|
||||
paste_bone_matrix(bone, matrix_copied, constrained, x_filter)
|
||||
#Get the rest of the bones to check if they are children of the current bone
|
||||
bones = set(bones_matrices.keys()).difference(pasted_bones)
|
||||
paste_bone_matrix(bone, matrix_copied, constrained, bones, x_filter)
|
||||
pasted_bones.add(bone)
|
||||
|
||||
class PasteRelativeMatrix(bpy.types.Operator):
|
||||
"""paste the relative matrix of the selection"""
|
||||
@@ -2522,7 +2530,15 @@ class ConvertRotationMode(bpy.types.Operator):
|
||||
# @classmethod
|
||||
# def poll(cls, context):
|
||||
# return context.object.type == 'ARMATURE'
|
||||
|
||||
def switch_rot_mode_keyframes(self, obj, posebone):
|
||||
# Switching any rotation mode keyframes to the new rotation mode value using to_rot_mode_index
|
||||
bone_path = posebone.path_from_id() + '.' if type(posebone) == bpy.types.PoseBone else ''
|
||||
fcurves = get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
fcu_rotation_mode = fcurves.find(data_path = bone_path + 'rotation_mode', index = 0)
|
||||
if fcu_rotation_mode:
|
||||
for keyframe in fcu_rotation_mode.keyframe_points:
|
||||
keyframe.co[1] = self.to_rot_mode_index
|
||||
|
||||
def execute(self, context):
|
||||
scene = context.scene
|
||||
selected_bones = context.selected_pose_bones
|
||||
@@ -2530,7 +2546,8 @@ class ConvertRotationMode(bpy.types.Operator):
|
||||
|
||||
to_rot_mode = scene.animtoolbox.rotation_mode
|
||||
to_rot_mode_fcu = rot_mode_to_channel(to_rot_mode)
|
||||
|
||||
#Getting the index of the rotation mode we want to convert to
|
||||
self.to_rot_mode_index = list(scene.animtoolbox.bl_rna.properties['rotation_mode'].enum_items.keys()).index(to_rot_mode)
|
||||
#get the keyframes from the bones
|
||||
for posebone in selected_bones:
|
||||
|
||||
@@ -2548,16 +2565,21 @@ class ConvertRotationMode(bpy.types.Operator):
|
||||
|
||||
keyframes = emp.get_bone_keyframes(posebone, transform)
|
||||
|
||||
#get all interpolations and handle types of the keyframes
|
||||
handle_types = emp.get_bone_keyframes(posebone, transform, property = 'interpolation')
|
||||
interpolations = handle_types[::3]
|
||||
handle_left_type = handle_types[1::3]
|
||||
handle_right_type = handle_types[2::3]
|
||||
|
||||
# rotation_mode_keyframes = emp.get_bone_keyframes(posebone, 'rotation_mode')
|
||||
self.switch_rot_mode_keyframes(obj, posebone)
|
||||
|
||||
inbetweens = []
|
||||
smartframes = sorted(set(map(lambda x: round(x, 2), keyframes[::2])))
|
||||
inbetweens = add_inbetweens(smartframes)
|
||||
all_frames = sorted(smartframes + inbetweens)
|
||||
#get all interpolations and handle types of the keyframes
|
||||
if len(smartframes) > 1:
|
||||
handle_types = emp.get_bone_keyframes(posebone, transform, property = 'interpolation')
|
||||
interpolations = handle_types[::3]
|
||||
handle_left_type = handle_types[1::3]
|
||||
handle_right_type = handle_types[2::3]
|
||||
|
||||
inbetweens = add_inbetweens(smartframes)
|
||||
|
||||
all_frames = sorted(smartframes + inbetweens)
|
||||
new_path = posebone.path_from_id() + '.' + to_rot_mode_fcu
|
||||
|
||||
#define array length
|
||||
@@ -2632,13 +2654,15 @@ class ConvertRotationMode(bpy.types.Operator):
|
||||
keyframe = new_fcu.keyframe_points[-1]
|
||||
|
||||
keyframe.co = (frame, fcu_keyframes[new_fcu][frame])
|
||||
keyframe.interpolation = interpolations[frame_index]
|
||||
keyframe.handle_left_type = handle_left_type[frame_index]
|
||||
keyframe.handle_right_type = handle_right_type[frame_index]
|
||||
if inbetweens:
|
||||
keyframe.interpolation = interpolations[frame_index]
|
||||
keyframe.handle_left_type = handle_left_type[frame_index]
|
||||
keyframe.handle_right_type = handle_right_type[frame_index]
|
||||
|
||||
new_fcu.update()
|
||||
|
||||
add_interpolations(new_fcurves, fcu_inbetweens)
|
||||
if inbetweens:
|
||||
add_interpolations(new_fcurves, fcu_inbetweens)
|
||||
|
||||
posebone.rotation_mode = to_rot_mode
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
bl_info = {
|
||||
"name": "AnimToolBox",
|
||||
"author": "Tal Hershkovich",
|
||||
"version" : (0, 0, 7, 3),
|
||||
"version" : (0, 0, 8),
|
||||
"blender" : (3, 2, 0),
|
||||
"location": "View3D - Properties - Animation Panel",
|
||||
"description": "A set of animation tools",
|
||||
@@ -133,15 +133,16 @@ class TempCtrlsBoneSettings(bpy.types.PropertyGroup):
|
||||
setup: bpy.props.EnumProperty(name = 'Setup Type', description="Describes what kind of setup the bone is part of", override = {'LIBRARY_OVERRIDABLE'},
|
||||
items = [('NONE', 'No Setup','No Setup Applied', 0),
|
||||
('WORLDSPACE', 'World Space Ctrl','World Space Ctrl setup', 1),
|
||||
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 2),
|
||||
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 3),
|
||||
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 4),
|
||||
('POLE', 'Temporary IK Pole setup','Temporary IK Pole', 5),
|
||||
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 6),
|
||||
('ROOT', 'Root', 'Root Ctrl for all the setups', 7),
|
||||
('EMPTY', 'Root', 'Root Ctrl for all the setups', 8),
|
||||
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 9),
|
||||
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 10)])
|
||||
('WORLDSPACE_CURSOR', 'World Space Cursor Ctrl','World Space Cursor pivot', 2),
|
||||
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 3),
|
||||
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 4),
|
||||
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 5),
|
||||
('POLE', 'Temporary IK Pole setup','Temporary IK Pole', 6),
|
||||
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 7),
|
||||
('ROOT', 'Root', 'Root Ctrl for all the setups', 8),
|
||||
('EMPTY', 'Root', 'Root Ctrl for all the setups', 9),
|
||||
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 10),
|
||||
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 11)])
|
||||
|
||||
#using org mostly to decide if it needs a custom shape
|
||||
org: bpy.props.EnumProperty(name = 'Org Type', description="Describes what if the function of the bone", override = {'LIBRARY_OVERRIDABLE'},
|
||||
@@ -152,21 +153,29 @@ class TempCtrlsBoneSettings(bpy.types.PropertyGroup):
|
||||
|
||||
shape: bpy.props.BoolProperty(name = "Apply shape", description = "Mark if the bone needs a shape", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
class TempCtrlsOrgIds(bpy.types.PropertyGroup):
|
||||
# A collection of the org ids used in each setup. Org ID is the direct connection
|
||||
# between original bones and ctrls
|
||||
pass
|
||||
|
||||
class TempCtrlsObjectSetups(bpy.types.PropertyGroup):
|
||||
#located at obj.animtoolbox.ctrl_setups
|
||||
#name: using string of the id
|
||||
setup: bpy.props.EnumProperty(name = 'Setup Type', description="Describes what kind of setup the bone is part of",
|
||||
items = [('NONE', 'No Setup','No Setup Applied', 0),
|
||||
('WORLDSPACE', 'World Space Ctrl','World Space Ctrl setup', 1),
|
||||
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 2),
|
||||
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 3),
|
||||
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 4),
|
||||
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 5),
|
||||
('ROOT', 'Root', 'Root Ctrl for all the setups', 6),
|
||||
('EMPTY', 'Root', 'Root Ctrl for all the setups', 8),
|
||||
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 9),
|
||||
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 10),
|
||||
])
|
||||
('WORLDSPACE_CURSOR', 'World Space Cursor Ctrl','World Space Cursor pivot', 2),
|
||||
('TEMPFK', 'Temporary FK setup','Temporary FK chain setup', 3),
|
||||
('TEMPFK_FLIP', 'Temporary flipped FK setup','Temporary flipped FK chain setup', 4),
|
||||
('TEMPIK', 'Temporary IK setup','Temporary IK setup', 5),
|
||||
('POLE', 'Temporary IK Pole setup','Temporary IK Pole', 6),
|
||||
('PARENTCTRL', 'Parent Ctrl from cursor setup','Parent Ctrl from cursor setup', 7),
|
||||
('ROOT', 'Root', 'Root Ctrl for all the setups', 8),
|
||||
('EMPTY', 'Root', 'Root Ctrl for all the setups', 9),
|
||||
('TRACK_TO', 'Track To','World Space Track to Ctrl setup', 10),
|
||||
('TRACK_TO_EMPTY', 'Track To Empty','World Space Track to Empty Ctrl setup', 11)])
|
||||
|
||||
org_ids: bpy.props.CollectionProperty(type = TempCtrlsOrgIds)
|
||||
|
||||
class MultikeyProperties(bpy.types.PropertyGroup):
|
||||
|
||||
@@ -238,37 +247,6 @@ class AnimToolBoxGlobalSettings(bpy.types.PropertyGroup):
|
||||
#Blendings
|
||||
inbetweener : bpy.props.FloatProperty(name='Inbetween Keyframe', description="Adds an inbetween Keyframe between the Layer's neighbor keyframes", soft_min = -1, soft_max = 1, default=0.0, options = set(), update = Tools.add_inbetween_key, override = {'LIBRARY_OVERRIDABLE'})
|
||||
|
||||
motion_path: bpy.props.BoolProperty(name = "Motion Path", description = "Flag when Motion Path is on", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_settings: bpy.props.BoolProperty(name = "Motion Path Settings", description = "Open the settings Menu", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_keyframe_scale: bpy.props.FloatProperty(name = "Scale Selecgted Keyframes Bounding Box", description = "Change the scale of the bounding box around the selected keyframes ", default = 0.1, step = 0.1, precision = 3)
|
||||
mp_color_before: bpy.props.FloatVectorProperty(name="Motion Path Before Color", subtype='COLOR', default=(1.0, 0.0, 0.0), min=0.0, max=1.0, description="Motion path color before the current frame")
|
||||
mp_color_after: bpy.props.FloatVectorProperty(name="Motion Path After Color", subtype='COLOR', default=(0.0, 1.0, 0.0), min=0.0, max=1.0, description="Motion path color before the current frame")
|
||||
mp_infront: bpy.props.BoolProperty(name = "Motion Path In Front", description = "Display motion path in front of all the objects", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_points: bpy.props.BoolProperty(name = "Motion Path Points", description = "Display motion path points", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_lines: bpy.props.BoolProperty(name = "Motion Path Lines", description = "Display motion path lines", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_handles: bpy.props.BoolProperty(name = "Motion Path Handles", description = "Display motion path handles on keyframe selection", default = True, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_display_frames: bpy.props.BoolProperty(name = "Frame Numbers", description = "Display frame numbers on all the keyframes", default = False, override = {'LIBRARY_OVERRIDABLE'})
|
||||
mp_handle_types: bpy.props.EnumProperty(name = 'Set Keyframe Handle Type', description="Set handle type for selected keyframes", default = 'AUTO', update = emp.update_handle_type_prop,
|
||||
items = [('FREE', 'Free', 'Free', 'HANDLE_FREE', 0),
|
||||
('ALIGNED','Aligned', 'Aligned', 'HANDLE_ALIGNED', 1),
|
||||
('VECTOR', 'Vector', 'Vector', 'HANDLE_VECTOR', 2),
|
||||
('AUTO','Automatic', 'Automatic', 'HANDLE_AUTO', 3),
|
||||
('AUTO_CLAMPED','Auto Clamped', 'Auto Clamped', 'HANDLE_AUTOCLAMPED', 4)])
|
||||
|
||||
mp_interpolation: bpy.props.EnumProperty(name = 'Set Interpolation', description="Set Keyframe Interpolation", default = 'BEZIER', update = emp.update_interpolation_prop,
|
||||
items = [('BEZIER', 'Bezier', 'Bezier', 'IPO_BEZIER', 0),
|
||||
('LINEAR','Linear', 'Linear', 'IPO_LINEAR', 1),
|
||||
('CONSTANT', 'Constant', 'Constant', 'IPO_CONSTANT', 2)])
|
||||
|
||||
mp_frame_range: bpy.props.EnumProperty(name = 'Frame Range', description="Type of Frame Range", default = 'SCENE', #update = emp.mp_frame_range_update,
|
||||
items = [('KEYS_ALL', 'All_Keys','Use the Scene Frame Length for the Range', 0),
|
||||
('SCENE', 'Scene','Use the Scene Frame Length for the Range', 1),
|
||||
('MANUAL', 'Manual','Custom Frame range using numerical input or the markers frame ranger', 2),
|
||||
('AROUND', 'Around Frames','Show only around the current frame', 3)])
|
||||
mp_before: bpy.props.IntProperty(name = "Before", description = "Show the frames Before the current frame", min = 0, default = 10)
|
||||
mp_after: bpy.props.IntProperty(name = "After", description = "Show the frames After the current frame", min = 0, default = 10)
|
||||
selected_keyframes: bpy.props.StringProperty(name="Selected Keyframes", description="Serialized representation of selected keyframes")
|
||||
|
||||
gizmo_size: bpy.props.IntProperty(name = "Add to Gizmo Size", description = "Addition to Gizmo Size", max = 100, min = -100, default = 10)
|
||||
|
||||
#Copy/Pase Matrix
|
||||
@@ -312,6 +290,13 @@ class AnimToolBoxPreferences(bpy.types.AddonPreferences):
|
||||
|
||||
#Editable motion path
|
||||
keyframes_range: bpy.props.IntProperty(name = "Keyframe Range", description = "The range of distance from the keyframes while hovering over them", min = 5, max = 100, default = 15)
|
||||
mp_pref: bpy.props.BoolProperty(name = "Editable Motion Path Colors Theme", description = "Set the Color them of editable motion path visualization", default = False)
|
||||
mp_keyframe_color: bpy.props.FloatVectorProperty(name="Keyframes", subtype='COLOR', default=(1.0, 1.0, 0.0, 1.0), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_handle_color: bpy.props.FloatVectorProperty(name="Handles", subtype='COLOR', default=(1.0, 0.8, 0.2, 1.0), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_remove_color: bpy.props.FloatVectorProperty(name="Remove Keyframes", subtype='COLOR', default=(0.0, 0.5, 1.0, 1.0), size=4, min=0.0, max=1.0, description="Keyframe color displayed before removing")
|
||||
mp_hover_color: bpy.props.FloatVectorProperty(name="Hover", subtype='COLOR', default=(1.0, 0.4, 0.2, 1.0), size=4, min=0.0, max=1.0, description="Color during Hovering")
|
||||
mp_handle_selection_color: bpy.props.FloatVectorProperty(name="Handles Selection", subtype='COLOR', default=(0.8, 0.65, 0.6, 0.8), size=4, min=0.0, max=1.0, description="Handles selection color")
|
||||
mp_key_selection_color: bpy.props.FloatVectorProperty(name="Keyframe Selection", subtype='COLOR', default=(0.8, 0.8, 0.6, 0.8), size=4, min=0.0, max=1.0, description="Keyframe selection color")
|
||||
|
||||
# addon updater preferences from `__init__`, be sure to copy all of them
|
||||
auto_check_update: bpy.props.BoolProperty(
|
||||
@@ -371,6 +356,22 @@ class AnimToolBoxPreferences(bpy.types.AddonPreferences):
|
||||
row.prop(self, 'clear_setup')
|
||||
row.prop(self, 'in_front')
|
||||
|
||||
layout.separator()
|
||||
box = layout.box()
|
||||
col = box.column()
|
||||
col.prop(self, 'mp_pref', icon = 'DOWNARROW_HLT', text = 'Editable Motion Path Preferences')
|
||||
if self.mp_pref:
|
||||
col.prop(self, 'keyframes_range', text = 'Keyframe Distance Range')
|
||||
col.label(text = 'Colors Theme')
|
||||
row = box.row()
|
||||
row.prop(self, 'mp_keyframe_color')
|
||||
row.prop(self, 'mp_handle_color')
|
||||
row.prop(self, 'mp_remove_color')
|
||||
row = box.row()
|
||||
row.prop(self, 'mp_hover_color')
|
||||
row.prop(self, 'mp_key_selection_color')
|
||||
row.prop(self, 'mp_handle_selection_color')
|
||||
|
||||
layout.separator()
|
||||
col = layout.column()
|
||||
col.label(text = 'Include Extras: ')
|
||||
@@ -385,12 +386,14 @@ def loadanimtoolbox_pre(self, context):
|
||||
if scene.animtoolbox.bake_frame_range:
|
||||
scene.animtoolbox.bake_frame_range = False
|
||||
|
||||
if scene.animtoolbox.motion_path:
|
||||
scene.animtoolbox.motion_path = False
|
||||
if scene.emp.motion_path:
|
||||
scene.emp.motion_path = False
|
||||
bpy.context.workspace.status_text_set(None)
|
||||
if 'mp_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('mp_dh')
|
||||
|
||||
bpy.context.scene.emp.selected_keyframes = '{}'
|
||||
|
||||
if 'markers_retimer_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['markers_retimer_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('markers_retimer_dh')
|
||||
@@ -411,16 +414,20 @@ def loadanimtoolbox_post(self, context):
|
||||
if Display.isolate_pose_mode not in bpy.app.handlers.depsgraph_update_pre:
|
||||
bpy.app.handlers.depsgraph_update_pre.append(Display.isolate_pose_mode)
|
||||
|
||||
if scene.animtoolbox.motion_path:
|
||||
scene.animtoolbox.motion_path = False
|
||||
if scene.emp.motion_path:
|
||||
scene.emp.motion_path = False
|
||||
bpy.context.workspace.status_text_set(None)
|
||||
if 'mp_dh' in dns:
|
||||
bpy.types.SpaceView3D.draw_handler_remove(dns['mp_dh'], 'WINDOW')
|
||||
bpy.app.driver_namespace.pop('mp_dh')
|
||||
# Reset keyframe selection for motion paths it is not used in window manager
|
||||
# Because it is used for undo
|
||||
bpy.context.scene.emp.selected_keyframes = '{}'
|
||||
|
||||
Tools.selection_order(self, context)
|
||||
|
||||
classes = (TempCtrlsItems, TempCtrlsObjectSetups, TempCtrlsSceneSettings,TempCtrlsBoneSettings, MultikeyProperties, IsolatedRigs,
|
||||
AnimToolBoxObjectSettings, AnimToolBoxUILayout, AnimToolBoxGlobalSettings) + ui.classes
|
||||
classes = (TempCtrlsItems, TempCtrlsOrgIds, TempCtrlsObjectSetups, TempCtrlsSceneSettings,TempCtrlsBoneSettings, MultikeyProperties,
|
||||
IsolatedRigs, AnimToolBoxObjectSettings, AnimToolBoxUILayout, AnimToolBoxGlobalSettings) + ui.classes
|
||||
|
||||
addon_keymaps = []
|
||||
|
||||
|
||||
+5
-5
@@ -1,16 +1,16 @@
|
||||
{
|
||||
"last_check": "2025-09-23 10:57:14.918240",
|
||||
"backup_date": "June-19-2025",
|
||||
"last_check": "2026-02-09 15:54:54.419194",
|
||||
"backup_date": "September-23-2025",
|
||||
"update_ready": true,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
"just_updated": false,
|
||||
"version_text": {
|
||||
"link": "https://gitlab.com/api/v4/projects/45739913/repository/archive.zip?sha=cb445f00491a54eb763f0d8e72eaae3e44e7d0ba",
|
||||
"link": "https://gitlab.com/api/v4/projects/45739913/repository/archive.zip?sha=7a9ad24a463bf1c8ae095ec853409979344e0738",
|
||||
"version": [
|
||||
0,
|
||||
0,
|
||||
8
|
||||
2,
|
||||
3
|
||||
]
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
@@ -46,7 +46,7 @@ def attr_default(obj, fcu_key):
|
||||
if attr not in obj.data.shape_keys.key_blocks:
|
||||
return [0]
|
||||
shapekey = obj.data.shape_keys.key_blocks[attr]
|
||||
return 0 if shapekey.slider_min <= 0 else shapekey.slider_min
|
||||
return [0] if shapekey.slider_min <= 0 else shapekey.slider_min
|
||||
#in case of transforms in object mode
|
||||
else:# fcu_key[0] in transform_types:
|
||||
source = obj
|
||||
@@ -273,6 +273,9 @@ def random_value(self, context):
|
||||
for key in fcu.keyframe_points:
|
||||
add_value(key, value * random.uniform(-threshold, threshold))
|
||||
fcu.update()
|
||||
|
||||
self['randomness'] = 0.1
|
||||
|
||||
|
||||
def evaluate_combine(data_path, added_array, eval_array, array_default, influence):
|
||||
|
||||
@@ -293,23 +296,17 @@ def evaluate_array(fcurves, fcu_path, frame, array_default = [0, 0, 0]):
|
||||
'''Create an array from all the indexes'''
|
||||
|
||||
array_len = len(array_default)
|
||||
fcu_array = []
|
||||
|
||||
#assigning the default array in case
|
||||
fcu_array = array_default.copy()
|
||||
#get the missing arrays in case quaternion is not complete
|
||||
missing_arrays = []
|
||||
for i in range(array_len):
|
||||
fcu = fcurves.find(fcu_path, index = i)
|
||||
if fcu is None:
|
||||
missing_arrays.append(i)
|
||||
continue
|
||||
fcu_array[i] = fcu.evaluate(frame)
|
||||
|
||||
fcu_array.append(fcu.evaluate(frame))
|
||||
|
||||
#In case it's a quaternion and missing attributes, then adding from default value
|
||||
if fcu_array and array_len == 4 and missing_arrays:
|
||||
for i in missing_arrays:
|
||||
fcu_array.insert(i, array_default[i])
|
||||
|
||||
if not len(fcu_array):
|
||||
if (fcu_array == array_default).all():
|
||||
return None
|
||||
return np.array(fcu_array)
|
||||
|
||||
@@ -325,7 +322,7 @@ def evaluate_layers(context, obj, anim_data, fcu, array_default):
|
||||
blend_types = {'ADD' : '+', 'SUBTRACT' : '-', 'MULTIPLY' : '*'}
|
||||
fcu_path = fcu.data_path
|
||||
|
||||
eval_array = array_default
|
||||
eval_array = array_default.copy()
|
||||
|
||||
for track in nla_tracks:
|
||||
if track.mute:
|
||||
@@ -373,6 +370,7 @@ def evaluate_layers(context, obj, anim_data, fcu, array_default):
|
||||
tweak_mode = anim_data.use_tweak_mode
|
||||
if tweak_mode:
|
||||
anim_data.use_tweak_mode = False
|
||||
|
||||
action = anim_data.action
|
||||
if action:
|
||||
influence = anim_data.action_influence
|
||||
@@ -425,6 +423,7 @@ def evaluate_value(self, context):
|
||||
for fcu in fcurves:
|
||||
if fcu in fcu_paths:
|
||||
continue
|
||||
current_value = None
|
||||
if Tools.filter_properties(context.scene.animtoolbox, fcu):
|
||||
continue
|
||||
if obj.mode == 'POSE':
|
||||
@@ -447,10 +446,11 @@ def evaluate_value(self, context):
|
||||
else:
|
||||
transform = fcu.data_path
|
||||
current_value = getattr(obj, transform)
|
||||
|
||||
#In case it was completly filtered out and not current value available
|
||||
if not current_value:
|
||||
continue
|
||||
|
||||
array_default = np.array(attr_default(obj, (fcu.data_path, fcu.array_index)))
|
||||
# array_default = np.array([attr_default(obj, (fcu.data_path, i)) for i in range(4)
|
||||
# if fcurves.find(fcu.data_path, index = i) is not None])
|
||||
eval_array = evaluate_layers(context, obj, anim_data, fcu, array_default)
|
||||
if eval_array is None:
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
|
||||
@@ -63,6 +63,7 @@ class ANIMTOOLBOX_MT_Temp_Ctrls(bpy.types.Menu):
|
||||
layout = self.layout
|
||||
custom_icons = preview_collections["main"]
|
||||
layout.operator('anim.bake_to_ctrl', text="World Space Ctrls", icon = 'WORLD')
|
||||
# layout.operator('anim.worldspace_cursor', text="World Space Cursor Ctrls", icon ='ORIENTATION_CURSOR')
|
||||
layout.operator('anim.bake_to_temp_fk', text="Temp FK Ctrls", icon = 'BONE_DATA')
|
||||
layout.operator('anim.bake_to_temp_ik', text="Temp IK Ctrls", icon = 'CON_KINEMATIC')
|
||||
layout.separator()
|
||||
@@ -163,7 +164,7 @@ class ANIMTOOLBOX_MT_operators(bpy.types.Menu):
|
||||
layout.separator(factor = 0.5)
|
||||
layout.operator('anim.switch_collections_visibility', icon = 'COLLECTION_COLOR_06', text = 'Animated Collections Visibilty')
|
||||
layout.operator('anim.isolate_pose_mode', icon_value = custom_icons["isolate"].icon_id, depress = scene.animtoolbox.isolate_pose_mode)
|
||||
layout.operator('object.motion_path_operator', text = 'Editable Motion Path', depress = scene.animtoolbox.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
layout.operator('object.motion_path_operator', text = 'Editable Motion Path', depress = scene.emp.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
layout.separator()
|
||||
layout.prop(context.preferences.addons[__package__].preferences, 'quick_menu', text = 'Use Quick Icons Menu')
|
||||
# layout.prop(context.window_manager.atb_ui, 'quick_menu', text = 'Use Quick Icons Menu')
|
||||
@@ -257,7 +258,10 @@ class TEMPCTRLS_PT_Panel(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
layout = self.layout
|
||||
box = layout.box()
|
||||
col = box.column()
|
||||
col.operator('anim.bake_to_ctrl', text="WorldSpace Ctrls", icon ='WORLD') #
|
||||
row = col.row()
|
||||
row.operator('anim.bake_to_ctrl', text="WorldSpace Ctrls", icon ='WORLD') #
|
||||
row.operator('anim.add_empty_ctrl', text="", icon ='EMPTY_AXIS')
|
||||
# col.operator('anim.worldspace_cursor', text="WorldSpace Cursor Ctrls", icon ='ORIENTATION_CURSOR')
|
||||
col.operator('anim.bake_to_temp_fk', text="Temp FK Ctrls", icon = 'BONE_DATA')
|
||||
col.operator('anim.bake_to_temp_ik', text="Temp IK Ctrls", icon = 'CON_KINEMATIC')
|
||||
|
||||
@@ -540,44 +544,65 @@ class ANIMTOOLBOX_PT_Display(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
|
||||
box = layout.box()
|
||||
row = box.row()
|
||||
row.operator('object.motion_path_operator', text = 'Editable Motion Path', depress = scene.animtoolbox.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
row.prop(scene.animtoolbox, 'mp_settings', text = '', icon = 'SETTINGS')
|
||||
if scene.animtoolbox.mp_settings:
|
||||
row = box.row()
|
||||
row.prop(scene.animtoolbox, 'mp_color_before', text = '')
|
||||
row.prop(scene.animtoolbox, 'mp_color_after', text = '')
|
||||
row = box.row()
|
||||
row.prop(scene.animtoolbox, 'mp_keyframe_scale', text = 'Scale Keyframes Box', icon = 'CUBE')
|
||||
row = box.row()
|
||||
row.prop(scene.animtoolbox, 'mp_points', text = 'Points')
|
||||
row.prop(scene.animtoolbox, 'mp_lines', text = 'Lines')
|
||||
row = box.row()
|
||||
row.prop(scene.animtoolbox, 'mp_handles', text = 'Handles')
|
||||
row.prop(scene.animtoolbox, 'mp_infront', text = 'In Front')
|
||||
row = box.row()
|
||||
row.prop(scene.animtoolbox, 'mp_display_frames', text = 'Display Keyframe Numbers')
|
||||
row = box.row()
|
||||
row.prop(context.preferences.addons[__package__].preferences, 'keyframes_range', text = 'Keyframe Distance Range')
|
||||
if context.object is None:
|
||||
return
|
||||
|
||||
row.operator('object.motion_path_operator', text = 'Editable Motion Path', depress = scene.emp.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
emp = scene.emp
|
||||
row.prop(scene.emp, 'settings', text = '', icon = 'SETTINGS')
|
||||
if scene.emp.settings:
|
||||
|
||||
split = box.split(factor = 0.4)
|
||||
split.label(text ='Frame Range')
|
||||
# row.prop(scene.animtoolbox, 'mp_frame_range', text = '')
|
||||
|
||||
split.prop(context.scene.animtoolbox, 'mp_frame_range', text = '')
|
||||
if context.scene.animtoolbox.mp_frame_range == 'MANUAL':
|
||||
split.prop(emp, 'frame_range', text = '')
|
||||
if emp.frame_range == 'MANUAL':
|
||||
row = box.row()
|
||||
row.prop(context.scene.animtoolbox, 'bake_frame_start', text = 'Start')
|
||||
row.prop(context.scene.animtoolbox, 'bake_frame_end', text = 'End')
|
||||
row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = scene.animtoolbox.bake_frame_range)
|
||||
|
||||
elif context.scene.animtoolbox.mp_frame_range == 'AROUND':
|
||||
row = box.row()
|
||||
row.prop(context.scene.animtoolbox, 'mp_before', text = 'Before')
|
||||
row.prop(context.scene.animtoolbox, 'mp_after', text = 'After')
|
||||
row.prop(emp, 'frame_start', text = 'Start')
|
||||
row.prop(emp, 'frame_end', text = 'End')
|
||||
# row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = scene.animtoolbox.bake_frame_range)
|
||||
|
||||
elif emp.frame_range == 'AROUND':
|
||||
row = box.row()
|
||||
row.prop(emp, 'before', text = 'Before')
|
||||
row.prop(emp, 'after', text = 'After')
|
||||
|
||||
box.separator(factor = 0.1)
|
||||
col = box.column()
|
||||
col.prop(emp, 'display_size', icon = 'DOWNARROW_HLT')
|
||||
if emp.display_size:
|
||||
col.prop(emp, 'thickness', text = 'Line Thickness')
|
||||
col.prop(emp, 'keyframe_size', text = 'Keyframes Size')
|
||||
col.prop(emp, 'frame_size', text = 'Frames Size')
|
||||
|
||||
box.separator(factor = 0.1)
|
||||
row = box.row()
|
||||
row.label(text = 'Visualization Type')
|
||||
row.prop(emp, 'vis_type', text = '')
|
||||
if emp.vis_type == 'VELOCITY':
|
||||
row = box.row()
|
||||
row.prop(emp, 'velocity_factor', text = '')
|
||||
row.prop(emp, 'clamp_min', text = '')
|
||||
row.prop(emp, 'clamp_max', text = '')
|
||||
|
||||
row = box.row()
|
||||
row.prop(emp, 'color_before', text = '')
|
||||
row.prop(emp, 'color_after', text = '')
|
||||
|
||||
row = box.row()
|
||||
row.prop(emp, 'points', text = 'Points')
|
||||
row.prop(emp, 'lines', text = 'Lines')
|
||||
row = box.row()
|
||||
row.prop(emp, 'handles', text = 'Handles')
|
||||
row.prop(emp, 'infront', text = 'In Front')
|
||||
row = box.row()
|
||||
row.prop(emp, 'display_frames', text = 'Display Keyframe Numbers')
|
||||
row.separator()
|
||||
row = box.row()
|
||||
row.operator('anim.go_to_keyframe')
|
||||
# row = box.row()
|
||||
# row.prop(context.preferences.addons[__package__].preferences, 'keyframes_range', text = 'Keyframe Distance Range')
|
||||
# if context.object is None:
|
||||
# return
|
||||
# row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = scene.animtoolbox.bake_frame_range)
|
||||
|
||||
class RIGGERTOOLBOX_PT_Panel(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
bl_label = "Rigger Toolbox"
|
||||
@@ -697,4 +722,4 @@ def draw_menu(self, context):
|
||||
layout.operator('anim.isolate_pose_mode', text = '', depress = scene.animtoolbox.isolate_pose_mode, icon_value = custom_icons["isolate"].icon_id)
|
||||
|
||||
layout.separator()
|
||||
layout.operator('object.motion_path_operator', text = '', depress = scene.animtoolbox.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
layout.operator('object.motion_path_operator', text = '', depress = scene.emp.motion_path, icon_value = custom_icons["mt"].icon_id)
|
||||
Binary file not shown.
+1964
-664
File diff suppressed because it is too large
Load Diff
@@ -124,7 +124,9 @@ def add_value(key, value):
|
||||
apply_handles(key, handle_r, handle_l)
|
||||
|
||||
#calculate the difference between current value and the fcurve value
|
||||
def add_diff(fcurves, path, current_value, eval_array):
|
||||
def add_diff(fcurves, path, current_value, eval_array):
|
||||
if eval_array is None:
|
||||
return
|
||||
array_value = current_value - eval_array
|
||||
if not any(array_value):
|
||||
return
|
||||
@@ -160,7 +162,7 @@ class ScaleValuesOp(bpy.types.Operator):
|
||||
for obj in context.selected_objects:
|
||||
if obj.animation_data.action is None:
|
||||
continue
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
fcurves = Tools.get_fcurves(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
if obj.mode == 'POSE':
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
@@ -255,7 +257,7 @@ def random_value(self, context):
|
||||
for obj in context.selected_objects:
|
||||
if obj.animation_data.action is None:
|
||||
continue
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, obj.animation_data.action)
|
||||
fcurves = Tools.get_fcurves(obj, obj.animation_data.action)
|
||||
for fcu in fcurves:
|
||||
if obj.mode == 'POSE':
|
||||
if selected_bones_filter(obj, fcu.data_path):
|
||||
@@ -306,8 +308,8 @@ def evaluate_array(fcurves, fcu_path, frame, array_default = [0, 0, 0]):
|
||||
continue
|
||||
fcu_array[i] = fcu.evaluate(frame)
|
||||
|
||||
if (fcu_array == array_default).all():
|
||||
return None
|
||||
# if (fcu_array == array_default).all():
|
||||
# return None
|
||||
return np.array(fcu_array)
|
||||
|
||||
def evaluate_layers(context, obj, anim_data, fcu, array_default):
|
||||
@@ -363,7 +365,7 @@ def evaluate_layers(context, obj, anim_data, fcu, array_default):
|
||||
frame_eval = last_frame - (frame_eval - strip.frame_start)
|
||||
offset = (strip.frame_start * 1/strip.scale - strip.action_frame_start) * strip.scale
|
||||
frame_eval = strip.frame_start * 1/strip.scale + (frame_eval - strip.frame_start) * 1/strip.scale - offset * 1/strip.scale
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
fcurves = Tools.get_fcurves(obj, action)
|
||||
eval_array = evaluate_blend_type(fcurves, eval_array, fcu_path, frame_eval, influence, array_default, blend_type, blend_types)
|
||||
|
||||
#Adding an extra layer from the action outside and on top of the nla
|
||||
@@ -376,7 +378,7 @@ def evaluate_layers(context, obj, anim_data, fcu, array_default):
|
||||
influence = anim_data.action_influence
|
||||
blend_type = anim_data.action_blend_type
|
||||
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
fcurves = Tools.get_fcurves(obj, action)
|
||||
eval_array = evaluate_blend_type(fcurves, eval_array, fcu_path, frame, influence, array_default, blend_type, blend_types)
|
||||
anim_data.use_tweak_mode = tweak_mode
|
||||
|
||||
@@ -419,7 +421,7 @@ def evaluate_value(self, context):
|
||||
if obj.mode == 'POSE':
|
||||
bonelist = context.selected_pose_bones if ui.multikey.selectedbones else obj.pose.bones
|
||||
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
fcurves = Tools.get_fcurves(obj, action)
|
||||
for fcu in fcurves:
|
||||
if fcu in fcu_paths:
|
||||
continue
|
||||
@@ -453,7 +455,7 @@ def evaluate_value(self, context):
|
||||
array_default = np.array(attr_default(obj, (fcu.data_path, fcu.array_index)))
|
||||
eval_array = evaluate_layers(context, obj, anim_data, fcu, array_default)
|
||||
if eval_array is None:
|
||||
fcurves = Tools.get_fcurves_channelbag(obj, action)
|
||||
# fcurves = Tools.get_fcurves(obj, action)
|
||||
eval_array = evaluate_array(fcurves, fcu.data_path, context.scene.frame_current, array_default)
|
||||
|
||||
#calculate the difference between current value and the fcurve value
|
||||
|
||||
@@ -558,7 +558,7 @@ class ANIMTOOLBOX_PT_Display(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
row = box.row()
|
||||
row.prop(emp, 'frame_start', text = 'Start')
|
||||
row.prop(emp, 'frame_end', text = 'End')
|
||||
# row.operator("anim.markers_bakerange", icon = 'MARKER', text ='', depress = scene.animtoolbox.bake_frame_range)
|
||||
row.operator("anim.emp_markers_range", icon = 'MARKER', text ='', depress = scene.emp.marker_frame_range)
|
||||
|
||||
elif emp.frame_range == 'AROUND':
|
||||
row = box.row()
|
||||
@@ -596,8 +596,33 @@ class ANIMTOOLBOX_PT_Display(ANIMTOOLBOX_PT_Panel, bpy.types.Panel):
|
||||
row = box.row()
|
||||
row.prop(emp, 'display_frames', text = 'Display Keyframe Numbers')
|
||||
row.separator()
|
||||
box = layout.box()
|
||||
split = box.split(factor = 0.35)
|
||||
split.label(text = 'Channels')
|
||||
split.prop(emp, 'channels', text ='')
|
||||
row = box.row()
|
||||
row.operator('anim.go_to_keyframe')
|
||||
if bpy.app.version >= (4, 2, 0):
|
||||
row.prop(emp, 'camera_space', icon = 'CON_CAMERASOLVER')
|
||||
#row = box.row()
|
||||
row.prop(emp, 'cursor_offset', icon = 'PIVOT_CURSOR')
|
||||
box.separator(factor = 0.05)
|
||||
row = box.row()
|
||||
row.operator('anim.go_to_keyframe', icon = 'NEXT_KEYFRAME')
|
||||
box.separator(factor = 0.05)
|
||||
# split = box.split(factor = 0.75)
|
||||
row = box.row()
|
||||
row.prop(emp, 'select_circle', text = 'Selection Brush', icon = 'MESH_CIRCLE')
|
||||
row = box.row()
|
||||
prop_edit_icon = 'PROP_ON' if emp.prop_edit else 'PROP_OFF'
|
||||
row.prop(emp, 'prop_edit', text = 'Proportional Editing', icon = prop_edit_icon)
|
||||
row.prop(emp, 'smooth', text = 'Smooth', icon = 'MOD_SMOOTH')
|
||||
row = box.row()
|
||||
if emp.prop_edit:
|
||||
row.prop(emp, 'prop_edit_falloff', text = '')
|
||||
row.prop(emp, 'radius', text = '')
|
||||
elif emp.smooth:
|
||||
row.prop(emp, 'smooth_strength', text = '')
|
||||
row.prop(emp, 'radius', text = '')
|
||||
# row = box.row()
|
||||
# row.prop(context.preferences.addons[__package__].preferences, 'keyframes_range', text = 'Keyframe Distance Range')
|
||||
# if context.object is None:
|
||||
|
||||
Binary file not shown.
+4
-4
@@ -1,17 +1,17 @@
|
||||
{
|
||||
"last_check": "2025-12-30 14:52:43.839129",
|
||||
"backup_date": "December-15-2025",
|
||||
"last_check": "2026-01-09 16:23:22.382598",
|
||||
"backup_date": "December-30-2025",
|
||||
"update_ready": true,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
"just_updated": false,
|
||||
"version_text": {
|
||||
"link": "https://api.github.com/repos/soupday/cc_blender_tools/zipball/refs/tags/2_3_4_p0",
|
||||
"link": "https://api.github.com/repos/soupday/cc_blender_tools/zipball/refs/tags/2_3_4_p1",
|
||||
"version": [
|
||||
2,
|
||||
3,
|
||||
4,
|
||||
0
|
||||
1
|
||||
]
|
||||
}
|
||||
}
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"last_check": "2025-12-30 14:52:43.839129",
|
||||
"backup_date": "December-30-2025",
|
||||
"last_check": "2026-01-09 16:23:22.382598",
|
||||
"backup_date": "January-9-2026",
|
||||
"update_ready": false,
|
||||
"ignore": false,
|
||||
"just_restored": false,
|
||||
|
||||
BIN
Binary file not shown.
@@ -1720,12 +1720,15 @@ class CC3Import(bpy.types.Operator):
|
||||
elif self.param == "BUILD" or self.param == "BUILD_REBUILD":
|
||||
chr_cache = props.get_context_character_cache(context)
|
||||
if chr_cache:
|
||||
bm = props.build_mode
|
||||
props.build_mode = "IMPORTED"
|
||||
mode_selection = utils.store_mode_selection_state()
|
||||
utils.object_mode()
|
||||
self.build_materials(context)
|
||||
self.build_drivers(context)
|
||||
self.do_import_report(context, stage = 1)
|
||||
utils.restore_mode_selection_state(mode_selection)
|
||||
props.build_mode = bm
|
||||
|
||||
elif self.param == "BUILD_DRIVERS":
|
||||
chr_cache = props.get_context_character_cache(context)
|
||||
@@ -1764,32 +1767,41 @@ class CC3Import(bpy.types.Operator):
|
||||
if chr_cache:
|
||||
utils.object_mode()
|
||||
if chr_cache.get_render_target() != "EEVEE":
|
||||
bm = props.build_mode
|
||||
props.build_mode = "IMPORTED"
|
||||
prefs.refractive_eyes = "PARALLAX"
|
||||
utils.log_info("Character is currently build for Cycles Rendering.")
|
||||
utils.log_info("Rebuilding Character for Eevee Rendering...")
|
||||
self.build_materials(context, render_target="EEVEE")
|
||||
self.build_drivers(context)
|
||||
props.build_mode = bm
|
||||
|
||||
elif self.param == "REBUILD_BAKE":
|
||||
chr_cache = props.get_context_character_cache(context)
|
||||
if chr_cache:
|
||||
utils.object_mode()
|
||||
props.wrinkle_mode = False
|
||||
bm = props.build_mode
|
||||
props.build_mode = "IMPORTED"
|
||||
prefs.refractive_eyes = "PARALLAX"
|
||||
utils.log_info("Rebuilding Character for Eevee Bake...")
|
||||
self.build_materials(context, render_target="EEVEE")
|
||||
self.build_drivers(context)
|
||||
props.build_mode = bm
|
||||
|
||||
elif self.param == "REBUILD_CYCLES":
|
||||
chr_cache = props.get_context_character_cache(context)
|
||||
if chr_cache:
|
||||
utils.object_mode()
|
||||
prefs.refractive_eyes = "SSR"
|
||||
if chr_cache.get_render_target() != "CYCLES":
|
||||
bm = props.build_mode
|
||||
props.build_mode = "IMPORTED"
|
||||
prefs.refractive_eyes = "SSR"
|
||||
utils.log_info("Character is currently build for Eevee Rendering.")
|
||||
utils.log_info("Rebuilding Character for Cycles Rendering...")
|
||||
self.build_materials(context, render_target="CYCLES")
|
||||
self.build_drivers(context)
|
||||
props.build_mode = bm
|
||||
|
||||
return {"FINISHED"}
|
||||
|
||||
|
||||
@@ -3869,7 +3869,9 @@ class LinkService():
|
||||
# generate new action set data
|
||||
set_id, set_generation = rigutils.generate_motion_set(actor_rig, motion_id, LINK_DATA.motion_prefix)
|
||||
remove_actions = []
|
||||
action_pairs = []
|
||||
if actor_rig:
|
||||
|
||||
if actor.get_type() == "PROP":
|
||||
# if it's a prop retarget the animation (or copy the rest pose):
|
||||
# props have no bind pose so the rest pose is the first frame of
|
||||
@@ -3888,6 +3890,7 @@ class LinkService():
|
||||
rigutils.copy_rest_pose(motion_rig, actor_rig)
|
||||
utils.safe_set_action(actor_rig, motion_rig_action)
|
||||
rigutils.update_prop_rig(actor_rig)
|
||||
|
||||
else: # Avatar
|
||||
if chr_cache.rigified:
|
||||
update_link_status(f"Retargeting Motion...")
|
||||
@@ -3897,11 +3900,14 @@ class LinkService():
|
||||
rigutils.set_armature_action_name(armature_action, actor_rig_id, motion_id, LINK_DATA.motion_prefix)
|
||||
remove_actions.append(motion_rig_action)
|
||||
else:
|
||||
actor_rig_action = utils.safe_get_action(actor_rig)
|
||||
rigutils.add_motion_set_data(motion_rig_action, set_id, set_generation, rl_arm_id=rl_arm_id)
|
||||
rigutils.set_armature_action_name(motion_rig_action, actor_rig_id, motion_id, LINK_DATA.motion_prefix)
|
||||
motion_rig_action.use_fake_user = LINK_DATA.use_fake_user
|
||||
utils.safe_set_action(actor_rig, motion_rig_action)
|
||||
action_pairs.append((actor_rig_action, motion_rig_action))
|
||||
rigutils.update_avatar_rig(actor_rig)
|
||||
|
||||
# assign motion object shape key actions:
|
||||
key_actions = rigutils.apply_source_key_actions(actor_rig,
|
||||
source_actions, copy=True,
|
||||
@@ -3909,11 +3915,12 @@ class LinkService():
|
||||
motion_prefix=LINK_DATA.motion_prefix,
|
||||
all_matching=True,
|
||||
set_id=set_id, set_generation=set_generation)
|
||||
for action in key_actions.values():
|
||||
actions = [ p[0] for p in key_actions.values() ]
|
||||
for action in actions:
|
||||
action.use_fake_user = LINK_DATA.use_fake_user
|
||||
# remove unused motion key actions
|
||||
for obj_action in source_actions["keys"].values():
|
||||
if obj_action not in key_actions.values():
|
||||
if obj_action not in actions:
|
||||
remove_actions.append(obj_action)
|
||||
# delete imported motion rig and objects
|
||||
for obj in motion_objects:
|
||||
|
||||
@@ -21,7 +21,7 @@ import bpy
|
||||
from . import imageutils, jsonutils, nodeutils, utils, params, vars
|
||||
|
||||
|
||||
def detect_skin_material(mat):
|
||||
def detect_skin_material_name(mat):
|
||||
name = mat.name.lower()
|
||||
if "std_skin_" in name or "ga_skin_" in name:
|
||||
return True
|
||||
@@ -67,7 +67,7 @@ def detect_key_words(hints, text):
|
||||
return "False"
|
||||
|
||||
|
||||
def detect_scalp_material(mat):
|
||||
def detect_scalp_material_name(mat):
|
||||
prefs = vars.prefs()
|
||||
material_name = mat.name.lower()
|
||||
hints = prefs.hair_scalp_hint.split(",")
|
||||
@@ -79,14 +79,14 @@ def detect_scalp_material(mat):
|
||||
return detect
|
||||
|
||||
|
||||
def detect_eyelash_material(mat):
|
||||
def detect_eyelash_material_name(mat):
|
||||
name = mat.name.lower()
|
||||
if "std_eyelash" in name or "ga_eyelash" in name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def detect_teeth_material(mat):
|
||||
def detect_teeth_material_name(mat):
|
||||
name = mat.name.lower()
|
||||
if "std_upper_teeth" in name:
|
||||
return True
|
||||
@@ -95,21 +95,21 @@ def detect_teeth_material(mat):
|
||||
return False
|
||||
|
||||
|
||||
def detect_tongue_material(mat):
|
||||
def detect_tongue_material_name(mat):
|
||||
name = mat.name.lower()
|
||||
if "std_tongue" in name or "ga_tongue" in name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def detect_nails_material(mat):
|
||||
def detect_nails_material_name(mat):
|
||||
name = mat.name.lower()
|
||||
if "std_nails" in name or "ga_nails" in name:
|
||||
return True
|
||||
return False
|
||||
|
||||
|
||||
def detect_body_object(chr_cache, obj):
|
||||
def detect_body_object_name(obj):
|
||||
name = obj.name.lower()
|
||||
if "base_body" in name or "game_body" in name:
|
||||
return True
|
||||
@@ -282,16 +282,16 @@ def detect_materials_by_name(chr_cache, obj, mat):
|
||||
|
||||
if detect_hair_object(obj, tex_dirs, chr_cache.get_import_dir()) == "True":
|
||||
object_type = "HAIR"
|
||||
if detect_scalp_material(mat) == "True":
|
||||
if detect_scalp_material_name(mat) == "True":
|
||||
material_type = "SCALP"
|
||||
elif detect_hair_material(obj, mat, tex_dirs, chr_cache.get_import_dir()) == "Deny":
|
||||
material_type = "DEFAULT"
|
||||
else:
|
||||
material_type = "HAIR"
|
||||
|
||||
elif detect_body_object(chr_cache, obj):
|
||||
elif detect_body_object_name(obj):
|
||||
object_type = "BODY"
|
||||
if detect_skin_material(mat):
|
||||
if detect_skin_material_name(mat):
|
||||
if "head" in mat_name:
|
||||
material_type = "SKIN_HEAD"
|
||||
elif "body" in mat_name:
|
||||
@@ -300,9 +300,9 @@ def detect_materials_by_name(chr_cache, obj, mat):
|
||||
material_type = "SKIN_ARM"
|
||||
elif "leg" in mat_name:
|
||||
material_type = "SKIN_LEG"
|
||||
elif detect_nails_material(mat):
|
||||
elif detect_nails_material_name(mat):
|
||||
material_type = "NAILS"
|
||||
elif detect_eyelash_material(mat):
|
||||
elif detect_eyelash_material_name(mat):
|
||||
material_type = "EYELASH"
|
||||
|
||||
elif detect_cornea_material(mat):
|
||||
@@ -333,14 +333,14 @@ def detect_materials_by_name(chr_cache, obj, mat):
|
||||
else:
|
||||
material_type = "TEARLINE_RIGHT"
|
||||
|
||||
elif detect_teeth_material(mat):
|
||||
elif detect_teeth_material_name(mat):
|
||||
object_type = "TEETH"
|
||||
if detect_material_side(mat, "UPPER"):
|
||||
material_type = "TEETH_UPPER"
|
||||
else:
|
||||
material_type = "TEETH_LOWER"
|
||||
|
||||
elif detect_tongue_material(mat):
|
||||
elif detect_tongue_material_name(mat):
|
||||
object_type = "TONGUE"
|
||||
material_type = "TONGUE"
|
||||
|
||||
@@ -368,12 +368,12 @@ def detect_materials_from_json(chr_cache, obj, mat, obj_json, mat_json):
|
||||
object_type = "HAIR"
|
||||
if detect_hair_material(obj, mat, tex_dirs, chr_cache.get_import_dir(), mat_json) == "True":
|
||||
material_type = "HAIR"
|
||||
elif detect_scalp_material(mat) == "True":
|
||||
elif detect_scalp_material_name(mat) == "True":
|
||||
material_type = "SCALP"
|
||||
else:
|
||||
material_type = "DEFAULT"
|
||||
|
||||
elif detect_eyelash_material(mat):
|
||||
elif detect_eyelash_material_name(mat):
|
||||
object_type = "BODY"
|
||||
material_type = "EYELASH"
|
||||
|
||||
@@ -402,7 +402,7 @@ def detect_materials_from_json(chr_cache, obj, mat, obj_json, mat_json):
|
||||
material_type = "SKIN_ARM"
|
||||
elif "leg" in mat_name:
|
||||
material_type = "SKIN_LEG"
|
||||
elif detect_nails_material(mat):
|
||||
elif detect_nails_material_name(mat):
|
||||
material_type = "NAILS"
|
||||
|
||||
elif shader == "RLHead":
|
||||
@@ -459,7 +459,12 @@ def detect_materials_from_json(chr_cache, obj, mat, obj_json, mat_json):
|
||||
object_type = "DEFAULT"
|
||||
material_type = "DEFAULT"
|
||||
|
||||
utils.log_info(f"Material: {mat_name} detected from Json data as: {material_type}")
|
||||
# final check for body
|
||||
if object_type == "DEFAULT" and material_type == "DEFAULT":
|
||||
if detect_body_object_name(obj) and detect_skin_material_name(mat):
|
||||
object_type = "BODY"
|
||||
|
||||
utils.log_info(f"Material: {obj.name}/{mat_name} detected from Json data as: {object_type}/{material_type}")
|
||||
return object_type, material_type
|
||||
|
||||
|
||||
|
||||
@@ -1364,9 +1364,9 @@ SHADER_MATRIX = [
|
||||
# modifier properties:
|
||||
# [prop_name, material_type, modifier_type, modifier_id, expression]
|
||||
"modifiers": [
|
||||
[ "eye_iris_depth", "EYE_RIGHT", "DISPLACE", "Eye_Displace_R", "mod.strength = 1.5 * parameters.eye_iris_depth"],
|
||||
[ "eye_iris_depth", "EYE_RIGHT", "DISPLACE", "Eye_Displace_R", "mod.strength = 1.0 * parameters.eye_iris_depth"],
|
||||
[ "eye_pupil_scale", "EYE_RIGHT", "UV_WARP", "Eye_UV_Warp_R", "mod.scale = (1.0 / parameters.eye_pupil_scale, 1.0 / parameters.eye_pupil_scale)" ],
|
||||
[ "eye_iris_depth", "EYE_LEFT", "DISPLACE", "Eye_Displace_L", "mod.strength = 1.5 * parameters.eye_iris_depth"],
|
||||
[ "eye_iris_depth", "EYE_LEFT", "DISPLACE", "Eye_Displace_L", "mod.strength = 1.0 * parameters.eye_iris_depth"],
|
||||
[ "eye_pupil_scale", "EYE_LEFT", "UV_WARP", "Eye_UV_Warp_L", "mod.scale = (1.0 / parameters.eye_pupil_scale, 1.0 / parameters.eye_pupil_scale)" ],
|
||||
],
|
||||
# material setting properties:
|
||||
@@ -1391,7 +1391,7 @@ SHADER_MATRIX = [
|
||||
"mapping": [
|
||||
["DIFFUSE", "Sclera Scale", "", "eye_sclera_scale"],
|
||||
["DIFFUSE", "Iris Radius", "", "eye_iris_radius"],
|
||||
["DIFFUSE", "Pupil Scale", "", "eye_pupil_scale"],
|
||||
["DIFFUSE", "Pupil Scale", "func_set_parallax_pupil_scale", "eye_pupil_scale"],
|
||||
["DIFFUSE", "Depth", "func_set_parallax_iris_depth", "eye_iris_depth"],
|
||||
["DIFFUSE", "IOR", "", "eye_ior"],
|
||||
["SCLERA", "Invert", "func_eye_invert", "eye_is_left_eye"],
|
||||
|
||||
@@ -552,7 +552,7 @@ class CC3ToolsAddonPreferences(bpy.types.AddonPreferences):
|
||||
("LOCAL","Local Machine","Connect to a DataLink server running on the local machine"),
|
||||
("REMOTE","Remote Host","Connect to a DataLink server running on a remote machine"),
|
||||
], default="LOCAL", name = "DataLink Target")
|
||||
datalink_auto_lighting: bpy.props.BoolProperty(default=True,
|
||||
datalink_auto_lighting: bpy.props.BoolProperty(default=False,
|
||||
description="Use automatic lighting from CC/iC Go-B")
|
||||
|
||||
|
||||
|
||||
@@ -2778,7 +2778,7 @@ def full_retarget_source_rig_action(op, chr_cache, src_rig=None, src_action=None
|
||||
rigutils.add_motion_set_data(armature_action, set_id, set_generation, rl_arm_id=rl_arm_id)
|
||||
armature_action.use_fake_user = props.rigify_retarget_use_fake_user if use_ui_options else True
|
||||
utils.log_info(f"Renaming armature action to: {armature_action.name}")
|
||||
for obj_id, key_action in key_actions.items():
|
||||
for obj_id, (key_action, old_key_action) in key_actions.items():
|
||||
rigutils.set_key_action_name(key_action, rig_id, motion_id, obj_id, motion_prefix)
|
||||
rigutils.add_motion_set_data(key_action, set_id, set_generation, obj_id=obj_id)
|
||||
utils.log_info(f"Renaming key action ({obj_id}) to: {key_action.name}")
|
||||
|
||||
@@ -428,6 +428,7 @@ def apply_source_key_actions(dst_rig, source_actions, all_matching=False, copy=F
|
||||
if obj.type == "MESH":
|
||||
if utils.object_has_shape_keys(obj):
|
||||
obj_id = get_action_obj_id(obj)
|
||||
old_action = utils.safe_get_action(obj.data.shape_keys)
|
||||
if (obj_id in source_actions["keys"] and
|
||||
obj_has_action_shape_keys(obj, source_actions["keys"][obj_id])):
|
||||
action = source_actions["keys"][obj_id]
|
||||
@@ -440,7 +441,7 @@ def apply_source_key_actions(dst_rig, source_actions, all_matching=False, copy=F
|
||||
utils.log_info(f" - Applying action: {action.name} to {obj_id}")
|
||||
utils.safe_set_action(obj.data.shape_keys, action)
|
||||
obj_used.append(obj)
|
||||
key_actions[obj_id] = action
|
||||
key_actions[obj_id] = (action, old_action)
|
||||
else:
|
||||
utils.safe_set_action(obj.data.shape_keys, None)
|
||||
|
||||
@@ -452,6 +453,7 @@ def apply_source_key_actions(dst_rig, source_actions, all_matching=False, copy=F
|
||||
if filter and obj not in filter: continue
|
||||
if obj not in obj_used and utils.object_has_shape_keys(obj):
|
||||
obj_id = get_action_obj_id(obj)
|
||||
old_action = utils.safe_get_action(obj.data.shape_keys)
|
||||
if body_action:
|
||||
if obj_has_action_shape_keys(obj, body_action):
|
||||
action = body_action
|
||||
@@ -464,7 +466,7 @@ def apply_source_key_actions(dst_rig, source_actions, all_matching=False, copy=F
|
||||
utils.log_info(f" - Applying action: {action.name} to {obj_id}")
|
||||
utils.safe_set_action(obj.data.shape_keys, action)
|
||||
obj_used.append(obj)
|
||||
key_actions[obj_id] = action
|
||||
key_actions[obj_id] = (action, old_action)
|
||||
return key_actions
|
||||
|
||||
|
||||
|
||||
@@ -210,13 +210,13 @@ def import_rlx_light(data: BinaryData, data_folder):
|
||||
cutoff_distance_cache = frame_cache(num_frames)
|
||||
spot_blend_cache = frame_cache(num_frames)
|
||||
spot_size_cache = frame_cache(num_frames)
|
||||
visible_cache = frame_cache(num_frames)
|
||||
render_cache = frame_cache(num_frames)
|
||||
|
||||
frame = 0
|
||||
start = None
|
||||
while not frames.eof():
|
||||
frame += 1
|
||||
time = frames.time()
|
||||
frame = frames.int()
|
||||
frame = frames.int() + 1
|
||||
if start is None:
|
||||
start = frame
|
||||
active = frames.bool()
|
||||
@@ -230,8 +230,6 @@ def import_rlx_light(data: BinaryData, data_folder):
|
||||
falloff = frames.float() / 100
|
||||
attenuation = frames.float() / 100
|
||||
darkness = frames.float()
|
||||
if not active:
|
||||
multiplier = 0.0
|
||||
cutoff_distance = range
|
||||
store_frame(light, loc_cache, frame, start, loc)
|
||||
store_frame(light, rot_cache, frame, start, rot)
|
||||
@@ -254,6 +252,9 @@ def import_rlx_light(data: BinaryData, data_folder):
|
||||
elif light_type == "POINT":
|
||||
energy = ENERGY_SCALE * multiplier
|
||||
store_frame(light, energy_cache, frame, start, energy)
|
||||
store_frame(light, visible_cache, frame, start, 0.0 if active else 1.0)
|
||||
store_frame(light, render_cache, frame, start, 0.0 if active else 1.0)
|
||||
|
||||
|
||||
ob_action, light_action, ob_slot, light_slot = prep_rlx_actions(light, name, "Export",
|
||||
reuse_existing=False,
|
||||
@@ -261,6 +262,8 @@ def import_rlx_light(data: BinaryData, data_folder):
|
||||
add_cache_fcurves(ob_action, light.path_from_id("location"), loc_cache, num_frames, "Location", slot=ob_slot)
|
||||
add_cache_rotation_fcurves(light, ob_action, rot_cache, num_frames, slot=ob_slot)
|
||||
add_cache_fcurves(ob_action, light.path_from_id("scale"), sca_cache, num_frames, "Scale", slot=ob_slot)
|
||||
add_cache_fcurves(light_action, light.path_from_id("hide_viewport"), visible_cache, num_frames, "Hide Viewport", slot=ob_slot, interpolation="CONSTANT")
|
||||
add_cache_fcurves(light_action, light.path_from_id("hide_render"), render_cache, num_frames, "Hide Render", slot=ob_slot, interpolation="CONSTANT")
|
||||
add_cache_fcurves(light_action, light.data.path_from_id("color"), color_cache, num_frames, "Color", slot=light_slot)
|
||||
add_cache_fcurves(light_action, light.data.path_from_id("energy"), energy_cache, num_frames, "Energy", slot=light_slot)
|
||||
add_cache_fcurves(light_action, light.data.path_from_id("cutoff_distance"), cutoff_distance_cache, num_frames, "Cutoff Distance", slot=light_slot)
|
||||
@@ -298,12 +301,10 @@ def import_rlx_camera(data: BinaryData, data_folder):
|
||||
f_stop_cache = frame_cache(num_frames)
|
||||
active_cache = []
|
||||
|
||||
frame = 0
|
||||
start = None
|
||||
while not frames.eof():
|
||||
frame += 1
|
||||
time = frames.time()
|
||||
frame = frames.int()
|
||||
frame = frames.int() + 1
|
||||
if start is None:
|
||||
start = frame
|
||||
loc = frames.vector() / 100
|
||||
@@ -427,7 +428,7 @@ def add_cache_rotation_fcurves(obj, action: bpy.types.Action, cache, num_frames,
|
||||
add_cache_fcurves(action, data_path, cache, num_frames, group_name=group_name, slot=slot)
|
||||
|
||||
|
||||
def add_cache_fcurves(action: bpy.types.Action, data_path, cache, num_frames, group_name=None, slot=None):
|
||||
def add_cache_fcurves(action: bpy.types.Action, data_path, cache, num_frames, group_name=None, slot=None, interpolation="LINEAR"):
|
||||
channels = utils.get_action_channels(action, slot)
|
||||
num_curves = len(cache)
|
||||
if channels:
|
||||
@@ -436,9 +437,51 @@ def add_cache_fcurves(action: bpy.types.Action, data_path, cache, num_frames, gr
|
||||
channels.groups.new(group_name)
|
||||
for i in range(0, num_curves):
|
||||
fcurve = channels.fcurves.new(data_path, index=i)
|
||||
fcurve.auto_smoothing = "NONE"
|
||||
fcurve.group = channels.groups[group_name]
|
||||
fcurve.keyframe_points.add(num_frames)
|
||||
fcurve.keyframe_points.foreach_set('co', cache[i])
|
||||
reduced = reduce_cache(cache[i], interpolation)
|
||||
num_reduced = int(len(reduced) / 2)
|
||||
fcurve.keyframe_points.add(num_reduced)
|
||||
fcurve.keyframe_points.foreach_set('co', reduced)
|
||||
if interpolation != "BEZIER":
|
||||
for keyframe in fcurve.keyframe_points:
|
||||
keyframe.interpolation = interpolation
|
||||
else:
|
||||
L = len(fcurve.keyframe_points)
|
||||
for i, keyframe in enumerate(fcurve.keyframe_points):
|
||||
prev = fcurve.keyframe_points[i-1] if i > 0 else keyframe
|
||||
next = fcurve.keyframe_points[i+1] if i < L-1 else keyframe
|
||||
keyframe.handle_left_type = "AUTO"
|
||||
keyframe.handle_left[0] = keyframe.co.x - 0.5
|
||||
keyframe.handle_left[1] = (keyframe.co.y + prev.co.y) * 0.5
|
||||
keyframe.handle_right_type = "AUTO"
|
||||
keyframe.handle_right[0] = keyframe.co.x + 0.5
|
||||
keyframe.handle_right[1] = (keyframe.co.y + next.co.y) * 0.5
|
||||
|
||||
def reduce_cache(cache, interpolation):
|
||||
if not cache or len(cache) <= 4:
|
||||
return cache
|
||||
reduced = []
|
||||
L = len(cache)
|
||||
Lm2 = L - 2
|
||||
# add first frame
|
||||
reduced.append(cache[0])
|
||||
reduced.append(cache[1])
|
||||
use_next = interpolation != "CONSTANT"
|
||||
for i in range(2, L, 2):
|
||||
frame = cache[i]
|
||||
value = cache[i+1]
|
||||
value_last = cache[i-1]
|
||||
value_next = cache[i+3] if i < Lm2 else value
|
||||
last_changed = abs(value - value_last) > 0.0001
|
||||
next_changed = abs(value - value_next) > 0.0001
|
||||
if last_changed or (use_next and next_changed):
|
||||
reduced.append(frame)
|
||||
reduced.append(value)
|
||||
# add last frame
|
||||
#reduced.append(cache[-2])
|
||||
#reduced.append(cache[-1])
|
||||
return reduced
|
||||
|
||||
|
||||
def add_camera_markers(camera, cache, num_frames, start):
|
||||
@@ -567,8 +610,10 @@ def decode_rlx_light(light_data, light: bpy.types.Object=None, container=None):
|
||||
light.data.contact_shadow_distance = 0.1
|
||||
light.data.contact_shadow_bias = 0.03
|
||||
light.data.contact_shadow_thickness = 0.001
|
||||
if not active:
|
||||
utils.hide(light)
|
||||
|
||||
light.hide_viewport = not active
|
||||
light.hide_render = not active
|
||||
|
||||
return light
|
||||
|
||||
|
||||
|
||||
@@ -2641,7 +2641,7 @@ def cycles_setup(context):
|
||||
pass
|
||||
|
||||
try:
|
||||
context.scene.cycles.preview_denoiser = 'OPTIX'
|
||||
context.scene.cycles.preview_denoiser = 'OPENIMAGEDENOISE'
|
||||
context.scene.cycles.denoiser = 'OPTIX'
|
||||
except:
|
||||
pass
|
||||
|
||||
@@ -67,7 +67,12 @@ def apply_multi_res_shape(body):
|
||||
mod = modifiers.get_object_modifier(body, modifiers.MOD_MULTIRES, modifiers.MOD_MULTIRES_NAME)
|
||||
if mod and utils.set_only_active_object(body):
|
||||
utils.log_info("Applying base shape")
|
||||
bpy.ops.object.multires_base_apply(modifier=mod.name)
|
||||
if utils.B500():
|
||||
# apply_heuristic=True applies base assuming it will be used subdivided
|
||||
# apply_heuristic=False applies base to level 0
|
||||
bpy.ops.object.multires_base_apply(modifier=mod.name, apply_heuristic=False)
|
||||
else:
|
||||
bpy.ops.object.multires_base_apply(modifier=mod.name)
|
||||
|
||||
|
||||
def displacement_map_func(value):
|
||||
@@ -209,20 +214,22 @@ def do_multires_bake(context, chr_cache, multires_mesh, layer_target, apply_shap
|
||||
utils.log_recess()
|
||||
utils.log_info("Baking complete!")
|
||||
|
||||
utils.delete_mesh_object(norm_body)
|
||||
|
||||
if layer_target == LAYER_TARGET_SCULPT and apply_shape and source_body:
|
||||
|
||||
utils.log_info("Transfering sculpt base shape to source body...")
|
||||
|
||||
utils.unhide(multires_mesh)
|
||||
utils.unhide(source_body)
|
||||
copy_base_shape(multires_mesh, source_body, layer_target, True)
|
||||
if norm_body and source_body:
|
||||
copy_base_shape(norm_body, source_body, layer_target, True)
|
||||
|
||||
# if there is a detail sculpt body, update that with the new base shape too
|
||||
detail_body = chr_cache.get_detail_body(context_object=source_body)
|
||||
if detail_body:
|
||||
copy_base_shape(multires_mesh, detail_body, layer_target, True)
|
||||
# if there is a detail sculpt body, update that with the new base shape too
|
||||
detail_body = chr_cache.get_detail_body(context_object=source_body)
|
||||
if detail_body:
|
||||
# the base shape has only been applied to the norm_body so far ...
|
||||
copy_base_shape(norm_body, detail_body, layer_target, True)
|
||||
|
||||
utils.delete_mesh_object(norm_body)
|
||||
|
||||
# restore render engine
|
||||
bake.post_bake(context, bake_state)
|
||||
|
||||
@@ -607,10 +607,13 @@ def func_export_eye_depth(cc, depth):
|
||||
return (depth) * 3.0
|
||||
|
||||
def func_set_eye_depth(cc, depth):
|
||||
return depth * 1.5
|
||||
return depth * 1.0
|
||||
|
||||
def func_set_parallax_iris_depth(cc, depth):
|
||||
return depth * 1.5 + 0.1
|
||||
return depth * 1.0
|
||||
|
||||
def func_set_parallax_pupil_scale(cc, scale):
|
||||
return scale * 0.6666
|
||||
|
||||
def func_index_f0(cc, v: list):
|
||||
return v[0]
|
||||
|
||||
@@ -1499,6 +1499,10 @@ def hide_tree(obj, hide=True, render=False):
|
||||
except: ...
|
||||
|
||||
|
||||
def show(obj: bpy.types.Object, show=True, render=False):
|
||||
hide(obj, hide=not show, render=render)
|
||||
|
||||
|
||||
def hide(obj: bpy.types.Object, hide=True, render=False):
|
||||
try:
|
||||
obj.hide_set(hide)
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
|
||||
# Don't index SpecStory auto-save files, but allow explicit context inclusion via @ references
|
||||
.specstory/**
|
||||
@@ -0,0 +1,23 @@
|
||||
# AssignedTask
|
||||
|
||||
AssignedTask is a task as it is received by the Worker.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**uuid** | **str** | |
|
||||
**job** | **str** | |
|
||||
**name** | **str** | |
|
||||
**status** | [**TaskStatus**](TaskStatus.md) | |
|
||||
**priority** | **int** | |
|
||||
**job_priority** | **int** | |
|
||||
**job_type** | **str** | |
|
||||
**task_type** | **str** | |
|
||||
**commands** | [**[Command]**](Command.md) | |
|
||||
**steps_completed** | **int** | |
|
||||
**steps_total** | **int** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# AssignedWorker
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**name** | **str** | |
|
||||
**uuid** | **str** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
# AvailableJobSetting
|
||||
|
||||
Single setting of a Job types.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**key** | **str** | Identifier for the setting, must be unique within the job type. |
|
||||
**type** | [**AvailableJobSettingType**](AvailableJobSettingType.md) | |
|
||||
**subtype** | [**AvailableJobSettingSubtype**](AvailableJobSettingSubtype.md) | | [optional]
|
||||
**choices** | **[str]** | When given, limit the valid values to these choices. Only usable with string type. | [optional]
|
||||
**propargs** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}** | Any extra arguments to the bpy.props.SomeProperty() call used to create this property. | [optional]
|
||||
**description** | **bool, date, datetime, dict, float, int, list, str, none_type** | The description/tooltip shown in the user interface. | [optional]
|
||||
**label** | **bool, date, datetime, dict, float, int, list, str, none_type** | Label for displaying this setting. If not specified, the key is used to generate a reasonable label. | [optional]
|
||||
**default** | **bool, date, datetime, dict, float, int, list, str, none_type** | The default value shown to the user when determining this setting. | [optional]
|
||||
**eval** | **str** | Python expression to be evaluated in order to determine the default value for this setting. | [optional]
|
||||
**eval_info** | [**AvailableJobSettingEvalInfo**](AvailableJobSettingEvalInfo.md) | | [optional]
|
||||
**visible** | [**AvailableJobSettingVisibility**](AvailableJobSettingVisibility.md) | | [optional]
|
||||
**required** | **bool** | Whether to immediately reject a job definition, of this type, without this particular setting. | [optional] if omitted the server will use the default value of False
|
||||
**editable** | **bool** | Whether to allow editing this setting after the job has been submitted. Would imply deleting all existing tasks for this job, and recompiling it. | [optional] if omitted the server will use the default value of False
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# AvailableJobSettingEvalInfo
|
||||
|
||||
Meta-data for the 'eval' expression.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**show_link_button** | **bool** | Enables the 'eval on submit' toggle button behavior for this setting. A toggle button will be shown in Blender's submission interface. When toggled on, the `eval` expression will determine the setting's value. Manually editing the setting is then no longer possible, and instead of an input field, the 'description' string is shown. An example use is the to-be-rendered frame range, which by default automatically follows the scene range, but can be overridden manually when desired. | defaults to False
|
||||
**description** | **str** | Description of what the 'eval' expression is doing. It is also used as placeholder text to show when the manual input field is hidden (because eval-on-submit has been toggled on by the user). | defaults to ""
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# AvailableJobSettingSubtype
|
||||
|
||||
Sub-type of the job setting. Currently only available for string types. `HASHED_FILE_PATH` is a directory path + `\"/######\"` appended.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | Sub-type of the job setting. Currently only available for string types. `HASHED_FILE_PATH` is a directory path + `\"/######\"` appended. | must be one of ["file_path", "dir_path", "file_name", "hashed_file_path", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# AvailableJobSettingType
|
||||
|
||||
Type of job setting, must be usable as IDProperty type in Blender. No nested structures (arrays, dictionaries) are supported.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | Type of job setting, must be usable as IDProperty type in Blender. No nested structures (arrays, dictionaries) are supported. | must be one of ["string", "int32", "float", "bool", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# AvailableJobSettingVisibility
|
||||
|
||||
When to show this setting. `visible`: always show. `submission`: only show in the UI of a job submitter (like a Blender add-on). `web`: only show in the web interface for management, but not when submitting the job. `hidden`: never show; only available to the job compiler script as internal setting.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | When to show this setting. `visible`: always show. `submission`: only show in the UI of a job submitter (like a Blender add-on). `web`: only show in the web interface for management, but not when submitting the job. `hidden`: never show; only available to the job compiler script as internal setting. | defaults to "visible", must be one of ["visible", "hidden", "submission", "web", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,17 @@
|
||||
# AvailableJobType
|
||||
|
||||
Job type supported by this Manager, and its parameters.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**name** | **str** | |
|
||||
**label** | **str** | |
|
||||
**settings** | [**[AvailableJobSetting]**](AvailableJobSetting.md) | |
|
||||
**etag** | **str** | Hash of the job type. If the job settings or the label change, this etag will change. This is used on job submission to ensure that the submitted job settings are up to date. |
|
||||
**description** | **str** | The description/tooltip shown in the user interface. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# AvailableJobTypes
|
||||
|
||||
List of job types supported by this Manager.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**job_types** | [**[AvailableJobType]**](AvailableJobType.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# BlenderPathCheckResult
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**input** | **str** | The input that was given to find this Blender. |
|
||||
**path** | **str** | The path that was found. |
|
||||
**source** | [**BlenderPathSource**](BlenderPathSource.md) | |
|
||||
**is_usable** | **bool** | Whether the path is usable or not. |
|
||||
**cause** | **str** | Description of why this path is (not) usable. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# BlenderPathFindResult
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | [**[BlenderPathCheckResult]**](BlenderPathCheckResult.md) | |
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# BlenderPathSource
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | | must be one of ["file_association", "path_envvar", "system_location", "input_path", "default", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# Command
|
||||
|
||||
Command represents a single command to execute by the Worker.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**name** | **str** | |
|
||||
**parameters** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}** | |
|
||||
**total_step_count** | **int** | Number of steps this command executes. This has to be implemented in the command's implementation on the Worker (to recognise what a \"step\" is), as well as given in the authoring code of the job type JavaScript script (to indicate how many steps the command invocation will perform). If not given, or set to 0, the command is not expected to send any step progress. In this case, the Worker will send a step update at completion of the command. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# Error
|
||||
|
||||
Generic error response.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**code** | **int** | HTTP status code of this response. Is included in the payload so that a single object represents all error information. Code 503 is used when the database is busy. The HTTP response will contain a 'Retry-After' HTTP header that indicates after which time the request can be retried. Following the header is not mandatory, and it's up to the client to do something reasonable like exponential backoff. |
|
||||
**message** | **str** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# EventFarmStatus
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **FarmStatusReport** | |
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
# EventJobUpdate
|
||||
|
||||
Subset of a Job, sent over SocketIO/MQTT when a job changes. For new jobs, `previous_status` will be excluded.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | UUID of the Job |
|
||||
**updated** | **datetime** | Timestamp of last update |
|
||||
**status** | [**JobStatus**](JobStatus.md) | |
|
||||
**type** | **str** | |
|
||||
**refresh_tasks** | **bool** | Indicates that the client should refresh all the job's tasks. This is sent for mass updates, where updating each individual task would generate too many updates to be practical. |
|
||||
**steps_completed** | **int** | |
|
||||
**steps_total** | **int** | |
|
||||
**priority** | **int** | | defaults to 50
|
||||
**name** | **str** | Name of the job | [optional]
|
||||
**previous_status** | [**JobStatus**](JobStatus.md) | | [optional]
|
||||
**delete_requested_at** | **datetime** | If job deletion was requested, this is the timestamp at which that request was stored on Flamenco Manager. | [optional]
|
||||
**was_deleted** | **bool** | When a job was just deleted, this is set to `true`. If this is specified, only the 'id' field is set, the rest will be empty. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# EventLastRenderedUpdate
|
||||
|
||||
Indicator that the last-rendered image of this job was updated.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**job_id** | **str** | |
|
||||
**thumbnail** | [**JobLastRenderedImageInfo**](JobLastRenderedImageInfo.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# EventLifeCycle
|
||||
|
||||
Flamenco life-cycle event, for things like shutting down, starting up, etc.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**type** | [**LifeCycleEventType**](LifeCycleEventType.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# EventTaskLogUpdate
|
||||
|
||||
Task log chunk, sent to a MQTT topic/SocketIO room dedicated to a single task, to avoid sending too many updates.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**task_id** | **str** | UUID of the Task |
|
||||
**log** | **str** | Chunk of the task log. May contain multiple lines of text. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# EventTaskUpdate
|
||||
|
||||
Subset of a Task, sent over SocketIO/MQTT when a task changes. For new tasks, `previous_status` will be excluded.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | UUID of the Task |
|
||||
**job_id** | **str** | |
|
||||
**name** | **str** | Name of the task |
|
||||
**updated** | **datetime** | Timestamp of last update |
|
||||
**status** | [**TaskStatus**](TaskStatus.md) | |
|
||||
**activity** | **str** | |
|
||||
**steps_completed** | **int** | |
|
||||
**steps_total** | **int** | |
|
||||
**worker** | [**AssignedWorker**](AssignedWorker.md) | | [optional]
|
||||
**previous_status** | [**TaskStatus**](TaskStatus.md) | | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# EventWorkerTagUpdate
|
||||
|
||||
Worker Tag, sent over SocketIO/MQTT when it changes.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**tag** | [**WorkerTag**](WorkerTag.md) | |
|
||||
**was_deleted** | **bool** | When a tag was just deleted, this is set to `true`. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
# EventWorkerUpdate
|
||||
|
||||
Subset of a Worker, sent over SocketIO/MQTT when a worker changes.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | UUID of the Worker |
|
||||
**name** | **str** | Name of the worker |
|
||||
**updated** | **datetime** | Timestamp of last update |
|
||||
**status** | [**WorkerStatus**](WorkerStatus.md) | |
|
||||
**version** | **str** | |
|
||||
**can_restart** | **bool** | Whether this Worker can auto-restart. |
|
||||
**last_seen** | **datetime** | Last time this worker was seen by the Manager. | [optional]
|
||||
**previous_status** | [**WorkerStatus**](WorkerStatus.md) | | [optional]
|
||||
**status_change** | [**WorkerStatusChangeRequest**](WorkerStatusChangeRequest.md) | | [optional]
|
||||
**deleted_at** | **datetime** | This is only set when the worker was deleted. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# FarmStatus
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | | must be one of ["active", "idle", "waiting", "asleep", "inoperative", "unknown", "starting", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# FarmStatusReport
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**status** | [**FarmStatus**](FarmStatus.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# FlamencoVersion
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**version** | **str** | Version of this Manager, meant for human consumption. For release builds it is the same as `shortversion`, for other builds it also includes the `git` version info. |
|
||||
**shortversion** | **str** | |
|
||||
**name** | **str** | |
|
||||
**git** | **str** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,29 @@
|
||||
# Job
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**name** | **str** | |
|
||||
**type** | **str** | |
|
||||
**submitter_platform** | **str** | Operating system of the submitter. This is used to recognise two-way variables. This should be a lower-case version of the platform, like \"linux\", \"windows\", \"darwin\", \"openbsd\", etc. Should be ompatible with Go's `runtime.GOOS`; run `go tool dist list` to get a list of possible platforms. As a special case, the platform \"manager\" can be given, which will be interpreted as \"the Manager's platform\". This is mostly to make test/debug scripts easier, as they can use a static document on all platforms. |
|
||||
**id** | **str** | UUID of the Job |
|
||||
**created** | **datetime** | Creation timestamp |
|
||||
**updated** | **datetime** | Timestamp of last update. |
|
||||
**status** | [**JobStatus**](JobStatus.md) | |
|
||||
**activity** | **str** | Description of the last activity on this job. |
|
||||
**steps_completed** | **int** | |
|
||||
**steps_total** | **int** | |
|
||||
**priority** | **int** | | defaults to 50
|
||||
**type_etag** | **str** | Hash of the job type, copied from the `AvailableJobType.etag` property of the job type. The job will be rejected if this field doesn't match the actual job type on the Manager. This prevents job submission with old settings, after the job compiler script has been updated. If this field is omitted, the check is bypassed. | [optional]
|
||||
**settings** | [**JobSettings**](JobSettings.md) | | [optional]
|
||||
**metadata** | [**JobMetadata**](JobMetadata.md) | | [optional]
|
||||
**storage** | [**JobStorageInfo**](JobStorageInfo.md) | | [optional]
|
||||
**worker_tag** | **str** | Worker tag that should execute this job. When a tag ID is given, only Workers in that tag will be scheduled to work on it. If empty or omitted, all workers can work on this job. | [optional]
|
||||
**initial_status** | [**JobStatus**](JobStatus.md) | | [optional]
|
||||
**delete_requested_at** | **datetime** | If job deletion was requested, this is the timestamp at which that request was stored on Flamenco Manager. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
# JobAllOf
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | UUID of the Job |
|
||||
**created** | **datetime** | Creation timestamp |
|
||||
**updated** | **datetime** | Timestamp of last update. |
|
||||
**status** | [**JobStatus**](JobStatus.md) | |
|
||||
**activity** | **str** | Description of the last activity on this job. |
|
||||
**steps_completed** | **int** | |
|
||||
**steps_total** | **int** | |
|
||||
**delete_requested_at** | **datetime** | If job deletion was requested, this is the timestamp at which that request was stored on Flamenco Manager. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# JobBlocklist
|
||||
|
||||
List of workers that are not allowed certain task types on a specific job.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | [**[JobBlocklistEntry]**](JobBlocklistEntry.md) | List of workers that are not allowed certain task types on a specific job. |
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# JobBlocklistEntry
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**worker_id** | **str** | |
|
||||
**task_type** | **str** | |
|
||||
**worker_name** | **str** | | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# JobDeletionInfo
|
||||
|
||||
Info about what will be deleted when this job is deleted.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**shaman_checkout** | **bool** | Whether the Shaman checkout directory will be removed along with the job. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# JobLastRenderedImageInfo
|
||||
|
||||
Enough information for a client to piece together different strings to form a host-relative URL to the last-rendered image. To construct the URL, concatenate \"{base}/{one of the suffixes}\".
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**base** | **str** | |
|
||||
**suffixes** | **[str]** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# JobMassDeletionSelection
|
||||
|
||||
Parameters to describe which jobs should be deleted.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**last_updated_max** | **datetime** | All jobs that were last updated before or on this timestamp will be deleted. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# JobMetadata
|
||||
|
||||
Arbitrary metadata strings. More complex structures can be modeled by using `a.b.c` notation for the key.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**any string name** | **str** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# JobPriorityChange
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**priority** | **int** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# JobSettings
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# JobStatus
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | | must be one of ["active", "canceled", "completed", "failed", "paused", "pause-requested", "queued", "cancel-requested", "requeueing", "under-construction", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# JobStatusChange
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**status** | [**JobStatus**](JobStatus.md) | |
|
||||
**reason** | **str** | The reason for this status change. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# JobStorageInfo
|
||||
|
||||
Storage info of a job, which Flamenco can use to remove job-related files when necessary.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**shaman_checkout_id** | **str** | 'Checkout ID' used when creating the Shaman checkout for this job. Aids in removing the checkout directory when the job is removed from Flamenco. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# JobTagChange
|
||||
|
||||
New tag to assign to a job. Can be empty to remove the tag (and thus make the job available to all workers).
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**id** | **str** | UUID of the tag. If this is given, 'name' should not be given. | [optional]
|
||||
**name** | **str** | Name of the tag. If this is given, 'id' should not be given. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# JobTasksSummary
|
||||
|
||||
Simplified list of tasks of a job. Contains all tasks, but not all info of each task.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**tasks** | [**[TaskSummary]**](TaskSummary.md) | | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,17 @@
|
||||
# JobsQuery
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**offset** | **int** | | [optional]
|
||||
**limit** | **int** | | [optional]
|
||||
**order_by** | **[str]** | | [optional]
|
||||
**status_in** | [**[JobStatus]**](JobStatus.md) | Return only jobs with a status in this array. | [optional]
|
||||
**metadata** | **{str: (str,)}** | Filter by metadata, using `LIKE` notation. | [optional]
|
||||
**settings** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}** | Filter by job settings, using `LIKE` notation. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# JobsQueryResult
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**jobs** | [**[Job]**](Job.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# LifeCycleEventType
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | | must be one of ["manager-startup", "manager-shutdown", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# ManagerConfiguration
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**storage_location** | **str** | Directory used for job file storage. |
|
||||
**shaman_enabled** | **bool** | Whether the Shaman file transfer API is available. |
|
||||
**is_first_run** | **bool** | Whether this is considered the first time the Manager runs. This is determined by a few factors, like a non-existent configuration file or certain settings being empty while they shouldn't be. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# ManagerVariable
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | |
|
||||
**is_twoway** | **bool** | One-way variables are the most common one, and are simple replacement from `{name}` to their value, which happens when a Task is given to a Worker. Two-way variables are also replaced when submitting a job, where the platform-specific value is replaced by `{name}`. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# ManagerVariableAudience
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | | must be one of ["workers", "users", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# ManagerVariables
|
||||
|
||||
Mapping from variable name to its properties.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**any string name** | [**ManagerVariable**](ManagerVariable.md) | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# MayKeepRunning
|
||||
|
||||
Indicates whether the worker may keep running the task.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**may_keep_running** | **bool** | |
|
||||
**reason** | **str** | |
|
||||
**status_change_requested** | **bool** | Indicates that a status change requested for the worker. It should use the `workerState` operation to determine which state to go to next. If this is `true`, `mayKeepRunning` MUST be `false`. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,744 @@
|
||||
# flamenco.manager.MetaApi
|
||||
|
||||
All URIs are relative to *http://localhost*
|
||||
|
||||
Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[**check_blender_exe_path**](MetaApi.md#check_blender_exe_path) | **POST** /api/v3/configuration/check/blender | Validate a CLI command for use as way to start Blender
|
||||
[**check_shared_storage_path**](MetaApi.md#check_shared_storage_path) | **POST** /api/v3/configuration/check/shared-storage | Validate a path for use as shared storage.
|
||||
[**find_blender_exe_path**](MetaApi.md#find_blender_exe_path) | **GET** /api/v3/configuration/check/blender | Find one or more CLI commands for use as way to start Blender
|
||||
[**get_configuration**](MetaApi.md#get_configuration) | **GET** /api/v3/configuration | Get the configuration of this Manager.
|
||||
[**get_configuration_file**](MetaApi.md#get_configuration_file) | **GET** /api/v3/configuration/file | Retrieve the configuration of Flamenco Manager.
|
||||
[**get_farm_status**](MetaApi.md#get_farm_status) | **GET** /api/v3/status | Get the status of this Flamenco farm.
|
||||
[**get_shared_storage**](MetaApi.md#get_shared_storage) | **GET** /api/v3/configuration/shared-storage/{audience}/{platform} | Get the shared storage location of this Manager, adjusted for the given audience and platform.
|
||||
[**get_variables**](MetaApi.md#get_variables) | **GET** /api/v3/configuration/variables/{audience}/{platform} | Get the variables of this Manager. Used by the Blender add-on to recognise two-way variables, and for the web interface to do variable replacement based on the browser's platform.
|
||||
[**get_version**](MetaApi.md#get_version) | **GET** /api/v3/version | Get the Flamenco version of this Manager
|
||||
[**save_setup_assistant_config**](MetaApi.md#save_setup_assistant_config) | **POST** /api/v3/configuration/setup-assistant | Update the Manager's configuration, and restart it in fully functional mode.
|
||||
[**update_configuration_file**](MetaApi.md#update_configuration_file) | **PUT** /api/v3/configuration/file | Overwrites the configuration file. It does not actively reload the new configuration.
|
||||
|
||||
|
||||
# **check_blender_exe_path**
|
||||
> BlenderPathCheckResult check_blender_exe_path()
|
||||
|
||||
Validate a CLI command for use as way to start Blender
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.path_check_input import PathCheckInput
|
||||
from flamenco.manager.model.blender_path_check_result import BlenderPathCheckResult
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
path_check_input = PathCheckInput(
|
||||
path="path_example",
|
||||
) # PathCheckInput | Command or executable path to check (optional)
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
# and optional values
|
||||
try:
|
||||
# Validate a CLI command for use as way to start Blender
|
||||
api_response = api_instance.check_blender_exe_path(path_check_input=path_check_input)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->check_blender_exe_path: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**path_check_input** | [**PathCheckInput**](PathCheckInput.md)| Command or executable path to check | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
[**BlenderPathCheckResult**](BlenderPathCheckResult.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Normal response, path check went fine. | - |
|
||||
**0** | Something went wrong. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **check_shared_storage_path**
|
||||
> PathCheckResult check_shared_storage_path()
|
||||
|
||||
Validate a path for use as shared storage.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.path_check_result import PathCheckResult
|
||||
from flamenco.manager.model.path_check_input import PathCheckInput
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
path_check_input = PathCheckInput(
|
||||
path="path_example",
|
||||
) # PathCheckInput | Path to check (optional)
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
# and optional values
|
||||
try:
|
||||
# Validate a path for use as shared storage.
|
||||
api_response = api_instance.check_shared_storage_path(path_check_input=path_check_input)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->check_shared_storage_path: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**path_check_input** | [**PathCheckInput**](PathCheckInput.md)| Path to check | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
[**PathCheckResult**](PathCheckResult.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Normal response, path check went fine. | - |
|
||||
**0** | Something went wrong. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **find_blender_exe_path**
|
||||
> BlenderPathFindResult find_blender_exe_path()
|
||||
|
||||
Find one or more CLI commands for use as way to start Blender
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.blender_path_find_result import BlenderPathFindResult
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
|
||||
# example, this endpoint has no required or optional parameters
|
||||
try:
|
||||
# Find one or more CLI commands for use as way to start Blender
|
||||
api_response = api_instance.find_blender_exe_path()
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->find_blender_exe_path: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
This endpoint does not need any parameter.
|
||||
|
||||
### Return type
|
||||
|
||||
[**BlenderPathFindResult**](BlenderPathFindResult.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Found locations of Blender. | - |
|
||||
**0** | Something went wrong. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_configuration**
|
||||
> ManagerConfiguration get_configuration()
|
||||
|
||||
Get the configuration of this Manager.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.manager_configuration import ManagerConfiguration
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
|
||||
# example, this endpoint has no required or optional parameters
|
||||
try:
|
||||
# Get the configuration of this Manager.
|
||||
api_response = api_instance.get_configuration()
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->get_configuration: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
This endpoint does not need any parameter.
|
||||
|
||||
### Return type
|
||||
|
||||
[**ManagerConfiguration**](ManagerConfiguration.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | normal response | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_configuration_file**
|
||||
> {str: (bool, date, datetime, dict, float, int, list, str, none_type)} get_configuration_file()
|
||||
|
||||
Retrieve the configuration of Flamenco Manager.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
|
||||
# example, this endpoint has no required or optional parameters
|
||||
try:
|
||||
# Retrieve the configuration of Flamenco Manager.
|
||||
api_response = api_instance.get_configuration_file()
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->get_configuration_file: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
This endpoint does not need any parameter.
|
||||
|
||||
### Return type
|
||||
|
||||
**{str: (bool, date, datetime, dict, float, int, list, str, none_type)}**
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json, application/yaml
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Normal response. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_farm_status**
|
||||
> FarmStatusReport get_farm_status()
|
||||
|
||||
Get the status of this Flamenco farm.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.farm_status_report import FarmStatusReport
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
|
||||
# example, this endpoint has no required or optional parameters
|
||||
try:
|
||||
# Get the status of this Flamenco farm.
|
||||
api_response = api_instance.get_farm_status()
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->get_farm_status: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
This endpoint does not need any parameter.
|
||||
|
||||
### Return type
|
||||
|
||||
[**FarmStatusReport**](FarmStatusReport.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | normal response | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_shared_storage**
|
||||
> SharedStorageLocation get_shared_storage(audience, platform)
|
||||
|
||||
Get the shared storage location of this Manager, adjusted for the given audience and platform.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.manager_variable_audience import ManagerVariableAudience
|
||||
from flamenco.manager.model.shared_storage_location import SharedStorageLocation
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
audience = ManagerVariableAudience("workers") # ManagerVariableAudience |
|
||||
platform = "platform_example" # str |
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Get the shared storage location of this Manager, adjusted for the given audience and platform.
|
||||
api_response = api_instance.get_shared_storage(audience, platform)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->get_shared_storage: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**audience** | **ManagerVariableAudience**| |
|
||||
**platform** | **str**| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**SharedStorageLocation**](SharedStorageLocation.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Normal response. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_variables**
|
||||
> ManagerVariables get_variables(audience, platform)
|
||||
|
||||
Get the variables of this Manager. Used by the Blender add-on to recognise two-way variables, and for the web interface to do variable replacement based on the browser's platform.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.manager_variable_audience import ManagerVariableAudience
|
||||
from flamenco.manager.model.manager_variables import ManagerVariables
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
audience = ManagerVariableAudience("workers") # ManagerVariableAudience |
|
||||
platform = "platform_example" # str |
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Get the variables of this Manager. Used by the Blender add-on to recognise two-way variables, and for the web interface to do variable replacement based on the browser's platform.
|
||||
api_response = api_instance.get_variables(audience, platform)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->get_variables: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**audience** | **ManagerVariableAudience**| |
|
||||
**platform** | **str**| |
|
||||
|
||||
### Return type
|
||||
|
||||
[**ManagerVariables**](ManagerVariables.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Normal response. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **get_version**
|
||||
> FlamencoVersion get_version()
|
||||
|
||||
Get the Flamenco version of this Manager
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.flamenco_version import FlamencoVersion
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
|
||||
# example, this endpoint has no required or optional parameters
|
||||
try:
|
||||
# Get the Flamenco version of this Manager
|
||||
api_response = api_instance.get_version()
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->get_version: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
This endpoint does not need any parameter.
|
||||
|
||||
### Return type
|
||||
|
||||
[**FlamencoVersion**](FlamencoVersion.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | normal response | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **save_setup_assistant_config**
|
||||
> save_setup_assistant_config()
|
||||
|
||||
Update the Manager's configuration, and restart it in fully functional mode.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.setup_assistant_config import SetupAssistantConfig
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
setup_assistant_config = SetupAssistantConfig(
|
||||
storage_location="storage_location_example",
|
||||
blender_executable=BlenderPathCheckResult(
|
||||
input="input_example",
|
||||
path="path_example",
|
||||
source=BlenderPathSource("file_association"),
|
||||
is_usable=True,
|
||||
cause="cause_example",
|
||||
),
|
||||
) # SetupAssistantConfig | Configuration to save. (optional)
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
# and optional values
|
||||
try:
|
||||
# Update the Manager's configuration, and restart it in fully functional mode.
|
||||
api_instance.save_setup_assistant_config(setup_assistant_config=setup_assistant_config)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->save_setup_assistant_config: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**setup_assistant_config** | [**SetupAssistantConfig**](SetupAssistantConfig.md)| Configuration to save. | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
void (empty response body)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**204** | Normal response. The webapp should do a full refresh at this point. | - |
|
||||
**0** | Something went wrong. | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **update_configuration_file**
|
||||
> update_configuration_file(body)
|
||||
|
||||
Overwrites the configuration file. It does not actively reload the new configuration.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import meta_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = meta_api.MetaApi(api_client)
|
||||
body = {} # {str: (bool, date, datetime, dict, float, int, list, str, none_type)} | The configuration values as a JSON
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Overwrites the configuration file. It does not actively reload the new configuration.
|
||||
api_instance.update_configuration_file(body)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling MetaApi->update_configuration_file: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**body** | **{str: (bool, date, datetime, dict, float, int, list, str, none_type)}**| The configuration values as a JSON |
|
||||
|
||||
### Return type
|
||||
|
||||
void (empty response body)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**204** | The configuration was successfully stored to flamenco-manager.yaml | - |
|
||||
**0** | Unable to save the configuration file | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# PathCheckInput
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**path** | **str** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# PathCheckResult
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**path** | **str** | The path that was checked. |
|
||||
**is_usable** | **bool** | Whether the path is usable or not. |
|
||||
**cause** | **str** | Description of why this path is (not) usable. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
# RegisteredWorker
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**uuid** | **str** | |
|
||||
**name** | **str** | |
|
||||
**address** | **str** | |
|
||||
**status** | [**WorkerStatus**](WorkerStatus.md) | |
|
||||
**platform** | **str** | |
|
||||
**software** | **str** | |
|
||||
**supported_task_types** | **[str]** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# SecurityError
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**message** | **str** | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# SetupAssistantConfig
|
||||
|
||||
Configuration obtained from the Setup Assistant.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**storage_location** | **str** | Directory used for job file storage. |
|
||||
**blender_executable** | [**BlenderPathCheckResult**](BlenderPathCheckResult.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,320 @@
|
||||
# flamenco.manager.ShamanApi
|
||||
|
||||
All URIs are relative to *http://localhost*
|
||||
|
||||
Method | HTTP request | Description
|
||||
------------- | ------------- | -------------
|
||||
[**shaman_checkout**](ShamanApi.md#shaman_checkout) | **POST** /api/v3/shaman/checkout/create | Create a directory, and symlink the required files into it. The files must all have been uploaded to Shaman before calling this endpoint.
|
||||
[**shaman_checkout_requirements**](ShamanApi.md#shaman_checkout_requirements) | **POST** /api/v3/shaman/checkout/requirements | Checks a Shaman Requirements file, and reports which files are unknown.
|
||||
[**shaman_file_store**](ShamanApi.md#shaman_file_store) | **POST** /api/v3/shaman/files/{checksum}/{filesize} | Store a new file on the Shaman server. Note that the Shaman server can forcibly close the HTTP connection when another client finishes uploading the exact same file, to prevent double uploads. The file's contents should be sent in the request body.
|
||||
[**shaman_file_store_check**](ShamanApi.md#shaman_file_store_check) | **GET** /api/v3/shaman/files/{checksum}/{filesize} | Check the status of a file on the Shaman server.
|
||||
|
||||
|
||||
# **shaman_checkout**
|
||||
> ShamanCheckoutResult shaman_checkout(shaman_checkout)
|
||||
|
||||
Create a directory, and symlink the required files into it. The files must all have been uploaded to Shaman before calling this endpoint.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import shaman_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.shaman_checkout import ShamanCheckout
|
||||
from flamenco.manager.model.shaman_checkout_result import ShamanCheckoutResult
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = shaman_api.ShamanApi(api_client)
|
||||
shaman_checkout = ShamanCheckout(
|
||||
files=[
|
||||
ShamanFileSpec(
|
||||
sha="sha_example",
|
||||
size=1,
|
||||
path="path_example",
|
||||
),
|
||||
],
|
||||
checkout_path="checkout_path_example",
|
||||
) # ShamanCheckout | Set of files to check out.
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Create a directory, and symlink the required files into it. The files must all have been uploaded to Shaman before calling this endpoint.
|
||||
api_response = api_instance.shaman_checkout(shaman_checkout)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling ShamanApi->shaman_checkout: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**shaman_checkout** | [**ShamanCheckout**](ShamanCheckout.md)| Set of files to check out. |
|
||||
|
||||
### Return type
|
||||
|
||||
[**ShamanCheckoutResult**](ShamanCheckoutResult.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Checkout was created successfully. | - |
|
||||
**424** | There were files missing. Use `shamanCheckoutRequirements` to figure out which ones. | - |
|
||||
**409** | Checkout already exists. | - |
|
||||
**0** | unexpected error | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **shaman_checkout_requirements**
|
||||
> ShamanRequirementsResponse shaman_checkout_requirements(shaman_requirements_request)
|
||||
|
||||
Checks a Shaman Requirements file, and reports which files are unknown.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import shaman_api
|
||||
from flamenco.manager.model.shaman_requirements_request import ShamanRequirementsRequest
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.shaman_requirements_response import ShamanRequirementsResponse
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = shaman_api.ShamanApi(api_client)
|
||||
shaman_requirements_request = ShamanRequirementsRequest(
|
||||
files=[
|
||||
ShamanFileSpec(
|
||||
sha="sha_example",
|
||||
size=1,
|
||||
path="path_example",
|
||||
),
|
||||
],
|
||||
) # ShamanRequirementsRequest | Set of files to check
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Checks a Shaman Requirements file, and reports which files are unknown.
|
||||
api_response = api_instance.shaman_checkout_requirements(shaman_requirements_request)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling ShamanApi->shaman_checkout_requirements: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**shaman_requirements_request** | [**ShamanRequirementsRequest**](ShamanRequirementsRequest.md)| Set of files to check |
|
||||
|
||||
### Return type
|
||||
|
||||
[**ShamanRequirementsResponse**](ShamanRequirementsResponse.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/json
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Subset of the posted requirements, indicating the unknown files. | - |
|
||||
**0** | unexpected error | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **shaman_file_store**
|
||||
> shaman_file_store(checksum, filesize, body)
|
||||
|
||||
Store a new file on the Shaman server. Note that the Shaman server can forcibly close the HTTP connection when another client finishes uploading the exact same file, to prevent double uploads. The file's contents should be sent in the request body.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import shaman_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = shaman_api.ShamanApi(api_client)
|
||||
checksum = "checksum_example" # str | SHA256 checksum of the file.
|
||||
filesize = 1 # int | Size of the file in bytes.
|
||||
body = open('/path/to/file', 'rb') # file_type | Contents of the file
|
||||
x_shaman_can_defer_upload = True # bool | The client indicates that it can defer uploading this file. The \"208\" response will not only be returned when the file is already fully known to the Shaman server, but also when someone else is currently uploading this file. (optional)
|
||||
x_shaman_original_filename = "X-Shaman-Original-Filename_example" # str | The original filename. If sent along with the request, it will be included in the server logs, which can aid in debugging. MUST either be ASCII or encoded using RFC 2047 (aka MIME encoding). In the latter case the encoding MUST be UTF-8. (optional)
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Store a new file on the Shaman server. Note that the Shaman server can forcibly close the HTTP connection when another client finishes uploading the exact same file, to prevent double uploads. The file's contents should be sent in the request body.
|
||||
api_instance.shaman_file_store(checksum, filesize, body)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling ShamanApi->shaman_file_store: %s\n" % e)
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
# and optional values
|
||||
try:
|
||||
# Store a new file on the Shaman server. Note that the Shaman server can forcibly close the HTTP connection when another client finishes uploading the exact same file, to prevent double uploads. The file's contents should be sent in the request body.
|
||||
api_instance.shaman_file_store(checksum, filesize, body, x_shaman_can_defer_upload=x_shaman_can_defer_upload, x_shaman_original_filename=x_shaman_original_filename)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling ShamanApi->shaman_file_store: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**checksum** | **str**| SHA256 checksum of the file. |
|
||||
**filesize** | **int**| Size of the file in bytes. |
|
||||
**body** | **file_type**| Contents of the file |
|
||||
**x_shaman_can_defer_upload** | **bool**| The client indicates that it can defer uploading this file. The \"208\" response will not only be returned when the file is already fully known to the Shaman server, but also when someone else is currently uploading this file. | [optional]
|
||||
**x_shaman_original_filename** | **str**| The original filename. If sent along with the request, it will be included in the server logs, which can aid in debugging. MUST either be ASCII or encoded using RFC 2047 (aka MIME encoding). In the latter case the encoding MUST be UTF-8. | [optional]
|
||||
|
||||
### Return type
|
||||
|
||||
void (empty response body)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: application/octet-stream
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**204** | The file was accepted. | - |
|
||||
**208** | The file was already known to the server. | - |
|
||||
**417** | There was a mismatch between the request parameters and the actual file size or checksum of the uploaded file. | - |
|
||||
**425** | Client should defer uploading this file. The file is currently in the process of being uploaded by someone else, and `X-Shaman-Can-Defer-Upload: true` was sent in the request. | - |
|
||||
**0** | unexpected error | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
# **shaman_file_store_check**
|
||||
> ShamanSingleFileStatus shaman_file_store_check(checksum, filesize)
|
||||
|
||||
Check the status of a file on the Shaman server.
|
||||
|
||||
### Example
|
||||
|
||||
|
||||
```python
|
||||
import time
|
||||
import flamenco.manager
|
||||
from flamenco.manager.api import shaman_api
|
||||
from flamenco.manager.model.error import Error
|
||||
from flamenco.manager.model.shaman_single_file_status import ShamanSingleFileStatus
|
||||
from pprint import pprint
|
||||
# Defining the host is optional and defaults to http://localhost
|
||||
# See configuration.py for a list of all supported configuration parameters.
|
||||
configuration = flamenco.manager.Configuration(
|
||||
host = "http://localhost"
|
||||
)
|
||||
|
||||
|
||||
# Enter a context with an instance of the API client
|
||||
with flamenco.manager.ApiClient() as api_client:
|
||||
# Create an instance of the API class
|
||||
api_instance = shaman_api.ShamanApi(api_client)
|
||||
checksum = "checksum_example" # str | SHA256 checksum of the file.
|
||||
filesize = 1 # int | Size of the file in bytes.
|
||||
|
||||
# example passing only required values which don't have defaults set
|
||||
try:
|
||||
# Check the status of a file on the Shaman server.
|
||||
api_response = api_instance.shaman_file_store_check(checksum, filesize)
|
||||
pprint(api_response)
|
||||
except flamenco.manager.ApiException as e:
|
||||
print("Exception when calling ShamanApi->shaman_file_store_check: %s\n" % e)
|
||||
```
|
||||
|
||||
|
||||
### Parameters
|
||||
|
||||
Name | Type | Description | Notes
|
||||
------------- | ------------- | ------------- | -------------
|
||||
**checksum** | **str**| SHA256 checksum of the file. |
|
||||
**filesize** | **int**| Size of the file in bytes. |
|
||||
|
||||
### Return type
|
||||
|
||||
[**ShamanSingleFileStatus**](ShamanSingleFileStatus.md)
|
||||
|
||||
### Authorization
|
||||
|
||||
No authorization required
|
||||
|
||||
### HTTP request headers
|
||||
|
||||
- **Content-Type**: Not defined
|
||||
- **Accept**: application/json
|
||||
|
||||
|
||||
### HTTP response details
|
||||
|
||||
| Status code | Description | Response headers |
|
||||
|-------------|-------------|------------------|
|
||||
**200** | Normal response. | - |
|
||||
**0** | unexpected error | - |
|
||||
|
||||
[[Back to top]](#) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to Model list]](../README.md#documentation-for-models) [[Back to README]](../README.md)
|
||||
|
||||
@@ -0,0 +1,14 @@
|
||||
# ShamanCheckout
|
||||
|
||||
Set of files with their SHA256 checksum, size in bytes, and desired location in the checkout directory.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**files** | [**[ShamanFileSpec]**](ShamanFileSpec.md) | |
|
||||
**checkout_path** | **str** | Path where the Manager should create this checkout. It is relative to the Shaman checkout path as configured on the Manager. In older versions of the Shaman this was just the \"checkout ID\", but in this version it can be a path like `project-slug/scene-name/unique-ID`. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# ShamanCheckoutResult
|
||||
|
||||
The result of a Shaman checkout.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**checkout_path** | **str** | Path where the Manager created this checkout. This can be different than what was requested, as the Manager will ensure a unique directory. The path is relative to the Shaman checkout path as configured on the Manager. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# ShamanFileSpec
|
||||
|
||||
Specification of a file in the Shaman storage.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**sha** | **str** | SHA256 checksum of the file |
|
||||
**size** | **int** | File size in bytes |
|
||||
**path** | **str** | Location of the file in the checkout |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# ShamanFileSpecWithStatus
|
||||
|
||||
Specification of a file, which could be in the Shaman storage, or not, depending on its status.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**sha** | **str** | SHA256 checksum of the file |
|
||||
**size** | **int** | File size in bytes |
|
||||
**path** | **str** | Location of the file in the checkout |
|
||||
**status** | [**ShamanFileStatus**](ShamanFileStatus.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
# ShamanFileStatus
|
||||
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**value** | **str** | | must be one of ["unknown", "uploading", "stored", ]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# ShamanRequirementsRequest
|
||||
|
||||
Set of files with their SHA256 checksum and size in bytes.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**files** | [**[ShamanFileSpec]**](ShamanFileSpec.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# ShamanRequirementsResponse
|
||||
|
||||
The files from a requirements request, with their status on the Shaman server. Files that are known to Shaman are excluded from the response.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**files** | [**[ShamanFileSpecWithStatus]**](ShamanFileSpecWithStatus.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
# ShamanSingleFileStatus
|
||||
|
||||
Status of a file in the Shaman storage.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**status** | [**ShamanFileStatus**](ShamanFileStatus.md) | |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,16 @@
|
||||
# SharedStorageLocation
|
||||
|
||||
Location of the shared storage, adjusted for a specific audience & platform. This uses two-way variables to adjust the shared storage path from the Manager's configuration.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**location** | **str** | |
|
||||
**audience** | [**ManagerVariableAudience**](ManagerVariableAudience.md) | |
|
||||
**platform** | **str** | |
|
||||
**shaman_enabled** | **bool** | Whether the Shaman file transfer API is available. |
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
@@ -0,0 +1,15 @@
|
||||
# SocketIOSubscription
|
||||
|
||||
Send by SocketIO clients as `/subscription` event type, to manage their subscription to job updates. Clients always get job updates, but for task updates or task logs they need to explicitly subscribe. For simplicity, clients can only subscribe to one job (to get task updates for that job) and one task's log at a time. This is not used by MQTT, as with that protocol the subscriptions are managed by the MQTT broker, not Flamenco.
|
||||
|
||||
## Properties
|
||||
Name | Type | Description | Notes
|
||||
------------ | ------------- | ------------- | -------------
|
||||
**op** | [**SocketIOSubscriptionOperation**](SocketIOSubscriptionOperation.md) | |
|
||||
**type** | [**SocketIOSubscriptionType**](SocketIOSubscriptionType.md) | |
|
||||
**uuid** | **str** | UUID of the thing to subscribe to / unsubscribe from. | [optional]
|
||||
**any string name** | **bool, date, datetime, dict, float, int, list, str, none_type** | any string name can be used but the value must be the correct type | [optional]
|
||||
|
||||
[[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user