Skip to content

Commit

Permalink
WIP Anim API
Browse files Browse the repository at this point in the history
  • Loading branch information
ang-xd committed Sep 5, 2024
1 parent fa8fdfc commit 34b89c5
Show file tree
Hide file tree
Showing 10 changed files with 224 additions and 15 deletions.
46 changes: 46 additions & 0 deletions MiraAPI/Animations/AnimationPresetManager.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
using MiraAPI.Animations;
using System;
using System.Collections.Generic;

namespace MiraAPI.Modifiers;

/// <summary>
/// The manager for handling modifiers.
/// </summary>
public static class AnimationPresetManager
{
private static uint _nextId;

/// <summary>
/// Gets registered Animation Presets.
/// </summary>
public static List<CustomAnimationPreset> Presets { get; internal set; } = new List<CustomAnimationPreset>();

private static uint GetNextId()
{
_nextId++;
return _nextId;
}

/// <summary>
/// Get Animation Preset by ID.
/// </summary>
/// <param name="id">The id of the preset you want to find.</param>
/// <returns>The animation preset.</returns>
public static CustomAnimationPreset? GetPresetById(uint id)
{
return Presets.Find(p => p.Id == id);
}

internal static void RegisterPreset(Type modifierType)
{
if (!typeof(CustomAnimationPreset).IsAssignableFrom(modifierType))
{
return;
}

CustomAnimationPreset preset = (CustomAnimationPreset)Activator.CreateInstance(modifierType);

Check warning on line 42 in MiraAPI/Animations/AnimationPresetManager.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
preset.Id = GetNextId();

Check warning on line 43 in MiraAPI/Animations/AnimationPresetManager.cs

View workflow job for this annotation

GitHub Actions / build

Dereference of a possibly null reference.
Presets.Add(preset);
}
}
24 changes: 24 additions & 0 deletions MiraAPI/Animations/CustomAnimationPreset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
using UnityEngine;

namespace MiraAPI.Animations;

/// <summary>
/// Configure an animation's settings using presets.
/// </summary>
/// <param name="clip">The animation clip the preset will use.</param>
public abstract class CustomAnimationPreset(AnimationClip clip)

Check warning on line 9 in MiraAPI/Animations/CustomAnimationPreset.cs

View workflow job for this annotation

GitHub Actions / build

Parameter 'clip' is unread.
{
internal uint Id;

internal void PlayAnimation(PlayerControl source)
{

}

/// <summary>
/// Check whether the local player should be able to see this animation.
/// </summary>
/// <param name="source">The player who the animation is being triggered upon.</param>
/// <returns>Whether the local player can see the animation or not.</returns>
public abstract bool AnimationVisible(PlayerControl source);
}
38 changes: 38 additions & 0 deletions MiraAPI/Animations/CustomAnimator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
using MiraAPI.Animations.Presets;
using MiraAPI.Modifiers;
using MiraAPI.Networking;
using MiraAPI.Utilities;
using Reactor.Networking.Attributes;
using Reactor.Utilities.Attributes;
using System;
using UnityEngine;

namespace MiraAPI.Animations;

[RegisterInIl2Cpp]
public class CustomAnimator(IntPtr cppPtr) : MonoBehaviour(cppPtr)

Check warning on line 13 in MiraAPI/Animations/CustomAnimator.cs

View workflow job for this annotation

GitHub Actions / build

Non-nullable field '_player' must contain a non-null value when exiting constructor. Consider adding the 'required' modifier or declaring the field as nullable.

Check warning on line 13 in MiraAPI/Animations/CustomAnimator.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'CustomAnimator'

Check warning on line 13 in MiraAPI/Animations/CustomAnimator.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'CustomAnimator.CustomAnimator(IntPtr)'
{
private PlayerControl _player;

private void Start()
{
_player = gameObject.GetComponent<PlayerControl>();

_player.GetCustomAnimator()?.TriggerCustomAnimation(new LocalAnimationPreset(new AnimationClip()));
}

public void TriggerCustomAnimation(CustomAnimationPreset preset) => RpcTriggerCustomAnimation(_player, preset.Id);

Check warning on line 24 in MiraAPI/Animations/CustomAnimator.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'CustomAnimator.TriggerCustomAnimation(CustomAnimationPreset)'


[MethodRpc((uint)MiraRpc.TriggerAnimation)]
internal static void RpcTriggerCustomAnimation(PlayerControl source, uint presetId)
{
CustomAnimationPreset preset = AnimationPresetManager.GetPresetById(presetId);

Check warning on line 30 in MiraAPI/Animations/CustomAnimator.cs

View workflow job for this annotation

GitHub Actions / build

Converting null literal or possible null value to non-nullable type.
if (preset is null) return;

if (preset.AnimationVisible(source))
{
preset.PlayAnimation(source);
}
}
}
11 changes: 11 additions & 0 deletions MiraAPI/Animations/Presets/LocalAnimationPreset.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
using UnityEngine;

namespace MiraAPI.Animations.Presets;
public class LocalAnimationPreset(AnimationClip clip) : CustomAnimationPreset(clip)

Check warning on line 4 in MiraAPI/Animations/Presets/LocalAnimationPreset.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'LocalAnimationPreset'

Check warning on line 4 in MiraAPI/Animations/Presets/LocalAnimationPreset.cs

View workflow job for this annotation

GitHub Actions / build

Missing XML comment for publicly visible type or member 'LocalAnimationPreset.LocalAnimationPreset(AnimationClip)'
{
/// <inheritdoc/>
public override bool AnimationVisible(PlayerControl source)
{
return source.AmOwner;
}
}
6 changes: 6 additions & 0 deletions MiraAPI/Animations/RegisterAnimationPresetAttribute.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
using System;

namespace MiraAPI.Animations;

[AttributeUsage(AttributeTargets.Class)]
public class RegisterAnimationPresetAttribute : Attribute;
5 changes: 5 additions & 0 deletions MiraAPI/Networking/MiraRpc.cs
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,9 @@ public enum MiraRpc : uint
/// Custom Murder RPC.
/// </summary>
CustomMurder,

/// <summary>
/// Trigger Animation using CustomAnimator.
/// </summary>
TriggerAnimation,
}
15 changes: 13 additions & 2 deletions MiraAPI/Patches/PlayerControlPatches.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
using HarmonyLib;
using MiraAPI.Animations;
using MiraAPI.Hud;
using MiraAPI.Modifiers;
using MiraAPI.Roles;
Expand All @@ -13,8 +14,9 @@ namespace MiraAPI.Patches;
public static class PlayerControlPatches
{
/// <summary>
/// Adds the modifier component to the player on start.
/// Adds the modifier and animator component to the player on start.
/// </summary>
/// <param name="__instance">The player which will be given the components.</param>
[HarmonyPrefix]
[HarmonyPatch(nameof(PlayerControl.Start))]
public static void PlayerControlStartPostfix(PlayerControl __instance)
Expand All @@ -24,12 +26,20 @@ public static void PlayerControlStartPostfix(PlayerControl __instance)
comp.DestroyImmediate();
}

if (__instance.gameObject.TryGetComponent<CustomAnimator>(out var anim))
{
anim.DestroyImmediate();
}

__instance.gameObject.AddComponent<CustomAnimator>();
__instance.gameObject.AddComponent<ModifierComponent>();
}

/// <summary>
/// Calls the OnDeath method for all active modifiers.
/// </summary>
/// <param name="__instance">The player who died.</param>
/// <param name="reason">The reason of the death.</param>
[HarmonyPostfix]
[HarmonyPatch(nameof(PlayerControl.Die))]
public static void PlayerControlDiePostfix(PlayerControl __instance, DeathReason reason)
Expand All @@ -38,13 +48,14 @@ public static void PlayerControlDiePostfix(PlayerControl __instance, DeathReason

if (modifiersComponent)
{
modifiersComponent.ActiveModifiers.ForEach(x=>x.OnDeath(reason));
modifiersComponent.ActiveModifiers.ForEach(x => x.OnDeath(reason));
}
}

/// <summary>
/// FixedUpdate handler for custom roles and custom buttons.
/// </summary>
/// <param name="__instance">The player who's fixed update is being called.</param>
[HarmonyPostfix]
[HarmonyPatch(nameof(PlayerControl.FixedUpdate))]
public static void PlayerControlFixedUpdatePostfix(PlayerControl __instance)
Expand Down
34 changes: 28 additions & 6 deletions MiraAPI/PluginLoading/MiraPluginManager.cs
Original file line number Diff line number Diff line change
@@ -1,26 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using BepInEx.Unity.IL2CPP;
using BepInEx.Unity.IL2CPP;
using MiraAPI.Animations;
using MiraAPI.Colors;
using MiraAPI.GameOptions;
using MiraAPI.GameOptions.Attributes;
using MiraAPI.Hud;
using MiraAPI.Modifiers;
using MiraAPI.Roles;
using MiraAPI.Utilities;
using MiraAPI.Utilities.Assets;
using Reactor.Networking;
using Reactor.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;

namespace MiraAPI.PluginLoading;

internal sealed class MiraPluginManager
{
private readonly Dictionary<Assembly, MiraPluginInfo> _registeredPlugins = [];

internal MiraPluginInfo[] RegisteredPlugins() => [.. _registeredPlugins.Values];

public List<LoadableBundleAsset<UnityEngine.Object>> BundleAssets = new();
internal uint NextAssetId { get; private set; }
internal uint GetNextAssetId()
{
NextAssetId++;
return NextAssetId;
}

public static MiraPluginManager Instance { get; private set; } = new();

internal void Initialize()
Expand All @@ -36,6 +45,7 @@ internal void Initialize()
var info = new MiraPluginInfo(miraPlugin, pluginInfo);
RegisterModifierAttribute(assembly);
RegisterAnimPresetAttribute(assembly);
RegisterAllOptions(assembly, info);
RegisterRoleAttribute(assembly, info);
Expand Down Expand Up @@ -161,6 +171,18 @@ private static void RegisterModifierAttribute(Assembly assembly)
}
}

private static void RegisterAnimPresetAttribute(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
{
var attribute = type.GetCustomAttribute<RegisterAnimationPresetAttribute>();
if (attribute != null)
{
AnimationPresetManager.RegisterPreset(type);
}
}
}

private static void RegisterButtonAttribute(Assembly assembly)
{
foreach (var type in assembly.GetTypes())
Expand Down
31 changes: 27 additions & 4 deletions MiraAPI/Utilities/Assets/LoadableBundleAsset.cs
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
using System;
using MiraAPI.PluginLoading;
using Reactor.Utilities.Extensions;
using System;
using UnityEngine;

namespace MiraAPI.Utilities.Assets;
Expand All @@ -10,8 +11,30 @@ namespace MiraAPI.Utilities.Assets;
/// <param name="name">The name of the asset.</param>
/// <param name="bundle">The AssetBundle that contains the asset.</param>
/// <typeparam name="T">The type of the asset to be loaded.</typeparam>
public class LoadableBundleAsset<T>(string name, AssetBundle bundle) : LoadableAsset<T> where T : UnityEngine.Object
public class LoadableBundleAsset<T> : LoadableAsset<T> where T : UnityEngine.Object
{

/// <summary>
/// Gets the ID of this asset. Used for networking.
/// </summary>
public uint AssetId { get; internal set; }
private string _name { get; }
private AssetBundle _bundle { get; }

/// <summary>
/// Initializes a new instance of the <see cref="LoadableBundleAsset{T}"/> class.
/// </summary>
/// <param name="name">Name of the bundle.</param>
/// <param name="bundle">Asset bundle.</param>
public LoadableBundleAsset(string name, AssetBundle bundle)
{
AssetId = MiraPluginManager.Instance.GetNextAssetId();
//MiraPluginManager.Instance.BundleAssets.Add((LoadableBundleAsset<Object>)this);

_name = name;
_bundle = bundle;
}

/// <summary>
/// Loads the asset from the asset bundle.
/// </summary>
Expand All @@ -24,11 +47,11 @@ public override T LoadAsset()
return LoadedAsset;
}

LoadedAsset = bundle.LoadAsset<T>(name);
LoadedAsset = _bundle.LoadAsset<T>(_name);

if (LoadedAsset == null)
{
throw new InvalidOperationException($"INVALID ASSET: {name}");
throw new InvalidOperationException($"INVALID ASSET: {_name}");
}

return LoadedAsset;
Expand Down
29 changes: 26 additions & 3 deletions MiraAPI/Utilities/Extensions.cs
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
using System;
using System.Collections.Generic;
using System.Linq;
using HarmonyLib;
using MiraAPI.Animations;
using MiraAPI.GameOptions;
using MiraAPI.Modifiers;
using MiraAPI.Networking;
using MiraAPI.Roles;
using Reactor.Networking.Attributes;
using Reactor.Utilities;
using System;
using System.Collections.Generic;
using System.Linq;
using UnityEngine;

namespace MiraAPI.Utilities;
Expand Down Expand Up @@ -116,6 +117,7 @@ public static bool IsCustom(this OptionBehaviour optionBehaviour)
}

private static readonly Dictionary<PlayerControl, ModifierComponent> ModifierComponents = [];
private static readonly Dictionary<PlayerControl, CustomAnimator> AnimatorComponents = [];

/// <summary>
/// Gets the ModifierComponent for a player.
Expand All @@ -138,6 +140,27 @@ public static bool IsCustom(this OptionBehaviour optionBehaviour)
return component;
}

/// <summary>
/// Gets the CustomAnimator for a player.
/// </summary>
/// <param name="player">The PlayerControl object.</param>
/// <returns>A CustomAnimator if there is one, null otherwise.</returns>
public static CustomAnimator? GetCustomAnimator(this PlayerControl player)
{
if (AnimatorComponents.TryGetValue(player, out var component))
{
return component;
}

component = player.GetComponent<CustomAnimator>();
if (component)
{
AnimatorComponents[player] = component;
}

return component;
}

/// <summary>
/// Randomizes a list.
/// </summary>
Expand Down

0 comments on commit 34b89c5

Please sign in to comment.