using 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 BepInEx.Unity.IL2CPP;
using HarmonyLib;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using Il2CppSystem;
using Il2CppSystem.Collections.Generic;
using Microsoft.CodeAnalysis;
using SOD.Common;
using SOD.Common.Extensions;
using SOD.Common.Helpers;
using UnityEngine;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: TargetFramework(".NETCoreApp,Version=v6.0", FrameworkDisplayName = "")]
[assembly: AssemblyCompany("BusinessAsUsual")]
[assembly: AssemblyConfiguration("Release")]
[assembly: AssemblyFileVersion("1.0.0.0")]
[assembly: AssemblyInformationalVersion("1.0.0")]
[assembly: AssemblyProduct("BusinessAsUsual")]
[assembly: AssemblyTitle("BusinessAsUsual")]
[assembly: AssemblyVersion("1.0.0.0")]
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;
}
}
}
namespace BusinessAsUsual
{
[BepInPlugin("Severedsolo.SOD.BusinessAsUsual", "BusinessAsUsual", "1.0.0")]
[BepInDependency(/*Could not decode attribute arguments.*/)]
public class BusinessAsUsual : BasePlugin
{
public const string PLUGIN_GUID = "Severedsolo.SOD.BusinessAsUsual";
public const string PLUGIN_NAME = "BusinessAsUsual";
public const string PLUGIN_VERSION = "1.0.0";
public static BusinessAsUsual Instance;
public static Random Random = new Random();
private static ConfigEntry<bool> debugMode { get; set; }
public override void Load()
{
//IL_000b: Unknown result type (might be due to invalid IL or missing references)
Instance = this;
new Harmony("Severedsolo.SOD.BusinessAsUsual").PatchAll(Assembly.GetExecutingAssembly());
Lib.Time.OnTimeInitialized += AddTimeEvents;
Lib.SaveGame.OnAfterNewGame += ResetMod;
Lib.SaveGame.OnAfterLoad += ResetMod;
debugMode = ((BasePlugin)this).Config.Bind<bool>("Debugging", "BusinessAsUsual.DebuggingEnabled", false, "Debugging Enabled");
LogInfo("Plugin is initialised", forcePrint: true);
}
private void ResetMod(object? sender, EventArgs e)
{
LoadBlacklist();
PatchUpdateGameLocation.AlreadyCheckedPeople.Clear();
PatchUpdateGameLocation.BusinessesWithSaleRecords.Clear();
LogInfo("All data reset", forcePrint: true);
}
private void LoadBlacklist()
{
PatchUpdateGameLocation.BlacklistedProducts.Clear();
string pluginDirectoryPath = Lib.SaveGame.GetPluginDirectoryPath(Assembly.GetExecutingAssembly());
if (Utility.IsNullOrWhiteSpace(pluginDirectoryPath))
{
return;
}
pluginDirectoryPath = Path.Combine(pluginDirectoryPath, "blacklist.txt");
if (!File.Exists(pluginDirectoryPath))
{
((BasePlugin)this).Log.LogWarning((object)("Blacklist file (expected to be at " + pluginDirectoryPath + ") does not exist!"));
return;
}
int num = 0;
using (StreamReader streamReader = new StreamReader(pluginDirectoryPath))
{
while (true)
{
string text = streamReader.ReadLine();
if (text == null)
{
break;
}
PatchUpdateGameLocation.BlacklistedProducts.Add(text);
num++;
LogInfo("Added " + text + " to blacklist", forcePrint: true);
}
}
LogInfo("Loaded " + num + " items from blacklist", forcePrint: true);
}
private void AddTimeEvents(object? sender, TimeChangedArgs e)
{
Lib.Time.OnHourChanged += CheckIfNeedToBackFillRecords;
}
private void CheckIfNeedToBackFillRecords(object? sender, TimeChangedArgs e)
{
PatchUpdateGameLocation.CreateFakeRecords();
}
public void LogInfo(string messageToLog, bool forcePrint = false)
{
if (forcePrint || debugMode.Value)
{
((BasePlugin)this).Log.LogInfo((object)messageToLog);
}
}
}
[HarmonyPatch(typeof(Human), "OnGameLocationChange")]
public class PatchUpdateGameLocation
{
public static Dictionary<string, Company> BusinessesWithSaleRecords = new Dictionary<string, Company>();
public static Dictionary<string, string?> AlreadyCheckedPeople = new Dictionary<string, string>();
public static List<string> BlacklistedProducts = new List<string>();
[HarmonyPostfix]
public static void Postfix(Human __instance)
{
if ((Object)(object)__instance == (Object)null || ((Actor)__instance).isPlayer || ((Actor)__instance).isMachine || ((Actor)__instance).isHomeless)
{
return;
}
if (BusinessesWithSaleRecords.Count == 0)
{
FindBusinessesWithSalesRecords();
}
object obj;
if (__instance == null)
{
obj = null;
}
else
{
NewGameLocation currentGameLocation = ((Actor)__instance).currentGameLocation;
obj = ((currentGameLocation != null) ? currentGameLocation.thisAsAddress : null);
}
if ((Object)obj == (Object)null || !BusinessesWithSaleRecords.TryGetValue(((Object)((Actor)__instance).currentGameLocation.thisAsAddress).name, out Company value) || value.companyRoster.Contains(__instance.job))
{
return;
}
AlreadyCheckedPeople.TryGetValue(((Object)__instance).name, out string value2);
if (Utility.IsNullOrWhiteSpace(value2) || !(value2 == value.name))
{
BusinessAsUsual.Instance.LogInfo(((Object)__instance).name + " is visiting " + ((Object)((Actor)__instance).currentGameLocation.thisAsAddress).name);
AlreadyCheckedPeople[((Object)__instance).name] = value.name;
if (IsValidToGenerateRecord(value, __instance))
{
SimulateSalesRecord(value, __instance);
}
}
}
private static bool IsValidToGenerateRecord(Company c, Human human)
{
int num = NumberOfRecordsInLast24Hours(c, human);
int num2 = NumberOfRecordsToGenerate(c);
if (num != int.MaxValue)
{
BusinessAsUsual.Instance.LogInfo(c.name + " has " + num + " sales records out of " + num2);
}
if (num <= num2)
{
return (Object)(object)human != (Object)(object)MurderController.Instance.currentMurderer;
}
return false;
}
private static int NumberOfRecordsToGenerate(Company c)
{
return c.prices.Count;
}
private static int NumberOfRecordsInLast24Hours(Company company, Human human)
{
float num = SessionData.Instance.gameTime - 24f;
int num2 = 0;
List<SalesRecord> list = EnumerableExtensions.ToList<SalesRecord>(company.sales);
int num3 = 0;
for (int num4 = list.Count - 1; num4 >= 0; num4--)
{
SalesRecord val = list[num4];
if (val != null)
{
if ((Object)(object)human != (Object)null && (Object)(object)val.GetPunter() == (Object)(object)human)
{
BusinessAsUsual.Instance.LogInfo("Punter already has a record");
return int.MaxValue;
}
if (val.time < num)
{
company.sales.Remove(val);
num2--;
num3++;
}
num2++;
}
}
if (num3 > 0)
{
BusinessAsUsual.Instance.LogInfo("Deleted " + num3 + " records from " + company.name + " as they were over 24 hours old");
}
return num2;
}
private static bool SimulateSalesRecord(Company c, Human visitor, bool forceCreate = false, bool generateFakeTimeStamp = false)
{
//IL_0222: Unknown result type (might be due to invalid IL or missing references)
//IL_0227: Unknown result type (might be due to invalid IL or missing references)
double num = BusinessAsUsual.Random.NextDouble();
double num2 = 1.0 - (double)NumberOfRecordsInLast24Hours(c, visitor) / (double)NumberOfRecordsToGenerate(c);
if (!forceCreate)
{
BusinessAsUsual.Instance.LogInfo("Rolled " + num + " needed " + num2);
}
if (!forceCreate && num2 < num)
{
return false;
}
if (c.prices.Count == 0 || !c.preset.recordSalesData || c.preset.isSelfEmployed)
{
return false;
}
BusinessAsUsual.Instance.LogInfo("Attempting to create fake record for " + ((Object)visitor).name + " in " + c.name);
int num3 = BusinessAsUsual.Random.Next(0, c.prices.Count);
List<InteractablePreset> val = new List<InteractablePreset>();
Enumerator<InteractablePreset, int> enumerator = c.prices.GetEnumerator();
while (enumerator.MoveNext())
{
KeyValuePair<InteractablePreset, int> current = enumerator.Current;
if (num3 != 0)
{
num3--;
continue;
}
InteractablePreset key = current.Key;
if (!((SoCustomComparison)(object)key == (SoCustomComparison)null) && !ProductIsBlacklisted(((Object)key).name.ToLower()) && !AlreadyHasItemPicked(visitor, key))
{
val.Add(key);
BusinessAsUsual.Instance.LogInfo(((Object)visitor).name + " is buying a " + ((Object)key).name);
MurderWeaponPreset weapon = key.weapon;
if (weapon == null || !(weapon.ammunition?.Count > 0))
{
break;
}
key = EnumerableExtensions.ToList<InteractablePreset>(key.weapon.ammunition)[BusinessAsUsual.Random.Next(0, key.weapon.ammunition.Count)];
if (!AlreadyHasItemPicked(visitor, key))
{
val.Add(key);
break;
}
}
}
if (val.Count == 0)
{
return false;
}
InteractablePreset[] array = Il2CppArrayBase<InteractablePreset>.op_Implicit(val.ToArray());
for (int i = 0; i < val.Count; i++)
{
InteractablePreset val2 = array[i];
if (!((SoCustomComparison)(object)val2 == (SoCustomComparison)null))
{
Interactable obj = InteractableCreator.Instance.CreateWorldInteractable(val2, visitor, visitor, (Human)null, Vector3.zero, Vector3.zero, (List<Passed>)null, (Object)null, "");
if (obj != null)
{
obj.SetInInventory(visitor);
}
}
}
float num4 = (generateFakeTimeStamp ? FakeTimeStamp() : SessionData.Instance.gameTime);
c.AddSalesRecord(visitor, val, num4);
BusinessAsUsual.Instance.LogInfo("Fake record created");
return true;
}
private static bool ProductIsBlacklisted(string productName)
{
for (int i = 0; i < BlacklistedProducts.Count; i++)
{
string value = BlacklistedProducts[i].ToLower();
if (productName.Contains(value))
{
return true;
}
}
return false;
}
private static bool AlreadyHasItemPicked(Human visitor, InteractablePreset ip)
{
Interactable[] array = Il2CppArrayBase<Interactable>.op_Implicit(((Actor)visitor).inventory.ToArray());
foreach (Interactable val in array)
{
if ((SoCustomComparison)(object)val.preset == (SoCustomComparison)(object)ip)
{
return true;
}
if ((SoCustomComparison)(object)ip.weapon != (SoCustomComparison)null && (SoCustomComparison)(object)val.preset.weapon != (SoCustomComparison)null)
{
if (ip.weapon.ammunition == null && val.preset.weapon.ammunition == null)
{
return true;
}
if (ip.weapon.ammunition != null && val.preset.weapon.ammunition != null)
{
return true;
}
}
}
return false;
}
private static float FakeTimeStamp()
{
return SessionData.Instance.gameTime - (float)BusinessAsUsual.Random.Next(1, 24) + (float)BusinessAsUsual.Random.NextDouble();
}
private static void FindBusinessesWithSalesRecords()
{
List<Company> list = EnumerableExtensions.ToList<Company>(CityData.Instance.companyDirectory);
for (int i = 0; i < list.Count; i++)
{
Company val = list[i];
if (val != null && val.prices.Count != 0 && val.preset.recordSalesData && !val.preset.isSelfEmployed && !BusinessesWithSaleRecords.Keys.Contains(((Object)val.address).name))
{
BusinessesWithSaleRecords.Add(((Object)val.address).name, val);
BusinessAsUsual.Instance.LogInfo(val.name + " is at " + ((Object)val.address).name);
}
}
}
public static void CreateFakeRecords()
{
List<Company> list = BusinessesWithSaleRecords.Values.ToList();
List<Human> potentialCitizens = new List<Human>((IEnumerable<Human>)EnumerableExtensions.ToList<Citizen>(CityData.Instance.citizenDirectory));
for (int i = 0; i < list.Count; i++)
{
Company val = list[i];
if (val == null)
{
continue;
}
int num = NumberOfRecordsToGenerate(val) / 4;
int num2 = NumberOfRecordsInLast24Hours(val, null);
BusinessAsUsual.Instance.LogInfo(val.name + " has " + num2 + "/" + num + " records");
if (num2 >= num)
{
continue;
}
int num3 = 0;
while (num > 0)
{
Human fakeCitizen = GetFakeCitizen(potentialCitizens);
if (SimulateSalesRecord(val, fakeCitizen, forceCreate: true, generateFakeTimeStamp: true))
{
num--;
num3++;
}
}
BusinessAsUsual.Instance.LogInfo("Created " + num3 + " fake records for " + val.name);
}
}
private static Human GetFakeCitizen(List<Human> potentialCitizens)
{
Human val;
do
{
val = potentialCitizens[BusinessAsUsual.Random.Next(0, potentialCitizens.Count)];
}
while (!((Object)(object)val != (Object)null) || ((Actor)val).isDead || ((Actor)val).isPlayer || !((Object)(object)val != (Object)(object)MurderController.Instance.currentMurderer) || ((Actor)val).isHomeless);
return val;
}
}
}