using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
using System.Runtime.Versioning;
using BepInEx;
using BepInEx.Configuration;
using HarmonyLib;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.Default | DebuggableAttribute.DebuggingModes.DisableOptimizations | DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints | DebuggableAttribute.DebuggingModes.EnableEditAndContinue)]
[assembly: AssemblyTitle("ProfitPercent")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("ProfitPercent")]
[assembly: AssemblyCopyright("Copyright © 2024")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("1aa9f185-5e80-46e0-935b-a30791a11860")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.8", FrameworkDisplayName = ".NET Framework 4.8")]
[assembly: AssemblyVersion("1.0.0.0")]
namespace ProfitPercent;
[BepInPlugin("pr0skynesis.profitpercent", "Profit Percent", "1.2.1")]
public class ProfitPercentMain : BaseUnityPlugin
{
public const string pluginGuid = "pr0skynesis.profitpercent";
public const string pluginName = "Profit Percent";
public const string pluginVersion = "1.2.1";
public static ConfigEntry<bool> coloredTextConfig;
public static ConfigEntry<int> greenThresholdConfig;
public static ConfigEntry<int> blueThresholdConfig;
public static ConfigEntry<bool> showBestDealsConfig;
public static ConfigEntry<bool> autoReceiptConfig;
public void Awake()
{
//IL_0006: Unknown result type (might be due to invalid IL or missing references)
//IL_000c: Expected O, but got Unknown
//IL_003d: Unknown result type (might be due to invalid IL or missing references)
//IL_004b: Expected O, but got Unknown
//IL_0080: Unknown result type (might be due to invalid IL or missing references)
//IL_008d: Expected O, but got Unknown
//IL_00c3: Unknown result type (might be due to invalid IL or missing references)
//IL_00d1: Expected O, but got Unknown
Harmony val = new Harmony("pr0skynesis.profitpercent");
MethodInfo methodInfo = AccessTools.Method(typeof(EconomyUI), "Awake", (Type[])null, (Type[])null);
MethodInfo methodInfo2 = AccessTools.Method(typeof(ProfitPercentPatches), "AwakePatch", (Type[])null, (Type[])null);
val.Patch((MethodBase)methodInfo, new HarmonyMethod(methodInfo2), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo3 = AccessTools.Method(typeof(EconomyUI), "ShowGoodPage", (Type[])null, (Type[])null);
MethodInfo methodInfo4 = AccessTools.Method(typeof(ProfitPercentPatches), "MainPatch", (Type[])null, (Type[])null);
val.Patch((MethodBase)methodInfo3, (HarmonyMethod)null, new HarmonyMethod(methodInfo4), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
MethodInfo methodInfo5 = AccessTools.Method(typeof(EconomyUIButton), "OnActivate", (Type[])null, (Type[])null);
MethodInfo methodInfo6 = AccessTools.Method(typeof(ProfitPercentPatches), "ButtonPatch", (Type[])null, (Type[])null);
val.Patch((MethodBase)methodInfo5, new HarmonyMethod(methodInfo6), (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null, (HarmonyMethod)null);
coloredTextConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("A) Colored text", "coloredText", true, "Enables the coloring of the profit in red (loss), green (profit), yellow (neither) and blue (high profit)");
greenThresholdConfig = ((BaseUnityPlugin)this).Config.Bind<int>("A) Colored text", "greenThreshold", 0, "Sets the value above which the profit % will be colored in green. E.g.: set to 30 to have the text be displayed as green only above 30% profit.");
blueThresholdConfig = ((BaseUnityPlugin)this).Config.Bind<int>("A) Colored text", "blueThreshold", 100, "Sets the value above which the profit % will be colored in blue, used to identify high profit margins.");
showBestDealsConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("B) Best Deals", "showBestDeals", true, "Display the best deals from the current port to the destinations in the currently selected bookmark. Set to false to disable.");
autoReceiptConfig = ((BaseUnityPlugin)this).Config.Bind<bool>("C) Automatic Receipts", "autoReceipts", true, "Get the receipt automatically when closing the trade book, if one is available. Set to false to disable.");
}
}
public class ProfitPercentPatches
{
private static TextMesh productionText = new TextMesh();
private static TextMesh percentText = new TextMesh();
private static TextMesh perPoundText = new TextMesh();
private static TextMesh highlightBar = new TextMesh();
private static TextMesh islandNames;
private static TextMesh buyColumn;
private static TextMesh goodName;
private static TextMesh sellColumn;
private static TextMesh header;
private static TextMesh profitColumn;
private static TextMesh daysAgo;
private static TextMesh tabLines;
private static TextMesh horizontalLine;
private static TextMesh conversionFees;
private static TextMesh bdBestDeals = new TextMesh();
private static TextMesh bdPercent = new TextMesh();
private static TextMesh bdPerPound = new TextMesh();
private static TextMesh bdAbsolute = new TextMesh();
private static MethodInfo buypInfo;
private static MethodInfo sellpInfo;
private static Good[] goods;
public static Dictionary<int, float[]> portProd = new Dictionary<int, float[]>();
private const float charSize = 0.8f;
private const float spacing = 0.073f;
private static float[] goodWeights;
private static string[] goodNames;
public static void AwakePatch(EconomyUI __instance)
{
buypInfo = AccessTools.Method(typeof(EconomyUI), "GetBuyPrice", (Type[])null, (Type[])null);
sellpInfo = AccessTools.Method(typeof(EconomyUI), "GetSellPrice", (Type[])null, (Type[])null);
Transform detailsUI = ((Component)__instance).transform.Find("good details (right panel)").Find("details UI");
GetVanillaColumns(detailsUI);
AddModColumns(detailsUI);
DisableUnusedUI(detailsUI);
InitializeProd();
}
public static void MainPatch(int[][] ___bookmarkIslands, int ___currentBookmark, IslandMarket ___currentIsland)
{
goodName.text = Capitalize(goodName.text);
InitializeUI();
if (goods == null)
{
InitializeGoods();
}
for (int i = 0; i < ___bookmarkIslands[___currentBookmark].Length; i++)
{
int num = ___bookmarkIslands[___currentBookmark][i];
int currentSelectedGood = EconomyUI.instance.currentSelectedGood;
if (num == ___currentIsland.GetPortIndex())
{
SetHighlightBar(i);
}
if (ProfitPercentMain.showBestDealsConfig.Value)
{
bdBestDeals.text = "<color=#4D0000>★ Best Deals! ★</color>";
FindBestDeals(___bookmarkIslands, ___currentBookmark, ___currentIsland);
}
else
{
bdBestDeals.text = "";
bdPercent.text = "";
bdPerPound.text = "";
bdAbsolute.text = "";
}
GetProduction(num, currentSelectedGood);
if (___currentIsland.knownPrices[num] == null || ___currentIsland.knownPrices[num].buyPrices == null)
{
if (num == ___currentIsland.GetPortIndex())
{
if (ProfitPercentMain.coloredTextConfig.Value)
{
TextMesh obj = islandNames;
obj.text = obj.text + "<color=#4D0000>• " + Port.ports[num].GetPortName() + "</color>\n";
}
else
{
TextMesh obj2 = islandNames;
obj2.text = obj2.text + "• " + Port.ports[num].GetPortName() + "\n";
}
}
else
{
TextMesh obj3 = islandNames;
obj3.text = obj3.text + Port.ports[num].GetPortName() + "\n";
}
TextMesh obj4 = profitColumn;
obj4.text += "?\n";
TextMesh obj5 = percentText;
obj5.text += "?\n";
TextMesh obj6 = perPoundText;
obj6.text += "?\n";
continue;
}
int num2 = BuyP(___currentIsland.GetPortIndex(), currentSelectedGood);
int num3 = SellP(num, currentSelectedGood);
int num4 = num3 - num2;
float num5 = Mathf.Round((float)num4 / (float)num2 * 100f);
float num6 = goodWeights[currentSelectedGood];
float num7 = (float)Math.Round((float)num4 / num6, 2);
if (ProfitPercentMain.coloredTextConfig.Value)
{
if (num == ___currentIsland.GetPortIndex())
{
TextMesh obj7 = islandNames;
obj7.text = obj7.text + "<color=#4D0000>• " + Port.ports[num].GetPortName() + "</color>\n";
}
else
{
TextMesh obj8 = islandNames;
obj8.text = obj8.text + Port.ports[num].GetPortName() + "\n";
}
int value = ProfitPercentMain.blueThresholdConfig.Value;
int value2 = ProfitPercentMain.greenThresholdConfig.Value;
if (ProfitPercentMain.blueThresholdConfig.Value < ProfitPercentMain.greenThresholdConfig.Value)
{
value = ProfitPercentMain.greenThresholdConfig.Value;
value2 = ProfitPercentMain.blueThresholdConfig.Value;
}
if (float.IsInfinity(num5))
{
TextMesh obj9 = profitColumn;
obj9.text += "<color=#CC7F00>- </color>\n";
TextMesh obj10 = percentText;
obj10.text += "<color=#CC7F00>- </color>\n";
TextMesh obj11 = perPoundText;
obj11.text += "<color=#CC7F00>- </color>\n";
}
else if (num5 > (float)value)
{
TextMesh obj12 = profitColumn;
obj12.text += $"<color=#051139>{num4}</color>\n";
TextMesh obj13 = percentText;
obj13.text += $"<color=#051139>{num5}<size=40%>%</size></color>\n";
TextMesh obj14 = perPoundText;
obj14.text += $"<color=#051139>{num7}</color>\n";
}
else if (num5 > (float)value2)
{
TextMesh obj15 = profitColumn;
obj15.text += $"<color=#003300>{num4}</color>\n";
TextMesh obj16 = percentText;
obj16.text += $"<color=#003300>{num5}<size=40%>%</size></color>\n";
TextMesh obj17 = perPoundText;
obj17.text += $"<color=#003300>{num7}</color>\n";
}
else if (num5 < 0f)
{
TextMesh obj18 = profitColumn;
obj18.text += $"<color=#4D0000>{num4}</color>\n";
TextMesh obj19 = percentText;
obj19.text += $"<color=#4D0000>{num5}<size=40%>%</size></color>\n";
TextMesh obj20 = perPoundText;
obj20.text += $"<color=#4D0000>{num7}</color>\n";
}
else
{
TextMesh obj21 = profitColumn;
obj21.text += $"<color=#CC7F00>{num4}</color>\n";
TextMesh obj22 = percentText;
obj22.text += $"<color=#CC7F00>{num5}<size=40%>%</size></color>\n";
TextMesh obj23 = perPoundText;
obj23.text += $"<color=#CC7F00>{num7}</color>\n";
}
}
else
{
if (num == ___currentIsland.GetPortIndex())
{
TextMesh obj24 = islandNames;
obj24.text = obj24.text + "• " + Port.ports[num].GetPortName() + "\n";
}
else
{
TextMesh obj25 = islandNames;
obj25.text = obj25.text + Port.ports[num].GetPortName() + "\n";
}
if (float.IsInfinity(num5))
{
TextMesh obj26 = profitColumn;
obj26.text += "- \n";
TextMesh obj27 = percentText;
obj27.text += "- \n";
TextMesh obj28 = perPoundText;
obj28.text += "- \n";
}
else
{
TextMesh obj29 = profitColumn;
obj29.text += $"{num4}\n";
TextMesh obj30 = percentText;
obj30.text += $"{num5}<size=40%>%</size>\n";
TextMesh obj31 = perPoundText;
obj31.text += $"{num7}\n";
}
}
}
}
public static void ButtonPatch(EconomyUIButton __instance)
{
if (((Object)__instance).name == "bookmark_button_X" && ProfitPercentMain.autoReceiptConfig.Value && EconomyUIReceiptScribe.instance.ReceiptAvailable())
{
EconomyUI.instance.PrintReceipt();
}
}
private static void GetVanillaColumns(Transform detailsUI)
{
islandNames = ((Component)detailsUI.GetChild(2)).GetComponent<TextMesh>();
islandNames.characterSize = 0.8f;
Move(((Component)islandNames).transform, 0.23f);
buyColumn = ((Component)detailsUI.GetChild(3)).GetComponent<TextMesh>();
buyColumn.characterSize = 0.8f;
Move(((Component)buyColumn).transform, -0.11f);
goodName = ((Component)detailsUI.GetChild(6)).GetComponent<TextMesh>();
sellColumn = ((Component)detailsUI.GetChild(7)).GetComponent<TextMesh>();
sellColumn.characterSize = 0.8f;
Move(((Component)sellColumn).transform, -0.27f);
header = ((Component)detailsUI.GetChild(8)).GetComponent<TextMesh>();
header.characterSize = 0.85f;
header.text = "days ago P. buy sell profit % p. pound";
profitColumn = ((Component)detailsUI.GetChild(9)).GetComponent<TextMesh>();
profitColumn.characterSize = 0.8f;
Move(((Component)profitColumn).transform, -0.45f);
daysAgo = ((Component)detailsUI.GetChild(11)).GetComponent<TextMesh>();
daysAgo.characterSize = 0.8f;
Move(((Component)daysAgo).transform, 0.133f);
tabLines = ((Component)detailsUI.GetChild(13)).GetComponent<TextMesh>();
tabLines.text = " | | | | | |";
horizontalLine = ((Component)detailsUI.GetChild(14)).GetComponent<TextMesh>();
Move(((Component)horizontalLine).transform, -0.94f);
conversionFees = ((Component)detailsUI.GetChild(16)).GetComponent<TextMesh>();
conversionFees.characterSize = 0.8f;
Move(((Component)conversionFees).transform, 0.64f, -0.8f);
}
private static void AddModColumns(Transform detailsUI)
{
//IL_02eb: Unknown result type (might be due to invalid IL or missing references)
productionText = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)productionText).name = "productionText";
productionText.characterSize = 0.8f;
Move(((Component)productionText).transform, 0.05f);
percentText = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)percentText).name = "percentText";
percentText.characterSize = 0.8f;
Move(((Component)percentText).transform, -0.61f);
perPoundText = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)perPoundText).name = "perPoundText";
perPoundText.characterSize = 0.8f;
Move(((Component)perPoundText).transform, -0.78f);
bdBestDeals = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)bdBestDeals).name = "bdBestDeals";
bdBestDeals.characterSize = 1f;
bdBestDeals.text = "<color=#4D0000>★ Best Deals! ★</color>";
((Component)bdBestDeals).transform.Rotate(0f, 0f, 15f);
Move(((Component)bdBestDeals).transform, 0.74f, -0.15f);
bdBestDeals.anchor = (TextAnchor)3;
bdPercent = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)bdPercent).name = "bdPercent";
bdPercent.characterSize = 0.7f;
bdPercent.text = "Salmon from here to there will give X in profit";
Move(((Component)bdPercent).transform, 0.64f, -0.2f);
bdPercent.anchor = (TextAnchor)3;
bdPerPound = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)bdPerPound).name = "bdPerPound";
bdPerPound.characterSize = 0.7f;
bdPerPound.text = "Salmon from here to there will give X in profit";
Move(((Component)bdPerPound).transform, 0.64f, -0.25f);
bdPerPound.anchor = (TextAnchor)3;
bdAbsolute = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)bdAbsolute).name = "bdAbsolute";
bdAbsolute.characterSize = 0.7f;
bdAbsolute.text = "Salmon from here to there will give X in profit";
Move(((Component)bdAbsolute).transform, 0.64f, -0.3f);
bdAbsolute.anchor = (TextAnchor)3;
highlightBar = Object.Instantiate<TextMesh>(buyColumn, detailsUI);
((Object)highlightBar).name = "highlightBar";
highlightBar.characterSize = 1f;
highlightBar.text = "┌───────────────────────────────────┐\n└───────────────────────────────────┘";
highlightBar.lineSpacing = 0.9f;
highlightBar.color = new Color(0.25f, 0f, 0f);
Move(((Component)highlightBar).transform, 0.64f, 0.622f);
highlightBar.anchor = (TextAnchor)3;
}
private static void DisableUnusedUI(Transform detailsUI)
{
((Component)detailsUI.Find("highlight (parent)")).gameObject.SetActive(false);
}
private static void InitializeUI()
{
islandNames.text = "";
productionText.text = "";
profitColumn.text = "";
perPoundText.text = "";
percentText.text = "";
((Component)highlightBar).gameObject.SetActive(false);
}
private static void InitializeProd()
{
Port[] array = Object.FindObjectsOfType<Port>();
Port[] array2 = array;
foreach (Port val in array2)
{
if (!((Object)(object)((Component)val).GetComponent<IslandMarket>() == (Object)null))
{
portProd.Add(val.portIndex, ((Component)val.island).GetComponent<IslandMarket>().production);
}
}
}
private static void InitializeGoods()
{
goods = (Good[])(object)new Good[portProd[0].Length];
goodNames = new string[portProd[0].Length];
goodWeights = new float[portProd[0].Length];
for (int i = 0; i < goods.Length; i++)
{
ShipItem good = PrefabsDirectory.instance.GetGood(i);
if (!((Object)(object)good == (Object)null))
{
goods[i] = ((Component)good).GetComponent<Good>();
goodNames[i] = good.name;
goodWeights[i] = goods[i].GetCargoWeight();
}
}
}
private static void SetHighlightBar(int i)
{
//IL_0035: Unknown result type (might be due to invalid IL or missing references)
((Component)highlightBar).gameObject.SetActive(true);
float y = 0.622f - 0.073f * (float)i;
Move(((Component)highlightBar).transform, ((Component)highlightBar).transform.localPosition.x, y);
}
private static void GetProduction(int portIndex, int goodIndex)
{
if (portProd[portIndex][goodIndex] >= 8f)
{
TextMesh obj = productionText;
obj.text += "★\n";
}
else if (portProd[portIndex][goodIndex] > 0f)
{
TextMesh obj2 = productionText;
obj2.text += "✓\n";
}
else if (portProd[portIndex][goodIndex] <= -5f)
{
TextMesh obj3 = productionText;
obj3.text += "‼\n";
}
else if (portProd[portIndex][goodIndex] <= 0f)
{
TextMesh obj4 = productionText;
obj4.text += "✗\n";
}
else
{
TextMesh obj5 = productionText;
obj5.text += "error\n";
}
}
private static int BuyP(int portIndex, int goodIndex)
{
object[] parameters = new object[2] { portIndex, goodIndex };
return (int)buypInfo.Invoke(EconomyUI.instance, parameters);
}
private static int SellP(int portIndex, int goodIndex)
{
object[] parameters = new object[2] { portIndex, goodIndex };
return (int)sellpInfo.Invoke(EconomyUI.instance, parameters);
}
private static void FindBestDeals(int[][] bookmark, int currentBookmark, IslandMarket currentMarket)
{
int num = int.MinValue;
float num2 = float.MinValue;
float num3 = float.MinValue;
int num4 = -1;
int num5 = -1;
int num6 = -1;
int num7 = -1;
int num8 = -1;
int num9 = -1;
int portIndex = currentMarket.GetPortIndex();
for (int i = 0; i < goods.Length; i++)
{
if ((Object)(object)goods[i] == (Object)null)
{
continue;
}
int num10 = BuyP(portIndex, i);
for (int j = 0; j < bookmark[currentBookmark].Length; j++)
{
int num11 = bookmark[currentBookmark][j];
if (currentMarket.knownPrices[num11] != null && currentMarket.knownPrices[num11].buyPrices != null)
{
int num12 = SellP(num11, i);
int num13 = ((num10 != 0) ? (num12 - num10) : int.MinValue);
float num14 = ((num10 != 0) ? Mathf.Round((float)num13 / (float)num10 * 100f) : float.MinValue);
float num15 = goodWeights[i];
float num16 = ((num10 != 0) ? ((float)Math.Round((float)num13 / num15, 2)) : float.MinValue);
if (num13 > num)
{
num = num13;
num4 = i;
num7 = num11;
}
if (num14 > num2)
{
num2 = num14;
num5 = i;
num8 = num11;
}
if (num16 > num3)
{
num3 = num16;
num6 = i;
num9 = num11;
}
}
}
}
bdPercent.text = $"• {Capitalize(goodNames[num5])} to {Port.ports[num8].GetPortName()} will return a profit of {num2}%!";
bdPerPound.text = $"• {Capitalize(goodNames[num6])} to {Port.ports[num9].GetPortName()} will return a profit of {num3} per pound!";
bdAbsolute.text = $"• {Capitalize(goodNames[num4])} to {Port.ports[num7].GetPortName()} will return a profit of {num} per unit!";
}
private static void Move(Transform transform, float x)
{
//IL_0002: 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_0011: Unknown result type (might be due to invalid IL or missing references)
Vector3 localPosition = transform.localPosition;
localPosition.x = x;
transform.localPosition = localPosition;
}
private static void Move(Transform transform, float x, float y)
{
//IL_0002: 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_0019: Unknown result type (might be due to invalid IL or missing references)
Vector3 localPosition = transform.localPosition;
localPosition.x = x;
localPosition.y = y;
transform.localPosition = localPosition;
}
private static string Capitalize(string s)
{
return char.ToUpper(s[0]) + s.Substring(1);
}
}