pyjallib 0.1.11__py3-none-any.whl → 0.1.12__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.11'
9
+ __version__ = '0.1.12'
10
10
 
11
11
  # reload_modules 함수를 패키지 레벨에서 사용 가능하게 함
12
12
  from pyjallib.namePart import NamePart, NamePartType
pyjallib/max/bip.py CHANGED
@@ -439,6 +439,71 @@ class Bip:
439
439
  if colNum > 0:
440
440
  rt.biped.deleteAllCopyCollections(inBipRoot.controller)
441
441
 
442
+ def collapse_layers(self, inBipRoot):
443
+ """
444
+ Biped 레이어 병합
445
+
446
+ Args:
447
+ inBipRoot: 대상 Biped 객체
448
+ """
449
+ if not self.is_biped_object(inBipRoot):
450
+ return False
451
+
452
+ layerNum = rt.biped.numLayers(inBipRoot.controller)
453
+ while layerNum > 0:
454
+ rt.biped.collapseAtLayer(inBipRoot.controller, 0)
455
+ layerNum = rt.biped.numLayers(inBipRoot.controller)
456
+
457
+ def save_bip_file(self, inBipRoot, inFile, inBakeAllKeys=True, inCollapseLayers=True, progress_callback=None):
458
+ """
459
+ Biped BIP 파일 저장
460
+
461
+ Args:
462
+ inBipRoot: 저장 대상 Biped 루트 노드
463
+ inFile: 저장할 BIP 파일 경로
464
+ inBakeAllKeys: 모든 키를 베이크할지 여부 (기본값: True)
465
+ inCollapseLayers: 레이어를 병합할지 여부 (기본값: True)
466
+
467
+ Returns:
468
+ bool: 저장 성공 시 True, 실패 시 False
469
+ """
470
+ if not self.is_biped_object(inBipRoot):
471
+ return False
472
+
473
+ directory = os.path.dirname(inFile)
474
+ if directory and not os.path.exists(directory):
475
+ try:
476
+ os.makedirs(directory, exist_ok=True)
477
+ except OSError as e:
478
+ return False
479
+
480
+ if inCollapseLayers:
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
+
504
+ rt.biped.saveBipFile(inBipRoot.controller, inFile)
505
+ return True
506
+
442
507
  def link_base_skeleton(self, skinBoneBaseName="b"):
443
508
  """
444
509
  기본 스켈레톤 링크 (Biped와 일반 뼈대 연결)
@@ -690,8 +755,8 @@ class Bip:
690
755
  toeNub.name = self.name.replace_name_part("Nub", toeNub.name, self.name.get_name_part_value_by_description("Nub", "Nub"))
691
756
 
692
757
  if toeLinkNum == 1:
693
- rToesList[0][0].name = self.name.replace_name_part("RealName", lToesList[0][0].name, "ball")
694
- rToesList[0][0].name = self.name.remove_name_part("Index", lToesList[0][0].name)
758
+ rToesList[0][0].name = self.name.replace_name_part("RealName", rToesList[0][0].name, "ball")
759
+ rToesList[0][0].name = self.name.remove_name_part("Index", rToesList[0][0].name)
695
760
  else:
696
761
  for i, item in enumerate(rToesList[0]):
697
762
  item.name = self.name.replace_name_part("RealName", item.name, "ball")
pyjallib/naming.py CHANGED
@@ -258,6 +258,18 @@ class Naming:
258
258
  패딩 숫자
259
259
  """
260
260
  return self._paddingNum
261
+
262
+ def get_filtering_char(self, inStr):
263
+ """
264
+ 문자열에서 구분자 문자 가져오기
265
+
266
+ Args:
267
+ inStr: 확인할 문자열
268
+
269
+ Returns:
270
+ 구분자 문자 (' ' 또는 '_' 또는 '')
271
+ """
272
+ return self._get_filtering_char(inStr)
261
273
 
262
274
  def get_name_part(self, inNamePartName):
263
275
  """
@@ -273,6 +285,15 @@ class Naming:
273
285
  if part.get_name() == inNamePartName:
274
286
  return part
275
287
  return None
288
+
289
+ def get_name_parts(self):
290
+ """
291
+ 모든 namePart 객체 가져오기
292
+
293
+ Returns:
294
+ namePart 객체 리스트
295
+ """
296
+ return self._nameParts
276
297
 
277
298
  def get_name_part_index(self, inNamePartName):
278
299
  """
@@ -473,7 +494,11 @@ class Naming:
473
494
 
474
495
  # 배열을 문자열로 결합
475
496
  newName = self._combine(combinedNameArray, inFilChar)
476
- newName = self.set_index_padding_num(newName)
497
+
498
+ # "Index"키가 있을 때만 패딩 적용
499
+ if "Index" in inPartsDict:
500
+ newName = self.set_index_padding_num(newName)
501
+
477
502
  return newName
478
503
 
479
504
  def get_RealName(self, inStr):
pyjallib/namingConfig.py CHANGED
@@ -388,7 +388,7 @@ class NamingConfig:
388
388
 
389
389
  return True
390
390
 
391
- def set_part_value_by_csv(self, part_name: str, csv_file_path: str) -> bool:
391
+ def set_part_value_by_csv(self, part_name: str, csv_file_path: str, encoding: str = "utf-8") -> bool:
392
392
  """
393
393
  특정 NamePart의 사전 정의 값을 CSV 파일로 설정
394
394
  CSV 파일 형식: value,description,koreanDescription (각 줄당)
@@ -396,6 +396,7 @@ class NamingConfig:
396
396
  Args:
397
397
  part_name: NamePart 이름
398
398
  csv_file_path: CSV 파일 경로
399
+ encoding: CSV 파일 인코딩 (기본값: "utf-8", "utf-8-sig" 등 사용 가능)
399
400
 
400
401
  Returns:
401
402
  설정 성공 여부 (True/False)
@@ -415,7 +416,7 @@ class NamingConfig:
415
416
  descriptions = []
416
417
  korean_descriptions = []
417
418
  try:
418
- with open(csv_file_path, 'r', encoding='utf-8', newline='') as f:
419
+ with open(csv_file_path, 'r', encoding=encoding, newline='') as f:
419
420
  reader = csv.reader(f)
420
421
  for row in reader:
421
422
  if len(row) >= 3: # Ensure row has at least 3 columns
pyjallib/perforce.py CHANGED
@@ -195,6 +195,183 @@ class Perforce:
195
195
  self._handle_p4_exception(e, f"설명으로 체인지 리스트 조회 ('{description}')")
196
196
  return {}
197
197
 
198
+ def get_change_list_by_description_pattern(self, description_pattern: str, exact_match: bool = False) -> list:
199
+ """설명 패턴과 일치하는 Pending 체인지 리스트들을 가져옵니다.
200
+
201
+ Args:
202
+ description_pattern (str): 검색할 설명 패턴
203
+ exact_match (bool, optional): True면 정확히 일치하는 설명만,
204
+ False면 패턴이 포함된 설명도 포함. 기본값 False
205
+
206
+ Returns:
207
+ list: 패턴과 일치하는 체인지 리스트 정보들의 리스트
208
+ """
209
+ if not self._is_connected():
210
+ return []
211
+
212
+ search_type = "정확히 일치" if exact_match else "패턴 포함"
213
+ logger.debug(f"설명 패턴으로 체인지 리스트 조회 중 ({search_type}): '{description_pattern}'")
214
+
215
+ try:
216
+ pending_changes = self.p4.run_changes("-l", "-s", "pending", "-u", self.p4.user, "-c", self.p4.client)
217
+ matching_changes = []
218
+
219
+ for cl in pending_changes:
220
+ cl_desc = cl.get('Description', b'').decode('utf-8', 'replace').strip()
221
+
222
+ # 패턴 매칭 로직
223
+ is_match = False
224
+ if exact_match:
225
+ # 정확한 일치
226
+ is_match = (cl_desc == description_pattern.strip())
227
+ else:
228
+ # 패턴이 포함되어 있는지 확인 (대소문자 구분 없음)
229
+ is_match = (description_pattern.lower().strip() in cl_desc.lower())
230
+
231
+ if is_match:
232
+ change_number = int(cl['change'])
233
+ change_info = self.get_change_list_by_number(change_number)
234
+ if change_info:
235
+ matching_changes.append(change_info)
236
+ logger.info(f"패턴 '{description_pattern}'에 매칭되는 체인지 리스트 {change_number} 발견: '{cl_desc}'")
237
+
238
+ if matching_changes:
239
+ logger.info(f"패턴 '{description_pattern}'에 매칭되는 체인지 리스트 {len(matching_changes)}개 조회 완료.")
240
+ else:
241
+ logger.info(f"패턴 '{description_pattern}'에 매칭되는 Pending 체인지 리스트를 찾을 수 없습니다.")
242
+
243
+ return matching_changes
244
+ except P4Exception as e:
245
+ self._handle_p4_exception(e, f"설명 패턴으로 체인지 리스트 조회 ('{description_pattern}')")
246
+ return []
247
+
248
+ def check_files_checked_out(self, file_paths: list) -> dict:
249
+ """파일들의 체크아웃 상태를 확인합니다.
250
+
251
+ Args:
252
+ file_paths (list): 확인할 파일 경로 리스트
253
+
254
+ Returns:
255
+ dict: 파일별 체크아웃 상태 정보
256
+ {
257
+ 'file_path': {
258
+ 'is_checked_out': bool,
259
+ 'change_list': int or None,
260
+ 'action': str or None,
261
+ 'user': str or None,
262
+ 'workspace': str or None
263
+ }
264
+ }
265
+ """
266
+ if not self._is_connected():
267
+ return {}
268
+ if not file_paths:
269
+ logger.debug("체크아웃 상태 확인할 파일 목록이 비어있습니다.")
270
+ return {}
271
+
272
+ logger.debug(f"파일 체크아웃 상태 확인 중 (파일 {len(file_paths)}개)")
273
+
274
+ result = {}
275
+ try:
276
+ # 각 파일의 상태 확인
277
+ for file_path in file_paths:
278
+ file_status = {
279
+ 'is_checked_out': False,
280
+ 'change_list': None,
281
+ 'action': None,
282
+ 'user': None,
283
+ 'workspace': None
284
+ }
285
+
286
+ try:
287
+ # p4 opened 명령으로 파일이 열려있는지 확인
288
+ opened_files = self.p4.run_opened(file_path)
289
+
290
+ if opened_files:
291
+ # 파일이 체크아웃되어 있음
292
+ file_info = opened_files[0]
293
+ file_status['is_checked_out'] = True
294
+ file_status['change_list'] = int(file_info.get('change', 0))
295
+ file_status['action'] = file_info.get('action', '')
296
+ file_status['user'] = file_info.get('user', '')
297
+ file_status['workspace'] = file_info.get('client', '')
298
+
299
+ logger.debug(f"파일 '{file_path}' 체크아웃됨: CL {file_status['change_list']}, "
300
+ f"액션: {file_status['action']}, 사용자: {file_status['user']}, "
301
+ f"워크스페이스: {file_status['workspace']}")
302
+ else:
303
+ # 파일이 체크아웃되지 않음
304
+ logger.debug(f"파일 '{file_path}' 체크아웃되지 않음")
305
+
306
+ except P4Exception as e:
307
+ # 파일이 perforce에 없거나 접근할 수 없는 경우
308
+ if any("not opened" in err.lower() or "no such file" in err.lower()
309
+ for err in self.p4.errors):
310
+ logger.debug(f"파일 '{file_path}' 체크아웃되지 않음 (perforce에 없거나 접근 불가)")
311
+ else:
312
+ self._handle_p4_exception(e, f"파일 '{file_path}' 체크아웃 상태 확인")
313
+
314
+ result[file_path] = file_status
315
+
316
+ checked_out_count = sum(1 for status in result.values() if status['is_checked_out'])
317
+ logger.info(f"파일 체크아웃 상태 확인 완료: 전체 {len(file_paths)}개 중 {checked_out_count}개 체크아웃됨")
318
+
319
+ return result
320
+
321
+ except P4Exception as e:
322
+ self._handle_p4_exception(e, f"파일들 체크아웃 상태 확인 ({file_paths})")
323
+ return {}
324
+
325
+ def is_file_checked_out(self, file_path: str) -> bool:
326
+ """단일 파일의 체크아웃 상태를 간단히 확인합니다.
327
+
328
+ Args:
329
+ file_path (str): 확인할 파일 경로
330
+
331
+ Returns:
332
+ bool: 체크아웃되어 있으면 True, 아니면 False
333
+ """
334
+ result = self.check_files_checked_out([file_path])
335
+ return result.get(file_path, {}).get('is_checked_out', False)
336
+
337
+ def is_file_in_pending_changelist(self, file_path: str, change_list_number: int) -> bool:
338
+ """특정 파일이 지정된 pending 체인지 리스트에 있는지 확인합니다.
339
+
340
+ Args:
341
+ file_path (str): 확인할 파일 경로
342
+ change_list_number (int): 확인할 체인지 리스트 번호
343
+
344
+ Returns:
345
+ bool: 파일이 해당 체인지 리스트에 있으면 True, 아니면 False
346
+ """
347
+ if not self._is_connected():
348
+ return False
349
+
350
+ logger.debug(f"파일 '{file_path}'가 체인지 리스트 {change_list_number}에 있는지 확인 중...")
351
+
352
+ try:
353
+ # 해당 체인지 리스트의 파일들 가져오기
354
+ opened_files = self.p4.run_opened("-c", change_list_number)
355
+
356
+ # 파일 경로 정규화
357
+ normalized_file_path = os.path.normpath(file_path)
358
+
359
+ for file_info in opened_files:
360
+ client_file = file_info.get('clientFile', '')
361
+ normalized_client_file = os.path.normpath(client_file)
362
+
363
+ if normalized_client_file == normalized_file_path:
364
+ logger.debug(f"파일 '{file_path}'가 체인지 리스트 {change_list_number}에서 발견됨 "
365
+ f"(액션: {file_info.get('action', '')})")
366
+ return True
367
+
368
+ logger.debug(f"파일 '{file_path}'가 체인지 리스트 {change_list_number}에 없음")
369
+ return False
370
+
371
+ except P4Exception as e:
372
+ self._handle_p4_exception(e, f"파일 '{file_path}' 체인지 리스트 {change_list_number} 포함 여부 확인")
373
+ return False
374
+
198
375
  def edit_change_list(self, change_list_number: int, description: str = None, add_file_paths: list = None, remove_file_paths: list = None) -> dict:
199
376
  """체인지 리스트를 편집합니다.
200
377
 
@@ -644,3 +821,188 @@ class Perforce:
644
821
  def __del__(self):
645
822
  """객체가 소멸될 때 자동으로 연결을 해제합니다."""
646
823
  self.disconnect()
824
+
825
+ def check_files_checked_out_all_users(self, file_paths: list) -> dict:
826
+ """파일들의 체크아웃 상태를 모든 사용자/워크스페이스에서 확인합니다.
827
+
828
+ Args:
829
+ file_paths (list): 확인할 파일 경로 리스트
830
+
831
+ Returns:
832
+ dict: 파일별 체크아웃 상태 정보
833
+ {
834
+ 'file_path': {
835
+ 'is_checked_out': bool,
836
+ 'change_list': int or None,
837
+ 'action': str or None,
838
+ 'user': str or None,
839
+ 'client': str or None
840
+ }
841
+ }
842
+ """
843
+ if not self._is_connected():
844
+ return {}
845
+ if not file_paths:
846
+ logger.debug("체크아웃 상태 확인할 파일 목록이 비어있습니다.")
847
+ return {}
848
+
849
+ logger.debug(f"파일 체크아웃 상태 확인 중 - 모든 사용자 (파일 {len(file_paths)}개)")
850
+
851
+ result = {}
852
+ try:
853
+ # 각 파일의 상태 확인
854
+ for file_path in file_paths:
855
+ file_status = {
856
+ 'is_checked_out': False,
857
+ 'change_list': None,
858
+ 'action': None,
859
+ 'user': None,
860
+ 'client': None
861
+ }
862
+
863
+ try:
864
+ # p4 opened -a 명령으로 모든 사용자의 파일 체크아웃 상태 확인
865
+ opened_files = self.p4.run_opened("-a", file_path)
866
+
867
+ if opened_files:
868
+ # 파일이 체크아웃되어 있음 (첫 번째 결과 사용)
869
+ file_info = opened_files[0]
870
+ file_status['is_checked_out'] = True
871
+ file_status['change_list'] = int(file_info.get('change', 0))
872
+ file_status['action'] = file_info.get('action', '')
873
+ file_status['user'] = file_info.get('user', '')
874
+ file_status['client'] = file_info.get('client', '')
875
+
876
+ logger.debug(f"파일 '{file_path}' 체크아웃됨: CL {file_status['change_list']}, "
877
+ f"액션: {file_status['action']}, 사용자: {file_status['user']}, "
878
+ f"클라이언트: {file_status['client']}")
879
+ else:
880
+ # 파일이 체크아웃되지 않음
881
+ logger.debug(f"파일 '{file_path}' 체크아웃되지 않음 (모든 사용자)")
882
+
883
+ except P4Exception as e:
884
+ # 파일이 perforce에 없거나 접근할 수 없는 경우
885
+ if any("not opened" in err.lower() or "no such file" in err.lower()
886
+ for err in self.p4.errors):
887
+ logger.debug(f"파일 '{file_path}' 체크아웃되지 않음 (perforce에 없거나 접근 불가)")
888
+ else:
889
+ self._handle_p4_exception(e, f"파일 '{file_path}' 체크아웃 상태 확인 (모든 사용자)")
890
+
891
+ result[file_path] = file_status
892
+
893
+ checked_out_count = sum(1 for status in result.values() if status['is_checked_out'])
894
+ logger.info(f"파일 체크아웃 상태 확인 완료 (모든 사용자): 전체 {len(file_paths)}개 중 {checked_out_count}개 체크아웃됨")
895
+
896
+ return result
897
+
898
+ except P4Exception as e:
899
+ self._handle_p4_exception(e, f"파일들 체크아웃 상태 확인 - 모든 사용자 ({file_paths})")
900
+ return {}
901
+
902
+ def is_file_checked_out_by_others(self, file_path: str) -> bool:
903
+ """단일 파일이 다른 사용자/워크스페이스에 의해 체크아웃되어 있는지 확인합니다.
904
+
905
+ Args:
906
+ file_path (str): 확인할 파일 경로
907
+
908
+ Returns:
909
+ bool: 다른 사용자에 의해 체크아웃되어 있으면 True, 아니면 False
910
+ """
911
+ result = self.check_files_checked_out_all_users([file_path])
912
+ file_status = result.get(file_path, {})
913
+
914
+ if not file_status.get('is_checked_out', False):
915
+ return False
916
+
917
+ # 현재 사용자와 클라이언트가 아닌 경우 다른 사용자로 간주
918
+ current_user = self.p4.user
919
+ current_client = self.p4.client
920
+
921
+ file_user = file_status.get('user', '')
922
+ file_client = file_status.get('client', '')
923
+
924
+ return (file_user != current_user) or (file_client != current_client)
925
+
926
+ def get_file_checkout_info_all_users(self, file_path: str) -> dict:
927
+ """단일 파일의 상세 체크아웃 정보를 모든 사용자에서 가져옵니다.
928
+
929
+ Args:
930
+ file_path (str): 확인할 파일 경로
931
+
932
+ Returns:
933
+ dict: 체크아웃 정보 또는 빈 딕셔너리
934
+ {
935
+ 'is_checked_out': bool,
936
+ 'change_list': int or None,
937
+ 'action': str or None,
938
+ 'user': str or None,
939
+ 'client': str or None,
940
+ 'is_checked_out_by_current_user': bool,
941
+ 'is_checked_out_by_others': bool
942
+ }
943
+ """
944
+ result = self.check_files_checked_out_all_users([file_path])
945
+ file_status = result.get(file_path, {})
946
+
947
+ if file_status.get('is_checked_out', False):
948
+ # 현재 사용자와 클라이언트인지 확인
949
+ current_user = self.p4.user
950
+ current_client = self.p4.client
951
+
952
+ file_user = file_status.get('user', '')
953
+ file_client = file_status.get('client', '')
954
+
955
+ is_current_user = (file_user == current_user) and (file_client == current_client)
956
+
957
+ file_status['is_checked_out_by_current_user'] = is_current_user
958
+ file_status['is_checked_out_by_others'] = not is_current_user
959
+ else:
960
+ file_status['is_checked_out_by_current_user'] = False
961
+ file_status['is_checked_out_by_others'] = False
962
+
963
+ return file_status
964
+
965
+ def get_files_checked_out_by_others(self, file_paths: list) -> list:
966
+ """파일 목록에서 다른 사용자/워크스페이스에 의해 체크아웃된 파일들을 찾습니다.
967
+
968
+ Args:
969
+ file_paths (list): 확인할 파일 경로 리스트
970
+
971
+ Returns:
972
+ list: 다른 사용자에 의해 체크아웃된 파일 정보 리스트
973
+ [
974
+ {
975
+ 'file_path': str,
976
+ 'user': str,
977
+ 'client': str,
978
+ 'change_list': int,
979
+ 'action': str
980
+ }
981
+ ]
982
+ """
983
+ if not file_paths:
984
+ return []
985
+
986
+ result = self.check_files_checked_out_all_users(file_paths)
987
+ files_by_others = []
988
+
989
+ current_user = self.p4.user
990
+ current_client = self.p4.client
991
+
992
+ for file_path, status in result.items():
993
+ if status.get('is_checked_out', False):
994
+ file_user = status.get('user', '')
995
+ file_client = status.get('client', '')
996
+
997
+ # 다른 사용자/클라이언트에 의해 체크아웃된 경우
998
+ if (file_user != current_user) or (file_client != current_client):
999
+ files_by_others.append({
1000
+ 'file_path': file_path,
1001
+ 'user': file_user,
1002
+ 'client': file_client,
1003
+ 'change_list': status.get('change_list'),
1004
+ 'action': status.get('action', '')
1005
+ })
1006
+
1007
+ logger.info(f"다른 사용자에 의해 체크아웃된 파일: {len(files_by_others)}개")
1008
+ return files_by_others
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: pyjallib
3
- Version: 0.1.11
3
+ Version: 0.1.12
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,9 +1,9 @@
1
- pyjallib/__init__.py,sha256=p42vjyKiUbkBVpBscAl-u6DPP6RqHznA4_8tNayPIIk,509
1
+ pyjallib/__init__.py,sha256=4EmbUX3I3DLJ3DpGz7kBAADCFskvffdUEPd3HIu7-9k,509
2
2
  pyjallib/namePart.py,sha256=lKIiOVkWrtAW-D3nuv--vHmdAnlQeVPaXLYUDhcr8QU,24177
3
3
  pyjallib/nameToPath.py,sha256=aBeezepLYdpv3VYxnQ2c4ZWzz2WjticXjkdbAIlVa1k,4676
4
- pyjallib/naming.py,sha256=8Yq_j8gZuG0OeOfF0TagVVwgozZS9Ca7aIifasrqRZY,36768
5
- pyjallib/namingConfig.py,sha256=3w8Xjs_HR3R0K25eySivJn58N9MZwfpk80ySZYVI7Qw,34005
6
- pyjallib/perforce.py,sha256=GcpPmV5I30fMOnjvnNVfKVkELqA-u3Pn0474VIl7DYA,29555
4
+ pyjallib/naming.py,sha256=b2C-P9VWV4Q2StqkizEwABblYOC5g6sXHzN0KpOZ_Ys,37419
5
+ pyjallib/namingConfig.py,sha256=QGpK5mCnRiclKqNKz3GJ2PeJO8fbVitAEdqWwnwo8oA,34127
6
+ pyjallib/perforce.py,sha256=XcF-YG250bh3obOkajPzMNwaJcCmXKIHIlJIEEFw6JE,46459
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
@@ -11,7 +11,7 @@ pyjallib/max/__init__.py,sha256=sLF07So7OcCccPOWixSjIkAhuye37-buK-1I5Hp8F4U,1537
11
11
  pyjallib/max/align.py,sha256=HKjCViQCuicGmtvHB6xxVv4BEGEBGtV2gO3NvR_6R2A,5183
12
12
  pyjallib/max/anim.py,sha256=QTpR8T047IMpV40wnMMNo080wY9rHMV9k7ISrh4P61I,26083
13
13
  pyjallib/max/autoClavicle.py,sha256=Iga8bWUhRabfFePObdwGJSshp5Gww1Jv1Hwcul_y0V4,9559
14
- pyjallib/max/bip.py,sha256=J0i-ZK2MO2hYS4aeRfTeGnIJxoCXmM-3ZftEPsBYLPU,27394
14
+ pyjallib/max/bip.py,sha256=kEneUnYph_GQXY1oojmzpJOV9bAYNBKagE0Ht3EGZ7o,30199
15
15
  pyjallib/max/bone.py,sha256=XVtX6e5UbMcGaOqz5UeoMEpQNMfbyQWDNM-UuS1CCUA,50019
16
16
  pyjallib/max/boneChain.py,sha256=weuOmGk7Y7i-0QNCr7G2hRPOecb5xmErshqpmXtikI0,5660
17
17
  pyjallib/max/constraint.py,sha256=93g-X0aZHtZMKXVKr8xMjIhbKou61yc2b3ubQKJquBs,40589
@@ -38,6 +38,6 @@ pyjallib/max/macro/jal_macro_helper.py,sha256=hd8e5x56aq7Qt0g-hP5bY0p-njVy8ja77_
38
38
  pyjallib/max/macro/jal_macro_link.py,sha256=E8i3z2xsrQiGDEz4Qoxc75hkpalzS95mOMcIic0J-Fc,1193
39
39
  pyjallib/max/macro/jal_macro_select.py,sha256=jeSFR_mqqudTTrZE1rU6qifJ4g441cYxXWcHPTWh1CU,2289
40
40
  pyjallib/max/ui/Container.py,sha256=QSk3oCqhfiR4aglSSkherRGAyPFqMRUt83L-0ENBz-s,5571
41
- pyjallib-0.1.11.dist-info/METADATA,sha256=FXi5CkTZfVvCBHO3IpxZEgWOfhsl3USJJk97DSuMXjI,870
42
- pyjallib-0.1.11.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
- pyjallib-0.1.11.dist-info/RECORD,,
41
+ pyjallib-0.1.12.dist-info/METADATA,sha256=0jeCReJS2g2RlmWhefBDeSPwlIoFDturmBEqrw_s3Y8,870
42
+ pyjallib-0.1.12.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
43
+ pyjallib-0.1.12.dist-info/RECORD,,