summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoryum <yum.food.vr@gmail.com>2022-10-20 18:42:42 -0700
committeryum <yum.food.vr@gmail.com>2022-10-20 18:44:08 -0700
commit3a0fe46d258559e641d0b379443280a549ff154f (patch)
treeadf2f71b48035720f4295d437387d40f24fd7afd
parentd7c225ab3fcad600e93e9464886702fd269fedd5 (diff)
Add preliminary support for negative anchors
Some animators generate negative anchors. Casting to u64 doesn't produce an anchor with a valid prefix, so idk what it is. Use the class ID from the little !u! bit instead of deriving it from the anchor. Some things probably don't work yet.
-rw-r--r--libunity.py92
1 files changed, 40 insertions, 52 deletions
diff --git a/libunity.py b/libunity.py
index 2e375af..0ecc5e2 100644
--- a/libunity.py
+++ b/libunity.py
@@ -362,44 +362,14 @@ class Mapping(Node):
for k, v in self.mapping.items():
cb(v)
-def classId(anchor):
- # AnimatorController
- if anchor.startswith("91"):
- return "91"
- # MonoBehaviour
- if anchor.startswith("114"):
- return "114"
- # BlendTree
- if anchor.startswith("206"):
- return "206"
- # AnimatorStateTransition
- if anchor.startswith("1101"):
- return "1101"
- # AnimatorState
- if anchor.startswith("1102"):
- return "1102"
- # AnimatorStateMachine
- if anchor.startswith("1107"):
- return "1107"
- # AnimatorTransition
- if anchor.startswith("1109"):
- return "1109"
-
- # IDK what this is lmao
- if anchor.startswith("74"):
- return "74"
- if anchor.startswith("115"):
- return "115"
-
- raise Exception("Unrecognized object: {}".format(anchor))
-
class UnityDocument(Mapping):
+ def __init__(self):
+ super().__init__()
+ self.class_id = None
+
def __str__(self):
return super().__str__()
- def classId(self):
- return classId(self.anchor)
-
# Class representing a Unity AnimatorController. Implements manipulations, like
# merging and reanchoring.
class UnityAnimator():
@@ -421,11 +391,11 @@ class UnityAnimator():
raise Exception("Duplicate anchor: {}, node 1: {}, node 2: {}".format(anchor, str(node), str(self.id_to_node[anchor])))
self.id_to_node[anchor] = node
- if classId(anchor) in self.class_to_next_id:
- cur_next = self.class_to_next_id[classId(anchor)]
- self.class_to_next_id[classId(anchor)] = max(int(anchor), cur_next)
+ if node.class_id in self.class_to_next_id:
+ cur_next = self.class_to_next_id[node.class_id]
+ self.class_to_next_id[node.class_id] = max(int(anchor), cur_next)
else:
- self.class_to_next_id[classId(anchor)] = int(anchor)
+ self.class_to_next_id[node.class_id] = int(anchor)
for k in self.class_to_next_id.keys():
self.class_to_next_id[k] += 1
@@ -442,18 +412,18 @@ class UnityAnimator():
return new_id
- def getUniqueId(self, anchor):
+ def getUniqueId(self, node):
# For whatever reason, generating a new ID for the MonoBehaviour
# embedded in VRChat's default animation ctrler makes Unity spit out
# warnings. Reuse the old one.
- if classId(anchor) == "114":
- return int(anchor)
+ if node.class_id == "114":
+ return int(node.anchor)
- if anchor in self.id_mapping.keys():
- return self.id_mapping[anchor]
+ if node.anchor in self.id_mapping.keys():
+ return self.id_mapping[node.anchor]
- new_id = self.allocateId(classId(anchor))
- self.id_mapping[anchor] = new_id
+ new_id = self.allocateId(node.class_id)
+ self.id_mapping[node.anchor] = new_id
return new_id
def mergeIterator(self, v):
@@ -470,14 +440,14 @@ class UnityAnimator():
def peekNodeOfClass(self, classId):
for node in self.nodes:
- if node.classId() == classId:
+ if node.class_id == classId:
return node
return None
def popNodeOfClass(self, classId):
result = None
for node in self.nodes:
- if node.classId() == classId:
+ if node.class_id == classId:
result = node
self.nodes.remove(result)
break
@@ -529,13 +499,13 @@ class UnityAnimator():
# Mapping from class ID (string) to new class ID (int)
self.id_mapping = self.id_mapping0
for node in self.nodes:
- new_id = self.getUniqueId(node.anchor)
+ new_id = self.getUniqueId(node)
node.anchor = str(new_id)
node.forEach(self.mergeIterator)
self.id_mapping = self.id_mapping1
for node in other.nodes:
- new_id = self.getUniqueId(node.anchor)
+ new_id = self.getUniqueId(node)
node.anchor = str(new_id)
node.forEach(self.mergeIterator)
@@ -587,6 +557,7 @@ class UnityAnimator():
# Create layer object
layer = UnityDocument()
+ layer.class_id = "1107"
layer.anchor = str(new_id)
mach = layer.addChildMapping('AnimatorStateMachine')
@@ -633,6 +604,7 @@ class UnityAnimator():
node = new_anim.nodes[0]
new_id = self.allocateId('1102')
+ node.class_id = "1102"
node.anchor = str(new_id)
state = node.mapping['AnimatorState']
state.mapping['m_Name'] = state_name
@@ -665,6 +637,7 @@ class UnityAnimator():
node = new_transition.nodes[0]
new_id = self.allocateId('1101')
+ node.class_id = "1101"
node.anchor = str(new_id)
state = node.mapping['AnimatorStateTransition']
state.mapping['m_DstState'].mapping['fileID'] = dst_state_id
@@ -691,7 +664,7 @@ class UnityAnimator():
animator_state_id = '1102'
for node in self.nodes:
- if node.classId() != animator_state_id:
+ if node.class_id != animator_state_id:
continue
# Looking at an animator state.
@@ -851,7 +824,7 @@ class UnityAnimator():
noop_anim_meta.load(noop_anim_path)
for node in self.nodes:
- if classId(node.anchor) != "1102":
+ if node.class_id != "1102":
continue
motion = node.mapping['AnimatorState'].mapping['m_Motion']
replace = False
@@ -873,7 +846,7 @@ def unityAnimatorToString(nodes):
"""[1:][:-1]
lines.append(preamble)
for doc in nodes:
- lines.append("--- !u!" + doc.classId() + " &" + doc.anchor)
+ lines.append("--- !u!" + doc.class_id + " &" + doc.anchor)
lines.append(str(doc))
result = '\n'.join(lines)
@@ -940,6 +913,19 @@ class UnityParser:
lines.append("...\n")
return '\n'.join(lines)
+ def getClassIds(self, yaml_str):
+ anchor_to_class_id = {}
+ for line in yaml_str.split("\n"):
+ if not line.startswith("---"):
+ continue
+
+ parts = line.split()
+ class_id = parts[1][3:]
+ anchor = parts[2][1:]
+ anchor_to_class_id[anchor] = class_id
+
+ return anchor_to_class_id
+
def parseFile(self, yaml_file):
yaml_str = ""
with open(yaml_file, "r") as f:
@@ -947,6 +933,7 @@ class UnityParser:
return self.parse(yaml_str)
def parse(self, yaml_str):
+ anchor_to_class_id = self.getClassIds(yaml_str)
yaml_str = self.cleanYaml(yaml_str)
for event in yaml.parse(yaml_str):
@@ -978,6 +965,7 @@ class UnityParser:
if self.cur_node == None:
self.cur_node = UnityDocument()
self.cur_node.anchor = event.anchor
+ self.cur_node.class_id = anchor_to_class_id[event.anchor]
else:
self.cur_node = self.cur_node.addChildMapping(self.cur_scalar)
self.pushState(self.MAPPING_START)