mirror of
https://github.com/ApeMV/AmongUsRevamped.git
synced 2026-10-19 15:51:59 +00:00
Add custom options menu
This commit is contained in:
1 parent
0979589ca3
commit
0a55c35108
15 files changed
+1756
-4
No files matched your search
@@ -0,0 +1,46 @@
|
||||
using System.Threading.Tasks;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionHolder.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
[HarmonyPatch]
|
||||
public static class Options
|
||||
{
|
||||
static Task taskOptionsLoad;
|
||||
|
||||
[HarmonyPatch(typeof(TranslationController), nameof(TranslationController.Initialize)), HarmonyPostfix]
|
||||
public static void OptionsLoadStart()
|
||||
{
|
||||
taskOptionsLoad = Task.Run(Load);
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start)), HarmonyPostfix]
|
||||
public static void WaitOptionsLoad()
|
||||
{
|
||||
taskOptionsLoad.Wait();
|
||||
}
|
||||
|
||||
public static OptionItem Testy;
|
||||
public static OptionItem Testy1;
|
||||
public static OptionItem Testy2;
|
||||
|
||||
|
||||
public static bool IsLoaded = false;
|
||||
|
||||
public static void Load()
|
||||
{
|
||||
if (IsLoaded) return;
|
||||
|
||||
//Main settings
|
||||
Testy = IntegerOptionItem.Create(3, "Testy", new IntegerValueRule(0, 50, 5), 10, TabGroup.GameModifiers, false);
|
||||
Testy1 = BooleanOptionItem.Create(4, "Testy1", true, TabGroup.ModSettings, false)
|
||||
.SetColor(Color.red);
|
||||
Testy2 = BooleanOptionItem.Create(5, "Testy2", true, TabGroup.ModSettings, false)
|
||||
.SetParent(Testy1);
|
||||
IsLoaded = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionBackup/OptionBackupData.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public class OptionBackupData
|
||||
{
|
||||
public List<OptionBackupValue> AllValues;
|
||||
public OptionBackupData(IGameOptions option)
|
||||
{
|
||||
AllValues = new(32);
|
||||
|
||||
foreach (ByteOptionNames name in Enum.GetValues(typeof(ByteOptionNames)))
|
||||
{
|
||||
if (option.TryGetByte(name, out var value))
|
||||
AllValues.Add(new ByteOptionBackupValue(name, value));
|
||||
}
|
||||
foreach (BoolOptionNames name in Enum.GetValues(typeof(BoolOptionNames)))
|
||||
{
|
||||
if (name == BoolOptionNames.GhostsDoTasks) continue;
|
||||
if (option.TryGetBool(name, out var value))
|
||||
AllValues.Add(new BoolOptionBackupValue(name, value));
|
||||
}
|
||||
foreach (FloatOptionNames name in Enum.GetValues(typeof(FloatOptionNames)))
|
||||
{
|
||||
if (option.TryGetFloat(name, out var value))
|
||||
AllValues.Add(new FloatOptionBackupValue(name, value));
|
||||
}
|
||||
foreach (Int32OptionNames name in Enum.GetValues(typeof(Int32OptionNames)))
|
||||
{
|
||||
if (option.TryGetInt(name, out var value))
|
||||
AllValues.Add(new IntOptionBackupValue(name, value));
|
||||
}
|
||||
AllValues.Add(new IntOptionBackupValue(Int32OptionNames.MaxPlayers, option.MaxPlayers));
|
||||
AllValues.Add(new UIntOptionBackupValue(UInt32OptionNames.Keywords, (uint)option.Keywords));
|
||||
|
||||
foreach (RoleTypes role in new RoleTypes[] { RoleTypes.Scientist, RoleTypes.Engineer, RoleTypes.GuardianAngel, RoleTypes.Shapeshifter, RoleTypes.Noisemaker, RoleTypes.Phantom, RoleTypes.Tracker, RoleTypes.Detective, RoleTypes.Viper })
|
||||
{
|
||||
AllValues.Add(new RoleRateBackupValue(role, option.RoleOptions.GetNumPerGame(role), option.RoleOptions.GetChancePerGame(role)));
|
||||
}
|
||||
}
|
||||
|
||||
public IGameOptions Restore(IGameOptions option)
|
||||
{
|
||||
foreach (var value in AllValues)
|
||||
{
|
||||
value.Restore(option);
|
||||
}
|
||||
return option;
|
||||
}
|
||||
|
||||
public byte GetByte(ByteOptionNames name) => Get<ByteOptionNames, byte>(name);
|
||||
public bool GetBool(BoolOptionNames name) => Get<BoolOptionNames, bool>(name);
|
||||
public float GetFloat(FloatOptionNames name) => Get<FloatOptionNames, float>(name);
|
||||
public int GetInt(Int32OptionNames name) => Get<Int32OptionNames, int>(name);
|
||||
public uint GetUInt(UInt32OptionNames name) => Get<UInt32OptionNames, uint>(name);
|
||||
public TValue Get<TKey, TValue>(TKey name)
|
||||
where TKey : Enum
|
||||
{
|
||||
var value = AllValues
|
||||
.OfType<OptionBackupValueBase<TKey, TValue>>()
|
||||
.Where(val => val.OptionName.Equals(name)).
|
||||
FirstOrDefault();
|
||||
|
||||
return value == null ? default : value.Value;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,82 @@
|
||||
using System;
|
||||
using AmongUs.GameOptions;
|
||||
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionBackup/OptionBackupValue.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public abstract class OptionBackupValue
|
||||
{
|
||||
public abstract void Restore(IGameOptions option);
|
||||
}
|
||||
|
||||
public abstract class OptionBackupValueBase<NameT, ValueT> : OptionBackupValue
|
||||
where NameT : Enum
|
||||
{
|
||||
public readonly NameT OptionName;
|
||||
public readonly ValueT Value;
|
||||
public OptionBackupValueBase(NameT name, ValueT value)
|
||||
{
|
||||
OptionName = name;
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class ByteOptionBackupValue : OptionBackupValueBase<ByteOptionNames, byte>
|
||||
{
|
||||
public ByteOptionBackupValue(ByteOptionNames name, byte value) : base(name, value) { }
|
||||
public override void Restore(IGameOptions option)
|
||||
{
|
||||
option.SetByte(OptionName, Value);
|
||||
}
|
||||
}
|
||||
public class BoolOptionBackupValue : OptionBackupValueBase<BoolOptionNames, bool>
|
||||
{
|
||||
public BoolOptionBackupValue(BoolOptionNames name, bool value) : base(name, value) { }
|
||||
public override void Restore(IGameOptions option)
|
||||
{
|
||||
option.SetBool(OptionName, Value);
|
||||
}
|
||||
}
|
||||
public class FloatOptionBackupValue : OptionBackupValueBase<FloatOptionNames, float>
|
||||
{
|
||||
public FloatOptionBackupValue(FloatOptionNames name, float value) : base(name, value) { }
|
||||
public override void Restore(IGameOptions option)
|
||||
{
|
||||
option.SetFloat(OptionName, Value);
|
||||
}
|
||||
}
|
||||
public class IntOptionBackupValue : OptionBackupValueBase<Int32OptionNames, int>
|
||||
{
|
||||
public IntOptionBackupValue(Int32OptionNames name, int value) : base(name, value) { }
|
||||
public override void Restore(IGameOptions option)
|
||||
{
|
||||
option.SetInt(OptionName, Value);
|
||||
}
|
||||
}
|
||||
public class UIntOptionBackupValue : OptionBackupValueBase<UInt32OptionNames, uint>
|
||||
{
|
||||
public UIntOptionBackupValue(UInt32OptionNames name, uint value) : base(name, value) { }
|
||||
public override void Restore(IGameOptions option)
|
||||
{
|
||||
option.SetUInt(OptionName, Value);
|
||||
}
|
||||
}
|
||||
|
||||
public class RoleRateBackupValue : OptionBackupValue
|
||||
{
|
||||
public RoleTypes roleType;
|
||||
public int maxCount;
|
||||
public int chance;
|
||||
|
||||
public RoleRateBackupValue(RoleTypes type, int maxCount, int chance)
|
||||
{
|
||||
this.roleType = type;
|
||||
this.maxCount = maxCount;
|
||||
this.chance = chance;
|
||||
}
|
||||
public override void Restore(IGameOptions option)
|
||||
{
|
||||
option.RoleOptions.SetRoleRate(roleType, maxCount, chance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionItems/BooleanOptionItem.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public class BooleanOptionItem : OptionItem
|
||||
{
|
||||
public BooleanOptionItem(int id, string name, bool defaultValue, TabGroup tab, bool isSingleValue)
|
||||
: base(id, name, defaultValue ? 1 : 0, tab, isSingleValue)
|
||||
{
|
||||
}
|
||||
public static BooleanOptionItem Create(
|
||||
int id, string name, bool defaultValue, TabGroup tab, bool isSingleValue
|
||||
)
|
||||
{
|
||||
return new BooleanOptionItem(
|
||||
id, name, defaultValue, tab, isSingleValue
|
||||
);
|
||||
}
|
||||
|
||||
public override string GetString()
|
||||
{
|
||||
return GetBool() ? "✓" : "X";
|
||||
}
|
||||
|
||||
public override void SetValue(int value)
|
||||
{
|
||||
base.SetValue(value % 2 == 0 ? 0 : 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionItems/FloatOptionItem.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public class FloatOptionItem : OptionItem
|
||||
{
|
||||
public FloatValueRule Rule;
|
||||
|
||||
public FloatOptionItem(int id, string name, float defaultValue, TabGroup tab, bool isSingleValue, FloatValueRule rule)
|
||||
: base(id, name, rule.GetNearestIndex(defaultValue), tab, isSingleValue)
|
||||
{
|
||||
Rule = rule;
|
||||
}
|
||||
public static FloatOptionItem Create(
|
||||
int id, string name, FloatValueRule rule, float defaultValue, TabGroup tab, bool isSingleValue
|
||||
)
|
||||
{
|
||||
return new FloatOptionItem(
|
||||
id, name, defaultValue, tab, isSingleValue, rule
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetInt() => (int)Rule.GetValueByIndex(CurrentValue);
|
||||
public override float GetFloat() => Rule.GetValueByIndex(CurrentValue);
|
||||
public override string GetString()
|
||||
{
|
||||
return ApplyFormat(Rule.GetValueByIndex(CurrentValue).ToString());
|
||||
}
|
||||
public override int GetValue()
|
||||
=> Rule.RepeatIndex(base.GetValue());
|
||||
|
||||
public override void SetValue(int value)
|
||||
{
|
||||
base.SetValue(Rule.RepeatIndex(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionItems/IntegerOptionItem.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public class IntegerOptionItem : OptionItem
|
||||
{
|
||||
public IntegerValueRule Rule;
|
||||
|
||||
public IntegerOptionItem(int id, string name, int defaultValue, TabGroup tab, bool isSingleValue, IntegerValueRule rule)
|
||||
: base(id, name, rule.GetNearestIndex(defaultValue), tab, isSingleValue)
|
||||
{
|
||||
Rule = rule;
|
||||
}
|
||||
public static IntegerOptionItem Create(
|
||||
int id, string name, IntegerValueRule rule, int defaultValue, TabGroup tab, bool isSingleValue
|
||||
)
|
||||
{
|
||||
return new IntegerOptionItem(
|
||||
id, name, defaultValue, tab, isSingleValue, rule
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetInt() => Rule.GetValueByIndex(CurrentValue);
|
||||
public override float GetFloat() => Rule.GetValueByIndex(CurrentValue);
|
||||
public override string GetString()
|
||||
{
|
||||
return ApplyFormat(Rule.GetValueByIndex(CurrentValue).ToString());
|
||||
}
|
||||
public override int GetValue()
|
||||
=> Rule.RepeatIndex(base.GetValue());
|
||||
|
||||
public override void SetValue(int value)
|
||||
{
|
||||
base.SetValue(Rule.RepeatIndex(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,229 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using BepInEx.Configuration;
|
||||
using UnityEngine;
|
||||
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionItems/OptionItem.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public abstract class OptionItem
|
||||
{
|
||||
public static IReadOnlyList<OptionItem> AllOptions => _allOptions;
|
||||
private static List<OptionItem> _allOptions = new();
|
||||
public static int CurrentPreset { get; set; }
|
||||
|
||||
public int Id { get; }
|
||||
public string Name { get; }
|
||||
public int DefaultValue { get; }
|
||||
public TabGroup Tab { get; }
|
||||
public bool IsSingleValue { get; }
|
||||
|
||||
public Color NameColor { get; protected set; }
|
||||
public OptionFormat ValueFormat { get; protected set; }
|
||||
public bool IsHeader { get; protected set; }
|
||||
public bool IsHidden { get; protected set; }
|
||||
public bool IsText { get; protected set; }
|
||||
public Dictionary<string, string> ReplacementDictionary
|
||||
{
|
||||
get => _replacementDictionary;
|
||||
set
|
||||
{
|
||||
if (value == null) _replacementDictionary?.Clear();
|
||||
else _replacementDictionary = value;
|
||||
}
|
||||
}
|
||||
private Dictionary<string, string> _replacementDictionary;
|
||||
|
||||
public int CurrentValue
|
||||
{
|
||||
get => GetValue();
|
||||
set => SetValue(value);
|
||||
}
|
||||
|
||||
public OptionItem Parent { get; private set; }
|
||||
public List<OptionItem> Children;
|
||||
|
||||
public ConfigEntry<int> CurrentEntry =>
|
||||
IsSingleValue ? singleEntry : AllConfigEntries[CurrentPreset];
|
||||
private ConfigEntry<int>[] AllConfigEntries;
|
||||
private ConfigEntry<int> singleEntry;
|
||||
|
||||
public OptionBehaviour OptionBehaviour;
|
||||
|
||||
public event EventHandler<UpdateValueEventArgs> UpdateValueEvent;
|
||||
|
||||
public OptionItem(int id, string name, int defaultValue, TabGroup tab, bool isSingleValue)
|
||||
{
|
||||
Id = id;
|
||||
Name = name;
|
||||
DefaultValue = defaultValue;
|
||||
Tab = tab;
|
||||
IsSingleValue = isSingleValue;
|
||||
|
||||
NameColor = Color.white;
|
||||
ValueFormat = OptionFormat.None;
|
||||
IsHeader = false;
|
||||
IsHidden = false;
|
||||
IsText = false;
|
||||
|
||||
Children = new();
|
||||
|
||||
AllConfigEntries = new ConfigEntry<int>[10];
|
||||
if (Id == 0)
|
||||
{
|
||||
singleEntry = Main.Instance.Config.Bind("Current Preset", id.ToString(), DefaultValue);
|
||||
CurrentPreset = singleEntry.Value;
|
||||
}
|
||||
else if (IsSingleValue)
|
||||
{
|
||||
singleEntry = Main.Instance.Config.Bind("SingleEntryOptions", id.ToString(), DefaultValue);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = 0; i < 1; i++)
|
||||
{
|
||||
AllConfigEntries[i] = Main.Instance.Config.Bind($"Preset{i + 1}", id.ToString(), DefaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
_allOptions.Add(this);
|
||||
}
|
||||
|
||||
public OptionItem Do(Action<OptionItem> action)
|
||||
{
|
||||
action(this);
|
||||
return this;
|
||||
}
|
||||
|
||||
public OptionItem SetColor(Color value) => Do(i => i.NameColor = value);
|
||||
public OptionItem SetValueFormat(OptionFormat value) => Do(i => i.ValueFormat = value);
|
||||
public OptionItem SetHeader(bool value) => Do(i => i.IsHeader = value);
|
||||
public OptionItem SetHidden(bool value) => Do(i => i.IsHidden = value);
|
||||
public OptionItem SetText(bool value) => Do(i => i.IsHidden = value);
|
||||
|
||||
public OptionItem SetParent(OptionItem parent) => Do(i =>
|
||||
{
|
||||
i.Parent = parent;
|
||||
parent.SetChild(i);
|
||||
});
|
||||
public OptionItem SetChild(OptionItem child) => Do(i => i.Children.Add(child));
|
||||
public OptionItem RegisterUpdateValueEvent(EventHandler<UpdateValueEventArgs> handler)
|
||||
=> Do(i => UpdateValueEvent += handler);
|
||||
|
||||
public OptionItem AddReplacement((string key, string value) kvp)
|
||||
=> Do(i =>
|
||||
{
|
||||
ReplacementDictionary ??= new();
|
||||
ReplacementDictionary.Add(kvp.key, kvp.value);
|
||||
});
|
||||
public OptionItem RemoveReplacement(string key)
|
||||
=> Do(i => ReplacementDictionary?.Remove(key));
|
||||
|
||||
public virtual string GetName(bool disableColor = false)
|
||||
{
|
||||
return disableColor ?
|
||||
Name :
|
||||
Utils.ColorString(NameColor, Name);
|
||||
}
|
||||
public virtual bool GetBool() => CurrentValue != 0 && (Parent == null || Parent.GetBool());
|
||||
public virtual int GetInt() => CurrentValue;
|
||||
public virtual float GetFloat() => CurrentValue;
|
||||
public virtual string GetString()
|
||||
{
|
||||
return ApplyFormat(CurrentValue.ToString());
|
||||
}
|
||||
public virtual int GetValue() => CurrentEntry.Value;
|
||||
|
||||
public virtual bool IsHiddenOn()
|
||||
{
|
||||
return IsHidden;
|
||||
}
|
||||
|
||||
public string ApplyFormat(string value)
|
||||
{
|
||||
if (ValueFormat == OptionFormat.Players) return value + " players";
|
||||
if (ValueFormat == OptionFormat.Seconds) return value + "s";
|
||||
if (ValueFormat == OptionFormat.Percent) return value + "%";
|
||||
if (ValueFormat == OptionFormat.Multiplier) return value + "x";
|
||||
return value;
|
||||
}
|
||||
|
||||
public virtual void Refresh()
|
||||
{
|
||||
if (OptionBehaviour is not null and StringOption opt)
|
||||
{
|
||||
opt.TitleText.text = GetName();
|
||||
opt.ValueText.text = GetString();
|
||||
opt.oldValue = opt.Value = CurrentValue;
|
||||
}
|
||||
}
|
||||
public virtual void SetValue(int value)
|
||||
{
|
||||
int beforeValue = CurrentEntry.Value;
|
||||
int afterValue = CurrentEntry.Value = value;
|
||||
|
||||
CallUpdateValueEvent(beforeValue, afterValue);
|
||||
Refresh();
|
||||
SyncAllOptions();
|
||||
}
|
||||
|
||||
public static OptionItem operator ++(OptionItem item)
|
||||
=> item.Do(item => item.SetValue(item.CurrentValue + 1));
|
||||
public static OptionItem operator --(OptionItem item)
|
||||
=> item.Do(item => item.SetValue(item.CurrentValue - 1));
|
||||
|
||||
public static void SwitchPreset(int newPreset)
|
||||
{
|
||||
CurrentPreset = Math.Clamp(newPreset, 0, 1);
|
||||
|
||||
foreach (var op in AllOptions)
|
||||
op.Refresh();
|
||||
|
||||
SyncAllOptions();
|
||||
}
|
||||
public static void SyncAllOptions()
|
||||
{
|
||||
if (
|
||||
PlayerControl.AllPlayerControls.Count <= 1 ||
|
||||
AmongUsClient.Instance.AmHost == false ||
|
||||
PlayerControl.LocalPlayer == null
|
||||
) return;
|
||||
|
||||
GameManager.Instance.RpcSyncCustomOptions();
|
||||
}
|
||||
|
||||
|
||||
private void CallUpdateValueEvent(int beforeValue, int currentValue)
|
||||
{
|
||||
if (UpdateValueEvent == null) return;
|
||||
UpdateValueEvent(this, new UpdateValueEventArgs(beforeValue, currentValue));
|
||||
}
|
||||
|
||||
public class UpdateValueEventArgs : EventArgs
|
||||
{
|
||||
public int CurrentValue { get; set; }
|
||||
public int BeforeValue { get; set; }
|
||||
public UpdateValueEventArgs(int beforeValue, int currentValue)
|
||||
{
|
||||
CurrentValue = currentValue;
|
||||
BeforeValue = beforeValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum TabGroup
|
||||
{
|
||||
ModSettings,
|
||||
GameModifiers,
|
||||
|
||||
}
|
||||
|
||||
public enum OptionFormat
|
||||
{
|
||||
None,
|
||||
Players,
|
||||
Seconds,
|
||||
Percent,
|
||||
Multiplier,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionItems/StringOptionItem.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public class StringOptionItem : OptionItem
|
||||
{
|
||||
public IntegerValueRule Rule;
|
||||
public string[] Selections;
|
||||
|
||||
public StringOptionItem(int id, string name, int defaultValue, TabGroup tab, bool isSingleValue, string[] selections)
|
||||
: base(id, name, defaultValue, tab, isSingleValue)
|
||||
{
|
||||
Rule = (0, selections.Length - 1, 1);
|
||||
Selections = selections;
|
||||
}
|
||||
public static StringOptionItem Create(
|
||||
int id, string name, string[] selections, int defaultIndex, TabGroup tab, bool isSingleValue
|
||||
)
|
||||
{
|
||||
return new StringOptionItem(
|
||||
id, name, defaultIndex, tab, isSingleValue, selections
|
||||
);
|
||||
}
|
||||
|
||||
public override int GetInt() => Rule.GetValueByIndex(CurrentValue);
|
||||
public override float GetFloat() => Rule.GetValueByIndex(CurrentValue);
|
||||
public override string GetString()
|
||||
{
|
||||
return Selections[Rule.GetValueByIndex(CurrentValue)];
|
||||
}
|
||||
public int GetChance()
|
||||
{
|
||||
if (Selections.Length == 2) return CurrentValue * 100;
|
||||
|
||||
var offset = 12 - Selections.Length;
|
||||
var index = CurrentValue + offset;
|
||||
var rate = index <= 1 ? index * 5 : (index - 1) * 10;
|
||||
return rate;
|
||||
}
|
||||
public override int GetValue()
|
||||
=> Rule.RepeatIndex(base.GetValue());
|
||||
|
||||
public override void SetValue(int value)
|
||||
{
|
||||
base.SetValue(Rule.RepeatIndex(value));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
// https://github.com/Yumenopai/TownOfHost_Y/blob/main/Modules/OptionItem/TextOptionItem.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public class TextOptionItem : OptionItem
|
||||
{
|
||||
public FloatValueRule Rule;
|
||||
|
||||
public TextOptionItem(int id, string name, TabGroup tab)
|
||||
: base(id, name, 0, tab, true)
|
||||
{
|
||||
IsText = true;
|
||||
}
|
||||
public static TextOptionItem Create(
|
||||
int id, string name, TabGroup tab
|
||||
)
|
||||
{
|
||||
return new TextOptionItem(
|
||||
id, name, tab
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
|
||||
// https://github.com/tukasa0001/TownOfHost/blob/main/Modules/OptionItems/ValueRule.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public abstract class ValueRule<T>
|
||||
{
|
||||
public T MinValue { get; protected set; }
|
||||
public T MaxValue { get; protected set; }
|
||||
public T Step { get; protected set; }
|
||||
|
||||
public ValueRule(T minValue, T maxValue, T step)
|
||||
{
|
||||
MinValue = minValue;
|
||||
MaxValue = maxValue;
|
||||
Step = step;
|
||||
}
|
||||
public ValueRule((T, T, T) tuple)
|
||||
: this(tuple.Item1, tuple.Item2, tuple.Item3)
|
||||
{ }
|
||||
|
||||
public abstract int RepeatIndex(int value);
|
||||
public abstract T GetValueByIndex(int index);
|
||||
public abstract int GetNearestIndex(T num);
|
||||
}
|
||||
|
||||
public class IntegerValueRule : ValueRule<int>
|
||||
{
|
||||
public IntegerValueRule(int minValue, int maxValue, int step)
|
||||
: base(minValue, maxValue, step) { }
|
||||
public IntegerValueRule((int, int, int) tuple)
|
||||
: base(tuple) { }
|
||||
|
||||
public static implicit operator IntegerValueRule((int, int, int) tuple)
|
||||
=> new(tuple);
|
||||
|
||||
public override int RepeatIndex(int value)
|
||||
{
|
||||
int MaxIndex = (MaxValue - MinValue) / Step;
|
||||
value = value % (MaxIndex + 1);
|
||||
if (value < 0) value = MaxIndex;
|
||||
return value;
|
||||
}
|
||||
|
||||
public override int GetValueByIndex(int index)
|
||||
=> RepeatIndex(index) * Step + MinValue;
|
||||
|
||||
public override int GetNearestIndex(int num)
|
||||
{
|
||||
return (int)Math.Round((num - MinValue) / (float)Step);
|
||||
}
|
||||
}
|
||||
|
||||
public class FloatValueRule : ValueRule<float>
|
||||
{
|
||||
public FloatValueRule(float minValue, float maxValue, float step)
|
||||
: base(minValue, maxValue, step) { }
|
||||
public FloatValueRule((float, float, float) tuple)
|
||||
: base(tuple) { }
|
||||
|
||||
public static implicit operator FloatValueRule((float, float, float) tuple)
|
||||
=> new(tuple);
|
||||
|
||||
public override int RepeatIndex(int value)
|
||||
{
|
||||
int MaxIndex = (int)((MaxValue - MinValue) / Step);
|
||||
value = value % (MaxIndex + 1);
|
||||
if (value < 0) value = MaxIndex;
|
||||
return value;
|
||||
}
|
||||
|
||||
public override float GetValueByIndex(int index)
|
||||
=> RepeatIndex(index) * Step + MinValue;
|
||||
|
||||
public override int GetNearestIndex(float num)
|
||||
{
|
||||
return (int)Math.Round((num - MinValue) / Step);
|
||||
}
|
||||
}
|
||||
}
|
||||
+110
@@ -0,0 +1,110 @@
|
||||
using HarmonyLib;
|
||||
using Hazel;
|
||||
using InnerNet;
|
||||
using UnityEngine;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public enum CustomRPC
|
||||
{
|
||||
SyncCustomOptions,
|
||||
AddCustomSettingsChangeMessage,
|
||||
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameManager), nameof(GameManager.HandleRpc))]
|
||||
class GameManagerHandleRpc
|
||||
{
|
||||
public static void Postfix(GameManager __instance, [HarmonyArgument(0)] byte callId, [HarmonyArgument(1)] MessageReader reader)
|
||||
{
|
||||
if (callId < 70) return;
|
||||
var rpcType = (CustomRPC)callId;
|
||||
switch (rpcType)
|
||||
{
|
||||
case CustomRPC.SyncCustomOptions:
|
||||
for (int i = reader.ReadInt32(); i < OptionItem.AllOptions.Count; ++i)
|
||||
{
|
||||
if (reader.BytesRemaining == 0) break;
|
||||
var co = OptionItem.AllOptions[i];
|
||||
if (co is TextOptionItem) continue;
|
||||
if (co.Id == 0)
|
||||
{
|
||||
co.SetValue(9);
|
||||
continue;
|
||||
}
|
||||
if (co.Id >= 1000 && co.IsHiddenOn()) continue;
|
||||
co.SetValue(reader.ReadInt32());
|
||||
}
|
||||
var viewSettingsPane = Object.FindObjectOfType<LobbyViewSettingsPane>();
|
||||
if (viewSettingsPane != null)
|
||||
{
|
||||
if (viewSettingsPane.currentTab != StringNames.OverviewCategory && viewSettingsPane.currentTab != StringNames.RolesCategory)
|
||||
viewSettingsPane.ChangeTab(viewSettingsPane.currentTab);
|
||||
LobbyViewPatch.ReCreateButtons(viewSettingsPane);
|
||||
}
|
||||
break;
|
||||
case CustomRPC.AddCustomSettingsChangeMessage:
|
||||
int optionId = reader.ReadInt32();
|
||||
var optionItem = OptionItem.AllOptions.FirstOrDefault(opt => opt.Id == optionId);
|
||||
if (optionItem == null) break;
|
||||
__instance.AddCustomSettingsChangeMessage(optionItem, reader.ReadString(), reader.ReadBoolean());
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static class RPC
|
||||
{
|
||||
|
||||
public static void AddCustomSettingsChangeMessage(this GameManager manager, OptionItem optionItem, string value, bool playSound)
|
||||
{
|
||||
string optionName = "";
|
||||
if (optionItem.Parent?.Parent?.Parent != null)
|
||||
optionName += optionItem.Parent.Parent.Parent.GetOptionNameSCM() + " → ";
|
||||
if (optionItem.Parent?.Parent != null)
|
||||
optionName += optionItem.Parent.Parent.GetOptionNameSCM() + " → ";
|
||||
if (optionItem.Parent != null)
|
||||
optionName += optionItem.Parent.GetOptionNameSCM() + " → ";
|
||||
optionName += optionItem.GetOptionNameSCM();
|
||||
string text = $"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">{optionName}</font>: <font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">{value}</font>";
|
||||
HudManager.Instance.Notifier.CustomSettingsChangeMessageLogic(optionItem, text, playSound);
|
||||
}
|
||||
|
||||
|
||||
public static void RpcSyncCustomOptions(this GameManager manager)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(manager.NetId, (byte)CustomRPC.SyncCustomOptions, SendOption.Reliable, -1);
|
||||
writer.Write(0);
|
||||
for (int i = 0; i < OptionItem.AllOptions.Count; ++i)
|
||||
{
|
||||
var co = OptionItem.AllOptions[i];
|
||||
if (co.Id == 0 || co is TextOptionItem) continue;
|
||||
if (co.Id >= 1000 && co.IsHiddenOn()) continue;
|
||||
if (writer.Length > 500)
|
||||
{
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
writer = AmongUsClient.Instance.StartRpcImmediately(manager.NetId, (byte)CustomRPC.SyncCustomOptions, SendOption.Reliable, -1);
|
||||
writer.Write(i);
|
||||
}
|
||||
writer.Write(co.CurrentValue);
|
||||
}
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public static void RpcAddCustomSettingsChangeMessage(this GameManager manager, OptionItem optionItem, string value, bool playSound)
|
||||
{
|
||||
manager.AddCustomSettingsChangeMessage(optionItem, value, playSound);
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(manager.NetId, (byte)CustomRPC.AddCustomSettingsChangeMessage, SendOption.Reliable, -1);
|
||||
writer.Write(optionItem.Id);
|
||||
writer.Write(value);
|
||||
writer.Write(playSound);
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
}
|
||||
}
|
||||
+87
-4
@@ -1,8 +1,91 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Data;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using InnerNet;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System;
|
||||
using System.Security.Cryptography;
|
||||
using System.Text;
|
||||
using AmongUs.InnerNet.GameDataMessages;
|
||||
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace HNSRevamped;
|
||||
|
||||
public static class Utils
|
||||
{
|
||||
public static bool isHideNSeek => GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.HideNSeek;
|
||||
}
|
||||
public static class Utils
|
||||
{
|
||||
public static bool isHideNSeek => GameOptionsManager.Instance.CurrentGameOptions.GameMode == GameModes.HideNSeek;
|
||||
|
||||
public static string ColorString(Color32 color, string str) => $"<#{color.r:x2}{color.g:x2}{color.b:x2}{color.a:x2}>{str}</color>";
|
||||
public static string ColorToHex(Color32 color) => $"#{color.r:x2}{color.g:x2}{color.b:x2}{color.a:x2}";
|
||||
|
||||
|
||||
|
||||
public static string GetTabName(TabGroup tab)
|
||||
{
|
||||
switch (tab)
|
||||
{
|
||||
case TabGroup.ModSettings:
|
||||
return "Mod Settings";
|
||||
case TabGroup.GameModifiers:
|
||||
return "Game Modifiers";
|
||||
|
||||
default:
|
||||
return "";
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyTranslator(this GameObject obj)
|
||||
{
|
||||
var translator = obj.GetComponent<TextTranslatorTMP>();
|
||||
if (translator != null)
|
||||
{
|
||||
Object.Destroy(translator);
|
||||
}
|
||||
}
|
||||
|
||||
public static void DestroyTranslator(this MonoBehaviour obj) => obj.gameObject.DestroyTranslator();
|
||||
|
||||
public static void CustomSettingsChangeMessageLogic(this NotificationPopper notificationPopper, OptionItem optionItem, string text, bool playSound)
|
||||
{
|
||||
if (notificationPopper.lastMessageKey == 10000 + optionItem.Id && notificationPopper.activeMessages.Count > 0)
|
||||
{
|
||||
notificationPopper.activeMessages[notificationPopper.activeMessages.Count - 1].UpdateMessage(text);
|
||||
}
|
||||
else
|
||||
{
|
||||
notificationPopper.lastMessageKey = 10000 + optionItem.Id;
|
||||
LobbyNotificationMessage settingmessage = Object.Instantiate(notificationPopper.notificationMessageOrigin, Vector3.zero, Quaternion.identity, notificationPopper.transform);
|
||||
settingmessage.transform.localPosition = new Vector3(0f, 0f, -2f);
|
||||
settingmessage.SetUp(text, notificationPopper.settingsChangeSprite, notificationPopper.settingsChangeColor, new Action(() =>
|
||||
{
|
||||
notificationPopper.OnMessageDestroy(settingmessage);
|
||||
}));
|
||||
notificationPopper.ShiftMessages();
|
||||
notificationPopper.AddMessageToQueue(settingmessage);
|
||||
}
|
||||
if (playSound)
|
||||
{
|
||||
SoundManager.Instance.PlaySoundImmediate(notificationPopper.settingsChangeSound, false, 1f, 1f, null);
|
||||
}
|
||||
}
|
||||
|
||||
public static string GetOptionNameSCM(this OptionItem optionItem)
|
||||
{
|
||||
if (optionItem.Name == "Enable")
|
||||
{
|
||||
int id = optionItem.Id;
|
||||
while (id % 10 != 0)
|
||||
--id;
|
||||
var optionItem2 = OptionItem.AllOptions.FirstOrDefault(opt => opt.Id == id);
|
||||
return optionItem2 != null ? optionItem2.GetName() : optionItem.GetName();
|
||||
}
|
||||
else
|
||||
return optionItem.GetName();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,536 @@
|
||||
using System;
|
||||
using Il2CppSystem.Collections.Generic;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
// https://github.com/Yumenopai/TownOfHost_Y/blob/main/Patches/GameOptionsPatch.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
public static class ModGameOptionsMenu
|
||||
{
|
||||
public static int TabIndex = 0;
|
||||
public static Dictionary<OptionBehaviour, int> OptionList = new();
|
||||
public static Dictionary<int, OptionBehaviour> BehaviourList = new();
|
||||
public static Dictionary<int, CategoryHeaderMasked> CategoryHeaderList = new();
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(GameOptionsMenu))]
|
||||
public static class GameOptionsMenuPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.Initialize)), HarmonyPrefix]
|
||||
private static bool InitializePrefix(GameOptionsMenu __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.TabIndex < 3) return true;
|
||||
if (__instance.Children == null || __instance.Children.Count == 0)
|
||||
{
|
||||
__instance.MapPicker.gameObject.SetActive(false);
|
||||
__instance.Children = new List<OptionBehaviour>();
|
||||
__instance.CreateSettings();
|
||||
__instance.cachedData = GameOptionsManager.Instance.CurrentGameOptions;
|
||||
for (int i = 0; i < __instance.Children.Count; i++)
|
||||
{
|
||||
OptionBehaviour optionBehaviour = __instance.Children[i];
|
||||
optionBehaviour.OnValueChanged = new Action<OptionBehaviour>(__instance.ValueChanged);
|
||||
}
|
||||
__instance.InitializeControllerNavigation();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.CreateSettings)), HarmonyPrefix]
|
||||
private static bool CreateSettingsPrefix(GameOptionsMenu __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.TabIndex < 3) return true;
|
||||
var modTab = (TabGroup)(ModGameOptionsMenu.TabIndex - 3);
|
||||
float num = 2.0f;
|
||||
const float pos_x = 0.952f;
|
||||
const float pos_z = -2.0f;
|
||||
for (int index = 0; index < OptionItem.AllOptions.Count; index++)
|
||||
{
|
||||
var option = OptionItem.AllOptions[index];
|
||||
if (option.Tab != modTab) continue;
|
||||
|
||||
var enabled = !option.IsHiddenOn() && (option.Parent == null || (!option.Parent.IsHiddenOn() && option.Parent.GetBool()));
|
||||
if (option.IsHeader || option is TextOptionItem)
|
||||
{
|
||||
CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||
categoryHeaderMasked.SetHeader(StringNames.RolesCategory, 20);
|
||||
categoryHeaderMasked.Title.text = option.GetName();
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one * 0.63f;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, pos_z);
|
||||
categoryHeaderMasked.transform.FindChild("HeaderText").GetComponent<TMPro.TextMeshPro>().fontStyle = TMPro.FontStyles.Bold;
|
||||
categoryHeaderMasked.transform.FindChild("HeaderText").GetComponent<TMPro.TextMeshPro>().outlineWidth = 0.17f;
|
||||
categoryHeaderMasked.gameObject.SetActive(enabled);
|
||||
ModGameOptionsMenu.CategoryHeaderList.TryAdd(index, categoryHeaderMasked);
|
||||
if (enabled) num -= 0.63f;
|
||||
}
|
||||
if (option is TextOptionItem) continue;
|
||||
var baseGameSetting = GetSetting(option);
|
||||
if (baseGameSetting == null) continue;
|
||||
|
||||
OptionBehaviour optionBehaviour;
|
||||
switch (baseGameSetting.Type)
|
||||
{
|
||||
case OptionTypes.Checkbox:
|
||||
{
|
||||
optionBehaviour = Object.Instantiate(__instance.checkboxOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||
optionBehaviour.transform.localPosition = new Vector3(pos_x, num, pos_z);
|
||||
OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type);
|
||||
optionBehaviour.SetClickMask(__instance.ButtonClickMask);
|
||||
optionBehaviour.SetUpFromData(baseGameSetting, 20);
|
||||
ModGameOptionsMenu.OptionList.TryAdd(optionBehaviour, index);
|
||||
break;
|
||||
}
|
||||
case OptionTypes.String:
|
||||
{
|
||||
optionBehaviour = Object.Instantiate(__instance.stringOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||
optionBehaviour.transform.localPosition = new Vector3(pos_x, num, pos_z);
|
||||
OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type);
|
||||
optionBehaviour.SetClickMask(__instance.ButtonClickMask);
|
||||
optionBehaviour.SetUpFromData(baseGameSetting, 20);
|
||||
ModGameOptionsMenu.OptionList.TryAdd(optionBehaviour, index);
|
||||
break;
|
||||
}
|
||||
case OptionTypes.Float:
|
||||
case OptionTypes.Int:
|
||||
{
|
||||
optionBehaviour = Object.Instantiate(__instance.numberOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer);
|
||||
optionBehaviour.transform.localPosition = new Vector3(pos_x, num, pos_z);
|
||||
OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type);
|
||||
optionBehaviour.SetClickMask(__instance.ButtonClickMask);
|
||||
optionBehaviour.SetUpFromData(baseGameSetting, 20);
|
||||
ModGameOptionsMenu.OptionList.TryAdd(optionBehaviour, index);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||
optionBehaviour.SetClickMask(__instance.ButtonClickMask);
|
||||
optionBehaviour.SetUpFromData(baseGameSetting, 20);
|
||||
ModGameOptionsMenu.OptionList.TryAdd(optionBehaviour, index);
|
||||
ModGameOptionsMenu.BehaviourList.TryAdd(index, optionBehaviour);
|
||||
optionBehaviour.gameObject.SetActive(enabled);
|
||||
__instance.Children.Add(optionBehaviour);
|
||||
if (enabled) num -= 0.45f;
|
||||
}
|
||||
__instance.ControllerSelectable.Clear();
|
||||
foreach (var x in __instance.scrollBar.GetComponentsInChildren<UiElement>())
|
||||
__instance.ControllerSelectable.Add(x);
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
||||
return false;
|
||||
}
|
||||
private static void OptionBehaviourSetSizeAndPosition(OptionBehaviour optionBehaviour, OptionItem option, OptionTypes type)
|
||||
{
|
||||
Vector3 positionOffset = new(0f, 0f, 0f);
|
||||
Vector3 scaleOffset = new(0f, 0f, 0f);
|
||||
Color color = new(0.7f, 0.7f, 0.7f);
|
||||
float sizeDelta_x = 5.7f;
|
||||
if (option.Parent?.Parent?.Parent != null)
|
||||
{
|
||||
scaleOffset = new(-0.18f, 0, 0);
|
||||
positionOffset = new(0.3f, 0f, 0f);
|
||||
color = new(0.7f, 0.5f, 0.5f);
|
||||
sizeDelta_x = 5.1f;
|
||||
}
|
||||
else if (option.Parent?.Parent != null)
|
||||
{
|
||||
scaleOffset = new(-0.12f, 0, 0);
|
||||
positionOffset = new(0.2f, 0f, 0f);
|
||||
color = new(0.5f, 0.5f, 0.7f);
|
||||
sizeDelta_x = 5.3f;
|
||||
}
|
||||
else if (option.Parent != null)
|
||||
{
|
||||
scaleOffset = new(-0.05f, 0, 0);
|
||||
positionOffset = new(0.1f, 0f, 0f);
|
||||
color = new(0.5f, 0.7f, 0.5f);
|
||||
sizeDelta_x = 5.5f;
|
||||
}
|
||||
optionBehaviour.transform.FindChild("LabelBackground").GetComponent<SpriteRenderer>().color = color;
|
||||
optionBehaviour.transform.FindChild("LabelBackground").localScale += new Vector3(0.9f, -0.2f, 0f) + scaleOffset;
|
||||
optionBehaviour.transform.FindChild("LabelBackground").localPosition += new Vector3(-0.4f, 0f, 0f) + positionOffset;
|
||||
optionBehaviour.transform.FindChild("Title Text").localPosition += new Vector3(-0.4f, 0f, 0f) + positionOffset; ;
|
||||
optionBehaviour.transform.FindChild("Title Text").GetComponent<RectTransform>().sizeDelta = new Vector2(sizeDelta_x, 0.37f);
|
||||
optionBehaviour.transform.FindChild("Title Text").GetComponent<TMPro.TextMeshPro>().alignment = TMPro.TextAlignmentOptions.MidlineLeft;
|
||||
optionBehaviour.transform.FindChild("Title Text").GetComponent<TMPro.TextMeshPro>().fontStyle = TMPro.FontStyles.Bold;
|
||||
optionBehaviour.transform.FindChild("Title Text").GetComponent<TMPro.TextMeshPro>().outlineWidth = 0.17f;
|
||||
switch (type)
|
||||
{
|
||||
case OptionTypes.Checkbox:
|
||||
optionBehaviour.transform.FindChild("Toggle").localPosition = new Vector3(1.46f, -0.042f);
|
||||
break;
|
||||
case OptionTypes.String:
|
||||
optionBehaviour.transform.FindChild("PlusButton").localPosition += new Vector3(1.7f, 0f, 0f);
|
||||
optionBehaviour.transform.FindChild("MinusButton").localPosition += new Vector3(0.9f, 0f, 0f);
|
||||
optionBehaviour.transform.FindChild("Value_TMP (1)").localPosition += new Vector3(1.3f, 0f, 0f);
|
||||
optionBehaviour.transform.FindChild("Value_TMP (1)").GetComponent<RectTransform>().sizeDelta = new Vector2(2.3f, 0.4f);
|
||||
goto default;
|
||||
case OptionTypes.Float:
|
||||
case OptionTypes.Int:
|
||||
optionBehaviour.transform.FindChild("PlusButton").localPosition += new Vector3(1.7f, 0f, 0f);
|
||||
optionBehaviour.transform.FindChild("MinusButton").localPosition += new Vector3(0.9f, 0f, 0f);
|
||||
optionBehaviour.transform.FindChild("Value_TMP").localPosition += new Vector3(1.3f, 0f, 0f);
|
||||
goto default;
|
||||
default:
|
||||
optionBehaviour.transform.FindChild("ValueBox").localScale += new Vector3(0.2f, 0f, 0f);
|
||||
optionBehaviour.transform.FindChild("ValueBox").localPosition += new Vector3(1.3f, 0f, 0f);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameOptionsMenu.ValueChanged)), HarmonyPrefix]
|
||||
private static bool ValueChangedPrefix(GameOptionsMenu __instance, OptionBehaviour option)
|
||||
{
|
||||
if (ModGameOptionsMenu.TabIndex < 3) return true;
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(option, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
if (item != null)
|
||||
{
|
||||
if (item is BooleanOptionItem)
|
||||
GameManager.Instance.RpcAddCustomSettingsChangeMessage(item, item.GetBool() ? "On" : "Off", true);
|
||||
else
|
||||
GameManager.Instance.RpcAddCustomSettingsChangeMessage(item, item.GetString(), true);
|
||||
if (item.Id == 0)
|
||||
{
|
||||
ReOpenSettingMenu();
|
||||
var viewSettingsPane = Object.FindObjectOfType<LobbyViewSettingsPane>();
|
||||
if (viewSettingsPane != null)
|
||||
LobbyViewPatch.ReCreateButtons(viewSettingsPane);
|
||||
}
|
||||
else if (item.Id == 2)
|
||||
{
|
||||
ReOpenSettingMenu();
|
||||
var viewSettingsPane = Object.FindObjectOfType<LobbyViewSettingsPane>();
|
||||
if (viewSettingsPane != null)
|
||||
LobbyViewPatch.ReCreateButtons(viewSettingsPane);
|
||||
}
|
||||
else if (item.Children.Count > 0)
|
||||
ReCreateSettings(__instance);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private static void ReCreateSettings(GameOptionsMenu __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.TabIndex < 3) return;
|
||||
var modTab = (TabGroup)(ModGameOptionsMenu.TabIndex - 3);
|
||||
float num = 2.0f;
|
||||
for (int index = 0; index < OptionItem.AllOptions.Count; index++)
|
||||
{
|
||||
var option = OptionItem.AllOptions[index];
|
||||
if (option.Tab != modTab) continue;
|
||||
var enabled = !option.IsHiddenOn() && (option.Parent == null || (!option.Parent.IsHiddenOn() && option.Parent.GetBool()));
|
||||
|
||||
if (ModGameOptionsMenu.CategoryHeaderList.TryGetValue(index, out var categoryHeaderMasked))
|
||||
{
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-0.903f, num, -2f);
|
||||
categoryHeaderMasked.gameObject.SetActive(enabled);
|
||||
if (enabled) num -= 0.63f;
|
||||
}
|
||||
if (ModGameOptionsMenu.BehaviourList.TryGetValue(index, out var optionBehaviour))
|
||||
{
|
||||
optionBehaviour.transform.localPosition = new Vector3(0.952f, num, -2f);
|
||||
optionBehaviour.gameObject.SetActive(enabled);
|
||||
if (enabled) num -= 0.45f;
|
||||
}
|
||||
}
|
||||
__instance.ControllerSelectable.Clear();
|
||||
foreach (var x in __instance.scrollBar.GetComponentsInChildren<UiElement>())
|
||||
__instance.ControllerSelectable.Add(x);
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
|
||||
}
|
||||
|
||||
public static BaseGameSetting GetSetting(OptionItem item)
|
||||
{
|
||||
BaseGameSetting baseGameSetting = null;
|
||||
if (item is BooleanOptionItem)
|
||||
{
|
||||
baseGameSetting = new CheckboxGameSetting
|
||||
{
|
||||
Type = OptionTypes.Checkbox,
|
||||
};
|
||||
}
|
||||
else if (item is IntegerOptionItem)
|
||||
{
|
||||
IntegerOptionItem intItem = item as IntegerOptionItem;
|
||||
baseGameSetting = new IntGameSetting
|
||||
{
|
||||
Type = OptionTypes.Int,
|
||||
Value = intItem.GetInt(),
|
||||
Increment = intItem.Rule.Step,
|
||||
ValidRange = new IntRange(intItem.Rule.MinValue, intItem.Rule.MaxValue),
|
||||
ZeroIsInfinity = false,
|
||||
SuffixType = NumberSuffixes.Multiplier,
|
||||
FormatString = string.Empty,
|
||||
};
|
||||
}
|
||||
else if (item is FloatOptionItem)
|
||||
{
|
||||
FloatOptionItem floatItem = item as FloatOptionItem;
|
||||
baseGameSetting = new FloatGameSetting
|
||||
{
|
||||
Type = OptionTypes.Float,
|
||||
Value = floatItem.GetFloat(),
|
||||
Increment = floatItem.Rule.Step,
|
||||
ValidRange = new FloatRange(floatItem.Rule.MinValue, floatItem.Rule.MaxValue),
|
||||
ZeroIsInfinity = false,
|
||||
SuffixType = NumberSuffixes.Multiplier,
|
||||
FormatString = string.Empty,
|
||||
};
|
||||
}
|
||||
else if (item is StringOptionItem)
|
||||
{
|
||||
StringOptionItem stringItem = item as StringOptionItem;
|
||||
baseGameSetting = new StringGameSetting
|
||||
{
|
||||
Type = OptionTypes.String,
|
||||
Values = new StringNames[stringItem.Selections.Length],
|
||||
Index = stringItem.GetInt(),
|
||||
};
|
||||
}
|
||||
if (baseGameSetting != null)
|
||||
baseGameSetting.Title = StringNames.Accept;
|
||||
return baseGameSetting;
|
||||
}
|
||||
|
||||
public static void ReOpenSettingMenu()
|
||||
{
|
||||
var tab = ModGameOptionsMenu.TabIndex;
|
||||
if (GameSettingMenu.Instance == null) return;
|
||||
GameSettingMenu.Instance.Close();
|
||||
OptionsConsole optionsConsole = null;
|
||||
foreach (var console in Object.FindObjectsOfType<OptionsConsole>())
|
||||
{
|
||||
if (console.HostOnly)
|
||||
optionsConsole = console;
|
||||
}
|
||||
if (optionsConsole == null) return;
|
||||
GameObject gameObject = Object.Instantiate(optionsConsole.MenuPrefab);
|
||||
gameObject.transform.SetParent(Camera.main.transform, false);
|
||||
gameObject.transform.localPosition = optionsConsole.CustomPosition;
|
||||
new LateTask(() => {
|
||||
if (GameSettingMenu.Instance == null) return;
|
||||
GameSettingMenu.Instance.ChangeTab(tab, false);
|
||||
}, 0f);
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(ToggleOption))]
|
||||
public static class ToggleOptionPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(ToggleOption.Initialize)), HarmonyPrefix]
|
||||
private static bool InitializePrefix(ToggleOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
__instance.TitleText.text = item.GetName();
|
||||
__instance.CheckMark.enabled = item.GetBool();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(ToggleOption.Toggle)), HarmonyPrefix]
|
||||
private static bool TogglePrefix(ToggleOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
__instance.CheckMark.enabled = !__instance.CheckMark.enabled;
|
||||
var item = OptionItem.AllOptions[index];
|
||||
item.SetValue(__instance.GetBool() ? 1 : 0);
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(NumberOption))]
|
||||
public static class NumberOptionPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(NumberOption.Initialize)), HarmonyPrefix]
|
||||
private static bool InitializePrefix(NumberOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
__instance.TitleText.text = item.GetName();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(NumberOption.UpdateValue)), HarmonyPrefix]
|
||||
private static bool UpdateValuePrefix(NumberOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
if (item is IntegerOptionItem integerOptionItem)
|
||||
{
|
||||
integerOptionItem.SetValue(integerOptionItem.Rule.GetNearestIndex(__instance.GetInt()));
|
||||
}
|
||||
else if (item is FloatOptionItem floatOptionItem)
|
||||
{
|
||||
floatOptionItem.SetValue(floatOptionItem.Rule.GetNearestIndex(__instance.GetFloat()));
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(NumberOption.FixedUpdate)), HarmonyPrefix]
|
||||
private static bool FixedUpdatePrefix(NumberOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
if (__instance.oldValue != __instance.Value)
|
||||
{
|
||||
__instance.oldValue = __instance.Value;
|
||||
__instance.ValueText.text = item.GetString();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(NumberOption.Increase)), HarmonyPrefix]
|
||||
public static bool IncreasePrefix(NumberOption __instance)
|
||||
{
|
||||
if (__instance.Value == __instance.ValidRange.max)
|
||||
{
|
||||
__instance.Value = __instance.ValidRange.min;
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(NumberOption.Decrease)), HarmonyPrefix]
|
||||
public static bool DecreasePrefix(NumberOption __instance)
|
||||
{
|
||||
if (__instance.Value == __instance.ValidRange.min)
|
||||
{
|
||||
__instance.Value = __instance.ValidRange.max;
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(NumberOption.AdjustButtonsActiveState)), HarmonyPrefix]
|
||||
public static bool AdjustButtonsActiveStatePrefix(NumberOption __instance)
|
||||
{
|
||||
__instance.MinusBtn.SetInteractable(true);
|
||||
__instance.PlusBtn.SetInteractable(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(StringOption))]
|
||||
public static class StringOptionPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(StringOption.Initialize)), HarmonyPrefix]
|
||||
private static bool InitializePrefix(StringOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
__instance.TitleText.text = item.GetName();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(StringOption.UpdateValue)), HarmonyPrefix]
|
||||
private static bool UpdateValuePrefix(StringOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
item.SetValue(__instance.GetInt());
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(StringOption.FixedUpdate)), HarmonyPrefix]
|
||||
private static bool FixedUpdatePrefix(StringOption __instance)
|
||||
{
|
||||
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out var index))
|
||||
{
|
||||
var item = OptionItem.AllOptions[index];
|
||||
if (__instance.oldValue != __instance.Value)
|
||||
{
|
||||
__instance.oldValue = __instance.Value;
|
||||
__instance.ValueText.text = item.GetString();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(StringOption.Increase)), HarmonyPrefix]
|
||||
public static bool IncreasePrefix(StringOption __instance)
|
||||
{
|
||||
if (__instance.Value == __instance.Values.Length - 1)
|
||||
{
|
||||
__instance.Value = 0;
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(StringOption.Decrease)), HarmonyPrefix]
|
||||
public static bool DecreasePrefix(StringOption __instance)
|
||||
{
|
||||
if (__instance.Value == 0)
|
||||
{
|
||||
__instance.Value = __instance.Values.Length - 1;
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(StringOption.AdjustButtonsActiveState)), HarmonyPrefix]
|
||||
public static bool AdjustButtonsActiveStatePrefix(StringOption __instance)
|
||||
{
|
||||
__instance.MinusBtn.SetInteractable(true);
|
||||
__instance.PlusBtn.SetInteractable(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
[HarmonyPatch(typeof(PlayerOption))]
|
||||
public static class PlayerOptionPatch
|
||||
{
|
||||
[HarmonyPatch(nameof(PlayerOption.Increase)), HarmonyPrefix]
|
||||
public static bool IncreasePrefix(PlayerOption __instance)
|
||||
{
|
||||
if (__instance.Value == __instance.Values.Count - 1)
|
||||
{
|
||||
__instance.Value = -1;
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(PlayerOption.Decrease)), HarmonyPrefix]
|
||||
public static bool DecreasePrefix(PlayerOption __instance)
|
||||
{
|
||||
if (__instance.Value < 0)
|
||||
{
|
||||
__instance.Value = __instance.Values.Count - 1;
|
||||
__instance.UpdateValue();
|
||||
__instance.OnValueChanged.Invoke(__instance);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
[HarmonyPatch(nameof(PlayerOption.AdjustButtonsActiveState)), HarmonyPrefix]
|
||||
public static bool AdjustButtonsActiveStatePrefix(PlayerOption __instance)
|
||||
{
|
||||
__instance.MinusBtn.SetInteractable(true);
|
||||
__instance.PlusBtn.SetInteractable(true);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,183 @@
|
||||
using System;
|
||||
using HarmonyLib;
|
||||
using System.Collections.Generic;
|
||||
using TMPro;
|
||||
using UnityEngine;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
// https://github.com/Yumenopai/TownOfHost_Y/blob/main/Patches/GameSettingMenuPatch.cs
|
||||
namespace HNSRevamped
|
||||
{
|
||||
[HarmonyPatch(typeof(GameSettingMenu))]
|
||||
public class GameSettingMenuPatch
|
||||
{
|
||||
private static GameOptionsMenu templateGameOptionsMenu;
|
||||
private static PassiveButton templateGameSettingsButton;
|
||||
static Dictionary<TabGroup, PassiveButton> ModSettingsButtons = new();
|
||||
static Dictionary<TabGroup, GameOptionsMenu> ModSettingsTabs = new();
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.Start)), HarmonyPrefix]
|
||||
[HarmonyPriority(Priority.First)]
|
||||
public static void StartPostfix(GameSettingMenu __instance)
|
||||
{
|
||||
ModSettingsButtons = new();
|
||||
int tabNum = 0;
|
||||
foreach (var tab in Enum.GetValues<TabGroup>())
|
||||
{
|
||||
|
||||
var button = Object.Instantiate(templateGameSettingsButton, __instance.GameSettingsButton.transform.parent);
|
||||
button.gameObject.SetActive(true);
|
||||
button.name = "Button_" + Utils.GetTabName(tab);
|
||||
var label = button.GetComponentInChildren<TextMeshPro>();
|
||||
label.DestroyTranslator();
|
||||
label.text = Utils.GetTabName(tab);
|
||||
|
||||
Vector3 offset = new (0.0f, 0.5f * (tabNum / 2), 0.0f);
|
||||
button.transform.localPosition = ((tabNum % 2 == 0) ? new Vector3(-3.9f, -0.9f, 0f) : new Vector3(-2.4f, -0.9f, 0f)) - offset;
|
||||
button.transform.localScale = new(0.45f, 0.6f, 1f);
|
||||
|
||||
var buttonComponent = button.GetComponent<PassiveButton>();
|
||||
buttonComponent.OnClick = new();
|
||||
buttonComponent.OnClick.AddListener((Action)(() => __instance.ChangeTab((int)tab + 3, false)));
|
||||
ModSettingsButtons.Add(tab, button);
|
||||
++tabNum;
|
||||
}
|
||||
|
||||
ModGameOptionsMenu.OptionList = new();
|
||||
ModGameOptionsMenu.BehaviourList = new();
|
||||
ModGameOptionsMenu.CategoryHeaderList = new();
|
||||
|
||||
ModSettingsTabs = new();
|
||||
foreach (var tab in Enum.GetValues<TabGroup>())
|
||||
{
|
||||
var setTab = Object.Instantiate(templateGameOptionsMenu, __instance.GameSettingsTab.transform.parent);
|
||||
setTab.name = Utils.GetTabName(tab);
|
||||
setTab.gameObject.SetActive(false);
|
||||
ModSettingsTabs.Add(tab, setTab);
|
||||
}
|
||||
foreach (var tab in Enum.GetValues<TabGroup>())
|
||||
{
|
||||
if (ModSettingsButtons.TryGetValue(tab, out var button))
|
||||
__instance.ControllerSelectable.Add(button);
|
||||
}
|
||||
}
|
||||
private static void SetDefaultButton(GameSettingMenu __instance)
|
||||
{
|
||||
var gamepreset = __instance.GamePresetsButton;
|
||||
gamepreset.gameObject.SetActive(false);
|
||||
|
||||
var gamesettings = __instance.GameSettingsButton;
|
||||
gamesettings.transform.localScale = new Vector3(0.45f, 0.6f, 1f);
|
||||
gamesettings.transform.localPosition = new Vector3(-3.9f, -0.4f, 0f);
|
||||
|
||||
var rolesettings = __instance.RoleSettingsButton;
|
||||
rolesettings.transform.localScale = new Vector3(0.45f, 0.6f, 1f);
|
||||
rolesettings.transform.localPosition = new(-2.4f, -0.4f, 0f);
|
||||
var label = rolesettings.GetComponentInChildren<TextMeshPro>();
|
||||
label.DestroyTranslator();
|
||||
label.text = "Vanilla Roles";
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab)), HarmonyPrefix]
|
||||
public static bool ChangeTabPrefix(GameSettingMenu __instance, ref int tabNum, [HarmonyArgument(1)] bool previewOnly)
|
||||
{
|
||||
if (!previewOnly)
|
||||
ModGameOptionsMenu.TabIndex = tabNum;
|
||||
GameOptionsMenu settingsTab;
|
||||
PassiveButton button;
|
||||
|
||||
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
|
||||
{
|
||||
foreach (var tab in Enum.GetValues<TabGroup>())
|
||||
{
|
||||
if (ModSettingsTabs.TryGetValue(tab, out settingsTab) && settingsTab != null)
|
||||
settingsTab.gameObject.SetActive(false);
|
||||
}
|
||||
foreach (var tab in Enum.GetValues<TabGroup>())
|
||||
{
|
||||
if (ModSettingsButtons.TryGetValue(tab, out button) && button != null)
|
||||
button.SelectButton(false);
|
||||
}
|
||||
}
|
||||
if (tabNum < 3) return true;
|
||||
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
|
||||
{
|
||||
__instance.PresetsTab.gameObject.SetActive(false);
|
||||
__instance.GameSettingsTab.gameObject.SetActive(false);
|
||||
__instance.RoleSettingsTab.gameObject.SetActive(false);
|
||||
__instance.GamePresetsButton.SelectButton(false);
|
||||
__instance.GameSettingsButton.SelectButton(false);
|
||||
__instance.RoleSettingsButton.SelectButton(false);
|
||||
|
||||
if (ModSettingsTabs.TryGetValue((TabGroup)(tabNum - 3), out settingsTab) && settingsTab != null)
|
||||
{
|
||||
settingsTab.gameObject.SetActive(true);
|
||||
__instance.MenuDescriptionText.DestroyTranslator();
|
||||
switch ((TabGroup)(tabNum - 3))
|
||||
{
|
||||
case TabGroup.ModSettings:
|
||||
__instance.MenuDescriptionText.text = "Mod Settings";
|
||||
break;
|
||||
case TabGroup.GameModifiers:
|
||||
__instance.MenuDescriptionText.text = "Game Modifiers";
|
||||
break;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
if (previewOnly)
|
||||
{
|
||||
__instance.ToggleLeftSideDarkener(false);
|
||||
__instance.ToggleRightSideDarkener(true);
|
||||
return false;
|
||||
}
|
||||
__instance.ToggleLeftSideDarkener(true);
|
||||
__instance.ToggleRightSideDarkener(false);
|
||||
if (ModSettingsButtons.TryGetValue((TabGroup)(tabNum - 3), out button) && button != null)
|
||||
button.SelectButton(true);
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.OnEnable)), HarmonyPrefix]
|
||||
private static bool OnEnablePrefix(GameSettingMenu __instance)
|
||||
{
|
||||
if (templateGameOptionsMenu == null)
|
||||
{
|
||||
templateGameOptionsMenu = Object.Instantiate(__instance.GameSettingsTab, __instance.GameSettingsTab.transform.parent);
|
||||
templateGameOptionsMenu.gameObject.SetActive(false);
|
||||
}
|
||||
if (templateGameSettingsButton == null)
|
||||
{
|
||||
templateGameSettingsButton = Object.Instantiate(__instance.GameSettingsButton, __instance.GameSettingsButton.transform.parent);
|
||||
templateGameSettingsButton.gameObject.SetActive(false);
|
||||
}
|
||||
SetDefaultButton(__instance);
|
||||
ControllerManager.Instance.OpenOverlayMenu(__instance.name, __instance.BackButton, __instance.DefaultButtonSelected, __instance.ControllerSelectable, false);
|
||||
DestroyableSingleton<HudManager>.Instance.menuNavigationPrompts.SetActive(false);
|
||||
if (Controller.currentTouchType != Controller.TouchType.Joystick)
|
||||
__instance.ChangeTab(1, Controller.currentTouchType == Controller.TouchType.Joystick);
|
||||
__instance.StartCoroutine(__instance.CoSelectDefault());
|
||||
return false;
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(GameSettingMenu.Close)), HarmonyPostfix]
|
||||
private static void ClosePostfix(GameSettingMenu __instance)
|
||||
{
|
||||
foreach (var button in ModSettingsButtons.Values)
|
||||
Object.Destroy(button);
|
||||
foreach (var tab in ModSettingsTabs.Values)
|
||||
Object.Destroy(tab);
|
||||
ModSettingsButtons = new();
|
||||
ModSettingsTabs = new();
|
||||
}
|
||||
}
|
||||
|
||||
[HarmonyPatch(typeof(PlayerControl), nameof(PlayerControl.RpcSyncSettings))]
|
||||
public class RpcSyncSettingsPatch
|
||||
{
|
||||
public static void Postfix()
|
||||
{
|
||||
OptionItem.SyncAllOptions();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,162 @@
|
||||
using System;
|
||||
using TMPro;
|
||||
using HarmonyLib;
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace HNSRevamped
|
||||
{
|
||||
[HarmonyPatch(typeof(LobbyViewSettingsPane))]
|
||||
public class LobbyViewPatch
|
||||
{
|
||||
private static Dictionary<TabGroup, GameObject> ViewSettingsButtons = new();
|
||||
private static float num;
|
||||
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.Awake))]
|
||||
[HarmonyPostfix]
|
||||
public static void AwakePostfix(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
__instance.gameModeText.DestroyTranslator();
|
||||
|
||||
var OverviewButton = __instance.taskTabButton.gameObject;
|
||||
OverviewButton.transform.localScale = new Vector3(0.4f, 1f, 1f);
|
||||
OverviewButton.transform.localPosition += new Vector3(-1.1f, 0f, 0f);
|
||||
|
||||
var RolesButton = __instance.rolesTabButton.gameObject;
|
||||
RolesButton.transform.localScale = new Vector3(0.4f, 1f, 1f);
|
||||
num = 1.4f;
|
||||
RolesButton.transform.localPosition = OverviewButton.transform.localPosition + Vector3.right * num * 1f;
|
||||
var label = RolesButton.transform.Find("FontPlacer").GetComponentInChildren<TextMeshPro>();
|
||||
label.DestroyTranslator();
|
||||
label.text = "Vanilla Roles";
|
||||
|
||||
ViewSettingsButtons = new();
|
||||
num = 2.8f;
|
||||
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.ChangeTab))]
|
||||
[HarmonyPrefix]
|
||||
public static bool ChangeTabPrefix(LobbyViewSettingsPane __instance, [HarmonyArgument(0)] StringNames category)
|
||||
{
|
||||
if (category == StringNames.OverviewCategory || category == StringNames.RolesCategory)
|
||||
{
|
||||
foreach (var button in ViewSettingsButtons.Values)
|
||||
button.GetComponent<PassiveButton>().SelectButton(false);
|
||||
return true;
|
||||
}
|
||||
__instance.currentTab = category;
|
||||
for (int i = 0; i < __instance.settingsInfo.Count; i++)
|
||||
{
|
||||
Object.Destroy(__instance.settingsInfo[i].gameObject);
|
||||
}
|
||||
__instance.settingsInfo.Clear();
|
||||
__instance.taskTabButton.SelectButton(false);
|
||||
__instance.rolesTabButton.SelectButton(false);
|
||||
foreach (var tab in ViewSettingsButtons.Keys)
|
||||
{
|
||||
if (tab == (TabGroup)__instance.currentTab)
|
||||
ViewSettingsButtons[tab].GetComponent<PassiveButton>().SelectButton(true);
|
||||
else
|
||||
ViewSettingsButtons[tab].GetComponent<PassiveButton>().SelectButton(false);
|
||||
}
|
||||
DrawOptions(__instance, (TabGroup)__instance.currentTab);
|
||||
__instance.scrollBar.ScrollToTop();
|
||||
return false;
|
||||
}
|
||||
|
||||
public static void DrawOptions(LobbyViewSettingsPane __instance, TabGroup tab)
|
||||
{
|
||||
float num = 1.44f;
|
||||
int settingsCount = 0;
|
||||
foreach (var option in OptionItem.AllOptions)
|
||||
{
|
||||
if (option.IsHiddenOn() || option.Tab != tab || (option.Parent != null && (option.Parent.IsHiddenOn() || !option.Parent.GetBool()))) continue;
|
||||
if (option.IsHeader || option is TextOptionItem)
|
||||
{
|
||||
num -= 0.85f;
|
||||
CategoryHeaderMasked categoryHeaderMasked = Object.Instantiate(__instance.categoryHeaderOrigin);
|
||||
categoryHeaderMasked.SetHeader(StringNames.None, 61);
|
||||
categoryHeaderMasked.transform.SetParent(__instance.settingsContainer);
|
||||
categoryHeaderMasked.transform.localScale = Vector3.one;
|
||||
categoryHeaderMasked.transform.localPosition = new Vector3(-9.77f, num, -2f);
|
||||
__instance.settingsInfo.Add(categoryHeaderMasked.gameObject);
|
||||
num -= 1f;
|
||||
categoryHeaderMasked.DestroyTranslator();
|
||||
categoryHeaderMasked.Title.text = option.GetName();
|
||||
settingsCount = 0;
|
||||
}
|
||||
if (option is TextOptionItem) continue;
|
||||
|
||||
ViewSettingsInfoPanel viewSettingsInfoPanel = Object.Instantiate(__instance.infoPanelOrigin);
|
||||
viewSettingsInfoPanel.transform.SetParent(__instance.settingsContainer);
|
||||
viewSettingsInfoPanel.transform.localScale = Vector3.one;
|
||||
float num2;
|
||||
if (settingsCount % 2 == 0)
|
||||
{
|
||||
num2 = -8.95f;
|
||||
if (settingsCount > 0)
|
||||
{
|
||||
num -= 0.85f;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num2 = -3f;
|
||||
}
|
||||
viewSettingsInfoPanel.transform.localPosition = new Vector3(num2, num, -2f);
|
||||
|
||||
if (option is BooleanOptionItem)
|
||||
{
|
||||
viewSettingsInfoPanel.SetInfoCheckbox(StringNames.None, 61, option.GetBool());
|
||||
}
|
||||
else
|
||||
{
|
||||
viewSettingsInfoPanel.SetInfo(StringNames.None, option.GetString(), 61);
|
||||
}
|
||||
viewSettingsInfoPanel.titleText.text = option.GetName();
|
||||
|
||||
if (option.Parent?.Parent?.Parent != null)
|
||||
{
|
||||
viewSettingsInfoPanel.transform.FindChild("LabelBackground").GetComponent<SpriteRenderer>().color = new(0.7f, 0.5f, 0.5f);
|
||||
}
|
||||
else if (option.Parent?.Parent != null)
|
||||
{
|
||||
viewSettingsInfoPanel.transform.FindChild("LabelBackground").GetComponent<SpriteRenderer>().color = new(0.5f, 0.5f, 0.7f);
|
||||
}
|
||||
else if (option.Parent != null)
|
||||
{
|
||||
viewSettingsInfoPanel.transform.FindChild("LabelBackground").GetComponent<SpriteRenderer>().color = new(0.5f, 0.7f, 0.5f);
|
||||
}
|
||||
|
||||
__instance.settingsInfo.Add(viewSettingsInfoPanel.gameObject);
|
||||
++settingsCount;
|
||||
}
|
||||
__instance.scrollBar.SetYBoundsMax(-num - 1.44f);
|
||||
}
|
||||
|
||||
public static void ReCreateButtons(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
foreach (var button in ViewSettingsButtons.Values)
|
||||
Object.Destroy(button.gameObject);
|
||||
ViewSettingsButtons = new();
|
||||
var OverviewButton = __instance.taskTabButton.gameObject;
|
||||
var RolesButton = __instance.rolesTabButton.gameObject;
|
||||
OverviewButton.transform.localScale = new Vector3(0.4f, 1f, 1f);
|
||||
RolesButton.transform.localScale = new Vector3(0.4f, 1f, 1f);
|
||||
num = 1.4f;
|
||||
RolesButton.transform.localPosition = OverviewButton.transform.localPosition + Vector3.right * num * 1f;
|
||||
num = 2.8f;
|
||||
|
||||
}
|
||||
|
||||
[HarmonyPatch(nameof(LobbyViewSettingsPane.OnEnable))]
|
||||
[HarmonyPostfix]
|
||||
public static void OnEnablePostfix(LobbyViewSettingsPane __instance)
|
||||
{
|
||||
ReCreateButtons(__instance);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user