using System; using System.Collections.Generic; using System.Collections.ObjectModel; using System.Diagnostics; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Bootstrap; using BepInEx.Configuration; using BepInEx.Logging; using Microsoft.CodeAnalysis; using RiskOfOptions; using RiskOfOptions.Options; using RoR2; using UnityEngine; using UnityEngine.Rendering; [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("AllyOutline")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Outlines teammates through walls")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0")] [assembly: AssemblyProduct("AllyOutline")] [assembly: AssemblyTitle("AllyOutline")] [assembly: AssemblyVersion("1.0.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 AllyOutline { internal static class AllyOutliner { private static Object _requester; private static bool _hooked; private static bool _requesting; private static readonly List Targets = new List(); private static readonly ReadOnlyCollection EmptyTeam = new ReadOnlyCollection(Array.Empty()); internal static void Init(Object requester) { _requester = requester; try { OutlineHighlight.onPreRenderOutlineHighlight = (Action)Delegate.Combine(OutlineHighlight.onPreRenderOutlineHighlight, new Action(OnPreRenderOutlineHighlight)); _hooked = true; } catch (Exception ex) { Plugin.Log.LogError((object)("OutlineHighlight のフックに失敗しました。縁取りは無効になります: " + ex)); } } internal static void Shutdown() { if (_hooked) { OutlineHighlight.onPreRenderOutlineHighlight = (Action)Delegate.Remove(OutlineHighlight.onPreRenderOutlineHighlight, new Action(OnPreRenderOutlineHighlight)); _hooked = false; } ReleaseRequest(); _requester = null; } internal static void Tick() { if (!_hooked) { return; } bool flag = ModConfig.Enabled.Value && HasAnyTarget(); if (flag != _requesting) { if (flag) { _requesting = true; OutlineHighlight.AddPreRenderHighlightRequest(_requester); } else { ReleaseRequest(); } } } private static void ReleaseRequest() { if (_requesting) { _requesting = false; OutlineHighlight.ReleasePreRenderHighlightRequest(_requester); } } private static void OnPreRenderOutlineHighlight(OutlineHighlight outlineHighlight) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_003d: Unknown result type (might be due to invalid IL or missing references) //IL_003f: 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) if (!ModConfig.Enabled.Value || !Object.op_Implicit((Object)(object)outlineHighlight)) { return; } try { SceneCamera sceneCamera = outlineHighlight.sceneCamera; if (!Object.op_Implicit((Object)(object)sceneCamera)) { return; } CameraRigController cameraRigController = sceneCamera.cameraRigController; if (Object.op_Implicit((Object)(object)cameraRigController)) { Color outlineColor = GetOutlineColor(); SilhouetteFill.BeginFrame(outlineHighlight, outlineColor); CollectTargets(cameraRigController); for (int i = 0; i < Targets.Count; i++) { AddOutline(outlineHighlight, Targets[i], outlineColor); } Targets.Clear(); } } catch (Exception ex) { Plugin.Log.LogError((object)("縁取りの追加に失敗しました: " + ex)); } } private static bool HasAnyTarget() { ReadOnlyCollection readOnlyInstancesList = CameraRigController.readOnlyInstancesList; for (int i = 0; i < readOnlyInstancesList.Count; i++) { CameraRigController val = readOnlyInstancesList[i]; if (Object.op_Implicit((Object)(object)val) && ((Behaviour)val).enabled) { CollectTargets(val); int count = Targets.Count; Targets.Clear(); if (count > 0) { return true; } } } return false; } internal static void CollectTargets(CameraRigController rig) { Targets.Clear(); CharacterBody targetBody = rig.targetBody; ReadOnlyCollection allies = GetAllies(rig); for (int i = 0; i < allies.Count; i++) { CharacterBody outlineTarget = GetOutlineTarget(allies[i], targetBody); if (Object.op_Implicit((Object)(object)outlineTarget)) { Targets.Add(outlineTarget); } } } private static ReadOnlyCollection GetAllies(CameraRigController rig) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Invalid comparison between Unknown and I4 //IL_000b: Unknown result type (might be due to invalid IL or missing references) TeamIndex targetTeamIndex = rig.targetTeamIndex; if ((int)targetTeamIndex != -1) { return TeamComponent.GetTeamMembers(targetTeamIndex); } return EmptyTeam; } private static CharacterBody GetOutlineTarget(TeamComponent teamComponent, CharacterBody viewer) { if (!Object.op_Implicit((Object)(object)teamComponent)) { return null; } CharacterBody body = teamComponent.body; if (!Object.op_Implicit((Object)(object)body)) { return null; } if (!ModConfig.ShowSelf.Value && (Object)(object)body == (Object)(object)viewer) { return null; } if (ModConfig.ShowMinions.Value) { return body; } if (!IsPlayer(body)) { return null; } return body; } private static bool IsPlayer(CharacterBody body) { CharacterMaster master = body.master; if (Object.op_Implicit((Object)(object)master)) { return Object.op_Implicit((Object)(object)master.playerCharacterMasterController); } return false; } private static void AddOutline(OutlineHighlight outlineHighlight, CharacterBody body, Color color) { //IL_0010: 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) CharacterModel model = GetModel(body); if (!Object.op_Implicit((Object)(object)model) || (int)model.visibility == 0) { return; } RendererInfo[] baseRendererInfos = model.baseRendererInfos; if (baseRendererInfos == null) { return; } for (int i = 0; i < baseRendererInfos.Length; i++) { Renderer renderer = baseRendererInfos[i].renderer; if (Object.op_Implicit((Object)(object)renderer) && renderer.enabled && ((Component)renderer).gameObject.activeInHierarchy && !SilhouetteFill.TryDraw(renderer)) { outlineHighlight.AddHighlight(renderer, color); } } } internal static CharacterModel GetModel(CharacterBody body) { ModelLocator modelLocator = body.modelLocator; if (!Object.op_Implicit((Object)(object)modelLocator)) { return null; } Transform modelTransform = modelLocator.modelTransform; if (!Object.op_Implicit((Object)(object)modelTransform)) { return null; } return ((Component)modelTransform).GetComponent(); } private static Color GetOutlineColor() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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) return Color32.op_Implicit(Color32.op_Implicit(ModConfig.OutlineColor.Value)); } } internal static class ModConfig { public static ConfigEntry Enabled; public static ConfigEntry ShowSelf; public static ConfigEntry ShowMinions; public static ConfigEntry OutlineColor; public static void Init(ConfigFile config) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) EnsureColorConverter(); Enabled = config.Bind("General", "Enabled", true, "味方プレイヤーを縁取る。off にするとバニラの見た目に戻る。"); ShowSelf = config.Bind("General", "Show Self", false, "自分自身も縁取る。自分は常に画面の中心に居るので既定では縁取らない。"); ShowMinions = config.Bind("General", "Show Minions", true, "味方が連れているドローン・タレット・召喚も縁取る。off にすると操作プレイヤーだけになる。"); OutlineColor = config.Bind("General", "Outline Color", new Color(0.2f, 0.8f, 1f, 1f), "縁取りの色。アルファは縁取りの濃さになる。RoR2 は色ごとにマテリアルを作って保持し続けるので、毎フレーム変わるような使い方はしない。"); if (!Chainloader.PluginInfos.ContainsKey("com.rune580.riskofoptions")) { Plugin.Log.LogInfo((object)"Risk of Options が見つからないので設定画面は登録しません。"); return; } try { RegisterRiskOfOptions(); Plugin.Log.LogInfo((object)"Risk of Options へ設定を登録しました。"); } catch (Exception ex) { Plugin.Log.LogWarning((object)("Risk of Options への設定登録に失敗しました: " + ex)); } } [MethodImpl(MethodImplOptions.NoInlining)] private static void RegisterRiskOfOptions() { //IL_000f: Unknown result type (might be due to invalid IL or missing references) //IL_0019: Expected O, but got Unknown //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0028: Expected O, but got Unknown //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0037: Expected O, but got Unknown //IL_003c: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown ModSettingsManager.SetModDescription("味方の輪郭を壁越しに表示します。誰がどこにいるか常に分かります。連れているタレットやドローンも含みます。自分自身は既定では縁取りません。"); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(Enabled)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ShowMinions)); ModSettingsManager.AddOption((BaseOption)new CheckBoxOption(ShowSelf)); ModSettingsManager.AddOption((BaseOption)new ColorOption(OutlineColor)); } private static void EnsureColorConverter() { //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Unknown result type (might be due to invalid IL or missing references) //IL_0070: Expected O, but got Unknown if (TomlTypeConverter.CanConvert(typeof(Color))) { return; } TomlTypeConverter.AddConverter(typeof(Color), new TypeConverter { ConvertToString = (object obj, Type type) => "#" + ColorUtility.ToHtmlStringRGBA((Color)obj), ConvertToObject = delegate(string str, Type type) { //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_000a: 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) Color white = default(Color); if (!ColorUtility.TryParseHtmlString(str, ref white)) { white = Color.white; } return white; } }); } } [BepInPlugin("OchaDashiMan.AllyOutline", "AllyOutline", "1.0.0")] [BepInDependency(/*Could not decode attribute arguments.*/)] public class Plugin : BaseUnityPlugin { public const string Guid = "OchaDashiMan.AllyOutline"; public const string ModName = "AllyOutline"; public const string Version = "1.0.0"; internal const string RiskOfOptionsGuid = "com.rune580.riskofoptions"; internal static ManualLogSource Log; private void Awake() { Log = ((BaseUnityPlugin)this).Logger; ModConfig.Init(((BaseUnityPlugin)this).Config); AllyOutliner.Init((Object)(object)this); Log.LogInfo((object)"AllyOutline 1.0.0 loaded."); } private void Update() { AllyOutliner.Tick(); } private void OnDestroy() { AllyOutliner.Shutdown(); } } internal static class SilhouetteFill { internal const string DefaultShaderName = "Hopoo Games/FX/Cloud Remap"; private const string ZTestName = "_ZTest"; private static readonly int ColorId = Shader.PropertyToID("_Color"); private static readonly int TintColorId = Shader.PropertyToID("_TintColor"); private static readonly int ZTestId = Shader.PropertyToID("_ZTest"); private static readonly int ZWriteId = Shader.PropertyToID("_ZWrite"); private static readonly int CullId = Shader.PropertyToID("_Cull"); private static readonly int SrcBlendId = Shader.PropertyToID("_SrcBlend"); private static readonly int DstBlendId = Shader.PropertyToID("_DstBlend"); private static readonly int MainTexId = Shader.PropertyToID("_MainTex"); private static FieldInfo _commandBufferField; private static bool _commandBufferFieldMissing; private static Material _material; private static string _materialShaderName; private static bool _shaderMissingLogged; private static CommandBuffer _buffer; private static bool _active; internal static void BeginFrame(OutlineHighlight outlineHighlight, Color color) { //IL_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0051: Unknown result type (might be due to invalid IL or missing references) _active = false; Material material = GetMaterial(ResolveShaderName()); if (!Object.op_Implicit((Object)(object)material)) { return; } CommandBuffer commandBuffer = GetCommandBuffer(outlineHighlight); if (commandBuffer != null) { if (material.HasProperty(ColorId)) { material.SetColor(ColorId, color); } if (material.HasProperty(TintColorId)) { material.SetColor(TintColorId, color); } _buffer = commandBuffer; _material = material; _active = true; } } internal static bool TryDraw(Renderer renderer) { if (!_active) { return false; } _buffer.DrawRenderer(renderer, _material, 0, 0); return true; } private static string ResolveShaderName() { return "Hopoo Games/FX/Cloud Remap"; } private static Material GetMaterial(string shaderName) { //IL_0058: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Expected O, but got Unknown if (Object.op_Implicit((Object)(object)_material) && _materialShaderName == shaderName) { return _material; } Shader val = FindLoadedShader(shaderName); if (!Object.op_Implicit((Object)(object)val)) { if (!_shaderMissingLogged) { _shaderMissingLogged = true; Plugin.Log.LogWarning((object)("塗りつぶし用のシェーダー \"" + shaderName + "\" が見つかりません。バニラの塗りつぶしへ落とします(縁取りは出ますが壁越しにはなりません)。")); } return null; } Material val2 = new Material(val) { hideFlags = (HideFlags)61 }; if (val2.HasProperty(ZTestId)) { val2.SetInt(ZTestId, 8); } if (val2.HasProperty(ZWriteId)) { val2.SetInt(ZWriteId, 0); } if (val2.HasProperty(CullId)) { val2.SetInt(CullId, 0); } if (val2.HasProperty(SrcBlendId)) { val2.SetInt(SrcBlendId, 1); } if (val2.HasProperty(DstBlendId)) { val2.SetInt(DstBlendId, 0); } if (val2.HasProperty(MainTexId)) { val2.SetTexture(MainTexId, (Texture)(object)Texture2D.whiteTexture); } SuppressFading(val2); _material = val2; _materialShaderName = shaderName; return val2; } private static void SuppressFading(Material material) { material.DisableKeyword("SOFTPARTICLES_ON"); SetIfPresent(material, "_FadeCloseOn", 0f); SetIfPresent(material, "_FadeCloseDistance", 0f); SetIfPresent(material, "_VertexColorOn", 0f); SetIfPresent(material, "_VertexAlphaOn", 0f); SetIfPresent(material, "_VertColor", 0f); SetIfPresent(material, "_Fade", 1f); SetIfPresent(material, "_ExternalAlpha", 1f); SetIfPresent(material, "_AlphaBias", 0f); SetIfPresent(material, "_Cutoff", 0f); SetIfPresent(material, "_WireframeOnly", 0f); } private static void SetIfPresent(Material material, string name, float value) { if (material.HasProperty(name)) { material.SetFloat(name, value); } } internal static Shader FindLoadedShader(string name) { Shader[] array = Resources.FindObjectsOfTypeAll(); for (int i = 0; i < array.Length; i++) { if (Object.op_Implicit((Object)(object)array[i]) && ((Object)array[i]).name == name) { return array[i]; } } return null; } private static CommandBuffer GetCommandBuffer(OutlineHighlight outlineHighlight) { if (_commandBufferFieldMissing) { return null; } if (_commandBufferField == null) { _commandBufferField = typeof(OutlineHighlight).GetField("commandBuffer", BindingFlags.Instance | BindingFlags.NonPublic); if (_commandBufferField == null) { _commandBufferFieldMissing = true; Plugin.Log.LogWarning((object)"OutlineHighlight.commandBuffer が見つかりません。バニラの塗りつぶしへ落とします(縁取りは出ますが壁越しにはなりません)。"); return null; } } object? value = _commandBufferField.GetValue(outlineHighlight); return (CommandBuffer)((value is CommandBuffer) ? value : null); } } }