pyjallib 0.1.10__py3-none-any.whl → 0.1.11__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 +7 -7
- pyjallib/max/__init__.py +24 -25
- pyjallib/max/autoClavicle.py +39 -4
- pyjallib/max/bip.py +2 -0
- pyjallib/max/bone.py +37 -0
- pyjallib/max/boneChain.py +182 -0
- pyjallib/max/groinBone.py +65 -29
- pyjallib/max/hip.py +44 -7
- pyjallib/max/kneeBone.py +61 -26
- pyjallib/max/macro/jal_macro_bone.py +1 -1
- pyjallib/max/twistBone.py +59 -40
- pyjallib/max/volumeBone.py +77 -26
- pyjallib/naming.py +1 -1
- pyjallib/perforce.py +127 -9
- {pyjallib-0.1.10.dist-info → pyjallib-0.1.11.dist-info}/METADATA +1 -1
- {pyjallib-0.1.10.dist-info → pyjallib-0.1.11.dist-info}/RECORD +17 -20
- pyjallib/max/autoClavicleChain.py +0 -173
- pyjallib/max/groinBoneChain.py +0 -173
- pyjallib/max/twistBoneChain.py +0 -162
- pyjallib/max/volumeBoneChain.py +0 -363
- {pyjallib-0.1.10.dist-info → pyjallib-0.1.11.dist-info}/WHEEL +0 -0
pyjallib/max/kneeBone.py
CHANGED
@@ -16,6 +16,8 @@ from .bone import Bone
|
|
16
16
|
from .constraint import Constraint
|
17
17
|
from .volumeBone import VolumeBone
|
18
18
|
|
19
|
+
from .boneChain import BoneChain
|
20
|
+
|
19
21
|
class KneeBone:
|
20
22
|
"""
|
21
23
|
자동 무릎 본(AutoKnee) 관련 기능을 제공하는 클래스.
|
@@ -310,17 +312,19 @@ class KneeBone:
|
|
310
312
|
result = self.volumeBone.create_bones(self.calf, self.thigh, inVolumeSize=5.0, inRotAxises=["Z", "Z"], inTransAxises=["PosY", "NegY"], inTransScales=transScales)
|
311
313
|
|
312
314
|
filteringChar = self.name._get_filtering_char(inCalf.name)
|
313
|
-
calfName = self.name.
|
315
|
+
calfName = self.name.get_RealName(inCalf.name)
|
316
|
+
calfName = calfName + filteringChar + "Vol"
|
314
317
|
isLower = calfName[0].islower()
|
315
318
|
replaceName = "Knee"
|
316
319
|
if isLower:
|
317
320
|
replaceName = replaceName.lower()
|
321
|
+
calfName = calfName.lower()
|
318
322
|
|
319
323
|
for item in result["Bones"]:
|
320
|
-
item.name.replace(calfName, replaceName)
|
324
|
+
item.name = item.name.replace(calfName, replaceName)
|
321
325
|
|
322
|
-
result["
|
323
|
-
result["RotHelper"].name.replace(calfName, replaceName)
|
326
|
+
result["RootBone"].name = result["RootBone"].name.replace(calfName, replaceName)
|
327
|
+
result["RotHelper"].name = result["RotHelper"].name.replace(calfName, replaceName)
|
324
328
|
|
325
329
|
# 결과 저장
|
326
330
|
if result and "Bones" in result:
|
@@ -379,7 +383,7 @@ class KneeBone:
|
|
379
383
|
|
380
384
|
liftTwistBone = self.bone.create_nub_bone(liftTwistBoneName, 2)
|
381
385
|
liftTwistBone.name = self.name.remove_name_part("Nub", liftTwistBone.name)
|
382
|
-
liftTwistBone.name = self.name.replace_name_part("Index", liftTwistBone.name, self.name.get_name("Index",
|
386
|
+
liftTwistBone.name = self.name.replace_name_part("Index", liftTwistBone.name, self.name.get_name("Index", item.name))
|
383
387
|
|
384
388
|
rt.setProperty(liftTwistBone, "transform", item.transform)
|
385
389
|
liftTwistBone.parent = item
|
@@ -404,7 +408,7 @@ class KneeBone:
|
|
404
408
|
|
405
409
|
liftTwistBone = self.bone.create_nub_bone(liftTwistBoneName, 2)
|
406
410
|
liftTwistBone.name = self.name.remove_name_part("Nub", liftTwistBone.name)
|
407
|
-
liftTwistBone.name = self.name.replace_name_part("Index", liftTwistBone.name, self.name.get_name("Index",
|
411
|
+
liftTwistBone.name = self.name.replace_name_part("Index", liftTwistBone.name, self.name.get_name("Index", item.name))
|
408
412
|
|
409
413
|
rt.setProperty(liftTwistBone, "transform", item.transform)
|
410
414
|
liftTwistBone.parent = item
|
@@ -420,7 +424,7 @@ class KneeBone:
|
|
420
424
|
self.calfTwistBones.append(liftTwistBone)
|
421
425
|
self.calfTwistHelpers.append(liftTwistHelper)
|
422
426
|
|
423
|
-
def create_bone(self, inThigh, inCalf, inFoot, inLiftScale=0.05, inKneePopScale=1
|
427
|
+
def create_bone(self, inThigh, inCalf, inFoot, inLiftScale=0.05, inKneePopScale=0.1, inKneeBackScale=1.5):
|
424
428
|
"""
|
425
429
|
자동 무릎 본 시스템의 모든 요소를 생성하는 주요 메서드입니다.
|
426
430
|
|
@@ -441,7 +445,7 @@ class KneeBone:
|
|
441
445
|
inKneeBackScale: 무릎 뒤쪽 돌출 스케일 (1.0이 기본값)
|
442
446
|
|
443
447
|
Returns:
|
444
|
-
|
448
|
+
BoneChain: 생성된 자동 무릎 본 체인 객체
|
445
449
|
"""
|
446
450
|
if not rt.isValidNode(inThigh) or not rt.isValidNode(inCalf) or not rt.isValidNode(inFoot):
|
447
451
|
return False
|
@@ -454,30 +458,61 @@ class KneeBone:
|
|
454
458
|
self.create_middle_bone(inThigh, inCalf, inKneePopScale=inKneePopScale, inKneeBackScale=inKneeBackScale)
|
455
459
|
self.create_twist_bones(inThigh, inCalf)
|
456
460
|
|
457
|
-
#
|
461
|
+
# 모든 생성된 본들 수집
|
462
|
+
all_bones = self.thighTwistBones + self.calfTwistBones + self.middleBones
|
463
|
+
all_helpers = [self.lookAtHleper, self.thighRotHelper, self.calfRotHelper,
|
464
|
+
self.thighRotRootHelper, self.calfRotRootHelper] + self.thighTwistHelpers + self.calfTwistHelpers
|
465
|
+
|
466
|
+
# 결과를 BoneChain 형태로 준비
|
458
467
|
result = {
|
459
|
-
"
|
460
|
-
"
|
461
|
-
"
|
462
|
-
"
|
463
|
-
"ThighRotHelper": self.thighRotHelper,
|
464
|
-
"CalfRotHelper": self.calfRotHelper,
|
465
|
-
"ThighRotRootHelper": self.thighRotRootHelper,
|
466
|
-
"CalfRotRootHelper": self.calfRotRootHelper,
|
467
|
-
"ThighTwistBones": self.thighTwistBones,
|
468
|
-
"CalfTwistBones": self.calfTwistBones,
|
469
|
-
"ThighTwistHelpers": self.thighTwistHelpers,
|
470
|
-
"CalfTwistHelpers": self.calfTwistHelpers,
|
471
|
-
"MiddleBones": self.middleBones,
|
472
|
-
"LiftScale": inLiftScale,
|
473
|
-
"KneePopScale": inKneePopScale,
|
474
|
-
"KneeBackScale": inKneeBackScale
|
468
|
+
"Bones": all_bones,
|
469
|
+
"Helpers": all_helpers,
|
470
|
+
"SourceBones": [inThigh, inCalf, inFoot],
|
471
|
+
"Parameters": [inLiftScale, inKneePopScale, inKneeBackScale]
|
475
472
|
}
|
476
473
|
|
477
474
|
# 메소드 호출 후 데이터 초기화
|
478
475
|
self.reset()
|
479
476
|
|
480
|
-
return result
|
477
|
+
return BoneChain.from_result(result)
|
478
|
+
|
479
|
+
def create_bones_from_chain(self, inBoneChain: BoneChain):
|
480
|
+
"""
|
481
|
+
기존 BoneChain 객체에서 자동 무릎 본을 생성합니다.
|
482
|
+
기존 설정을 복원하거나 저장된 데이터에서 무릎 셋업을 재생성할 때 사용합니다.
|
483
|
+
|
484
|
+
Args:
|
485
|
+
inBoneChain (BoneChain): 자동 무릎 본 정보를 포함한 BoneChain 객체
|
486
|
+
|
487
|
+
Returns:
|
488
|
+
BoneChain: 업데이트된 BoneChain 객체 또는 실패 시 None
|
489
|
+
"""
|
490
|
+
if not inBoneChain or inBoneChain.is_empty():
|
491
|
+
return None
|
492
|
+
|
493
|
+
# 기존 객체 삭제
|
494
|
+
inBoneChain.delete()
|
495
|
+
|
496
|
+
# BoneChain에서 필요한 정보 추출
|
497
|
+
sourceBones = inBoneChain.sourceBones
|
498
|
+
parameters = inBoneChain.parameters
|
499
|
+
|
500
|
+
# 필수 소스 본 확인
|
501
|
+
if len(sourceBones) < 3 or not rt.isValidNode(sourceBones[0]) or not rt.isValidNode(sourceBones[1]) or not rt.isValidNode(sourceBones[2]):
|
502
|
+
return None
|
503
|
+
|
504
|
+
# 파라미터 가져오기 (또는 기본값 사용)
|
505
|
+
liftScale = parameters[0] if len(parameters) > 0 else 0.05
|
506
|
+
kneePopScale = parameters[1] if len(parameters) > 1 else 0.1
|
507
|
+
kneeBackScale = parameters[2] if len(parameters) > 2 else 1.5
|
508
|
+
|
509
|
+
# 무릎 본 생성
|
510
|
+
inThigh = sourceBones[0]
|
511
|
+
inCalf = sourceBones[1]
|
512
|
+
inFoot = sourceBones[2]
|
513
|
+
|
514
|
+
# 새로운 자동 무릎 본 생성
|
515
|
+
return self.create_bone(inThigh, inCalf, inFoot, liftScale, kneePopScale, kneeBackScale)
|
481
516
|
|
482
517
|
def reset(self):
|
483
518
|
"""
|
@@ -273,7 +273,7 @@ def jal_bone_nub_create():
|
|
273
273
|
for item in non_bone_array:
|
274
274
|
jal.bone.create_nub_bone_on_obj(item)
|
275
275
|
else:
|
276
|
-
jal.bone.create_nub_bone("Temp
|
276
|
+
jal.bone.create_nub_bone("Temp", 2)
|
277
277
|
|
278
278
|
# Register macroscripts
|
279
279
|
macroScript_Category = "jalTools"
|
pyjallib/max/twistBone.py
CHANGED
@@ -19,6 +19,8 @@ from .constraint import Constraint
|
|
19
19
|
from .bip import Bip
|
20
20
|
from .bone import Bone
|
21
21
|
|
22
|
+
from .boneChain import BoneChain
|
23
|
+
|
22
24
|
|
23
25
|
class TwistBone:
|
24
26
|
"""
|
@@ -121,12 +123,7 @@ class TwistBone:
|
|
121
123
|
twistNum (int, optional): 생성할 트위스트 뼈대의 개수. 기본값은 4입니다.
|
122
124
|
|
123
125
|
Returns:
|
124
|
-
|
125
|
-
"Bones": 생성된 뼈대 객체들의 배열
|
126
|
-
"Type": "Upper" (상체 타입)
|
127
|
-
"Limb": 부모 객체 참조
|
128
|
-
"Child": 자식 객체 참조
|
129
|
-
"TwistNum": 생성된 트위스트 뼈대 개수
|
126
|
+
BoneChain: 생성된 트위스트 뼈대 BoneChain 객체
|
130
127
|
"""
|
131
128
|
limb = inObj
|
132
129
|
distance = rt.distance(limb, inChild)
|
@@ -134,7 +131,6 @@ class TwistBone:
|
|
134
131
|
inObjXAxisVec = inObj.objectTransform.row1
|
135
132
|
distanceDir = 1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else -1.0
|
136
133
|
offssetAmount = (distance / twistNum) * distanceDir
|
137
|
-
weightVal = 100.0 / (twistNum-1)
|
138
134
|
|
139
135
|
boneChainArray = []
|
140
136
|
|
@@ -172,6 +168,8 @@ class TwistBone:
|
|
172
168
|
lastBone.parent = limb
|
173
169
|
self.anim.move_local(lastBone, offssetAmount*(twistNum-1), 0, 0)
|
174
170
|
|
171
|
+
weightVal = 100.0 / (twistNum-1)
|
172
|
+
|
175
173
|
if twistNum > 2:
|
176
174
|
for i in range(1, twistNum-1):
|
177
175
|
twistExtraBone = self.bone.create_nub_bone(boneName, 2)
|
@@ -197,25 +195,18 @@ class TwistBone:
|
|
197
195
|
|
198
196
|
boneChainArray.append(lastBone)
|
199
197
|
|
200
|
-
# 결과를
|
201
|
-
|
202
|
-
self.child = inChild
|
203
|
-
self.twistNum = twistNum
|
204
|
-
self.bones = boneChainArray
|
205
|
-
self.twistType = "Upper"
|
206
|
-
|
207
|
-
returnVal = {
|
198
|
+
# 결과를 BoneChain 형태로 준비
|
199
|
+
result = {
|
208
200
|
"Bones": boneChainArray,
|
209
|
-
"
|
210
|
-
"
|
211
|
-
"
|
212
|
-
"TwistNum": twistNum
|
201
|
+
"Helpers": [],
|
202
|
+
"SourceBones": [inObj, inChild],
|
203
|
+
"Parameters": [twistNum, "Upper"]
|
213
204
|
}
|
214
205
|
|
215
206
|
# 메소드 호출 후 데이터 초기화
|
216
207
|
self.reset()
|
217
208
|
|
218
|
-
return
|
209
|
+
return BoneChain.from_result(result)
|
219
210
|
|
220
211
|
def create_lower_limb_bones(self, inObj, inChild, twistNum=4):
|
221
212
|
"""
|
@@ -231,12 +222,7 @@ class TwistBone:
|
|
231
222
|
twistNum (int, optional): 생성할 트위스트 뼈대의 개수. 기본값은 4입니다.
|
232
223
|
|
233
224
|
Returns:
|
234
|
-
|
235
|
-
"Bones": 생성된 뼈대 객체들의 배열
|
236
|
-
"Type": "Lower" (하체 타입)
|
237
|
-
"Limb": 부모 객체 참조
|
238
|
-
"Child": 자식 객체 참조
|
239
|
-
"TwistNum": 생성된 트위스트 뼈대 개수
|
225
|
+
BoneChain: 생성된 트위스트 뼈대 BoneChain 객체
|
240
226
|
"""
|
241
227
|
limb = inChild
|
242
228
|
distance = rt.distance(inObj, inChild)
|
@@ -244,7 +230,6 @@ class TwistBone:
|
|
244
230
|
inObjXAxisVec = inObj.objectTransform.row1
|
245
231
|
distanceDir = 1.0 if rt.dot(inObjXAxisVec, facingDirVec) > 0 else -1.0
|
246
232
|
offssetAmount = (distance / twistNum) * distanceDir
|
247
|
-
weightVal = 100.0 / (twistNum-1)
|
248
233
|
|
249
234
|
boneChainArray = []
|
250
235
|
|
@@ -281,6 +266,8 @@ class TwistBone:
|
|
281
266
|
lastBone.parent = inObj
|
282
267
|
self.anim.move_local(lastBone, 0, 0, 0)
|
283
268
|
|
269
|
+
weightVal = 100.0 / (twistNum-1)
|
270
|
+
|
284
271
|
if twistNum > 2:
|
285
272
|
for i in range(1, twistNum-1):
|
286
273
|
twistExtraBone = self.bone.create_nub_bone(boneName, 2)
|
@@ -306,22 +293,54 @@ class TwistBone:
|
|
306
293
|
|
307
294
|
boneChainArray.append(lastBone)
|
308
295
|
|
309
|
-
# 결과를
|
310
|
-
|
311
|
-
self.child = inChild
|
312
|
-
self.twistNum = twistNum
|
313
|
-
self.bones = boneChainArray
|
314
|
-
self.twistType = "Lower"
|
315
|
-
|
316
|
-
returnVal = {
|
296
|
+
# 결과를 BoneChain 형태로 준비
|
297
|
+
result = {
|
317
298
|
"Bones": boneChainArray,
|
318
|
-
"
|
319
|
-
"
|
320
|
-
"
|
321
|
-
"TwistNum": twistNum
|
299
|
+
"Helpers": [],
|
300
|
+
"SourceBones": [inObj, inChild],
|
301
|
+
"Parameters": [twistNum, "Lower"]
|
322
302
|
}
|
323
303
|
|
324
304
|
# 메소드 호출 후 데이터 초기화
|
325
305
|
self.reset()
|
326
306
|
|
327
|
-
return
|
307
|
+
return BoneChain.from_result(result)
|
308
|
+
|
309
|
+
def create_bones_from_chain(self, inBoneChain: BoneChain):
|
310
|
+
"""
|
311
|
+
기존 BoneChain 객체에서 트위스트 본을 생성합니다.
|
312
|
+
기존 설정을 복원하거나 저장된 데이터에서 트위스트 본 셋업을 재생성할 때 사용합니다.
|
313
|
+
|
314
|
+
Args:
|
315
|
+
inBoneChain (BoneChain): 트위스트 본 정보를 포함한 BoneChain 객체
|
316
|
+
|
317
|
+
Returns:
|
318
|
+
BoneChain: 업데이트된 BoneChain 객체 또는 실패 시 None
|
319
|
+
"""
|
320
|
+
if not inBoneChain or inBoneChain.is_empty():
|
321
|
+
return None
|
322
|
+
|
323
|
+
# 기존 객체 삭제
|
324
|
+
inBoneChain.delete()
|
325
|
+
|
326
|
+
# BoneChain에서 필요한 정보 추출
|
327
|
+
sourceBones = inBoneChain.sourceBones
|
328
|
+
parameters = inBoneChain.parameters
|
329
|
+
|
330
|
+
# 필수 소스 본 확인
|
331
|
+
if len(sourceBones) < 2 or not rt.isValidNode(sourceBones[0]) or not rt.isValidNode(sourceBones[1]):
|
332
|
+
return None
|
333
|
+
|
334
|
+
# 파라미터 가져오기 (또는 기본값 사용)
|
335
|
+
twistNum = parameters[0] if len(parameters) > 0 else 4
|
336
|
+
twistType = parameters[1] if len(parameters) > 1 else "Upper"
|
337
|
+
|
338
|
+
# 본 생성
|
339
|
+
inObj = sourceBones[0]
|
340
|
+
inChild = sourceBones[1]
|
341
|
+
|
342
|
+
# 타입에 따라 적절한 방식으로 트위스트 본 생성
|
343
|
+
if twistType == "Upper":
|
344
|
+
return self.create_upper_limb_bones(inObj, inChild, twistNum)
|
345
|
+
else:
|
346
|
+
return self.create_lower_limb_bones(inObj, inChild, twistNum)
|
pyjallib/max/volumeBone.py
CHANGED
@@ -18,6 +18,8 @@ from .helper import Helper
|
|
18
18
|
from .bone import Bone
|
19
19
|
from .constraint import Constraint
|
20
20
|
|
21
|
+
from .boneChain import BoneChain
|
22
|
+
|
21
23
|
|
22
24
|
class VolumeBone: # Updated class name to match the new file name
|
23
25
|
"""
|
@@ -69,8 +71,8 @@ class VolumeBone: # Updated class name to match the new file name
|
|
69
71
|
"\n"
|
70
72
|
"q = localDeltaTm.rotation\n"
|
71
73
|
"\n"
|
72
|
-
"eulerRot = (quatToEuler q order:
|
73
|
-
"swizzledRot = (eulerAngles eulerRot.
|
74
|
+
"eulerRot = (quatToEuler q order:5)\n"
|
75
|
+
"swizzledRot = (eulerAngles eulerRot.y eulerRot.z eulerRot.x)\n"
|
74
76
|
"saturatedTwist = abs ((swizzledRot.x*axis.x + swizzledRot.y*axis.y + swizzledRot.z*axis.z)/180.0)\n"
|
75
77
|
"\n"
|
76
78
|
"trAxis * saturatedTwist * volumeSize * transScale\n"
|
@@ -213,7 +215,7 @@ class VolumeBone: # Updated class name to match the new file name
|
|
213
215
|
inTransScales: 변환 비율 리스트
|
214
216
|
|
215
217
|
Returns:
|
216
|
-
|
218
|
+
BoneChain: 생성된 볼륨 본 체인 객체
|
217
219
|
"""
|
218
220
|
if rt.isValidNode(inObj) == False or rt.isValidNode(inParent) == False:
|
219
221
|
return None
|
@@ -242,32 +244,81 @@ class VolumeBone: # Updated class name to match the new file name
|
|
242
244
|
if rt.isValidNode(volBone):
|
243
245
|
bones.append(volBone)
|
244
246
|
|
245
|
-
#
|
246
|
-
|
247
|
-
|
248
|
-
|
249
|
-
|
250
|
-
self.rotAxises = inRotAxises.copy()
|
251
|
-
self.transAxises = inTransAxises.copy()
|
252
|
-
self.transScales = inTransScales.copy()
|
253
|
-
self.volumeSize = inVolumeSize
|
254
|
-
self.rotScale = inRotScale
|
255
|
-
|
256
|
-
# VolumeBoneChain이 필요로 하는 형태의 결과 딕셔너리 생성
|
247
|
+
# 모든 생성된 본들 모음
|
248
|
+
all_bones = [rootBone] + bones
|
249
|
+
rotHelper = self.rotHelper
|
250
|
+
|
251
|
+
# BoneChain에 필요한 형태의 결과 딕셔너리 생성
|
257
252
|
result = {
|
258
|
-
"
|
259
|
-
"
|
260
|
-
"
|
261
|
-
"
|
262
|
-
"LimbParent": inParent,
|
263
|
-
"Bones": bones,
|
264
|
-
"RotAxises": inRotAxises,
|
265
|
-
"TransAxises": inTransAxises,
|
266
|
-
"TransScales": inTransScales,
|
267
|
-
"VolumeSize": inVolumeSize
|
253
|
+
"Bones": all_bones,
|
254
|
+
"Helpers": [rotHelper],
|
255
|
+
"SourceBones": [inObj, inParent],
|
256
|
+
"Parameters": [inRotScale, inVolumeSize] + inRotAxises + inTransAxises + inTransScales
|
268
257
|
}
|
269
258
|
|
270
259
|
# 메소드 호출 후 데이터 초기화
|
271
260
|
self.reset()
|
272
261
|
|
273
|
-
return result
|
262
|
+
return BoneChain.from_result(result)
|
263
|
+
|
264
|
+
def create_bones_from_chain(self, inBoneChain: BoneChain):
|
265
|
+
"""
|
266
|
+
기존 BoneChain 객체에서 볼륨 본을 생성합니다.
|
267
|
+
기존 설정을 복원하거나 저장된 데이터에서 볼륨 본 셋업을 재생성할 때 사용합니다.
|
268
|
+
|
269
|
+
Args:
|
270
|
+
inBoneChain (BoneChain): 볼륨 본 정보를 포함한 BoneChain 객체
|
271
|
+
|
272
|
+
Returns:
|
273
|
+
BoneChain: 업데이트된 BoneChain 객체 또는 실패 시 None
|
274
|
+
"""
|
275
|
+
if not inBoneChain or inBoneChain.is_empty():
|
276
|
+
return None
|
277
|
+
|
278
|
+
# 기존 객체 삭제
|
279
|
+
inBoneChain.delete()
|
280
|
+
|
281
|
+
# BoneChain에서 필요한 정보 추출
|
282
|
+
sourceBones = inBoneChain.sourceBones
|
283
|
+
parameters = inBoneChain.parameters
|
284
|
+
|
285
|
+
# 필수 소스 본 확인
|
286
|
+
if len(sourceBones) < 2 or not rt.isValidNode(sourceBones[0]) or not rt.isValidNode(sourceBones[1]):
|
287
|
+
return None
|
288
|
+
|
289
|
+
# 최소 필요 파라미터 확인
|
290
|
+
if len(parameters) < 2:
|
291
|
+
return None
|
292
|
+
|
293
|
+
# 파라미터 가져오기
|
294
|
+
inRotScale = parameters[0]
|
295
|
+
inVolumeSize = parameters[1]
|
296
|
+
|
297
|
+
# 회전축, 변환축, 변환비율을 파라미터에서 추출
|
298
|
+
# 최소한 하나의 축 세트는 필요
|
299
|
+
param_count = len(parameters)
|
300
|
+
if param_count <= 2:
|
301
|
+
# 기본 값 사용
|
302
|
+
inRotAxises = ["Z"]
|
303
|
+
inTransAxises = ["PosY"]
|
304
|
+
inTransScales = [1.0]
|
305
|
+
else:
|
306
|
+
# 파라미터 중간을 3등분하여 각 목록 추출
|
307
|
+
axis_count = (param_count - 2) // 3
|
308
|
+
|
309
|
+
inRotAxises = parameters[2:2+axis_count]
|
310
|
+
inTransAxises = parameters[2+axis_count:2+axis_count*2]
|
311
|
+
inTransScales = parameters[2+axis_count*2:2+axis_count*3]
|
312
|
+
|
313
|
+
# 리스트 길이가 일치하지 않으면 기본값으로 보완
|
314
|
+
if len(inRotAxises) != len(inTransAxises) or len(inRotAxises) != len(inTransScales):
|
315
|
+
min_len = min(len(inRotAxises), len(inTransAxises), len(inTransScales))
|
316
|
+
inRotAxises = inRotAxises[:min_len] if min_len > 0 else ["Z"]
|
317
|
+
inTransAxises = inTransAxises[:min_len] if min_len > 0 else ["PosY"]
|
318
|
+
inTransScales = inTransScales[:min_len] if min_len > 0 else [1.0]
|
319
|
+
|
320
|
+
# 새로운 볼륨 본 생성
|
321
|
+
inObj = sourceBones[0]
|
322
|
+
inParent = sourceBones[1]
|
323
|
+
|
324
|
+
return self.create_bones(inObj, inParent, inRotScale, inVolumeSize, inRotAxises, inTransAxises, inTransScales)
|
pyjallib/naming.py
CHANGED
@@ -494,7 +494,7 @@ class Naming:
|
|
494
494
|
for part in self._nameParts:
|
495
495
|
partName = part.get_name()
|
496
496
|
partType = part.get_type()
|
497
|
-
if partType != NamePartType.REALNAME:
|
497
|
+
if partType.value != NamePartType.REALNAME.value:
|
498
498
|
foundName = self.get_name(partName, inStr)
|
499
499
|
nonRealNameArray.append(foundName)
|
500
500
|
|
pyjallib/perforce.py
CHANGED
@@ -283,6 +283,36 @@ class Perforce:
|
|
283
283
|
bool: 체크아웃 성공 시 True, 실패 시 False
|
284
284
|
"""
|
285
285
|
return self._file_op("edit", file_path, change_list_number, "체크아웃")
|
286
|
+
|
287
|
+
def checkout_files(self, file_paths: list, change_list_number: int) -> bool:
|
288
|
+
"""여러 파일을 한 번에 체크아웃합니다.
|
289
|
+
|
290
|
+
Args:
|
291
|
+
file_paths (list): 체크아웃할 파일 경로 리스트
|
292
|
+
change_list_number (int): 체인지 리스트 번호
|
293
|
+
|
294
|
+
Returns:
|
295
|
+
bool: 모든 파일 체크아웃 성공 시 True, 하나라도 실패 시 False
|
296
|
+
"""
|
297
|
+
if not file_paths:
|
298
|
+
logger.debug("체크아웃할 파일 목록이 비어있습니다.")
|
299
|
+
return True
|
300
|
+
|
301
|
+
logger.info(f"체인지 리스트 {change_list_number}에 {len(file_paths)}개 파일 체크아웃 시도...")
|
302
|
+
|
303
|
+
all_success = True
|
304
|
+
for file_path in file_paths:
|
305
|
+
success = self.checkout_file(file_path, change_list_number)
|
306
|
+
if not success:
|
307
|
+
all_success = False
|
308
|
+
logger.warning(f"파일 '{file_path}' 체크아웃 실패")
|
309
|
+
|
310
|
+
if all_success:
|
311
|
+
logger.info(f"모든 파일({len(file_paths)}개)을 체인지 리스트 {change_list_number}에 성공적으로 체크아웃했습니다.")
|
312
|
+
else:
|
313
|
+
logger.warning(f"일부 파일을 체인지 리스트 {change_list_number}에 체크아웃하지 못했습니다.")
|
314
|
+
|
315
|
+
return all_success
|
286
316
|
|
287
317
|
def add_file(self, file_path: str, change_list_number: int) -> bool:
|
288
318
|
"""파일을 추가합니다.
|
@@ -295,6 +325,36 @@ class Perforce:
|
|
295
325
|
bool: 추가 성공 시 True, 실패 시 False
|
296
326
|
"""
|
297
327
|
return self._file_op("add", file_path, change_list_number, "추가")
|
328
|
+
|
329
|
+
def add_files(self, file_paths: list, change_list_number: int) -> bool:
|
330
|
+
"""여러 파일을 한 번에 추가합니다.
|
331
|
+
|
332
|
+
Args:
|
333
|
+
file_paths (list): 추가할 파일 경로 리스트
|
334
|
+
change_list_number (int): 체인지 리스트 번호
|
335
|
+
|
336
|
+
Returns:
|
337
|
+
bool: 모든 파일 추가 성공 시 True, 하나라도 실패 시 False
|
338
|
+
"""
|
339
|
+
if not file_paths:
|
340
|
+
logger.debug("추가할 파일 목록이 비어있습니다.")
|
341
|
+
return True
|
342
|
+
|
343
|
+
logger.info(f"체인지 리스트 {change_list_number}에 {len(file_paths)}개 파일 추가 시도...")
|
344
|
+
|
345
|
+
all_success = True
|
346
|
+
for file_path in file_paths:
|
347
|
+
success = self.add_file(file_path, change_list_number)
|
348
|
+
if not success:
|
349
|
+
all_success = False
|
350
|
+
logger.warning(f"파일 '{file_path}' 추가 실패")
|
351
|
+
|
352
|
+
if all_success:
|
353
|
+
logger.info(f"모든 파일({len(file_paths)}개)을 체인지 리스트 {change_list_number}에 성공적으로 추가했습니다.")
|
354
|
+
else:
|
355
|
+
logger.warning(f"일부 파일을 체인지 리스트 {change_list_number}에 추가하지 못했습니다.")
|
356
|
+
|
357
|
+
return all_success
|
298
358
|
|
299
359
|
def delete_file(self, file_path: str, change_list_number: int) -> bool:
|
300
360
|
"""파일을 삭제합니다.
|
@@ -307,6 +367,36 @@ class Perforce:
|
|
307
367
|
bool: 삭제 성공 시 True, 실패 시 False
|
308
368
|
"""
|
309
369
|
return self._file_op("delete", file_path, change_list_number, "삭제")
|
370
|
+
|
371
|
+
def delete_files(self, file_paths: list, change_list_number: int) -> bool:
|
372
|
+
"""여러 파일을 한 번에 삭제합니다.
|
373
|
+
|
374
|
+
Args:
|
375
|
+
file_paths (list): 삭제할 파일 경로 리스트
|
376
|
+
change_list_number (int): 체인지 리스트 번호
|
377
|
+
|
378
|
+
Returns:
|
379
|
+
bool: 모든 파일 삭제 성공 시 True, 하나라도 실패 시 False
|
380
|
+
"""
|
381
|
+
if not file_paths:
|
382
|
+
logger.debug("삭제할 파일 목록이 비어있습니다.")
|
383
|
+
return True
|
384
|
+
|
385
|
+
logger.info(f"체인지 리스트 {change_list_number}에서 {len(file_paths)}개 파일 삭제 시도...")
|
386
|
+
|
387
|
+
all_success = True
|
388
|
+
for file_path in file_paths:
|
389
|
+
success = self.delete_file(file_path, change_list_number)
|
390
|
+
if not success:
|
391
|
+
all_success = False
|
392
|
+
logger.warning(f"파일 '{file_path}' 삭제 실패")
|
393
|
+
|
394
|
+
if all_success:
|
395
|
+
logger.info(f"모든 파일({len(file_paths)}개)을 체인지 리스트 {change_list_number}에서 성공적으로 삭제했습니다.")
|
396
|
+
else:
|
397
|
+
logger.warning(f"일부 파일을 체인지 리스트 {change_list_number}에서 삭제하지 못했습니다.")
|
398
|
+
|
399
|
+
return all_success
|
310
400
|
|
311
401
|
def submit_change_list(self, change_list_number: int) -> bool:
|
312
402
|
"""체인지 리스트를 제출합니다.
|
@@ -393,6 +483,28 @@ class Perforce:
|
|
393
483
|
self._handle_p4_exception(e, f"체인지 리스트 {change_list_number} 삭제")
|
394
484
|
return False
|
395
485
|
|
486
|
+
def revert_file(self, file_path: str, change_list_number: int) -> bool:
|
487
|
+
"""체인지 리스트에서 특정 파일을 되돌립니다.
|
488
|
+
|
489
|
+
Args:
|
490
|
+
file_path (str): 되돌릴 파일 경로
|
491
|
+
change_list_number (int): 체인지 리스트 번호
|
492
|
+
|
493
|
+
Returns:
|
494
|
+
bool: 되돌리기 성공 시 True, 실패 시 False
|
495
|
+
"""
|
496
|
+
if not self._is_connected():
|
497
|
+
return False
|
498
|
+
|
499
|
+
logger.info(f"파일 '{file_path}'을 체인지 리스트 {change_list_number}에서 되돌리기 시도...")
|
500
|
+
try:
|
501
|
+
self.p4.run_revert("-c", change_list_number, file_path)
|
502
|
+
logger.info(f"파일 '{file_path}'를 체인지 리스트 {change_list_number}에서 되돌리기 성공.")
|
503
|
+
return True
|
504
|
+
except P4Exception as e:
|
505
|
+
self._handle_p4_exception(e, f"파일 '{file_path}'를 체인지 리스트 {change_list_number}에서 되돌리기")
|
506
|
+
return False
|
507
|
+
|
396
508
|
def revert_files(self, change_list_number: int, file_paths: list) -> bool:
|
397
509
|
"""체인지 리스트 내의 특정 파일들을 되돌립니다.
|
398
510
|
|
@@ -401,7 +513,7 @@ class Perforce:
|
|
401
513
|
file_paths (list): 되돌릴 파일 경로 리스트
|
402
514
|
|
403
515
|
Returns:
|
404
|
-
bool: 되돌리기 성공 시 True, 실패 시 False
|
516
|
+
bool: 모든 파일 되돌리기 성공 시 True, 하나라도 실패 시 False
|
405
517
|
"""
|
406
518
|
if not self._is_connected():
|
407
519
|
return False
|
@@ -410,14 +522,20 @@ class Perforce:
|
|
410
522
|
return True
|
411
523
|
|
412
524
|
logger.info(f"체인지 리스트 {change_list_number}에서 {len(file_paths)}개 파일 되돌리기 시도...")
|
413
|
-
|
414
|
-
|
415
|
-
|
416
|
-
|
417
|
-
|
418
|
-
|
419
|
-
|
420
|
-
|
525
|
+
|
526
|
+
all_success = True
|
527
|
+
for file_path in file_paths:
|
528
|
+
success = self.revert_file(file_path, change_list_number)
|
529
|
+
if not success:
|
530
|
+
all_success = False
|
531
|
+
logger.warning(f"파일 '{file_path}' 되돌리기 실패")
|
532
|
+
|
533
|
+
if all_success:
|
534
|
+
logger.info(f"모든 파일({len(file_paths)}개)을 체인지 리스트 {change_list_number}에서 성공적으로 되돌렸습니다.")
|
535
|
+
else:
|
536
|
+
logger.warning(f"일부 파일을 체인지 리스트 {change_list_number}에서 되돌리지 못했습니다.")
|
537
|
+
|
538
|
+
return all_success
|
421
539
|
|
422
540
|
def check_update_required(self, file_paths: list) -> bool:
|
423
541
|
"""파일이나 폴더의 업데이트 필요 여부를 확인합니다.
|