using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
using System.Security;
using System.Security.Permissions;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Microsoft.CodeAnalysis;
using Photon.Pun;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETFramework,Version=v4.8.1", FrameworkDisplayName = ".NET Framework 4.8.1")]
[assembly: SecurityPermission(SecurityAction.RequestMinimum, SkipVerification = true)]
[assembly: AssemblyVersion("0.0.0.0")]
[module: UnverifiableCode]
[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 ScoutCannonHelper
{
internal sealed class AimScope : MonoBehaviour
{
private GameObject _camObj;
private Camera _cam;
private RenderTexture _rt;
private int _rtWidth;
private int _rtHeight;
private bool _visible;
private static Type _urpCameraDataType;
private static bool _urpTypeResolved;
private void Update()
{
try
{
Tick();
}
catch (Exception arg)
{
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogError((object)$"[童子军大炮] 瞄准小窗异常:{arg}");
}
}
}
private void Tick()
{
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
if (ModConfig.ScopeEnabled == null || !ModConfig.ScopeEnabled.Value || !CannonViewState.Aiming)
{
SetVisible(visible: false);
return;
}
if (!CannonUtil.TryGetHeldMuzzle(out var muzzle, out var direction))
{
SetVisible(visible: false);
return;
}
EnsureCamera();
UpdateCamera(muzzle, direction);
SetVisible(visible: true);
}
private void EnsureCamera()
{
//IL_0017: Unknown result type (might be due to invalid IL or missing references)
//IL_0021: Expected O, but got Unknown
//IL_017e: Unknown result type (might be due to invalid IL or missing references)
//IL_0188: Expected O, but got Unknown
if ((Object)(object)_camObj == (Object)null)
{
_camObj = new GameObject("ScoutCannonHelper_AimScopeCamera");
_camObj.transform.SetParent(((Component)this).transform, false);
((Object)_camObj).hideFlags = (HideFlags)61;
_cam = _camObj.AddComponent<Camera>();
((Behaviour)_cam).enabled = false;
_cam.depth = -50f;
_cam.clearFlags = (CameraClearFlags)1;
_cam.nearClipPlane = 0.03f;
_cam.farClipPlane = 1500f;
_cam.allowHDR = false;
_cam.allowMSAA = false;
_cam.stereoTargetEye = (StereoTargetEyeMask)0;
int num = LayerMask.NameToLayer("UI");
_cam.cullingMask = ((num >= 0) ? (~(1 << num)) : (-1));
EnsureUrpCameraData();
}
int num2 = Mathf.Clamp(Mathf.RoundToInt(ModConfig.ScopeWidth.Value), 96, 1280);
int num3 = Mathf.Clamp(Mathf.RoundToInt((float)num2 * 9f / 16f), 54, 720);
if ((Object)(object)_rt == (Object)null || _rtWidth != num2 || _rtHeight != num3)
{
if ((Object)(object)_rt != (Object)null)
{
_cam.targetTexture = null;
_rt.Release();
Object.Destroy((Object)(object)_rt);
}
_rt = new RenderTexture(num2, num3, 24, (RenderTextureFormat)7);
((Object)_rt).hideFlags = (HideFlags)61;
_rt.Create();
_cam.targetTexture = _rt;
_rtWidth = num2;
_rtHeight = num3;
}
_cam.fieldOfView = Mathf.Clamp(ModConfig.ScopeFov.Value, 20f, 110f);
}
private void EnsureUrpCameraData()
{
Type urpCameraDataType = GetUrpCameraDataType();
if (urpCameraDataType == null)
{
return;
}
try
{
if ((Object)(object)_camObj.GetComponent(urpCameraDataType) == (Object)null)
{
_camObj.AddComponent(urpCameraDataType);
}
}
catch
{
}
}
private static Type GetUrpCameraDataType()
{
if (_urpTypeResolved)
{
return _urpCameraDataType;
}
_urpTypeResolved = true;
try
{
_urpCameraDataType = Type.GetType("UnityEngine.Rendering.Universal.UniversalAdditionalCameraData, Unity.RenderPipelines.Universal.Runtime");
if (_urpCameraDataType == null)
{
Assembly[] assemblies = AppDomain.CurrentDomain.GetAssemblies();
for (int i = 0; i < assemblies.Length; i++)
{
Type type = assemblies[i].GetType("UnityEngine.Rendering.Universal.UniversalAdditionalCameraData", throwOnError: false);
if (type != null)
{
_urpCameraDataType = type;
break;
}
}
}
}
catch
{
_urpCameraDataType = null;
}
return _urpCameraDataType;
}
private void UpdateCamera(Transform muzzle, Vector3 direction)
{
//IL_0018: Unknown result type (might be due to invalid IL or missing references)
//IL_001d: Unknown result type (might be due to invalid IL or missing references)
//IL_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0045: 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)
//IL_004c: Unknown result type (might be due to invalid IL or missing references)
//IL_0061: Unknown result type (might be due to invalid IL or missing references)
//IL_0062: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: 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_0014: Unknown result type (might be due to invalid IL or missing references)
if (((Vector3)(ref direction)).sqrMagnitude < 1E-06f)
{
direction = muzzle.forward;
}
direction = ((Vector3)(ref direction)).normalized;
float num = Mathf.Max(0f, ModConfig.ScopeForwardOffset.Value);
_camObj.transform.position = muzzle.position + direction * num;
_camObj.transform.rotation = Quaternion.LookRotation(direction, Vector3.up);
}
private void SetVisible(bool visible)
{
_visible = visible;
if ((Object)(object)_cam != (Object)null)
{
((Behaviour)_cam).enabled = visible;
}
}
private void OnDestroy()
{
try
{
if ((Object)(object)_cam != (Object)null)
{
_cam.targetTexture = null;
}
if ((Object)(object)_rt != (Object)null)
{
_rt.Release();
Object.Destroy((Object)(object)_rt);
}
}
catch
{
}
}
private void OnGUI()
{
if (!_visible || (Object)(object)_rt == (Object)null)
{
return;
}
try
{
DrawScope();
}
catch
{
}
}
private void DrawScope()
{
//IL_00ae: Unknown result type (might be due to invalid IL or missing references)
//IL_00b3: Unknown result type (might be due to invalid IL or missing references)
//IL_00c9: Unknown result type (might be due to invalid IL or missing references)
//IL_0107: Unknown result type (might be due to invalid IL or missing references)
//IL_0116: Unknown result type (might be due to invalid IL or missing references)
//IL_011d: Unknown result type (might be due to invalid IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01c5: Unknown result type (might be due to invalid IL or missing references)
//IL_01d4: Unknown result type (might be due to invalid IL or missing references)
float num = Mathf.Clamp(ModConfig.ScopeWidth.Value, 96f, Mathf.Max(96f, (float)Screen.width - 16f));
float num2 = num * 9f / 16f;
float num3 = Mathf.Clamp(ModConfig.ScopeMargin.Value, 0f, 200f);
int num4 = Mathf.Clamp(ModConfig.ScopeCorner.Value, 0, 3);
bool num5 = num4 == 2 || num4 == 3;
bool flag = num4 == 1 || num4 == 3;
float num6 = (num5 ? num3 : ((float)Screen.width - num3 - num));
float num7 = (flag ? num3 : ((float)Screen.height - num3 - num2));
Rect val = default(Rect);
((Rect)(ref val))..ctor(num6, num7, num, num2);
Color color = GUI.color;
GUI.color = new Color(0f, 0f, 0f, 0.85f);
GUI.DrawTexture(new Rect(((Rect)(ref val)).x - 2f, ((Rect)(ref val)).y - 2f, ((Rect)(ref val)).width + 4f, ((Rect)(ref val)).height + 4f), (Texture)(object)Texture2D.whiteTexture);
GUI.color = color;
GUI.DrawTexture(val, (Texture)(object)_rt, (ScaleMode)0, false);
if (ModConfig.ScopeCrosshair.Value)
{
float num8 = ((Rect)(ref val)).x + ((Rect)(ref val)).width * 0.5f;
float num9 = ((Rect)(ref val)).y + ((Rect)(ref val)).height * 0.5f;
GUI.color = new Color(1f, 1f, 1f, 0.8f);
GUI.DrawTexture(new Rect(num8 - 9f, num9 - 1f, 18f, 2f), (Texture)(object)Texture2D.whiteTexture);
GUI.DrawTexture(new Rect(num8 - 1f, num9 - 9f, 2f, 18f), (Texture)(object)Texture2D.whiteTexture);
GUI.color = color;
}
}
}
internal static class CannonViewState
{
public static bool Aiming;
}
internal sealed class CannonController : MonoBehaviour
{
private float _enterHold;
private bool _enterConsumed;
private float _igniteHold;
private float _igniteBlockUntil;
private Texture2D _crosshairTex;
private string _colorCachedKey;
private Color _colorCachedValue = new Color(0.22f, 1f, 0.42f, 1f);
private const float IgniteCooldown = 1f;
private const int CrosshairTexSize = 64;
private static MethodInfo _warp2;
private static MethodInfo _warp3;
private static bool _warpResolved;
private static void ResolveWarpMethod()
{
if (_warpResolved)
{
return;
}
_warpResolved = true;
Type typeFromHandle = typeof(Character);
_warp2 = typeFromHandle.GetMethod("WarpPlayerRPC", BindingFlags.Instance | BindingFlags.Public, null, new Type[2]
{
typeof(Vector3),
typeof(bool)
}, null);
_warp3 = typeFromHandle.GetMethod("WarpPlayerRPC", BindingFlags.Instance | BindingFlags.Public, null, new Type[3]
{
typeof(Vector3),
typeof(bool),
typeof(PhotonMessageInfo)
}, null);
if (_warp2 == null && _warp3 == null)
{
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogWarning((object)"[童子军大炮] 未找到 Character.WarpPlayerRPC,进入大炮功能不可用。");
}
}
}
private static void InvokeWarp(Character target, Vector3 position, bool poof)
{
//IL_0020: Unknown result type (might be due to invalid IL or missing references)
//IL_0053: Unknown result type (might be due to invalid IL or missing references)
//IL_0067: Unknown result type (might be due to invalid IL or missing references)
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
ResolveWarpMethod();
try
{
if (_warp2 != null)
{
_warp2.Invoke(target, new object[2] { position, poof });
}
else if (_warp3 != null)
{
_warp3.Invoke(target, new object[3]
{
position,
poof,
(object)default(PhotonMessageInfo)
});
}
}
catch (TargetInvocationException ex)
{
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogError((object)$"[童子军大炮] WarpPlayerRPC 调用异常:{ex.InnerException ?? ex}");
}
}
catch (Exception arg)
{
ManualLogSource loggerRef2 = Plugin.LoggerRef;
if (loggerRef2 != null)
{
loggerRef2.LogError((object)$"[童子军大炮] WarpPlayerRPC 反射异常:{arg}");
}
}
}
private void Update()
{
try
{
Tick();
}
catch (Exception arg)
{
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogError((object)$"[童子军大炮] Update 异常:{arg}");
}
}
}
private void Tick()
{
Character localCharacter = Character.localCharacter;
bool alive = (Object)(object)localCharacter != (Object)null && (Object)(object)localCharacter.data != (Object)null && !localCharacter.data.dead;
TickViewToggle();
TickEnter(localCharacter, alive);
TickIgnite(localCharacter, alive);
}
private void TickViewToggle()
{
//IL_0027: Unknown result type (might be due to invalid IL or missing references)
bool flag = false;
if (ModConfig.ViewEnabled.Value)
{
flag = CannonUtil.TryGetHeldScroll(out var _, out var _);
}
if (!flag)
{
CannonViewState.Aiming = false;
}
else if (KeyPressedThisFrame(ModConfig.ViewKey.Value))
{
CannonViewState.Aiming = !CannonViewState.Aiming;
ModConfig.Log(CannonViewState.Aiming ? "已进入炮口视角。" : "已恢复自由视角。");
}
}
private void TickEnter(Character local, bool alive)
{
//IL_0024: Unknown result type (might be due to invalid IL or missing references)
//IL_00a9: Unknown result type (might be due to invalid IL or missing references)
if (!ModConfig.EnterEnabled.Value)
{
_enterHold = 0f;
_enterConsumed = false;
return;
}
if (!KeyHeld(ModConfig.EnterKey.Value))
{
_enterHold = 0f;
_enterConsumed = false;
return;
}
_enterHold += Time.deltaTime;
if (!_enterConsumed && !(_enterHold < ModConfig.EnterHold.Value) && alive && !((Object)(object)local == (Object)null) && CannonUtil.TryGetAimedCannon(CannonUtil.GetCamera(), ModConfig.EnterRange.Value, out var cannon))
{
Transform entry = CannonUtil.GetEntry(cannon);
if (!((Object)(object)entry == (Object)null))
{
InvokeWarp(local, entry.position, poof: false);
_enterConsumed = true;
_enterHold = 0f;
ModConfig.Log("已进入大炮内。");
}
}
}
private void TickIgnite(Character local, bool alive)
{
//IL_002d: Unknown result type (might be due to invalid IL or missing references)
if (!ModConfig.IgniteEnabled.Value || !alive || Time.time < _igniteBlockUntil)
{
_igniteHold = 0f;
return;
}
if (!KeyHeld(ModConfig.IgniteKey.Value))
{
_igniteHold = 0f;
return;
}
if (!CannonUtil.TryGetNearbyUnlitCannon(local, ModConfig.IgniteRadius.Value, out var cannon, out var _))
{
_igniteHold = 0f;
return;
}
_igniteHold += Time.deltaTime;
if (!(_igniteHold < ModConfig.IgniteHold.Value))
{
_igniteHold = 0f;
_igniteBlockUntil = Time.time + 1f;
if (!cannon.lit)
{
cannon.Light();
ModConfig.Log("炮内点火成功。");
}
}
}
private void OnGUI()
{
try
{
DrawCrosshair();
}
catch
{
}
}
private void DrawCrosshair()
{
//IL_0049: Unknown result type (might be due to invalid IL or missing references)
//IL_004e: Unknown result type (might be due to invalid IL or missing references)
//IL_0050: Unknown result type (might be due to invalid IL or missing references)
//IL_0055: 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_005d: 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_0064: 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_0091: 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_0238: Unknown result type (might be due to invalid IL or missing references)
//IL_023e: Unknown result type (might be due to invalid IL or missing references)
//IL_0243: Unknown result type (might be due to invalid IL or missing references)
//IL_0252: 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_0121: Unknown result type (might be due to invalid IL or missing references)
//IL_013d: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Unknown result type (might be due to invalid IL or missing references)
//IL_01c8: Unknown result type (might be due to invalid IL or missing references)
//IL_01d5: Unknown result type (might be due to invalid IL or missing references)
//IL_01f1: Unknown result type (might be due to invalid IL or missing references)
//IL_020b: Unknown result type (might be due to invalid IL or missing references)
//IL_021a: Unknown result type (might be due to invalid IL or missing references)
if (!ModConfig.ViewEnabled.Value || !ModConfig.ViewCrosshair.Value || !CannonViewState.Aiming || !CannonUtil.TryGetHeldMuzzle(out var muzzle, out var direction))
{
return;
}
Camera camera = CannonUtil.GetCamera();
if ((Object)(object)camera == (Object)null)
{
return;
}
float value = ModConfig.CrosshairRange.Value;
Vector3 val = muzzle.position + direction * value;
Vector3 val2 = camera.WorldToScreenPoint(val);
float num = (float)Screen.width * 0.5f;
float num2 = (float)Screen.height * 0.5f;
float x = val2.x;
float num3 = (float)Screen.height - val2.y;
EnsureCrosshairTexture();
float num4 = ModConfig.CrosshairSize.Value * Mathf.Max(1f, (float)Screen.height / 1080f);
float num5 = num4 + 6f;
bool num6 = val2.z > 0f && x >= num5 && x <= (float)Screen.width - num5 && num3 >= num5 && num3 <= (float)Screen.height - num5;
float num7 = 1f;
float num15;
float num16;
if (!num6)
{
if (!ModConfig.ViewEdgeIndicator.Value)
{
return;
}
float num8 = ((val2.z > 0f) ? (x - num) : (num - x));
float num9 = ((val2.z > 0f) ? (num3 - num2) : (num2 - num3));
Vector2 val3 = default(Vector2);
((Vector2)(ref val3))..ctor(num8, num9);
if (((Vector2)(ref val3)).sqrMagnitude < 0.0001f)
{
((Vector2)(ref val3))..ctor(0f, -1f);
}
((Vector2)(ref val3)).Normalize();
float num10 = Mathf.Max(1f, num - num5);
float num11 = Mathf.Max(1f, num2 - num5);
float num12 = ((Mathf.Abs(val3.x) > 0.0001f) ? (num10 / Mathf.Abs(val3.x)) : float.MaxValue);
float num13 = ((Mathf.Abs(val3.y) > 0.0001f) ? (num11 / Mathf.Abs(val3.y)) : float.MaxValue);
float num14 = Mathf.Min(num12, num13);
num15 = num + val3.x * num14;
num16 = num2 + val3.y * num14;
num7 = 0.55f;
}
else
{
num15 = x;
num16 = num3;
}
Color color = GUI.color;
Color crosshairColor = GetCrosshairColor();
crosshairColor.a *= num7;
GUI.color = crosshairColor;
GUI.DrawTexture(new Rect(num15 - num4, num16 - num4, num4 * 2f, num4 * 2f), (Texture)(object)_crosshairTex, (ScaleMode)0, true);
GUI.color = color;
}
private Color GetCrosshairColor()
{
//IL_001a: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: Unknown result type (might be due to invalid IL or missing references)
//IL_003a: 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)
string value = ModConfig.CrosshairColor.Value;
if (value == _colorCachedKey)
{
return _colorCachedValue;
}
_colorCachedKey = value;
Color colorCachedValue = default(Color);
if (!string.IsNullOrEmpty(value) && ColorUtility.TryParseHtmlString(value, ref colorCachedValue))
{
_colorCachedValue = colorCachedValue;
}
return _colorCachedValue;
}
private void EnsureCrosshairTexture()
{
//IL_002e: Unknown result type (might be due to invalid IL or missing references)
//IL_002f: Unknown result type (might be due to invalid IL or missing references)
//IL_017b: Unknown result type (might be due to invalid IL or missing references)
//IL_0185: Expected O, but got Unknown
//IL_0150: Unknown result type (might be due to invalid IL or missing references)
//IL_0155: Unknown result type (might be due to invalid IL or missing references)
if ((Object)(object)_crosshairTex != (Object)null)
{
return;
}
int num = 64;
Color32[] array = (Color32[])(object)new Color32[num * num];
Color32 val = default(Color32);
((Color32)(ref val))..ctor((byte)0, (byte)0, (byte)0, (byte)0);
for (int i = 0; i < array.Length; i++)
{
array[i] = val;
}
float num2 = (float)(num - 1) * 0.5f;
float num3 = num2 - 2f;
float num4 = num3 - 3f;
for (int j = 0; j < num; j++)
{
for (int k = 0; k < num; k++)
{
float num5 = (float)k - num2;
float num6 = (float)j - num2;
float num7 = Mathf.Sqrt(num5 * num5 + num6 * num6);
bool num8 = num7 >= num4 && num7 <= num3;
bool flag = num7 <= 1.6f;
bool flag2 = false;
if (!num8 && !flag)
{
bool num9 = Mathf.Abs(num5) <= 1f && Mathf.Abs(num6) >= num3 + 1f && Mathf.Abs(num6) <= num3 + 6f;
bool flag3 = Mathf.Abs(num6) <= 1f && Mathf.Abs(num5) >= num3 + 1f && Mathf.Abs(num5) <= num3 + 6f;
flag2 = num9 || flag3;
}
if (num8 || flag || flag2)
{
array[j * num + k] = new Color32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue);
}
}
}
_crosshairTex = new Texture2D(num, num, (TextureFormat)4, false);
_crosshairTex.SetPixels32(array);
_crosshairTex.Apply();
((Object)_crosshairTex).hideFlags = (HideFlags)61;
}
private static bool KeyHeld(KeyCode key)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
if ((int)key == 0)
{
return false;
}
return Input.GetKey(key);
}
private static bool KeyPressedThisFrame(KeyCode key)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
if ((int)key == 0)
{
return false;
}
return Input.GetKeyDown(key);
}
}
internal static class CannonUtil
{
private static readonly FieldInfo[] ScoutCannonFields = typeof(ScoutCannon).GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static FieldInfo _tubeField;
private static FieldInfo _entryField;
private static bool _fieldsResolved;
private static readonly FieldInfo MainCameraCamField = typeof(MainCamera).GetField("cam", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
private static readonly List<ScoutCannon> CannonCache = new List<ScoutCannon>();
private static float _cannonCacheTime = -999f;
private const float CannonCacheInterval = 2f;
private static Constructable _lastConstructable;
private static bool _lastConstructableIsCannon;
private static void ResolveFields()
{
if (_fieldsResolved)
{
return;
}
_fieldsResolved = true;
FieldInfo[] scoutCannonFields = ScoutCannonFields;
foreach (FieldInfo fieldInfo in scoutCannonFields)
{
if (fieldInfo.Name == "tube")
{
_tubeField = fieldInfo;
}
else if (fieldInfo.Name == "entry")
{
_entryField = fieldInfo;
}
}
}
public static bool TryGetHeldScroll(out Constructable constructable, out Item item)
{
constructable = null;
item = null;
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null || (Object)(object)localCharacter.data == (Object)null)
{
return false;
}
item = localCharacter.data.currentItem;
if ((Object)(object)item == (Object)null)
{
return false;
}
Constructable component = ((Component)item).GetComponent<Constructable>();
if ((Object)(object)component == (Object)null || !IsCannonScroll(component))
{
return false;
}
constructable = component;
return true;
}
private static bool IsCannonScroll(Constructable c)
{
if ((Object)(object)c == (Object)(object)_lastConstructable)
{
return _lastConstructableIsCannon;
}
_lastConstructable = c;
_lastConstructableIsCannon = false;
try
{
if ((Object)(object)c.constructedPrefab != (Object)null)
{
_lastConstructableIsCannon = (Object)(object)c.constructedPrefab.GetComponentInChildren<ScoutCannon>(true) != (Object)null;
}
if (!_lastConstructableIsCannon)
{
string text = (((Object)(object)((Component)c).gameObject != (Object)null) ? ((Object)((Component)c).gameObject).name : string.Empty);
if ((Object)(object)c.constructedPrefab != (Object)null)
{
text = text + " " + ((Object)c.constructedPrefab).name;
}
if ((Object)(object)c.previewPrefab != (Object)null)
{
text = text + " " + ((Object)c.previewPrefab).name;
}
_lastConstructableIsCannon = text.IndexOf("cannon", StringComparison.OrdinalIgnoreCase) >= 0;
}
}
catch
{
_lastConstructableIsCannon = false;
}
return _lastConstructableIsCannon;
}
public static bool TryGetHeldMuzzle(out Transform muzzle, out Vector3 direction)
{
//IL_0004: Unknown result type (might be due to invalid IL or missing references)
//IL_0009: Unknown result type (might be due to invalid IL or missing references)
//IL_009f: Unknown result type (might be due to invalid IL or missing references)
//IL_00a4: Unknown result type (might be due to invalid IL or missing references)
muzzle = null;
direction = Vector3.zero;
if (!TryGetHeldScroll(out var constructable, out var _))
{
return false;
}
ConstructablePreview currentPreview = constructable.currentPreview;
if ((Object)(object)currentPreview == (Object)null)
{
return false;
}
Transform transform = ((Component)currentPreview).transform;
Transform val = null;
val = FindChildByName(transform, "Entry");
if ((Object)(object)val == (Object)null)
{
val = FindChildByName(transform, "Cannon");
}
if ((Object)(object)val == (Object)null && transform.childCount > 0)
{
Transform child = transform.GetChild(0);
if ((Object)(object)child != (Object)null && child.childCount > 0)
{
val = child.GetChild(0);
}
}
if ((Object)(object)val == (Object)null)
{
val = transform;
}
muzzle = val;
direction = val.forward;
return ((Vector3)(ref direction)).sqrMagnitude > 1E-06f;
}
private static Transform FindChildByName(Transform root, string name)
{
if ((Object)(object)root == (Object)null || string.IsNullOrEmpty(name))
{
return null;
}
Transform[] componentsInChildren = ((Component)root).GetComponentsInChildren<Transform>(true);
for (int i = 0; i < componentsInChildren.Length; i++)
{
if ((Object)(object)componentsInChildren[i] != (Object)null && ((Object)componentsInChildren[i]).name == name)
{
return componentsInChildren[i];
}
}
return null;
}
public static Camera GetCamera()
{
try
{
MainCamera instance = MainCamera.instance;
if ((Object)(object)instance != (Object)null && MainCameraCamField != null)
{
object? value = MainCameraCamField.GetValue(instance);
Camera val = (Camera)((value is Camera) ? value : null);
if ((Object)(object)val != (Object)null)
{
return val;
}
}
}
catch
{
}
return Camera.main;
}
public static List<ScoutCannon> GetCannons()
{
if (Time.unscaledTime - _cannonCacheTime < 2f)
{
return CannonCache;
}
_cannonCacheTime = Time.unscaledTime;
CannonCache.Clear();
try
{
ScoutCannon[] array = Object.FindObjectsByType<ScoutCannon>((FindObjectsSortMode)0);
for (int i = 0; i < array.Length; i++)
{
if ((Object)(object)array[i] != (Object)null)
{
CannonCache.Add(array[i]);
}
}
}
catch
{
}
return CannonCache;
}
public static void InvalidateCannonCache()
{
_cannonCacheTime = -999f;
}
public static Transform GetTube(ScoutCannon cannon)
{
ResolveFields();
object? obj = _tubeField?.GetValue(cannon);
Transform val = (Transform)((obj is Transform) ? obj : null);
if ((Object)(object)val == (Object)null && (Object)(object)cannon != (Object)null)
{
val = ((Component)cannon).transform.Find("Cannon");
}
return val;
}
public static Transform GetEntry(ScoutCannon cannon)
{
ResolveFields();
object? obj = _entryField?.GetValue(cannon);
Transform val = (Transform)((obj is Transform) ? obj : null);
if ((Object)(object)val == (Object)null && (Object)(object)cannon != (Object)null)
{
val = ((Component)cannon).transform.Find("Cannon/Entry");
}
return val;
}
public static bool TryGetAimedCannon(Camera cam, float range, out ScoutCannon cannon)
{
//IL_0015: 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)
cannon = null;
if ((Object)(object)cam == (Object)null)
{
return false;
}
RaycastHit[] array;
try
{
array = Physics.RaycastAll(((Component)cam).transform.position, ((Component)cam).transform.forward, range, -1, (QueryTriggerInteraction)2);
}
catch
{
return false;
}
if (array == null || array.Length == 0)
{
return false;
}
Array.Sort(array, (RaycastHit a, RaycastHit b) => ((RaycastHit)(ref a)).distance.CompareTo(((RaycastHit)(ref b)).distance));
for (int num = 0; num < array.Length; num++)
{
if (!((Object)(object)((RaycastHit)(ref array[num])).collider == (Object)null))
{
ScoutCannon componentInParent = ((Component)((RaycastHit)(ref array[num])).collider).GetComponentInParent<ScoutCannon>();
if ((Object)(object)componentInParent != (Object)null)
{
cannon = componentInParent;
return true;
}
}
}
return false;
}
public static bool TryGetNearbyUnlitCannon(Character local, float radius, out ScoutCannon cannon, out float distance)
{
//IL_0016: Unknown result type (might be due to invalid IL or missing references)
//IL_001b: 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)
//IL_0054: Unknown result type (might be due to invalid IL or missing references)
cannon = null;
distance = float.MaxValue;
if ((Object)(object)local == (Object)null)
{
return false;
}
Vector3 center = local.Center;
List<ScoutCannon> cannons = GetCannons();
for (int i = 0; i < cannons.Count; i++)
{
ScoutCannon val = cannons[i];
if ((Object)(object)val == (Object)null || val.lit)
{
continue;
}
Transform entry = GetEntry(val);
if (!((Object)(object)entry == (Object)null))
{
float num = Vector3.Distance(center, entry.position);
if (num <= radius && num < distance)
{
cannon = val;
distance = num;
}
}
}
return (Object)(object)cannon != (Object)null;
}
public static Vector2 DirectionToLook(Vector3 dir)
{
//IL_0000: Unknown result type (might be due to invalid IL or missing references)
//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_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_000e: Unknown result type (might be due to invalid IL or missing references)
//IL_0013: Unknown result type (might be due to invalid IL or missing references)
//IL_0014: Unknown result type (might be due to invalid IL or missing references)
//IL_0031: Unknown result type (might be due to invalid IL or missing references)
//IL_0037: Unknown result type (might be due to invalid IL or missing references)
//IL_003e: Unknown result type (might be due to invalid IL or missing references)
Quaternion val = Quaternion.LookRotation(dir, Vector3.up);
Vector3 eulerAngles = ((Quaternion)(ref val)).eulerAngles;
if (eulerAngles.x > 180f)
{
eulerAngles.x -= 360f;
}
return new Vector2(eulerAngles.y, 0f - eulerAngles.x);
}
}
internal static class ModConfig
{
public static ConfigEntry<bool> ViewEnabled;
public static ConfigEntry<KeyCode> ViewKey;
public static ConfigEntry<bool> ViewLockCamera;
public static ConfigEntry<bool> ViewFullAlign;
public static ConfigEntry<bool> ViewCrosshair;
public static ConfigEntry<bool> ViewEdgeIndicator;
public static ConfigEntry<float> CrosshairSize;
public static ConfigEntry<float> CrosshairRange;
public static ConfigEntry<string> CrosshairColor;
public static ConfigEntry<bool> ScopeEnabled;
public static ConfigEntry<int> ScopeCorner;
public static ConfigEntry<float> ScopeWidth;
public static ConfigEntry<float> ScopeMargin;
public static ConfigEntry<float> ScopeFov;
public static ConfigEntry<float> ScopeForwardOffset;
public static ConfigEntry<bool> ScopeCrosshair;
public static ConfigEntry<bool> EnterEnabled;
public static ConfigEntry<KeyCode> EnterKey;
public static ConfigEntry<float> EnterHold;
public static ConfigEntry<float> EnterRange;
public static ConfigEntry<bool> BlockAutoPull;
public static ConfigEntry<bool> IgniteEnabled;
public static ConfigEntry<KeyCode> IgniteKey;
public static ConfigEntry<float> IgniteHold;
public static ConfigEntry<float> IgniteRadius;
public static ConfigEntry<bool> DebugLog;
public static void Init(ConfigFile config)
{
//IL_00cc: Unknown result type (might be due to invalid IL or missing references)
//IL_00d6: Expected O, but got Unknown
//IL_0104: Unknown result type (might be due to invalid IL or missing references)
//IL_010e: Expected O, but got Unknown
//IL_016a: Unknown result type (might be due to invalid IL or missing references)
//IL_0174: Expected O, but got Unknown
//IL_01a2: Unknown result type (might be due to invalid IL or missing references)
//IL_01ac: Expected O, but got Unknown
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01e4: Expected O, but got Unknown
//IL_0212: Unknown result type (might be due to invalid IL or missing references)
//IL_021c: Expected O, but got Unknown
//IL_024a: Unknown result type (might be due to invalid IL or missing references)
//IL_0254: Expected O, but got Unknown
//IL_02d4: Unknown result type (might be due to invalid IL or missing references)
//IL_02de: Expected O, but got Unknown
//IL_030c: Unknown result type (might be due to invalid IL or missing references)
//IL_0316: Expected O, but got Unknown
//IL_0396: Unknown result type (might be due to invalid IL or missing references)
//IL_03a0: Expected O, but got Unknown
//IL_03ce: Unknown result type (might be due to invalid IL or missing references)
//IL_03d8: Expected O, but got Unknown
ViewEnabled = config.Bind<bool>("视角对准炮口", "启用炮口瞄准指示", true, "开启后,手持童子军大炮建造卷轴、地面出现大炮放置预览时,按切换键显示炮口瞄准指示(准星;炮口指向上方或屏幕外时在屏幕边缘提示),据此看清大炮将打向哪里、方便决定放在什么位置。默认不改变相机朝向,因此移动、瞄准地面落点、放置大炮都不受影响;若还想让相机也贴齐炮口方向(便于直视远方目标),请打开下面的“锁定视角到炮口”。再按一下切换键关闭。");
ViewKey = config.Bind<KeyCode>("视角对准炮口", "切换按键", (KeyCode)118, "按下一次显示炮口瞄准指示,再按一次关闭。");
ViewLockCamera = config.Bind<bool>("视角对准炮口", "锁定视角到炮口", false, "开启后,瞄准状态下把相机朝向(俯仰与水平)锁定为放置预览的炮口方向,屏幕中心即炮口指向,便于直视远方目标。注意:大炮放置依赖相机朝地面发射线判定落点(Constructable.TryUpdatePreview),锁住相机后相机无法下看地面,会导致无法放置大炮;建议只在观察远方时临时开启,放置时保持关闭。默认关闭。");
ViewFullAlign = config.Bind<bool>("视角对准炮口", "完全对齐炮口方向", true, "仅当“锁定视角到炮口”开启时生效。开启:俯仰与水平都锁定为炮口方向(屏幕中心即炮口指向);关闭:只对齐俯仰,水平方向仍可自由转动(大炮预览的水平朝向本就跟随视线,因此通常也一致)。");
ViewCrosshair = config.Bind<bool>("视角对准炮口", "显示炮口准星", true, "处于炮口瞄准状态时,在炮口方向的投影点上绘制准星。");
ViewEdgeIndicator = config.Bind<bool>("视角对准炮口", "屏幕外显示边缘指示", true, "炮口指向上方或屏幕外时,在屏幕边缘显示准星提示,便于俯视地面放置大炮时也能知道炮口朝向。");
CrosshairSize = config.Bind<float>("视角对准炮口", "准星基础尺寸", 26f, new ConfigDescription("准星基础半径(像素),会随分辨率与界面缩放自动适配。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(6f, 80f), Array.Empty<object>()));
CrosshairRange = config.Bind<float>("视角对准炮口", "准星投影距离", 300f, new ConfigDescription("准星绘制在炮口方向该距离处的屏幕投影上。数值越大,准星越接近炮口指向的“正前方”,且不受近距离物体视差影响(推荐 200 以上)。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 1000f), Array.Empty<object>()));
CrosshairColor = config.Bind<string>("视角对准炮口", "准星颜色", "#39FF6A", "准星颜色,十六进制,例如 #39FF6A(绿色)、#FF3B30(红色)、#FFFFFF(白色)。");
ScopeEnabled = config.Bind<bool>("瞄准小窗", "启用瞄准小窗", true, "开启后,处于炮口瞄准状态时,在屏幕一角实时显示从炮口沿炮口方向看出去的画面(画中画)。这样你可以一边用主视角查看地面、移动并放置大炮,一边在小窗里直接看到炮口对准的远方,不必再靠准星猜测。需额外渲染一遍场景,有少量性能开销;不需要时可关闭。");
ScopeCorner = config.Bind<int>("瞄准小窗", "小窗位置", 0, new ConfigDescription("小窗贴着屏幕哪个角:0=右下,1=右上,2=左下,3=左上。", (AcceptableValueBase)(object)new AcceptableValueRange<int>(0, 3), Array.Empty<object>()));
ScopeWidth = config.Bind<float>("瞄准小窗", "小窗宽度(像素)", 320f, new ConfigDescription("小窗的宽度,高度自动按 16:9 计算。数值越大越清晰、开销越高。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(96f, 800f), Array.Empty<object>()));
ScopeMargin = config.Bind<float>("瞄准小窗", "小窗边距(像素)", 16f, new ConfigDescription("小窗与屏幕边缘的距离。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 200f), Array.Empty<object>()));
ScopeFov = config.Bind<float>("瞄准小窗", "视野角度", 60f, new ConfigDescription("小窗的相机视野角度(FOV)。数值越小画面越“拉近”,便于看远处目标。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(20f, 110f), Array.Empty<object>()));
ScopeForwardOffset = config.Bind<float>("瞄准小窗", "相机前移(米)", 0.25f, new ConfigDescription("小窗相机从炮口节点沿炮口方向前移的距离。若小窗里看到炮管内壁或角色手臂,可适当加大。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0f, 5f), Array.Empty<object>()));
ScopeCrosshair = config.Bind<bool>("瞄准小窗", "小窗内准星", true, "在小窗画面中心绘制一个十字准星,表示炮口正指向的位置。");
EnterEnabled = config.Bind<bool>("进入大炮", "启用进入大炮", true, "开启后,对准一门已放置的童子军大炮,长按进入键即可直接把角色送入炮口内。");
EnterKey = config.Bind<KeyCode>("进入大炮", "进入按键", (KeyCode)120, "对准大炮长按该键进入炮内。");
EnterHold = config.Bind<float>("进入大炮", "长按时间(秒)", 0.3f, new ConfigDescription("对准大炮后需要持续按住的时长,达到后执行进入。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.05f, 3f), Array.Empty<object>()));
EnterRange = config.Bind<float>("进入大炮", "瞄准射线距离(米)", 25f, new ConfigDescription("对准判定所用的最大射线距离。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(2f, 200f), Array.Empty<object>()));
BlockAutoPull = config.Bind<bool>("进入大炮", "禁止自动吸附本地玩家", true, "原版大炮会把走到炮口 1 米内的最近角色自动吸进炮内(这是原版装载队友的机制,见 ScoutCannon.FixedUpdate)。开启本项后,当你自己位于吸附范围内时跳过该自动吸附,避免只是在大炮附近走动就被吸进去;只有按进入键才会进入。关闭则保留原版自动吸附行为。注意:该逻辑由主机执行,因此仅当你是主机时生效。");
IgniteEnabled = config.Bind<bool>("炮内点火", "启用炮内点火", true, "开启后,当角色处于某门未点火大炮的炮口附近时,长按点火键即可点燃。已点火或正在点火的大炮不会重复触发。");
IgniteKey = config.Bind<KeyCode>("炮内点火", "点火按键", (KeyCode)101, "在大炮内长按该键点火(默认 E,与游戏交互键一致)。");
IgniteHold = config.Bind<float>("炮内点火", "长按时间(秒)", 1f, new ConfigDescription("在炮内按住点火键的时长,达到后点火。默认与原版引信交互时长一致。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.1f, 5f), Array.Empty<object>()));
IgniteRadius = config.Bind<float>("炮内点火", "炮内判定半径(米)", 2.2f, new ConfigDescription("角色与炮口 Distance 在该半径内即视为“在大炮内”,可点火。", (AcceptableValueBase)(object)new AcceptableValueRange<float>(0.5f, 6f), Array.Empty<object>()));
DebugLog = config.Bind<bool>("调试", "详细日志", false, "开启后在 BepInEx 控制台输出进入/点火/切换视角的调试信息。");
}
public static void Log(string message)
{
if (DebugLog != null && DebugLog.Value)
{
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogInfo((object)("[童子军大炮] " + message));
}
}
}
}
[HarmonyPatch(typeof(ScoutCannon), "FixedUpdate")]
internal static class AutoPullPatch
{
private const float VanillaPullRadius = 1f;
[HarmonyPrefix]
private static bool Prefix(ScoutCannon __instance)
{
//IL_0032: Unknown result type (might be due to invalid IL or missing references)
//IL_0038: Unknown result type (might be due to invalid IL or missing references)
if (!ModConfig.BlockAutoPull.Value)
{
return true;
}
Character localCharacter = Character.localCharacter;
if ((Object)(object)localCharacter == (Object)null)
{
return true;
}
Transform entry = CannonUtil.GetEntry(__instance);
if ((Object)(object)entry == (Object)null)
{
return true;
}
if (Vector3.Distance(localCharacter.Center, entry.position) < 1f)
{
return false;
}
return true;
}
}
[BepInPlugin("com.fufu.scoutcannonhelper", "童子军大炮", "0.1.6")]
internal sealed class Plugin : BaseUnityPlugin
{
private Harmony _harmony;
private GameObject _host;
internal static Plugin Instance { get; private set; }
internal static ManualLogSource LoggerRef { get; private set; }
private void Awake()
{
//IL_0022: Unknown result type (might be due to invalid IL or missing references)
//IL_002c: Expected O, but got Unknown
//IL_006d: Unknown result type (might be due to invalid IL or missing references)
//IL_0077: Expected O, but got Unknown
Instance = this;
LoggerRef = ((BaseUnityPlugin)this).Logger;
ModConfig.Init(((BaseUnityPlugin)this).Config);
_harmony = new Harmony("com.fufu.scoutcannonhelper");
try
{
_harmony.PatchAll(Assembly.GetExecutingAssembly());
((BaseUnityPlugin)this).Logger.LogInfo((object)"[童子军大炮] v0.1.6 已加载,Harmony 补丁应用成功。");
}
catch (Exception arg)
{
((BaseUnityPlugin)this).Logger.LogError((object)$"[童子军大炮] Harmony 补丁应用失败:{arg}");
}
_host = new GameObject("ScoutCannonHelper_Host");
Object.DontDestroyOnLoad((Object)(object)_host);
((Object)_host).hideFlags = (HideFlags)61;
_host.AddComponent<CannonController>();
_host.AddComponent<AimScope>();
((BaseUnityPlugin)this).Logger.LogInfo((object)"[童子军大炮] 控制器已挂载。");
}
private void OnDestroy()
{
try
{
Harmony harmony = _harmony;
if (harmony != null)
{
harmony.UnpatchSelf();
}
}
catch
{
}
}
}
internal static class PluginInfo
{
public const string PLUGIN_GUID = "com.fufu.scoutcannonhelper";
public const string PLUGIN_NAME = "童子军大炮";
public const string PLUGIN_VERSION = "0.1.6";
}
}
namespace ScoutCannonHelper.Patches
{
[HarmonyPatch(typeof(Character), "RecalculateLookDirections")]
internal static class LookPatch
{
private static void Prefix(Character __instance)
{
//IL_003a: 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_0040: Unknown result type (might be due to invalid IL or missing references)
//IL_0041: 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_0087: Unknown result type (might be due to invalid IL or missing references)
//IL_0097: Unknown result type (might be due to invalid IL or missing references)
//IL_0099: Unknown result type (might be due to invalid IL or missing references)
//IL_0069: Unknown result type (might be due to invalid IL or missing references)
//IL_0070: 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)
try
{
if (!((Object)(object)__instance == (Object)null) && __instance.IsLocal && ModConfig.ViewLockCamera.Value && CannonViewState.Aiming && CannonUtil.TryGetHeldMuzzle(out var _, out var direction))
{
Vector2 val = CannonUtil.DirectionToLook(direction);
float num = Mathf.Clamp(val.y, -85f, 85f);
if (ModConfig.ViewFullAlign.Value)
{
__instance.data.lookValues = new Vector2(val.x, num);
return;
}
Vector2 lookValues = __instance.data.lookValues;
lookValues.y = num;
__instance.data.lookValues = lookValues;
}
}
catch
{
}
}
}
}