pyjallib 0.1.14__py3-none-any.whl → 0.1.16__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.14'
9
+ __version__ = '0.1.16'
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,185 @@
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
+ addOnArray = []
169
+ for item in nodeArray:
170
+ if item.layer.name == inAddonLayerName:
171
+ addOnArray.append(item)
172
+
173
+ # 애드온 노드들의 의존성 가져오기
174
+ addOnRefArray = self.get_dependencies(addOnArray)
175
+
176
+ # 모든 노드들을 returnArray에 추가 (중복 없이)
177
+ for item in nodeArray:
178
+ if item not in returnArray:
179
+ returnArray.append(item)
180
+
181
+ for item in addOnRefArray:
182
+ if item not in returnArray:
183
+ returnArray.append(item)
184
+
185
+ return returnArray
pyjallib/perforce.py CHANGED
@@ -604,20 +604,31 @@ class Perforce:
604
604
  if not self._is_connected():
605
605
  return False
606
606
  logger.info(f"체인지 리스트 {change_list_number} 제출 시도...")
607
+
608
+ submit_success = False
607
609
  try:
608
610
  self.p4.run_submit("-c", change_list_number)
609
611
  logger.info(f"체인지 리스트 {change_list_number} 제출 성공.")
610
-
611
- # 제출 후 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트
612
- if auto_revert_unchanged:
613
- self._auto_revert_unchanged_files(change_list_number)
614
-
615
- return True
612
+ submit_success = True
616
613
  except P4Exception as e:
617
614
  self._handle_p4_exception(e, f"체인지 리스트 {change_list_number} 제출")
618
615
  if any("nothing to submit" in err.lower() for err in self.p4.errors):
619
616
  logger.warning(f"체인지 리스트 {change_list_number}에 제출할 파일이 없습니다.")
620
- return False
617
+ submit_success = False
618
+
619
+ # 제출 성공 여부와 관계없이 후속 작업 실행
620
+ try:
621
+ # 제출 후 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트
622
+ if auto_revert_unchanged:
623
+ self._auto_revert_unchanged_files(change_list_number)
624
+ self._auto_revert_unchanged_files_in_default_changelist()
625
+
626
+ # 빈 체인지 리스트 삭제
627
+ self.delete_empty_change_list(change_list_number)
628
+ except Exception as e:
629
+ logger.error(f"체인지 리스트 {change_list_number} 제출 후 후속 작업 중 오류 발생: {e}")
630
+
631
+ return submit_success
621
632
 
622
633
  def _auto_revert_unchanged_files(self, change_list_number: int) -> None:
623
634
  """제출 후 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트합니다.
@@ -671,10 +682,60 @@ class Perforce:
671
682
  logger.info(f"체인지 리스트 {change_list_number}에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 완료")
672
683
  else:
673
684
  logger.debug(f"체인지 리스트 {change_list_number}에서 변경사항이 없는 파일이 없습니다.")
685
+
686
+ # default change list에서도 변경사항이 없는 파일들 처리
687
+ self._auto_revert_unchanged_files_in_default_changelist()
674
688
 
675
689
  except P4Exception as e:
676
690
  self._handle_p4_exception(e, f"체인지 리스트 {change_list_number} 자동 리버트 처리")
677
691
 
692
+ def _auto_revert_unchanged_files_in_default_changelist(self) -> None:
693
+ """default change list에서 변경사항이 없는 체크아웃된 파일들을 자동으로 리버트합니다."""
694
+ logger.debug("default change list에서 변경사항이 없는 파일들 자동 리버트 시도...")
695
+ try:
696
+ # get_default_change_list를 사용해서 default change list의 파일들 가져오기
697
+ default_cl_info = self.get_default_change_list()
698
+
699
+ if not default_cl_info or not default_cl_info.get('Files'):
700
+ logger.debug("default change list에 체크아웃된 파일이 없습니다.")
701
+ return
702
+
703
+ files_list = default_cl_info.get('Files', [])
704
+ unchanged_files = []
705
+
706
+ for file_path in files_list:
707
+ try:
708
+ # p4 diff 명령으로 파일의 변경사항 확인
709
+ diff_result = self.p4.run_diff("-sa", file_path)
710
+
711
+ # diff 결과가 비어있으면 변경사항이 없음
712
+ if not diff_result:
713
+ unchanged_files.append(file_path)
714
+ logger.debug(f"default change list의 파일 '{file_path}'에 변경사항이 없어 리버트 대상으로 추가")
715
+ else:
716
+ logger.debug(f"default change list의 파일 '{file_path}'에 변경사항이 있어 리버트하지 않음")
717
+
718
+ except P4Exception as e:
719
+ # diff 명령 실패 시에도 리버트 대상으로 추가 (안전하게 처리)
720
+ unchanged_files.append(file_path)
721
+ logger.debug(f"default change list의 파일 '{file_path}' diff 확인 실패, 리버트 대상으로 추가: {e}")
722
+
723
+ # 변경사항이 없는 파일들을 리버트
724
+ if unchanged_files:
725
+ logger.info(f"default change list에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 시도...")
726
+ for file_path in unchanged_files:
727
+ try:
728
+ self.p4.run_revert(file_path)
729
+ logger.info(f"default change list의 파일 '{file_path}' 자동 리버트 완료")
730
+ except P4Exception as e:
731
+ self._handle_p4_exception(e, f"default change list의 파일 '{file_path}' 자동 리버트")
732
+ logger.info(f"default change list에서 변경사항이 없는 파일 {len(unchanged_files)}개 자동 리버트 완료")
733
+ else:
734
+ logger.debug("default change list에서 변경사항이 없는 파일이 없습니다.")
735
+
736
+ except P4Exception as e:
737
+ self._handle_p4_exception(e, "default change list 자동 리버트 처리")
738
+
678
739
  def revert_change_list(self, change_list_number: int) -> bool:
679
740
  """체인지 리스트를 되돌리고 삭제합니다.
680
741
 
@@ -1118,3 +1179,29 @@ class Perforce:
1118
1179
 
1119
1180
  logger.info(f"다른 사용자에 의해 체크아웃된 파일: {len(files_by_others)}개")
1120
1181
  return files_by_others
1182
+
1183
+ def get_default_change_list(self) -> dict:
1184
+ """default change list의 정보를 가져옵니다.
1185
+
1186
+ Returns:
1187
+ dict: get_change_list_by_number와 동일한 형태의 딕셔너리
1188
+ """
1189
+ if not self._is_connected():
1190
+ return {}
1191
+ logger.debug("default change list 정보 조회 중...")
1192
+ try:
1193
+ opened_files = self.p4.run_opened("-c", "default")
1194
+ files_list = [f.get('clientFile', '') for f in opened_files]
1195
+ result = {
1196
+ 'Change': 'default',
1197
+ 'Description': 'Default change',
1198
+ 'User': getattr(self.p4, 'user', ''),
1199
+ 'Client': getattr(self.p4, 'client', ''),
1200
+ 'Status': 'pending',
1201
+ 'Files': files_list
1202
+ }
1203
+ logger.info(f"default change list 정보 조회 완료: {len(files_list)}개 파일")
1204
+ return result
1205
+ except P4Exception as e:
1206
+ self._handle_p4_exception(e, "default change list 정보 조회")
1207
+ return {}
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyjallib
3
- Version: 0.1.14
3
+ Version: 0.1.16
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=or1aolPeqzUTuj7mEsvepJ3vXibO18C4SA60Ypeahu0,509
1
+ pyjallib/__init__.py,sha256=x9MQjDWegE6dAs6jPCgRy9ymBM8DqQ2XpSqGgmLY-tA,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=Z3hMO-3RMFIiNX0kxV2VOhu-euM0k5nLEtuu9QWp410,52605
6
+ pyjallib/perforce.py,sha256=VQswiyQ6CHCAgFJO5MjC2Su1qNU4yfAQmFZGapNR6_g,57329
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=tjI1h5zObL0TgX3gkebiqosTlEOPglaKfIbsQ14ET50,7896
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.14.dist-info/METADATA,sha256=7Zzp4ny8Umo3ZNETlrKbLIbtYb5aJc_Um78xtTDlOYw,870
46
- pyjallib-0.1.14.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
47
- pyjallib-0.1.14.dist-info/RECORD,,
47
+ pyjallib-0.1.16.dist-info/METADATA,sha256=zPdi6nX3h5VvUBW371qgdfefTHTdBY-oB4ge8nYVzQs,870
48
+ pyjallib-0.1.16.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
49
+ pyjallib-0.1.16.dist-info/RECORD,,