pyjallib 0.1.13__py3-none-any.whl → 0.1.15__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
pyjallib/__init__.py CHANGED
@@ -6,7 +6,7 @@ pyjallib Package
6
6
  Python library for game character development pipeline.
7
7
  """
8
8
 
9
- __version__ = '0.1.13'
9
+ __version__ = '0.1.15'
10
10
 
11
11
  # reload_modules 함수를 패키지 레벨에서 사용 가능하게 함
12
12
  from pyjallib.namePart import NamePart, NamePartType
pyjallib/max/__init__.py CHANGED
@@ -24,6 +24,7 @@ from pyjallib.max.link import Link
24
24
 
25
25
  from pyjallib.max.bip import Bip
26
26
  from pyjallib.max.skin import Skin
27
+ from pyjallib.max.skeleton import Skeleton
27
28
  from pyjallib.max.morph import Morph
28
29
 
29
30
  from pyjallib.max.boneChain import BoneChain
@@ -39,6 +40,7 @@ from pyjallib.max.rootMotion import RootMotion
39
40
 
40
41
  from pyjallib.max.fbxHandler import FBXHandler
41
42
  from pyjallib.max.toolManager import ToolManager
43
+ from pyjallib.max.progress import Progress
42
44
 
43
45
  from pyjallib.max.ui.Container import Container
44
46
 
@@ -57,6 +59,7 @@ __all__ = [
57
59
  'Link',
58
60
  'Bip',
59
61
  'Skin',
62
+ 'Skeleton',
60
63
  'Morph',
61
64
  'BoneChain',
62
65
  'TwistBone',
@@ -68,5 +71,6 @@ __all__ = [
68
71
  'RootMotion',
69
72
  'FBXHandler',
70
73
  'ToolManager',
74
+ 'Progress',
71
75
  'Container'
72
76
  ]
pyjallib/max/header.py CHANGED
@@ -23,6 +23,7 @@ from .link import Link
23
23
 
24
24
  from .bip import Bip
25
25
  from .skin import Skin
26
+ from .skeleton import Skeleton
26
27
 
27
28
  from .twistBone import TwistBone
28
29
  from .autoClavicle import AutoClavicle
@@ -74,6 +75,7 @@ class Header:
74
75
 
75
76
  self.bip = Bip(animService=self.anim, nameService=self.name, boneService=self.bone)
76
77
  self.skin = Skin()
78
+ self.skeleton = Skeleton(animService=self.anim, nameService=self.name, boneService=self.bone, bipService=self.bip, layerService=self.layer)
77
79
 
78
80
  self.twistBone = TwistBone(nameService=self.name, animService=self.anim, constraintService=self.constraint, bipService=self.bip, boneService=self.bone)
79
81
  self.groinBone = GroinBone(nameService=self.name, animService=self.anim, constraintService=self.constraint, boneService=self.bone, helperService=self.helper)
@@ -0,0 +1,40 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ Progress 모듈 - 3ds Max 작업 진행 상황 표시 관련 기능 제공
6
+ """
7
+
8
+ from pymxs import runtime as rt
9
+
10
+ class Progress:
11
+ """
12
+ 3ds Max 작업 진행 상황 표시 관련 기능을 제공하는 클래스.
13
+ """
14
+ def __init__(self, inTaskName: str, inTotalSteps: int = 0):
15
+ """
16
+ 클래스 초기화
17
+ """
18
+ self.taskName = inTaskName
19
+ self.currentStep = 0
20
+ self.totalSteps = inTotalSteps
21
+ self.currentPercent = 0
22
+
23
+ def update(self, inCurrentStep: int) -> int:
24
+ """
25
+ 현재 진행율(%)을 반환합니다.
26
+ """
27
+ if self.totalSteps == 0:
28
+ self.currentStep = inCurrentStep % 100
29
+ self.currentPercent = int(self.currentStep)
30
+ else:
31
+ self.currentStep = inCurrentStep
32
+ self.currentPercent = int((self.currentStep / self.totalSteps) * 100)
33
+ return self.currentPercent
34
+
35
+ def reset(self):
36
+ """
37
+ 진행 상태를 초기화합니다.
38
+ """
39
+ self.currentStep = 0
40
+ self.currentPercent = 0
@@ -0,0 +1,192 @@
1
+ #!/usr/bin/env python
2
+ # -*- coding: utf-8 -*-
3
+
4
+ """
5
+ 스켈레톤 모듈 - 3ds Max용 스켈레톤 관련 기능 제공
6
+ 원본 MAXScript의 skeleton.ms를 Python으로 변환하였으며, pymxs 모듈 기반으로 구현됨
7
+ """
8
+
9
+ from pymxs import runtime as rt
10
+
11
+ # Import necessary service classes for default initialization
12
+ from .anim import Anim
13
+ from .name import Name
14
+ from .bone import Bone
15
+ from .bip import Bip
16
+ from .layer import Layer
17
+
18
+ from .progress import Progress
19
+
20
+
21
+ class Skeleton:
22
+ """
23
+ 스켈레톤 관련 기능을 제공하는 클래스.
24
+ MAXScript의 _Skeleton 구조체 개념을 Python으로 재구현한 클래스이며,
25
+ 3ds Max의 기능들을 pymxs API를 통해 제어합니다.
26
+ """
27
+
28
+ def __init__(self, animService=None, nameService=None, boneService=None, bipService=None, layerService=None):
29
+ """
30
+ 클래스 초기화
31
+
32
+ Args:
33
+ animService: Anim 서비스 인스턴스 (제공되지 않으면 새로 생성)
34
+ nameService: Name 서비스 인스턴스 (제공되지 않으면 새로 생성)
35
+ boneService: Bone 서비스 인스턴스 (제공되지 않으면 새로 생성)
36
+ bipService: Bip 서비스 인스턴스 (제공되지 않으면 새로 생성)
37
+ layerService: Layer 서비스 인스턴스 (제공되지 않으면 새로 생성)
38
+ """
39
+ self.anim = animService if animService else Anim()
40
+ self.name = nameService if nameService else Name()
41
+ self.bone = boneService if boneService else Bone(nameService=self.name, animService=self.anim)
42
+ self.bip = bipService if bipService else Bip(animService=self.anim, nameService=self.name, boneService=self.bone)
43
+ self.layer = layerService if layerService else Layer()
44
+
45
+ # def get_dependencies(self, inObj):
46
+ # """
47
+ # 객체의 의존성을 가져옴
48
+
49
+ # Args:
50
+ # inObj: 의존성을 확인할 객체 또는 객체 배열
51
+
52
+ # Returns:
53
+ # 의존성 노드 배열
54
+ # """
55
+ # # core - 단일 객체인 경우 배열로 변환
56
+ # if rt.classOf(inObj) != rt.Array:
57
+ # inObj = [inObj]
58
+ # else:
59
+ # # rt.Array를 Python 리스트로 변환
60
+ # inObj = list(inObj)
61
+
62
+ # nodeArray = []
63
+ # res = inObj.copy()
64
+
65
+ # for each in inObj:
66
+ # # Biped 객체인 경우 건너뛰기
67
+ # if self.bip.is_biped_object(each):
68
+ # continue
69
+
70
+ # # 컨트롤러의 의존성 추가
71
+ # controller_deps = rt.refs.dependson(each.controller)
72
+ # if controller_deps:
73
+ # res.extend(controller_deps)
74
+
75
+ # # Skin 속성이 있는 경우 Skin의 의존성 추가
76
+ # if rt.isProperty(each, rt.name("Skin")):
77
+ # skin_deps = rt.refs.dependson(each.skin)
78
+ # if skin_deps:
79
+ # res.extend(skin_deps)
80
+
81
+ # # 의존성 배열을 순회하면서 추가 의존성 확인
82
+ # i = 0
83
+ # while i < len(res):
84
+ # # 노드가 아닌 경우 추가 의존성 확인
85
+ # if rt.superClassOf(res[i]) != rt.node:
86
+ # additional_deps = rt.refs.dependson(res[i])
87
+ # if additional_deps:
88
+ # res.extend(additional_deps)
89
+ # # 유효한 노드인 경우
90
+ # if rt.isValidNode(res[i]):
91
+ # # 노드 배열에 추가
92
+ # if res[i] not in nodeArray:
93
+ # nodeArray.append(res[i])
94
+
95
+ # # 부모 노드 확인 및 추가
96
+ # parentNode = res[i].parent
97
+ # if rt.isValidNode(parentNode) and parentNode not in nodeArray:
98
+ # res.append(parentNode)
99
+ # nodeArray.append(parentNode)
100
+
101
+ # i += 1
102
+
103
+ # return nodeArray
104
+
105
+ def get_dependencies(self, inObjs):
106
+ targetObjs = rt.Array()
107
+ for item in inObjs:
108
+ if rt.isValidNode(item):
109
+ rt.append(targetObjs, item)
110
+
111
+ maxcriptCode = ""
112
+ maxcriptCode += "fn pyjallib_max_skeleton_get_dependencies obj = \n"
113
+ maxcriptCode += "(\n"
114
+ maxcriptCode += " node_array = #()\n"
115
+ maxcriptCode += " res = deepCopy obj\n"
116
+ maxcriptCode += " \n"
117
+ maxcriptCode += " for each in obj do \n"
118
+ maxcriptCode += " (\n"
119
+ maxcriptCode += " isBipedObj = (classOf each.controller == BipSlave_control) or (classOf each.controller == Footsteps) or (classOf each.controller == Vertical_Horizontal_Turn)\n"
120
+ maxcriptCode += " if isBipedObj then continue\n"
121
+ maxcriptCode += "\n"
122
+ maxcriptCode += " join res (refs.dependson each.controller)\n"
123
+ maxcriptCode += "\n"
124
+ maxcriptCode += " if isproperty each #skin do ( join res (refs.dependson each.skin) )\n"
125
+ maxcriptCode += "\n"
126
+ maxcriptCode += " i = 0\n"
127
+ maxcriptCode += " while i < res.count do \n"
128
+ maxcriptCode += " (\n"
129
+ maxcriptCode += " i += 1\n"
130
+ maxcriptCode += " if classof (superclassof res[i]) != node then \n"
131
+ maxcriptCode += " join res (refs.dependson res[i])\n"
132
+ maxcriptCode += "\n"
133
+ maxcriptCode += " else if isvalidnode res[i] do\n"
134
+ maxcriptCode += " (\n"
135
+ maxcriptCode += " appendifunique node_array res[i]\n"
136
+ maxcriptCode += "\n"
137
+ maxcriptCode += " parent_node=res[i].parent\n"
138
+ maxcriptCode += " if isValidNode parent_node and findItem node_array parent_node == 0 do\n"
139
+ maxcriptCode += " ( \n"
140
+ maxcriptCode += " appendIfUnique res parent_node\n"
141
+ maxcriptCode += " appendIfUnique node_array parent_node\n"
142
+ maxcriptCode += " )\n"
143
+ maxcriptCode += " )\n"
144
+ maxcriptCode += " )\n"
145
+ maxcriptCode += " )\n"
146
+ maxcriptCode += " \n"
147
+ maxcriptCode += " return node_array\n"
148
+ maxcriptCode += ")\n"
149
+
150
+ rt.execute(maxcriptCode)
151
+ return rt.pyjallib_max_skeleton_get_dependencies(targetObjs)
152
+
153
+ def get_all_dependencies(self, inObjs, inAddonLayerName="Rig_Addon"):
154
+ """
155
+ 객체의 모든 의존성을 가져옴 (애드온 레이어 포함)
156
+
157
+ Args:
158
+ inObjs: 의존성을 확인할 객체 배열
159
+ inAddonLayerName: 애드온 레이어 이름 (기본값: "Rig_Addon")
160
+
161
+ Returns:
162
+ 모든 의존성 노드 배열 (중복 제거됨)
163
+ """
164
+ returnArray = []
165
+ nodeArray = self.get_dependencies(inObjs)
166
+
167
+
168
+ # 애드온 레이어의 노드들만 필터링
169
+ addOnArray = []
170
+ for item in nodeArray:
171
+ if item.layer.name == inAddonLayerName:
172
+ addOnArray.append(item)
173
+
174
+ # 애드온 노드들의 의존성 가져오기
175
+ addOnRefArray = []
176
+ progress = Progress("Get All Dependencies", inTotalSteps=len(addOnArray))
177
+ for i,item in enumerate(addOnArray):
178
+ refs = self.get_dependencies(item)
179
+ progress.update(i)
180
+
181
+ addOnRefArray.extend(refs)
182
+
183
+ # 모든 노드들을 returnArray에 추가 (중복 없이)
184
+ for item in nodeArray:
185
+ if item not in returnArray:
186
+ returnArray.append(item)
187
+
188
+ for item in addOnRefArray:
189
+ if item not in returnArray:
190
+ returnArray.append(item)
191
+
192
+ return returnArray
pyjallib/perforce.py CHANGED
@@ -16,10 +16,14 @@ from pathlib import Path
16
16
 
17
17
  # 로깅 설정
18
18
  logger = logging.getLogger(__name__)
19
- logger.setLevel(logging.DEBUG)
19
+
20
+ # 기본 로그 레벨은 ERROR로 설정 (디버그 모드는 생성자에서 설정)
21
+ logger.setLevel(logging.ERROR)
22
+
20
23
  # 사용자 문서 폴더 내 로그 파일 저장
21
24
  log_path = os.path.join(Path.home() / "Documents", 'Perforce.log')
22
25
  file_handler = logging.FileHandler(log_path, encoding='utf-8')
26
+ file_handler.setLevel(logging.ERROR) # 기본적으로 ERROR 레벨만 기록
23
27
  file_handler.setFormatter(logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s'))
24
28
  logger.addHandler(file_handler)
25
29
 
@@ -27,8 +31,19 @@ logger.addHandler(file_handler)
27
31
  class Perforce:
28
32
  """P4Python을 사용하여 Perforce 작업을 수행하는 클래스."""
29
33
 
30
- def __init__(self):
31
- """Perforce 인스턴스를 초기화합니다."""
34
+ def __init__(self, debug_mode: bool = False):
35
+ """Perforce 인스턴스를 초기화합니다.
36
+
37
+ Args:
38
+ debug_mode (bool): True로 설정하면 DEBUG 레벨 로그를 활성화합니다.
39
+ 기본값은 False (ERROR 레벨만 기록)
40
+ """
41
+ # 디버그 모드에 따라 로그 레벨 설정
42
+ if debug_mode:
43
+ logger.setLevel(logging.DEBUG)
44
+ file_handler.setLevel(logging.DEBUG)
45
+ logger.debug("디버그 모드가 활성화되었습니다.")
46
+
32
47
  self.p4 = P4()
33
48
  self.connected = False
34
49
  self.workspaceRoot = r""
@@ -575,11 +590,13 @@ class Perforce:
575
590
 
576
591
  return all_success
577
592
 
578
- def submit_change_list(self, change_list_number: int) -> bool:
593
+ def submit_change_list(self, change_list_number: int, auto_revert_unchanged: bool = True) -> bool:
579
594
  """체인지 리스트를 제출합니다.
580
595
 
581
596
  Args:
582
597
  change_list_number (int): 제출할 체인지 리스트 번호
598
+ auto_revert_unchanged (bool, optional): 제출 후 변경사항이 없는 체크아웃된 파일들을
599
+ 자동으로 리버트할지 여부. 기본값 True
583
600
 
584
601
  Returns:
585
602
  bool: 제출 성공 시 True, 실패 시 False
@@ -590,6 +607,11 @@ class Perforce:
590
607
  try:
591
608
  self.p4.run_submit("-c", change_list_number)
592
609
  logger.info(f"체인지 리스트 {change_list_number} 제출 성공.")
610
+
611
+ # 제출 후 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트
612
+ if auto_revert_unchanged:
613
+ self._auto_revert_unchanged_files(change_list_number)
614
+
593
615
  return True
594
616
  except P4Exception as e:
595
617
  self._handle_p4_exception(e, f"체인지 리스트 {change_list_number} 제출")
@@ -597,6 +619,117 @@ class Perforce:
597
619
  logger.warning(f"체인지 리스트 {change_list_number}에 제출할 파일이 없습니다.")
598
620
  return False
599
621
 
622
+ def _auto_revert_unchanged_files(self, change_list_number: int) -> None:
623
+ """제출 후 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트합니다.
624
+
625
+ Args:
626
+ change_list_number (int): 체인지 리스트 번호
627
+ """
628
+ logger.debug(f"체인지 리스트 {change_list_number}에서 변경사항이 없는 파일들 자동 리버트 시도...")
629
+ try:
630
+ # 체인지 리스트에서 체크아웃된 파일들 가져오기
631
+ opened_files = self.p4.run_opened("-c", change_list_number)
632
+
633
+ if not opened_files:
634
+ logger.debug(f"체인지 리스트 {change_list_number}에 체크아웃된 파일이 없습니다.")
635
+ return
636
+
637
+ unchanged_files = []
638
+ for file_info in opened_files:
639
+ file_path = file_info.get('clientFile', '')
640
+ action = file_info.get('action', '')
641
+
642
+ # edit 액션의 파일만 확인 (add, delete는 변경사항이 있음)
643
+ if action == 'edit':
644
+ try:
645
+ # p4 diff 명령으로 파일의 변경사항 확인
646
+ diff_result = self.p4.run_diff("-sa", file_path)
647
+
648
+ # diff 결과가 비어있으면 변경사항이 없음
649
+ if not diff_result:
650
+ unchanged_files.append(file_path)
651
+ logger.debug(f"파일 '{file_path}'에 변경사항이 없어 리버트 대상으로 추가")
652
+ else:
653
+ logger.debug(f"파일 '{file_path}'에 변경사항이 있어 리버트하지 않음")
654
+
655
+ except P4Exception as e:
656
+ # diff 명령 실패 시에도 리버트 대상으로 추가 (안전하게 처리)
657
+ unchanged_files.append(file_path)
658
+ logger.debug(f"파일 '{file_path}' diff 확인 실패, 리버트 대상으로 추가: {e}")
659
+ else:
660
+ logger.debug(f"파일 '{file_path}'는 {action} 액션이므로 리버트하지 않음")
661
+
662
+ # 변경사항이 없는 파일들을 리버트
663
+ if unchanged_files:
664
+ logger.info(f"체인지 리스트 {change_list_number}에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 시도...")
665
+ for file_path in unchanged_files:
666
+ try:
667
+ self.p4.run_revert("-c", change_list_number, file_path)
668
+ logger.info(f"파일 '{file_path}' 자동 리버트 완료")
669
+ except P4Exception as e:
670
+ self._handle_p4_exception(e, f"파일 '{file_path}' 자동 리버트")
671
+ logger.info(f"체인지 리스트 {change_list_number}에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 완료")
672
+ else:
673
+ logger.debug(f"체인지 리스트 {change_list_number}에서 변경사항이 없는 파일이 없습니다.")
674
+
675
+ # default change list에서도 변경사항이 없는 파일들 처리
676
+ self._auto_revert_unchanged_files_in_default_changelist()
677
+
678
+ except P4Exception as e:
679
+ self._handle_p4_exception(e, f"체인지 리스트 {change_list_number} 자동 리버트 처리")
680
+
681
+ def _auto_revert_unchanged_files_in_default_changelist(self) -> None:
682
+ """default change list에서 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트합니다."""
683
+ logger.debug("default change list에서 변경사항이 없는 파일들 자동 리버트 시도...")
684
+ try:
685
+ # default change list에서 체크아웃된 파일들 가져오기
686
+ opened_files = self.p4.run_opened("-c", "default")
687
+
688
+ if not opened_files:
689
+ logger.debug("default change list에 체크아웃된 파일이 없습니다.")
690
+ return
691
+
692
+ unchanged_files = []
693
+ for file_info in opened_files:
694
+ file_path = file_info.get('clientFile', '')
695
+ action = file_info.get('action', '')
696
+
697
+ # edit 액션의 파일만 확인 (add, delete는 변경사항이 있음)
698
+ if action == 'edit':
699
+ try:
700
+ # p4 diff 명령으로 파일의 변경사항 확인
701
+ diff_result = self.p4.run_diff("-sa", file_path)
702
+
703
+ # diff 결과가 비어있으면 변경사항이 없음
704
+ if not diff_result:
705
+ unchanged_files.append(file_path)
706
+ logger.debug(f"default change list의 파일 '{file_path}'에 변경사항이 없어 리버트 대상으로 추가")
707
+ else:
708
+ logger.debug(f"default change list의 파일 '{file_path}'에 변경사항이 있어 리버트하지 않음")
709
+
710
+ except P4Exception as e:
711
+ # diff 명령 실패 시에도 리버트 대상으로 추가 (안전하게 처리)
712
+ unchanged_files.append(file_path)
713
+ logger.debug(f"default change list의 파일 '{file_path}' diff 확인 실패, 리버트 대상으로 추가: {e}")
714
+ else:
715
+ logger.debug(f"default change list의 파일 '{file_path}'는 {action} 액션이므로 리버트하지 않음")
716
+
717
+ # 변경사항이 없는 파일들을 리버트
718
+ if unchanged_files:
719
+ logger.info(f"default change list에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 시도...")
720
+ for file_path in unchanged_files:
721
+ try:
722
+ self.p4.run_revert(file_path)
723
+ logger.info(f"default change list의 파일 '{file_path}' 자동 리버트 완료")
724
+ except P4Exception as e:
725
+ self._handle_p4_exception(e, f"default change list의 파일 '{file_path}' 자동 리버트")
726
+ logger.info(f"default change list에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 완료")
727
+ else:
728
+ logger.debug("default change list에서 변경사항이 없는 파일이 없습니다.")
729
+
730
+ except P4Exception as e:
731
+ self._handle_p4_exception(e, "default change list 자동 리버트 처리")
732
+
600
733
  def revert_change_list(self, change_list_number: int) -> bool:
601
734
  """체인지 리스트를 되돌리고 삭제합니다.
602
735
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyjallib
3
- Version: 0.1.13
3
+ Version: 0.1.15
4
4
  Summary: A utility library for 3D game character development pipelines.
5
5
  Author-email: Dongseok Kim <jalnagakds@gmail.com>
6
6
  Requires-Python: >=3.10
@@ -1,13 +1,13 @@
1
- pyjallib/__init__.py,sha256=ntM7q_hmCFkCShsMra8MKtcPGZf4z-MYuPIc3jyp6aM,509
1
+ pyjallib/__init__.py,sha256=jf7VzQoweVj0AiRCD4CeHLUjlvrcoxyKp5rNDL22Drc,509
2
2
  pyjallib/namePart.py,sha256=lKIiOVkWrtAW-D3nuv--vHmdAnlQeVPaXLYUDhcr8QU,24177
3
3
  pyjallib/nameToPath.py,sha256=aBeezepLYdpv3VYxnQ2c4ZWzz2WjticXjkdbAIlVa1k,4676
4
4
  pyjallib/naming.py,sha256=b2C-P9VWV4Q2StqkizEwABblYOC5g6sXHzN0KpOZ_Ys,37419
5
5
  pyjallib/namingConfig.py,sha256=QGpK5mCnRiclKqNKz3GJ2PeJO8fbVitAEdqWwnwo8oA,34127
6
- pyjallib/perforce.py,sha256=MhG4nCJxvrCBlEKmZXVRI93jcfTcJHlM_xn002OxXU8,48032
6
+ pyjallib/perforce.py,sha256=pkCDaso4TAs-au0E8X1JwXPJ-TVbO2Fjz4k_Wh3z8bc,56078
7
7
  pyjallib/py.typed,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
8
8
  pyjallib/reloadModules.py,sha256=RAEG3IxzJ0TlsjvnZwJt56JOkc2j8voqAnRbfQuZ44g,1151
9
9
  pyjallib/ConfigFiles/namingConfig.json,sha256=Ov4bbVJb6qodPaooU63e11YUMGXXPWFAA4AQq1sLBYU,1486
10
- pyjallib/max/__init__.py,sha256=UCvMt5FFWYQz2-ifPyI4ExwqxpPHx5WJEUDREW-QLwc,1649
10
+ pyjallib/max/__init__.py,sha256=D5yORjy_n4b2MPq6suG3Wj7oq7hROr8jWUoUu8JSCtU,1771
11
11
  pyjallib/max/align.py,sha256=HKjCViQCuicGmtvHB6xxVv4BEGEBGtV2gO3NvR_6R2A,5183
12
12
  pyjallib/max/anim.py,sha256=scfxLSSXfFAlxgFi_qePrbONYc4mpKB8mXIxtYtFtl0,29032
13
13
  pyjallib/max/autoClavicle.py,sha256=m5rs313-qkaHfs9TUr98HYRVFdB25E_fW-YiY4o9zhE,9559
@@ -17,7 +17,7 @@ pyjallib/max/boneChain.py,sha256=qTvbnJVuBchOdOBhi8wPxPClQ-5Wbkhc7Y2H47nUjCc,574
17
17
  pyjallib/max/constraint.py,sha256=93g-X0aZHtZMKXVKr8xMjIhbKou61yc2b3ubQKJquBs,40589
18
18
  pyjallib/max/fbxHandler.py,sha256=rVcnxZh5_Cu012wKIFgiGO_XvZF07Oy3jezxUhIpmSo,8703
19
19
  pyjallib/max/groinBone.py,sha256=yBexwDTrnXViP8DRACIMnnpJWErbn9RIA61_d3iADCc,9193
20
- pyjallib/max/header.py,sha256=miL-dCC1z1syugn9_L-DN0HbdPwTdcvJS0e_UlT8H5A,4199
20
+ pyjallib/max/header.py,sha256=qqiaSLACsa0nv15cKiqwhgyHrPYI4MYHFzFZpfzY5pw,4380
21
21
  pyjallib/max/helper.py,sha256=Na3jFRwLsjHh4rz0Tk_r_CwHQxOA6n8LhDRA9x5xcSk,18018
22
22
  pyjallib/max/hip.py,sha256=RavoZgK7zP2sXDa4A8CXEbHB6g8MQ-604XryZbStx0E,12684
23
23
  pyjallib/max/kneeBone.py,sha256=cs5bCZtHxgLf6u80er1rV_PBF_SizqRgcTjYmy1q3IM,25316
@@ -27,8 +27,10 @@ pyjallib/max/mirror.py,sha256=TcbfZXSk-VJQstNqAmD6VGCqYBF9bMuJtFTg-6SiGdQ,14505
27
27
  pyjallib/max/mocap.py,sha256=tD0yhan8GBYLBZtdpGBlYC-DzdQkT4gsbqeo5lpyQXU,12544
28
28
  pyjallib/max/morph.py,sha256=I8HRYx4NznL6GZL4CbT9iTv05SeaBW_mJJ4PzMxCBkw,12664
29
29
  pyjallib/max/name.py,sha256=DcJt2td-N7vfUGyWazdGTD4-0JW-noa7z5nwc6SHm6I,15337
30
+ pyjallib/max/progress.py,sha256=0_ry9NiYJZGqwBtvR-oGwV40Z57AtOBG0RcuQwwOeq4,1162
30
31
  pyjallib/max/rootMotion.py,sha256=H9kvh9dx4zLLBYuigGyN0XZsdGAF5d7YRBdaokZmCiw,31399
31
32
  pyjallib/max/select.py,sha256=HMJD2WNX3zVBEeYrj0UX2YXM3fHNItfw6UtQSItNsoU,9487
33
+ pyjallib/max/skeleton.py,sha256=4U4N2jA0GX4HqX1UOuUM1Yp3eud5ghqSRIO7FV-6poA,8138
32
34
  pyjallib/max/skin.py,sha256=5mBzG2wSUxoGlkFeb9Ys8uUxOwuZRGeqUMTI9LiWWZU,41937
33
35
  pyjallib/max/toolManager.py,sha256=ya6beAGzk1_culw4H7lBdr7klnS-Yl8mVGg13A41Q8A,3185
34
36
  pyjallib/max/twistBone.py,sha256=VPZLDE5V6KEW-i5gAberggEeR2YRzLwsFfFQBT4AB1U,17295
@@ -42,6 +44,6 @@ pyjallib/max/macro/jal_macro_helper.py,sha256=hd8e5x56aq7Qt0g-hP5bY0p-njVy8ja77_
42
44
  pyjallib/max/macro/jal_macro_link.py,sha256=E8i3z2xsrQiGDEz4Qoxc75hkpalzS95mOMcIic0J-Fc,1193
43
45
  pyjallib/max/macro/jal_macro_select.py,sha256=jeSFR_mqqudTTrZE1rU6qifJ4g441cYxXWcHPTWh1CU,2289
44
46
  pyjallib/max/ui/Container.py,sha256=QSk3oCqhfiR4aglSSkherRGAyPFqMRUt83L-0ENBz-s,5571
45
- pyjallib-0.1.13.dist-info/METADATA,sha256=8CqMSZqqGuOjrwZtXYCzOt5f87-YXJMKoUSoAaAGRvs,870
46
- pyjallib-0.1.13.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
- pyjallib-0.1.13.dist-info/RECORD,,
47
+ pyjallib-0.1.15.dist-info/METADATA,sha256=syGZwRd9A7gdeiOYxG9QpXz-o7qkMZhrRsvwEaEyCYo,870
48
+ pyjallib-0.1.15.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
+ pyjallib-0.1.15.dist-info/RECORD,,