456 lines
18 KiB
C#
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;
|
|
}
|
|
}
|
|
|
|
}
|
|
}
|