using System;
using System.Collections;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
using Photon.Pun;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("CrewLateJoin")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("FluxTeam")]
[assembly: AssemblyProduct("CrewLateJoin")]
[assembly: AssemblyCopyright("Copyright © FluxTeam 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("8f3d5e42-1c9f-4a8b-9e2d-5c1a8b3d9e4f")]
[assembly: AssemblyFileVersion("1.0.2.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.0.2.0")]
namespace CrewLateJoin;
[BepInPlugin("FluxTeam.CrewLateJoin", "Crew Late Join", "1.0.2")]
public class CrewLateJoin : BaseUnityPlugin
{
private const string GUID = "FluxTeam.CrewLateJoin";
private const string NAME = "Crew Late Join";
private const string VERSION = "1.0.2";
internal static ManualLogSource logger;
internal static CrewLateJoin instance;
public static ConfigEntry<bool> AllowLateJoin;
public static ConfigEntry<bool> EnableCartDurationChanges;
public static ConfigEntry<float> CartStayDuration;
private void Awake()
{
//IL_00de: Unknown result type (might be due to invalid IL or missing references)
//IL_010a: Unknown result type (might be due to invalid IL or missing references)
//IL_0110: Expected O, but got Unknown
//IL_0120: Unknown result type (might be due to invalid IL or missing references)
//IL_0126: Expected O, but got Unknown
//IL_0126: Unknown result type (might be due to invalid IL or missing references)
//IL_015a: Unknown result type (might be due to invalid IL or missing references)
//IL_0161: Expected O, but got Unknown
//IL_0161: Unknown result type (might be due to invalid IL or missing references)
//IL_0197: Unknown result type (might be due to invalid IL or missing references)
//IL_019e: Expected O, but got Unknown
//IL_019e: Unknown result type (might be due to invalid IL or missing references)
//IL_01da: Unknown result type (might be due to invalid IL or missing references)
//IL_01e1: Expected O, but got Unknown
//IL_01e1: Unknown result type (might be due to invalid IL or missing references)
//IL_0218: Unknown result type (might be due to invalid IL or missing references)
//IL_021f: Expected O, but got Unknown
logger = ((BaseUnityPlugin)this).Logger;
instance = this;
AllowLateJoin = ((BaseUnityPlugin)this).Config.Bind<bool>("Network.Room", "AllowLateJoin", true, "Allow players to join the room even after the game has started");
EnableCartDurationChanges = ((BaseUnityPlugin)this).Config.Bind<bool>("Network.Cart", "EnableCartDurationChanges", false, "Enable custom cart stay duration. When disabled, uses vanilla stay duration.");
CartStayDuration = ((BaseUnityPlugin)this).Config.Bind<float>("Network.Cart", "CartStayDuration", 90f, "How long the cart stays in seconds. Only used if EnableCartDurationChanges is true. Vanilla default is 90s.");
logger.LogInfo((object)"Crew Late Join v1.0.2 loaded!");
logger.LogInfo((object)$"Config - Allow Late Join: {AllowLateJoin.Value}");
logger.LogInfo((object)$"Config - Cart Duration Changes: {EnableCartDurationChanges.Value}, Duration: {CartStayDuration.Value}s");
try
{
Harmony val = new Harmony("FluxTeam.CrewLateJoin");
MethodInfo methodInfo = AccessTools.Method(typeof(GameController), "StartNewMapRPC", (Type[])null, (Type[])null);
HarmonyMethod val2 = new HarmonyMethod(typeof(GameControllerPatches), "StartNewMapRPC_Prefix", (Type[])null);
HarmonyMethod val3 = new HarmonyMethod(typeof(GameControllerPatches), "StartNewMapRPC_Postfix", (Type[])null);
val.Patch((MethodBase)methodInfo, val2, val3, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(GameController), "GoToCheckpointRPC", (Type[])null, (Type[])null);
HarmonyMethod val4 = new HarmonyMethod(typeof(GameControllerPatches), "GoToCheckpointRPC_Postfix", (Type[])null);
val.Patch((MethodBase)methodInfo2, (HarmonyMethod)null, val4, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(GameController), "ResetGameRPC", (Type[])null, (Type[])null);
HarmonyMethod val5 = new HarmonyMethod(typeof(GameControllerPatches), "ResetGameRPC_Postfix", (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, val5, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
ItemCarrierPatches.InitializeReflection();
MethodInfo methodInfo4 = AccessTools.Method(typeof(ItemCarrierController), "Start", (Type[])null, (Type[])null);
HarmonyMethod val6 = new HarmonyMethod(typeof(ItemCarrierPatches), "Start_Postfix", (Type[])null);
val.Patch((MethodBase)methodInfo4, (HarmonyMethod)null, val6, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo5 = AccessTools.Method(typeof(ItemCarrierController), "Update", (Type[])null, (Type[])null);
HarmonyMethod val7 = new HarmonyMethod(typeof(ItemCarrierPatches), "Update_Prefix", (Type[])null);
val.Patch((MethodBase)methodInfo5, val7, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
logger.LogInfo((object)"Harmony patches applied successfully");
}
catch (Exception arg)
{
logger.LogError((object)$"Failed to apply Harmony patches: {arg}");
}
}
}
public static class GameControllerPatches
{
public static void StartNewMapRPC_Prefix()
{
if (CrewLateJoin.AllowLateJoin.Value && PhotonNetwork.IsMasterClient)
{
CrewLateJoin.logger.LogInfo((object)"AllowLateJoin Enabled - Photon Room will be reopened after StartNewMapRPC");
}
}
public static void StartNewMapRPC_Postfix()
{
if (PhotonNetwork.IsMasterClient && CrewLateJoin.AllowLateJoin.Value)
{
CrewLateJoin.logger.LogInfo((object)"AllowLateJoin Enabled - Forcing Photon Room to stay Open (IsOpen = true)");
PhotonNetwork.CurrentRoom.IsOpen = true;
PhotonNetwork.CurrentRoom.IsVisible = true;
}
}
public static void GoToCheckpointRPC_Postfix()
{
if (PhotonNetwork.IsMasterClient && CrewLateJoin.AllowLateJoin.Value)
{
PhotonNetwork.CurrentRoom.IsOpen = true;
}
}
public static void ResetGameRPC_Postfix()
{
if (PhotonNetwork.IsMasterClient && CrewLateJoin.AllowLateJoin.Value)
{
PhotonNetwork.CurrentRoom.IsOpen = true;
}
}
}
public static class ItemCarrierPatches
{
private static FieldInfo _arriveTimerField;
private static FieldInfo _departTimerField;
private static FieldInfo _itemsField;
private static FieldInfo _stateField;
private static FieldInfo _stayDurationField;
private static FieldInfo _animatorField;
private static FieldInfo _speedField;
private static FieldInfo _crankSpeedField;
private static FieldInfo _maxCrankSpeedField;
private static FieldInfo _wheelSpeedField;
private static FieldInfo _maxWheelSpeedField;
private static FieldInfo _frontAxleField;
private static FieldInfo _backAxleField;
private static int _lastLoggedState = -1;
private static bool _hasAppliedDuration = false;
public static void InitializeReflection()
{
CrewLateJoin.logger.LogInfo((object)"Initializing ItemCarrier reflection fields...");
_arriveTimerField = AccessTools.Field(typeof(ItemCarrierController), "arriveTimer");
_departTimerField = AccessTools.Field(typeof(ItemCarrierController), "departTimer");
_itemsField = AccessTools.Field(typeof(ItemCarrierController), "items");
_stateField = AccessTools.Field(typeof(ItemCarrierController), "state");
_stayDurationField = AccessTools.Field(typeof(ItemCarrierController), "stayDuration");
_animatorField = AccessTools.Field(typeof(ItemCarrierController), "animator");
_speedField = AccessTools.Field(typeof(ItemCarrierController), "speed");
_crankSpeedField = AccessTools.Field(typeof(ItemCarrierController), "crankSpeed");
_maxCrankSpeedField = AccessTools.Field(typeof(ItemCarrierController), "maxCrankSpeed");
_wheelSpeedField = AccessTools.Field(typeof(ItemCarrierController), "wheelSpeed");
_maxWheelSpeedField = AccessTools.Field(typeof(ItemCarrierController), "maxWheelSpeed");
_frontAxleField = AccessTools.Field(typeof(ItemCarrierController), "frontAxle");
_backAxleField = AccessTools.Field(typeof(ItemCarrierController), "backAxle");
CrewLateJoin.logger.LogInfo((object)"ItemCarrier reflection fields initialized");
}
public static void Start_Postfix(ItemCarrierController __instance)
{
if (!((Object)(object)__instance == (Object)null) && !(_stayDurationField == null))
{
float num = (float)_stayDurationField.GetValue(__instance);
ConfigEntry<bool> enableCartDurationChanges = CrewLateJoin.EnableCartDurationChanges;
if (enableCartDurationChanges != null && enableCartDurationChanges.Value && !_hasAppliedDuration)
{
float num2 = CrewLateJoin.CartStayDuration?.Value ?? num;
_stayDurationField.SetValue(__instance, num2);
_hasAppliedDuration = true;
CrewLateJoin.logger.LogInfo((object)$"Applied custom cart stay duration: {num2}s (vanilla: {num}s)");
}
}
}
private static bool ShouldApplyCustomLogic()
{
if (!CrewLateJoin.AllowLateJoin.Value)
{
return false;
}
if ((Object)(object)SurfaceGenerator.instance != (Object)null && SurfaceGenerator.instance.traveling)
{
return false;
}
if ((Object)(object)GameController.instance != (Object)null && !GameController.instance.atCheckpoint)
{
return true;
}
return false;
}
public static bool Update_Prefix(ItemCarrierController __instance)
{
PhotonView component = ((Component)__instance).GetComponent<PhotonView>();
if ((Object)(object)component == (Object)null)
{
return true;
}
if (!component.IsMine)
{
UpdateVisuals(__instance);
return false;
}
if (!ShouldApplyCustomLogic())
{
return true;
}
UpdateCartLogic(__instance, component);
UpdateVisuals(__instance);
return false;
}
private static void UpdateCartLogic(ItemCarrierController instance, PhotonView pv)
{
float num = (float)_arriveTimerField.GetValue(instance);
float num2 = (float)_departTimerField.GetValue(instance);
IList list = _itemsField.GetValue(instance) as IList;
int num3 = (int)_stateField.GetValue(instance);
num -= Time.deltaTime;
num2 -= Time.deltaTime;
_arriveTimerField.SetValue(instance, num);
_departTimerField.SetValue(instance, num2);
if (num <= 0f && list.Count > 0 && num3 == 0)
{
pv.RPC("ArriveRPC", (RpcTarget)0, Array.Empty<object>());
if (num3 != _lastLoggedState)
{
CrewLateJoin.logger.LogInfo((object)"Cart arriving (AllowLateJoin fix active)");
_lastLoggedState = 1;
}
}
if (num3 == 2 && ((bool)AccessTools.Method(typeof(ItemCarrierController), "AllItemsTaken", (Type[])null, (Type[])null).Invoke(instance, null) || num2 <= 0f))
{
pv.RPC("DepartRPC", (RpcTarget)0, Array.Empty<object>());
if (num3 != _lastLoggedState)
{
CrewLateJoin.logger.LogInfo((object)"Cart departing (AllowLateJoin fix active)");
_lastLoggedState = 3;
}
}
}
private static void UpdateVisuals(ItemCarrierController instance)
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
//IL_0011: Expected O, but got Unknown
//IL_0073: Unknown result type (might be due to invalid IL or missing references)
//IL_0083: Unknown result type (might be due to invalid IL or missing references)
//IL_008a: Expected O, but got Unknown
//IL_00a5: 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_00ba: Unknown result type (might be due to invalid IL or missing references)
//IL_00c4: Unknown result type (might be due to invalid IL or missing references)
//IL_00d5: Unknown result type (might be due to invalid IL or missing references)
//IL_00e2: Unknown result type (might be due to invalid IL or missing references)
//IL_00e9: Unknown result type (might be due to invalid IL or missing references)
//IL_00f3: Unknown result type (might be due to invalid IL or missing references)
Animator val = (Animator)_animatorField.GetValue(instance);
float num = (float)_speedField.GetValue(instance);
float num2 = (float)_crankSpeedField.GetValue(instance);
float num3 = (float)_maxCrankSpeedField.GetValue(instance);
float num4 = (float)_wheelSpeedField.GetValue(instance);
float num5 = (float)_maxWheelSpeedField.GetValue(instance);
Transform val2 = (Transform)_frontAxleField.GetValue(instance);
Transform val3 = (Transform)_backAxleField.GetValue(instance);
val.SetFloat("Speed", Mathf.Clamp(num * num2, 0f - num3, num3));
((Component)val2).transform.Rotate(Vector3.up * (0f - Mathf.Min(num, num5)) * num4 * Time.deltaTime);
((Component)val3).transform.Rotate(Vector3.up * Mathf.Min(num, num5) * num4 * Time.deltaTime);
}
}