SDM_LethalCompany_Mod/ScarletMansion/ScarletMansion/PluginConfigClasses.cs

456 lines
18 KiB
C#

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Unity.Netcode;
using System.Runtime.Serialization.Formatters.Binary;
using System.IO;
using HarmonyLib;
using BepInEx;
using BepInEx.Configuration;
using BepInEx.Logging;
using UnityEngine;
using System.Reflection;
using static ScarletMansion.PluginConfig;
namespace ScarletMansion {
public partial class PluginConfig : SyncedInstance<PluginConfig> {
public abstract class NumberRange<T> {
private string name;
[SerializeField] protected T _min;
[SerializeField] protected T _max;
public T min {
get {
return _min;
} set {
_min = value;
Verify();
}
}
public T max {
get {
return _max;
} set {
_max = value;
Verify();
}
}
public NumberRange(string name){
this.name = name;
_min = default;
_max = default;
}
public virtual void Verify(){
Plugin.logger.LogDebug($"Verifying min/max for {name}");
}
public override string ToString() {
return $"({min}, {max})";
}
}
[System.Serializable]
public class IntRange : NumberRange<int> {
public IntRange(string name) : base(name) { }
public override void Verify() {
base.Verify();
_max = Mathf.Max(_min, _max);
}
public DunGen.IntRange GetDungenIntRange(){
return new DunGen.IntRange(min, max);
}
}
[System.Serializable]
public class FloatRange : NumberRange<float> {
public FloatRange(string name) : base(name) { }
public override void Verify() {
base.Verify();
_max = Mathf.Max(_min, _max);
}
public DunGen.FloatRange GetDungenFloatRange(){
return new DunGen.FloatRange(min, max);
}
}
[System.Serializable]
public class BranchingPathRange {
private string name;
public IntRange count;
public IntRange depth;
public BranchingPathRange(string name){
this.name = name;
count = new IntRange($"{name} count");
depth = new IntRange($"{name} depth");
}
public void UpdateValues(DunGen.DungeonArchetype archetype){
archetype.BranchCount = new DunGen.IntRange(count.min, count.max);
archetype.BranchingDepth = new DunGen.IntRange(depth.min, depth.max);
}
public override string ToString() {
return $"{count.ToString()}+{depth.ToString()}";
}
}
[System.Serializable]
public class Enemy {
public bool enabled;
public int health;
public float speed;
}
[System.Serializable]
public class SpawnableEnemy : Enemy {
public int spawnWeightBase;
public float spawnWeightStealPercentage;
}
[System.Serializable]
public class Item {
public bool enabled;
public IntRange valueRange;
public Item(string name) {
valueRange = new IntRange($"{name} value range");
}
}
[System.Serializable]
public class ScrapItem : Item {
public int spawnWeight;
public bool spawnOnAllMoons;
public ScrapItem(string name) : base(name) { }
}
public abstract class ConfigEntryBundleBase {
public class FieldPropertyInfo {
public FieldInfo fieldInfo;
public PropertyInfo propertyInfo;
public FieldPropertyInfo(FieldInfo fieldInfo){
this.fieldInfo = fieldInfo;
}
public FieldPropertyInfo(PropertyInfo propertyInfo){
this.propertyInfo = propertyInfo;
}
public void SetValue(object obj, object value){
if (fieldInfo != null) fieldInfo.SetValue(obj, value);
if (propertyInfo != null) propertyInfo.SetValue(obj, value);
}
public object GetValue(object obj){
if (fieldInfo != null) return fieldInfo.GetValue(obj);
if (propertyInfo != null) return propertyInfo.GetValue(obj);
return null;
}
public Type GetFieldPropertyType(){
if (fieldInfo != null) return fieldInfo.FieldType;
if (propertyInfo != null) return propertyInfo.PropertyType;
return null;
}
}
public abstract IEnumerable<ConfigEntryBase> GetConfigs();
public abstract void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget);
}
public class ConfigEntryBundleExtraParameters {
public Action<PluginConfig> onSettingsChanged;
public bool callOnBind;
public ConfigEntryBundleExtraParameters(Action<PluginConfig> onSettingsChanged, bool callOnBind){
this.onSettingsChanged = onSettingsChanged;
this.callOnBind = callOnBind;
}
public void CallAction(PluginConfig instance, bool isBind){
if (isBind && !callOnBind) return;
onSettingsChanged?.Invoke(instance);
}
}
public class ConfigEntryBundle<T> : ConfigEntryBundleBase {
public ConfigEntry<T> config;
public ConfigDefinition definition;
public T defaultValue;
public ConfigDescription description;
public ConfigEntryBundleExtraParameters extra;
public ConfigEntryBundle(string section, string key, T dvalue, string desc, ConfigEntryBundleExtraParameters extra = null, AcceptableValueBase valuebase = null){
definition = new ConfigDefinition(section, key);
defaultValue = dvalue;
description = new ConfigDescription(desc, valuebase);
if (extra == null) extra = new ConfigEntryBundleExtraParameters(null, false);
this.extra = extra;
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
config = cfg.Bind(definition, defaultValue, description);
config.SettingChanged += (obj, args) => {
Plugin.logger.LogDebug($"Config settings {config.Definition.Key} changed");
memberInfo.SetValue(memberTarget, config.Value);
extra.CallAction(instance, false);
};
memberInfo.SetValue(memberTarget, config.Value);
extra.CallAction(instance, true);
}
public void Bind(ConfigFile cfg, PluginConfig instance){
config = cfg.Bind(definition, defaultValue, description);
config.SettingChanged += (obj, args) => {
Plugin.logger.LogDebug($"Config settings {config.Definition.Key} changed");
extra.CallAction(instance, false);
};
extra.CallAction(instance, true);
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
yield return config;
}
}
public class ConfigEntryBundleMinMax<T> : ConfigEntryBundleBase {
public ConfigEntryBundle<T> min;
public ConfigEntryBundle<T> max;
public ConfigEntryBundleMinMax(string section, string keyMin, string keyMax, T defaultValueMin, T defaultValueMax, string descMin, string descMax, ConfigEntryBundleExtraParameters extra = null, AcceptableValueBase valuebase = null){
min = new ConfigEntryBundle<T>(section, keyMin, defaultValueMin, descMin, extra, valuebase);
max = new ConfigEntryBundle<T>(section, keyMax, defaultValueMax, descMax, extra, valuebase);
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
var type = memberInfo.GetFieldPropertyType();
var minProp = type.GetProperty("min", BindingFlags.Public | BindingFlags.Instance);
var maxProp = type.GetProperty("max", BindingFlags.Public | BindingFlags.Instance);
min.Bind(cfg, instance, new FieldPropertyInfo(minProp), memberInfo.GetValue(memberTarget));
max.Bind(cfg, instance, new FieldPropertyInfo(maxProp), memberInfo.GetValue(memberTarget));
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
yield return min.config;
yield return max.config;
}
}
public class ConfigEntryBundleBranchingPath : ConfigEntryBundleBase {
public ConfigEntryBundleMinMax<int> count;
public ConfigEntryBundleMinMax<int> depth;
public ConfigEntryBundleBranchingPath(string section, int sectionId, string extraMessage, int countMinValue, int countMaxValue, int depthMinValue, int depthMaxValue, ConfigEntryBundleExtraParameters extra = null){
count = new ConfigEntryBundleMinMax<int>(
section,
$"Section {sectionId} Count Min",
$"Section {sectionId} Count Max",
countMinValue,
countMaxValue,
_branchPathBranchCountMessage(sectionId, "minimum", extraMessage),
_branchPathBranchCountMessage(sectionId, "maximum", extraMessage),
extra,
new AcceptableValueRange<int>(0, 20)
);
depth = new ConfigEntryBundleMinMax<int>(
section,
$"Section {sectionId} Depth Min",
$"Section {sectionId} Depth Max",
depthMinValue,
depthMaxValue,
_branchPathBranchDepthMessage(sectionId, "minimum", extraMessage),
_branchPathBranchDepthMessage(sectionId, "maximum", extraMessage),
extra,
new AcceptableValueRange<int>(0, 20)
);
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
var type = memberInfo.GetFieldPropertyType();
var countField = type.GetField("count", BindingFlags.Public | BindingFlags.Instance);
var depthField = type.GetField("depth", BindingFlags.Public | BindingFlags.Instance);
count.Bind(cfg, instance, new FieldPropertyInfo(countField), memberInfo.GetValue(memberTarget));
depth.Bind(cfg, instance, new FieldPropertyInfo(depthField), memberInfo.GetValue(memberTarget));
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
foreach(var a in count.GetConfigs()) {
yield return a;
}
foreach(var a in depth.GetConfigs()) {
yield return a;
}
}
}
public class ConfigEntryBundleEnemy : ConfigEntryBundleBase {
public ConfigEntryBundle<bool> enabled;
public ConfigEntryBundle<int> health;
public ConfigEntryBundle<float> speed;
public ConfigEntryBundleEnemy(string section, string enemyName, int baseHealth, float baseSpeed, ConfigEntryBundleExtraParameters extra = null){
var enabledDesc = $"If disabled, {enemyName} is disabled from spawning.";
var healthDesc = $"The health of the {enemyName}. A shovel is 1 damage.";
var speedDesc = $"The speed of the {enemyName} during their killing/aggressive stance. The player's default speed is 4.6.";
enabled = new ConfigEntryBundle<bool>(section, "Enabled", true, enabledDesc, extra);
health = new ConfigEntryBundle<int>(section, "Health", baseHealth, healthDesc, extra, new AcceptableValueRange<int>(1, 20));
speed = new ConfigEntryBundle<float>(section, "Speed", baseSpeed, speedDesc, extra, new AcceptableValueRange<float>(1f, 20f));
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
var type = memberInfo.GetFieldPropertyType();
var enabledProp = type.GetField("enabled", BindingFlags.Public | BindingFlags.Instance);
var healthProp = type.GetField("health", BindingFlags.Public | BindingFlags.Instance);
var speedProp = type.GetField("speed", BindingFlags.Public | BindingFlags.Instance);
enabled.Bind(cfg, instance, new FieldPropertyInfo(enabledProp), memberInfo.GetValue(memberTarget));
if (health.defaultValue > 0) health.Bind(cfg, instance, new FieldPropertyInfo(healthProp), memberInfo.GetValue(memberTarget));
speed.Bind(cfg, instance, new FieldPropertyInfo(speedProp), memberInfo.GetValue(memberTarget));
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
yield return enabled.config;
if (health.defaultValue > 0) yield return health.config;
yield return speed.config;
}
}
public class ConfigEntryBundleSpawnableEnemy : ConfigEntryBundleEnemy {
public ConfigEntryBundle<int> spawnWeightBase;
public ConfigEntryBundle<float> spawnWeightStealPercentage;
public ConfigEntryBundleSpawnableEnemy(string section, string enemyName, string replacementEnemyName, int baseHealth, float baseSpeed, ConfigEntryBundleExtraParameters extra = null) : base(section, enemyName, baseHealth, baseSpeed, extra) {
var weightBaseDesc = $"The base spawn weight of the {enemyName}. This is added onto the spawn weight stolen from the {replacementEnemyName}, or the base weight of 10 if the moon doesn't spawn the {replacementEnemyName}.";
var weightStealPercentageDesc = $"The percentage of spawn weight that the {enemyName} steals from the {replacementEnemyName} for that moon.\nSetting this 0 means that the {replacementEnemyName}'s weight is unaffected and the {enemyName}'s weight is based entirely by Spawn Weight Base.\nSetting this 1 means the {enemyName} effectively replaces the {replacementEnemyName}.";
spawnWeightBase = new ConfigEntryBundle<int>(section, "Spawn Weight Base", 0, weightBaseDesc, extra, new AcceptableValueRange<int>(0, 999));
spawnWeightStealPercentage = new ConfigEntryBundle<float>(section, "Spawn Weight Steal Percentage", 0.75f, weightStealPercentageDesc, extra, new AcceptableValueRange<float>(0f, 1f));
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
base.Bind(cfg, instance, memberInfo, memberTarget);
var type = memberInfo.GetFieldPropertyType();
var weightBaseProp = type.GetField("spawnWeightBase", BindingFlags.Public | BindingFlags.Instance);
var weightStealPercentageProp = type.GetField("spawnWeightStealPercentage", BindingFlags.Public | BindingFlags.Instance);
spawnWeightBase.Bind(cfg, instance, new FieldPropertyInfo(weightBaseProp), memberInfo.GetValue(memberTarget));
spawnWeightStealPercentage.Bind(cfg, instance, new FieldPropertyInfo(weightStealPercentageProp), memberInfo.GetValue(memberTarget));
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
foreach(var a in base.GetConfigs()) {
yield return a;
}
yield return spawnWeightBase.config;
yield return spawnWeightStealPercentage.config;
}
}
public class ConfigEntryBundleItem : ConfigEntryBundleBase {
public ConfigEntryBundle<bool> enabled;
public ConfigEntryBundleMinMax<int> valueRange;
private static string _valueMessage(string itemName, string minmax) => $"The {minmax} scrap value of {itemName}. Lethal Company multiplies all scrap values by 0.4.";
public ConfigEntryBundleItem(string section, string keyPrefix, string itemName, int baseValueMin, int baseValueMax, ConfigEntryBundleExtraParameters extra = null){
var enabledDesc = $"If disabled, {itemName} is disabled from spawning.";
enabled = new ConfigEntryBundle<bool>(section, $"{keyPrefix}Enabled", true, enabledDesc, extra);
valueRange = new ConfigEntryBundleMinMax<int>(
section,
$"Value Min",
$"Value Max",
baseValueMin,
baseValueMax,
_valueMessage(itemName, "minimum"),
_valueMessage(itemName, "maximum"),
extra,
new AcceptableValueRange<int>(1, 400)
);
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
var type = memberInfo.GetFieldPropertyType();
var enabledProp = type.GetField("enabled", BindingFlags.Public | BindingFlags.Instance);
var valueRangeProp = type.GetField("valueRange", BindingFlags.Public | BindingFlags.Instance);
enabled.Bind(cfg, instance, new FieldPropertyInfo(enabledProp), memberInfo.GetValue(memberTarget));
if (valueRange.min.defaultValue > 0) valueRange.Bind(cfg, instance, new FieldPropertyInfo(valueRangeProp), memberInfo.GetValue(memberTarget));
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
yield return enabled.config;
if (valueRange.min.defaultValue > 0) {
foreach(var a in valueRange.GetConfigs()) {
yield return a;
}
}
}
}
public class ConfigEntryBundleScrapItem : ConfigEntryBundleItem {
public ConfigEntryBundle<int> spawnWeight;
public ConfigEntryBundle<bool> spawnOnAllMoons;
public ConfigEntryBundleScrapItem(string section, string itemName, int baseValueMin, int baseValueMax, int baseSpawnWeight, ConfigEntryBundleExtraParameters extra = null) : base(section, string.Empty, itemName, baseValueMin, baseValueMax, extra) {
var weightDesc = $"The {itemName}'s spawn weight. Calculating spawn chance (%) is difficult as the total scrap weight for each moon varies from ~600 to ~850.";
var spawnDesc = $"If enabled, the {itemName} scrap item will spawn on all moons regardless if SDM loaded.";
spawnWeight = new ConfigEntryBundle<int>(section, "Spawn Weight Base", baseSpawnWeight, weightDesc, extra, new AcceptableValueRange<int>(0, 999));
spawnOnAllMoons = new ConfigEntryBundle<bool>(section, "Spawn On All Moons", false, spawnDesc, extra);
}
public override void Bind(ConfigFile cfg, PluginConfig instance, FieldPropertyInfo memberInfo, object memberTarget) {
base.Bind(cfg, instance, memberInfo, memberTarget);
var type = memberInfo.GetFieldPropertyType();
var weightDescProp = type.GetField("spawnWeight", BindingFlags.Public | BindingFlags.Instance);
var spawnDescProp = type.GetField("spawnOnAllMoons", BindingFlags.Public | BindingFlags.Instance);
spawnWeight.Bind(cfg, instance, new FieldPropertyInfo(weightDescProp), memberInfo.GetValue(memberTarget));
spawnOnAllMoons.Bind(cfg, instance, new FieldPropertyInfo(spawnDescProp), memberInfo.GetValue(memberTarget));
}
public override IEnumerable<ConfigEntryBase> GetConfigs() {
foreach(var a in base.GetConfigs()) {
yield return a;
}
yield return spawnWeight.config;
yield return spawnOnAllMoons.config;
}
}
}
}