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 FairShare v1.0.0
FairShare.dll
Decompiled 20 hours agousing System; using System.Collections.Generic; using System.Diagnostics; using System.IO; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using BepInEx; using BepInEx.Configuration; using Microsoft.CodeAnalysis; using On.RoR2; using R2API; using RoR2; using UnityEngine; using UnityEngine.Events; using UnityEngine.Networking; [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("FairShare")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+4f1aaccd70f98eafb26ffba818f3b21607794682")] [assembly: AssemblyProduct("FairShare")] [assembly: AssemblyTitle("FairShare")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } } namespace FairShare { [BepInPlugin("com.creeper2002.fairshare", "FairShare", "0.4.1")] [BepInProcess("Risk of Rain 2.exe")] public sealed class Plugin : BaseUnityPlugin { public const string Guid = "com.creeper2002.fairshare"; public const string Name = "FairShare"; public const string Version = "0.4.1"; internal static ConfigEntry<int> DeadZone; internal static ConfigEntry<float> PercentPerItem; internal static ConfigEntry<float> MinCostPercent; internal static ConfigEntry<float> MaxCostPercent; internal static ConfigEntry<bool> DebugLogging; private static int temporaryDisplayCostDepth; internal static ArtifactDef FairShareArtifact; private void Awake() { //IL_00b9: Unknown result type (might be due to invalid IL or missing references) //IL_00c3: Expected O, but got Unknown //IL_00ca: Unknown result type (might be due to invalid IL or missing references) //IL_00d4: Expected O, but got Unknown //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e5: Expected O, but got Unknown DeadZone = ((BaseUnityPlugin)this).Config.Bind<int>("Scaling", "ItemsBeforeScaling", 5, "Inventory difference from the living-player average ignored before scaling begins."); PercentPerItem = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "PercentPerItem", 5f, "Percent price change per item beyond the dead zone."); MinCostPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "MinimumCostPercent", 50f, "Lowest allowed personal money price as a percentage of normal cost."); MaxCostPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Scaling", "MaximumCostPercent", 200f, "Highest allowed personal money price as a percentage of normal cost."); DebugLogging = ((BaseUnityPlugin)this).Config.Bind<bool>("Debug", "LogPurchases", false, "Log FairShare purchase calculations for troubleshooting."); RegisterArtifact(); PurchaseInteraction.GetContextString += new hook_GetContextString(PurchaseInteraction_GetContextString); PurchaseInteraction.GetInteractability += new hook_GetInteractability(PurchaseInteraction_GetInteractability); PurchaseInteraction.OnInteractionBegin += new hook_OnInteractionBegin(PurchaseInteraction_OnInteractionBegin); ((BaseUnityPlugin)this).Logger.LogInfo((object)"FairShare 0.4.1 loaded. Personal multiplayer money pricing is available through the Artifact of Fair Share."); } private void OnDestroy() { //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_0011: Expected O, but got Unknown //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Expected O, but got Unknown //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_0033: Expected O, but got Unknown PurchaseInteraction.GetContextString -= new hook_GetContextString(PurchaseInteraction_GetContextString); PurchaseInteraction.GetInteractability -= new hook_GetInteractability(PurchaseInteraction_GetInteractability); PurchaseInteraction.OnInteractionBegin -= new hook_OnInteractionBegin(PurchaseInteraction_OnInteractionBegin); } private void RegisterArtifact() { //IL_002b: 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_0063: 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) Texture2D val = LoadEmbeddedTexture("FairShare.artifact_fairshare.png"); Texture2D val2 = CreateDeselectedTexture(val); Sprite smallIconSelectedSprite = Sprite.Create(val, new Rect(0f, 0f, (float)((Texture)val).width, (float)((Texture)val).height), new Vector2(0.5f, 0.5f), 100f); Sprite smallIconDeselectedSprite = Sprite.Create(val2, new Rect(0f, 0f, (float)((Texture)val2).width, (float)((Texture)val2).height), new Vector2(0.5f, 0.5f), 100f); FairShareArtifact = ScriptableObject.CreateInstance<ArtifactDef>(); FairShareArtifact.cachedName = "ArtifactOfFairShare"; FairShareArtifact.nameToken = "FAIRSHARE_ARTIFACT_NAME"; FairShareArtifact.descriptionToken = "FAIRSHARE_ARTIFACT_DESCRIPTION"; FairShareArtifact.smallIconSelectedSprite = smallIconSelectedSprite; FairShareArtifact.smallIconDeselectedSprite = smallIconDeselectedSprite; LanguageAPI.Add(FairShareArtifact.nameToken, "Artifact of Fair Share"); LanguageAPI.Add(FairShareArtifact.descriptionToken, "Those with more must pay more. Money prices scale with your item count relative to the living team average."); ContentAddition.AddArtifactDef(FairShareArtifact); } private static Texture2D LoadEmbeddedTexture(string resourceName) { //IL_0060: 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_006c: Expected O, but got Unknown //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Expected O, but got Unknown using Stream stream = typeof(Plugin).Assembly.GetManifestResourceStream(resourceName); if (stream == null) { throw new InvalidOperationException("Embedded artifact icon '" + resourceName + "' was not found."); } byte[] array = new byte[stream.Length]; int num; for (int i = 0; i < array.Length; i += num) { num = stream.Read(array, i, array.Length - i); if (num <= 0) { break; } } Texture2D val = new Texture2D(2, 2, (TextureFormat)4, false); if (!ImageConversion.LoadImage(val, array)) { throw new InvalidOperationException("Failed to load embedded Artifact of Fair Share icon."); } ((Object)val).name = "ArtifactOfFairShareIcon"; return val; } private static Texture2D CreateDeselectedTexture(Texture2D source) { //IL_000e: Unknown result type (might be due to invalid IL or missing references) //IL_0014: Expected O, but got Unknown //IL_0021: 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_0027: 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_0040: 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_0063: Unknown result type (might be due to invalid IL or missing references) //IL_0068: Unknown result type (might be due to invalid IL or missing references) Texture2D val = new Texture2D(((Texture)source).width, ((Texture)source).height, (TextureFormat)4, false); Color[] pixels = source.GetPixels(); for (int i = 0; i < pixels.Length; i++) { Color val2 = pixels[i]; float num = (val2.r * 0.299f + val2.g * 0.587f + val2.b * 0.114f) * 0.55f; pixels[i] = new Color(num, num, num, val2.a); } val.SetPixels(pixels); val.Apply(); ((Object)val).name = "ArtifactOfFairShareIconDeselected"; return val; } internal static bool IsFairShareEnabled() { if ((Object)(object)FairShareArtifact != (Object)null && (Object)(object)RunArtifactManager.instance != (Object)null) { return RunArtifactManager.instance.IsArtifactEnabled(FairShareArtifact); } return false; } private string PurchaseInteraction_GetContextString(orig_GetContextString orig, PurchaseInteraction self, Interactor activator) { if (!TryGetPersonalCost(self, activator, out var _, out var personalCost) || temporaryDisplayCostDepth > 0) { return orig.Invoke(self, activator); } int cost = self.cost; temporaryDisplayCostDepth++; try { self.cost = personalCost; return orig.Invoke(self, activator); } finally { self.cost = cost; temporaryDisplayCostDepth--; } } private Interactability PurchaseInteraction_GetInteractability(orig_GetInteractability orig, PurchaseInteraction self, Interactor activator) { //IL_0018: Unknown result type (might be due to invalid IL or missing references) //IL_0042: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Invalid comparison between Unknown and I4 //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_006b: 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_005c: Unknown result type (might be due to invalid IL or missing references) //IL_0062: Invalid comparison between Unknown and I4 //IL_0065: Unknown result type (might be due to invalid IL or missing references) if (!TryGetPersonalCost(self, activator, out var master, out var personalCost) || temporaryDisplayCostDepth > 0) { return orig.Invoke(self, activator); } int cost = self.cost; uint money = master.money; temporaryDisplayCostDepth++; try { self.cost = personalCost; Interactability val = orig.Invoke(self, activator); if ((int)val != 2 && money < (uint)personalCost) { master.money = (uint)personalCost; if ((int)orig.Invoke(self, activator) == 2) { return (Interactability)2; } } return val; } finally { master.money = money; self.cost = cost; temporaryDisplayCostDepth--; } } private void PurchaseInteraction_OnInteractionBegin(orig_OnInteractionBegin orig, PurchaseInteraction self, Interactor activator) { if (!NetworkServer.active || !TryGetPersonalCost(self, activator, out var master, out var personalCost)) { orig.Invoke(self, activator); return; } int num = Math.Max(0, self.cost); uint money = master.money; if (DebugLogging.Value) { int rawItemCount = GetRawItemCount(master); float averageItemCount = GetAverageItemCount(); float personalMultiplier = GetPersonalMultiplier(master); ((BaseUnityPlugin)this).Logger.LogInfo((object)($"Purchase attempt: base=${num}, personal=${personalCost}, money=${money}, " + $"items={rawItemCount}, living average={averageItemCount:0.##}, multiplier={personalMultiplier:0.###}x")); } if (money < (uint)personalCost) { if (DebugLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)"Purchase rejected by FairShare: player cannot afford their personal price."); } return; } if (personalCost == num) { orig.Invoke(self, activator); return; } long val = money + num - personalCost; uint money2 = (uint)Math.Max(0L, Math.Min(4294967295L, val)); bool purchaseCompleted = false; UnityAction<Interactor> val2 = delegate { purchaseCompleted = true; }; ((UnityEvent<Interactor>)(object)self.onPurchase).AddListener(val2); master.money = money2; try { orig.Invoke(self, activator); } finally { ((UnityEvent<Interactor>)(object)self.onPurchase).RemoveListener(val2); if (!purchaseCompleted) { master.money = money; } } if (DebugLogging.Value) { ((BaseUnityPlugin)this).Logger.LogInfo((object)(purchaseCompleted ? $"FairShare purchase completed. Remaining money=${master.money}." : "Vanilla did not complete the purchase; temporary money adjustment was restored.")); } } internal static bool TryGetPersonalCost(PurchaseInteraction interaction, Interactor activator, out CharacterMaster master, out int personalCost) { //IL_003b: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Invalid comparison between Unknown and I4 master = GetMaster(activator); personalCost = (((Object)(object)interaction != (Object)null) ? interaction.cost : 0); if (!IsFairShareEnabled()) { return false; } if ((Object)(object)interaction == (Object)null || (Object)(object)master == (Object)null) { return false; } if ((int)interaction.costType != 1) { return false; } if (GetEligibleMasters().Count <= 1) { return false; } personalCost = GetPersonalMoneyCost(interaction.cost, master); return true; } internal static CharacterMaster GetMaster(Interactor activator) { if ((Object)(object)activator == (Object)null) { return null; } CharacterBody component = ((Component)activator).GetComponent<CharacterBody>(); if (!((Object)(object)component != (Object)null)) { return null; } return component.master; } internal unsafe static int GetRawItemCount(CharacterMaster master) { //IL_0020: 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_002a: Unknown result type (might be due to invalid IL or missing references) //IL_002f: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0049: Unknown result type (might be due to invalid IL or missing references) //IL_004f: Invalid comparison between Unknown and I4 //IL_0059: Unknown result type (might be due to invalid IL or missing references) if ((Object)(object)master == (Object)null || (Object)(object)master.inventory == (Object)null) { return 0; } int num = 0; AllItemsEnumerator enumerator = ItemCatalog.allItems.GetEnumerator(); try { while (((AllItemsEnumerator)(ref enumerator)).MoveNext()) { ItemIndex current = ((AllItemsEnumerator)(ref enumerator)).Current; ItemDef itemDef = ItemCatalog.GetItemDef(current); if (!((Object)(object)itemDef == (Object)null) && !itemDef.hidden && (int)itemDef.tier != 5) { num += Math.Max(0, master.inventory.GetItemCountPermanent(current)); } } return num; } finally { ((IDisposable)(*(AllItemsEnumerator*)(&enumerator))/*cast due to .constrained prefix*/).Dispose(); } } internal static List<CharacterMaster> GetEligibleMasters() { return CharacterMaster.readOnlyInstancesList.Where((CharacterMaster m) => (Object)(object)m != (Object)null && (Object)(object)m.playerCharacterMasterController != (Object)null && (Object)(object)m.inventory != (Object)null && (Object)(object)m.GetBody() != (Object)null).ToList(); } internal static float GetAverageItemCount() { List<CharacterMaster> eligibleMasters = GetEligibleMasters(); if (eligibleMasters.Count == 0) { return 0f; } return (float)((IEnumerable<CharacterMaster>)eligibleMasters).Average((Func<CharacterMaster, int>)GetRawItemCount); } internal static float GetPersonalMultiplier(CharacterMaster master) { if ((Object)(object)master == (Object)null) { return 1f; } List<CharacterMaster> eligibleMasters = GetEligibleMasters(); if (eligibleMasters.Count <= 1) { return 1f; } float num = (float)((IEnumerable<CharacterMaster>)eligibleMasters).Average((Func<CharacterMaster, int>)GetRawItemCount); float num2 = (float)GetRawItemCount(master) - num; int num3 = Math.Max(0, DeadZone.Value); float num4 = 0f; if (num2 > (float)num3) { num4 = num2 - (float)num3; } else if (num2 < (float)(-num3)) { num4 = num2 + (float)num3; } float val = 1f + num4 * (PercentPerItem.Value / 100f); float val2 = Math.Max(0f, MinCostPercent.Value / 100f); float val3 = Math.Max(val2, MaxCostPercent.Value / 100f); return Math.Max(val2, Math.Min(val3, val)); } internal static int GetPersonalMoneyCost(int baseCost, CharacterMaster buyer) { if (baseCost <= 0) { return Math.Max(0, baseCost); } double value = (double)baseCost * (double)GetPersonalMultiplier(buyer); return Math.Max(1, (int)Math.Round(value, MidpointRounding.AwayFromZero)); } } }