pyjallib 0.1.15__py3-none-any.whl → 0.1.17__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 +4 -2
- pyjallib/logger.py +201 -0
- pyjallib/max/bip.py +0 -21
- pyjallib/max/skeleton.py +1 -8
- pyjallib/naming.py +4 -1
- pyjallib/perforce.py +213 -262
- pyjallib/progressEvent.py +75 -0
- pyjallib/ue5/ConfigFiles/UE5NamingConfig.json +487 -0
- pyjallib/ue5/__init__.py +170 -0
- pyjallib/ue5/disableInterchangeFrameWork.py +82 -0
- pyjallib/ue5/inUnreal/__init__.py +95 -0
- pyjallib/ue5/inUnreal/animationImporter.py +114 -0
- pyjallib/ue5/inUnreal/baseImporter.py +184 -0
- pyjallib/ue5/inUnreal/importerSettings.py +179 -0
- pyjallib/ue5/inUnreal/skeletalMeshImporter.py +112 -0
- pyjallib/ue5/inUnreal/skeletonImporter.py +105 -0
- pyjallib/ue5/logger.py +200 -0
- pyjallib/ue5/templateProcessor.py +254 -0
- pyjallib/ue5/templates/__init__.py +106 -0
- pyjallib/ue5/templates/animImportTemplate.py +22 -0
- pyjallib/ue5/templates/skeletalMeshImportTemplate.py +22 -0
- pyjallib/ue5/templates/skeletonImportTemplate.py +21 -0
- {pyjallib-0.1.15.dist-info → pyjallib-0.1.17.dist-info}/METADATA +1 -1
- {pyjallib-0.1.15.dist-info → pyjallib-0.1.17.dist-info}/RECORD +25 -8
- {pyjallib-0.1.15.dist-info → pyjallib-0.1.17.dist-info}/WHEEL +0 -0
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.
|
9
|
+
__version__ = '0.1.17'
|
10
10
|
|
11
11
|
# reload_modules 함수를 패키지 레벨에서 사용 가능하게 함
|
12
12
|
from pyjallib.namePart import NamePart, NamePartType
|
@@ -14,4 +14,6 @@ from pyjallib.naming import Naming
|
|
14
14
|
from pyjallib.namingConfig import NamingConfig
|
15
15
|
from pyjallib.nameToPath import NameToPath
|
16
16
|
from pyjallib.perforce import Perforce
|
17
|
-
from pyjallib.reloadModules import reload_modules
|
17
|
+
from pyjallib.reloadModules import reload_modules
|
18
|
+
from pyjallib.logger import Logger
|
19
|
+
from pyjallib.progressEvent import ProgressEvent
|
pyjallib/logger.py
ADDED
@@ -0,0 +1,201 @@
|
|
1
|
+
#!/usr/bin/env python
|
2
|
+
# -*- coding: utf-8 -*-
|
3
|
+
|
4
|
+
"""
|
5
|
+
PyJalLib 중앙 집중식 로깅 모듈
|
6
|
+
모든 PyJalLib 모듈에서 사용할 수 있는 통합 로깅 시스템을 제공합니다.
|
7
|
+
"""
|
8
|
+
|
9
|
+
import logging
|
10
|
+
from pathlib import Path
|
11
|
+
from typing import Optional
|
12
|
+
from datetime import datetime
|
13
|
+
|
14
|
+
|
15
|
+
class Logger:
|
16
|
+
"""PyJalLib 간단한 로깅 클래스"""
|
17
|
+
|
18
|
+
def __init__(self, inLogPath: Optional[str] = None, inLogFileName: Optional[str] = None, inEnableConsole: bool = True, inEnableUE5: bool = False):
|
19
|
+
"""로거 인스턴스 초기화
|
20
|
+
|
21
|
+
Args:
|
22
|
+
inLogPath (str, optional): 로그 파일 저장 경로.
|
23
|
+
None인 경우 기본 경로 사용 (Documents/PyJalLib/logs)
|
24
|
+
inLogFileName (str, optional): 로그 파일명 (확장자 제외).
|
25
|
+
None인 경우 기본값 "pyjallib" 사용
|
26
|
+
실제 파일명은 "YYYYMMDD_파일명.log" 형식으로 생성
|
27
|
+
inEnableConsole (bool): 콘솔 출력 활성화 여부 (기본값: True)
|
28
|
+
inEnableUE5 (bool): UE5 출력 활성화 여부 (기본값: False)
|
29
|
+
"""
|
30
|
+
# 기본 로그 경로 설정
|
31
|
+
if inLogPath is None:
|
32
|
+
documents_path = Path.home() / "Documents"
|
33
|
+
self._logPath = documents_path / "PyJalLib" / "logs"
|
34
|
+
else:
|
35
|
+
self._logPath = Path(inLogPath)
|
36
|
+
|
37
|
+
# 로그 디렉토리 생성
|
38
|
+
self._logPath.mkdir(parents=True, exist_ok=True)
|
39
|
+
|
40
|
+
# 로그 파일명 설정 (확장자 제외)
|
41
|
+
self._logFileName = inLogFileName if inLogFileName is not None else "pyjallib"
|
42
|
+
|
43
|
+
# 출력 옵션 설정
|
44
|
+
self._enableConsole = inEnableConsole
|
45
|
+
self._enableUE5 = inEnableUE5
|
46
|
+
self._sessionName = None # 초기에는 세션 없음
|
47
|
+
|
48
|
+
# 로거 생성 및 설정
|
49
|
+
self._logger = logging.getLogger(f"pyjallib_{id(self)}")
|
50
|
+
self._logger.setLevel(logging.DEBUG)
|
51
|
+
self._logger.handlers.clear() # 기존 핸들러 제거
|
52
|
+
self._setup_handlers()
|
53
|
+
|
54
|
+
def debug(self, inMessage: str) -> None:
|
55
|
+
"""디버그 레벨 로그 메시지"""
|
56
|
+
self._logger.debug(inMessage)
|
57
|
+
|
58
|
+
def info(self, inMessage: str) -> None:
|
59
|
+
"""정보 레벨 로그 메시지"""
|
60
|
+
self._logger.info(inMessage)
|
61
|
+
|
62
|
+
def warning(self, inMessage: str) -> None:
|
63
|
+
"""경고 레벨 로그 메시지"""
|
64
|
+
self._logger.warning(inMessage)
|
65
|
+
|
66
|
+
def error(self, inMessage: str) -> None:
|
67
|
+
"""에러 레벨 로그 메시지"""
|
68
|
+
self._logger.error(inMessage)
|
69
|
+
|
70
|
+
def critical(self, inMessage: str) -> None:
|
71
|
+
"""치명적 에러 레벨 로그 메시지"""
|
72
|
+
self._logger.critical(inMessage)
|
73
|
+
|
74
|
+
def set_session(self, inSessionName: str) -> None:
|
75
|
+
"""새로운 로깅 세션 설정 및 시작
|
76
|
+
|
77
|
+
Args:
|
78
|
+
inSessionName (str): 세션 구분용 이름
|
79
|
+
"""
|
80
|
+
# 기존 세션이 있다면 종료
|
81
|
+
if self._sessionName is not None:
|
82
|
+
self.end_session()
|
83
|
+
|
84
|
+
# 새 세션 시작
|
85
|
+
self._sessionName = inSessionName
|
86
|
+
separator_msg = f"===== {self._sessionName} 로깅 시작 ====="
|
87
|
+
self._log_separator(separator_msg)
|
88
|
+
|
89
|
+
def end_session(self) -> None:
|
90
|
+
"""현재 로깅 세션 종료 구분선 출력"""
|
91
|
+
if self._sessionName is not None:
|
92
|
+
separator_msg = f"===== {self._sessionName} 로깅 끝 ====="
|
93
|
+
self._log_separator(separator_msg)
|
94
|
+
self._sessionName = None
|
95
|
+
|
96
|
+
def close(self) -> None:
|
97
|
+
"""로거 핸들러들을 명시적으로 닫기"""
|
98
|
+
for handler in self._logger.handlers[:]:
|
99
|
+
try:
|
100
|
+
handler.close()
|
101
|
+
self._logger.removeHandler(handler)
|
102
|
+
except Exception:
|
103
|
+
pass
|
104
|
+
|
105
|
+
def _log_separator(self, inMessage: str) -> None:
|
106
|
+
"""구분선 메시지를 모든 핸들러에 직접 출력"""
|
107
|
+
# 구분선은 INFO 레벨로 출력하되, 특별한 포맷 사용
|
108
|
+
separator_record = logging.LogRecord(
|
109
|
+
name=self._logger.name,
|
110
|
+
level=logging.INFO,
|
111
|
+
pathname="",
|
112
|
+
lineno=0,
|
113
|
+
msg=inMessage,
|
114
|
+
args=(),
|
115
|
+
exc_info=None
|
116
|
+
)
|
117
|
+
|
118
|
+
# 각 핸들러에 직접 전송 (포맷터 우회)
|
119
|
+
for handler in self._logger.handlers:
|
120
|
+
try:
|
121
|
+
# 핸들러 레벨 확인
|
122
|
+
if handler.level <= logging.INFO:
|
123
|
+
# 구분선만 특별한 포맷으로 출력
|
124
|
+
if hasattr(handler, 'stream'):
|
125
|
+
handler.stream.write(inMessage + "\n")
|
126
|
+
if hasattr(handler, 'flush'):
|
127
|
+
handler.flush()
|
128
|
+
elif isinstance(handler, _UE5LogHandler):
|
129
|
+
# UE5 핸들러의 경우 직접 emit 호출
|
130
|
+
handler.emit(separator_record)
|
131
|
+
except Exception:
|
132
|
+
# 핸들러 오류 시 무시
|
133
|
+
pass
|
134
|
+
|
135
|
+
def _setup_handlers(self) -> None:
|
136
|
+
"""로거에 핸들러 설정"""
|
137
|
+
# 파일 핸들러 (항상 활성화) - 날짜 기반 파일명
|
138
|
+
current_date = datetime.now().strftime("%Y%m%d")
|
139
|
+
log_filename = f"{current_date}_{self._logFileName}.log"
|
140
|
+
log_file = self._logPath / log_filename
|
141
|
+
file_handler = logging.FileHandler(log_file, encoding='utf-8')
|
142
|
+
file_handler.setFormatter(self._get_formatter())
|
143
|
+
self._logger.addHandler(file_handler)
|
144
|
+
|
145
|
+
# 콘솔 핸들러 (선택사항)
|
146
|
+
if self._enableConsole:
|
147
|
+
console_handler = logging.StreamHandler()
|
148
|
+
console_handler.setFormatter(self._get_formatter())
|
149
|
+
self._logger.addHandler(console_handler)
|
150
|
+
|
151
|
+
# UE5 핸들러 (선택사항)
|
152
|
+
if self._enableUE5:
|
153
|
+
ue5_handler = self._create_ue5_handler()
|
154
|
+
if ue5_handler:
|
155
|
+
self._logger.addHandler(ue5_handler)
|
156
|
+
|
157
|
+
def _get_formatter(self) -> logging.Formatter:
|
158
|
+
"""표준 포맷터 반환"""
|
159
|
+
return logging.Formatter(
|
160
|
+
'%(asctime)s - %(levelname)s - %(message)s',
|
161
|
+
datefmt='%Y-%m-%d %H:%M:%S'
|
162
|
+
)
|
163
|
+
|
164
|
+
def _create_ue5_handler(self) -> Optional[logging.Handler]:
|
165
|
+
"""UE5 핸들러 생성 (기존 UE5LogHandler 코드 활용)"""
|
166
|
+
try:
|
167
|
+
return _UE5LogHandler()
|
168
|
+
except Exception:
|
169
|
+
# UE5 핸들러 생성 실패 시 None 반환
|
170
|
+
return None
|
171
|
+
|
172
|
+
|
173
|
+
class _UE5LogHandler(logging.Handler):
|
174
|
+
"""UE5 전용 로그 핸들러 - UE5의 로그 시스템과 호환되도록 설계"""
|
175
|
+
|
176
|
+
def emit(self, record):
|
177
|
+
"""로그 레코드를 UE5 로그 시스템으로 전송"""
|
178
|
+
try:
|
179
|
+
# UE5의 unreal.log 함수 사용
|
180
|
+
import unreal
|
181
|
+
|
182
|
+
# 메시지 포맷팅
|
183
|
+
message = self.format(record) if self.formatter else record.getMessage()
|
184
|
+
|
185
|
+
# 로그 레벨에 따라 적절한 UE5 로그 함수 호출
|
186
|
+
if record.levelno >= logging.ERROR:
|
187
|
+
unreal.log_error(f"[PyJalLib] {message}")
|
188
|
+
elif record.levelno >= logging.WARNING:
|
189
|
+
unreal.log_warning(f"[PyJalLib] {message}")
|
190
|
+
elif record.levelno >= logging.INFO:
|
191
|
+
unreal.log(f"[PyJalLib] {message}")
|
192
|
+
else: # DEBUG
|
193
|
+
unreal.log(f"[PyJalLib-DEBUG] {message}")
|
194
|
+
|
195
|
+
except ImportError:
|
196
|
+
# unreal 모듈이 없는 경우 표준 출력 사용
|
197
|
+
message = self.format(record) if self.formatter else record.getMessage()
|
198
|
+
print(f"[PyJalLib] {message}")
|
199
|
+
except Exception:
|
200
|
+
# 모든 예외를 무시하여 로깅 실패가 애플리케이션을 중단하지 않도록 함
|
201
|
+
pass
|
pyjallib/max/bip.py
CHANGED
@@ -479,27 +479,6 @@ class Bip:
|
|
479
479
|
|
480
480
|
if inCollapseLayers:
|
481
481
|
self.collapse_layers(inBipRoot)
|
482
|
-
|
483
|
-
if inBakeAllKeys:
|
484
|
-
allTargetBipedObjs = self.get_nodes(inBipRoot)
|
485
|
-
startFrame = rt.execute("(animationRange.start as integer) / TicksPerFrame")
|
486
|
-
endFrame = rt.execute("(animationRange.end as integer) / TicksPerFrame")
|
487
|
-
totalFrame = endFrame - startFrame + 1
|
488
|
-
|
489
|
-
for frame in range(startFrame, endFrame + 1):
|
490
|
-
for item in allTargetBipedObjs:
|
491
|
-
if item == item.controller.rootNode:
|
492
|
-
horizontalController = rt.getPropertyController(item.controller, "horizontal")
|
493
|
-
verticalController = rt.getPropertyController(item.controller, "vertical")
|
494
|
-
turningController = rt.getPropertyController(item.controller, "turning")
|
495
|
-
|
496
|
-
rt.biped.addNewKey(horizontalController, frame)
|
497
|
-
rt.biped.addNewKey(verticalController, frame)
|
498
|
-
rt.biped.addNewKey(turningController, frame)
|
499
|
-
else:
|
500
|
-
rt.biped.addNewKey(item.controller, frame)
|
501
|
-
if progress_callback:
|
502
|
-
progress_callback(frame - startFrame + 1, totalFrame)
|
503
482
|
|
504
483
|
minFrame = 0.0
|
505
484
|
maxFrame = 0.0
|
pyjallib/max/skeleton.py
CHANGED
@@ -164,7 +164,6 @@ class Skeleton:
|
|
164
164
|
returnArray = []
|
165
165
|
nodeArray = self.get_dependencies(inObjs)
|
166
166
|
|
167
|
-
|
168
167
|
# 애드온 레이어의 노드들만 필터링
|
169
168
|
addOnArray = []
|
170
169
|
for item in nodeArray:
|
@@ -172,13 +171,7 @@ class Skeleton:
|
|
172
171
|
addOnArray.append(item)
|
173
172
|
|
174
173
|
# 애드온 노드들의 의존성 가져오기
|
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)
|
174
|
+
addOnRefArray = self.get_dependencies(addOnArray)
|
182
175
|
|
183
176
|
# 모든 노드들을 returnArray에 추가 (중복 없이)
|
184
177
|
for item in nodeArray:
|
pyjallib/naming.py
CHANGED
@@ -1014,7 +1014,10 @@ class Naming:
|
|
1014
1014
|
nameArray[partIndex] = inNewName
|
1015
1015
|
|
1016
1016
|
newName = self._combine(nameArray, self._get_filtering_char(inStr))
|
1017
|
-
|
1017
|
+
|
1018
|
+
indexIndex = self.get_name_part_index("Index")
|
1019
|
+
if indexIndex >= 0:
|
1020
|
+
newName = self.set_index_padding_num(newName)
|
1018
1021
|
|
1019
1022
|
return newName
|
1020
1023
|
|