using System;
using System.Collections.Generic;
using System.IO;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using UnityEngine;
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: AssemblyVersion("0.0.0.0")]
namespace PricingExporter;
[BepInPlugin("RB007.plugins.PricingExporter", "PricingExporter", "1.0.0")]
public class PricingExporterPlugin : BaseUnityPlugin
{
private struct PricingEntry
{
public int productID;
public string displayName;
public string brand;
public int productTier;
public float unitCost;
public float sellPrice;
public float margin;
public float recommendedPrice;
}
private const string GUID = "RB007.plugins.PricingExporter";
private const string PluginName = "PricingExporter";
private const string VersionString = "1.0.0";
public static ConfigEntry<KeyCode> exportKey;
public static ConfigEntry<float> targetMarginPercent;
private void Awake()
{
//IL_0052: Unknown result type (might be due to invalid IL or missing references)
exportKey = ((BaseUnityPlugin)this).Config.Bind<KeyCode>("Settings", "Export Key", (KeyCode)289, "按下这个键会把当前所有在售商品的定价导出为 CSV 文件。");
targetMarginPercent = ((BaseUnityPlugin)this).Config.Bind<float>("Settings", "Target Margin Percent", 20f, "计算推荐售价时,在进货成本基础上增加的百分比利润。");
Debug.Log((object)string.Concat("[PricingExporter] Loaded successfully! Press ", exportKey.Value, " in-game to export pricing."));
}
private void Update()
{
//IL_0005: Unknown result type (might be due to invalid IL or missing references)
if (Input.GetKeyDown(exportKey.Value))
{
ExportPricingToCsv();
}
}
private void ExportPricingToCsv()
{
ProductListing val = Object.FindFirstObjectByType<ProductListing>();
if ((Object)(object)val == (Object)null)
{
Debug.LogWarning((object)"[PricingExporter] 尚未进入游戏存档,无法导出定价。");
ShowNotification("StockPlus导出: 请先进入游戏存档");
return;
}
try
{
List<PricingEntry> list = ComputePricingEntries(val);
StringBuilder stringBuilder = new StringBuilder();
stringBuilder.AppendLine("商品ID,商品名称,品牌,产品等级,进货成本,当前售价,当前盈亏,状态,推荐不亏本售价(成本+" + targetMarginPercent.Value + "%)");
foreach (PricingEntry item in list)
{
string text = ((!(item.margin < 0f)) ? "盈利" : "亏本");
stringBuilder.AppendLine(item.productID + "," + CsvEscape(item.displayName) + "," + CsvEscape(item.brand) + "," + item.productTier + "," + item.unitCost.ToString("F2") + "," + item.sellPrice.ToString("F2") + "," + item.margin.ToString("F2") + "," + text + "," + item.recommendedPrice.ToString("F2"));
}
string text2 = Path.Combine(Paths.GameRootPath, "StockPlus_Exports");
Directory.CreateDirectory(text2);
string path = "定价表_" + DateTime.Now.ToString("yyyyMMdd_HHmmss") + ".csv";
string text3 = Path.Combine(text2, path);
File.WriteAllText(text3, stringBuilder.ToString(), new UTF8Encoding(encoderShouldEmitUTF8Identifier: true));
Debug.Log((object)("[PricingExporter] 已导出 " + list.Count + " 件商品 -> " + text3));
ShowNotification("已导出 " + list.Count + " 件商品定价表");
}
catch (Exception ex)
{
Debug.LogError((object)("[PricingExporter] 导出失败: " + ex));
ShowNotification("StockPlus导出失败,详见日志");
}
}
private List<PricingEntry> ComputePricingEntries(ProductListing plisting)
{
List<PricingEntry> list = new List<PricingEntry>();
Type nestedType = typeof(ProductListing).GetNestedType("ProductData", BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo field = typeof(ProductListing).GetField("productsData", BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
FieldInfo field2 = nestedType.GetField("productTier");
FieldInfo field3 = nestedType.GetField("basePricePerUnit");
FieldInfo field4 = nestedType.GetField("productBrand");
Array array = (Array)field.GetValue(plisting);
foreach (int availableProduct in plisting.availableProducts)
{
if (availableProduct < 0 || availableProduct >= array.Length)
{
continue;
}
object value = array.GetValue(availableProduct);
if (value == null)
{
continue;
}
int num = (int)field2.GetValue(value);
if (!plisting.unlockedProductTiers[num])
{
continue;
}
float num2 = (float)field3.GetValue(value);
string brand = ((!(field4 != null)) ? "" : ((string)field4.GetValue(value)));
float num3 = num2 * plisting.tierInflation[num];
float num4 = ((availableProduct >= plisting.productPlayerPricing.Length) ? 0f : plisting.productPlayerPricing[availableProduct]);
float margin = num4 - num3;
float num5 = num3 * (1f + targetMarginPercent.Value / 100f);
num5 = Mathf.Round(num5 * 100f) / 100f;
string displayName = "商品 #" + availableProduct;
if ((Object)(object)LocalizationManager.instance != (Object)null)
{
string localizationString = LocalizationManager.instance.GetLocalizationString("product" + availableProduct);
if (!string.IsNullOrEmpty(localizationString))
{
displayName = localizationString;
}
}
list.Add(new PricingEntry
{
productID = availableProduct,
displayName = displayName,
brand = brand,
productTier = num,
unitCost = num3,
sellPrice = num4,
margin = margin,
recommendedPrice = num5
});
}
return list;
}
private static string CsvEscape(string value)
{
if (string.IsNullOrEmpty(value))
{
return "\"\"";
}
return "\"" + value.Replace("\"", "\"\"") + "\"";
}
private static void ShowNotification(string message)
{
try
{
if ((Object)(object)GameCanvas.Instance != (Object)null)
{
GameCanvas.Instance.CreateCanvasNotification(message);
}
}
catch
{
}
}
}