pyjallib 0.1.12__py3-none-any.whl → 0.1.13__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 +1 -1
- pyjallib/max/__init__.py +8 -4
- pyjallib/max/anim.py +84 -0
- pyjallib/max/autoClavicle.py +1 -1
- pyjallib/max/bip.py +89 -79
- pyjallib/max/bone.py +84 -22
- pyjallib/max/boneChain.py +19 -22
- pyjallib/max/fbxHandler.py +215 -0
- pyjallib/max/groinBone.py +3 -3
- pyjallib/max/header.py +10 -13
- pyjallib/max/hip.py +4 -4
- pyjallib/max/kneeBone.py +44 -20
- pyjallib/max/layer.py +12 -6
- pyjallib/max/mocap.py +376 -0
- pyjallib/max/rootMotion.py +639 -0
- pyjallib/max/toolManager.py +92 -0
- pyjallib/max/twistBone.py +5 -1
- pyjallib/max/volumeBone.py +2 -1
- pyjallib/perforce.py +34 -0
- {pyjallib-0.1.12.dist-info → pyjallib-0.1.13.dist-info}/METADATA +1 -1
- {pyjallib-0.1.12.dist-info → pyjallib-0.1.13.dist-info}/RECORD +22 -18
- {pyjallib-0.1.12.dist-info → pyjallib-0.1.13.dist-info}/WHEEL +0 -0
@@ -0,0 +1,92 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
ToolManager 모듈 - 3DS Max에서 실행되는 도구들을 관리
|
6
|
+
도구 인스턴스 생성, 닫기 등을 담당
|
7
|
+
"""
|
8
|
+
|
9
|
+
from PySide2 import QtWidgets, QtCore
|
10
|
+
import gc
|
11
|
+
|
12
|
+
class ToolManager:
|
13
|
+
def __init__(self):
|
14
|
+
self.tools = {} # {tool_class_name: [instances]} 형태로 관리
|
15
|
+
|
16
|
+
def register_tool(self, tool_instance):
|
17
|
+
"""도구 인스턴스를 등록합니다"""
|
18
|
+
class_name = tool_instance.__class__.__name__
|
19
|
+
|
20
|
+
if class_name not in self.tools:
|
21
|
+
self.tools[class_name] = []
|
22
|
+
|
23
|
+
self.tools[class_name].append(tool_instance)
|
24
|
+
|
25
|
+
def close_tool_by_type(self, tool_class):
|
26
|
+
"""특정 유형의 도구를 모두 닫습니다"""
|
27
|
+
class_name = tool_class.__name__
|
28
|
+
|
29
|
+
if class_name not in self.tools:
|
30
|
+
return
|
31
|
+
|
32
|
+
# 해당 클래스의 모든 인스턴스 정리
|
33
|
+
for tool in self.tools[class_name]:
|
34
|
+
try:
|
35
|
+
if hasattr(tool, 'close'):
|
36
|
+
tool.close()
|
37
|
+
if hasattr(tool, 'deleteLater'):
|
38
|
+
tool.deleteLater()
|
39
|
+
except (RuntimeError, AttributeError) as e:
|
40
|
+
print(f"도구 닫기 오류: {e}")
|
41
|
+
|
42
|
+
# 목록 비우기
|
43
|
+
self.tools[class_name] = []
|
44
|
+
|
45
|
+
# 추가적으로 QApplication.allWidgets()를 통한 검사
|
46
|
+
try:
|
47
|
+
window_title = None
|
48
|
+
if hasattr(tool_class, 'windowTitle'):
|
49
|
+
window_title = tool_class.windowTitle
|
50
|
+
|
51
|
+
for widget in QtWidgets.QApplication.allWidgets():
|
52
|
+
if (isinstance(widget, QtWidgets.QDialog) and
|
53
|
+
((window_title and hasattr(widget, 'windowTitle') and widget.windowTitle() == window_title) or
|
54
|
+
widget.__class__.__name__ == class_name)):
|
55
|
+
try:
|
56
|
+
widget.close()
|
57
|
+
widget.deleteLater()
|
58
|
+
except:
|
59
|
+
pass
|
60
|
+
except Exception as e:
|
61
|
+
print(f"위젯 검색 오류: {e}")
|
62
|
+
|
63
|
+
# 가비지 컬렉션 수행
|
64
|
+
gc.collect()
|
65
|
+
|
66
|
+
def show_tool(self, tool_class, **kwargs):
|
67
|
+
"""
|
68
|
+
도구를 표시합니다. 중복 실행을 방지하고 항상 새 인스턴스를 생성합니다.
|
69
|
+
|
70
|
+
Args:
|
71
|
+
tool_class: 도구 클래스
|
72
|
+
**kwargs: 도구 클래스 생성자에 전달할 인자들
|
73
|
+
|
74
|
+
Returns:
|
75
|
+
새로 생성된 도구 인스턴스
|
76
|
+
"""
|
77
|
+
# 기존 인스턴스 모두 정리
|
78
|
+
self.close_tool_by_type(tool_class)
|
79
|
+
|
80
|
+
# 약간의 지연을 두어 정리 완료를 기다림
|
81
|
+
QtCore.QTimer.singleShot(50, lambda: None)
|
82
|
+
|
83
|
+
# 새 인스턴스 생성
|
84
|
+
tool_instance = tool_class(**kwargs)
|
85
|
+
|
86
|
+
# 도구 등록
|
87
|
+
self.register_tool(tool_instance)
|
88
|
+
|
89
|
+
# 도구 표시
|
90
|
+
tool_instance.show()
|
91
|
+
|
92
|
+
return tool_instance
|
pyjallib/max/twistBone.py
CHANGED
@@ -258,6 +258,9 @@ class TwistBone:
|
|
258
258
|
twistBoneRotListController.setActive(twistBoneRotListController.count)
|
259
259
|
twistBoneRotListController.weight[0] = 100.0
|
260
260
|
|
261
|
+
# 첫 번째 트위스트 본을 boneChainArray에 추가
|
262
|
+
boneChainArray.append(twistBone)
|
263
|
+
|
261
264
|
if twistNum > 1:
|
262
265
|
lastBone = self.bone.create_nub_bone(boneName, 2)
|
263
266
|
lastBone.name = self.name.replace_name_part("Index", boneName, str(twistNum))
|
@@ -320,7 +323,8 @@ class TwistBone:
|
|
320
323
|
if not inBoneChain or inBoneChain.is_empty():
|
321
324
|
return None
|
322
325
|
|
323
|
-
# 기존 객체 삭제
|
326
|
+
# 기존 객체 삭제 (delete_all 대신 delete 사용)
|
327
|
+
# delete는 bones와 helpers만 삭제하고 sourceBones와 parameters는 유지함
|
324
328
|
inBoneChain.delete()
|
325
329
|
|
326
330
|
# BoneChain에서 필요한 정보 추출
|
pyjallib/max/volumeBone.py
CHANGED
@@ -275,7 +275,8 @@ class VolumeBone: # Updated class name to match the new file name
|
|
275
275
|
if not inBoneChain or inBoneChain.is_empty():
|
276
276
|
return None
|
277
277
|
|
278
|
-
# 기존 객체 삭제
|
278
|
+
# 기존 객체 삭제 (delete_all 대신 delete 사용)
|
279
|
+
# delete는 bones와 helpers만 삭제하고 sourceBones와 parameters는 유지함
|
279
280
|
inBoneChain.delete()
|
280
281
|
|
281
282
|
# BoneChain에서 필요한 정보 추출
|
pyjallib/perforce.py
CHANGED
@@ -771,6 +771,40 @@ class Perforce:
|
|
771
771
|
self._handle_p4_exception(e, f"파일/폴더 업데이트 필요 여부 확인 ({processed_paths})")
|
772
772
|
return False
|
773
773
|
|
774
|
+
def is_file_in_perforce(self, file_path: str) -> bool:
|
775
|
+
"""파일이 Perforce에 속하는지 확인합니다.
|
776
|
+
|
777
|
+
Args:
|
778
|
+
file_path (str): 확인할 파일 경로
|
779
|
+
|
780
|
+
Returns:
|
781
|
+
bool: 파일이 Perforce에 속하면 True, 아니면 False
|
782
|
+
"""
|
783
|
+
if not self._is_connected():
|
784
|
+
return False
|
785
|
+
|
786
|
+
logger.debug(f"파일 '{file_path}'가 Perforce에 속하는지 확인 중...")
|
787
|
+
try:
|
788
|
+
# p4 files 명령으로 파일 정보 조회
|
789
|
+
file_info = self.p4.run_files(file_path)
|
790
|
+
|
791
|
+
# 파일 정보가 있고, 'no such file(s)' 오류가 없는 경우
|
792
|
+
if file_info and not any("no such file(s)" in str(err).lower() for err in self.p4.errors):
|
793
|
+
logger.info(f"파일 '{file_path}'가 Perforce에 존재합니다.")
|
794
|
+
return True
|
795
|
+
else:
|
796
|
+
logger.info(f"파일 '{file_path}'가 Perforce에 존재하지 않습니다.")
|
797
|
+
return False
|
798
|
+
|
799
|
+
except P4Exception as e:
|
800
|
+
# 파일이 존재하지 않는 경우는 일반적인 상황이므로 경고 레벨로 로깅
|
801
|
+
if any("no such file(s)" in err.lower() for err in self.p4.errors):
|
802
|
+
logger.info(f"파일 '{file_path}'가 Perforce에 존재하지 않습니다.")
|
803
|
+
return False
|
804
|
+
else:
|
805
|
+
self._handle_p4_exception(e, f"파일 '{file_path}' Perforce 존재 여부 확인")
|
806
|
+
return False
|
807
|
+
|
774
808
|
def sync_files(self, file_paths: list) -> bool:
|
775
809
|
"""파일이나 폴더를 동기화합니다.
|
776
810
|
|
@@ -1,34 +1,38 @@
|
|
1
|
-
pyjallib/__init__.py,sha256=
|
1
|
+
pyjallib/__init__.py,sha256=ntM7q_hmCFkCShsMra8MKtcPGZf4z-MYuPIc3jyp6aM,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=
|
6
|
+
pyjallib/perforce.py,sha256=MhG4nCJxvrCBlEKmZXVRI93jcfTcJHlM_xn002OxXU8,48032
|
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=
|
10
|
+
pyjallib/max/__init__.py,sha256=UCvMt5FFWYQz2-ifPyI4ExwqxpPHx5WJEUDREW-QLwc,1649
|
11
11
|
pyjallib/max/align.py,sha256=HKjCViQCuicGmtvHB6xxVv4BEGEBGtV2gO3NvR_6R2A,5183
|
12
|
-
pyjallib/max/anim.py,sha256=
|
13
|
-
pyjallib/max/autoClavicle.py,sha256=
|
14
|
-
pyjallib/max/bip.py,sha256=
|
15
|
-
pyjallib/max/bone.py,sha256=
|
16
|
-
pyjallib/max/boneChain.py,sha256=
|
12
|
+
pyjallib/max/anim.py,sha256=scfxLSSXfFAlxgFi_qePrbONYc4mpKB8mXIxtYtFtl0,29032
|
13
|
+
pyjallib/max/autoClavicle.py,sha256=m5rs313-qkaHfs9TUr98HYRVFdB25E_fW-YiY4o9zhE,9559
|
14
|
+
pyjallib/max/bip.py,sha256=uhnNwt9EOP1ezPEBf7uIAqveBh3afzXbgr2ydJzTo0U,31471
|
15
|
+
pyjallib/max/bone.py,sha256=ImFUqdUoKeXD44rYsccJdgLClbqazraGmsv66I-tyGI,52923
|
16
|
+
pyjallib/max/boneChain.py,sha256=qTvbnJVuBchOdOBhi8wPxPClQ-5Wbkhc7Y2H47nUjCc,5740
|
17
17
|
pyjallib/max/constraint.py,sha256=93g-X0aZHtZMKXVKr8xMjIhbKou61yc2b3ubQKJquBs,40589
|
18
|
-
pyjallib/max/
|
19
|
-
pyjallib/max/
|
18
|
+
pyjallib/max/fbxHandler.py,sha256=rVcnxZh5_Cu012wKIFgiGO_XvZF07Oy3jezxUhIpmSo,8703
|
19
|
+
pyjallib/max/groinBone.py,sha256=yBexwDTrnXViP8DRACIMnnpJWErbn9RIA61_d3iADCc,9193
|
20
|
+
pyjallib/max/header.py,sha256=miL-dCC1z1syugn9_L-DN0HbdPwTdcvJS0e_UlT8H5A,4199
|
20
21
|
pyjallib/max/helper.py,sha256=Na3jFRwLsjHh4rz0Tk_r_CwHQxOA6n8LhDRA9x5xcSk,18018
|
21
|
-
pyjallib/max/hip.py,sha256=
|
22
|
-
pyjallib/max/kneeBone.py,sha256=
|
23
|
-
pyjallib/max/layer.py,sha256=
|
22
|
+
pyjallib/max/hip.py,sha256=RavoZgK7zP2sXDa4A8CXEbHB6g8MQ-604XryZbStx0E,12684
|
23
|
+
pyjallib/max/kneeBone.py,sha256=cs5bCZtHxgLf6u80er1rV_PBF_SizqRgcTjYmy1q3IM,25316
|
24
|
+
pyjallib/max/layer.py,sha256=luDAzWzXXPiRq7v5lm-xv0Vd8meEEe7HSoX6ZoKpvu0,8825
|
24
25
|
pyjallib/max/link.py,sha256=J3z9nkP8ZxAh9yYhR16tjQFCJTCYZMSB0MGbSHfA7uI,2592
|
25
26
|
pyjallib/max/mirror.py,sha256=TcbfZXSk-VJQstNqAmD6VGCqYBF9bMuJtFTg-6SiGdQ,14505
|
27
|
+
pyjallib/max/mocap.py,sha256=tD0yhan8GBYLBZtdpGBlYC-DzdQkT4gsbqeo5lpyQXU,12544
|
26
28
|
pyjallib/max/morph.py,sha256=I8HRYx4NznL6GZL4CbT9iTv05SeaBW_mJJ4PzMxCBkw,12664
|
27
29
|
pyjallib/max/name.py,sha256=DcJt2td-N7vfUGyWazdGTD4-0JW-noa7z5nwc6SHm6I,15337
|
30
|
+
pyjallib/max/rootMotion.py,sha256=H9kvh9dx4zLLBYuigGyN0XZsdGAF5d7YRBdaokZmCiw,31399
|
28
31
|
pyjallib/max/select.py,sha256=HMJD2WNX3zVBEeYrj0UX2YXM3fHNItfw6UtQSItNsoU,9487
|
29
32
|
pyjallib/max/skin.py,sha256=5mBzG2wSUxoGlkFeb9Ys8uUxOwuZRGeqUMTI9LiWWZU,41937
|
30
|
-
pyjallib/max/
|
31
|
-
pyjallib/max/
|
33
|
+
pyjallib/max/toolManager.py,sha256=ya6beAGzk1_culw4H7lBdr7klnS-Yl8mVGg13A41Q8A,3185
|
34
|
+
pyjallib/max/twistBone.py,sha256=VPZLDE5V6KEW-i5gAberggEeR2YRzLwsFfFQBT4AB1U,17295
|
35
|
+
pyjallib/max/volumeBone.py,sha256=xt58rhMeA1YQQl6_y3GPikYLJXTfyoASSsnT0Nt285E,14776
|
32
36
|
pyjallib/max/ConfigFiles/3DSMaxNamingConfig.json,sha256=PBUYawCELG0aLNRdTh6j-Yka4eNdmpF4P8iRyp0Ngpg,3717
|
33
37
|
pyjallib/max/ConfigFiles/Default_3DSMaxNamingConfig.json,sha256=PBUYawCELG0aLNRdTh6j-Yka4eNdmpF4P8iRyp0Ngpg,3717
|
34
38
|
pyjallib/max/macro/jal_macro_align.py,sha256=_Iqwskz0i4AVlP_AhDrqHwhLml6zoDWkVAxPF3AKqEQ,4286
|
@@ -38,6 +42,6 @@ pyjallib/max/macro/jal_macro_helper.py,sha256=hd8e5x56aq7Qt0g-hP5bY0p-njVy8ja77_
|
|
38
42
|
pyjallib/max/macro/jal_macro_link.py,sha256=E8i3z2xsrQiGDEz4Qoxc75hkpalzS95mOMcIic0J-Fc,1193
|
39
43
|
pyjallib/max/macro/jal_macro_select.py,sha256=jeSFR_mqqudTTrZE1rU6qifJ4g441cYxXWcHPTWh1CU,2289
|
40
44
|
pyjallib/max/ui/Container.py,sha256=QSk3oCqhfiR4aglSSkherRGAyPFqMRUt83L-0ENBz-s,5571
|
41
|
-
pyjallib-0.1.
|
42
|
-
pyjallib-0.1.
|
43
|
-
pyjallib-0.1.
|
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,,
|
File without changes
|