diff --git a/Essentials/Essentials.csproj b/Essentials/Essentials.csproj index 03108b2..6228666 100644 --- a/Essentials/Essentials.csproj +++ b/Essentials/Essentials.csproj @@ -2,7 +2,7 @@ netstandard2.1 latest - 0.2.0-dev.7 + 0.2.0-dev.8 Among Us modding essentials CoMaNdO @@ -14,7 +14,7 @@ true 1701;1702; - $(AmongUs_2020-12-9) + $(AmongUs_2020-12-9s) NuclearPowered/Mappings:0.1.3 2020.12.9s @@ -24,6 +24,7 @@ true 1701;1702; + $(AmongUs_2021-3-5s) NuclearPowered/Mappings:0.2.0 2021.3.5s @@ -39,7 +40,7 @@ - + diff --git a/Essentials/Options/CustomOption.Button.cs b/Essentials/Options/CustomOption.Button.cs new file mode 100644 index 0000000..fa1a47a --- /dev/null +++ b/Essentials/Options/CustomOption.Button.cs @@ -0,0 +1,104 @@ +using Essentials.Extensions; +using System; + +namespace Essentials.Options +{ + /// + /// A derivative of , handling "buttons" in the options menu. + /// + public class CustomOptionButton : CustomOption, IToggleOption + { + public override bool SendRpc { get { return false; } } + + /// + /// Adds an option header. + /// + /// The title of the header + /// The button will be visible in the lobby options menu + /// The button title will appear in the HUD (option list) in the lobby + /// The button's initial (client sided) value, can be used to hide/show other options + public CustomOptionButton(string title, bool menu = true, bool hud = false, bool initialValue = false) : base(title, title, false, CustomOptionType.Toggle, initialValue) + { + HudStringFormat = (_, name, _) => name; + + MenuVisible = menu; + HudVisible = hud; + } + + protected override bool GameOptionCreated(OptionBehaviour o) + { + if (o is ToggleOption toggle) + { + toggle.TitleText.Text = GetFormattedName(); + + toggle.CheckMark.enabled = toggle.oldValue = false; + + toggle.transform.FindChild("CheckBox")?.gameObject?.SetActive(false); + + return true; + } + else if (o is StringOption str) // Display options in menu for non-host + { + str.TitleText.Text = GetFormattedName(); + + str.Value = str.oldValue = 0; + + str.ValueText.Text = GetFormattedValue(); + + return true; + } + + return false; + } + + /// + /// Toggles the option value (called when the button is pressed). + /// + public virtual void Toggle() + { + SetValue(!GetValue()); + } + + /// + /// Sets a new value + /// + /// The new value + public virtual void SetValue(bool value) + { + SetValue(value, true); + } + + /// The boolean-casted default value. + public virtual bool GetDefaultValue() + { + return GetDefaultValue(); + } + + /// The boolean-casted old value. + public virtual bool GetOldValue() + { + return GetOldValue(); + } + + /// The boolean-casted current value. + public virtual bool GetValue() + { + return GetValue(); + } + } + + public partial class CustomOption + { + /// + /// Adds a "button" in the options menu. + /// + /// The title of the button + /// The button will be visible in the lobby options menu + /// The button title will appear in the HUD (option list) in the lobby + /// The button's initial (client sided) value, can be used to hide/show other options + public static CustomOptionButton AddButton(string title, bool menu = true, bool hud = false, bool initialValue = false) + { + return new CustomOptionButton(title, menu, hud, initialValue); + } + } +} \ No newline at end of file diff --git a/Essentials/Options/CustomOption.Header.cs b/Essentials/Options/CustomOption.Header.cs index 5b6377a..0e28483 100644 --- a/Essentials/Options/CustomOption.Header.cs +++ b/Essentials/Options/CustomOption.Header.cs @@ -1,41 +1,36 @@ namespace Essentials.Options { /// - /// A derivative of , handling option headers. + /// A derivative of , handling option headers. /// - public class CustomOptionHeader : CustomOption + public class CustomOptionHeader : CustomOptionButton { - public override bool SendRpc { get { return false; } } - /// /// Adds an option header. /// /// The title of the header /// The header will be visible in the lobby options menu - /// The header will appear in the option list in the lobby - public CustomOptionHeader(string title, bool menu = true, bool hud = true) : base(title, title, false, CustomOptionType.Toggle, false) + /// The header will appear in the HUD (option list) in the lobby + /// The header's initial (client sided) value, can be used to hide/show other options + public CustomOptionHeader(string title, bool menu = true, bool hud = true, bool initialValue = false) : base(title, menu, hud, initialValue) { - OnValueChanged += (sender, args) => - { - args.Cancel = true; - }; - - ToStringFormat = (_, name, _) => name; - - MenuVisible = menu; - HudVisible = hud; } - protected override void GameOptionCreated(OptionBehaviour o) + protected override bool GameOptionCreated(OptionBehaviour o) { - if (o is not ToggleOption toggle) return; + if (!base.GameOptionCreated(o)) return false; - toggle.TitleText.Text = GetFormattedName(); + if (o is ToggleOption toggle) toggle.transform.FindChild("Background")?.gameObject?.SetActive(false); - toggle.CheckMark.enabled = toggle.oldValue = false; + return true; + } - toggle.transform.FindChild("Background")?.gameObject?.SetActive(false); - toggle.transform.FindChild("CheckBox")?.gameObject?.SetActive(false); + /// + /// Toggles the option value (called when the header is pressed). + /// + public override void Toggle() + { + base.Toggle(); } } @@ -46,10 +41,11 @@ public partial class CustomOption /// /// The title of the header /// The header will be visible in the lobby options menu - /// The header will appear in the option list in the lobby - public static CustomOptionHeader AddHeader(string title, bool menu = true, bool hud = true) + /// The header will appear in the HUD (option list) in the lobby + /// The header's initial (client sided) value, can be used to hide/show other options + public static CustomOptionHeader AddHeader(string title, bool menu = true, bool hud = true, bool initialValue = false) { - return new CustomOptionHeader(title, menu, hud); + return new CustomOptionHeader(title, menu, hud, initialValue); } } } \ No newline at end of file diff --git a/Essentials/Options/CustomOption.Number.cs b/Essentials/Options/CustomOption.Number.cs index ed4750c..57237c5 100644 --- a/Essentials/Options/CustomOption.Number.cs +++ b/Essentials/Options/CustomOption.Number.cs @@ -70,7 +70,7 @@ public CustomNumberOption(string id, string name, bool saveValue, float value, f ConfigEntry = saveValue ? EssentialsPlugin.Instance.Config.Bind(PluginID, ConfigID, GetDefaultValue()) : null; SetValue(ConfigEntry == null ? GetDefaultValue() : ConfigEntry.Value, false); - StringFormat = (sender, value) => value.ToString(); + ValueStringFormat = (sender, value) => value.ToString(); } protected override OptionOnValueChangedEventArgs OnValueChangedEventArgs(object value, object oldValue) @@ -83,9 +83,9 @@ protected override OptionValueChangedEventArgs ValueChangedEventArgs(object valu return new NumberOptionValueChangedEventArgs(value, Value); } - protected override void GameOptionCreated(OptionBehaviour o) + protected override bool GameOptionCreated(OptionBehaviour o) { - if (o is not NumberOption number) return; + if (o is not NumberOption number) return false; number.TitleText.Text = GetFormattedName(); number.ValidRange = new FloatRange(Min, Max); @@ -96,6 +96,8 @@ protected override void GameOptionCreated(OptionBehaviour o) number.Value = number.Field_3 = GetValue(); #endif number.ValueText.Text = GetFormattedValue(); + + return true; } /// diff --git a/Essentials/Options/CustomOption.Patches.cs b/Essentials/Options/CustomOption.Patches.cs index ff2f42c..862fa0c 100644 --- a/Essentials/Options/CustomOption.Patches.cs +++ b/Essentials/Options/CustomOption.Patches.cs @@ -49,7 +49,12 @@ private static List GetGameOptions(float lowestY) ToggleOption toggle = Object.Instantiate(toggleOption, toggleOption.transform.parent);//.DontDestroy(); - option.OnGameOptionCreated(toggle); + if (!option.OnGameOptionCreated(toggle)) + { + toggle.Destroy(); + + continue; + } options.Add(toggle); @@ -61,7 +66,12 @@ private static List GetGameOptions(float lowestY) NumberOption number = Object.Instantiate(numberOption, numberOption.transform.parent);//.DontDestroy(); - option.OnGameOptionCreated(number); + if (!option.OnGameOptionCreated(number)) + { + number.Destroy(); + + continue; + } options.Add(number); @@ -94,7 +104,12 @@ private static List GetGameOptions(float lowestY) StringOption str = Object.Instantiate(stringOption, stringOption.transform.parent);//.DontDestroy(); - option.OnGameOptionCreated(str); + if (!option.OnGameOptionCreated(str)) + { + str.Destroy(); + + continue; + } options.Add(str); @@ -166,7 +181,7 @@ private static IEnumerable TargetMethods() private static void Postfix(ref string __result) { int firstNewline = __result.IndexOf('\n'); - StringBuilder sb = new StringBuilder(ClearDefaultLobbyText ? __result.Substring(0, firstNewline + 1) : __result); + StringBuilder sb = new StringBuilder(ClearDefaultHudText ? __result.Substring(0, firstNewline + 1) : __result); if (ShamelessPlug) sb.AppendLine("[FF1111FF]DorCoMaNdO on GitHub/Twitter/Twitch[]"); foreach (CustomOption option in Options) if (option.HudVisible) sb.AppendLine(option.ToString()); @@ -174,7 +189,7 @@ private static void Postfix(ref string __result) __result = sb.ToString(); string insert = ":"; - if (LobbyTextScroller && (HudManager.Instance?.GameSettings?.Height).GetValueOrDefault() + 0.02F > HudPosition.Height) insert = " (Scroll for more):"; + if (HudTextScroller && (HudManager.Instance?.GameSettings?.Height).GetValueOrDefault() + 0.02F > HudPosition.Height) insert = " (Scroll for more):"; __result = __result.Insert(firstNewline, insert); // Remove last newline (for the scroller to not overscroll one line) @@ -293,7 +308,8 @@ public static void Postfix() if (AmongUsClient.Instance?.AmHost != true || PlayerControl.AllPlayerControls.Count < 2 || !PlayerControl.LocalPlayer) return; //Rpc.Send(Options.Where(o => o.SendRpc).Select(o => ((string, CustomOptionType, object))o).ToArray()); - foreach (CustomOption option in Options) if (option.SendRpc) Rpc.Instance.Send(option); + foreach (CustomOption option in Options) if (option.SendRpc) Rpc.Instance.Send(option, true); + //Rpc.Instance.Send(Options.Where(o => o.SendRpc).Select(o => ((int, CustomOptionType, object))o).ToArray()); } } @@ -308,12 +324,12 @@ private static void UpdateScroller(object sender, EventArgs e) if (hudManager?.GameSettings?.transform == null) return; - hudManager.GameSettings.scale = LobbyTextScale; + hudManager.GameSettings.scale = HudTextScale; const float XOffset = 0.066666F, YOffset = 0.1F; // Scroller disabled - if (!LobbyTextScroller) + if (!HudTextScroller) { // Remove scroller if disabled late if (OptionsScroller != null) diff --git a/Essentials/Options/CustomOption.Rpc.cs b/Essentials/Options/CustomOption.Rpc.cs index cfcebb8..fc4d7f5 100644 --- a/Essentials/Options/CustomOption.Rpc.cs +++ b/Essentials/Options/CustomOption.Rpc.cs @@ -1,6 +1,5 @@ using Hazel; using Reactor; -using System; using System.Linq; namespace Essentials.Options @@ -34,7 +33,7 @@ internal static void HandleRpc(PlayerControl sender, (string, CustomOptionType, }*/ [RegisterCustomRpc] - private protected class Rpc : PlayerCustomRpc + private protected class Rpc : PlayerCustomRpc { public static Rpc Instance { get { return Rpc.Instance; } } @@ -44,7 +43,7 @@ public Rpc(EssentialsPlugin plugin) : base(plugin) public override RpcLocalHandling LocalHandling { get { return RpcLocalHandling.None; } } - public override void Write(MessageWriter writer, (string, CustomOptionType, object) option) + public override void Write(MessageWriter writer, (int, CustomOptionType, object) option) { writer.Write(option.Item1); // ID writer.Write((int)option.Item2); // Type @@ -53,9 +52,9 @@ public override void Write(MessageWriter writer, (string, CustomOptionType, obje else if (option.Item2 == CustomOptionType.String) writer.Write((int)option.Item3); } - public override (string, CustomOptionType, object) Read(MessageReader reader) + public override (int, CustomOptionType, object) Read(MessageReader reader) { - string id = reader.ReadString(); + int id = reader.ReadInt32(); CustomOptionType type = (CustomOptionType)reader.ReadInt32(); object value = null; if (type == CustomOptionType.Toggle) value = reader.ReadBoolean(); @@ -65,34 +64,47 @@ public override (string, CustomOptionType, object) Read(MessageReader reader) return (id, type, value); } - public override void Handle(PlayerControl sender, (string, CustomOptionType, object) option) + public override void Handle(PlayerControl sender, (int, CustomOptionType, object) option) { if (sender?.Data == null) return; - string id = option.Item1; + int id = option.Item1; CustomOptionType type = option.Item2; - CustomOption customOption = Options.FirstOrDefault(o => o.Type == type && o.ID.Equals(id, StringComparison.Ordinal)); + CustomOption customOption = Options.FirstOrDefault(o => o.Type == type && o.GetHashCode() == id); if (customOption == null) { - EssentialsPlugin.Logger.LogWarning($"Received option that could not be found: \"{id}\" of type {type}."); + EssentialsPlugin.Logger.LogWarning($"Received option that could not be found, hashcode: {id}, type: {type}."); return; } object value = option.Item3; - if (Debug) EssentialsPlugin.Logger.LogInfo($"\"{id}\" type: {type}, value: {value}, current value: {customOption.Value}"); + if (Debug) EssentialsPlugin.Logger.LogInfo($"\"{customOption.ID}\" type: {type}, value: {value}, current value: {customOption.Value}"); customOption.SetValue(value, true); - if (Debug) EssentialsPlugin.Logger.LogInfo($"\"{id}\", set value: {customOption.Value}"); + if (Debug) EssentialsPlugin.Logger.LogInfo($"\"{customOption.ID}\", set value: {customOption.Value}"); } } - public static implicit operator (string ID, CustomOptionType Type, object Value)(CustomOption option) + public static implicit operator (int ID, CustomOptionType Type, object Value)(CustomOption option) { - return (option.ID, option.Type, option.GetValue()); + return (option.GetHashCode(), option.Type, option.GetValue()); + } + + /*public static implicit operator (int ID, CustomOptionType Type, object Value)[](CustomOption option) + { + return new[] { ((int, CustomOptionType, object))option }; + }*/ + + public override int GetHashCode() + { + unchecked + { + return PluginID.GetHashCode() ^ ConfigID.GetHashCode();// ^ Type.GetHashCode(); + } } } } \ No newline at end of file diff --git a/Essentials/Options/CustomOption.String.cs b/Essentials/Options/CustomOption.String.cs index 73074eb..b1e9958 100644 --- a/Essentials/Options/CustomOption.String.cs +++ b/Essentials/Options/CustomOption.String.cs @@ -1,4 +1,6 @@ using BepInEx.Configuration; +using System; +using System.Collections.Generic; namespace Essentials.Options { @@ -22,10 +24,11 @@ public class CustomStringOption : CustomOption, IStringOption /// public readonly ConfigEntry ConfigEntry; + protected readonly string[] _values; /// /// The text values the option can present. /// - public readonly string[] Values; + public IReadOnlyCollection Values { get { return Array.AsReadOnly(_values); } } /// The ID of the option, used to maintain the last value when is true and to transmit the value between players /// The name/title of the option @@ -33,7 +36,7 @@ public class CustomStringOption : CustomOption, IStringOption /// The string values that may be displayed, initial/default value is index 0 public CustomStringOption(string id, string name, bool saveValue, string[] values) : base(id, name, saveValue, CustomOptionType.String, 0) { - Values = values; + _values = values; ValueChanged += (sender, args) => { @@ -43,7 +46,7 @@ public CustomStringOption(string id, string name, bool saveValue, string[] value ConfigEntry = saveValue ? EssentialsPlugin.Instance.Config.Bind(PluginID, ConfigID, GetDefaultValue()) : null; SetValue(ConfigEntry == null ? GetDefaultValue() : ConfigEntry.Value, false); - StringFormat = (sender, value) => Values[(int)value]; + ValueStringFormat = (sender, value) => _values[(int)value]; } protected override OptionOnValueChangedEventArgs OnValueChangedEventArgs(object value, object oldValue) @@ -56,40 +59,38 @@ protected override OptionValueChangedEventArgs ValueChangedEventArgs(object valu return new StringOptionValueChangedEventArgs(value, Value); } - protected override void GameOptionCreated(OptionBehaviour o) + protected override bool GameOptionCreated(OptionBehaviour o) { - if (o is not StringOption str) return; + if (o is not StringOption str) return false; str.TitleText.Text = GetFormattedName(); + str.Value = str.oldValue = GetValue(); + str.ValueText.Text = GetFormattedValue(); + + return true; } /// - /// Increases by 1 while it's lower than the length of or sets it back to 0 once the length is exceeded. + /// Increases by 1 while it's lower than the length of or sets it back to 0 once the length is exceeded. /// public virtual void Increase() { - int next = GetValue() + 1; - if (next >= Values.Length) next = 0; - - SetValue(next); + SetValue((GetValue() + 1) % _values.Length); } /// - /// Decreases by 1 while it's higher than 0 or sets it back to the length of -1. + /// Decreases by 1 while it's higher than 0 or sets it back to the length of -1. /// public virtual void Decrease() { - int next = GetValue() - 1; - if (next < 0) next = Values.Length - 1; - - SetValue(next); + SetValue((GetValue() + (_values.Length - 1)) % _values.Length); } protected virtual void SetValue(int value, bool raiseEvents) { - if (value < 0 || value >= Values.Length) value = GetDefaultValue(); + if (value < 0 || value >= _values.Length) value = GetDefaultValue(); base.SetValue(value, raiseEvents); } @@ -124,7 +125,7 @@ public virtual int GetValue() /// The text at index . public virtual string GetText(int value) { - return Values[value]; + return _values[value]; } /// The current text. diff --git a/Essentials/Options/CustomOption.Toggle.cs b/Essentials/Options/CustomOption.Toggle.cs index 5e1aabb..983b1c6 100644 --- a/Essentials/Options/CustomOption.Toggle.cs +++ b/Essentials/Options/CustomOption.Toggle.cs @@ -37,7 +37,7 @@ public CustomToggleOption(string id, string name, bool saveValue, bool value) : ConfigEntry = saveValue ? EssentialsPlugin.Instance.Config.Bind(PluginID, ConfigID, GetDefaultValue()) : null; SetValue(ConfigEntry == null ? GetDefaultValue() : ConfigEntry.Value, false); - StringFormat = (sender, value) => ((bool)value) ? "On" : "Off"; + ValueStringFormat = (sender, value) => ((bool)value) ? "On" : "Off"; } protected override OptionOnValueChangedEventArgs OnValueChangedEventArgs(object value, object oldValue) @@ -50,19 +50,28 @@ protected override OptionValueChangedEventArgs ValueChangedEventArgs(object valu return new ToggleOptionValueChangedEventArgs(value, Value); } - protected override void GameOptionCreated(OptionBehaviour o) + protected override bool GameOptionCreated(OptionBehaviour o) { if (o is ToggleOption toggle) { toggle.TitleText.Text = GetFormattedName(); + toggle.CheckMark.enabled = toggle.oldValue = GetValue(); + + return true; } - else if (o is StringOption str) // Display settings in menu for non-host + else if (o is StringOption str) // Display options in menu for non-host { str.TitleText.Text = GetFormattedName(); + str.Value = str.oldValue = 0; + str.ValueText.Text = GetFormattedValue(); + + return true; } + + return false; } /// diff --git a/Essentials/Options/CustomOption.cs b/Essentials/Options/CustomOption.cs index 009d898..7b40521 100644 --- a/Essentials/Options/CustomOption.cs +++ b/Essentials/Options/CustomOption.cs @@ -35,7 +35,7 @@ public partial class CustomOption private static List Options = new List(); /// - /// Enables or disables the credit string appended to the option list in the lobby. + /// Enables or disables the credit string appended to the HUD (option list) in the lobby. /// Please provide credit or reference elsewhere if you disable this. /// public static bool ShamelessPlug { get; set; } = true; @@ -46,19 +46,19 @@ public partial class CustomOption public static bool Debug { get; set; } = true; /// - /// The size of lobby options text, game default is 0.65F, Essentials default is 0.5F. + /// The size of HUD (lobby options) text, game default is 0.65F, Essentials default is 0.5F. /// - public static float LobbyTextScale { get; set; } = 0.5F; + public static float HudTextScale { get; set; } = 0.5F; /// - /// Enables or disables the lobby options text scroller. + /// Enables or disables the HUD (lobby options) text scroller. /// - public static bool LobbyTextScroller { get; set; } = true; + public static bool HudTextScroller { get; set; } = true; /// - /// Clear the game's default options list before listing custom options in the lobby. + /// Clear the game's default options list before listing custom options in the lobby HUD. /// - public static bool ClearDefaultLobbyText { get; set; } = false; + public static bool ClearDefaultHudText { get; set; } = false; /// /// The ID of the plugin that created the option. @@ -118,32 +118,38 @@ public partial class CustomOption public event EventHandler ValueChanged; /// - /// The game object that represents the custom option in the lobby options list. + /// The game object that represents the custom option in the lobby options menu. /// public virtual OptionBehaviour GameSetting { get; protected set; } + public static Func DefaultNameStringFormat = (_, name) => name; /// /// The string format reflecting the option name, result returned by . + /// Arguments: the sending custom option, option name. /// - public virtual Func NameStringFormat { get; set; } + public virtual Func NameStringFormat { get; set; } = DefaultNameStringFormat; + public static Func DefaultValueStringFormat = (_, value) => value.ToString(); /// /// The string format reflecting the value, result returned by . + /// Arguments: the sending custom option, current value. /// - public virtual Func StringFormat { get; set; } + public virtual Func ValueStringFormat { get; set; } = DefaultValueStringFormat; + public static Func DefaultHudStringFormat = (_, name, value) => $"{name}: {value}[]"; /// /// The string format reflecting the option name and value, result returned by . - /// Used when displaying the option in the lobby option list. + /// Used when displaying the option in the lobby HUD (option list). + /// Arguments: the sending custom option, formatted name, formatted value. /// - public virtual Func ToStringFormat { get; set; } + public virtual Func HudStringFormat { get; set; } = DefaultHudStringFormat; /// /// Affects whether the custom option will be visible in the lobby options menu. /// public virtual bool MenuVisible { get; set; } = true; /// - /// Affects whether the custom option will appear in the option list in the lobby. + /// Affects whether the custom option will appear in the HUD (option list) in the lobby. /// public virtual bool HudVisible { get; set; } = true; @@ -207,9 +213,9 @@ protected virtual OptionValueChangedEventArgs ValueChangedEventArgs(object value return new OptionValueChangedEventArgs(value, Value); } - private void OnGameOptionCreated(OptionBehaviour o) + private bool OnGameOptionCreated(OptionBehaviour o) { - if (o == null) return; + if (o == null) return false; try { @@ -217,7 +223,7 @@ private void OnGameOptionCreated(OptionBehaviour o) o.name = o.gameObject.name = ID; - GameOptionCreated(o); + if (!GameOptionCreated(o)) return false; } catch (Exception e) { @@ -225,15 +231,17 @@ private void OnGameOptionCreated(OptionBehaviour o) } GameSetting = o; + + return true; } /// /// Called when the game object is (re)created for this option. /// /// The game object that was created for this option - protected virtual void GameOptionCreated(OptionBehaviour o) + protected virtual bool GameOptionCreated(OptionBehaviour o) { - // throw unimplemented? + return true; // throw unimplemented? } /// @@ -305,7 +313,7 @@ public void SetToDefault(bool raiseEvents = true) /// Whether or not to raise events protected virtual void SetValue(object value, bool raiseEvents) { - if (value?.GetType() != Value?.GetType() || Value == value) return; // Refuse value updates that don't match the option type + if (value?.GetType() != Value?.GetType() || Value == value) return; // Refuse value updates that don't match the option type. if (raiseEvents && OnValueChanged != null && AmongUsClient.Instance?.AmHost == true && PlayerControl.LocalPlayer) { @@ -408,19 +416,19 @@ public T GetOldValue() /// passed through . public string GetFormattedName() { - return NameStringFormat?.Invoke(this, Name) ?? Name.ToString(); + return (NameStringFormat ?? DefaultNameStringFormat).Invoke(this, Name); } - /// passed through . + /// passed through . public string GetFormattedValue() { - return StringFormat?.Invoke(this, Value) ?? Value.ToString(); + return (ValueStringFormat ?? DefaultValueStringFormat).Invoke(this, Value); } - /// or the return value of when provided. + /// or the return value of when provided. public override string ToString() { - return $"{ToStringFormat?.Invoke(this, GetFormattedName(), GetFormattedValue()) ?? $"{GetFormattedName()}: {GetFormattedValue()}"}[]"; + return (HudStringFormat ?? DefaultHudStringFormat).Invoke(this, GetFormattedName(), GetFormattedValue()); } } } \ No newline at end of file diff --git a/Essentials/Properties/launchSettings.json b/Essentials/Properties/launchSettings.json index 2d84dd3..f4c50f9 100644 --- a/Essentials/Properties/launchSettings.json +++ b/Essentials/Properties/launchSettings.json @@ -2,11 +2,11 @@ "profiles": { "2021.3.5s": { "commandName": "Executable", - "executablePath": "%AmongUs%\\Among Us.exe" + "executablePath": "%AmongUs_2021-3-5s%\\Among Us.exe" }, "2020.12.9s": { "commandName": "Executable", - "executablePath": "%AmongUs_2020-12-9%\\Among Us.exe" + "executablePath": "%AmongUs_2020-12-9s%\\Among Us.exe" } } } \ No newline at end of file diff --git a/Essentials/README.md b/Essentials/README.md new file mode 100644 index 0000000..918f30e --- /dev/null +++ b/Essentials/README.md @@ -0,0 +1,24 @@ +# Essentials +Essentials is a modding library for Among Us with APIs to speed up and ease development, and to improve mod compatibility. + +## Installation +**NOTE:** At the moment, official builds are only compiled for the Steam client. +1. Install [BepInEx](https://docs.reactor.gg/docs/basic/install_bepinex). +2. Install [Reactor](https://docs.reactor.gg/docs/basic/install_reactor) (CI 38 or newer for Essentials 0.1.1+, CI 45 for Among Us version 2021.3.5s). +3. Grab the [latest release](https://github.com/DorCoMaNdO/Reactor-Essentials/releases/latest) for your client version (support for older clients may be dropped, in that case browse [previous releases](https://github.com/DorCoMaNdO/Reactor-Essentials/releases)). +4. Place the downloaded release in `Among Us/BepInEx/plugins/` (same steps as installing Reactor). + +## Development +To develop plugins with Essentials, Essentials needs to be installed, follow the steps above before proceeding. +This guide assumes Reactor.OxygenFilter.MSBuild is being used. +1. Open your project file (`.csproj`). +2. Add or locate an `ItemGroup` tag. +3. Add the following line: `` +4. If using Visual Studio, building your project once with `dotnet build` may be required due to a Mono.Cecil issue present in Reactor.OxygenFilter.MSBuild. + +## Building Essentials +Newer versions of Essentials use configurations based on Among Us target version(s) and override the `AmongUs` environment variable as a result. +Essentials depends on Reactor, follow installation steps 1 and 2 before proceeding. +1. Add an environment variable for your targeted Among Us version(s), the environment variable needs to be prefixed with `AmongUs_` and then be followed by the client version, with dashes substituting dots, for example: `AmongUs_2020-12-9s` for version 2020.12.9s. +2. Select the configuration for the targeted Among Us version (in Visual Studio, if building for more than one version, you can use Build -> Batch Build... from the toolbar and select all the target versions and then `Build`). +3. The compiled binary will be copied to the `plugins` folder of your targeted Among Us version(s), as well as a `bin` folder in the solution's folder. \ No newline at end of file