mirror of
https://github.com/D1GQ/BetterAmongUs.git
synced 2026-10-20 01:46:19 +00:00
Move to string based ids for Settings, add option to disable setting compressing
This commit is contained in:
1 parent
0b8f284676
commit
7460720178
16 files changed
+255
-236
No files matched your search
@@ -89,7 +89,7 @@ internal static class BetterDataManager
|
||||
/// <summary>
|
||||
/// Current compressed settings file path.
|
||||
/// </summary>
|
||||
internal static string SettingsFilePath => Path.Combine(Folders.settingsFolderPath, $"Preset-{BAUConfigs.SettingsPreset.Value}.dat");
|
||||
internal static string SettingsFilePath => GetSettingsFilePathFromPreset(BAUConfigs.SettingsPreset.Value);
|
||||
|
||||
/// <summary>
|
||||
/// File containing banned player identifiers.
|
||||
@@ -133,6 +133,15 @@ internal static class BetterDataManager
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file path for the settings file associated with a specific preset number.
|
||||
/// </summary>
|
||||
/// <param name="preset">The preset number to get the settings file for.</param>
|
||||
internal static string GetSettingsFilePathFromPreset(int preset)
|
||||
{
|
||||
return Path.Combine(Folders.settingsFolderPath, $"Preset-{preset}.json");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the persistent data path for Among Us.
|
||||
/// </summary>
|
||||
@@ -239,24 +248,29 @@ internal static class BetterDataManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves a setting with the specified ID.
|
||||
/// Saves a setting with the specified identifier to the game settings file.
|
||||
/// </summary>
|
||||
/// <param name="id">The setting identifier.</param>
|
||||
/// <param name="input">The setting value to save.</param>
|
||||
internal static void SaveSetting(int id, object? input)
|
||||
/// <param name="id">The unique identifier key for the setting.</param>
|
||||
/// <param name="input">The value to save. Can be any object type that is JSON-serializable.</param>
|
||||
internal static void SaveSetting(string id, object? input)
|
||||
{
|
||||
id = id.Split(".").Last();
|
||||
Files.BetterGameSettingsFile.Settings[id] = input;
|
||||
Files.BetterGameSettingsFile.Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Checks if a setting can be loaded as the specified type.
|
||||
/// Determines whether a setting exists and can be loaded as the specified type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type to check against.</typeparam>
|
||||
/// <param name="id">The setting identifier.</param>
|
||||
/// <returns>True if the setting exists and can be cast to type T, false otherwise.</returns>
|
||||
internal static bool CanLoadSetting<T>(int id)
|
||||
/// <typeparam name="T">The target type to check compatibility with.</typeparam>
|
||||
/// <param name="id">The unique identifier key for the setting.</param>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the setting exists and the value is of type <typeparamref name="T"/>;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
internal static bool CanLoadSetting<T>(string id)
|
||||
{
|
||||
id = id.Split(".").Last();
|
||||
if (Files.BetterGameSettingsFile.Settings.TryGetValue(id, out var value))
|
||||
{
|
||||
if (value is T)
|
||||
@@ -269,14 +283,22 @@ internal static class BetterDataManager
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads a setting with the specified ID, returning a default value if not found.
|
||||
/// Loads a setting with the specified identifier, returning a default value if the setting
|
||||
/// does not exist or cannot be cast to the requested type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">The type of the setting value.</typeparam>
|
||||
/// <param name="id">The setting identifier.</param>
|
||||
/// <param name="Default">The default value to return and save if the setting doesn't exist.</param>
|
||||
/// <returns>The setting value or the default value if not found.</returns>
|
||||
internal static T? LoadSetting<T>(int id, T? Default = default)
|
||||
/// <typeparam name="T">The expected type of the setting value.</typeparam>
|
||||
/// <param name="id">The unique identifier key for the setting.</param>
|
||||
/// <param name="Default">
|
||||
/// The default value to return if the setting is not found. This value will also be
|
||||
/// automatically saved to the settings file.
|
||||
/// </param>
|
||||
/// <returns>
|
||||
/// The stored setting value cast to type <typeparamref name="T"/>, or the specified
|
||||
/// <paramref name="Default"/> value if the setting doesn't exist.
|
||||
/// </returns>
|
||||
internal static T? LoadSetting<T>(string id, T? Default = default)
|
||||
{
|
||||
id = id.Split(".").Last();
|
||||
if (Files.BetterGameSettingsFile.Settings.TryGetValue(id, out var value))
|
||||
{
|
||||
if (value is T castValue)
|
||||
|
||||
@@ -68,6 +68,11 @@ internal static class BAUConfigs
|
||||
/// </summary>
|
||||
internal static BAUConfigEntry<bool> VentColorGroups { get; } = new("Better Options", "VentColorGroups", true);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration entry for compress settings file setting.
|
||||
/// </summary>
|
||||
internal static BAUConfigEntry<bool> CompressSettingFiles { get; } = new("Better Options", "CompressSettingFiles", false);
|
||||
|
||||
/// <summary>
|
||||
/// Gets the configuration entry for command prefix setting.
|
||||
/// </summary>
|
||||
|
||||
@@ -6,18 +6,21 @@ using System.Text.Json.Serialization;
|
||||
namespace BetterAmongUs.Data.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Abstract base class for JSON file handling with serialization and deserialization capabilities.
|
||||
/// Provides a base class for JSON-backed data files with automatic
|
||||
/// loading, validation, and serialization.
|
||||
/// </summary>
|
||||
internal abstract class AbstractJsonFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets the file path where the JSON data will be stored.
|
||||
/// Gets the path to the JSON file.
|
||||
/// </summary>
|
||||
internal abstract string FilePath { get; }
|
||||
private bool _hasInit;
|
||||
|
||||
private bool _initialized;
|
||||
|
||||
/// <summary>
|
||||
/// Gets the JSON serializer options used for serialization and deserialization.
|
||||
/// Gets the <see cref="JsonSerializerOptions"/> used for serialization
|
||||
/// and deserialization.
|
||||
/// </summary>
|
||||
protected virtual JsonSerializerOptions SerializerOptions { get; } = new()
|
||||
{
|
||||
@@ -28,161 +31,129 @@ internal abstract class AbstractJsonFile
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
/// Initializes the JSON file, creating it if it doesn't exist or loading existing data.
|
||||
/// Initializes the file by loading existing data if possible and
|
||||
/// writing the current state back to disk.
|
||||
/// </summary>
|
||||
internal virtual void Init()
|
||||
{
|
||||
if (_hasInit)
|
||||
if (_initialized)
|
||||
return;
|
||||
|
||||
_hasInit = true;
|
||||
_initialized = true;
|
||||
|
||||
if (!IsFileValid())
|
||||
{
|
||||
Save();
|
||||
return;
|
||||
}
|
||||
if (IsFileValid())
|
||||
Load();
|
||||
|
||||
Load();
|
||||
Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Loads data from the JSON file into the current instance.
|
||||
/// Loads the file contents into the current instance.
|
||||
/// </summary>
|
||||
/// <returns>True if loading was successful, false otherwise.</returns>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the file was successfully loaded;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
protected virtual bool Load()
|
||||
{
|
||||
try
|
||||
{
|
||||
var content = TryReadFromFile();
|
||||
if (string.IsNullOrEmpty(content.Trim()))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
var json = ReadFromFile();
|
||||
|
||||
var data = JsonSerializer.Deserialize(content, GetType(), SerializerOptions);
|
||||
if (data == null)
|
||||
{
|
||||
Logger_.Error("Deserialization returned null");
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return false;
|
||||
|
||||
var data = JsonSerializer.Deserialize(json, GetType(), SerializerOptions);
|
||||
if (data is null)
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach (var property in GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance))
|
||||
{
|
||||
if (property.GetCustomAttribute<JsonPropertyNameAttribute>() == null) continue;
|
||||
if (property.CanWrite)
|
||||
if (property.CanWrite &&
|
||||
property.GetCustomAttribute<JsonPropertyNameAttribute>() != null)
|
||||
{
|
||||
var value = property.GetValue(data);
|
||||
property.SetValue(this, value);
|
||||
property.SetValue(this, property.GetValue(data));
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
catch (JsonException ex)
|
||||
{
|
||||
Logger_.Error($"JSON parsing error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger_.Error($"Unexpected error: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Attempts to read content from the file, returning an empty string on failure.
|
||||
/// </summary>
|
||||
/// <returns>The file content or an empty string if reading fails.</returns>
|
||||
private string TryReadFromFile()
|
||||
{
|
||||
try
|
||||
{
|
||||
return ReadFromFile();
|
||||
}
|
||||
catch
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the current instance's data to the JSON file.
|
||||
/// </summary>
|
||||
/// <returns>True if saving was successful, false otherwise.</returns>
|
||||
internal virtual bool Save()
|
||||
{
|
||||
try
|
||||
{
|
||||
var json = JsonSerializer.Serialize(this, GetType(), SerializerOptions);
|
||||
WriteToFile(json);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger_.Error(ex);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Determines whether the file specified by the current FilePath exists and contains valid, non-empty JSON content.
|
||||
/// Saves the current instance to the JSON file.
|
||||
/// </summary>
|
||||
/// <returns>true if the file exists, is not empty, and contains valid, non-empty JSON content; otherwise, false.</returns>
|
||||
private bool IsFileValid()
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the file was successfully written;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
internal virtual bool Save()
|
||||
{
|
||||
var directory = Path.GetDirectoryName(FilePath);
|
||||
if (!string.IsNullOrEmpty(directory) && !Directory.Exists(directory))
|
||||
try
|
||||
{
|
||||
Directory.CreateDirectory(directory);
|
||||
WriteToFile(JsonSerializer.Serialize(this, GetType(), SerializerOptions));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (!File.Exists(FilePath))
|
||||
catch (Exception ex)
|
||||
{
|
||||
Logger_.Error(ex);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
var content = TryReadFromFile();
|
||||
if (string.IsNullOrEmpty(content.Trim())) return false;
|
||||
/// <summary>
|
||||
/// Determines whether the JSON file exists and contains valid,
|
||||
/// non-empty JSON.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the file is valid; otherwise,
|
||||
/// <see langword="false"/>.
|
||||
/// </returns>
|
||||
private bool IsFileValid()
|
||||
{
|
||||
Directory.CreateDirectory(Path.GetDirectoryName(FilePath)!);
|
||||
|
||||
if (!File.Exists(FilePath))
|
||||
return false;
|
||||
|
||||
try
|
||||
{
|
||||
var jsonElement = JsonSerializer.Deserialize<JsonElement>(content);
|
||||
var json = ReadFromFile();
|
||||
|
||||
var fileInfo = new FileInfo(FilePath);
|
||||
if (fileInfo.Length == 0)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(json))
|
||||
return false;
|
||||
}
|
||||
|
||||
if (jsonElement.ValueKind == JsonValueKind.Object && !jsonElement.EnumerateObject().Any() ||
|
||||
jsonElement.ValueKind == JsonValueKind.Array && !jsonElement.EnumerateArray().Any())
|
||||
var element = JsonSerializer.Deserialize<JsonElement>(json);
|
||||
|
||||
return element.ValueKind switch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
JsonValueKind.Object => element.EnumerateObject().Any(),
|
||||
JsonValueKind.Array => element.EnumerateArray().Any(),
|
||||
_ => true
|
||||
};
|
||||
}
|
||||
catch (Exception)
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads the content from the JSON file.
|
||||
/// Reads the contents of the JSON file.
|
||||
/// </summary>
|
||||
/// <returns>The content of the JSON file.</returns>
|
||||
/// <returns>The raw JSON string.</returns>
|
||||
protected virtual string ReadFromFile()
|
||||
{
|
||||
return File.ReadAllText(FilePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes the JSON string to the file.
|
||||
/// Writes JSON content to the file.
|
||||
/// </summary>
|
||||
/// <param name="json">The JSON string to write.</param>
|
||||
protected virtual void WriteToFile(string json)
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
using BetterAmongUs.Modules;
|
||||
using BetterAmongUs.Data.Config;
|
||||
using BetterAmongUs.Modules;
|
||||
using BetterAmongUs.Modules.OptionItems;
|
||||
using BetterAmongUs.Patches.Gameplay.UI.Settings;
|
||||
using System.IO.Compression;
|
||||
using System.Text;
|
||||
using System.Text.Json;
|
||||
@@ -11,10 +14,25 @@ namespace BetterAmongUs.Data.Json;
|
||||
/// </summary>
|
||||
internal sealed class BetterGameSettingsFile : AbstractJsonFile
|
||||
{
|
||||
/// <summary>
|
||||
/// Gets or initializes the custom file path override for the settings file.
|
||||
/// </summary>
|
||||
internal string? OverrideFilePath { get; init; }
|
||||
|
||||
/// <summary>
|
||||
/// The current version identifier for the settings file format.
|
||||
/// </summary>
|
||||
internal const string SETTINGS_VERSION = "2.0";
|
||||
|
||||
/// <summary>
|
||||
/// The dictionary key used to store the settings file version.
|
||||
/// </summary>
|
||||
internal const string SETTINGS_VERSION_KEY = "FileVer";
|
||||
|
||||
/// <summary>
|
||||
/// Gets the file path for the game settings file.
|
||||
/// </summary>
|
||||
internal override string FilePath => BetterDataManager.Files.SettingsFilePath;
|
||||
internal override string FilePath => OverrideFilePath ?? BetterDataManager.Files.SettingsFilePath;
|
||||
|
||||
/// <summary>
|
||||
/// Loads the settings file and converts JSON elements to their appropriate types.
|
||||
@@ -48,16 +66,53 @@ internal sealed class BetterGameSettingsFile : AbstractJsonFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Validate settings file version
|
||||
object? versionObject = null;
|
||||
Settings.TryGetValue(SETTINGS_VERSION_KEY, out versionObject);
|
||||
if (versionObject == null || versionObject is not SETTINGS_VERSION)
|
||||
{
|
||||
Settings.Clear();
|
||||
Save();
|
||||
foreach (var opt in OptionItem.AllOptions)
|
||||
{
|
||||
opt.TryLoad(true);
|
||||
}
|
||||
GameSettingsPatch.BetterSettingsTab?.UpdateVisuals();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
return success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Saves the current settings to the file, ensuring the version key is included.
|
||||
/// </summary>
|
||||
/// <returns>
|
||||
/// <see langword="true"/> if the save operation was successful;
|
||||
/// otherwise, <see langword="false"/>.
|
||||
/// </returns>
|
||||
internal override bool Save()
|
||||
{
|
||||
Settings[SETTINGS_VERSION_KEY] = SETTINGS_VERSION;
|
||||
Settings = Settings.OrderBy(kvp => kvp.Key != SETTINGS_VERSION_KEY)
|
||||
.ThenBy(kvp => kvp.Key)
|
||||
.ToDictionary(kvp => kvp.Key, kvp => kvp.Value);
|
||||
return base.Save();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Writes JSON data to the file with GZIP compression and base64 encoding.
|
||||
/// </summary>
|
||||
/// <param name="json">The JSON string to write to the file.</param>
|
||||
protected override void WriteToFile(string json)
|
||||
{
|
||||
if (!BAUConfigs.CompressSettingFiles.Value)
|
||||
{
|
||||
base.WriteToFile(json);
|
||||
return;
|
||||
}
|
||||
|
||||
var jsonDoc = JsonDocument.Parse(json);
|
||||
var settingsDict = jsonDoc.RootElement.GetProperty(nameof(Settings));
|
||||
var sb = new StringBuilder();
|
||||
@@ -73,7 +128,7 @@ internal sealed class BetterGameSettingsFile : AbstractJsonFile
|
||||
{
|
||||
if (kvp.Value.TryGetSingle(out float floatValue))
|
||||
{
|
||||
if (Settings.TryGetValue(int.Parse(kvp.Name), out var originalValue) && originalValue is float)
|
||||
if (Settings.TryGetValue(kvp.Name, out var originalValue) && originalValue is float)
|
||||
{
|
||||
sb.Append(floatValue.ToString("0.0########", System.Globalization.CultureInfo.InvariantCulture));
|
||||
}
|
||||
@@ -102,13 +157,22 @@ internal sealed class BetterGameSettingsFile : AbstractJsonFile
|
||||
ms.Position = 0;
|
||||
File.WriteAllText(FilePath, Convert.ToBase64String(ms.ToArray()));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Reads compressed JSON data from the file and decompresses it.
|
||||
/// </summary>
|
||||
/// <returns>The decompressed JSON string.</returns>
|
||||
protected override string ReadFromFile()
|
||||
{
|
||||
byte[] compressedBytes = Convert.FromBase64String(File.ReadAllText(FilePath).Trim());
|
||||
string text = File.ReadAllText(FilePath).Trim();
|
||||
|
||||
byte[] compressedBytes = new byte[text.Length];
|
||||
if (!Convert.TryFromBase64String(text, compressedBytes, out var bytesWritten))
|
||||
{
|
||||
return text; // Not valid base64, return original json
|
||||
}
|
||||
Array.Resize(ref compressedBytes, bytesWritten);
|
||||
|
||||
using var ms = new MemoryStream(compressedBytes);
|
||||
using var gzip = new GZipStream(ms, CompressionMode.Decompress);
|
||||
using var reader = new StreamReader(gzip);
|
||||
@@ -125,13 +189,10 @@ internal sealed class BetterGameSettingsFile : AbstractJsonFile
|
||||
}
|
||||
}
|
||||
|
||||
var resultDict = new Dictionary<int, object?>();
|
||||
var resultDict = new Dictionary<string, object?>();
|
||||
foreach (var kvp in settingsDict)
|
||||
{
|
||||
if (int.TryParse(kvp.Key, out int key))
|
||||
{
|
||||
resultDict[key] = kvp.Value.Deserialize<object?>();
|
||||
}
|
||||
resultDict[kvp.Key] = kvp.Value.Deserialize<object?>();
|
||||
}
|
||||
|
||||
return JsonSerializer.Serialize(new { Settings = resultDict });
|
||||
@@ -141,5 +202,5 @@ internal sealed class BetterGameSettingsFile : AbstractJsonFile
|
||||
/// Gets the dictionary of game settings with integer keys and various value types.
|
||||
/// </summary>
|
||||
[JsonPropertyName(nameof(Settings))]
|
||||
public Dictionary<int, object?> Settings { get; set; } = [];
|
||||
public Dictionary<string, object?> Settings { get; set; } = [];
|
||||
}
|
||||
@@ -16,17 +16,16 @@ public sealed class OptionCheckboxItem : OptionItem<bool>
|
||||
internal sealed override bool ShowChildren => base.ShowChildren && Value;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new checkbox option item or returns an existing one with the same ID.
|
||||
/// Creates a new checkbox option item.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this option.</param>
|
||||
/// <param name="tab">The tab this option belongs to.</param>
|
||||
/// <param name="translationString">The translation key for the option name.</param>
|
||||
/// <param name="defaultValue">The default value for the checkbox.</param>
|
||||
/// <param name="parent">Optional parent option for hierarchical organization.</param>
|
||||
/// <returns>A new or existing OptionCheckboxItem instance.</returns>
|
||||
internal static OptionCheckboxItem Create(int id, OptionTab tab, TranslationStrings.TranslationString translationString, bool defaultValue, OptionItem? parent = null)
|
||||
internal static OptionCheckboxItem Create(OptionTab tab, TranslationStrings.TranslationString translationString, bool defaultValue, OptionItem? parent = null)
|
||||
{
|
||||
if (GetOptionById(id) is OptionCheckboxItem checkboxItem)
|
||||
if (GetOptionByTranslationName(translationString) is OptionCheckboxItem checkboxItem)
|
||||
{
|
||||
checkboxItem.CreateBehavior();
|
||||
return checkboxItem;
|
||||
@@ -34,7 +33,6 @@ public sealed class OptionCheckboxItem : OptionItem<bool>
|
||||
|
||||
OptionCheckboxItem Item = new();
|
||||
AllOptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.TranslationName = translationString;
|
||||
Item.DefaultValue = defaultValue;
|
||||
|
||||
@@ -36,9 +36,8 @@ public class OptionFloatItem : OptionItem<float>
|
||||
protected (string prefix, string postfix) Fixs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new float option item or returns an existing one with the same ID.
|
||||
/// Creates a new float option item.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this option.</param>
|
||||
/// <param name="tab">The tab this option belongs to.</param>
|
||||
/// <param name="translationString">The translation key for the option name.</param>
|
||||
/// <param name="Min_Max_Increment">Tuple containing min value, max value, and increment step.</param>
|
||||
@@ -47,9 +46,9 @@ public class OptionFloatItem : OptionItem<float>
|
||||
/// <param name="parent">Optional parent option for hierarchical organization.</param>
|
||||
/// <param name="canBeInfinite">Whether this option can represent infinite values.</param>
|
||||
/// <returns>A new or existing OptionFloatItem instance.</returns>
|
||||
internal static OptionFloatItem Create(int id, OptionTab tab, TranslationStrings.TranslationString translationString, (float minValue, float maxValue, float incrementValue) Min_Max_Increment, float defaultValue, (string prefix, string postfix) Prefix_Postfix = new(), OptionItem? parent = null, bool canBeInfinite = false)
|
||||
internal static OptionFloatItem Create(OptionTab tab, TranslationStrings.TranslationString translationString, (float minValue, float maxValue, float incrementValue) Min_Max_Increment, float defaultValue, (string prefix, string postfix) Prefix_Postfix = new(), OptionItem? parent = null, bool canBeInfinite = false)
|
||||
{
|
||||
if (GetOptionById(id) is OptionFloatItem floatItem)
|
||||
if (GetOptionByTranslationName(translationString) is OptionFloatItem floatItem)
|
||||
{
|
||||
floatItem.CreateBehavior();
|
||||
return floatItem;
|
||||
@@ -57,7 +56,6 @@ public class OptionFloatItem : OptionItem<float>
|
||||
|
||||
OptionFloatItem Item = new();
|
||||
AllOptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.TranslationName = translationString;
|
||||
Item.Increment = Min_Max_Increment.incrementValue;
|
||||
|
||||
@@ -36,9 +36,8 @@ public sealed class OptionIntItem : OptionItem<int>
|
||||
private (string prefix, string postfix) Fixs { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new integer option item or returns an existing one with the same ID.
|
||||
/// Creates a new integer option item.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this option.</param>
|
||||
/// <param name="tab">The tab this option belongs to.</param>
|
||||
/// <param name="translationString">The translation key for the option name.</param>
|
||||
/// <param name="Min_Max_Increment">Tuple containing min value, max value, and increment step.</param>
|
||||
@@ -47,9 +46,9 @@ public sealed class OptionIntItem : OptionItem<int>
|
||||
/// <param name="parent">Optional parent option for hierarchical organization.</param>
|
||||
/// <param name="canBeInfinite">Whether this option can represent infinite values.</param>
|
||||
/// <returns>A new or existing OptionIntItem instance.</returns>
|
||||
internal static OptionIntItem Create(int id, OptionTab tab, TranslationStrings.TranslationString translationString, (int minValue, int maxValue, int incrementValue) Min_Max_Increment, int defaultValue, (string prefix, string postfix) Prefix_Postfix = new(), OptionItem? parent = null, bool canBeInfinite = false)
|
||||
internal static OptionIntItem Create(OptionTab tab, TranslationStrings.TranslationString translationString, (int minValue, int maxValue, int incrementValue) Min_Max_Increment, int defaultValue, (string prefix, string postfix) Prefix_Postfix = new(), OptionItem? parent = null, bool canBeInfinite = false)
|
||||
{
|
||||
if (GetOptionById(id) is OptionIntItem intItem)
|
||||
if (GetOptionByTranslationName(translationString) is OptionIntItem intItem)
|
||||
{
|
||||
intItem.CreateBehavior();
|
||||
return intItem;
|
||||
@@ -57,7 +56,6 @@ public sealed class OptionIntItem : OptionItem<int>
|
||||
|
||||
OptionIntItem Item = new();
|
||||
AllOptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.TranslationName = translationString;
|
||||
Item.Increment = Min_Max_Increment.incrementValue;
|
||||
|
||||
@@ -24,15 +24,15 @@ public abstract class OptionItem
|
||||
/// <summary>
|
||||
/// Gets the localized display name of the option.
|
||||
/// </summary>
|
||||
public string Name => TranslationName != null ? TranslationName.Value.LocalizedString : string.Empty;
|
||||
public string Name => TranslationName.LocalizedString;
|
||||
|
||||
private static int nextIdIndex;
|
||||
/// <summary>
|
||||
/// Gets the unique identifier of the option.
|
||||
/// </summary>
|
||||
public int Id => _id ?? -1;
|
||||
public int Id { get; } = 1000 * (++nextIdIndex);
|
||||
|
||||
protected int? _id { get; set; } = null;
|
||||
protected TranslationStrings.TranslationString? TranslationName { get; set; } = null;
|
||||
protected TranslationStrings.TranslationString TranslationName { get; set; } = default;
|
||||
internal OptionTab? Tab { get; set; }
|
||||
internal OptionBehaviour? Option { get; set; }
|
||||
internal GameObject? Obj { get; set; }
|
||||
@@ -54,7 +54,7 @@ public abstract class OptionItem
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier of the option.</param>
|
||||
/// <returns>The option with the specified ID, or null if not found.</returns>
|
||||
internal static OptionItem? GetOptionById(int id) => AllOptions.FirstOrDefault(opt => opt._id == id);
|
||||
internal static OptionItem? GetOptionByTranslationName(TranslationStrings.TranslationString translationString) => AllOptions.FirstOrDefault(opt => opt.TranslationName.Key == translationString.Key);
|
||||
|
||||
/// <summary>
|
||||
/// Updates the visual appearance of the option.
|
||||
@@ -105,9 +105,6 @@ public abstract class OptionItem
|
||||
/// <param name="custom">Optional custom text to display instead of the value.</param>
|
||||
internal void PopNotification(string custom = "")
|
||||
{
|
||||
if (_id == null)
|
||||
return;
|
||||
|
||||
string value = custom == string.Empty ? ValueAsString() : custom;
|
||||
string msg = $"<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">{GetParentPath()} " +
|
||||
$"<color=#868686><size=85%>{TranslationStrings.BetterSetting_SetTo}</size></color> {value}";
|
||||
@@ -557,10 +554,7 @@ public abstract class OptionItem<T> : OptionItem
|
||||
if (!CanLoad)
|
||||
return;
|
||||
|
||||
if (_id == null)
|
||||
return;
|
||||
|
||||
Value = BetterDataManager.LoadSetting(Id, DefaultValue);
|
||||
Value = BetterDataManager.LoadSetting(TranslationName.Key, DefaultValue);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -571,9 +565,6 @@ public abstract class OptionItem<T> : OptionItem
|
||||
if (!CanLoad)
|
||||
return;
|
||||
|
||||
if (_id == null)
|
||||
return;
|
||||
|
||||
BetterDataManager.SaveSetting(Id, Value);
|
||||
BetterDataManager.SaveSetting(TranslationName.Key, Value);
|
||||
}
|
||||
}
|
||||
@@ -8,17 +8,16 @@ namespace BetterAmongUs.Modules.OptionItems;
|
||||
public sealed class OptionPercentItem : OptionFloatItem
|
||||
{
|
||||
/// <summary>
|
||||
/// Creates a new percentage option item or returns an existing one with the same ID.
|
||||
/// Creates a new percentage option item.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this option.</param>
|
||||
/// <param name="tab">The tab this option belongs to.</param>
|
||||
/// <param name="translationString">The translation key for the option name.</param>
|
||||
/// <param name="defaultValue">The default percentage value (0-100).</param>
|
||||
/// <param name="parent">Optional parent option for hierarchical organization.</param>
|
||||
/// <returns>A new or existing OptionPercentItem instance.</returns>
|
||||
internal static OptionPercentItem Create(int id, OptionTab tab, TranslationStrings.TranslationString translationString, float defaultValue, OptionItem? parent = null)
|
||||
internal static OptionPercentItem Create(OptionTab tab, TranslationStrings.TranslationString translationString, float defaultValue, OptionItem? parent = null)
|
||||
{
|
||||
if (GetOptionById(id) is OptionPercentItem floatItem)
|
||||
if (GetOptionByTranslationName(translationString) is OptionPercentItem floatItem)
|
||||
{
|
||||
floatItem.CreateBehavior();
|
||||
return floatItem;
|
||||
@@ -26,7 +25,6 @@ public sealed class OptionPercentItem : OptionFloatItem
|
||||
|
||||
OptionPercentItem Item = new();
|
||||
AllOptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.TranslationName = translationString;
|
||||
Item.Increment = 5;
|
||||
|
||||
@@ -35,20 +35,19 @@ public sealed class OptionPlayerItem : OptionItem<int>
|
||||
/// </summary>
|
||||
internal override bool CanLoad => false;
|
||||
|
||||
private static List<OptionPlayerItem> optionPlayerItems = [];
|
||||
private static readonly List<OptionPlayerItem> optionPlayerItems = [];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new player option item or returns an existing one with the same ID.
|
||||
/// Creates a new player option item.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this option.</param>
|
||||
/// <param name="tab">The tab this option belongs to.</param>
|
||||
/// <param name="translationString">The translation key for the option name.</param>
|
||||
/// <param name="parent">Optional parent option for hierarchical organization.</param>
|
||||
/// <param name="canBeRandom">Whether this option allows random player selection.</param>
|
||||
/// <returns>A new or existing OptionPlayerItem instance.</returns>
|
||||
internal static OptionPlayerItem Create(int id, OptionTab tab, TranslationStrings.TranslationString translationString, OptionItem? parent = null, bool canBeRandom = true)
|
||||
internal static OptionPlayerItem Create(OptionTab tab, TranslationStrings.TranslationString translationString, OptionItem? parent = null, bool canBeRandom = true)
|
||||
{
|
||||
if (optionPlayerItems.FirstOrDefault(opt => opt.Id == id) is OptionPlayerItem playerItem)
|
||||
if (optionPlayerItems.FirstOrDefault(opt => opt.TranslationName.Key == translationString.Key) is OptionPlayerItem playerItem)
|
||||
{
|
||||
playerItem.CreateBehavior();
|
||||
return playerItem;
|
||||
@@ -57,7 +56,6 @@ public sealed class OptionPlayerItem : OptionItem<int>
|
||||
OptionPlayerItem Item = new();
|
||||
optionPlayerItems.Add(Item);
|
||||
Item.Value = canBeRandom ? -1 : 0; ;
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.TranslationName = translationString;
|
||||
Item.CanBeRandom = canBeRandom;
|
||||
|
||||
@@ -13,15 +13,12 @@ internal sealed class OptionPresetItem : OptionStringItem
|
||||
internal override bool CanLoad => false;
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new preset item for the options menu. If an item with the preset ID already exists,
|
||||
/// it reuses the existing item and sets up its behavior.
|
||||
/// Creates a new preset item for the options menu.
|
||||
/// </summary>
|
||||
/// <returns>The created or reused <see cref="OptionPresetItem"/> instance.</returns>
|
||||
internal static OptionPresetItem Create()
|
||||
{
|
||||
int id = int.MaxValue;
|
||||
|
||||
if (GetOptionById(id) is OptionPresetItem stringItem)
|
||||
if (GetOptionByTranslationName(TranslationStrings.Setting_Presets) is OptionPresetItem stringItem)
|
||||
{
|
||||
stringItem.CreateBehavior();
|
||||
return stringItem;
|
||||
@@ -29,7 +26,6 @@ internal sealed class OptionPresetItem : OptionStringItem
|
||||
|
||||
OptionPresetItem Item = new();
|
||||
AllOptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = GameSettingsPatch.BetterSettingsTab;
|
||||
Item.TranslationName = TranslationStrings.Setting_Presets;
|
||||
Item.TranslatorStrings = Enumerable.Repeat(new TranslationStrings.TranslationString(string.Empty), 10).ToArray();
|
||||
|
||||
@@ -20,9 +20,8 @@ public class OptionStringItem : OptionItem<int>
|
||||
protected TranslationStrings.TranslationString[] TranslatorStrings { get; set; } = [];
|
||||
|
||||
/// <summary>
|
||||
/// Creates a new string option item or returns an existing one with the same ID.
|
||||
/// Creates a new string option item.
|
||||
/// </summary>
|
||||
/// <param name="id">The unique identifier for this option.</param>
|
||||
/// <param name="tab">The tab this option belongs to.</param>
|
||||
/// <param name="translationStringName">The translation key for the option name.</param>
|
||||
/// <param name="translationStrings">Array of translation keys for the selectable string values.</param>
|
||||
@@ -30,14 +29,14 @@ public class OptionStringItem : OptionItem<int>
|
||||
/// <param name="parent">Optional parent option for hierarchical organization.</param>
|
||||
/// <returns>A new or existing OptionStringItem instance.</returns>
|
||||
/// <exception cref="ArgumentException">Thrown when tranStrings has less than 2 elements.</exception>
|
||||
internal static OptionStringItem Create(int id, OptionTab tab, TranslationStrings.TranslationString translationStringName, TranslationStrings.TranslationString[] translationStrings, int defaultValue, OptionItem? parent = null)
|
||||
internal static OptionStringItem Create(OptionTab tab, TranslationStrings.TranslationString translationStringName, TranslationStrings.TranslationString[] translationStrings, int defaultValue, OptionItem? parent = null)
|
||||
{
|
||||
if (translationStrings.Length < 2)
|
||||
{
|
||||
throw new ArgumentException("tranStrings must have more then 1 string!");
|
||||
}
|
||||
|
||||
if (GetOptionById(id) is OptionStringItem stringItem)
|
||||
if (GetOptionByTranslationName(translationStringName) is OptionStringItem stringItem)
|
||||
{
|
||||
stringItem.CreateBehavior();
|
||||
return stringItem;
|
||||
@@ -45,7 +44,6 @@ public class OptionStringItem : OptionItem<int>
|
||||
|
||||
OptionStringItem Item = new();
|
||||
AllOptions.Add(Item);
|
||||
Item._id = id;
|
||||
Item.Tab = tab;
|
||||
Item.TranslationName = translationStringName;
|
||||
Item.TranslatorStrings = translationStrings;
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using BetterAmongUs.Data;
|
||||
using BetterAmongUs.Data.Config;
|
||||
using BetterAmongUs.Data.Json;
|
||||
using BetterAmongUs.Generated;
|
||||
using BetterAmongUs.Managers;
|
||||
using BetterAmongUs.Modules;
|
||||
@@ -56,6 +57,7 @@ internal static class OptionsMenuBehaviourPatch
|
||||
|
||||
ClientOptionItem.CreateToggle(TranslationStrings.BetterOption_VentColorGroups, BAUConfigs.VentColorGroups, 2, __instance, MiniMapBehaviourPatch.ClearMapIcons);
|
||||
ClientOptionItem.CreateToggle(TranslationStrings.BetterOption_MinimapIcons, BAUConfigs.MinimapIcons, 2, __instance, MiniMapBehaviourPatch.ClearMapIcons);
|
||||
ClientOptionItem.CreateToggle(TranslationStrings.BetterOption_CompressSettingFiles, BAUConfigs.CompressSettingFiles, 2, __instance, ConvertAllSettingFiles);
|
||||
|
||||
// Button options (no toggle)
|
||||
if (!ModInfo.Starlight)
|
||||
@@ -126,6 +128,28 @@ internal static class OptionsMenuBehaviourPatch
|
||||
});
|
||||
}
|
||||
|
||||
private static void ConvertAllSettingFiles()
|
||||
{
|
||||
for (int i = 0; i < 10; i++)
|
||||
{
|
||||
if (i == BAUConfigs.SettingsPreset.Value)
|
||||
{
|
||||
BetterDataManager.Files.BetterGameSettingsFile.Save();
|
||||
continue;
|
||||
}
|
||||
|
||||
string path = BetterDataManager.GetSettingsFilePathFromPreset(i);
|
||||
if (File.Exists(path))
|
||||
{
|
||||
var settings = new BetterGameSettingsFile
|
||||
{
|
||||
OverrideFilePath = path
|
||||
};
|
||||
settings.Init();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static TabGroup CreateTabPage(OptionsMenuBehaviour __instance, string name)
|
||||
{
|
||||
// Clone last tab as template for new Better Options tab
|
||||
|
||||
@@ -67,79 +67,34 @@ internal static class GameSettingsPatch
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
OptionTitleItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_TextHeader_HostOnly);
|
||||
BetterGameSettings.WhenCheating = OptionStringItem.Create(100, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_WhenCheating,
|
||||
BetterGameSettings.WhenCheating = OptionStringItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_WhenCheating,
|
||||
[TranslationStrings.BetterSetting_Setting_WhenCheating_Notify, TranslationStrings.BetterSetting_Setting_WhenCheating_Kick, TranslationStrings.BetterSetting_Setting_WhenCheating_Ban], 2);
|
||||
BetterGameSettings.InvalidFriendCode = OptionCheckboxItem.Create(200, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_InvalidFriendCode, true);
|
||||
BetterGameSettings.CancelInvalidSabotage = OptionCheckboxItem.Create(900, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_CancelInvalidSabotage, true);
|
||||
BetterGameSettings.UseBanPlayerList = OptionCheckboxItem.Create(300, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanPlayerList, true);
|
||||
BetterGameSettings.UseBanNameList = OptionCheckboxItem.Create(400, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanNameList, true);
|
||||
BetterGameSettings.UseBanWordList = OptionCheckboxItem.Create(500, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanWordList, true);
|
||||
BetterGameSettings.UseBanWordListOnlyLobby = OptionCheckboxItem.Create(1400, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanWordListOnlyLobby, true, BetterGameSettings.UseBanWordList);
|
||||
BetterGameSettings.InvalidFriendCode = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_InvalidFriendCode, true);
|
||||
BetterGameSettings.CancelInvalidSabotage = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_CancelInvalidSabotage, true);
|
||||
BetterGameSettings.UseBanPlayerList = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanPlayerList, true);
|
||||
BetterGameSettings.UseBanNameList = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanNameList, true);
|
||||
BetterGameSettings.UseBanWordList = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanWordList, true);
|
||||
BetterGameSettings.UseBanWordListOnlyLobby = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_UseBanWordListOnlyLobby, true, BetterGameSettings.UseBanWordList);
|
||||
}
|
||||
|
||||
// General detection settings
|
||||
OptionTitleItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_TextHeader_Detections);
|
||||
BetterGameSettings.CensorDetectionReason = OptionCheckboxItem.Create(1300, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_CensorDetectionReason, false);
|
||||
BetterGameSettings.DetectedLevel = OptionCheckboxItem.Create(1800, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectedLevel, false);
|
||||
BetterGameSettings.DetectedLevelAbove = OptionIntItem.Create(600, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectedLevelAbove, (100, 10000, 5), 500, ("Lv ", ""), BetterGameSettings.DetectedLevel);
|
||||
BetterGameSettings.KickLevel = OptionCheckboxItem.Create(1900, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_KickLevel, false);
|
||||
BetterGameSettings.KickLevelBelow = OptionIntItem.Create(1700, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_KickLevelBelow, (0, 10000, 1), 0, ("Lv ", ""), BetterGameSettings.KickLevel);
|
||||
BetterGameSettings.DetectCheatClients = OptionCheckboxItem.Create(700, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectCheatClients, true);
|
||||
BetterGameSettings.DetectInvalidRpcs = OptionCheckboxItem.Create(800, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectInvalidRpcs, true);
|
||||
BetterGameSettings.RpcRateLimiting = OptionCheckboxItem.Create(2000, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_RpcRateLimiting, true);
|
||||
BetterGameSettings.RpcRateLimit = OptionIntItem.Create(2100, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_RateLimit, (25, 1000, 1), 50, ("", " PS"), BetterGameSettings.RpcRateLimiting);
|
||||
BetterGameSettings.CensorDetectionReason = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_CensorDetectionReason, false);
|
||||
BetterGameSettings.DetectedLevel = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectedLevel, false);
|
||||
BetterGameSettings.DetectedLevelAbove = OptionIntItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectedLevelAbove, (100, 10000, 5), 500, ("Lv ", ""), BetterGameSettings.DetectedLevel);
|
||||
BetterGameSettings.KickLevel = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_KickLevel, false);
|
||||
BetterGameSettings.KickLevelBelow = OptionIntItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_KickLevelBelow, (0, 10000, 1), 0, ("Lv ", ""), BetterGameSettings.KickLevel);
|
||||
BetterGameSettings.DetectCheatClients = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectCheatClients, true);
|
||||
BetterGameSettings.DetectInvalidRpcs = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_DetectInvalidRpcs, true);
|
||||
BetterGameSettings.RpcRateLimiting = OptionCheckboxItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_RpcRateLimiting, true);
|
||||
BetterGameSettings.RpcRateLimit = OptionIntItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_RateLimit, (25, 1000, 1), 50, ("", " PS"), BetterGameSettings.RpcRateLimiting);
|
||||
}
|
||||
|
||||
// Role algorithm settings
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_MainHeader_RoleAlgorithm);
|
||||
BetterGameSettings.RoleRandomizer = OptionStringItem.Create(1100, BetterSettingsTab, TranslationStrings.BetterSetting_Setting_RoleRandomizer, [new("System.Random"), new("UnityEngine.Random")], 0);
|
||||
// BetterGameSettings.DesyncRoles = OptionCheckboxItem.Create(1200, BetterSettingsTab, "BetterSetting.Setting.DesyncRoles", true);
|
||||
}
|
||||
|
||||
// Gameplay Settings section
|
||||
{
|
||||
// Show only for hosts
|
||||
if (IsPreload || GameState.IsHost)
|
||||
{
|
||||
/*
|
||||
// Normal game mode settings
|
||||
if (IsPreload || !GameState.IsHideNSeek)
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.Gameplay");
|
||||
BetterGameSettings.DisableSabotages = OptionCheckboxItem.Create(1500, BetterSettingsTab, "BetterSetting.Setting.DisableSabotages", false);
|
||||
BetterGameSettings.DisableSabotagesForDead = OptionCheckboxItem.Create(1600, BetterSettingsTab, "BetterSetting.Setting.DisableSabotagesForDead", false);
|
||||
}
|
||||
|
||||
// Hide & Seek specific settings with dynamic impostor selection
|
||||
if (IsPreload || GameState.IsHideNSeek)
|
||||
{
|
||||
OptionHeaderItem.Create(BetterSettingsTab, "BetterSetting.MainHeader.HideNSeek");
|
||||
OptionTitleItem.Create(BetterSettingsTab, $"<color={RoleTypes.Impostor.GetRoleHex()}>{Translator.GetString(StringNames.ImpostorsCategory)}</color>");
|
||||
BetterGameSettings.HideAndSeekImpNum = OptionIntItem.Create(1000, BetterSettingsTab, "BetterSetting.Setting.HideAndSeekImpNum", (1, 5, 1), 1);
|
||||
|
||||
// Create player selection dropdowns that appear based on impostor count
|
||||
BetterGameSettingsTemp.HideAndSeekImp2 = OptionPlayerItem.Create(0, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 2;
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp3 = OptionPlayerItem.Create(1, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp3.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 3 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.GetValue() != -1;
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp4 = OptionPlayerItem.Create(2, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp4.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 4 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.GetValue() != -1 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp3.GetValue() != -1;
|
||||
|
||||
BetterGameSettingsTemp.HideAndSeekImp5 = OptionPlayerItem.Create(3, BetterSettingsTab, "BetterSetting.TempSetting.HideAndSeekImpNum", BetterGameSettings.HideAndSeekImpNum);
|
||||
BetterGameSettingsTemp.HideAndSeekImp5.ShowCondition = () => BetterGameSettings.HideAndSeekImpNum.GetValue() >= 5 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp2.GetValue() != -1 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp3.GetValue() != -1 &&
|
||||
BetterGameSettingsTemp.HideAndSeekImp4.GetValue() != -1;
|
||||
}
|
||||
*/
|
||||
}
|
||||
BetterGameSettings.RoleRandomizer = OptionStringItem.Create(BetterSettingsTab, TranslationStrings.BetterSetting_Setting_RoleRandomizer, [new("System.Random"), new("UnityEngine.Random")], 0);
|
||||
}
|
||||
|
||||
BetterSettingsTab.UpdateVisuals();
|
||||
|
||||
@@ -63,6 +63,7 @@
|
||||
"BetterOption.ShowFPS": "ShowFPS",
|
||||
"BetterOption.VentColorGroups": "Vent Color Groups",
|
||||
"BetterOption.MinimapIcons": "Minimap Icons",
|
||||
"BetterOption.CompressSettingFiles": "Compress Setting Files",
|
||||
|
||||
"BetterOption.SaveData": "Open Save Data",
|
||||
"BetterOption.ToVanilla": "Switch To Vanilla",
|
||||
|
||||
@@ -323,6 +323,11 @@ public static class TranslationStrings
|
||||
/// </summary>
|
||||
public static readonly TranslationString BetterOption_MinimapIcons = new("BetterOption.MinimapIcons");
|
||||
|
||||
/// <summary>
|
||||
/// Base Translation: Compress Setting Files
|
||||
/// </summary>
|
||||
public static readonly TranslationString BetterOption_CompressSettingFiles = new("BetterOption.CompressSettingFiles");
|
||||
|
||||
/// <summary>
|
||||
/// Base Translation: Open Save Data
|
||||
/// </summary>
|
||||
|
||||
Reference in new issue
Block a user