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 static class CannonHoldState
{
public static ScoutCannon Cannon;
public static float ExpireAt;
public static bool IsHolding(ScoutCannon cannon)
{
if ((Object)(object)cannon != (Object)null && (Object)(object)Cannon == (Object)(object)cannon)
{
return Time.unscaledTime < ExpireAt;
}
return false;
}
public static void Begin(ScoutCannon cannon, float keepAlive)
{
Cannon = cannon;
ExpireAt = Time.unscaledTime + keepAlive;
}
public static void Release()
{
Cannon = null;
ExpireAt = 0f;
}
}
internal sealed class CannonController : MonoBehaviour
{
private float _enterHold;
private bool _enterConsumed;
private bool _viewWasHolding;
private float _igniteHold;
private float _igniteBlockUntil;
private const float IgniteCooldown = 1f;
private const float HoldKeepAlive = 2f;
private const float HoldReleaseRadius = 3f;
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);
TickHold(localCharacter);
}
private void TickViewToggle()
{
//IL_0067: 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;
_viewWasHolding = false;
return;
}
if (!_viewWasHolding)
{
_viewWasHolding = true;
CannonViewState.Aiming = ModConfig.ScopeDefaultOn != null && ModConfig.ScopeDefaultOn.Value;
if (CannonViewState.Aiming)
{
ModConfig.Log("已进入炮口视角(默认开启)。");
}
}
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_00fd: 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_00d1: Unknown result type (might be due to invalid IL or missing references)
//IL_00d3: 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) || (Object)(object)CannonUtil.GetEntry(cannon) == (Object)null)
{
return;
}
if (ModConfig.EnterBackpack.Value && CannonUtil.IsHoldingBackpack(local))
{
_enterConsumed = true;
_enterHold = 0f;
Vector3 backpackDropPosition = CannonUtil.GetBackpackDropPosition(cannon);
if (CannonUtil.TryDropHeldBackpack(local, backpackDropPosition))
{
ModConfig.Log("已把背包放入大炮内。");
return;
}
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogWarning((object)"[童子军大炮] 手持背包但放入失败,已跳过本次进入。");
}
}
else
{
InvokeWarp(local, CannonUtil.GetPlayerWarpPosition(cannon), poof: false);
CannonHoldState.Begin(cannon, 2f);
_enterConsumed = true;
_enterHold = 0f;
ModConfig.Log("已进入大炮内。");
}
}
private static void TickHold(Character local)
{
//IL_0050: 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)
ScoutCannon cannon = CannonHoldState.Cannon;
if ((Object)(object)cannon == (Object)null)
{
return;
}
if ((Object)(object)local == (Object)null || (Object)(object)local.data == (Object)null || local.data.sinceJump < 0.3f)
{
CannonHoldState.Release();
return;
}
Transform entry = CannonUtil.GetEntry(cannon);
if ((Object)(object)entry == (Object)null || Vector3.Distance(local.Center, entry.position) > 3f)
{
CannonHoldState.Release();
}
else
{
CannonHoldState.Begin(cannon, 2f);
}
}
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 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 ConstructablePreview _muzzlePreviewKey;
private static Transform _muzzleTransform;
private static readonly RaycastHit[] AimHits = (RaycastHit[])(object)new RaycastHit[128];
private static readonly bool[] AimConsumed = new bool[128];
private const float PlayerInsetFromMuzzle = 0.25f;
private const float BackpackInsetFromCenter = 0.15f;
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_00cb: Unknown result type (might be due to invalid IL or missing references)
//IL_00d0: 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;
if ((Object)(object)currentPreview == (Object)(object)_muzzlePreviewKey && (Object)(object)_muzzleTransform != (Object)null)
{
val = _muzzleTransform;
}
else
{
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;
}
_muzzlePreviewKey = currentPreview;
_muzzleTransform = val;
}
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;
}
int num;
try
{
num = Physics.RaycastNonAlloc(((Component)cam).transform.position, ((Component)cam).transform.forward, AimHits, range, -1, (QueryTriggerInteraction)2);
}
catch
{
return false;
}
for (int i = 0; i < num; i++)
{
AimConsumed[i] = false;
}
int num2 = -1;
float num3 = float.MaxValue;
for (int j = 0; j < num; j++)
{
if (!AimConsumed[j] && !((Object)(object)((RaycastHit)(ref AimHits[j])).collider == (Object)null) && ((RaycastHit)(ref AimHits[j])).distance < num3)
{
num3 = ((RaycastHit)(ref AimHits[j])).distance;
num2 = j;
}
}
while (num2 >= 0)
{
ScoutCannon componentInParent = ((Component)((RaycastHit)(ref AimHits[num2])).collider).GetComponentInParent<ScoutCannon>();
if ((Object)(object)componentInParent != (Object)null)
{
cannon = componentInParent;
return true;
}
AimConsumed[num2] = true;
num2 = -1;
num3 = float.MaxValue;
for (int k = 0; k < num; k++)
{
if (!AimConsumed[k] && (Object)(object)((RaycastHit)(ref AimHits[k])).collider != (Object)null && ((RaycastHit)(ref AimHits[k])).distance < num3)
{
num3 = ((RaycastHit)(ref AimHits[k])).distance;
num2 = k;
}
}
}
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);
}
public static Vector3 GetPlayerWarpPosition(ScoutCannon cannon)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: 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_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_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: 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_0025: Unknown result type (might be due to invalid IL or missing references)
//IL_0019: Unknown result type (might be due to invalid IL or missing references)
Transform entry = GetEntry(cannon);
if ((Object)(object)entry == (Object)null)
{
if (!((Object)(object)cannon != (Object)null))
{
return Vector3.zero;
}
return ((Component)cannon).transform.position;
}
Transform tube = GetTube(cannon);
if ((Object)(object)tube == (Object)null)
{
return entry.position;
}
Vector3 val = entry.position - tube.forward * 0.25f;
ModConfig.Log($"[童子军大炮] 角色落点:entry={entry.position} forward={tube.forward} point={val}");
return val;
}
public static Vector3 GetBackpackDropPosition(ScoutCannon cannon)
{
//IL_0043: Unknown result type (might be due to invalid IL or missing references)
//IL_0049: 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_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_0064: Unknown result type (might be due to invalid IL or missing references)
//IL_006f: Unknown result type (might be due to invalid IL or missing references)
//IL_0079: Unknown result type (might be due to invalid IL or missing references)
//IL_0089: 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_0035: Unknown result type (might be due to invalid IL or missing references)
//IL_0029: Unknown result type (might be due to invalid IL or missing references)
Transform tube = GetTube(cannon);
if ((Object)(object)tube == (Object)null)
{
Transform entry = GetEntry(cannon);
if (!((Object)(object)entry != (Object)null))
{
if (!((Object)(object)cannon != (Object)null))
{
return Vector3.zero;
}
return ((Component)cannon).transform.position;
}
return entry.position;
}
Vector3 val = tube.position - tube.forward * 0.15f;
ModConfig.Log($"[童子军大炮] 背包落点:tube={tube.position} forward={tube.forward} point={val}");
return val;
}
public static bool IsHoldingBackpack(Character local)
{
if ((Object)(object)local != (Object)null && (Object)(object)local.data != (Object)null)
{
return local.data.currentItem is Backpack;
}
return false;
}
public static bool TryDropHeldBackpack(Character local, Vector3 position)
{
//IL_009d: Unknown result type (might be due to invalid IL or missing references)
//IL_00a6: Unknown result type (might be due to invalid IL or missing references)
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
if (!IsHoldingBackpack(local))
{
return false;
}
CharacterItems val = ((local.refs != null) ? local.refs.items : null);
Player player = local.player;
if ((Object)(object)val == (Object)null || (Object)(object)player == (Object)null || !val.currentSelectedSlot.IsSome)
{
return false;
}
byte value = val.currentSelectedSlot.Value;
ItemSlot itemSlot = player.GetItemSlot(value);
if (itemSlot == null)
{
return false;
}
PhotonView component = ((Component)val).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null)
{
return false;
}
try
{
component.RPC("DropItemRpc", (RpcTarget)0, new object[7]
{
0f,
value,
position,
Vector3.zero,
local.data.currentItem.transform.rotation,
itemSlot.data,
false
});
return true;
}
catch (Exception arg)
{
ManualLogSource loggerRef = Plugin.LoggerRef;
if (loggerRef != null)
{
loggerRef.LogError((object)$"[童子军大炮] 放入背包失败:{arg}");
}
return false;
}
}
}
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> ScopeEnabled;
public static ConfigEntry<bool> ScopeDefaultOn;
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<bool> EnterBackpack;
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_00c0: Unknown result type (might be due to invalid IL or missing references)
//IL_00ca: Expected O, but got Unknown
//IL_00f8: Unknown result type (might be due to invalid IL or missing references)
//IL_0102: Expected O, but got Unknown
//IL_0130: Unknown result type (might be due to invalid IL or missing references)
//IL_013a: Expected O, but got Unknown
//IL_0168: Unknown result type (might be due to invalid IL or missing references)
//IL_0172: Expected O, but got Unknown
//IL_01a0: Unknown result type (might be due to invalid IL or missing references)
//IL_01aa: Expected O, but got Unknown
//IL_022a: Unknown result type (might be due to invalid IL or missing references)
//IL_0234: Expected O, but got Unknown
//IL_027d: Unknown result type (might be due to invalid IL or missing references)
//IL_0287: Expected O, but got Unknown
//IL_0307: Unknown result type (might be due to invalid IL or missing references)
//IL_0311: Expected O, but got Unknown
//IL_033f: Unknown result type (might be due to invalid IL or missing references)
//IL_0349: 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, "仅当“锁定视角到炮口”开启时生效。开启:俯仰与水平都锁定为炮口方向(屏幕中心即炮口指向);关闭:只对齐俯仰,水平方向仍可自由转动(大炮预览的水平朝向本就跟随视线,因此通常也一致)。");
ScopeEnabled = config.Bind<bool>("瞄准小窗", "启用瞄准小窗", true, "开启后,处于炮口瞄准状态时,在屏幕一角实时显示从炮口沿炮口方向看出去的画面(画中画)。这样你可以一边用主视角查看地面、移动并放置大炮,一边在小窗里直接看到炮口对准的远方,不必再靠准星猜测。需额外渲染一遍场景,有少量性能开销;不需要时可关闭。");
ScopeDefaultOn = config.Bind<bool>("瞄准小窗", "默认开启瞄准状态", false, "开启后,只要手持大炮建造卷轴,无需按切换键就自动进入炮口瞄准状态(小窗随之显示);按一下切换键仍可临时关闭。关闭时保持原行为:必须按切换键才显示。未手持卷轴、或瞄准状态关闭时,小窗相机不会创建、也不渲染,无额外性能开销。");
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>()));
EnterBackpack = config.Bind<bool>("进入大炮", "手持背包时放入背包", true, "开启后,对准大炮长按进入键时:若手里正拿着背包,则把背包丢进炮管最里面(背包会被大炮以更高发射力射出),角色自己不进炮;手里没拿背包时角色照常进入。关闭后进入键始终让角色进炮。");
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 CannonHoldState.IsHolding(__instance);
}
return true;
}
}
[BepInPlugin("ScoutCannonHelper", "童子军大炮", "0.3.0")]
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("ScoutCannonHelper");
try
{
_harmony.PatchAll(Assembly.GetExecutingAssembly());
((BaseUnityPlugin)this).Logger.LogInfo((object)"[童子军大炮] v0.3.0 已加载,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 = "ScoutCannonHelper";
public const string PLUGIN_NAME = "童子军大炮";
public const string PLUGIN_VERSION = "0.3.0";
}
}
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
{
}
}
}
}