Please disclose if any significant portion of your mod was created using AI tools by adding the 'AI Generated' category. Failing to do so may result in the mod being removed from Thunderstore.
Decompiled source of Repo Contracts v0.5.16
BepInEx\plugins\RepoContracts\RepoContracts.dll
Decompiled 2 weeks ago
The result has been truncated due to the large size, download it to view full contents!
using System; using System.Collections; using System.Collections.Generic; using System.Diagnostics; using System.Globalization; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using BepInEx.Logging; using ExitGames.Client.Photon; using HarmonyLib; using Microsoft.CodeAnalysis; using Photon.Pun; using Photon.Realtime; using RepoContracts.Adapters; using RepoContracts.Contracts; using RepoContracts.Networking; using RepoContracts.Patches; using RepoContracts.Rewards; using RepoContracts.UI; using UnityEngine; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.1", FrameworkDisplayName = ".NET Standard 2.1")] [assembly: AssemblyCompany("RepoContracts")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyDescription("Optional contract objectives and tiered rewards for R.E.P.O.")] [assembly: AssemblyFileVersion("0.5.16.0")] [assembly: AssemblyInformationalVersion("0.5.16")] [assembly: AssemblyProduct("RepoContracts")] [assembly: AssemblyTitle("RepoContracts")] [assembly: AssemblyVersion("0.5.16.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.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 RepoContracts { [BepInPlugin("com.amgru.repocontracts", "RepoContracts", "0.5.16")] [BepInDependency(/*Could not decode attribute arguments.*/)] public sealed class Plugin : BaseUnityPlugin { public const string PluginGuid = "com.amgru.repocontracts"; public const string PluginName = "RepoContracts"; public const string PluginVersion = "0.5.16"; internal static ConfigEntry<bool> EnableRepoContracts; internal static ConfigEntry<int> OfferedContractsPerLevel; internal static ConfigEntry<int> SelectedContractsPerLevel; internal static ConfigEntry<bool> OneActiveContractAtATime; internal static ConfigEntry<bool> AdvanceQueueOnFailure; internal static ConfigEntry<bool> AdvanceQueueOnCompletion; internal static ConfigEntry<bool> EnableMilestoneContracts; internal static ConfigEntry<int> MilestoneContractEveryXLevels; internal static ConfigEntry<bool> AllowNormalContractsDuringMilestone; internal static ConfigEntry<float> RewardMultiplier; internal static ConfigEntry<FailureStrictness> FailureStrictness; internal static ConfigEntry<DisciplineMode> DisciplineMode; internal static ConfigEntry<bool> EnableDisciplineDebt; internal static ConfigEntry<bool> EnableDebugLogging; internal static ConfigEntry<bool> AutoLockFirstOffersForDebug; internal static ConfigEntry<KeyCode> ContractHudKey; internal static ConfigEntry<KeyCode> ContractBoardLockKey; internal static ConfigEntry<float> BoardSideOffset; internal static ConfigEntry<float> BoardForwardOffset; internal static ConfigEntry<float> BoardUpOffset; internal static ConfigEntry<float> BoardYawOffset; internal static ConfigEntry<float> BoardScale; internal static ConfigEntry<float> BoardNudgeStep; internal static ConfigEntry<float> BoardRotateStep; internal static ConfigEntry<bool> EnableExperimentalContracts; internal static ConfigEntry<bool> EnableAssetHeavyContracts; internal static ConfigEntry<bool> EnableCompatibilityMode; private Harmony? harmony; internal static Plugin Instance { get; private set; } internal static ContractManager Manager { get; private set; } internal static ManualLogSource Log => ((BaseUnityPlugin)Instance).Logger; private void Awake() { //IL_03c1: Unknown result type (might be due to invalid IL or missing references) //IL_03cb: Expected O, but got Unknown Instance = this; EnableRepoContracts = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "EnableRepoContracts", true, "Enables or disables Repo Contracts."); OfferedContractsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Contracts", "OfferedContractsPerLevel", 5, "Contracts shown on the truck board."); SelectedContractsPerLevel = ((BaseUnityPlugin)this).Config.Bind<int>("Contracts", "SelectedContractsPerLevel", 3, "Contracts selected into the priority queue."); OneActiveContractAtATime = ((BaseUnityPlugin)this).Config.Bind<bool>("Contracts", "OneActiveContractAtATime", true, "Only one selected contract is active at a time."); AdvanceQueueOnFailure = ((BaseUnityPlugin)this).Config.Bind<bool>("Contracts", "AdvanceQueueOnFailure", true, "Automatically activate the next contract when the active one fails."); AdvanceQueueOnCompletion = ((BaseUnityPlugin)this).Config.Bind<bool>("Contracts", "AdvanceQueueOnCompletion", true, "Automatically activate the next contract when the active one completes."); EnableMilestoneContracts = ((BaseUnityPlugin)this).Config.Bind<bool>("Milestones", "EnableMilestoneContracts", true, "Enables special all-encompassing milestone contracts."); MilestoneContractEveryXLevels = ((BaseUnityPlugin)this).Config.Bind<int>("Milestones", "MilestoneContractEveryXLevels", 3, "Offer a milestone contract every X completed levels."); AllowNormalContractsDuringMilestone = ((BaseUnityPlugin)this).Config.Bind<bool>("Milestones", "AllowNormalContractsDuringMilestone", false, "Allows the normal queue alongside milestone contracts."); RewardMultiplier = ((BaseUnityPlugin)this).Config.Bind<float>("Rewards", "RewardMultiplier", 1f, "Scales additive contract rewards."); FailureStrictness = ((BaseUnityPlugin)this).Config.Bind<FailureStrictness>("Contracts", "FailureStrictness", RepoContracts.Contracts.FailureStrictness.Normal, "How punishing failure variants should be."); DisciplineMode = ((BaseUnityPlugin)this).Config.Bind<DisciplineMode>("Discipline", "DisciplineMode", RepoContracts.Contracts.DisciplineMode.Standard, "Future penalty severity for failed contracts when discipline debt is enabled."); EnableDisciplineDebt = ((BaseUnityPlugin)this).Config.Bind<bool>("Discipline", "EnableDisciplineDebt", false, "Future/off-by-default setting. When enabled, failed contracts add debt that withholds future contract rewards."); EnableDebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "EnableDebugLogging", true, "Logs adapter activity and TODO hook gaps."); AutoLockFirstOffersForDebug = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "AutoLockFirstOffersForDebug", false, "Debug helper that auto-selects and locks the first offered contracts after generation."); ContractHudKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ContractHudKey", (KeyCode)99, "Keyboard key that toggles the active contract HUD overlay."); ContractBoardLockKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Controls", "ContractBoardLockKey", (KeyCode)108, "Host keyboard key that locks/tallies board votes while pointing at the board."); BoardSideOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "SideOffset", -6.149996f, "Meters to the truck side from the anchor for the contract TV."); BoardForwardOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "ForwardOffset", -0.04999985f, "Meters forward/back from the anchor for the contract TV."); BoardUpOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "UpOffset", 0.3499997f, "Meters upward from the anchor for the contract TV."); BoardYawOffset = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "YawOffset", 270f, "Yaw offset from the truck anchor for the contract TV."); BoardScale = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "Scale", 2.099999f, "Overall contract TV scale."); BoardNudgeStep = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "NudgeStep", 0.1f, "Meters moved per calibration key press."); BoardRotateStep = ((BaseUnityPlugin)this).Config.Bind<float>("Board", "RotateStep", 5f, "Degrees rotated per calibration key press."); EnableExperimentalContracts = ((BaseUnityPlugin)this).Config.Bind<bool>("Contracts", "EnableExperimentalContracts", false, "Allows contracts that rely on unverified or risky hooks."); EnableAssetHeavyContracts = ((BaseUnityPlugin)this).Config.Bind<bool>("Contracts", "EnableAssetHeavyContracts", false, "Allows contracts needing new world models, VFX, SFX, or heavier UI assets."); EnableCompatibilityMode = ((BaseUnityPlugin)this).Config.Bind<bool>("Compatibility", "EnableCompatibilityMode", true, "Skips contracts needing risky object replacement, spawn replacement, control manipulation, or enemy roster manipulation."); ContractBoardUi boardUi = ((Component)this).gameObject.AddComponent<ContractBoardUi>(); ContractHud hud = ((Component)this).gameObject.AddComponent<ContractHud>(); Manager = new ContractManager(new ContractCatalog(), new RewardAdapter(), new ContractSyncAdapter(), boardUi, hud); harmony = new Harmony("com.amgru.repocontracts"); harmony.PatchAll(); OptionalContractPatches.Apply(harmony); HookAudit.LogKnownHookStatus(); ((BaseUnityPlugin)this).Logger.LogInfo((object)"RepoContracts v0.5.16 loaded."); } private void Update() { Manager?.PollSyncedState(); Manager?.UpdateActiveWorldContracts(); } private void OnDestroy() { Harmony? obj = harmony; if (obj != null) { obj.UnpatchSelf(); } } internal static void SaveSettings() { ((BaseUnityPlugin)Instance).Config.Save(); } } } namespace RepoContracts.Patches { [HarmonyPatch(typeof(LevelGenerator), "GenerateDone")] internal static class LevelGeneratorGenerateDonePatch { private static void Postfix() { if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } Plugin.Manager.GenerateOffersAtTruck(); if (Plugin.Manager.Queue.OfferedContracts.Count != 0) { Plugin.Manager.EventBus.OnLevelStarted(); if (Plugin.AutoLockFirstOffersForDebug.Value) { Plugin.Manager.HostLockQueue(); } } } } [HarmonyPatch(typeof(HurtCollider), "EnemyHurt")] internal static class ContractEnemyHurtPatch { private static void Postfix(HurtCollider __instance, Enemy _enemy, bool __result) { if (__result && SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_enemy != (Object)null) { Plugin.Manager.EventBus.OnEnemyDamaged(((Component)_enemy).gameObject, 1, "hurt-collider"); } } } [HarmonyPatch(typeof(HurtCollider), "PlayerHurt")] internal static class ContractPlayerHurtPatch { private static void Postfix(PlayerAvatar _player) { if (SemiFunc.IsMasterClientOrSingleplayer() && (Object)(object)_player != (Object)null) { Plugin.Manager.EventBus.OnPlayerDamaged(((Component)_player).gameObject); } } } [HarmonyPatch(typeof(EnemyHealth), "DeathImpulseRPC")] internal static class ContractEnemyKilledPatch { private static void Postfix(EnemyHealth __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { Enemy component = ((Component)__instance).GetComponent<Enemy>(); GameObject enemy = (((Object)(object)component != (Object)null) ? ((Component)component).gameObject : ((Component)__instance).gameObject); Plugin.Manager.HandleEnemyKilled(enemy, "verified-enemy-health"); } } } [HarmonyPatch(typeof(PlayerAvatar), "PlayerDeathRPC")] internal static class ContractPlayerDeathPatch { private static void Postfix(PlayerAvatar __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { Plugin.Manager.HandlePlayerDeath(((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(ItemGun), "Shoot")] internal static class ContractProjectileWeaponUsedPatch { private static void Postfix(ItemGun __instance, bool __result) { if (__result && SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { Plugin.Manager.EventBus.OnProjectileWeaponUsed(((Component)__instance).gameObject); } } } [HarmonyPatch(typeof(RoundDirector), "HaulCheck")] internal static class ContractHaulCheckPatch { private static void Postfix(RoundDirector __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { List<GameObject> candidates = __instance.dollarHaulList.Where((GameObject item) => (Object)(object)item != (Object)null).ToList(); Plugin.Manager.CaptureExtractionCandidates(candidates); } } } [HarmonyPatch(typeof(RoundDirector), "ExtractionCompleted")] internal static class ContractExtractionCompletedPatch { private static void Postfix(RoundDirector __instance) { if (SemiFunc.IsMasterClientOrSingleplayer()) { Plugin.Manager.HandleExtractionCompleted(null); } } } [HarmonyPatch(typeof(ExtractionPoint), "DestroyTheFirstPhysObjectsInHaulList")] internal static class ContractExtractionPointItemExtractPatch { private static bool Prefix(ExtractionPoint __instance) { if (!SemiFunc.IsMasterClientOrSingleplayer() || (Object)(object)RoundDirector.instance == (Object)null || RoundDirector.instance.dollarHaulList.Count == 0) { return true; } if ((Object)(object)__instance != (Object)null && Plugin.Manager.ShouldBlockPressurePlateExtraction(((Component)__instance).gameObject)) { return false; } GameObject val = RoundDirector.instance.dollarHaulList[0]; if ((Object)(object)val == (Object)null || (Object)(object)val.GetComponent<ValuableObject>() == (Object)null) { return true; } Plugin.Manager.HandleValuableExtracting(val, ((Object)(object)__instance != (Object)null) ? ((Component)__instance).gameObject : null); return true; } } [HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "BreakRPC")] internal static class ContractValuableBreakPatch { private static bool Prefix(PhysGrabObjectImpactDetector __instance) { if (!((Object)(object)__instance == (Object)null)) { return !Plugin.Manager.IsProtectedPressurePlateWeight(((Component)__instance).gameObject); } return true; } private static void Postfix(PhysGrabObjectImpactDetector __instance, float valueLost, bool _loseValue) { if (_loseValue && SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { ValuableObject component = ((Component)__instance).GetComponent<ValuableObject>(); if (!((Object)(object)component == (Object)null)) { Plugin.Manager.HandleValuableDamaged(((Component)component).gameObject, Mathf.RoundToInt(valueLost)); } } } } [HarmonyPatch(typeof(PhysGrabObjectImpactDetector), "DestroyObjectRPC")] internal static class ContractValuableDestroyedPatch { private static bool Prefix(PhysGrabObjectImpactDetector __instance) { if (!((Object)(object)__instance == (Object)null)) { return !Plugin.Manager.IsProtectedPressurePlateWeight(((Component)__instance).gameObject); } return true; } private static void Postfix(PhysGrabObjectImpactDetector __instance) { if (SemiFunc.IsMasterClientOrSingleplayer() && !((Object)(object)__instance == (Object)null)) { ValuableObject component = ((Component)__instance).GetComponent<ValuableObject>(); if (!((Object)(object)component == (Object)null)) { Plugin.Manager.HandleValuableDestroyed(((Component)component).gameObject); } } } } [HarmonyPatch(typeof(PhysGrabObject), "GrabStarted")] internal static class ContractItemGrabStartedPatch { private static void Postfix(PhysGrabObject __instance, PhysGrabber player) { if (!((Object)(object)__instance == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer()) { ValuableObject component = ((Component)__instance).GetComponent<ValuableObject>(); if (!((Object)(object)component == (Object)null)) { Plugin.Manager.HandleItemGrabbed(((Component)component).gameObject, ((Object)(object)player != (Object)null) ? ((Component)player).gameObject : null); } } } } [HarmonyPatch(typeof(PhysGrabObject), "GrabPlayerAddRPC")] internal static class ContractItemGrabPlayerAddPatch { private static void Postfix(PhysGrabObject __instance, int photonViewID) { if (!((Object)(object)__instance == (Object)null) && SemiFunc.IsMasterClientOrSingleplayer()) { ValuableObject component = ((Component)__instance).GetComponent<ValuableObject>(); if (!((Object)(object)component == (Object)null)) { PhotonView obj = PhotonView.Find(photonViewID); GameObject player = ((obj != null) ? ((Component)obj).gameObject : null); Plugin.Manager.HandleItemGrabbed(((Component)component).gameObject, player); } } } } internal static class OptionalContractPatches { internal static void Apply(Harmony harmony) { PatchIfFound(harmony, typeof(TruckHealer), "Heal", "player healing", null, AccessTools.Method(typeof(OptionalContractPatches), "TruckHealerHealPostfix", (Type[])null, (Type[])null)); PatchIfFound(harmony, typeof(RunManager), "ChangeLevel", "level transition fallback", AccessTools.Method(typeof(OptionalContractPatches), "RunManagerChangeLevelPrefix", (Type[])null, (Type[])null)); } private static void PatchIfFound(Harmony harmony, Type type, string methodName, string label, MethodInfo? prefix = null, MethodInfo? postfix = null) { //IL_0024: 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) MethodInfo methodInfo = HookAudit.TryMethod(type, methodName, label); if (!(methodInfo == null)) { object obj = harmony; obj = methodInfo; obj = (object)((!(prefix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(prefix)); obj = (object)((!(postfix != null)) ? ((HarmonyMethod)null) : new HarmonyMethod(postfix)); ((Harmony)obj).Patch((MethodBase)obj, (HarmonyMethod)obj, (HarmonyMethod)obj, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null); } } private static void TruckHealerHealPostfix() { if (SemiFunc.IsMasterClientOrSingleplayer()) { Plugin.Manager.EventBus.OnPlayerHealed(null, 10); } } private static void RunManagerChangeLevelPrefix() { //IL_000d: Unknown result type (might be due to invalid IL or missing references) if (SemiFunc.IsMasterClientOrSingleplayer()) { Plugin.Manager.CompleteLevel(Vector3.zero); } } } } namespace RepoContracts.UI { internal static class ContractAssets { private static readonly Dictionary<string, Texture2D?> Textures = new Dictionary<string, Texture2D>(); private static readonly Dictionary<string, Material?> Materials = new Dictionary<string, Material>(); internal static Texture2D? Texture(string relativePath) { //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0060: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Expected O, but got Unknown if (Textures.TryGetValue(relativePath, out Texture2D value)) { return value; } string path = FindAssetPath(relativePath); if (!File.Exists(path)) { Plugin.Log.LogWarning((object)("[RepoContracts] Missing packaged asset: " + relativePath)); Textures[relativePath] = null; return null; } try { Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false) { name = Path.GetFileNameWithoutExtension(relativePath), wrapMode = (TextureWrapMode)1, filterMode = (FilterMode)1 }; if (!LoadImage(val, File.ReadAllBytes(path))) { Plugin.Log.LogWarning((object)("[RepoContracts] Unity could not decode packaged asset: " + relativePath)); Textures[relativePath] = null; return null; } Textures[relativePath] = val; return val; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[RepoContracts] Failed to load packaged asset " + relativePath + ": " + ex.Message)); Textures[relativePath] = null; return null; } } internal static Material? Material(string relativePath, Color tint, bool transparent = true) { //IL_0006: 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) //IL_0072: Unknown result type (might be due to invalid IL or missing references) //IL_0088: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_0090: Unknown result type (might be due to invalid IL or missing references) //IL_0097: Expected O, but got Unknown string key = $"{relativePath}|{tint}|{transparent}"; if (Materials.TryGetValue(key, out Material value)) { return value; } Texture2D val = Texture(relativePath); if ((Object)(object)val == (Object)null) { Materials[key] = null; return null; } Material val2 = new Material(Shader.Find("Unlit/Transparent") ?? Shader.Find("GUI/Text Shader") ?? Shader.Find("Standard")) { name = "RepoContracts " + Path.GetFileNameWithoutExtension(relativePath), mainTexture = (Texture)(object)val, color = tint }; if (transparent) { ConfigureTransparentMaterial(val2); } Materials[key] = val2; return val2; } internal static void ApplyTexture(GameObject target, string relativePath, Color tint, bool transparent = true) { //IL_0008: Unknown result type (might be due to invalid IL or missing references) Renderer component = target.GetComponent<Renderer>(); Material val = Material(relativePath, tint, transparent); if ((Object)(object)component != (Object)null && (Object)(object)val != (Object)null) { component.material = val; } } internal static void ApplyTextMaterial(TextMesh text, Color color) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0065: Unknown result type (might be due to invalid IL or missing references) //IL_005d: Unknown result type (might be due to invalid IL or missing references) //IL_006b: Expected O, but got Unknown //IL_009f: Unknown result type (might be due to invalid IL or missing references) text.color = color; Renderer component = ((Component)text).GetComponent<Renderer>(); if ((Object)(object)component == (Object)null) { return; } Material val = (((Object)(object)text.font != (Object)null) ? text.font.material : null); Shader val2 = Shader.Find("GUI/Text Shader"); if (!((Object)(object)val == (Object)null) || !((Object)(object)val2 == (Object)null)) { Material val3 = (((Object)(object)val != (Object)null) ? new Material(val) : new Material(val2)); if ((Object)(object)val2 != (Object)null) { val3.shader = val2; } if ((Object)(object)val != (Object)null && (Object)(object)val.mainTexture != (Object)null) { val3.mainTexture = val.mainTexture; } val3.color = color; val3.renderQueue = 3000; component.material = val3; } } private static string FindAssetPath(string relativePath) { string text = relativePath.Replace('/', Path.DirectorySeparatorChar); string text2 = Path.Combine(Paths.PluginPath, "RepoContracts", "assets", text); if (File.Exists(text2)) { return text2; } string text3 = Path.Combine(Path.GetDirectoryName(typeof(Plugin).Assembly.Location) ?? Paths.PluginPath, "assets", text); if (File.Exists(text3)) { return text3; } return Path.Combine(Paths.GameRootPath, "assets", "repo_contracts", text); } private static bool LoadImage(Texture2D texture, byte[] bytes) { MethodInfo methodInfo = (Type.GetType("UnityEngine.ImageConversion, UnityEngine.ImageConversionModule") ?? Type.GetType("UnityEngine.ImageConversion, UnityEngine.CoreModule") ?? Type.GetType("UnityEngine.ImageConversion, UnityEngine"))?.GetMethod("LoadImage", BindingFlags.Static | BindingFlags.Public, null, new Type[3] { typeof(Texture2D), typeof(byte[]), typeof(bool) }, null); if (methodInfo == null) { Plugin.Log.LogWarning((object)"[RepoContracts] UnityEngine.ImageConversion.LoadImage was unavailable; packaged PNG assets cannot be decoded."); return false; } object obj = methodInfo.Invoke(null, new object[3] { texture, bytes, false }); bool flag = default(bool); int num; if (obj is bool) { flag = (bool)obj; num = 1; } else { num = 0; } return (byte)((uint)num & (flag ? 1u : 0u)) != 0; } private static void ConfigureTransparentMaterial(Material material) { material.SetFloat("_Mode", 3f); material.SetInt("_SrcBlend", 5); material.SetInt("_DstBlend", 10); material.SetInt("_ZWrite", 0); material.DisableKeyword("_ALPHATEST_ON"); material.EnableKeyword("_ALPHABLEND_ON"); material.DisableKeyword("_ALPHAPREMULTIPLY_ON"); material.renderQueue = 3000; } } internal sealed class ContractBoardUi : MonoBehaviour { private readonly List<ContractBoardCard> cards = new List<ContractBoardCard>(); private ContractQueue? queue; private GameObject? boardRoot; private TextMesh? headerText; private TextMesh? selectedText; private TextMesh? promptText; private int highlightedIndex = -1; private bool placementMode; private float readableSideSign = -1f; private float controllerMoveCooldownUntil; internal void Show(ContractQueue contractQueue) { queue = contractQueue; EnsureBoard(); RebuildBoardText(); LogBoard("show"); } internal void Refresh(ContractQueue contractQueue) { queue = contractQueue; EnsureBoard(); RebuildBoardText(); LogBoard("refresh"); } internal void Hide() { if ((Object)(object)boardRoot != (Object)null) { Object.Destroy((Object)(object)boardRoot); boardRoot = null; } cards.Clear(); headerText = null; selectedText = null; promptText = null; highlightedIndex = -1; } internal Vector3? GetRewardSpawnPosition() { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0048: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0052: 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_006c: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boardRoot == (Object)null) { return null; } return boardRoot.transform.position - boardRoot.transform.forward * (1.15f * Plugin.BoardScale.Value) + Vector3.up * (0.2f * Plugin.BoardScale.Value); } private void Update() { //IL_00ec: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)boardRoot != (Object)null) { UpdatePlacementMode(); if (placementMode) { return; } } if (queue == null || (Object)(object)boardRoot == (Object)null || queue.OfferedContracts.Count == 0) { return; } UpdateHighlight(); if (queue.IsLocked) { return; } UpdateControllerHighlight(); Plugin.Manager.TryAutoLockQueueFromVotes(); if (highlightedIndex >= 0 && highlightedIndex < queue.OfferedContracts.Count) { if (BoardClickPressed()) { VoteNextRank(); } else if (Input.GetKeyDown((KeyCode)49) || ControllerRankPressed(1)) { Vote(1); } else if (Input.GetKeyDown((KeyCode)50) || ControllerRankPressed(2)) { Vote(2); } else if (Input.GetKeyDown((KeyCode)51) || ControllerRankPressed(3)) { Vote(3); } if (Input.GetKeyDown(Plugin.ContractBoardLockKey.Value)) { Plugin.Manager.HostLockQueueFromVotes(); } } } private void Vote(int rank) { if (queue != null) { string localPlayerId = GetLocalPlayerId(); string definitionId = queue.OfferedContracts[highlightedIndex].DefinitionId; if (Plugin.Manager.CastVote(localPlayerId, rank, definitionId)) { RebuildBoardText(); Plugin.Manager.TryAutoLockQueueFromVotes(); } } } private void VoteNextRank() { if (queue == null || highlightedIndex < 0 || highlightedIndex >= queue.OfferedContracts.Count) { return; } string localPlayerId = GetLocalPlayerId(); Plugin.Manager.PlayerVotes.TryGetValue(localPlayerId, out string[] value); string definitionId = queue.OfferedContracts[highlightedIndex].DefinitionId; if (value != null) { int num = Array.IndexOf(value, definitionId); if (num >= 0) { Vote(num + 1); return; } } int num2 = ((value != null) ? Array.FindIndex(value, string.IsNullOrWhiteSpace) : 0); int rank = ((num2 < 0) ? 1 : (num2 + 1)); Vote(rank); } private void EnsureBoard() { //IL_003a: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00b2: 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_00a0: 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_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00e2: Expected O, but got Unknown //IL_00ed: Unknown result type (might be due to invalid IL or missing references) //IL_00fe: Unknown result type (might be due to invalid IL or missing references) //IL_010f: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_01a1: Unknown result type (might be due to invalid IL or missing references) //IL_01c0: Unknown result type (might be due to invalid IL or missing references) //IL_01e4: Unknown result type (might be due to invalid IL or missing references) //IL_0231: Unknown result type (might be due to invalid IL or missing references) //IL_0250: Unknown result type (might be due to invalid IL or missing references) //IL_0274: Unknown result type (might be due to invalid IL or missing references) //IL_02c1: Unknown result type (might be due to invalid IL or missing references) //IL_02e0: Unknown result type (might be due to invalid IL or missing references) //IL_0304: Unknown result type (might be due to invalid IL or missing references) //IL_0351: Unknown result type (might be due to invalid IL or missing references) //IL_0370: Unknown result type (might be due to invalid IL or missing references) //IL_0394: Unknown result type (might be due to invalid IL or missing references) //IL_03e1: Unknown result type (might be due to invalid IL or missing references) //IL_0400: Unknown result type (might be due to invalid IL or missing references) //IL_0424: Unknown result type (might be due to invalid IL or missing references) //IL_0471: Unknown result type (might be due to invalid IL or missing references) //IL_0490: Unknown result type (might be due to invalid IL or missing references) //IL_04b4: Unknown result type (might be due to invalid IL or missing references) //IL_050d: Unknown result type (might be due to invalid IL or missing references) //IL_052c: Unknown result type (might be due to invalid IL or missing references) //IL_0550: Unknown result type (might be due to invalid IL or missing references) //IL_0575: Unknown result type (might be due to invalid IL or missing references) //IL_0589: Unknown result type (might be due to invalid IL or missing references) //IL_05ae: Unknown result type (might be due to invalid IL or missing references) //IL_05c2: Unknown result type (might be due to invalid IL or missing references) //IL_05e7: Unknown result type (might be due to invalid IL or missing references) //IL_05fb: Unknown result type (might be due to invalid IL or missing references) //IL_0620: Unknown result type (might be due to invalid IL or missing references) //IL_0634: Unknown result type (might be due to invalid IL or missing references) //IL_0650: Unknown result type (might be due to invalid IL or missing references) //IL_066e: Unknown result type (might be due to invalid IL or missing references) //IL_068f: Unknown result type (might be due to invalid IL or missing references) //IL_06ad: Unknown result type (might be due to invalid IL or missing references) //IL_06ce: Unknown result type (might be due to invalid IL or missing references) //IL_06ec: Unknown result type (might be due to invalid IL or missing references) //IL_075e: Unknown result type (might be due to invalid IL or missing references) //IL_077d: Unknown result type (might be due to invalid IL or missing references) //IL_07c6: Unknown result type (might be due to invalid IL or missing references) //IL_07e4: Unknown result type (might be due to invalid IL or missing references) //IL_085b: Unknown result type (might be due to invalid IL or missing references) //IL_087a: Unknown result type (might be due to invalid IL or missing references) //IL_089e: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)boardRoot != (Object)null)) { GameObject val = FindTruckAnchor(); Vector3 position = (((Object)(object)val != (Object)null) ? (val.transform.position + val.transform.right * Plugin.BoardSideOffset.Value + val.transform.forward * Plugin.BoardForwardOffset.Value + Vector3.up * Plugin.BoardUpOffset.Value) : (Vector3.up * Plugin.BoardUpOffset.Value)); Quaternion rotation = (((Object)(object)val != (Object)null) ? Quaternion.Euler(0f, val.transform.eulerAngles.y + Plugin.BoardYawOffset.Value, 0f) : Quaternion.identity); boardRoot = new GameObject("Repo Contracts Board"); boardRoot.transform.position = position; boardRoot.transform.rotation = rotation; boardRoot.transform.localScale = Vector3.one * Plugin.BoardScale.Value; if ((Object)(object)((val != null) ? val.transform.parent : null) != (Object)null) { boardRoot.transform.SetParent(val.transform.parent, true); } readableSideSign = ResolveReadableSideSign(boardRoot.transform); GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "Repo Contracts Board Back"; obj.transform.SetParent(boardRoot.transform, false); obj.transform.localPosition = Vector3.zero; obj.transform.localScale = new Vector3(1.58f, 0.92f, 0.045f); DisablePhysicalCollider(obj); SetColor(obj, new Color(0.008f, 0.012f, 0.014f, 1f)); GameObject obj2 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj2).name = "Repo Contracts TV Bezel"; obj2.transform.SetParent(boardRoot.transform, false); obj2.transform.localPosition = new Vector3(0f, 0f, SurfaceZ(0.03f)); obj2.transform.localScale = new Vector3(1.68f, 1.02f, 0.035f); DisablePhysicalCollider(obj2); SetColor(obj2, new Color(0.02f, 0.022f, 0.024f, 1f)); GameObject obj3 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj3).name = "Repo Contracts TV Screen"; obj3.transform.SetParent(boardRoot.transform, false); obj3.transform.localPosition = new Vector3(0f, 0f, SurfaceZ(0.035f)); obj3.transform.localScale = new Vector3(1.5f, 0.82f, 0.018f); DisablePhysicalCollider(obj3); SetColor(obj3, new Color(0.006f, 0.035f, 0.04f, 1f)); GameObject obj4 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj4).name = "Repo Contracts Card Panel"; obj4.transform.SetParent(boardRoot.transform, false); obj4.transform.localPosition = new Vector3(-0.2f, -0.035f, SurfaceZ(0.07f)); obj4.transform.localScale = new Vector3(1.14f, 0.68f, 0.012f); DisablePhysicalCollider(obj4); SetColor(obj4, new Color(0.004f, 0.018f, 0.02f, 1f)); GameObject obj5 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj5).name = "Repo Contracts Accent Rail"; obj5.transform.SetParent(boardRoot.transform, false); obj5.transform.localPosition = new Vector3(-0.2f, 0.305f, SurfaceZ(0.118f)); obj5.transform.localScale = new Vector3(1.16f, 0.012f, 0.01f); DisablePhysicalCollider(obj5); SetColor(obj5, new Color(0.18f, 0.62f, 0.52f, 1f)); GameObject obj6 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj6).name = "Repo Contracts TV Glow"; obj6.transform.SetParent(boardRoot.transform, false); obj6.transform.localPosition = new Vector3(0f, 0f, SurfaceZ(0.052f)); obj6.transform.localScale = new Vector3(1.38f, 0.68f, 0.01f); DisablePhysicalCollider(obj6); SetColor(obj6, new Color(0.006f, 0.035f, 0.035f, 0.55f)); float num = SurfaceZ(0.13f); GameObject obj7 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj7).name = "Repo Contracts Votes Panel"; obj7.transform.SetParent(boardRoot.transform, false); obj7.transform.localPosition = new Vector3(0.54f, -0.044f, SurfaceZ(0.122f)); obj7.transform.localScale = new Vector3(0.34f, 0.646f, 0.012f); DisablePhysicalCollider(obj7); SetColor(obj7, new Color(0.66f, 0.7f, 0.54f, 1f)); CreatePanelBorder("Votes Border Top", new Vector3(0.54f, 0.285f, SurfaceZ(0.136f)), new Vector3(0.36f, 0.008f, 0.01f)); CreatePanelBorder("Votes Border Bottom", new Vector3(0.54f, -0.373f, SurfaceZ(0.136f)), new Vector3(0.36f, 0.008f, 0.01f)); CreatePanelBorder("Votes Border Left", new Vector3(0.36f, -0.044f, SurfaceZ(0.136f)), new Vector3(0.008f, 0.646f, 0.01f)); CreatePanelBorder("Votes Border Right", new Vector3(0.72f, -0.044f, SurfaceZ(0.136f)), new Vector3(0.008f, 0.646f, 0.01f)); headerText = CreateText("Header", new Vector3(-0.68f, 0.365f, num), 0.009f, new Color(0.72f, 0.94f, 0.86f, 1f)); selectedText = CreateText("Selected", new Vector3(0.39f, 0.255f, num), 0.0058f, new Color(0.025f, 0.035f, 0.025f, 1f)); promptText = CreateText("Prompt", new Vector3(-0.68f, -0.36f, num), 0.0048f, new Color(0.72f, 0.94f, 0.72f, 1f)); for (int i = 0; i < 5; i++) { GameObject obj8 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj8).name = $"Repo Contracts Card {i + 1}"; obj8.transform.SetParent(boardRoot.transform, false); obj8.transform.localPosition = new Vector3(-0.18f, 0.22f - (float)i * 0.132f, SurfaceZ(0.108f)); obj8.transform.localScale = new Vector3(1.14f, 0.118f, 0.035f); MakeTriggerOnly(obj8); ContractBoardCard contractBoardCard = obj8.AddComponent<ContractBoardCard>(); contractBoardCard.Index = i; contractBoardCard.Text = CreateText($"CardText{i}", new Vector3(-0.69f, 0.253f - (float)i * 0.132f, num), 0.0049f, new Color(0.045f, 0.055f, 0.04f, 1f)); cards.Add(contractBoardCard); GameObject obj9 = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj9).name = $"Repo Contracts Row Separator {i + 1}"; obj9.transform.SetParent(boardRoot.transform, false); obj9.transform.localPosition = new Vector3(-0.18f, 0.154f - (float)i * 0.132f, SurfaceZ(0.136f)); obj9.transform.localScale = new Vector3(1.12f, 0.006f, 0.01f); DisablePhysicalCollider(obj9); SetColor(obj9, new Color(0.055f, 0.06f, 0.05f, 1f)); } } } private void CreatePanelBorder(string name, Vector3 localPosition, Vector3 localScale) { //IL_0034: 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_0060: Unknown result type (might be due to invalid IL or missing references) GameObject obj = GameObject.CreatePrimitive((PrimitiveType)3); ((Object)obj).name = "Repo Contracts " + name; obj.transform.SetParent(boardRoot.transform, false); obj.transform.localPosition = localPosition; obj.transform.localScale = localScale; DisablePhysicalCollider(obj); SetColor(obj, new Color(0.055f, 0.065f, 0.052f, 1f)); } private void UpdatePlacementMode() { if (Input.GetKeyDown((KeyCode)290)) { placementMode = !placementMode; Plugin.Log.LogInfo((object)(placementMode ? "[RepoContracts] Placement ON: Numpad 4/6 side, 8/2 forward, 7/9 up, 1/3 yaw, +/- scale, F9 save/exit." : "[RepoContracts] Placement OFF.")); RebuildBoardText(); SavePlacement(); } if (placementMode) { bool flag = false; float num = Mathf.Max(0.01f, Plugin.BoardNudgeStep.Value); float num2 = Mathf.Max(0.5f, Plugin.BoardRotateStep.Value); if (Input.GetKeyDown((KeyCode)260)) { ConfigEntry<float> boardSideOffset = Plugin.BoardSideOffset; boardSideOffset.Value -= num; flag = true; } if (Input.GetKeyDown((KeyCode)262)) { ConfigEntry<float> boardSideOffset2 = Plugin.BoardSideOffset; boardSideOffset2.Value += num; flag = true; } if (Input.GetKeyDown((KeyCode)258)) { ConfigEntry<float> boardForwardOffset = Plugin.BoardForwardOffset; boardForwardOffset.Value -= num; flag = true; } if (Input.GetKeyDown((KeyCode)264)) { ConfigEntry<float> boardForwardOffset2 = Plugin.BoardForwardOffset; boardForwardOffset2.Value += num; flag = true; } if (Input.GetKeyDown((KeyCode)263)) { ConfigEntry<float> boardUpOffset = Plugin.BoardUpOffset; boardUpOffset.Value += num; flag = true; } if (Input.GetKeyDown((KeyCode)265)) { ConfigEntry<float> boardUpOffset2 = Plugin.BoardUpOffset; boardUpOffset2.Value -= num; flag = true; } if (Input.GetKeyDown((KeyCode)257)) { ConfigEntry<float> boardYawOffset = Plugin.BoardYawOffset; boardYawOffset.Value -= num2; flag = true; } if (Input.GetKeyDown((KeyCode)259)) { ConfigEntry<float> boardYawOffset2 = Plugin.BoardYawOffset; boardYawOffset2.Value += num2; flag = true; } if (Input.GetKeyDown((KeyCode)270) || Input.GetKeyDown((KeyCode)61)) { ConfigEntry<float> boardScale = Plugin.BoardScale; boardScale.Value += 0.04f; flag = true; } if (Input.GetKeyDown((KeyCode)269) || Input.GetKeyDown((KeyCode)45)) { Plugin.BoardScale.Value = Mathf.Max(0.25f, Plugin.BoardScale.Value - 0.04f); flag = true; } if (flag) { RecreateBoard(); SavePlacement(); } } } private void ApplyPlacement() { //IL_003a: 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_0054: Unknown result type (might be due to invalid IL or missing references) //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0064: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_0078: Unknown result type (might be due to invalid IL or missing references) //IL_007d: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_001e: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00c6: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_00b4: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_0102: Unknown result type (might be due to invalid IL or missing references) //IL_0113: Unknown result type (might be due to invalid IL or missing references) //IL_0122: Unknown result type (might be due to invalid IL or missing references) if (!((Object)(object)boardRoot == (Object)null)) { GameObject val = FindTruckAnchor(); Vector3 position = (((Object)(object)val != (Object)null) ? (val.transform.position + val.transform.right * Plugin.BoardSideOffset.Value + val.transform.forward * Plugin.BoardForwardOffset.Value + Vector3.up * Plugin.BoardUpOffset.Value) : (Vector3.up * Plugin.BoardUpOffset.Value)); Quaternion rotation = (((Object)(object)val != (Object)null) ? Quaternion.Euler(0f, val.transform.eulerAngles.y + Plugin.BoardYawOffset.Value, 0f) : Quaternion.Euler(0f, Plugin.BoardYawOffset.Value, 0f)); boardRoot.transform.position = position; boardRoot.transform.rotation = rotation; boardRoot.transform.localScale = Vector3.one * Plugin.BoardScale.Value; } } private void RecreateBoard() { if ((Object)(object)boardRoot != (Object)null) { Object.Destroy((Object)(object)boardRoot); boardRoot = null; } cards.Clear(); headerText = null; selectedText = null; promptText = null; highlightedIndex = -1; EnsureBoard(); RebuildBoardText(); } private static void SavePlacement() { Plugin.SaveSettings(); Plugin.Log.LogInfo((object)("[RepoContracts] Board placement saved: " + $"SideOffset={Plugin.BoardSideOffset.Value:F2}, " + $"ForwardOffset={Plugin.BoardForwardOffset.Value:F2}, " + $"UpOffset={Plugin.BoardUpOffset.Value:F2}, " + $"YawOffset={Plugin.BoardYawOffset.Value:F1}, " + $"Scale={Plugin.BoardScale.Value:F2}")); } private void UpdateHighlight() { int num = -1; Transform val = (((Object)(object)PlayerController.instance != (Object)null && (Object)(object)PlayerController.instance.cameraGameObject != (Object)null) ? PlayerController.instance.cameraGameObject.transform : (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform : null)); if ((Object)(object)val != (Object)null && TryGetBoardAimIndex(val, out var index)) { num = index; } if (num != highlightedIndex) { highlightedIndex = num; RebuildBoardText(); } } private bool TryGetBoardAimIndex(Transform aim, out int index) { //IL_0028: 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) //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_008b: Unknown result type (might be due to invalid IL or missing references) //IL_008c: 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_00e0: Unknown result type (might be due to invalid IL or missing references) index = -1; if ((Object)(object)boardRoot == (Object)null || queue == null) { return false; } Plane val = default(Plane); ((Plane)(ref val))..ctor(boardRoot.transform.forward, boardRoot.transform.position); Ray val2 = default(Ray); ((Ray)(ref val2))..ctor(aim.position, aim.forward); float num = default(float); if (!((Plane)(ref val)).Raycast(val2, ref num) || num < 0f || num > 7f) { return false; } Vector3 val3 = boardRoot.transform.InverseTransformPoint(((Ray)(ref val2)).GetPoint(num)); if (val3.x < -0.78f || val3.x > 0.33f) { return false; } int num2 = Mathf.Min(queue.OfferedContracts.Count, cards.Count); for (int i = 0; i < num2; i++) { float num3 = 0.22f - (float)i * 0.132f; if (Mathf.Abs(val3.y - num3) <= 0.072f) { index = i; return true; } } return false; } private void UpdateControllerHighlight() { if (queue != null && queue.OfferedContracts.Count != 0 && !(Time.time < controllerMoveCooldownUntil)) { int num = 0; float axisRaw = Input.GetAxisRaw("Vertical"); if (axisRaw > 0.55f || Input.GetKeyDown((KeyCode)343)) { num = -1; } else if (axisRaw < -0.55f || Input.GetKeyDown((KeyCode)344)) { num = 1; } if (num != 0) { int count = queue.OfferedContracts.Count; highlightedIndex = ((highlightedIndex >= 0) ? ((highlightedIndex + num + count) % count) : 0); controllerMoveCooldownUntil = Time.time + 0.22f; RebuildBoardText(); } } } private static bool ControllerRankPressed(int rank) { return rank switch { 1 => Input.GetKeyDown((KeyCode)330) || SafeInputDown((InputKey)26), 2 => Input.GetKeyDown((KeyCode)331) || SafeInputDown((InputKey)27), 3 => Input.GetKeyDown((KeyCode)332) || SafeInputDown((InputKey)28), _ => false, }; } private static bool BoardClickPressed() { if (!Input.GetMouseButtonDown(0) && !Input.GetKeyDown((KeyCode)101) && !Input.GetKeyDown((KeyCode)13) && !Input.GetKeyDown((KeyCode)330)) { return SafeInputDown((InputKey)2); } return true; } private static bool SafeInputDown(InputKey key) { //IL_0000: Unknown result type (might be due to invalid IL or missing references) try { return SemiFunc.InputDown(key); } catch { return false; } } private void RebuildBoardText() { //IL_010c: Unknown result type (might be due to invalid IL or missing references) if (queue == null || (Object)(object)boardRoot == (Object)null) { return; } if ((Object)(object)headerText != (Object)null) { headerText.text = (queue.IsLocked ? "QUEUE LOCKED" : "CONTRACT BOARD"); } for (int i = 0; i < cards.Count; i++) { ContractBoardCard contractBoardCard = cards[i]; if ((Object)(object)contractBoardCard == (Object)null || (Object)(object)((Component)contractBoardCard).gameObject == (Object)null) { continue; } if (i >= queue.OfferedContracts.Count) { ((Component)contractBoardCard).gameObject.SetActive(false); continue; } ((Component)contractBoardCard).gameObject.SetActive(true); ContractInstance contractInstance = queue.OfferedContracts[i]; if (contractInstance == null || contractInstance.Definition == null) { if ((Object)(object)contractBoardCard.Text != (Object)null) { contractBoardCard.Text.text = $"{i + 1}. Contract unavailable"; } SetColor(((Component)contractBoardCard).gameObject, new Color(0.12f, 0.12f, 0.12f, 1f)); continue; } ContractDefinition definition = contractInstance.Definition; ApplyCardVisual(((Component)contractBoardCard).gameObject, definition.Rarity, i == highlightedIndex); if ((Object)(object)contractBoardCard.Text != (Object)null) { contractBoardCard.Text.text = BuildCardText(i, contractInstance); } } if ((Object)(object)selectedText != (Object)null) { selectedText.text = BuildVoteSummary(); } if ((Object)(object)promptText != (Object)null) { promptText.text = (placementMode ? "PLACE: numpad move/yaw, +/- scale, F9 save" : (queue.IsLocked ? "Press C for active contracts." : "Aim + click/interact vote. 1/2/3 rank.")); } } private string BuildVoteSummary() { if (queue == null) { return string.Empty; } string localPlayerId = GetLocalPlayerId(); Plugin.Manager.PlayerVotes.TryGetValue(localPlayerId, out string[] value); string text = "Priority\n"; for (int i = 0; i < Plugin.SelectedContractsPerLevel.Value; i++) { string definitionId = ((value != null && i < value.Length) ? value[i] : string.Empty); ContractInstance contractInstance = ((!string.IsNullOrWhiteSpace(definitionId)) ? queue.OfferedContracts.FirstOrDefault((ContractInstance c) => c.DefinitionId == definitionId) : null); text += string.Format("{0}. {1}\n", i + 1, (contractInstance?.Definition != null) ? VoteName(contractInstance.Definition.DisplayName) : "-"); } int num = ((!SemiFunc.IsMultiplayer() || PhotonNetwork.PlayerList == null) ? 1 : PhotonNetwork.PlayerList.Length); return text + $"{Plugin.Manager.PlayerVotes.Count}/{num} ready"; } private TextMesh CreateText(string name, Vector3 localPosition, float size, Color color) { //IL_000b: Unknown result type (might be due to invalid IL or missing references) //IL_0010: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0033: 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_0072: Unknown result type (might be due to invalid IL or missing references) GameObject val = new GameObject("Repo Contracts " + name); val.transform.SetParent(boardRoot.transform, false); val.transform.localPosition = localPosition; val.transform.localRotation = TextRotation(); TextMesh obj = val.AddComponent<TextMesh>(); obj.anchor = (TextAnchor)0; obj.alignment = (TextAlignment)0; obj.characterSize = size; obj.fontSize = 64; obj.text = string.Empty; ContractAssets.ApplyTextMaterial(obj, color); return obj; } private static string BuildCardText(int index, ContractInstance contract) { return $"{index + 1} {contract.Definition.DisplayName} {DifficultyLabel(contract.Definition.Rarity)} {RewardLabel(contract.RewardRoll)}\n" + BoardRuleLabel(contract); } private static string VoteName(string displayName) { return displayName switch { "High Value Quota" => "High Value", "No Truck Healing" => "No Healing", "No Damage Taken" => "No Damage", "Melee Kills Only" => "Melee", "Pressure Plates" => "Plates", "Fragile Delivery" => "Fragile", "Cursed Delivery" => "Cursed", _ => Shorten(displayName, 10), }; } private static string Shorten(string value, int maxLength) { if (string.IsNullOrWhiteSpace(value)) { return string.Empty; } if (value.Length <= maxLength) { return value; } return value.Substring(0, Mathf.Max(1, maxLength - 1)) + "."; } private static string DifficultyLabel(ContractRarity rarity) { return rarity switch { ContractRarity.Common => "EASY", ContractRarity.Uncommon => "MED", ContractRarity.Rare => "HARD", ContractRarity.Epic => "EPIC", ContractRarity.Legendary => "LEG", _ => rarity.ToString(), }; } private static string ProgressLabel(ContractInstance contract) { if (contract.Definition.ProgressHook != ContractHook.ExtractionValueChanged) { return $"Goal {contract.RequiredProgress}"; } return $"${contract.RequiredProgress:N0}"; } private static string BoardRuleLabel(ContractInstance contract) { switch (contract.Definition.Id) { case "clean_sweep": case "debt_collector": return "Extract " + ProgressLabel(contract); case "monster_hunter": return $"Kill {contract.RequiredProgress}"; case "melee_clause": return $"Melee kills {contract.RequiredProgress}"; case "glass_cargo": return "Extract fragile item"; case "cursed_loot": return "Extract cursed item; no player damage"; case "no_deaths": case "no_one_left_bent": return "Extract; no deaths"; case "no_damage": return "Extract; no damage"; case "limited_healing": return "Extract; no healing"; case "no_loud_tools": return "Extract; no guns"; case "pressure_plate_extraction": return "Secure plates"; default: return Shorten(contract.Definition.ShortDescription, 22); } } private static string RewardLabel(RewardRoll reward) { switch (reward.Kind) { case RewardKind.CashBonus: case RewardKind.MoneyBag: return $"+${reward.Amount:N0}"; case RewardKind.ShopItem: return "Shop item"; case RewardKind.Weapon: return "Weapon"; case RewardKind.UpgradeDiscount: return "Upgrade"; case RewardKind.SurpriseBox: return "Present"; case RewardKind.CosmeticToken: return "Cosmetic"; default: return Shorten(reward.PreviewText, 18); } } private static Color GetCardColor(ContractRarity rarity, bool highlighted) { //IL_0033: 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) //IL_0052: Unknown result type (might be due to invalid IL or missing references) //IL_0057: Unknown result type (might be due to invalid IL or missing references) //IL_006e: Unknown result type (might be due to invalid IL or missing references) //IL_0073: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_008f: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: 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_00c2: Unknown result type (might be due to invalid IL or missing references) //IL_00c7: Unknown result type (might be due to invalid IL or missing references) //IL_00cf: 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) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_00cd: Unknown result type (might be due to invalid IL or missing references) Color val = (Color)(rarity switch { ContractRarity.Common => new Color(0.46f, 0.58f, 0.42f, 1f), ContractRarity.Uncommon => new Color(0.58f, 0.54f, 0.36f, 1f), ContractRarity.Rare => new Color(0.62f, 0.43f, 0.34f, 1f), ContractRarity.Epic => new Color(0.5f, 0.38f, 0.58f, 1f), ContractRarity.Legendary => new Color(0.64f, 0.49f, 0.3f, 1f), _ => new Color(0.42f, 0.48f, 0.46f, 1f), }); if (!highlighted) { return val; } return Color.Lerp(val, Color.white, 0.18f); } private static void ApplyCardVisual(GameObject card, ContractRarity rarity, bool highlighted) { //IL_0003: Unknown result type (might be due to invalid IL or missing references) SetColor(card, GetCardColor(rarity, highlighted)); } private static GameObject? FindTruckAnchor() { if ((Object)(object)TruckSafetySpawnPoint.instance != (Object)null) { return ((Component)TruckSafetySpawnPoint.instance).gameObject; } if ((Object)(object)TruckHealer.instance != (Object)null) { return ((Component)TruckHealer.instance).gameObject; } if ((Object)(object)TruckScreenText.instance != (Object)null) { return ((Component)TruckScreenText.instance).gameObject; } return GameObject.Find("cctv") ?? GameObject.Find("cctv (1)"); } private float SurfaceZ(float depth) { return Mathf.Sign(readableSideSign) * Mathf.Abs(depth); } private Quaternion TextRotation() { //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) if (!(readableSideSign < 0f)) { return Quaternion.Euler(0f, 180f, 0f); } return Quaternion.identity; } private static float ResolveReadableSideSign(Transform boardTransform) { //IL_0075: Unknown result type (might be due to invalid IL or missing references) //IL_007a: Unknown result type (might be due to invalid IL or missing references) Transform val = (((Object)(object)PlayerController.instance != (Object)null && (Object)(object)PlayerController.instance.cameraGameObject != (Object)null) ? PlayerController.instance.cameraGameObject.transform : (((Object)(object)Camera.main != (Object)null) ? ((Component)Camera.main).transform : (((Object)(object)PlayerAvatar.instance != (Object)null) ? ((Component)PlayerAvatar.instance).transform : null))); if ((Object)(object)val == (Object)null) { return -1f; } if (!(boardTransform.InverseTransformPoint(val.position).z >= 0f)) { return -1f; } return 1f; } private static string GetLocalPlayerId() { if (!SemiFunc.IsMultiplayer() || PhotonNetwork.LocalPlayer == null) { return "singleplayer"; } return $"player-{PhotonNetwork.LocalPlayer.ActorNumber}"; } private static void SetColor(GameObject target, Color color) { //IL_0016: Unknown result type (might be due to invalid IL or missing references) Renderer component = target.GetComponent<Renderer>(); if ((Object)(object)component != (Object)null) { component.material.color = color; } } private static void DisablePhysicalCollider(GameObject target) { Collider component = target.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { Object.Destroy((Object)(object)component); } } private static void MakeTriggerOnly(GameObject target) { Collider component = target.GetComponent<Collider>(); if ((Object)(object)component != (Object)null) { component.isTrigger = true; } } private void LogBoard(string action) { if (Plugin.EnableDebugLogging.Value && queue != null) { Plugin.Log.LogInfo((object)$"[RepoContracts] Board UI {action}: {queue.OfferedContracts.Count} offers, {queue.SelectedContracts.Count} selected."); } } } internal sealed class ContractBoardCard : MonoBehaviour { internal int Index { get; set; } internal TextMesh? Text { get; set; } } internal sealed class ContractHud : MonoBehaviour { private ContractQueue? queue; private string notification = string.Empty; private float notificationUntil; private bool visible; private bool overlayOpen; private GameObject? trackedTarget; private string trackedTargetLabel = string.Empty; internal void ShowActive(ContractQueue contractQueue) { queue = contractQueue; visible = true; LogHud(); } internal void Hide() { visible = false; overlayOpen = false; notification = string.Empty; trackedTarget = null; trackedTargetLabel = string.Empty; } internal void SetTrackedTarget(GameObject? target, string label) { trackedTarget = target; trackedTargetLabel = label; } internal void NotifyComplete(ContractInstance contract) { ShowNotification("Contract Complete: " + contract.Definition.DisplayName); } internal void NotifyFailed(ContractInstance contract) { ShowNotification("Contract Failed: " + contract.Definition.DisplayName); } internal void NotifyNext(ContractInstance contract) { ShowNotification("Next Contract Active: " + contract.Definition.DisplayName); } internal void NotifyDiscipline(string message) { ShowNotification(message); } private void Update() { //IL_0005: Unknown result type (might be due to invalid IL or missing references) if (Input.GetKeyDown(Plugin.ContractHudKey.Value)) { overlayOpen = !overlayOpen; } } private void OnGUI() { //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0034: 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_0043: Unknown result type (might be due to invalid IL or missing references) //IL_004b: Expected O, but got Unknown //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_0062: Unknown result type (might be due to invalid IL or missing references) //IL_006a: Expected O, but got Unknown //IL_0074: 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_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0089: Expected O, but got Unknown //IL_00ab: Unknown result type (might be due to invalid IL or missing references) //IL_00c5: Unknown result type (might be due to invalid IL or missing references) //IL_0103: Unknown result type (might be due to invalid IL or missing references) if (!visible || !overlayOpen || queue == null) { DrawTrackedTarget(); DrawNotification(); return; } GUIStyle val = new GUIStyle(GUI.skin.label) { fontSize = 16, fontStyle = (FontStyle)1, wordWrap = false }; GUIStyle val2 = new GUIStyle(GUI.skin.label) { fontSize = 13, wordWrap = true }; GUIStyle val3 = new GUIStyle(GUI.skin.label) { fontSize = 12, wordWrap = false }; Rect rect = default(Rect); ((Rect)(ref rect))..ctor((float)Screen.width - 620f, 30f, 590f, 430f); DrawTexturedBox(rect, "ui/hud/ui_active_contract_hud_panel.png", new Color(0.65f, 1f, 0.95f, 0.78f)); GUILayout.BeginArea(new Rect(((Rect)(ref rect)).x + 20f, ((Rect)(ref rect)).y + 14f, ((Rect)(ref rect)).width - 40f, ((Rect)(ref rect)).height - 28f)); GUILayout.Label("Repo Contracts", val, Array.Empty<GUILayoutOption>()); if (Plugin.EnableDisciplineDebt.Value && queue.DisciplineDebt > 0) { GUILayout.Label(string.Format("Discipline Debt: {0} future reward{1} withheld", queue.DisciplineDebt, (queue.DisciplineDebt == 1) ? string.Empty : "s"), val2, Array.Empty<GUILayoutOption>()); } ContractInstance activeContract = queue.ActiveContract; if (activeContract == null) { GUILayout.Label(queue.IsLocked ? "No active contract." : "Vote at the truck contract board.", val2, Array.Empty<GUILayoutOption>()); } else { GUILayout.Label($"Active {queue.ActiveIndex + 1}/{queue.SelectedContracts.Count}: {activeContract.Definition.DisplayName}", val, Array.Empty<GUILayoutOption>()); GUILayout.Label(Shorten(activeContract.Definition.ObjectiveText, 92), val2, Array.Empty<GUILayoutOption>()); GUILayout.Label($"Progress: {activeContract.CurrentProgress}/{activeContract.RequiredProgress}", val2, Array.Empty<GUILayoutOption>()); GUILayout.Label("Failure: " + Shorten(activeContract.Definition.FailureText, 82), val2, Array.Empty<GUILayoutOption>()); GUILayout.Label("Reward: " + activeContract.RewardRoll.PreviewText, val2, Array.Empty<GUILayoutOption>()); string id = activeContract.Definition.Id; if ((id == "glass_cargo" || id == "cursed_loot") ? true : false) { string value; string text = ((activeContract.SelectedTargets.TryGetValue("targetName", out value) && !string.IsNullOrWhiteSpace(value)) ? value : "Random marked valuable"); GUILayout.Label("Target: " + text, val2, Array.Empty<GUILayoutOption>()); } } GUILayout.Space(8f); for (int i = 0; i < queue.SelectedContracts.Count; i++) { ContractInstance contractInstance = queue.SelectedContracts[i]; GUILayout.Label($"{i + 1}. {Shorten(contractInstance.Definition.DisplayName, 24)} - {contractInstance.Status}", val3, Array.Empty<GUILayoutOption>()); } GUILayout.EndArea(); DrawTrackedTarget(); DrawNotification(); } private void DrawNotification() { //IL_0094: Unknown result type (might be due to invalid IL or missing references) //IL_0096: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Unknown result type (might be due to invalid IL or missing references) if (!string.IsNullOrEmpty(notification) && !(Time.time >= notificationUntil)) { Rect rect = default(Rect); ((Rect)(ref rect))..ctor(((float)Screen.width - 520f) * 0.5f, 80f, 520f, 70f); string asset = (notification.Contains("Failed") ? "ui/banners/ui_banner_contract_failed.png" : (notification.Contains("Complete") ? "ui/banners/ui_banner_contract_complete.png" : (notification.Contains("Reward") ? "ui/banners/ui_banner_reward_earned.png" : "ui/warnings/ui_warning_timer_critical.png"))); DrawTexturedBox(rect, asset, Color.white); GUILayout.BeginArea(new Rect(((Rect)(ref rect)).x + 28f, ((Rect)(ref rect)).y + 18f, ((Rect)(ref rect)).width - 56f, ((Rect)(ref rect)).height - 28f)); GUILayout.Label(notification, Array.Empty<GUILayoutOption>()); GUILayout.EndArea(); } } private void DrawTrackedTarget() { //IL_008e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_009d: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) //IL_00a7: 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) //IL_00aa: Unknown result type (might be due to invalid IL or missing references) //IL_00af: Unknown result type (might be due to invalid IL or missing references) //IL_00b0: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Unknown result type (might be due to invalid IL or missing references) //IL_00dc: Unknown result type (might be due to invalid IL or missing references) //IL_00f1: Unknown result type (might be due to invalid IL or missing references) //IL_012c: Unknown result type (might be due to invalid IL or missing references) //IL_014a: Unknown result type (might be due to invalid IL or missing references) //IL_0169: Unknown result type (might be due to invalid IL or missing references) //IL_0179: Unknown result type (might be due to invalid IL or missing references) //IL_00fb: Unknown result type (might be due to invalid IL or missing references) //IL_010c: 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_01d1: Unknown result type (might be due to invalid IL or missing references) //IL_01ea: Unknown result type (might be due to invalid IL or missing references) //IL_0215: Unknown result type (might be due to invalid IL or missing references) //IL_0253: Unknown result type (might be due to invalid IL or missing references) ContractInstance contractInstance = queue?.ActiveContract; bool flag = !visible || (Object)(object)trackedTarget == (Object)null; if (!flag) { string text = contractInstance?.Definition.Id; bool flag2 = ((text == "glass_cargo" || text == "cursed_loot") ? true : false); flag = !flag2; } if (flag) { return; } Camera main = Camera.main; if (!((Object)(object)main == (Object)null)) { Vector3 val = trackedTarget.transform.position + Vector3.up * 0.6f; Vector3 val2 = main.WorldToScreenPoint(val); bool num = val2.z < 0f; if (num) { val2.x = (float)Screen.width - val2.x; val2.y = (float)Screen.height - val2.y; } float num2 = 48f; bool flag3 = num || val2.x < num2 || val2.x > (float)Screen.width - num2 || val2.y < num2 || val2.y > (float)Screen.height - num2; float num3 = Mathf.Clamp(val2.x, num2, (float)Screen.width - num2); float num4 = Mathf.Clamp((float)Screen.height - val2.y, num2, (float)Screen.height - num2); float num5 = Vector3.Distance(((Component)main).transform.position, trackedTarget.transform.position); string arg = (string.IsNullOrWhiteSpace(trackedTargetLabel) ? contractInstance.Definition.DisplayName.ToUpperInvariant() : trackedTargetLabel); string arg2 = ((contractInstance.Definition.Id == "cursed_loot") ? "CURSED TARGET" : "MARKED TARGET"); Color color = GUI.color; GUI.color = new Color(0.2f, 1f, 0.9f, 0.95f); GUI.Box(new Rect(((float)Screen.width - 320f) * 0.5f, 132f, 320f, 54f), $"{arg2}\n{arg} - {Mathf.RoundToInt(num5)}m"); GUI.Box(new Rect(num3 - 105f, num4 - 26f, 210f, 52f), string.Format("{0}\n{1} - {2}m", flag3 ? "TARGET" : "MARKED", arg, Mathf.RoundToInt(num5))); GUI.color = color; } } private void ShowNotification(string message) { notification = message; notificationUntil = Time.time + 4f; if (Plugin.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)("[RepoContracts] HUD notification: " + message)); } } private static void DrawTexturedBox(Rect rect, string asset, Color tint) { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0026: Unknown result type (might be due to invalid IL or missing references) //IL_0015: 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) Texture2D val = ContractAssets.Texture(asset); Color color = GUI.color; if ((Object)(object)val != (Object)null) { GUI.color = tint; GUI.DrawTexture(rect, (Texture)(object)val, (ScaleMode)0, true); } else { GUI.Box(rect, GUIContent.none); } GUI.color = color; } private static string Shorten(string value, int maxLength) { if (string.IsNullOrWhiteSpace(value) || value.Length <= maxLength) { return value ?? string.Empty; } return value.Substring(0, Mathf.Max(1, maxLength - 1)) + "."; } private void LogHud() { if (Plugin.EnableDebugLogging.Value && visible && queue != null) { ContractInstance activeContract = queue.ActiveContract; if (activeContract == null) { Plugin.Log.LogInfo((object)"[RepoContracts] HUD ready: no active contract."); } else { Plugin.Log.LogInfo((object)($"[RepoContracts] HUD active {queue.ActiveIndex + 1}/{queue.SelectedContracts.Count}: " + $"{activeContract.Definition.DisplayName} {activeContract.CurrentProgress}/{activeContract.RequiredProgress}. " + "Reward: " + activeContract.RewardRoll.PreviewText)); } } } } } namespace RepoContracts.Rewards { internal sealed class RewardAdapter { private static readonly FieldInfo? DollarOverrideField = typeof(ValuableObject).GetField("dollarValueOverride", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic); internal void Grant(RewardRoll reward, Vector3 position, RewardDeliveryContext context) { //IL_0059: Unknown result type (might be due to invalid IL or missing references) //IL_0158: 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_00ae: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0115: Unknown result type (might be due to invalid IL or missing references) //IL_001a: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_012f: Unknown result type (might be due to invalid IL or missing references) //IL_00a5: Unknown result type (might be due to invalid IL or missing references) //IL_00da: Unknown result type (might be due to invalid IL or missing references) //IL_010c: Unknown result type (might be due to invalid IL or missing references) if (!SemiFunc.IsMasterClientOrSingleplayer()) { return; } if (!context.CashRewardsUsable && IsCashReward(reward)) { GrantNonCashSubstitute(reward, position, context); return; } switch (reward.Kind) { case RewardKind.CashBonus: case RewardKind.MoneyBag: SpawnMoneyBag(position, Mathf.RoundToInt((float)reward.Amount * Plugin.RewardMultiplier.Value)); break; case RewardKind.ShopItem: if (!TrySpawnShopItemReward(reward, position, IsGeneralShopReward, "shop item")) { GrantFallback(reward, position, context); } break; case RewardKind.Weapon: if (!TrySpawnShopItemReward(reward, position, IsWeaponReward, "weapon")) { GrantFallback(reward, position, context); } break; case RewardKind.UpgradeDiscount: if (!TrySpawnShopItemReward(reward, position, IsUpgradeReward, "upgrade")) { GrantFallback(reward, position, context); } break; case RewardKind.SurpriseBox: if (!TrySpawnSurpriseReward(reward, position)) { GrantFallback(reward, position, context); } break; case RewardKind.CosmeticToken: if (!TryGrantCosmeticToken(reward)) { GrantFallback(reward, position, context); } break; case RewardKind.SpawnableValuable: case RewardKind.ContractRerollToken: Plugin.Log.LogWarning((object)$"[RepoContracts] Reward adapter TODO: {reward.Kind} is modeled but not safely implemented yet."); GrantFallback(reward, position, context); break; default: Plugin.Log.LogWarning((object)$"[RepoContracts] Unknown reward kind {reward.Kind}."); break; } } private static bool IsCashReward(RewardRoll reward) { RewardKind kind = reward.Kind; if ((uint)kind <= 1u) { return true; } return false; } private static void GrantNonCashSubstitute(RewardRoll reward, Vector3 position, RewardDeliveryContext context) { //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0063: Unknown result type (might be due to invalid IL or missing references) Plugin.Log.LogInfo((object)("[RepoContracts] Cash reward converted because cash is unsafe now (" + context.Reason + ").")); if (!TrySpawnShopItemReward(reward, position, IsGeneralShopReward, "shop item substitute") && !TryGrantCosmeticToken(reward)) { Plugin.Log.LogWarning((object)"[RepoContracts] Non-cash substitute failed; spawning money bag as last-resort fallback."); SpawnFallbackMoneyBag(reward, position); } } private static void GrantFallback(RewardRoll reward, Vector3 position, RewardDeliveryContext context) { //IL_000a: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) if (context.CashRewardsUsable) { SpawnFallbackMoneyBag(reward, position); return; } if (TryGrantCosmeticToken(reward)) { Plugin.Log.LogInfo((object)("[RepoContracts] Granted cosmetic token fallback because cash is unsafe now (" + context.Reason + ").")); return; } Plugin.Log.LogWarning((object)"[RepoContracts] Cash-unsafe fallback had no cosmetic path; spawning money bag as last resort."); SpawnFallbackMoneyBag(reward, position); } private static void SpawnMoneyBag(Vector3 position, int amount) { //IL_0082: 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_0065: Unknown result type (might be due to invalid IL or missing references) //IL_0066: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)AssetManager.instance == (Object)null || (Object)(object)AssetManager.instance.surplusValuableSmall == (Object)null) { Plugin.Log.LogWarning((object)"[RepoContracts] Money bag reward unavailable: AssetManager.surplusValuableSmall was not found."); return; } GameObject surplusValuableSmall = AssetManager.instance.surplusValuableSmall; int num = Mathf.Max(1000, Mathf.RoundToInt(Mathf.Round((float)amount / 100f) * 100f)); ValuableObject component = (SemiFunc.IsMultiplayer() ? PhotonNetwork.InstantiateRoomObject("Valuables/" + ((Object)surplusValuableSmall).name, position, Quaternion.identity, (byte)0, (object[])null) : Object.Instantiate<GameObject>(surplusValuableSmall, position, Quaternion.identity)).GetComponent<ValuableObject>(); if ((Object)(object)component != (Object)null) { DollarOverrideField?.SetValue(component, num); } Plugin.Log.LogInfo((object)$"[RepoContracts] Spawned contract money bag reward ${num}."); } private static void SpawnFallbackMoneyBag(RewardRoll reward, Vector3 position) { //IL_0019: Unknown result type (might be due to invalid IL or missing references) int num = ((reward.Amount > 0) ? reward.Amount : 2500); SpawnMoneyBag(position, Mathf.RoundToInt((float)num * Plugin.RewardMultiplier.Value)); } private static bool TrySpawnShopItemReward(RewardRoll reward, Vector3 position, Func<Item, bool> predicate, string label) { //IL_0072: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)StatsManager.instance == (Object)null || StatsManager.instance.itemDictionary == null) { Plugin.Log.LogWarning((object)("[RepoContracts] " + label + " reward unavailable: StatsManager item dictionary was not ready.")); return false; } List<Item> eligibleItems = GetEligibleItems(predicate); if (eligibleItems.Count == 0) { Plugin.Log.LogWarning((object)("[RepoContracts] " + label + " reward unavailable: no eligible shop items were found.")); return false; } return TrySpawnItem(eligibleItems[Random.Range(0, eligibleItems.Count)], position, label); } private static bool TrySpawnSurpriseReward(RewardRoll reward, Vector3 position) { //IL_0066: Unknown result type (might be due to invalid IL or missing references) //IL_011e: Unknown result type (might be due to invalid IL or missing references) //IL_011f: 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) if ((Object)(object)StatsManager.instance == (Object)null || StatsManager.instance.itemDictionary == null) { Plugin.Log.LogWarning((object)"[RepoContracts] surprise reward unavailable: StatsManager item dictionary was not ready."); return false; } List<Item> eligibleItems = GetEligibleItems(IsPresentBoxReward); if (eligibleItems.Count > 0) { return TrySpawnItem(eligibleItems[Random.Range(0, eligibleItems.Count)], position, "surprise present"); } List<Item> eligibleItems2 = GetEligibleItems(IsGeneralShopReward); if (eligibleItems2.Count == 0) { Plugin.Log.LogWarning((object)"[RepoContracts] surprise reward unavailable: no eligible bundle items were found."); return false; } int num; switch (reward.Rarity) { case ContractRarity.Epic: case ContractRarity.Legendary: num = 3; break; case ContractRarity.Rare: num = 2; break; default: num = 2; break; } int num2 = num; bool flag = false; Vector3 val = default(Vector3); for (int i = 0; i < num2; i++) { Item selected = eligibleItems2[Random.Range(0, eligibleItems2.Count)]; ((Vector3)(ref val))..ctor(((float)i - (float)(num2 - 1) * 0.5f) * 0.55f, 0f, Random.Range(-0.25f, 0.25f)); flag |= TrySpawnItem(selected, position + val, "surprise bundle item"); } return flag; } private static List<Item> GetEligibleItems(Func<Item, bool> predicate) { Func<Item, bool> predicate2 = predicate; return StatsManager.instance.itemDictionary.Values.Where((Item item) => (Object)(object)item != (Object)null && !item.disabled && item.physicalItem && item.prefab != null && item.prefab.IsValid() && predicate2(item)).ToList(); } private static bool TrySpawnItem(Item selected, Vector3 position, string label) { //IL_0000: 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_0010: 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_0038: Unknown result type (might be due to invalid IL or missing references) //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) Quaternion val = Quaternion.identity * selected.spawnRotationOffset; try { if ((Object)(object)(SemiFunc.IsMultiplayer() ? PhotonNetwork.InstantiateRoomObject(selected.prefab.ResourcePath, position, val, (byte)0, (object[])null) : Object.Instantiate<GameObject>(selected.prefab.Prefab, position, val)) == (Object)null) { Plugin.Log.LogWarning((object)("[RepoContracts] " + label + " reward failed to spawn: " + selected.itemName + ".")); return false; } Plugin.Log.LogInfo((object)("[RepoContracts] Spawned contract " + label + " reward: " + selected.itemName + ".")); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[RepoContracts] " + label + " reward failed to spawn " + selected.itemName + ": " + ex.Message)); return false; } } private static bool TryGrantCosmeticToken(RewardRoll reward) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)MetaManager.instance == (Object)null) { Plugin.Log.LogWarning((object)"[RepoContracts] Cosmetic token reward unavailable: MetaManager was not ready."); return false; } try { MetaManager.instance.CosmeticTokenAdd(ToGameRarity(reward.Rarity)); Plugin.Log.LogInfo((object)$"[RepoContracts] Granted contract cosmetic token reward: {reward.Rarity}."); return true; } catch (Exception ex) { Plugin.Log.LogWarning((object)("[RepoContracts] Cosmetic token reward failed: " + ex.Message)); return false; } } private static bool IsGeneralShopReward(Item item) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Expected I4, but got Unknown itemType itemType = item.itemType; switch ((int)itemType) { case 0: case 1: case 2: case 5: case 6: case 7: case 9: case 10: case 11: case 12: case 13: case 14: case 15: return true; default: return false; } } private static bool IsWeaponReward(Item item) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_0027: Expected I4, but got Unknown //IL_0027: Unknown result type (might be due to invalid IL or missing references) //IL_002a: Invalid comparison between Unknown and I4 itemType itemType = item.itemType; switch (itemType - 6) { default: if ((int)itemType != 15) { break; } goto case 0; case 0: case 1: case 3: case 5: return true; case 2: case 4: break; } return false; } private static bool IsUpgradeReward(Item item) { //IL_0001: Unknown result type (might be due to invalid IL or missing references) //IL_0006: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0009: Unknown result type (might be due to invalid IL or missing references) //IL_000b: Invalid comparison between Unknown and I4 itemType itemType = item.itemType; if (itemType - 3 <= 1) { return true; } return false; } private static bool IsPresentBoxReward(Item item) { string[] obj = new string[5] { item.itemName, " ", ((Object)item).name, " ", null }; PrefabRef prefab = item.prefab; obj[4] = ((prefab != null) ? prefab.ResourcePath : null); string text = string.Concat(obj).ToLowerInvariant(); if (!text.Contains("present") && !text.Contains("gift") && !text.Contains("surprise") && !text.Contains("package") && !text.Contains("crate")) { return text.Contains("box"); } return true; } private static Rarity ToGameRarity(ContractRarity rarity) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0025: 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) //IL_002d: Unknown result type (might be due to invalid IL or missing references) //IL_0032: 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) return (Rarity)(rarity switch { ContractRarity.Common => 0, ContractRarity.Uncommon => 1, ContractRarity.Rare => 2, ContractRarity.Epic => 3, ContractRarity.Legendary => 3, _ => 0, }); } } internal readonly struct RewardDeliveryContext { internal bool CashRewardsUsable { get; } internal string Reason { get; } private RewardDeliveryContext(bool cashRewardsUsable, string reason) { CashRewardsUsable = cashRewardsUsable; Reason = reason; } internal static RewardDeliveryContext Normal() { return new RewardDeliveryContext(cashRewardsUsable: true, "normal"); } internal static RewardDeliveryContext CashUnsafe(string reason) { return new RewardDeliveryContext(cashRewardsUsable: false, reason); } } } namespace RepoContracts.Networking { internal sealed class ContractSyncAdapter { internal readonly struct ContractSnapshot { internal static readonly ContractSnapshot Empty = new ContractSnapshot(Array.Empty<ContractInstance>(), Array.Empty<ContractInstance>(), -1, isLocked: false, 0, string.Empty); internal IReadOnlyList<ContractInstance> Offers { get; } internal IReadOnlyList<ContractInstance> Selected { get; } internal int ActiveIndex { get; } internal bool IsLocked { get; } internal int DisciplineDebt { get; } internal string VoteSessionId { get; } internal ContractSnapshot(IReadOnlyList<ContractInstance> offers, IReadOnlyList<ContractInstance> selected, int activeIndex, bool isLocked, int disciplineDebt, string voteSessionId) { Offers = offers; Selected = selected; ActiveIndex = activeIndex; IsLocked = isLocked; DisciplineDebt = disciplineDebt; VoteSessionId = voteSessionId; } } private const string StateKey = "RepoContracts.State"; private const string RevisionKey = "RepoContracts.Revision"; private int revision; internal void SyncOffers(ContractQueue queue) { Publish("offers", queue); } internal void SyncSelection(ContractQueue queue) { Publish("selection", queue); } internal void SyncLockedQueue(ContractQueue queue) { Publish("locked queue", queue); } internal void SyncVotes(ContractQueue queue, IReadOnlyDictionary<string, string[]> votes) { Publish("votes", queue); if (Plugin.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)$"[RepoContracts] Synced votes players={votes.Count}, offers={queue.OfferedContracts.Count}."); } } internal void SyncProgress(ContractQueue queue) { Publish("progress", queue); } internal void SyncCleared() { //IL_0016: Unknown result type (might be due to invalid IL or missing references) //IL_0021: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Unknown result type (might be due to invalid IL or missing references) //IL_0046: Expected O, but got Unknown if (CanPublish()) { revision++; Hashtable val = new Hashtable { [(object)"RepoContracts.State"] = string.Empty, [(object)"RepoContracts.Revision"] = revision }; PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); if (Plugin.EnableDebugLogging.Value) { Plugin.Log.LogInfo((object)"[RepoContracts] Synced cleared contract state."); } } } internal bool TryReadSnapshot(ref int lastRevision, out string snapshot) { snapshot = string.Empty; if (SemiFunc.IsMultiplayer()) { Room currentRoom = PhotonNetwork.CurrentRoom; if (((currentRoom != null) ? ((RoomInfo)currentRoom).CustomProperties : null) != null) { if (!((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"RepoContracts.Revision", out object value) || !(value is int num)) { return false; } if (num == lastRevision) { return false; } lastRevision = num; if (((Dictionary<object, object>)(object)((RoomInfo)PhotonNetwork.CurrentRoom).CustomProperties).TryGetValue((object)"RepoContracts.State", out object value2) && value2 is string text) { snapshot = text; } return true; } } return false; } internal string Serialize(ContractQueue queue) { string text = string.Join(",", queue.OfferedContracts.Select((ContractInstance c) => Escape(c.DefinitionId))); string text2 = string.Join("^", queue.SelectedContracts.Select(SerializeContract)); return string.Join("|", "v1", queue.IsLocked ? "1" : "0", queue.ActiveIndex.ToString(), text, text2, queue.DisciplineDebt.ToString(), Escape(queue.VoteSessionId)); } internal bool TryDeserialize(string snapshot, IReadOnlyList<ContractDefinition> catalog, out ContractSnapshot result) { result = ContractSnapshot.Empty; if (string.IsNullOrWhiteSpace(snapshot)) { return true; } string[] array = snapshot.Split('|'); if (array.Length < 5 || array[0] != "v1") { return false; } bool isLocked = array[1] == "1"; int.TryParse(array[2], out var result2); List<ContractInstance> list = new List<ContractInstance>(); foreach (string id in SplitList(array[3], ',')) { ContractDefinition contractDefinition = catalog.FirstOrDefault((ContractDefinition c) => c.Id == Unescape(id)); if (contractDefinition != null) { list.Add(new ContractInstance(contractDefinition, 0)); } } List<ContractInstance> list2 = new List<ContractInstance>(); foreach (string item in SplitList(array[4], '^')) { ContractInstance contractInstance = DeserializeContract(item, catalog); if (contractInstance != null) { list2.Add(contractInstance); } } int result3 = 0; if (array.Length > 5) { int.TryParse(array[5], out result3); } string voteSessionId = ((array.Length > 6) ? Unescape(array[6]) : string.Empty); result = new ContractSnapshot(list, list2, result2, isLocked, result3, voteSessionId); return true; } private void Publish(string label, ContractQueue queue) { //IL_001d: Unknown result type (might be due to invalid IL or missing references) //IL_0028: 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_004f: Expected O, but got Unknown if (!CanPublish()) { LogLocal(label, queue); return; } revision++; Hashtable val = new Hashtable { [(object)"RepoContracts.State"] = Serialize(queue), [(object)"RepoContracts.Revision"] = revision }; PhotonNetwork.CurrentRoom.SetCustomProperties(val, (Hashtable)null, (WebFlags)null); LogLocal(label, queue); } private static bool CanPublish() { if (SemiFunc.IsMultiplayer() && SemiFunc.IsMasterClientOrSingleplayer()) { return PhotonNetwork.CurrentRoom != null; } return false; } private static void LogLocal(string stateName, ContractQueue queue) { if (Plugin.EnableDebugLogging.Value) { string text = (CanPublish() ? "Synced" : "Local"); Plugin.Log.LogInfo((object)string.Format("[RepoContracts] {0} {1}: offered={2}, selected={3}, active={4}.", text, stateName, queue.OfferedContracts.Count, queue.SelectedContracts.Count, queue.ActiveContract?.Definition.DisplayName ?? "none")); } } private static string SerializeContract(ContractInstance contract) { string value = string.Join(";", contract.SelectedTargets.Select<KeyValuePair<string, string>, string>((KeyValuePair<string, string> kv) => Escape(kv.Key) + "=" + Escape(kv.Value))); return string.Join("~", Escape(contract.DefinitionId), ((int)contract.Status).ToString(), contract.CurrentProgress.ToString(), contract.RequiredProgress.ToString(), Escape(contract.FailureReason), Escape(value), contract.RewardRoll.Amount.ToString(), Escape(contract.RewardRoll.PreviewText), ((int)contract.RewardRoll.Kind).ToString(), Escape(contract.RewardRoll.RewardId)); } private static ContractInstance? DeserializeContract(string data, IReadOnlyList<ContractDefinition> catalog) { string[] array = data.Split('~'); if (array.Length < 4) { return null; } string definitionId = Unescape(array[0]); ContractDefinition contractDefinition = catalog.FirstOrDefault((ContractDefinition c) => c.Id == definitionId); if (contractDefinition == null) { return null; } ContractInstance contractInstance = new ContractInstance(contractDefinition, 0); if (int.TryParse(array[1], out var result)) { contractInstance.SetStatus((ContractStatus)result); } int.TryParse(array[2], out var result2); int.TryParse(array[3], out var result3); contractInstance.SetProgress(result2, result3); if (array.Length > 4) { contractInstance.SetFailureReason(Unescape(array[4])); } if (array.Length > 5) { foreach (string item in SplitList(Unescape(array[5]), ';')) { int num = item.IndexOf('='); if (num > 0) { Dictionary<string, string> selectedTargets = contractInstance.SelectedTargets; string key = Unescape(item.Substring(0, num)); string text = item; int num2 = num + 1; selectedTargets[key] = Unescape(text.Substring(num2, text.Length - num2)); } } } if (array.Length > 6 && int.TryParse(array[6], out var result4) && result4 > 0) { string previewText = ((array.Length > 7) ? Unescape(array[7]) : contractInstance.RewardRoll.PreviewText); RewardKind kind = contractInstance.RewardRoll.Kind; if (array.Length > 8 && int.TryParse(array[8], out var result5) && Enum.IsDefined(typeof(RewardKind), result5)) { kind = (RewardKind)result5; } string rewardId = ((array.Length > 9) ? Unescape(array[9]) : contractInstance.RewardRoll.RewardId); contractInstance.SetRewardRoll(new RewardRoll(kind, contractInstance.RewardRoll.Rarity, result4, rewardId, previewText)); } return contractInstance; } private static IEnumerable<string> SplitList(string value, char separator) { if (!string.IsNullOrWhiteSpace(value)) { return from v in value.Split(separator) where !string.IsNullOrWhiteSpace(v) select v; } return