rimworld-animations/1.6/Source/Utilities/AnimationUtility.cs
2025-10-02 08:53:32 -07:00

167 lines
6.2 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using HarmonyLib;
using RimWorld;
using UnityEngine;
using Verse;
using Verse.AI;
namespace Rimworld_Animations {
public static class AnimationUtility
{
public static void StartAnimation(List<Pawn> participants)
{
participants[0].Drawer.renderer.SetAnimation(AnimationDefOf.TestAnimation1);
participants[1].Drawer.renderer.SetAnimation(AnimationDefOf.TestAnimation2);
}
//startgroupanimator with anchor
//don't anchor to self if anchor is self
public static void StartGroupAnimation(List<Pawn> participants, GroupAnimationDef groupAnimationDef, Thing anchor)
{
int seed = GenTicks.TicksGame;
for (int i = 0; i < participants.Count; i++)
{
if (anchor is Pawn pawn && pawn == participants[i])
{
participants[i].TryGetComp<CompExtendedAnimator>().PlayGroupAnimation(groupAnimationDef, null, i, seed, participants);
}
else
{
BaseExtendedAnimatorAnchor animatorAnchor = new ExtendedAnimatorAnchor_Thing(anchor);
participants[i].TryGetComp<CompExtendedAnimator>().PlayGroupAnimation(groupAnimationDef, animatorAnchor, i, seed, participants);
}
}
}
//startgroupanimation without anchor; just play where standing
public static void StartGroupAnimation(List<Pawn> participants, GroupAnimationDef groupAnimationDef)
{
int seed = GenTicks.TicksGame;
for (int i = 0; i < participants.Count; i++)
{
participants[i].TryGetComp<CompExtendedAnimator>().PlayGroupAnimation(groupAnimationDef, i, seed, participants);
}
}
public static void StopGroupAnimation(List<Pawn> participants)
{
foreach (Pawn pawn in participants)
{
pawn.TryGetComp<CompExtendedAnimator>()?.StopAnimating();
}
}
public static void StopGroupAnimation(Pawn participant)
{
participant.TryGetComp<CompExtendedAnimator>()?.StopAnimating();
}
public static GroupAnimationDef FindGroupAnimation(List<Pawn> participants, out List<Pawn> pawnOrder)
{
/* This method is fooken expensive
List<(GroupAnimationDef, List<Pawn>, int Priority)> potentialAnimations = new List<(GroupAnimationDef, List<Pawn>, int)>();
List<List<Pawn>> participantPermutations = GetPermutations(participants);
//for each groupanimationdef where the number of participants matches the number of actors,
foreach (GroupAnimationDef groupAnimationDef in DefDatabase<GroupAnimationDef>.AllDefsListForReading.Where(x => x.numActors == participants.Count))
{
//ignore groupanimations without contexts; those are usu. branches
if (groupAnimationDef.contexts.NullOrEmpty()) continue;
//check all permutations of the list of pawns, with each groupanimationdef
foreach (List<Pawn> participantPermutation in participantPermutations)
{
//if groupanimation works with that particular pawn permutation,
if (groupAnimationDef.CanAnimationBeUsed(participantPermutation, out int priority, out int contextNum))
{
//add it to the list of potential animations, in a tuple with that permutation
potentialAnimations.Add((groupAnimationDef, participantPermutation, priority));
}
}
}
*/
List<(GroupAnimationDef, List<Pawn>, int Priority)> potentialAnimations = new List<(GroupAnimationDef, List<Pawn>, int)>();
foreach (GroupAnimationDef groupAnimationDef in DefDatabase<GroupAnimationDef>.AllDefsListForReading)
{
if (groupAnimationDef.CanAnimationBeUsed(participants, out List<Pawn> bestPermutation, out int highestPriority))
{
potentialAnimations.Add((groupAnimationDef, bestPermutation, highestPriority));
}
}
//Randomize the list,
potentialAnimations.OrderBy(_ => Rand.Int);
(GroupAnimationDef, List<Pawn>, int) selectedAnimation;
potentialAnimations.TryRandomElementByWeight(((GroupAnimationDef, List<Pawn>, int) x) => x.Item3, out selectedAnimation);
//Find a highest priority animation, out as selectedAnimation
// .TryMaxBy(((GroupAnimationDef, List<Pawn>, int) x) => x.Item3, out (GroupAnimationDef, List<Pawn>, int) selectedAnimation);
//set pawnOrder as selected animation permutation
pawnOrder = selectedAnimation.Item2;
//return selected animation
return selectedAnimation.Item1;
}
public static int GetAnimationLength(Pawn pawn)
{
return pawn.TryGetComp<CompExtendedAnimator>().AnimationLength;
}
public static string OffsetLookupKey(Pawn pawn)
{
string bodyTypeDef = (pawn.story?.bodyType != null) ? pawn.story.bodyType.ToString() : "";
CompExtendedAnimator extendedAnimator = pawn.TryGetComp<CompExtendedAnimator>();
return extendedAnimator.CurrentGroupAnimation.defName + pawn.def.defName + bodyTypeDef + extendedAnimator.ActorIndex;
}
static List<List<T>> GetPermutations<T>(List<T> list)
{
if (list.Count == 0) return new List<List<T>> { new List<T>() };
var result = new List<List<T>>();
for (int i = 0; i < list.Count; i++)
{
var element = list[i];
var remaining = list.Where((_, index) => index != i).ToList();
foreach (var permutation in GetPermutations(remaining))
{
permutation.Insert(0, element);
result.Add(permutation);
}
}
return result;
}
}
}