Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of DrifterBracken v2.1.0
DrifterBracken.dll
Decompiled 4 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using HarmonyLib; using Microsoft.CodeAnalysis; using UnityEngine; using UnityEngine.AI; using UnityEngine.Animations; using UnityEngine.InputSystem; using UnityEngine.InputSystem.Controls; using UnityEngine.Playables; using UnityEngine.Rendering.HighDefinition; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("DrifterBracken")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.18.0.0")] [assembly: AssemblyInformationalVersion("1.18.0")] [assembly: AssemblyProduct("DrifterBracken")] [assembly: AssemblyTitle("DrifterBracken")] [assembly: AssemblyVersion("1.18.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace DrifterBracken { public class BrackenAnimTester : MonoBehaviour { private static BrackenAnimTester _primary; private Animator _animator; private AnimationClip[] _clips = (AnimationClip[])(object)new AnimationClip[0]; private RuntimeAnimatorController _originalController; private readonly List<Behaviour> _suspended = new List<Behaviour>(); private PlayableGraph _graph; private AnimationClipPlayable _playable; private bool _graphLive; private Transform[] _recBones = (Transform[])(object)new Transform[0]; private readonly List<PoseClip> _recClips = new List<PoseClip>(); private readonly List<PoseFrame> _recFrames = new List<PoseFrame>(); private float _recAccum; private const float RecFps = 20f; private int _index; private float _timer; private bool _running; private bool _paused; private bool _held; private float _heldSpeed = 1f; private void Awake() { _animator = ((Component)this).GetComponentInChildren<Animator>(true); if ((Object)(object)_animator == (Object)null) { ((Behaviour)this).enabled = false; return; } _clips = (AnimationClip[])(((Object)(object)_animator.runtimeAnimatorController == (Object)null) ? ((Array)new AnimationClip[0]) : ((Array)(from c in _animator.runtimeAnimatorController.animationClips where (Object)(object)c != (Object)null group c by ((Object)c).name into grp select grp.First() into c orderby ((Object)c).name select c).ToArray())); SkinnedMeshRenderer val = ((IEnumerable<SkinnedMeshRenderer>)((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true)).FirstOrDefault((Func<SkinnedMeshRenderer, bool>)((SkinnedMeshRenderer r) => r.bones != null && r.bones.Length > 60)); if ((Object)(object)val != (Object)null) { _recBones = val.bones.Where((Transform b) => (Object)(object)b != (Object)null).ToArray(); } if ((Object)(object)_primary == (Object)null) { _primary = this; } Plugin.Log.LogInfo((object)("Test mode: " + _clips.Length + " clips on '" + ((Object)this).name + "' -> " + string.Join(", ", _clips.Select((AnimationClip c) => ((Object)c).name).ToArray()))); } private void OnDestroy() { Stop(); Release(); if ((Object)(object)_primary == (Object)(object)this) { _primary = null; } } private void Update() { bool flag = Plugin.HoldActive && !Plugin.TestActive; if (flag && !_held) { HoldStill(); } else if (!flag && _held) { Release(); } if (Plugin.TestActive && !_running) { Begin(); } else if (!Plugin.TestActive && _running) { Stop(); } if (!_running || _clips.Length == 0) { return; } if (Plugin.ConsumeStep(out var step)) { Show(_index + step); return; } if (Plugin.ConsumePause()) { _paused = !_paused; } if (!_paused) { if (Plugin.RecordPoses.Value && (Object)(object)_primary == (Object)(object)this) { Sample(); } _timer += Time.deltaTime; float num = _clips[_index].length; if (num <= 0.01f) { num = 2f; } if (_timer >= num + Plugin.TestHold.Value) { Show(_index + 1); } } } private void Begin() { //IL_0043: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) _running = true; Suspend(); _originalController = _animator.runtimeAnimatorController; _animator.runtimeAnimatorController = null; _graph = PlayableGraph.Create("DrifterBrackenTest:" + ((Object)this).GetInstanceID()); ((PlayableGraph)(ref _graph)).SetTimeUpdateMode((DirectorUpdateMode)1); AnimationPlayableOutput val = AnimationPlayableOutput.Create(_graph, "anim", _animator); _playable = AnimationClipPlayable.Create(_graph, (_clips.Length != 0) ? _clips[0] : null); PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationClipPlayable>(val, _playable); _graphLive = true; ((PlayableGraph)(ref _graph)).Play(); _index = -1; Show(0); Plugin.Log.LogInfo((object)("Test mode ON - frozen, cycling " + _clips.Length + " clips.")); } private void Stop() { if (_running) { _running = false; _paused = false; if (_graphLive && ((PlayableGraph)(ref _graph)).IsValid()) { ((PlayableGraph)(ref _graph)).Destroy(); } _graphLive = false; if ((Object)(object)_animator != (Object)null) { _animator.runtimeAnimatorController = _originalController; } Resume(); Plugin.Log.LogInfo((object)"Test mode OFF - Bracken released."); } } private void Suspend() { //IL_0081: Unknown result type (might be due to invalid IL or missing references) _suspended.Clear(); MonoBehaviour[] components = ((Component)this).GetComponents<MonoBehaviour>(); foreach (MonoBehaviour val in components) { if (!((Object)(object)val == (Object)null) && !((Object)(object)val == (Object)(object)this) && ((Behaviour)val).enabled && val is EnemyAI) { ((Behaviour)val).enabled = false; _suspended.Add((Behaviour)(object)val); } } NavMeshAgent component = ((Component)this).GetComponent<NavMeshAgent>(); if ((Object)(object)component != (Object)null && ((Behaviour)component).enabled) { if (component.isOnNavMesh) { component.isStopped = true; } component.velocity = Vector3.zero; ((Behaviour)component).enabled = false; _suspended.Add((Behaviour)(object)component); } components = ((Component)this).GetComponentsInChildren<MonoBehaviour>(true); foreach (MonoBehaviour val2 in components) { if (!((Object)(object)val2 == (Object)null) && ((Behaviour)val2).enabled && !(((object)val2).GetType().Name != "RigBuilder")) { ((Behaviour)val2).enabled = false; _suspended.Add((Behaviour)(object)val2); } } } private void Resume() { foreach (Behaviour item in _suspended) { if ((Object)(object)item != (Object)null) { item.enabled = true; } } _suspended.Clear(); } private void HoldStill() { _held = true; Suspend(); if ((Object)(object)_animator != (Object)null) { _heldSpeed = ((_animator.speed <= 0f) ? 1f : _animator.speed); _animator.speed = 0f; } Plugin.Log.LogInfo((object)("Hold still ON - '" + ((Object)this).name + "' frozen on its current pose.")); } private void Release() { if (_held) { _held = false; if ((Object)(object)_animator != (Object)null) { _animator.speed = _heldSpeed; } Resume(); Plugin.Log.LogInfo((object)("Hold still OFF - '" + ((Object)this).name + "' released.")); } } private void Sample() { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0056: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_0082: Unknown result type (might be due to invalid IL or missing references) //IL_00a0: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_00ce: Unknown result type (might be due to invalid IL or missing references) //IL_00d7: Unknown result type (might be due to invalid IL or missing references) if (_recBones.Length == 0) { return; } _recAccum += Time.deltaTime; if (!(_recAccum < 0.05f)) { _recAccum = 0f; float[] array = new float[_recBones.Length * 4]; for (int i = 0; i < _recBones.Length; i++) { Quaternion localRotation = _recBones[i].localRotation; array[i * 4] = localRotation.x; array[i * 4 + 1] = localRotation.y; array[i * 4 + 2] = localRotation.z; array[i * 4 + 3] = localRotation.w; } Vector3 localPosition = _recBones[0].localPosition; _recFrames.Add(new PoseFrame { r = array, p = new float[3] { localPosition.x, localPosition.y, localPosition.z } }); } } private void FlushClip() { if (!Plugin.RecordPoses.Value || (Object)(object)_primary != (Object)(object)this) { return; } if (_index < 0 || _index >= _clips.Length || _recFrames.Count == 0) { _recFrames.Clear(); return; } string name = ((Object)_clips[_index]).name; if (_recClips.Any((PoseClip c) => c.name == name)) { _recFrames.Clear(); return; } _recClips.Add(new PoseClip { name = name, fps = 20f, frames = _recFrames.ToArray() }); _recFrames.Clear(); if (_recClips.Count >= _clips.Length) { WriteRecording(); } } private void WriteRecording() { try { PoseRecording poseRecording = new PoseRecording { bones = _recBones.Select((Transform b) => ((Object)b).name).ToArray(), clips = _recClips.ToArray() }; string text = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location), "bracken_anim.json"); File.WriteAllText(text, JsonUtility.ToJson((object)poseRecording)); Plugin.Log.LogInfo((object)($"Recorded {_recClips.Count} clips, " + $"{_recClips.Sum((PoseClip c) => c.frames.Length)} frames -> {text}")); } catch (Exception ex) { Plugin.Log.LogError((object)("Could not write recording: " + ex.Message)); } } private void Show(int i) { //IL_005a: Unknown result type (might be due to invalid IL or missing references) //IL_005f: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0084: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_009b: Unknown result type (might be due to invalid IL or missing references) //IL_00ad: Unknown result type (might be due to invalid IL or missing references) //IL_00b8: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) FlushClip(); if (_clips.Length == 0) { return; } _index = (i % _clips.Length + _clips.Length) % _clips.Length; _timer = 0f; if (_graphLive && ((PlayableGraph)(ref _graph)).IsValid()) { AnimationPlayableOutput val = (AnimationPlayableOutput)((PlayableGraph)(ref _graph)).GetOutput(0); if (PlayableExtensions.IsValid<AnimationClipPlayable>(_playable)) { ((PlayableGraph)(ref _graph)).DestroyPlayable<AnimationClipPlayable>(_playable); } _playable = AnimationClipPlayable.Create(_graph, _clips[_index]); ((AnimationClipPlayable)(ref _playable)).SetApplyFootIK(false); PlayableOutputExtensions.SetSourcePlayable<AnimationPlayableOutput, AnimationClipPlayable>(val, _playable); PlayableExtensions.SetTime<AnimationClipPlayable>(_playable, 0.0); PlayableExtensions.SetSpeed<AnimationClipPlayable>(_playable, 1.0); Plugin.Log.LogInfo((object)($"Test clip {_index + 1}/{_clips.Length}: '{((Object)_clips[_index]).name}' " + $"({_clips[_index].length:F2}s, loop={((Motion)_clips[_index]).isLooping})")); } } private void OnGUI() { //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Expected O, but got Unknown //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Expected O, but got Unknown //IL_006b: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00cc: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0159: Unknown result type (might be due to invalid IL or missing references) //IL_0168: Unknown result type (might be due to invalid IL or missing references) //IL_0177: Unknown result type (might be due to invalid IL or missing references) //IL_0190: Unknown result type (might be due to invalid IL or missing references) if (_running && !((Object)(object)_primary != (Object)(object)this) && _clips.Length != 0) { GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 18 }; val.normal.textColor = Color.white; GUIStyle val2 = val; GUIStyle val3 = new GUIStyle(GUI.skin.box); GUI.Box(new Rect(10f, 10f, 430f, 104f), GUIContent.none, val3); GUI.Label(new Rect(20f, 16f, 420f, 26f), "DRIFTER BRACKEN - TEST MODE" + (_paused ? " [PAUSED]" : ""), val2); GUI.Label(new Rect(20f, 42f, 420f, 26f), $"{_index + 1}/{_clips.Length} {((Object)_clips[_index]).name} ({_clips[_index].length:F2}s)", val2); GUI.Label(new Rect(20f, 68f, 420f, 26f), $"{Plugin.TestToggle.Value} exit {Plugin.TestNext.Value}/{Plugin.TestPrev.Value} step" + $" {Plugin.TestPause.Value} pause", val2); } } } [HarmonyPatch(typeof(FlowermanAI), "OnCollideWithPlayer")] internal static class HeldBrackenCannotGrabPatch { private static bool Prefix() { if (!Plugin.HoldActive) { return !Plugin.TestActive; } return false; } } public class DrifterBrackenSkin : MonoBehaviour { private readonly List<Material> _owned = new List<Material>(); private SkinnedMeshRenderer _lod1; private SkinnedMeshRenderer[] _mine = (SkinnedMeshRenderer[])(object)new SkinnedMeshRenderer[0]; private Renderer[] _hidden = (Renderer[])(object)new Renderer[0]; private bool _ready; private EnemyAI _ai; private float _voiceTimer; private static readonly string[] StripSlots = new string[19] { "_MaskMap", "_NormalMap", "_NormalMapOS", "_BentNormalMap", "_BentNormalMapOS", "_DetailMap", "_HeightMap", "_EmissiveColorMap", "_SpecularColorMap", "_AnisotropyMap", "_CoatMaskMap", "_SubsurfaceMaskMap", "_ThicknessMap", "_TangentMap", "_TangentMapOS", "_IridescenceMaskMap", "_IridescenceThicknessMap", "_TransmissionMaskMap", "_TransmittanceColorMap" }; private static readonly string[] StripKeywords = new string[14] { "_NORMALMAP", "_NORMALMAP_TANGENT_SPACE", "_MASKMAP", "_DETAIL_MAP", "_HEIGHTMAP", "_EMISSIVE_COLOR_MAP", "_EMISSION", "_BENTNORMALMAP", "_MATERIAL_FEATURE_SUBSURFACE_SCATTERING", "_MATERIAL_FEATURE_TRANSMISSION", "_MATERIAL_FEATURE_ANISOTROPY", "_MATERIAL_FEATURE_IRIDESCENCE", "_MATERIAL_FEATURE_CLEAR_COAT", "_MATERIAL_FEATURE_SPECULAR_COLOR" }; private static bool _loggedShader; private static bool _loggedValidate; private static bool _loggedEyes; private void Start() { try { Setup(); } catch (Exception ex) { Plugin.Log.LogError((object)("Setup failed on '" + ((Object)this).name + "': " + ex)); } } private void Setup() { //IL_013e: Unknown result type (might be due to invalid IL or missing references) //IL_0143: Unknown result type (might be due to invalid IL or missing references) //IL_015f: Unknown result type (might be due to invalid IL or missing references) //IL_0165: Unknown result type (might be due to invalid IL or missing references) //IL_016f: Unknown result type (might be due to invalid IL or missing references) //IL_0175: Unknown result type (might be due to invalid IL or missing references) //IL_017f: Unknown result type (might be due to invalid IL or missing references) //IL_0185: Unknown result type (might be due to invalid IL or missing references) //IL_01b7: Unknown result type (might be due to invalid IL or missing references) //IL_01d9: Unknown result type (might be due to invalid IL or missing references) if (Plugin.Meshes.Count == 0) { return; } SkinnedMeshRenderer[] componentsInChildren = ((Component)this).GetComponentsInChildren<SkinnedMeshRenderer>(true); _lod1 = ((IEnumerable<SkinnedMeshRenderer>)componentsInChildren).FirstOrDefault((Func<SkinnedMeshRenderer, bool>)((SkinnedMeshRenderer r) => ((Object)r).name == "LOD1")) ?? componentsInChildren.FirstOrDefault(); if ((Object)(object)_lod1 == (Object)null) { Plugin.Log.LogError((object)"No Bracken renderer found."); return; } Transform[] bones = _lod1.bones; Transform rootBone = _lod1.rootBone; Material template = ((IEnumerable<Material>)((Renderer)_lod1).sharedMaterials).FirstOrDefault((Func<Material, bool>)((Material m) => (Object)(object)m != (Object)null)); List<SkinnedMeshRenderer> list = new List<SkinnedMeshRenderer>(); foreach (KeyValuePair<string, Mesh> mesh in Plugin.Meshes) { Mesh value = mesh.Value; if (value.bindposes.Length != bones.Length) { Plugin.Log.LogError((object)($"'{mesh.Key}' has {value.bindposes.Length} bindposes but the Bracken " + $"has {bones.Length} bones - skipping.")); continue; } GameObject val = new GameObject("Drifter_" + mesh.Key); val.transform.SetParent(((Component)_lod1).transform.parent, false); val.transform.localPosition = Vector3.zero; val.transform.localRotation = Quaternion.identity; val.transform.localScale = Vector3.one; SkinnedMeshRenderer val2 = val.AddComponent<SkinnedMeshRenderer>(); val2.sharedMesh = value; val2.bones = bones; val2.rootBone = rootBone; ((Renderer)val2).localBounds = ((Renderer)_lod1).localBounds; val2.quality = (SkinQuality)4; val2.updateWhenOffscreen = false; ((Renderer)val2).shadowCastingMode = ((Renderer)_lod1).shadowCastingMode; ((Renderer)val2).receiveShadows = ((Renderer)_lod1).receiveShadows; string[] value2; string[] array = (Plugin.MaterialNames.TryGetValue(mesh.Key, out value2) ? value2 : new string[0]); Material[] array2 = (Material[])(object)new Material[value.subMeshCount]; for (int num = 0; num < array2.Length; num++) { array2[num] = BuildMaterial(template, (num < array.Length) ? array[num] : ""); } ((Renderer)val2).sharedMaterials = array2; list.Add(val2); Plugin.Log.LogInfo((object)($"Attached '{mesh.Key}': {value.vertexCount} verts, " + $"{value.subMeshCount} submeshes, {bones.Length} bones.")); } _mine = list.ToArray(); if (_mine.Length == 0) { Plugin.Log.LogError((object)"Nothing attached."); return; } List<Renderer> list2 = new List<Renderer> { (Renderer)(object)_lod1 }; Transform[] componentsInChildren2 = ((Component)this).GetComponentsInChildren<Transform>(true); foreach (Transform val3 in componentsInChildren2) { if (((Object)val3).name == "LeftEye" || ((Object)val3).name == "RightEye") { list2.AddRange(((Component)val3).GetComponents<Renderer>()); } } _hidden = list2.Where((Renderer r) => (Object)(object)r != (Object)null).ToArray(); _ready = true; } private void LateUpdate() { Plugin.PollHotkeys(); _voiceTimer += Time.deltaTime; if (_voiceTimer >= 1f) { _voiceTimer = 0f; if (DrifterVoice.Enabled) { if ((Object)(object)_ai == (Object)null) { _ai = ((Component)this).GetComponent<EnemyAI>(); } DrifterVoice.FillState(_ai); } } if (!_ready) { return; } bool enabled = (Object)(object)_lod1 != (Object)null && ((Renderer)_lod1).enabled; for (int i = 0; i < _mine.Length; i++) { if ((Object)(object)_mine[i] != (Object)null) { ((Renderer)_mine[i]).enabled = enabled; } } bool value = Plugin.HideOriginal.Value; for (int j = 0; j < _hidden.Length; j++) { if ((Object)(object)_hidden[j] != (Object)null) { _hidden[j].forceRenderingOff = value; } } } private void OnDestroy() { SkinnedMeshRenderer[] mine = _mine; foreach (SkinnedMeshRenderer val in mine) { if ((Object)(object)val != (Object)null) { Object.Destroy((Object)(object)((Component)val).gameObject); } } foreach (Material item in _owned) { if ((Object)(object)item != (Object)null) { Object.Destroy((Object)(object)item); } } _owned.Clear(); } private Material BuildMaterial(Material template, string slotName) { //IL_002e: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0034: Expected O, but got Unknown //IL_0530: Unknown result type (might be due to invalid IL or missing references) //IL_0535: Unknown result type (might be due to invalid IL or missing references) //IL_011b: Unknown result type (might be due to invalid IL or missing references) //IL_0212: Unknown result type (might be due to invalid IL or missing references) //IL_033e: Unknown result type (might be due to invalid IL or missing references) //IL_03e9: Unknown result type (might be due to invalid IL or missing references) //IL_03f0: Unknown result type (might be due to invalid IL or missing references) Shader val = (((Object)(object)template != (Object)null) ? template.shader : Shader.Find("HDRP/Lit")); Material val2 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(template)); ((Object)val2).name = "Drifter_" + slotName; _owned.Add(val2); if (!_loggedShader) { _loggedShader = true; Plugin.Log.LogInfo((object)("Materials built on shader '" + (((Object)(object)val != (Object)null) ? ((Object)val).name : "<none>") + "' (template '" + (((Object)(object)template != (Object)null) ? ((Object)template).name : "<none>") + "')")); } string[] stripSlots = StripSlots; foreach (string text in stripSlots) { if (val2.HasProperty(text)) { val2.SetTexture(text, (Texture)null); } } stripSlots = StripKeywords; foreach (string text2 in stripSlots) { val2.DisableKeyword(text2); } SetColor(val2, Color.black, "_EmissiveColor", "_EmissionColor"); if (val2.HasProperty("_NormalMapSpace")) { val2.SetFloat("_NormalMapSpace", 0f); } val2.renderQueue = (((Object)(object)val != (Object)null) ? val.renderQueue : (-1)); string text3 = slotName.ToLowerInvariant(); string text4 = (text3.Contains("teeth") ? "drifter_teeth" : (text3.Contains("eye") ? "drifter_eyes" : (text3.Contains("hair") ? "drifter_hair" : (text3.Contains("lower") ? "drifter_lower_body" : (text3.Contains("head") ? "drifter_head" : "drifter_upper_body"))))); Texture2D val3 = Tex(text4); bool flag = SetTex(val2, val3, "_BaseColorMap", "_MainTex", "_BaseMap"); SetColor(val2, Color.white, "_BaseColor", "_Color"); Plugin.Log.LogInfo((object)(" slot '" + slotName + "' -> " + text4 + (((Object)(object)val3 == (Object)null) ? " [TEXTURE MISSING FROM BUNDLE]" : (flag ? $" ({((Texture)val3).width}x{((Texture)val3).height})" : " [NO BASE COLOUR PROPERTY ON SHADER]")))); if (text4 == "drifter_head") { Texture2D val4 = Tex("drifter_head_normal"); if ((Object)(object)val4 != (Object)null && SetTex(val2, val4, "_NormalMap", "_BumpMap")) { val2.EnableKeyword("_NORMALMAP"); } } if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", Plugin.Smoothness.Value); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", 0f); } if (text4 == "drifter_eyes") { SetColor(val2, Color.black, "_BaseColor", "_Color"); if (val2.HasProperty("_Smoothness")) { val2.SetFloat("_Smoothness", 0f); } if (val2.HasProperty("_Metallic")) { val2.SetFloat("_Metallic", 0f); } float value = Plugin.EyeBrightness.Value; Texture2D val5 = Tex("drifter_eyes"); if (value > 0f && (Object)(object)val5 != (Object)null) { SetTex(val2, val5, "_EmissiveColorMap", "_EmissionMap"); SetColor(val2, Color.white * value, "_EmissiveColor", "_EmissionColor"); if (val2.HasProperty("_UseEmissiveIntensity")) { val2.SetFloat("_UseEmissiveIntensity", 0f); } if (val2.HasProperty("_EmissiveExposureWeight")) { val2.SetFloat("_EmissiveExposureWeight", 0f); } val2.EnableKeyword("_EMISSIVE_COLOR_MAP"); val2.EnableKeyword("_EMISSION"); } } try { HDMaterial.ValidateMaterial(val2); } catch (Exception ex) { if (!_loggedValidate) { _loggedValidate = true; Plugin.Log.LogWarning((object)("HDMaterial.ValidateMaterial unavailable: " + ex.Message)); } } if (text4 == "drifter_eyes" && !_loggedEyes) { _loggedEyes = true; Texture val6 = (val2.HasProperty("_EmissiveColorMap") ? val2.GetTexture("_EmissiveColorMap") : null); Plugin.Log.LogInfo((object)(" eyes: emissive map = " + (((Object)(object)val6 == (Object)null) ? "NONE" : ((Object)val6).name) + ", _EMISSIVE_COLOR_MAP keyword = " + val2.IsKeywordEnabled("_EMISSIVE_COLOR_MAP") + ", emissive colour = " + ((object)val2.GetColor("_EmissiveColor")/*cast due to .constrained prefix*/).ToString())); } return val2; } private static Texture2D Tex(string key) { if (!Plugin.Textures.TryGetValue(key, out var value)) { return null; } return value; } private static bool SetTex(Material m, Texture2D t, params string[] props) { if ((Object)(object)t == (Object)null) { return false; } bool result = false; foreach (string text in props) { if (m.HasProperty(text)) { m.SetTexture(text, (Texture)(object)t); result = true; } } return result; } private static void SetColor(Material m, Color c, params string[] props) { //IL_0015: Unknown result type (might be due to invalid IL or missing references) foreach (string text in props) { if (m.HasProperty(text)) { m.SetColor(text, c); } } } } internal static class DrifterVoice { private static readonly FieldInfo FAngerVoice = AccessTools.Field(typeof(FlowermanAI), "creatureAngerVoice"); private static readonly FieldInfo FCrackNeck = AccessTools.Field(typeof(FlowermanAI), "crackNeckSFX"); private static readonly FieldInfo FStunSFX = AccessTools.Field(typeof(EnemyType), "stunSFX"); private static readonly FieldInfo FClips = AccessTools.Field(typeof(EnemyType), "audioClips"); private static readonly FieldInfo FAngerMode = AccessTools.Field(typeof(FlowermanAI), "isInAngerMode"); private static bool _stunDone; private static bool _loggedClips; internal static bool Enabled { get { if (Plugin.ReplaceVoice != null && Plugin.ReplaceVoice.Value) { return Plugin.Voice.Count > 0; } return false; } } internal static AudioClip Pick(string category) { if (!Plugin.Voice.TryGetValue(category, out var value) || value.Count == 0) { return null; } return value[Random.Range(0, value.Count)]; } internal static void FillState(EnemyAI ai) { if ((Object)(object)ai == (Object)null || (Object)(object)ai.enemyType == (Object)null || FClips == null || !(FClips.GetValue(ai.enemyType) is AudioClip[] array)) { return; } bool flag = FAngerMode != null && ai is FlowermanAI && (bool)FAngerMode.GetValue(ai); string category = (flag ? "enraged" : "spotted"); for (int i = 0; i < array.Length; i++) { AudioClip val = Pick(category) ?? Pick("spotted") ?? Pick("enraged"); if ((Object)(object)val != (Object)null) { array[i] = val; } } if (!_loggedClips) { _loggedClips = true; Plugin.Log.LogInfo((object)("Voice: enemyType.audioClips has " + array.Length + " slot(s), all filled from state (angry=" + flag + ")")); } if (!_stunDone && FStunSFX != null) { AudioClip val2 = Pick("stunned"); if ((Object)(object)val2 != (Object)null) { FStunSFX.SetValue(ai.enemyType, val2); _stunDone = true; } } } internal static void SetAngerVoice(FlowermanAI f) { if (!((Object)(object)f == (Object)null) && !(FAngerVoice == null)) { object? value = FAngerVoice.GetValue(f); AudioSource val = (AudioSource)((value is AudioSource) ? value : null); AudioClip val2 = Pick("enraged"); if ((Object)(object)val != (Object)null && (Object)(object)val2 != (Object)null) { val.clip = val2; } } } internal static void SetKillVoice(FlowermanAI f) { if (!((Object)(object)f == (Object)null) && !(FCrackNeck == null)) { AudioClip val = Pick("kill"); if ((Object)(object)val != (Object)null) { FCrackNeck.SetValue(f, val); } } } } [HarmonyPatch(typeof(EnemyAI), "PlayAudioOfCurrentState")] internal static class VoiceStatePatch { private static void Prefix(EnemyAI __instance) { if (DrifterVoice.Enabled && __instance is FlowermanAI) { DrifterVoice.FillState(__instance); } } } [HarmonyPatch(typeof(FlowermanAI), "EnterAngerModeClientRpc")] internal static class VoiceAngerPatch { private static void Prefix(FlowermanAI __instance) { if (DrifterVoice.Enabled) { DrifterVoice.FillState((EnemyAI)(object)__instance); DrifterVoice.SetAngerVoice(__instance); } } } [HarmonyPatch(typeof(FlowermanAI), "KillPlayerAnimationClientRpc")] internal static class VoiceKillPatch { private static void Prefix(FlowermanAI __instance) { if (DrifterVoice.Enabled) { DrifterVoice.SetKillVoice(__instance); } } } [HarmonyPatch(typeof(EnemyAI), "SetEnemyStunned")] internal static class VoiceStunPatch { private static void Prefix(EnemyAI __instance) { if (DrifterVoice.Enabled && __instance is FlowermanAI) { DrifterVoice.FillState(__instance); } } } [BepInPlugin("drifterbracken", "Drifter Bracken", "1.18.0")] public class Plugin : BaseUnityPlugin { public const string Guid = "drifterbracken"; internal static ManualLogSource Log; internal static readonly Dictionary<string, Mesh> Meshes = new Dictionary<string, Mesh>(); internal static readonly Dictionary<string, string[]> MaterialNames = new Dictionary<string, string[]>(); internal static readonly Dictionary<string, Texture2D> Textures = new Dictionary<string, Texture2D>(); internal static readonly Dictionary<string, List<AudioClip>> Voice = new Dictionary<string, List<AudioClip>>(); internal static ConfigEntry<float> EyeBrightness; internal static ConfigEntry<float> Smoothness; internal static ConfigEntry<bool> HideOriginal; internal static ConfigEntry<bool> ReplaceVoice; internal static ConfigEntry<bool> TestAutoStart; internal static ConfigEntry<bool> RecordPoses; internal static ConfigEntry<float> TestHold; internal static ConfigEntry<KeyboardShortcut> TestToggle; internal static ConfigEntry<KeyboardShortcut> TestNext; internal static ConfigEntry<KeyboardShortcut> TestPrev; internal static ConfigEntry<KeyboardShortcut> TestPause; internal static ConfigEntry<KeyboardShortcut> HoldKey; internal static bool TestActive; internal static bool HoldActive; private static int _step; private static int _stepFrame = -1; private static int _pauseFrame = -1; private static readonly Dictionary<KeyCode, Key> KeyFixups = new Dictionary<KeyCode, Key> { { (KeyCode)13, (Key)2 }, { (KeyCode)271, (Key)77 }, { (KeyCode)306, (Key)55 }, { (KeyCode)305, (Key)56 }, { (KeyCode)96, (Key)4 }, { (KeyCode)316, (Key)74 } }; private static readonly Dictionary<string, bool> _held = new Dictionary<string, bool>(); private static bool _kbLogged; private static float _kbNag; private static int _polledFrame = -1; private static int _tick; internal static bool ConsumeStep(out int step) { step = _step; if (_stepFrame == Time.frameCount) { return _step != 0; } return false; } internal static bool ConsumePause() { return _pauseFrame == Time.frameCount; } private unsafe static Key ToKey(KeyCode c) { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Unknown result type (might be due to invalid IL or missing references) if (KeyFixups.TryGetValue(c, out var value)) { return value; } string text = ((object)(*(KeyCode*)(&c))/*cast due to .constrained prefix*/).ToString(); if (text.StartsWith("Alpha")) { text = "Digit" + text.Substring(5); } else if (text.StartsWith("Keypad")) { text = "Numpad" + text.Substring(6); } if (!Enum.TryParse<Key>(text, out value)) { return (Key)0; } return value; } private static Keyboard Kb() { return Keyboard.current ?? InputSystem.GetDevice<Keyboard>(); } internal static bool Pressed(ConfigEntry<KeyboardShortcut> e) { //IL_000c: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Unknown result type (might be due to invalid IL or missing references) //IL_0015: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_001f: Unknown result type (might be due to invalid IL or missing references) //IL_0020: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0036: Unknown result type (might be due to invalid IL or missing references) //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Unknown result type (might be due to invalid IL or missing references) //IL_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_005b: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) Keyboard val = Kb(); if (val == null) { return false; } KeyboardShortcut value = e.Value; Key val2 = ToKey(((KeyboardShortcut)(ref value)).MainKey); if ((int)val2 == 0) { return false; } bool flag = ((ButtonControl)val[val2]).isPressed; if (flag) { value = e.Value; foreach (KeyCode modifier in ((KeyboardShortcut)(ref value)).Modifiers) { Key val3 = ToKey(modifier); if ((int)val3 != 0 && !((ButtonControl)val[val3]).isPressed) { flag = false; break; } } } string key = ((ConfigEntryBase)e).Definition.Section + "/" + ((ConfigEntryBase)e).Definition.Key; _held.TryGetValue(key, out var value2); _held[key] = flag; if (flag) { return !value2; } return false; } private static void KeyboardDiagnostics() { //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) Keyboard val = Kb(); if (val != null) { if (!_kbLogged) { _kbLogged = true; Log.LogInfo((object)("Keyboard found: '" + ((InputControl)val).name + "', Input System updateMode=" + ((object)InputSystem.settings.updateMode/*cast due to .constrained prefix*/).ToString() + ". Hotkeys are live.")); } return; } _kbNag += Time.unscaledDeltaTime; if (!(_kbNag < 15f)) { _kbNag = 0f; Log.LogWarning((object)("Input System has no keyboard device yet, so hotkeys cannot fire. Devices: " + string.Join(", ", ((IEnumerable<InputDevice>)(object)InputSystem.devices).Select((InputDevice d) => ((InputControl)d).name).ToArray()))); } } private void Awake() { //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_0043: Expected O, but got Unknown //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_0080: Expected O, but got Unknown //IL_0133: Unknown result type (might be due to invalid IL or missing references) //IL_013d: Expected O, but got Unknown //IL_015c: Unknown result type (might be due to invalid IL or missing references) //IL_018a: Unknown result type (might be due to invalid IL or missing references) //IL_01b8: Unknown result type (might be due to invalid IL or missing references) //IL_01e6: Unknown result type (might be due to invalid IL or missing references) //IL_0214: Unknown result type (might be due to invalid IL or missing references) //IL_0245: Unknown result type (might be due to invalid IL or missing references) //IL_026e: Unknown result type (might be due to invalid IL or missing references) //IL_0273: Unknown result type (might be due to invalid IL or missing references) //IL_0291: Unknown result type (might be due to invalid IL or missing references) //IL_0296: Unknown result type (might be due to invalid IL or missing references) Log = ((BaseUnityPlugin)this).Logger; Smoothness = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "Smoothness", 0.35f, new ConfigDescription("Surface smoothness. The Drifter's roughness maps aren't shipped, so this is a flat value.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 1f), Array.Empty<object>())); EyeBrightness = ((BaseUnityPlugin)this).Config.Bind<float>("Look", "EyeBrightness", 2f, new ConfigDescription("How bright the eyes render. They are unlit, so this is their brightness in any light. 1 is the texture as authored, higher blooms, 0 goes black.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 8f), Array.Empty<object>())); ReplaceVoice = ((BaseUnityPlugin)this).Config.Bind<bool>("Look", "ReplaceVoice", true, "Give the Bracken the Drifter's voice - stalking, anger, the neck snap and being stunned. Turn off to keep the vanilla sounds."); HideOriginal = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "HideOriginalBracken", true, "Hide the vanilla Bracken mesh. Turn off to see both models overlaid while tuning."); TestAutoStart = ((BaseUnityPlugin)this).Config.Bind<bool>("TestMode", "AutoStart", false, "Start every Bracken frozen and cycling its animations, without pressing the toggle key."); RecordPoses = ((BaseUnityPlugin)this).Config.Bind<bool>("TestMode", "RecordPoses", true, "While cycling, sample the Bracken's skeleton and write bracken_anim.json next to the plugin. The standalone retarget test scene replays that file, so the animations can be inspected without launching the game."); TestHold = ((BaseUnityPlugin)this).Config.Bind<float>("TestMode", "HoldSeconds", 1f, new ConfigDescription("Extra pause after each clip finishes before the next one starts.", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 10f), Array.Empty<object>())); HoldKey = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("TestMode", "HoldStillKey", new KeyboardShortcut((KeyCode)288, Array.Empty<KeyCode>()), "Freeze every Bracken where it stands, on its pose, without cycling animations. Its AI is off while held, so it will not chase or kill - walk up and look at it."); TestToggle = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("TestMode", "ToggleKey", new KeyboardShortcut((KeyCode)289, Array.Empty<KeyCode>()), "Freeze every Bracken in place and cycle through all of its animations."); TestNext = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("TestMode", "NextKey", new KeyboardShortcut((KeyCode)290, Array.Empty<KeyCode>()), "Step to the next animation."); TestPrev = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("TestMode", "PrevKey", new KeyboardShortcut((KeyCode)291, Array.Empty<KeyCode>()), "Step to the previous animation."); TestPause = ((BaseUnityPlugin)this).Config.Bind<KeyboardShortcut>("TestMode", "PauseKey", new KeyboardShortcut((KeyCode)292, Array.Empty<KeyCode>()), "Hold the current animation instead of advancing."); if (LoadBundle()) { TestActive = TestAutoStart.Value; new Harmony("drifterbracken").PatchAll(Assembly.GetExecutingAssembly()); Log.LogInfo((object)("Drifter Bracken ready. Hold still: " + ((object)HoldKey.Value/*cast due to .constrained prefix*/).ToString() + ", test mode: " + ((object)TestToggle.Value/*cast due to .constrained prefix*/).ToString() + ". Waiting for the Input System to report a keyboard.")); } } private void Update() { PollHotkeys(); } internal static void PollHotkeys() { //IL_0076: Unknown result type (might be due to invalid IL or missing references) //IL_007b: Unknown result type (might be due to invalid IL or missing references) if (_polledFrame == Time.frameCount) { return; } _polledFrame = Time.frameCount; if (_tick < 3) { _tick++; Keyboard val = Kb(); Log.LogInfo((object)("Hotkey poll " + _tick + ": keyboard=" + ((val == null) ? "null" : ((InputControl)val).name) + ", devices=" + InputSystem.devices.Count)); } KeyboardDiagnostics(); if (Pressed(HoldKey)) { HoldActive = !HoldActive; Log.LogInfo((object)("Hold still " + (HoldActive ? "ON" : "OFF"))); } if (Pressed(TestToggle)) { TestActive = !TestActive; Log.LogInfo((object)("Test mode " + (TestActive ? "ON" : "OFF"))); } if (TestActive) { _step = 0; if (Pressed(TestNext)) { _step = 1; _stepFrame = Time.frameCount; } else if (Pressed(TestPrev)) { _step = -1; _stepFrame = Time.frameCount; } if (Pressed(TestPause)) { _pauseFrame = Time.frameCount; } } } private bool LoadBundle() { string text = Path.Combine(Path.GetDirectoryName(((BaseUnityPlugin)this).Info.Location), "drifterbracken"); if (!File.Exists(text)) { Log.LogError((object)("Asset bundle missing - expected it next to the plugin at '" + text + "'.")); return false; } AssetBundle val = AssetBundle.LoadFromFile(text); if ((Object)(object)val == (Object)null) { Log.LogError((object)"Asset bundle failed to load (built for the wrong Unity version?)."); return false; } Mesh[] array = val.LoadAllAssets<Mesh>(); foreach (Mesh val2 in array) { if (((Object)val2).name.EndsWith("_rebound")) { Meshes[((Object)val2).name.Substring(0, ((Object)val2).name.Length - "_rebound".Length)] = val2; } } GameObject[] array2 = val.LoadAllAssets<GameObject>(); for (int i = 0; i < array2.Length; i++) { SkinnedMeshRenderer[] componentsInChildren = array2[i].GetComponentsInChildren<SkinnedMeshRenderer>(true); foreach (SkinnedMeshRenderer val3 in componentsInChildren) { MaterialNames[((Object)val3).name] = ((Renderer)val3).sharedMaterials.Select((Material x) => (!((Object)(object)x != (Object)null)) ? "" : ((Object)x).name).ToArray(); } } Texture2D[] array3 = val.LoadAllAssets<Texture2D>(); foreach (Texture2D val4 in array3) { Textures[((Object)val4).name] = val4; } AudioClip[] array4 = val.LoadAllAssets<AudioClip>(); foreach (AudioClip val5 in array4) { string key = ((Object)val5).name.Split('_')[0]; if (!Voice.TryGetValue(key, out var value)) { value = (Voice[key] = new List<AudioClip>()); } value.Add(val5); } if (Voice.Count > 0) { Log.LogInfo((object)("Voice lines: " + string.Join(", ", (from kv in Voice orderby kv.Key select kv.Key + " x" + kv.Value.Count).ToArray()))); } if (Meshes.Count == 0) { Log.LogError((object)"No pre-bound meshes in the bundle."); return false; } Log.LogInfo((object)($"Loaded {Meshes.Count} pre-bound meshes and {Textures.Count} textures: " + string.Join(", ", Meshes.Keys.ToArray()))); return true; } } [HarmonyPatch] internal static class FlowermanStartPatch { private static MethodBase TargetMethod() { return AccessTools.DeclaredMethod(typeof(FlowermanAI), "Start", (Type[])null, (Type[])null) ?? AccessTools.Method(typeof(EnemyAI), "Start", (Type[])null, (Type[])null); } private static void Postfix(EnemyAI __instance) { if (__instance is FlowermanAI && !((Object)(object)((Component)__instance).GetComponent<DrifterBrackenSkin>() != (Object)null)) { ((Component)__instance).gameObject.AddComponent<DrifterBrackenSkin>(); ((Component)__instance).gameObject.AddComponent<BrackenAnimTester>(); } } } [Serializable] public class PoseFrame { public float[] r; public float[] p; } [Serializable] public class PoseClip { public string name; public float fps; public PoseFrame[] frames; } [Serializable] public class PoseRecording { public string[] bones; public PoseClip[] clips; } }