Fully fix memory leak from settings UI + fix UI reload breaking it

This commit is contained in:
Gurge44 committed 2026-04-07 11:00:40 +02:00
1 parent 07296ed616
commit 52132e18f8
22 files changed
+160 -84

No files matched your search

+2
View File
@@ -207,6 +207,7 @@ public class Main : BasePlugin
public static ConfigEntry<bool> ButtonCooldownInDecimalUnder10s { get; private set; }
public static ConfigEntry<bool> CancelPetAnimation { get; private set; }
public static ConfigEntry<bool> TryFixStuttering { get; private set; }
public static ConfigEntry<bool> ShowClientControlGUI { get; private set; }
public static ConfigEntry<float> UIScaleFactor { get; private set; }
// Preset Name Options
@@ -300,6 +301,7 @@ public class Main : BasePlugin
ButtonCooldownInDecimalUnder10s = Config.Bind("Client Options", "ButtonCooldownInDecimalUnder10s", false);
CancelPetAnimation = Config.Bind("Client Options", "CancelPetAnimation", true);
TryFixStuttering = Config.Bind("Client Options", "TryFixStuttering", true);
ShowClientControlGUI = Config.Bind("Client Options", "ShowClientControlGUI", true);
UIScaleFactor = Config.Bind("Client Options", "UIScaleFactor", 1f);
AddComponent<ClientControlGUI>();
+1 -1
View File
@@ -25,7 +25,7 @@ public class ClientOptionItem
ToggleButtonBehaviour mouseMoveToggle = optionsMenuBehaviour.DisableMouseMovement;
if (CustomBackground == null)
if (!CustomBackground)
{
CustomBackground = Object.Instantiate(optionsMenuBehaviour.Background, optionsMenuBehaviour.transform);
CustomBackground.name = "CustomBackground";
+8 -9
View File
@@ -8,7 +8,6 @@ namespace EHR.Modules.Extensions;
public sealed class CountdownTimer : IDisposable
{
private readonly float _durationSeconds;
private readonly Stopwatch _stopwatch;
private Coroutine _coroutine;
private bool _completed;
@@ -27,7 +26,7 @@ public sealed class CountdownTimer : IDisposable
throw new ArgumentOutOfRangeException(nameof(durationSeconds));
_durationSeconds = durationSeconds;
_stopwatch = new Stopwatch();
Stopwatch = new Stopwatch();
_cancelOnMeeting = cancelOnMeeting;
_cancelOnGameEnd = cancelOnGameEnd;
@@ -57,12 +56,12 @@ public sealed class CountdownTimer : IDisposable
if (_completed)
return TimeSpan.Zero;
TimeSpan remaining = TimeSpan.FromSeconds(_durationSeconds) - _stopwatch.Elapsed;
TimeSpan remaining = TimeSpan.FromSeconds(_durationSeconds) - Stopwatch.Elapsed;
return remaining >= TimeSpan.Zero ? remaining : TimeSpan.Zero;
}
}
public Stopwatch Stopwatch => _stopwatch;
public Stopwatch Stopwatch { get; }
public void Start()
{
@@ -70,7 +69,7 @@ public sealed class CountdownTimer : IDisposable
return;
_completed = false;
_stopwatch.Restart();
Stopwatch.Restart();
_coroutine = Main.Instance.StartCoroutine(_hasTickEvent ? Run() : RunWithoutTicks());
}
@@ -84,7 +83,7 @@ public sealed class CountdownTimer : IDisposable
{
int lastRemaining = (int)Math.Ceiling(Remaining.TotalSeconds);
while (_stopwatch.Elapsed.TotalSeconds < _durationSeconds)
while (Stopwatch.Elapsed.TotalSeconds < _durationSeconds)
{
int remaining = (int)Math.Ceiling(Remaining.TotalSeconds);
@@ -101,7 +100,7 @@ public sealed class CountdownTimer : IDisposable
if (remaining > 1)
yield return new WaitForSecondsRealtime(1f);
else
yield return new WaitForSecondsRealtime((float)(_durationSeconds - _stopwatch.Elapsed.TotalSeconds));
yield return new WaitForSecondsRealtime((float)(_durationSeconds - Stopwatch.Elapsed.TotalSeconds));
}
Complete();
@@ -119,7 +118,7 @@ public sealed class CountdownTimer : IDisposable
return;
_completed = true;
_stopwatch.Stop();
Stopwatch.Stop();
try
{
@@ -146,7 +145,7 @@ public sealed class CountdownTimer : IDisposable
_coroutine = null;
}
_stopwatch.Stop();
Stopwatch.Stop();
OnElapsed = null;
OnTick = null;
OnCanceled = null;
+28
View File
@@ -1200,6 +1200,34 @@ public static class GuessManager
public static void Postfix()
{
Object.Destroy(TextTemplate.gameObject);
if (GuesserUI) Object.Destroy(GuesserUI);
foreach (List<Transform> roleButtonsValue in RoleButtons.Values)
{
foreach (Transform transform in roleButtonsValue)
{
if (transform.gameObject)
Object.Destroy(transform.gameObject);
}
}
foreach (SpriteRenderer spriteRenderer in RoleSelectButtons.Values)
{
if (spriteRenderer.gameObject)
Object.Destroy(spriteRenderer.gameObject);
}
foreach (SpriteRenderer spriteRenderer in PageButtons)
{
if (spriteRenderer.gameObject)
Object.Destroy(spriteRenderer.gameObject);
}
TextTemplate = null;
GuesserUI = null;
RoleButtons.Clear();
RoleSelectButtons.Clear();
PageButtons.Clear();
}
}
+37 -32
View File
@@ -30,6 +30,7 @@ public static class ModUpdater
public static string DownloadUrl;
private static GenericPopup InfoPopup;
private static GenericPopup InfoPopupV2;
private static readonly HttpClient HttpClient = new();
[HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start))]
[HarmonyPrefix]
@@ -75,8 +76,7 @@ public static class ModUpdater
public static string Get(string url)
{
string result;
HttpClient req = new();
HttpResponseMessage res = req.GetAsync(url).Result;
HttpResponseMessage res = HttpClient.GetAsync(url).Result;
Stream stream = res.Content.ReadAsStreamAsync().Result;
try
@@ -227,9 +227,7 @@ public static class ModUpdater
// Delete the temporary file if it exists
if (File.Exists(savePath)) File.Delete(savePath);
HttpResponseMessage response;
using (HttpClient client = new()) response = await client.GetAsync(url);
HttpResponseMessage response = await HttpClient.GetAsync(url);
if (response is not { IsSuccessStatusCode: true }) throw new($"File retrieval failed with status code: {response.StatusCode}");
@@ -266,9 +264,7 @@ public static class ModUpdater
// Delete the temporary file if it exists
if (File.Exists(savePath)) File.Delete(savePath);
HttpResponseMessage response;
using (HttpClient client = new()) response = await client.GetAsync(url);
HttpResponseMessage response = await HttpClient.GetAsync(url);
if (response is not { IsSuccessStatusCode: true }) throw new($"File retrieval failed with status code: {response.StatusCode}");
@@ -302,41 +298,44 @@ public static class ModUpdater
public static void ShowPopup(string message, StringNames buttonText, bool showButton = false, bool buttonIsExit = true)
{
if (InfoPopup == null) return;
if (!InfoPopup) return;
InfoPopup.Show(message);
Transform button = InfoPopup.transform.FindChild("ExitGame");
if (button != null)
if (button)
{
button.gameObject.SetActive(showButton);
button.GetChild(0).GetComponent<TextTranslatorTMP>().TargetText = buttonText;
button.GetChild(0).GetComponent<TextTranslatorTMP>().ResetText();
button.GetComponent<PassiveButton>().OnClick = new();
var textTranslatorTMP = button.GetChild(0).GetComponent<TextTranslatorTMP>();
textTranslatorTMP.TargetText = buttonText;
textTranslatorTMP.ResetText();
var passiveButton = button.GetComponent<PassiveButton>();
passiveButton.OnClick = new();
if (buttonIsExit)
button.GetComponent<PassiveButton>().OnClick.AddListener((Action)Application.Quit);
passiveButton.OnClick.AddListener((Action)Application.Quit);
else
button.GetComponent<PassiveButton>().OnClick.AddListener((Action)(() => InfoPopup.Close()));
passiveButton.OnClick.AddListener((Action)(() => InfoPopup.Close()));
}
}
private static void ShowPopupWithTwoButtons(string message, string firstButtonText, string secondButtonText = "", Action onClickOnFirstButton = null, Action onClickOnSecondButton = null)
{
if (InfoPopupV2 != null)
if (InfoPopupV2)
{
var templateExitGame = InfoPopupV2.transform.FindChild("ExitGame");
if (templateExitGame == null) return;
if (!templateExitGame) return;
var background = InfoPopupV2.transform.FindChild("Background");
if (background == null) return;
if (!background) return;
background.localScale *= 2f;
InfoPopupV2.Show(message);
templateExitGame.gameObject.SetActive(false);
var firstButton = Object.Instantiate(templateExitGame, InfoPopupV2.transform);
var secondButton = Object.Instantiate(templateExitGame, InfoPopupV2.transform);
if (firstButton != null)
if (firstButton)
{
firstButton.gameObject.SetActive(true);
firstButton.name = "FirstButton";
@@ -344,17 +343,20 @@ public static class ModUpdater
firstButton.transform.localPosition = new Vector3(firstButtonTransform.localPosition.x - 1f, firstButtonTransform.localPosition.y - 0.7f, firstButtonTransform.localPosition.z);
firstButton.transform.localScale *= 1.2f;
var firstButtonGetChild = firstButton.GetChild(0);
firstButtonGetChild.GetComponent<TextTranslatorTMP>().TargetText = StringNames.Cancel;
firstButtonGetChild.GetComponent<TextTranslatorTMP>().ResetText();
firstButtonGetChild.GetComponent<TextTranslatorTMP>().DestroyTranslator();
var textTranslatorTMP = firstButtonGetChild.GetComponent<TextTranslatorTMP>();
textTranslatorTMP.TargetText = StringNames.Cancel;
textTranslatorTMP.ResetText();
textTranslatorTMP.DestroyTranslator();
firstButtonGetChild.GetComponent<TextMeshPro>().text = firstButtonText;
firstButtonGetChild.GetComponent<TMP_Text>().text = firstButtonText;
firstButton.GetComponent<PassiveButton>().OnClick = new();
var passiveButton = firstButton.GetComponent<PassiveButton>();
passiveButton.OnClick = new();
if (onClickOnFirstButton != null)
firstButton.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() => { onClickOnFirstButton(); InfoPopupV2.Close();}));
else firstButton.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() => InfoPopupV2.Close()));
passiveButton.OnClick.AddListener((UnityAction)(() => { onClickOnFirstButton(); InfoPopupV2.Close();}));
else passiveButton.OnClick.AddListener((UnityAction)(() => InfoPopupV2.Close()));
}
if (secondButton != null)
if (secondButton)
{
secondButton.gameObject.SetActive(true);
secondButton.name = "SecondButton";
@@ -362,18 +364,21 @@ public static class ModUpdater
secondButton.transform.localPosition = new Vector3(secondButtonTransform.localPosition.x + 1f, secondButtonTransform.localPosition.y - 0.7f, secondButtonTransform.localPosition.z);
secondButton.transform.localScale *= 1.2f;
var secondButtonGetChild = secondButton.GetChild(0);
secondButtonGetChild.GetComponent<TextTranslatorTMP>().TargetText = StringNames.Cancel;
secondButtonGetChild.GetComponent<TextTranslatorTMP>().ResetText();
var textTranslatorTMP = secondButtonGetChild.GetComponent<TextTranslatorTMP>();
textTranslatorTMP.TargetText = StringNames.Cancel;
textTranslatorTMP.ResetText();
if (!string.IsNullOrWhiteSpace(secondButtonText))
{
secondButtonGetChild.GetComponent<TextTranslatorTMP>().DestroyTranslator();
textTranslatorTMP.DestroyTranslator();
secondButtonGetChild.GetComponent<TextMeshPro>().text = secondButtonText;
secondButtonGetChild.GetComponent<TMP_Text>().text = secondButtonText;
}
secondButton.GetComponent<PassiveButton>().OnClick = new();
var passiveButton = secondButton.GetComponent<PassiveButton>();
passiveButton.OnClick = new();
if (onClickOnSecondButton != null)
secondButton.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() => { onClickOnSecondButton(); InfoPopupV2.Close(); }));
else secondButton.GetComponent<PassiveButton>().OnClick.AddListener((UnityAction)(() => InfoPopupV2.Close()));
passiveButton.OnClick.AddListener((UnityAction)(() => { onClickOnSecondButton(); InfoPopupV2.Close(); }));
else passiveButton.OnClick.AddListener((UnityAction)(() => InfoPopupV2.Close()));
}
}
}
-1
View File
@@ -98,7 +98,6 @@ public static class OnlinePresetsManager
TextMeshPro plusText = row.PlusBtn.GetComponentInChildren<TextMeshPro>();
plusText.DestroyTranslator();
plusText.text = "ⓘ";
row.PlusBtn.transform.localPosition += new Vector3(1.8f, 0f, 0f);
row.PlusBtn.OnClick = new();
row.PlusBtn.OnClick.AddListener((UnityAction)(() =>
{
+2 -1
View File
@@ -65,7 +65,8 @@ public abstract class OptionItem
private bool IsHidden { get; set; }
public bool IsText { get; protected set; }
public TextOptionItem Header { get; set; } = null;
public TextOptionItem Header { get; set; }
public BaseGameSetting CachedSetting { get; set; }
public Dictionary<string, string> ReplacementDictionary
{
+19
View File
@@ -33,6 +33,7 @@ public static class OptionsMenuBehaviourStartPatch
private static ClientOptionItem ButtonCooldownInDecimalUnder10s;
private static ClientOptionItem CancelPetAnimation;
private static ClientOptionItem TryFixStuttering;
private static ClientOptionItem ShowClientControlGUI;
#if DEBUG
private static ClientOptionItem GodMode;
#endif
@@ -256,6 +257,24 @@ public static class OptionsMenuBehaviourStartPatch
}
}
}
if (ShowClientControlGUI == null || !ShowClientControlGUI.ToggleButton)
{
ShowClientControlGUI = ClientOptionItem.Create("ShowClientControlGUI", Main.ShowClientControlGUI, __instance, ShowClientControlGUIButtonToggle);
static void ShowClientControlGUIButtonToggle()
{
switch (Main.ShowClientControlGUI.Value)
{
case true when !ClientControlGUI.Instance:
Main.Instance.AddComponent<ClientControlGUI>();
break;
case false when ClientControlGUI.Instance:
Object.Destroy(ClientControlGUI.Instance);
break;
}
}
}
#if DEBUG
if ((GodMode == null || GodMode.ToggleButton == null) && DebugModeManager.AmDebugger)
+24 -18
View File
@@ -20,7 +20,7 @@ namespace EHR;
public static class ModGameOptionsMenu
{
public static int TabIndex;
public static readonly List<BaseGameSetting> BaseGameSettingCache = new();
public static readonly List<Coroutine> RunningMainCoroutines = new();
public static readonly Dictionary<OptionBehaviour, int> OptionList = new();
public static readonly Dictionary<int, OptionBehaviour> BehaviourList = new();
public static readonly Dictionary<int, CategoryHeaderMasked> CategoryHeaderList = new();
@@ -46,7 +46,7 @@ public static class ModGameOptionsMenu
foreach (var btn in ui.GetComponentsInChildren<PassiveButton>(true))
btn.OnClick.RemoveAllListeners();
Object.Destroy(ui);
Object.DestroyImmediate(ui);
}
SpawnedUI.Clear();
@@ -64,7 +64,7 @@ public static class ModGameOptionsMenu
kv.Key.SetClickMask(null);
if (kv.Key.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Object.Destroy(kv.Key.gameObject);
Object.DestroyImmediate(kv.Key.gameObject);
}
}
@@ -76,7 +76,7 @@ public static class ModGameOptionsMenu
kv.Value.SetClickMask(null);
if (kv.Value.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Object.Destroy(kv.Value.gameObject);
Object.DestroyImmediate(kv.Value.gameObject);
}
}
@@ -86,18 +86,20 @@ public static class ModGameOptionsMenu
{
if (kv.Value.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Object.Destroy(kv.Value.gameObject);
Object.DestroyImmediate(kv.Value.gameObject);
}
}
foreach (var setting in BaseGameSettingCache)
foreach (var co in RunningMainCoroutines)
{
if (setting) Object.Destroy(setting);
if (co != null)
Main.Instance.StopCoroutine(co);
}
OptionList.Clear();
BehaviourList.Clear();
CategoryHeaderList.Clear();
BaseGameSettingCache.Clear();
RunningMainCoroutines.Clear();
}
}
@@ -289,8 +291,6 @@ public static class GameOptionsMenuPatch
foreach (UiElement x in __instance.scrollBar.GetComponentsInChildren<UiElement>())
__instance.ControllerSelectable.Add(x);
yield break;
}
float CalculateScrollBarYBoundsMax()
@@ -468,6 +468,8 @@ public static class GameOptionsMenuPatch
}
public static BaseGameSetting GetSetting(OptionItem item)
{
if (item.CachedSetting) return item.CachedSetting;
BaseGameSetting baseGameSetting;
switch (item)
@@ -525,7 +527,7 @@ public static class GameOptionsMenuPatch
if (baseGameSetting)
{
baseGameSetting.Title = StringNames.Accept;
ModGameOptionsMenu.BaseGameSettingCache.Add(baseGameSetting);
item.CachedSetting = baseGameSetting;
}
return baseGameSetting;
}
@@ -878,7 +880,11 @@ public static class StringOptionPatch
long now = Utils.TimeStamp;
bool startCoRoutine = now > HelpShowEndTS;
HelpShowEndTS = now + 15;
if (startCoRoutine) Main.Instance.StartCoroutine(CoRoutine());
if (startCoRoutine)
{
var co = Main.Instance.StartCoroutine(CoRoutine());
ModGameOptionsMenu.RunningMainCoroutines.Add(co);
}
IEnumerator CoRoutine()
{
@@ -1077,14 +1083,14 @@ public static class GameSettingMenuPatch
private static float VanillaKillCooldownOnOpen = 1;
private static float ModdedKillCooldownOnOpen = 1;
public static void DestroySetting()
private static void DestroySetting()
{
foreach (var button in ModSettingsButtons.Values)
{
if (button)
{
button.OnClick.RemoveAllListeners();
Object.Destroy(button.gameObject);
Object.DestroyImmediate(button.gameObject);
}
}
@@ -1101,7 +1107,7 @@ public static class GameSettingMenuPatch
if (child.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Object.Destroy(child.gameObject);
Object.DestroyImmediate(child.gameObject);
}
tab.Children.Clear();
}
@@ -1109,7 +1115,7 @@ public static class GameSettingMenuPatch
}
foreach (var gmButton in GMButtons)
if (gmButton) Object.Destroy(gmButton);
if (gmButton) Object.DestroyImmediate(gmButton);
ModSettingsButtons.Clear();
ModSettingsTabs.Clear();
@@ -1499,7 +1505,7 @@ public static class GameSettingMenuPatch
if (!OnlinePresetsManager.PresetsLoaded && tabGroup == TabGroup.PresetExplorer)
{
Main.Instance.StartCoroutine(
var co = Main.Instance.StartCoroutine(
OnlinePresetsManager.FetchPresetList(list =>
{
OnlinePresetsManager.CachedPresets = list;
@@ -1507,6 +1513,7 @@ public static class GameSettingMenuPatch
GameOptionsMenuPatch.ReloadUI();
})
);
ModGameOptionsMenu.RunningMainCoroutines.Add(co);
}
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
@@ -1678,5 +1685,4 @@ public static class RpcSyncSettingsPatch
{
OptionItem.SyncAllOptions();
}
}
+24 -11
View File
@@ -28,6 +28,20 @@ public static class LobbyViewSettingsPanePatch
private static readonly HashSet<CustomRoles> RoleEnabledList = [];
private static StringNames VanillaSettingsTabName => StringNames.OverviewCategory;
private static StringNames VanillaRolesTabName => StringNames.RolesCategory;
// Storing Unity objects in static variables prevents GC from collecting them
// (and everything inside them, like event listeners)
// even if the object was destroyed
// This method doesn't check object lifetime because it's called when a game starts,
// and these are guaranteed to be destroyed by then
public static void ClearReferences()
{
RoleListCoroutine = null;
OptionsCoroutine = null;
ShowOnlyEnabledRolesButton = null;
TabButtons.Clear();
AllTabButtons.Clear();
}
[HarmonyPatch(nameof(LobbyViewSettingsPane.Awake))]
[HarmonyPostfix]
@@ -293,7 +307,7 @@ public static class LobbyViewSettingsPanePatch
rightPassiveButton.OnClick.AddListener((UnityAction)(() =>
{
LastGameModeSelected++;
CustomGameMode[] enumGameModes = Enum.GetValues<CustomGameMode>().Without(CustomGameMode.All).ToArray();
CustomGameMode[] enumGameModes = Enum.GetValues<CustomGameMode>()[..^1];
if ((int)LastGameModeSelected > enumGameModes.Length)
LastGameModeSelected = CustomGameMode.Standard;
__instance.ChangeTab(VanillaSettingsTabName);
@@ -313,7 +327,7 @@ public static class LobbyViewSettingsPanePatch
leftButtonPassiveButton.OnClick.AddListener((UnityAction)(() =>
{
LastGameModeSelected--;
CustomGameMode[] enumGameModes = Enum.GetValues<CustomGameMode>().Without(CustomGameMode.All).ToArray();
CustomGameMode[] enumGameModes = Enum.GetValues<CustomGameMode>()[..^1];
if ((int)LastGameModeSelected < 0x01)
LastGameModeSelected = (CustomGameMode)enumGameModes.Length;
__instance.ChangeTab(VanillaSettingsTabName);
@@ -722,7 +736,7 @@ public static class LobbyViewSettingsPanePatch
private static void DrawRoles(LobbyViewSettingsPane viewSettings, TabGroup tabName)
{
var yPos = 1.3f;
var xPos = -6.53f;
const float xPos = -6.53f;
float xPosOpt;
var index = 0;
RoleEnabledList.Clear();
@@ -828,7 +842,7 @@ public static class LobbyViewSettingsPanePatch
// Roles
if (allCustomRoles.FindFirst(x => x.ToString() == realName, out CustomRoles role))
{
if (role == default(CustomRoles) || role is CustomRoles.CovenLeader) continue;
if (role is default(CustomRoles) or CustomRoles.CovenLeader) continue;
try
{
@@ -911,9 +925,7 @@ public static class LobbyViewSettingsPanePatch
viewSettings.settingsInfo.Add(viewSettingsInfoPanelRoleVariant.gameObject);
yPos -= 0.65f;
}
else if (LastGameModeSelected == CustomGameMode.HideAndSeek && role is CustomRoles.Seeker or CustomRoles.Hider)
RoleEnabledList.Add(role);
else if (!enabledOrNotCollapsed && enabled && !roleDisabled)
else if (LastGameModeSelected == CustomGameMode.HideAndSeek && role is CustomRoles.Seeker or CustomRoles.Hider || !enabledOrNotCollapsed && enabled && !roleDisabled)
RoleEnabledList.Add(role);
}
catch (Exception e) { Utils.ThrowException(e); }
@@ -922,8 +934,8 @@ public static class LobbyViewSettingsPanePatch
{
// Skip all role settings
if (option.Parent != null && allCustomRoles.Any(x => x.ToString() == option.Parent?.Name)) continue;
else if (option.Parent?.Parent != null && allCustomRoles.Any(x => x.ToString() == option.Parent?.Parent?.Name)) continue;
else if (option.Parent?.Parent?.Parent != null && allCustomRoles.Any(x => x.ToString() == option.Parent?.Parent?.Parent.Name)) continue;
if (option.Parent?.Parent != null && allCustomRoles.Any(x => x.ToString() == option.Parent?.Parent?.Name)) continue;
if (option.Parent?.Parent?.Parent != null && allCustomRoles.Any(x => x.ToString() == option.Parent?.Parent?.Parent.Name)) continue;
ViewSettingsInfoPanel viewSettingsInfoPanel = Object.Instantiate(viewSettings.infoPanelOrigin, Vector3.zero, Quaternion.identity, viewSettings.settingsContainer);
viewSettingsInfoPanel.name = option.Name;
@@ -986,6 +998,7 @@ public static class LobbyViewSettingsPanePatch
if (RoleEnabledList.Count <= 0) yield break;
yield return CoShowRoleSettings().WrapToIl2Cpp();
yield break;
IEnumerator CoShowRoleSettings()
{
@@ -1001,8 +1014,8 @@ public static class LobbyViewSettingsPanePatch
float leftY = startY;
float rightY = startY;
float leftX = -5.8f;
var rightX = 0.15f;
const float leftX = -5.8f;
const float rightX = 0.15f;
foreach (CustomRoles role in RoleEnabledList)
{
+1 -1
View File
@@ -185,7 +185,7 @@ public static class MainMenuManagerPatch
{
GameOptionsManager.Instance.Initialize();
if (GameOptionsManager.Instance.normalGameHostOptions.MapId is 3 or > 5)
if (GameOptionsManager.Instance.normalGameHostOptions.MapId == 3 || (GameOptionsManager.Instance.normalGameHostOptions.MapId > 5 && !SubmergedCompatibility.Loaded))
{
GameOptionsManager.Instance.normalGameHostOptions.MapId = 0;
GameOptionsManager.Instance.SaveNormalHostOptions();
+2
View File
@@ -280,6 +280,8 @@ internal static class ChangeRoleSettings
ChatCommands.LastSpectators.UnionWith(ChatCommands.Spectators);
RPCHandlerPatch.RemoveExpiredWhiteList();
LobbyViewSettingsPanePatch.ClearReferences();
try
{
+1
View File
@@ -10589,6 +10589,7 @@
"ButtonCooldownInDecimalUnder10s": "Button Cooldown in Decimal Under 10s",
"CancelPetAnimation": "Fully Cancel Self Pet Animation As Host",
"TryFixStuttering": "Try to Fix Stuttering",
"ShowClientControlGUI": "Show Client Control GUI",
"GM": "Game Master",
"GMInfo": "Spectate the chaos!",
"GMInfoLong": "(Other):\\nThe Game Master is an observer role. Their presence does not affect the game; all players know who the Game Master is. The Game Master role will be assigned to the Host/Spectators, who will automatically become a ghost at the start of the game.",
@@ -81,7 +81,7 @@ public class Imitator : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates.ToArray())
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || pc.IsAlive()) continue;
if (!pc || pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
@@ -418,7 +418,7 @@ public class Inspector : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates)
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
+1 -1
View File
@@ -267,7 +267,7 @@ public class Judge : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates)
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
@@ -135,7 +135,7 @@ public class Retributionist : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates.ToArray())
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
+1 -1
View File
@@ -281,7 +281,7 @@ public class Swapper : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates)
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
@@ -295,7 +295,7 @@ public class Councillor : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates.ToArray())
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
+1 -1
View File
@@ -204,7 +204,7 @@ internal class Nemesis : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates.ToArray())
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
@@ -64,7 +64,7 @@ public class Ventriloquist : RoleBase
foreach (PlayerVoteArea pva in __instance.playerStates.ToArray())
{
PlayerControl pc = Utils.GetPlayerById(pva.TargetPlayerId);
if (pc == null || !pc.IsAlive()) continue;
if (!pc || !pc.IsAlive()) continue;
GameObject template = pva.Buttons.transform.Find("CancelButton").gameObject;
GameObject targetBox = Object.Instantiate(template, pva.transform);
+3 -2
View File
@@ -105,8 +105,9 @@ public class Starspawn : RoleBase
private static void CreateStarspawnButton(MeetingHud __instance)
{
if (GameObject.Find("StarspawnButton") != null) Object.Destroy(GameObject.Find("StarspawnButton").gameObject);
if (PlayerControl.LocalPlayer == null || !PlayerControl.LocalPlayer.IsAlive()) return;
GameObject existingButton = GameObject.Find("StarspawnButton");
if (existingButton) Object.Destroy(existingButton.gameObject);
if (!PlayerControl.LocalPlayer || !PlayerControl.LocalPlayer.IsAlive()) return;
GameObject parent = GameObject.Find("Main Camera").transform.Find("Hud").Find("ChatUi").Find("ChatScreenRoot").Find("ChatScreenContainer").gameObject;
GameObject template = __instance.transform.Find("MeetingContents").Find("ButtonStuff").Find("button_skipVoting").gameObject;