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.InteropServices;
using System.Runtime.Versioning;
using System.Text;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using HarmonyLib;
[assembly: CompilationRelaxations(8)]
[assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)]
[assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)]
[assembly: AssemblyTitle("Erenshor-CustomSimPlayerNames")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Erenshor-CustomSimPlayerNames")]
[assembly: AssemblyCopyright("Copyright © 2025")]
[assembly: AssemblyTrademark("")]
[assembly: ComVisible(false)]
[assembly: Guid("6c1f6b4f-ac83-4639-ab86-e03790207e0f")]
[assembly: AssemblyFileVersion("1.1.0")]
[assembly: TargetFramework(".NETFramework,Version=v4.7.2", FrameworkDisplayName = ".NET Framework 4.7.2")]
[assembly: AssemblyVersion("1.1.0.0")]
namespace Erenshor_CustomSimPlayerNames;
[BepInPlugin("Brad522.CustomSimPlayerNames", "Custom SimPlayer Names", "1.1.0")]
public class CustomSimPlayerNames : BaseUnityPlugin
{
[HarmonyPatch(typeof(SimPlayerMngr))]
[HarmonyPatch("CreateGenericSimPlayers")]
public class SimPlayerMngr_CreateGenericSimPlayers_Patch
{
[HarmonyPrefix]
public static void Prefix()
{
LoadNamesFromFile("NameDatabaseMale.txt");
LoadNamesFromFile("NameDatabaseFemale.txt", female: true);
}
}
public static CustomSimPlayerNames Instance;
internal const string ModName = "CustomSimPlayerNames";
internal const string ModVersion = "1.1.0";
internal const string ModDescription = "Custom SimPlayer Names";
internal const string Author = "Brad522";
private const string ModGUID = "Brad522.CustomSimPlayerNames";
private readonly Harmony harmony = new Harmony("Brad522.CustomSimPlayerNames");
internal static ManualLogSource Log;
internal static Random RandomGen;
public static ConfigEntry<bool> RandomizeNames;
private static readonly HashSet<string> randomizedFiles = new HashSet<string>();
private static readonly HashSet<string> ReservedWindowsNames = new HashSet<string>(StringComparer.OrdinalIgnoreCase)
{
"CON", "PRN", "AUX", "NUL", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6",
"COM7", "COM8", "COM9", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7",
"LPT8", "LPT9"
};
public void Awake()
{
Instance = this;
RandomizeNames = ((BaseUnityPlugin)this).Config.Bind<bool>("General", "RandomizeNames", false, "If true, SimPlayer names will be assigned randomly instead of in order.");
Log = ((BaseUnityPlugin)this).Logger;
RandomGen = new Random();
harmony.PatchAll();
}
private static void LoadNamesFromFile(string fileName = "CustomSimPlayerNames.txt", bool female = false)
{
string directoryName = Path.GetDirectoryName(Path.GetFullPath(Assembly.GetExecutingAssembly().Location));
string text = Path.Combine(directoryName, fileName);
if (!File.Exists(text))
{
Log.LogError((object)("[CustomSimPlayerNames] Name file not found: " + text));
return;
}
try
{
string[] array = File.ReadAllLines(text);
List<string> list = new List<string>();
string[] array2 = array;
for (int i = 0; i < array2.Length; i++)
{
string text2 = array2[i].Trim();
if (!string.IsNullOrEmpty(text2))
{
string text3 = text2.Normalize(NormalizationForm.FormC);
if (!IsValidName(text3))
{
Log.LogWarning((object)("[CustomSimPlayerNames] Invalid name skipped: " + text2));
}
else if (list.Contains(text3))
{
Log.LogWarning((object)("[CustomSimPlayerNames] Duplicate name skipped: " + text3));
}
else
{
list.Add(text3);
}
}
}
ref List<string> reference = ref female ? ref GameData.SimMngr.NameDatabaseFemale : ref GameData.SimMngr.NameDatabaseMale;
if (list.Count < 60 && reference != null)
{
int num = 0;
foreach (string item in reference)
{
if (!list.Contains(item))
{
list.Add(item);
num++;
if (list.Count >= 60)
{
break;
}
}
}
Log.LogDebug((object)$"[CustomSimPlayerNames] Added {num} names from existing database to {fileName}");
}
if (RandomizeNames.Value)
{
string text4 = Path.Combine(directoryName, Path.GetFileNameWithoutExtension(fileName) + "_original.txt");
if (!File.Exists(text4))
{
File.Copy(text, text4);
Log.LogDebug((object)("[CustomSimPlayerNames] Created backup of original names file at " + text4));
}
else
{
Log.LogWarning((object)("[CustomSimPlayerNames] Backup file already exists: " + text4));
}
ShuffleNames(list);
File.WriteAllLines(text, list);
Log.LogDebug((object)("[CustomSimPlayerNames] Shuffled names and saved to " + text));
MarkRandomizationCompleteIfNeeded(fileName);
}
Log.LogDebug((object)$"[CustomSimPlayerNames] Loaded {list.Count} names from {text}");
reference = list;
}
catch (IOException ex)
{
Log.LogError((object)("[CustomSimPlayerNames] Error reading name file: " + ex.Message));
}
}
private static bool IsValidName(string name)
{
if (string.IsNullOrWhiteSpace(name))
{
return false;
}
if (name.IndexOfAny(Path.GetInvalidFileNameChars()) >= 0)
{
return false;
}
if (name.EndsWith(" ") || name.EndsWith("."))
{
return false;
}
if (ReservedWindowsNames.Contains(name))
{
return false;
}
if (name.Length > 30)
{
return false;
}
if (name.Any((char c) => char.IsControl(c)))
{
return false;
}
return true;
}
private static void ShuffleNames(List<string> names)
{
int num = names.Count;
while (num > 1)
{
num--;
int num2 = RandomGen.Next(num + 1);
int index = num;
int index2 = num2;
string value = names[num2];
string value2 = names[num];
names[index] = value;
names[index2] = value2;
}
Log.LogDebug((object)"[CustomSimPlayerNames] Names shuffled.");
}
private static void MarkRandomizationCompleteIfNeeded(string justRandomized)
{
randomizedFiles.Add(justRandomized);
if (randomizedFiles.Contains("NameDatabaseMale.txt") && randomizedFiles.Contains("NameDatabaseFemale.txt"))
{
Log.LogInfo((object)"[CustomSimPlayerNames] All name databases have been randomized.");
RandomizeNames.Value = false;
((BaseUnityPlugin)Instance).Config.Save();
randomizedFiles.Clear();
}
}
}