using HarmonyLib; using RimWorld; using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.Threading.Tasks; using UnityEngine; using Verse; namespace Rimworld_Animations { [HarmonyPatch(typeof(PawnRenderTree), "TryGetMatrix")] public class HarmonyPatch_PawnRenderTree { public static bool Prefix(PawnRenderTree __instance, Dictionary ___nodesByTag, Dictionary> ___nodeAncestors, PawnRenderNode node, ref PawnDrawParms parms, ref Matrix4x4 matrix, ref bool __result) { /* * Facing offsets fix */ //find lowest parent that is animating, or nothing if not animating //don't do anything if portrait if (parms.Portrait) return true; PawnRenderNode animatingNode = node; while (animatingNode != null && !(animatingNode.AnimationWorker is AnimationWorker_KeyframesExtended)) { animatingNode = animatingNode.parent; } //if animating parent node found, if (animatingNode?.AnimationWorker is AnimationWorker_KeyframesExtended animatingNodeAnimationWorker) { //change parm to facing to animate correctly parms.facing = animatingNodeAnimationWorker.facingAtTick(__instance.AnimationTick, animatingNode.tree.currentAnimation, animatingNode); } /* * Set Render Node to absolute transform */ if (node.Props is PawnRenderNodeProperties_GraphicVariants graphicVariantProp) { //absolute transform -- floating if (graphicVariantProp.absoluteTransform) { matrix = parms.matrix; //absolute transform -- just use the node's transform, not its ancestors node.GetTransform(parms, out Vector3 offset, out Vector3 pivot, out Quaternion quaternion, out Vector3 scale); if (offset != Vector3.zero) matrix *= Matrix4x4.Translate(offset); if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(pivot); if (quaternion != Quaternion.identity) matrix *= Matrix4x4.Rotate(quaternion); if (scale != Vector3.one) matrix *= Matrix4x4.Scale(scale); if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(scale).inverse; float num = node.Worker.AltitudeFor(node, parms); if (num != 0f) { matrix *= Matrix4x4.Translate(Vector3.up * num); } __result = true; return false; } //for graphic variant props to scale independently else if (graphicVariantProp.scaleIndependently) { matrix = parms.matrix; if (!___nodeAncestors.TryGetValue(node, out var value)) { __instance.SetDirty(); AccessTools.Method(typeof(PawnRenderTree), "TrySetupGraphIfNeeded").Invoke(__instance, new object[] { }); if (!___nodeAncestors.TryGetValue(node, out value)) { __result = false; return false; } } for (int i = 0; i < value.Count; i++) { value[i].GetTransform(parms, out var offset, out var pivot, out var rotation, out var scale); bool canRotate = !node.Props.rotateIndependently || value[i] == node; bool canScale = !graphicVariantProp.scaleIndependently || value[i] == node; if (offset != Vector3.zero) matrix *= Matrix4x4.Translate(offset); if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(pivot); if (canRotate && rotation != Quaternion.identity) matrix *= Matrix4x4.Rotate(rotation); if (canScale && scale != Vector3.one) matrix *= Matrix4x4.Scale(scale); if (pivot != Vector3.zero) matrix *= Matrix4x4.Translate(scale).inverse; } float num = node.Worker.AltitudeFor(node, parms); if (num != 0f) { matrix *= Matrix4x4.Translate(Vector3.up * num); } __result = true; return false; } } return true; } } //recaching //done here because changing parms causes recaching anyway, so might as well do it here [HarmonyPatch(typeof(PawnRenderTree), "AdjustParms")] public class HarmonyPatch_PawnRenderTree2 { public static void Prefix(PawnRenderTree __instance, ref PawnDrawParms parms) { int animationTick = __instance.AnimationTick; if (__instance.rootNode.AnimationWorker is AnimationWorker_KeyframesExtended rootAnimWorkerExtended) { //recache during facing turn if (rootAnimWorkerExtended.shouldRecache(animationTick, __instance.currentAnimation, __instance.rootNode)) { __instance.rootNode.requestRecache = true; return; } } foreach (PawnRenderNode node in __instance.rootNode.children) { if (node.AnimationWorker is AnimationWorker_KeyframesExtended animWorkerExtended) { //recache during flicker on/off if (animWorkerExtended.shouldRecache(animationTick, node.tree.currentAnimation, node)) { node.requestRecache = true; return; } } } } } }