FINALLY FIX MEMORY LEAK OMG (+ improved the lobby settings UI overall)

This commit is contained in:
Gurge44 committed 2026-06-10 15:30:05 +02:00
1 parent 3bb0758e55
commit bccb216e2d
29 files changed
+365 -557

No files matched your search

+1 -1
View File
@@ -33,7 +33,7 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2026.3.31" PrivateAssets="all" Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Debug'" />
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2026.6.5" PrivateAssets="all" Condition="'$(Configuration)' == 'Release' Or '$(Configuration)' == 'Debug'" />
<PackageReference Include="AmongUs.GameLibs.Android" Version="2025.10.14" PrivateAssets="all" Condition="'$(Configuration)' == 'Android'"/>
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1"/>
<PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.735" Private="false" ExcludeAssets="runtime;native" />
+2
View File
@@ -326,6 +326,8 @@ public static class CaptureTheFlag
if (pc && outfit != null)
Utils.RpcChangeSkin(pc, outfit);
}
DefaultOutfits = [];
}
}
+1 -1
View File
@@ -174,7 +174,7 @@ internal static class CustomHnS
}
}
Dictionary<Team, PlayerControl[]> playerTeams =Main.TeamValues[1..4]
Dictionary<Team, PlayerControl[]> playerTeams = Main.TeamValues[1..4]
.SelectMany(x => Enumerable.Repeat(x, Math.Max(memberNum[x], 0)))
.Shuffle()
.Zip(allPlayers)
+5 -1
View File
@@ -664,7 +664,11 @@ public static class KingOfTheZones
}
}
void ResetSkins() => DefaultOutfits.Select(x => (pc: x.Key.GetPlayer(), outfit: x.Value)).DoIf(x => x.pc && x.outfit != null, x => Utils.RpcChangeSkin(x.pc, x.outfit));
void ResetSkins()
{
DefaultOutfits.Select(x => (pc: x.Key.GetPlayer(), outfit: x.Value)).DoIf(x => x.pc && x.outfit != null, x => Utils.RpcChangeSkin(x.pc, x.outfit));
DefaultOutfits = [];
}
}
public static bool IsNotInLocalPlayersTeam(PlayerControl pc)
+1 -2
View File
@@ -14,7 +14,6 @@ public static class TheMindGame
{
private static Dictionary<byte, int> Points = [];
private static Dictionary<byte, int> SuperPoints = [];
private static Dictionary<PlayerControl, int> DefaultColorIds = [];
private static Dictionary<byte, Group> Groups = [];
private static Dictionary<Group, List<byte>> GroupPlayers = [];
private static List<SystemTypes> AllRooms = [];
@@ -276,7 +275,7 @@ public static class TheMindGame
var pcCount = aapc.Count;
Points = aapc.ToDictionary(x => x.PlayerId, _ => 0);
SuperPoints = aapc.ToDictionary(x => x.PlayerId, _ => 0);
DefaultColorIds = aapc.ToDictionary(x => x, x => x.Data.DefaultOutfit.ColorId);
aapc.ToDictionary(x => x, x => x.Data.DefaultOutfit.ColorId);
PlayerItems = aapc.ToDictionary(x => x.PlayerId, _ => new List<Item>());
Groups = [];
+6
View File
@@ -1060,6 +1060,12 @@ public class Main : BasePlugin
catch (Exception e) { Utils.ThrowException(e); }
}
public Coroutine StartCoroutine(Il2CppSystem.Collections.IEnumerator coroutine)
{
if (coroutine == null) return null;
return coroutines.StartCoroutine(coroutine);
}
public Coroutine StartCoroutine(IEnumerator coroutine)
{
if (coroutine == null) return null;
-2
View File
@@ -46,7 +46,6 @@ public static class Camouflage
public static bool IsCamouflage;
public static bool BlockCamouflage;
public static Dictionary<byte, NetworkedPlayerInfo.PlayerOutfit> PlayerSkins = [];
public static List<byte> ResetSkinAfterDeathPlayers = [];
private static HashSet<byte> WaitingForSkinChange = [];
private static int SkippedCamoTimes;
@@ -57,7 +56,6 @@ public static class Camouflage
{
IsCamouflage = false;
PlayerSkins = [];
ResetSkinAfterDeathPlayers = [];
WaitingForSkinChange = [];
SkippedCamoTimes = 0;
+4 -2
View File
@@ -969,8 +969,10 @@ static class PreventLargePacketKickPatch
public static bool Prefix([HarmonyArgument(0)] MessageWriter msg)
{
if (msg.Length <= 1200) return true;
if (GameStates.CurrentServerType is GameStates.ServerType.Local or GameStates.ServerType.Vanilla)
var serverType = GameStates.CurrentServerType;
if (serverType is GameStates.ServerType.Local or GameStates.ServerType.Vanilla || (serverType == GameStates.ServerType.Niko && msg.Length > 1400))
{
Logger.Warn($" Blocked large packet from sending (size: {msg.Length})", nameof(PreventLargePacketKickPatch));
return false;
+3 -16
View File
@@ -457,13 +457,7 @@ public static class CollectionExtensions
foreach (PlayerControl player in players)
{
hasValue |= sender.Notify(player, text, time, overrideAll, log, setName);
if (sender.stream.Length > 500)
{
sender.SendMessage();
sender = CustomRpcSender.Create("NotifyPlayers", SendOption.Reliable);
hasValue = false;
}
// RpcSetName will handle oversized packets
}
sender.SendMessage(dispose: !hasValue);
@@ -475,15 +469,8 @@ public static class CollectionExtensions
for (int index = 0; index < players.Count; index++)
{
PlayerControl player = players[index];
hasValue |= sender.Notify(player, text, time, overrideAll, log, setName);
if (sender.stream.Length > 500)
{
sender.SendMessage();
sender = CustomRpcSender.Create("NotifyPlayers", SendOption.Reliable);
hasValue = false;
}
hasValue |= sender.Notify(players[index], text, time, overrideAll, log, setName);
// RpcSetName will handle oversized packets
}
sender.SendMessage(dispose: !hasValue);
+30 -27
View File
@@ -14,20 +14,25 @@ namespace EHR.Modules;
public static class OnlinePresetsManager
{
private static readonly Dictionary<int, StringOption> OptionBehaviourCache = [];
private static readonly Dictionary<int, CategoryHeaderMasked> HeaderCache = [];
public static List<PresetMeta> CachedPresets = [];
public static bool PresetsLoaded = false;
public static IEnumerator CreatePresetExplorerUI(GameOptionsMenu menu)
public static void CreatePresetExplorerUI(GameOptionsMenu menu)
{
if (!PresetsLoaded) return;
float y = 2.0f;
{
CategoryHeaderMasked header = ModGameOptionsMenu.Track(Object.Instantiate(
CategoryHeaderMasked header = HeaderCache.TryGetValue(0, out CategoryHeaderMasked cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate(
menu.categoryHeaderOrigin,
Vector3.zero,
Quaternion.identity,
menu.settingsContainer
));
HeaderCache[0] = header;
header.SetHeader(StringNames.RolesCategory, 20);
header.Title.DestroyTranslator();
@@ -37,11 +42,11 @@ public static class OnlinePresetsManager
y -= 0.8f;
StringOption upload = ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer));
StringOption upload = OptionBehaviourCache.TryGetValue(-1, out StringOption uploadCache) ? uploadCache : ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer));
upload.name = nameof(OnlinePresetsManager) + ";" + Translator.GetString("UploadPreset");
upload.transform.localPosition = new Vector3(0.952f, y, -2f);
upload.SetClickMask(menu.ButtonClickMask);
upload.SetUpFromData(ScriptableObject.CreateInstance<StringGameSetting>(), 20);
upload.SetUpFromData(null, 20);
Object.Destroy(upload.transform.FindChild("Value_TMP (1)").gameObject);
Object.Destroy(upload.transform.FindChild("ValueBox").gameObject);
@@ -57,17 +62,19 @@ public static class OnlinePresetsManager
upload.gameObject.SetActive(true);
menu.Children.Add(upload);
OptionBehaviourCache[-1] = upload;
y -= 0.6f;
}
{
CategoryHeaderMasked header = ModGameOptionsMenu.Track(Object.Instantiate(
CategoryHeaderMasked header = HeaderCache.TryGetValue(1, out CategoryHeaderMasked cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate(
menu.categoryHeaderOrigin,
Vector3.zero,
Quaternion.identity,
menu.settingsContainer
));
HeaderCache[1] = header;
header.SetHeader(StringNames.RolesCategory, 20);
header.Title.DestroyTranslator();
@@ -78,23 +85,22 @@ public static class OnlinePresetsManager
y -= 0.8f;
}
if (!PresetsLoaded) yield break;
foreach (PresetMeta preset in CachedPresets)
for (var index = 0; index < CachedPresets.Count; index++)
{
StringOption row = ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer));
PresetMeta preset = CachedPresets[index];
StringOption row = OptionBehaviourCache.TryGetValue(index, out StringOption cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate(menu.stringOptionOrigin, Vector3.zero, Quaternion.identity, menu.settingsContainer));
row.name = $"{nameof(OnlinePresetsManager)};{string.Format(Translator.GetString("OnlinePresetInfo"), preset.name, preset.author, (Utils.TimeStamp - (long)preset.created_at) / 86400, preset.downloads)}";
row.transform.localPosition = new Vector3(0.952f, y, -2f);
row.SetClickMask(menu.ButtonClickMask);
row.SetUpFromData(ScriptableObject.CreateInstance<StringGameSetting>(), 20);
row.SetUpFromData(null, 20);
Object.Destroy(row.transform.FindChild("Value_TMP (1)").gameObject);
Object.Destroy(row.transform.FindChild("ValueBox").gameObject);
row.OnValueChanged = new Action<OptionBehaviour>(menu.ValueChanged);
row.LabelBackground.transform.localScale += new Vector3(1f, 0f, 0f);
row.TitleText.GetComponent<RectTransform>().sizeDelta = new(5.7f, 0.37f);
TextMeshPro plusText = row.PlusBtn.GetComponentInChildren<TextMeshPro>();
plusText.DestroyTranslator();
plusText.text = "ⓘ";
@@ -103,7 +109,7 @@ public static class OnlinePresetsManager
{
bool b = plusText.text == "ⓘ";
GameObject.Find("PlayerOptionsMenu(Clone)").transform.FindChild("What Is This?").gameObject.SetActive(b);
GameSettingMenuPatch.GMButtons.ForEach(x => x.gameObject.SetActive(!b));
GameSettingMenuPatch.GMButtons.Values.Do(x => x.gameObject.SetActive(!b));
if (b) GameSettingMenu.Instance.MenuDescriptionText.text = preset.description;
plusText.text = b ? "∅" : "ⓘ";
}));
@@ -112,14 +118,13 @@ public static class OnlinePresetsManager
row.MinusBtn.OnClick = new();
row.MinusBtn.OnClick.AddListener((UnityAction)(() =>
{
ModGameOptionsMenu.Reloading = true;
LateTask.New(() => ModGameOptionsMenu.Reloading = false, 0.01f);
LateTask.New(() => { }, 0.01f);
GameSettingMenu.Instance.Close();
Prompt.Show(Translator.GetString("Promt.ApplyPreset"), () =>
{
Logger.SendInGame(Translator.GetString("DownloadingPreset"));
Main.Instance.StartCoroutine(
DownloadPreset(preset.id, downloadedPreset =>
{
@@ -129,10 +134,10 @@ public static class OnlinePresetsManager
if (!downloadedPreset.TryGetValue(id, out int newValue)) continue;
optionItem.SetValue(newValue, doSave: false, doSync: false);
}
OptionItem.SyncAllOptions();
OptionSaver.Save();
Logger.SendInGame(Translator.GetString("PresetApplied"), Color.green);
})
);
@@ -143,13 +148,13 @@ public static class OnlinePresetsManager
if (!GameStates.IsLobby) return;
GameObject.Find("Host Buttons").transform.FindChild("Edit").GetComponent<PassiveButton>().ReceiveClickDown();
}, 0.1f);
LateTask.New(() =>
{
if (!GameStates.IsLobby || !GameSettingMenu.Instance) return;
const int index = (int)TabGroup.PresetExplorer + 3;
GameSettingMenu.Instance.ChangeTab(index, Controller.currentTouchType == Controller.TouchType.Joystick);
ModGameOptionsMenu.TabIndex = index;
const int tabIndex = (int)TabGroup.PresetExplorer + 3;
GameSettingMenu.Instance.ChangeTab(tabIndex, Controller.currentTouchType == Controller.TouchType.Joystick);
ModGameOptionsMenu.TabIndex = tabIndex;
}, 0.4f);
});
}));
@@ -160,13 +165,11 @@ public static class OnlinePresetsManager
row.gameObject.SetActive(true);
menu.Children.Add(row);
OptionBehaviourCache[index] = row;
y -= 0.6f;
if (y < -10)
yield return null;
}
menu.scrollBar.SetYBoundsMax(-y - 1.65f);
menu.ControllerSelectable.Clear();
+1 -1
View File
@@ -3093,7 +3093,7 @@ public static class Options
IntegrateNaturalDisasters = new BooleanOptionItem(24454, "IntegrateNaturalDisasters", false, TabGroup.GameSettings)
.SetColor(new Color32(193, 255, 209, byte.MaxValue))
.RegisterUpdateValueEvent((_, _, _) => GameOptionsMenuPatch.ReloadUI());
.RegisterUpdateValueEvent((_, _, _) => GameOptionsMenuPatch.ReCreateSettings(GameSettingMenuPatch.ModSettingsTabs[TabGroup.GameSettings]));
EnableGameTimeLimit = new BooleanOptionItem(24455, "EnableGameTimeLimit", false, TabGroup.GameSettings)
.SetColor(new Color32(193, 255, 209, byte.MaxValue))
-1
View File
@@ -64,7 +64,6 @@ public abstract class OptionItem
public bool IsText { get; protected set; }
public TextOptionItem Header { get; set; }
public BaseGameSetting CachedSetting { get; set; }
public Dictionary<string, string> ReplacementDictionary
{
+7
View File
@@ -105,4 +105,11 @@ public static class Prompt
return true;
}
}
public static void Reset()
{
CurrentQuestion = string.Empty;
ClearQueue();
HidePromt();
}
}
+1 -16
View File
@@ -619,22 +619,7 @@ internal static class RPCHandlerPatch
}
case CustomRPC.NotificationPopper:
{
byte typeId = reader.ReadByte();
int optionId = reader.ReadPackedInt32();
int customRole = reader.ReadPackedInt32();
bool playSound = reader.ReadBoolean();
OptionItem key = OptionItem.FastOptions[optionId];
switch (typeId)
{
case 0:
NotificationPopperPatch.AddSettingsChangeMessage(key, playSound);
break;
case 1:
NotificationPopperPatch.AddRoleSettingsChangeMessage(key, (CustomRoles)customRole, playSound);
break;
}
NotificationPopperPatch.AddSettingsChangeMessage(OptionItem.FastOptions[reader.ReadPackedInt32()], reader.ReadBoolean());
break;
}
case CustomRPC.RequestCommandProcessing:
+32 -15
View File
@@ -90,7 +90,7 @@ public static class Utils
private static readonly StringBuilder ContAliveLog = new(100);
private static readonly Dictionary<string, Sprite> CachedSprites = [];
public static readonly Dictionary<string, Sprite> CachedSprites = [];
private static long LastNotifyRolesErrorTS = TimeStamp;
@@ -468,22 +468,38 @@ public static class Utils
mode = mode.Replace("color=", string.Empty);
return parentheses ? $"({mode})" : mode;
}
public static Color GetTabColor(this TabGroup tab)
extension(TabGroup tab)
{
return tab switch
public Color GetTabColor()
{
TabGroup.SystemSettings => new(0.2f, 0.2f, 0.2f),
TabGroup.GameSettings => new(0.2f, 0.4f, 0.3f),
TabGroup.TaskSettings => new(0.4f, 0.2f, 0.5f),
TabGroup.ImpostorRoles => new(0.5f, 0.2f, 0.2f),
TabGroup.CrewmateRoles => new(0.2f, 0.4f, 0.5f),
TabGroup.NeutralRoles => new(0.5f, 0.4f, 0.2f),
TabGroup.CovenRoles => new(0.5f, 0.2f, 0.4f),
TabGroup.Addons => new(0.4f, 0.2f, 0.3f),
TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f),
TabGroup.PresetExplorer => new(0.5f, 0.5f, 0.5f),
_ => new(0.3f, 0.3f, 0.3f)
};
return tab switch
{
TabGroup.SystemSettings => new(0.2f, 0.2f, 0.2f),
TabGroup.GameSettings => new(0.2f, 0.4f, 0.3f),
TabGroup.TaskSettings => new(0.4f, 0.2f, 0.5f),
TabGroup.ImpostorRoles => new(0.5f, 0.2f, 0.2f),
TabGroup.CrewmateRoles => new(0.2f, 0.4f, 0.5f),
TabGroup.NeutralRoles => new(0.5f, 0.4f, 0.2f),
TabGroup.CovenRoles => new(0.5f, 0.2f, 0.4f),
TabGroup.Addons => new(0.4f, 0.2f, 0.3f),
TabGroup.OtherRoles => new(0.4f, 0.4f, 0.4f),
TabGroup.PresetExplorer => new(0.5f, 0.5f, 0.5f),
_ => new(0.3f, 0.3f, 0.3f)
};
}
public bool IsRelevant(CustomGameMode? gm = null)
{
if (tab == TabGroup.PresetExplorer) return true;
return (gm ?? Options.CurrentGameMode) switch
{
CustomGameMode.Standard => true,
CustomGameMode.HideAndSeek => tab <= TabGroup.NeutralRoles,
_ => tab <= TabGroup.TaskSettings
};
}
}
public static string GetRoleColorCode(CustomRoles role, string defaultHtml = "#ffffff")
@@ -4908,6 +4924,7 @@ public static class Utils
{
foreach (var pc in players)
{
if (pc.IsModdedClient()) continue;
var dummyImp = players.FirstOrDefault(x => x != pc);
if (dummyImp) dummyImp.RpcSetRoleDesync(RoleTypes.Impostor, pc.OwnerId);
}
+1 -2
View File
@@ -16,12 +16,11 @@ internal static class PingTrackerUpdatePatch
{
public static PingTracker Instance;
private static readonly StringBuilder Sb = new();
private static long LastUpdate;
private static readonly float[] FpsBuffer = new float[10];
private static int FpsIndex;
private static int FpsCount;
private static Color32 FpsColor = new(0, 165, 255, 255);
private static readonly Color32 FpsColor = new(0, 165, 255, 255);
public static bool Prefix(PingTracker __instance)
{
+3
View File
@@ -19,7 +19,10 @@ static class ExceptionSwallowers
yield return AccessTools.Method(typeof(PlayerControl), nameof(PlayerControl.RawSetName));
yield return AccessTools.Method(typeof(PlayerControl), nameof(PlayerControl.SetName));
yield return AccessTools.Method(typeof(CosmeticsLayer), nameof(CosmeticsLayer.UpdateBodyMaterial));
yield return AccessTools.Method(typeof(CosmeticsCache), nameof(CosmeticsCache.ClearUnusedCosmetics));
yield return AccessTools.Method(typeof(InnerNetClient), nameof(InnerNetClient.SendOrDisconnect));
yield return AccessTools.Method(typeof(DisconnectPopup), nameof(DisconnectPopup.DoShow));
yield return AccessTools.Method(typeof(IGameOptionsExtensions), nameof(IGameOptionsExtensions.GetValue));
}
public static Exception Finalizer()
+236 -337
View File
@@ -20,103 +20,54 @@ namespace EHR;
public static class ModGameOptionsMenu
{
public static int TabIndex;
public static bool Reloading;
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();
private static readonly List<GameObject> SpawnedUI = new();
public static readonly System.Collections.Generic.Dictionary<CustomRoles, Transform> HelpIconList = [];
public static readonly System.Collections.Generic.Dictionary<OptionItem, BaseGameSetting> BaseGameSettingCache = [];
public static readonly HashSet<GameObject> SpawnedUI = new();
public static T Track<T>(T obj) where T : Object
{
if (obj is GameObject go)
SpawnedUI.Add(go);
else if (obj is Component c)
SpawnedUI.Add(c.gameObject);
switch (obj)
{
case GameObject go:
SpawnedUI.Add(go);
break;
case Component c:
SpawnedUI.Add(c.gameObject);
break;
}
return obj;
}
public static void DestroyOption()
public static Color32 GetCurrentThemeColor(TabGroup? tab = null)
{
foreach (var ui in SpawnedUI)
CustomGameMode gm = Options.CurrentGameMode;
Color32 color = gm == CustomGameMode.Standard ? (tab ?? (TabGroup)(TabIndex - 3)) switch
{
if (!ui) continue;
foreach (var btn in ui.GetComponentsInChildren<PassiveButton>(true))
btn.OnClick.RemoveAllListeners();
Destroy(ui);
}
SpawnedUI.Clear();
foreach (var kv in OptionItem.AllOptions)
{
kv.OptionBehaviour = null;
kv.Header = null;
}
foreach (var kv in OptionList)
{
if (kv.Key)
{
kv.Key.OnValueChanged = null;
kv.Key.SetClickMask(null);
if (kv.Key.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Destroy(kv.Key.gameObject);
}
}
foreach (var kv in BehaviourList)
{
if (kv.Value)
{
kv.Value.OnValueChanged = null;
kv.Value.SetClickMask(null);
if (kv.Value.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Destroy(kv.Value.gameObject);
}
}
foreach (var kv in CategoryHeaderList)
{
if (kv.Value)
{
if (kv.Value.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
Destroy(kv.Value.gameObject);
}
}
foreach (var co in RunningMainCoroutines)
{
if (co != null)
Main.Instance.StopCoroutine(co);
}
OptionList.Clear();
BehaviourList.Clear();
CategoryHeaderList.Clear();
RunningMainCoroutines.Clear();
}
public static void Destroy(GameObject gameObject)
{
if (Reloading) Object.DestroyImmediate(gameObject);
else Object.Destroy(gameObject);
TabGroup.ImpostorRoles => new Color32(255, 25, 25, 255),
TabGroup.CrewmateRoles => new Color32(140, 255, 255, 255),
TabGroup.NeutralRoles => new Color32(255, 171, 27, 255),
TabGroup.CovenRoles => new Color32(123, 63, 187, 255),
_ => new Color32(0, 165, 255, 255)
} : Main.GameModeColors.TryGetValue(gm, out var c) ? c : new Color32(0, 165, 255, 255);
return color;
}
}
[HarmonyPatch(typeof(GameOptionsMenu))]
public static class GameOptionsMenuPatch
{
public static GameOptionsMenu Instance;
[HarmonyPatch(nameof(GameOptionsMenu.Initialize))]
[HarmonyPrefix]
private static bool InitializePrefix(GameOptionsMenu __instance)
{
Instance = __instance;
if (ModGameOptionsMenu.TabIndex < 3) return true;
if (__instance.Children == null || __instance.Children.Count == 0)
@@ -187,7 +138,7 @@ public static class GameOptionsMenuPatch
if (modTab == TabGroup.PresetExplorer)
{
__instance.StartCoroutine(OnlinePresetsManager.CreatePresetExplorerUI(__instance).WrapToIl2Cpp());
OnlinePresetsManager.CreatePresetExplorerUI(__instance);
return false;
}
@@ -216,7 +167,7 @@ public static class GameOptionsMenuPatch
if (option is TextOptionItem toi)
{
CategoryHeaderMasked categoryHeaderMasked = ModGameOptionsMenu.Track(Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer));
CategoryHeaderMasked categoryHeaderMasked = ModGameOptionsMenu.CategoryHeaderList.TryGetValue(index, out CategoryHeaderMasked cache) ? cache : ModGameOptionsMenu.Track(Object.Instantiate(__instance.categoryHeaderOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer));
categoryHeaderMasked.SetHeader(StringNames.RolesCategory, 20);
categoryHeaderMasked.Title.SetText(option.GetName(disableColor: true).Trim('★', ' '));
categoryHeaderMasked.Background.color = categoryHeaderMasked.Divider.color = option.NameColor;
@@ -255,25 +206,27 @@ public static class GameOptionsMenuPatch
BaseGameSetting baseGameSetting = GetSetting(option);
if (!baseGameSetting) continue;
OptionBehaviour optionBehaviour;
try
if (!ModGameOptionsMenu.BehaviourList.TryGetValue(index, out OptionBehaviour optionBehaviour))
{
optionBehaviour = baseGameSetting.Type switch
try
{
OptionTypes.Checkbox => ModGameOptionsMenu.Track(Object.Instantiate(__instance.checkboxOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)),
OptionTypes.String => ModGameOptionsMenu.Track(Object.Instantiate(__instance.stringOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)),
OptionTypes.Float or OptionTypes.Int => ModGameOptionsMenu.Track(Object.Instantiate(__instance.numberOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)),
_ => throw new Exception()
};
optionBehaviour = baseGameSetting.Type switch
{
OptionTypes.Checkbox => ModGameOptionsMenu.Track(Object.Instantiate(__instance.checkboxOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)),
OptionTypes.String => ModGameOptionsMenu.Track(Object.Instantiate(__instance.stringOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)),
OptionTypes.Float or OptionTypes.Int => ModGameOptionsMenu.Track(Object.Instantiate(__instance.numberOptionOrigin, Vector3.zero, Quaternion.identity, __instance.settingsContainer)),
_ => throw new Exception()
};
}
catch { continue; }
optionBehaviour.transform.localPosition = new(posX, num, posZ);
OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type);
}
else
{
optionBehaviour.transform.localPosition = new(posX, num, posZ);
}
catch { continue; }
optionBehaviour.transform.localPosition = new(posX, num, posZ);
OptionBehaviourSetSizeAndPosition(optionBehaviour, option, baseGameSetting.Type);
if (!ModGameOptionsMenu.OptionList.ContainsValue(index) && option.Name == "Preset")
GameSettingMenuPatch.PresetBehaviour = (NumberOption)optionBehaviour;
optionBehaviour.transform.localPosition = new(0.952f, num, -2f);
optionBehaviour.SetClickMask(__instance.ButtonClickMask);
@@ -298,6 +251,8 @@ public static class GameOptionsMenuPatch
foreach (UiElement x in __instance.scrollBar.GetComponentsInChildren<UiElement>())
__instance.ControllerSelectable.Add(x);
Canvas.ForceUpdateCanvases();
}
float CalculateScrollBarYBoundsMax()
@@ -323,7 +278,7 @@ public static class GameOptionsMenuPatch
}
}
public static bool AllParentsEnabledAndVisible(OptionItem o, bool checkCollapsedSection = true)
private static bool AllParentsEnabledAndVisible(OptionItem o, bool checkCollapsedSection = true)
{
while (true)
{
@@ -415,7 +370,7 @@ public static class GameOptionsMenuPatch
public static void UpdatePostfix(GameOptionsMenu __instance)
{
// Disable scroll options when chat open
if (!HudManager.InstanceExists || !__instance.gameObject.activeSelf) return;
if (!HudManager.InstanceExists || !__instance.gameObject.activeSelf || !GameSettingMenu.Instance) return;
__instance.scrollBar.enabled = !HudManager.Instance.Chat.IsOpenOrOpening;
}
@@ -473,9 +428,60 @@ public static class GameOptionsMenuPatch
__instance.scrollBar.SetYBoundsMax(-num - 1.65f);
}
public static void RefreshSettingValues()
{
// ReSharper disable once UseDeconstruction - unsupported here by Il2Cpp
foreach (KeyValuePair<OptionBehaviour, int> kvp in ModGameOptionsMenu.OptionList)
{
OptionBehaviour optionBehaviour = kvp.Key;
OptionItem optionItem = OptionItem.AllOptions[kvp.Value];
switch (optionItem)
{
case BooleanOptionItem when optionBehaviour is ToggleOption toggleOption:
var color = ModGameOptionsMenu.GetCurrentThemeColor(optionItem.Tab);
toggleOption.CheckMark.color = color;
toggleOption.CheckMark.enabled = optionItem.GetBool();
toggleOption.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent<SpriteRenderer>().color = color;
break;
case StringOptionItem when optionBehaviour is StringOption stringOption:
stringOption.Value = optionItem.GetInt();
stringOption.UpdateValue();
break;
case FloatOptionItem or IntegerOptionItem when optionBehaviour is NumberOption numberOption:
numberOption.Value = optionItem.GetFloat();
break;
}
}
GameOptionsManager.Instance.GameHostOptions = GameOptionsManager.Instance.CurrentGameOptions;
GameManager.Instance.LogicOptions.SyncOptions();
}
public static void RefreshTabButtons()
{
foreach ((TabGroup tab, PassiveButton button) in GameSettingMenuPatch.ModSettingsButtons)
button.gameObject.SetActive(tab.IsRelevant());
}
public static void RefreshCheckMarkColors()
{
// ReSharper disable once UseDeconstruction - unsupported here by Il2Cpp
foreach (KeyValuePair<OptionBehaviour, int> kvp in ModGameOptionsMenu.OptionList)
{
if (kvp.Key is ToggleOption toggleOption)
{
var color = ModGameOptionsMenu.GetCurrentThemeColor(OptionItem.AllOptions[kvp.Value].Tab);
toggleOption.CheckMark.color = color;
toggleOption.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent<SpriteRenderer>().color = color;
}
}
}
public static BaseGameSetting GetSetting(OptionItem item)
{
if (item.CachedSetting) return item.CachedSetting;
if (ModGameOptionsMenu.BaseGameSettingCache.TryGetValue(item, out BaseGameSetting cache)) return cache;
BaseGameSetting baseGameSetting;
@@ -515,67 +521,14 @@ public static class GameOptionsMenuPatch
stringGameSetting.Index = stringOptionItem.GetInt();
baseGameSetting = stringGameSetting;
break;
case PresetOptionItem presetOptionItem:
var presetIntGameSetting = ScriptableObject.CreateInstance<IntGameSetting>();
presetIntGameSetting.Type = OptionTypes.Int;
presetIntGameSetting.Value = presetOptionItem.GetInt();
presetIntGameSetting.Increment = presetOptionItem.Rule.Step;
presetIntGameSetting.ValidRange = new(presetOptionItem.Rule.MinValue, presetOptionItem.Rule.MaxValue);
presetIntGameSetting.ZeroIsInfinity = false;
presetIntGameSetting.SuffixType = NumberSuffixes.Multiplier;
presetIntGameSetting.FormatString = string.Empty;
baseGameSetting = presetIntGameSetting;
break;
default:
baseGameSetting = null;
break;
return null;
}
if (baseGameSetting)
{
baseGameSetting.Title = StringNames.Accept;
item.CachedSetting = baseGameSetting;
}
baseGameSetting.Title = StringNames.Accept;
ModGameOptionsMenu.BaseGameSettingCache[item] = baseGameSetting;
return baseGameSetting;
}
// From MoreGamemodes, by Rabek009
public static void ReloadUI()
{
int tab = ModGameOptionsMenu.TabIndex;
if (!GameSettingMenu.Instance) return;
ModGameOptionsMenu.Reloading = true;
LateTask.New(() => ModGameOptionsMenu.Reloading = false, 0.01f);
GameSettingMenu.Instance.Close();
OptionsConsole optionsConsole = null;
foreach (OptionsConsole console in Object.FindObjectsOfType<OptionsConsole>())
{
if (console.HostOnly)
optionsConsole = console;
}
if (!optionsConsole) return;
Camera main = Camera.main;
if (main)
{
GameObject gameObject = ModGameOptionsMenu.Track(Object.Instantiate(optionsConsole.MenuPrefab, main.transform, false));
gameObject.transform.localPosition = optionsConsole.CustomPosition;
}
LateTask.New(() =>
{
if (!GameSettingMenu.Instance) return;
GameSettingMenu.Instance.ChangeTab(tab, false);
}, 0.01f);
LateTask.New(() => GameObject.Find("PlayerOptionsMenu(Clone)")?.transform.FindChild("What Is This?")?.gameObject.SetActive(false), 0.02f);
}
}
[HarmonyPatch(typeof(ToggleOption))]
@@ -589,15 +542,7 @@ public static class ToggleOptionPatch
{
OptionItem item = OptionItem.AllOptions[index];
CustomGameMode gm = Options.CurrentGameMode;
Color32 color = gm == CustomGameMode.Standard ? (TabGroup)(ModGameOptionsMenu.TabIndex - 3) switch
{
TabGroup.ImpostorRoles => new Color32(255, 25, 25, 255),
TabGroup.CrewmateRoles => new Color32(140, 255, 255, 255),
TabGroup.NeutralRoles => new Color32(255, 171, 27, 255),
TabGroup.CovenRoles => new Color32(123, 63, 187, 255),
_ => new Color32(0, 165, 255, 255)
} : Main.GameModeColors.TryGetValue(gm, out var c) ? c : new Color32(0, 165, 255, 255);
var color = ModGameOptionsMenu.GetCurrentThemeColor();
__instance.CheckMark.sprite = Utils.LoadSprite("EHR.Resources.Images.Checkmark.png", 100f);
__instance.CheckMark.color = color;
var renderer = __instance.CheckMark.transform.parent.FindChild("ActiveSprite").GetComponent<SpriteRenderer>();
@@ -715,10 +660,6 @@ public static class NumberOptionPatch
case FloatOptionItem floatOptionItem:
floatOptionItem.SetValue(floatOptionItem.Rule.GetNearestIndex(__instance.GetFloat()));
break;
case PresetOptionItem presetOptionItem:
presetOptionItem.SetValue(presetOptionItem.Rule.GetNearestIndex(__instance.GetInt()));
GameOptionsMenuPatch.ReloadUI();
break;
}
NotificationPopperPatch.AddSettingsChangeMessage(item, true);
@@ -811,12 +752,13 @@ public static class NumberOptionPatch
public static class StringOptionPatch
{
private static long HelpShowEndTS;
private static readonly Dictionary<StringOption, string> NameCache = new();
[HarmonyPatch(nameof(StringOption.Initialize))]
[HarmonyPrefix]
private static bool InitializePrefix(StringOption __instance)
{
if (__instance.name.StartsWith(nameof(OnlinePresetsManager))) return true;
if (__instance.name.StartsWith(nameof(OnlinePresetsManager))) return false;
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index))
{
@@ -855,6 +797,7 @@ public static class StringOptionPatch
}
__instance.TitleText.SetText(name);
NameCache[__instance] = name;
return false;
}
@@ -864,7 +807,8 @@ public static class StringOptionPatch
private static void SetupHelpIcon(CustomRoles role, StringOption option)
{
Transform template = option.MinusBtn.transform;
Transform icon = ModGameOptionsMenu.Track(Object.Instantiate(template, template.parent, true));
bool cached = ModGameOptionsMenu.HelpIconList.TryGetValue(role, out Transform cache);
Transform icon = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(template, template.parent, true));
icon.name = $"{role}HelpIcon";
var text = icon.GetComponentInChildren<TextMeshPro>();
text.SetText("?");
@@ -890,7 +834,7 @@ public static class StringOptionPatch
catch { infoLong = str; }
GameObject.Find("PlayerOptionsMenu(Clone)").transform.FindChild("What Is This?").gameObject.SetActive(true);
GameSettingMenuPatch.GMButtons.ForEach(x => x.gameObject.SetActive(false));
GameSettingMenuPatch.GMButtons.Values.Do(x => x.gameObject.SetActive(false));
var info = $"{value.ToColoredString()}: {infoLong}";
GameSettingMenu.Instance.MenuDescriptionText.SetText(info);
@@ -898,11 +842,7 @@ public static class StringOptionPatch
long now = Utils.TimeStamp;
bool startCoRoutine = now > HelpShowEndTS;
HelpShowEndTS = now + 15;
if (startCoRoutine)
{
var co = Main.Instance.StartCoroutine(CoRoutine());
ModGameOptionsMenu.RunningMainCoroutines.Add(co);
}
if (startCoRoutine) GameSettingMenu.Instance.StartCoroutine(CoRoutine().WrapToIl2Cpp());
IEnumerator CoRoutine()
{
@@ -917,16 +857,17 @@ public static class StringOptionPatch
if (findChild) findChild.gameObject.SetActive(false);
}
GameSettingMenuPatch.GMButtons.ForEach(x => x.gameObject.SetActive(true));
GameSettingMenuPatch.GMButtons.Values.Do(x => x.gameObject.SetActive(true));
}
}
}
}));
gameOptionButton.interactableColor = Color.black;
gameOptionButton.interactableHoveredColor = new Color32(0, 165, 255, 255);
gameOptionButton.interactableHoveredColor = ModGameOptionsMenu.GetCurrentThemeColor();
icon.localPosition += new Vector3(-0.8f, 0f, 0f);
icon.SetAsLastSibling();
ModGameOptionsMenu.HelpIconList[role] = icon;
}
public static string GetGhostRoleTeam(CustomRoles role)
@@ -968,43 +909,8 @@ public static class StringOptionPatch
{
OptionItem item = OptionItem.AllOptions[index];
item.SetValue(__instance.GetInt());
string name = item.GetName();
string name1 = name;
if (Main.CustomRoleValues.FindFirst(x => Translator.GetString($"{x}") == name1.RemoveHtmlTags(), out CustomRoles role))
{
if (role.ToString().Contains("GuardianAngel")) role = CustomRoles.GA;
name = name.RemoveHtmlTags();
switch (Options.UsePets.GetBool())
{
case true when role.PetActivatedAbility():
name += Translator.GetString("SupportsPetIndicator");
break;
case false when role.OnlySpawnsWithPets():
name += Translator.GetString("RequiresPetIndicator");
Prompt.Show(Translator.GetString("Promt.RequiresPets"), () => Options.UsePets.SetValue(1), () => { });
break;
}
if (role.IsExperimental()) name += $"<size=2>{Translator.GetString("ExperimentalRoleIndicator")}</size>";
if (role.IsGhostRole()) name += GetGhostRoleTeam(role);
if (role.IsDevFavoriteRole()) name += " <size=2><#00ffff>★</color></size>";
__instance.TitleText.fontWeight = FontWeight.Black;
__instance.TitleText.outlineColor = new(255, 255, 255, 255);
__instance.TitleText.outlineWidth = 0.04f;
__instance.LabelBackground.color = Utils.GetRoleColor(role);
__instance.TitleText.color = Color.white;
name = $"<size=3.5>{name}</size>";
NotificationPopperPatch.AddRoleSettingsChangeMessage(item, role, true);
}
else
NotificationPopperPatch.AddSettingsChangeMessage(item, true);
__instance.TitleText.SetText(name);
NotificationPopperPatch.AddSettingsChangeMessage(item, true);
__instance.TitleText.SetText(NameCache[__instance]);
return false;
}
@@ -1074,7 +980,7 @@ public static class StringOptionPatch
[HarmonyPatch(typeof(GameSettingMenu))]
public static class GameSettingMenuPatch
{
public static readonly System.Collections.Generic.List<GameObject> GMButtons = [];
public static readonly System.Collections.Generic.Dictionary<CustomGameMode, GameObject> GMButtons = [];
private static readonly Vector3 ButtonPositionLeft = new(-3.9f, -0.55f, 0f);
private static readonly Vector3 ButtonPositionRight = new(-2.4f, -0.55f, 0f);
@@ -1084,10 +990,9 @@ public static class GameSettingMenuPatch
private static GameOptionsMenu TemplateGameOptionsMenu;
private static PassiveButton TemplateGameSettingsButton;
private static readonly System.Collections.Generic.Dictionary<TabGroup, PassiveButton> ModSettingsButtons = [];
private static readonly System.Collections.Generic.Dictionary<TabGroup, GameOptionsMenu> ModSettingsTabs = [];
public static readonly System.Collections.Generic.Dictionary<TabGroup, PassiveButton> ModSettingsButtons = [];
public static readonly System.Collections.Generic.Dictionary<TabGroup, GameOptionsMenu> ModSettingsTabs = [];
public static NumberOption PresetBehaviour;
public static long LastPresetChange;
public static FreeChatInputField InputField;
@@ -1101,58 +1006,16 @@ public static class GameSettingMenuPatch
private static float VanillaKillCooldownOnOpen = 1;
private static float ModdedKillCooldownOnOpen = 1;
private static void DestroySetting()
{
foreach (var button in ModSettingsButtons.Values)
{
if (button)
{
button.OnClick.RemoveAllListeners();
ModGameOptionsMenu.Destroy(button.gameObject);
}
}
foreach (var tab in ModSettingsTabs.Values)
{
if (!tab) continue;
if (tab.Children != null)
{
foreach (var child in tab.Children)
{
if (!child) continue;
if (child.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
ModGameOptionsMenu.Destroy(child.gameObject);
}
tab.Children.Clear();
}
ModGameOptionsMenu.Destroy(tab.gameObject);
}
foreach (var gmButton in GMButtons)
if (gmButton) ModGameOptionsMenu.Destroy(gmButton);
ModSettingsButtons.Clear();
ModSettingsTabs.Clear();
GMButtons.Clear();
InputField = null;
SearchForOptionsAction = null;
}
[HarmonyPatch(nameof(GameSettingMenu.Start))]
[HarmonyPrefix]
[HarmonyPriority(Priority.First)]
public static void StartPostfix(GameSettingMenu __instance)
public static void StartPrefix(ref GameSettingMenu __instance)
{
try
{
(OptionItem MinSetting, OptionItem MaxSetting) = Options.FactionMinMaxSettings[Team.Impostor];
MinImpsOnOpen = MinSetting.GetInt();
MaxImpsOnOpen = MaxSetting.GetInt();
(OptionItem minSetting, OptionItem maxSetting) = Options.FactionMinMaxSettings[Team.Impostor];
MinImpsOnOpen = minSetting.GetInt();
MaxImpsOnOpen = maxSetting.GetInt();
NumImpsOnOpen = Main.NormalOptions.NumImpostors;
VanillaKillCooldownOnOpen = Main.NormalOptions.KillCooldown;
@@ -1160,20 +1023,12 @@ public static class GameSettingMenuPatch
}
catch (Exception e) { Utils.ThrowException(e); }
ModSettingsButtons.Clear();
TabGroup[] tabGroups = Main.TabGroupValues;
tabGroups = Options.CurrentGameMode switch
foreach (TabGroup tab in Main.TabGroupValues)
{
CustomGameMode.Standard => tabGroups,
CustomGameMode.HideAndSeek => tabGroups[..6],
_ => tabGroups[..3]
};
foreach (TabGroup tab in tabGroups)
{
PassiveButton button = ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameSettingsButton, __instance.GameSettingsButton.transform.parent));
button.gameObject.SetActive(true);
bool cached = ModSettingsButtons.TryGetValue(tab, out PassiveButton cache);
PassiveButton button = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameSettingsButton, __instance.GameSettingsButton.transform.parent));
if (cached) button.transform.SetParent(__instance.GameSettingsButton.transform.parent, false);
button.gameObject.SetActive(tab.IsRelevant());
button.name = "Button_" + tab;
var label = button.GetComponentInChildren<TextMeshPro>();
label.DestroyTranslator();
@@ -1194,23 +1049,23 @@ public static class GameSettingMenuPatch
var buttonComponent = button.GetComponent<PassiveButton>();
buttonComponent.OnClick = new();
buttonComponent.OnClick.AddListener((Action)(() => __instance.ChangeTab((int)tab + 3, false)));
buttonComponent.OnClick.AddListener((Action)(() => GameSettingMenu.Instance.ChangeTab((int)tab + 3, false)));
ModSettingsButtons.Add(tab, button);
ModSettingsButtons[tab] = button;
}
ModSettingsTabs.Clear();
foreach (TabGroup tab in tabGroups)
foreach (TabGroup tab in Main.TabGroupValues)
{
GameOptionsMenu setTab = ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameOptionsMenu, __instance.GameSettingsTab.transform.parent));
bool cached = ModSettingsTabs.TryGetValue(tab, out GameOptionsMenu cache);
GameOptionsMenu setTab = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(TemplateGameOptionsMenu, __instance.GameSettingsTab.transform.parent));
if (cached) setTab.transform.SetParent(__instance.GameSettingsTab.transform.parent, false);
setTab.name = "tab_" + tab;
setTab.gameObject.SetActive(false);
ModSettingsTabs.Add(tab, setTab);
ModSettingsTabs[tab] = setTab;
}
foreach (TabGroup tab in tabGroups)
foreach (TabGroup tab in Main.TabGroupValues)
{
if (ModSettingsButtons.TryGetValue(tab, out PassiveButton button))
__instance.ControllerSelectable.Add(button);
@@ -1222,11 +1077,20 @@ public static class GameSettingMenuPatch
SetupExtendedUI(__instance);
}
private static readonly System.Collections.Generic.Dictionary<int, GameObject> ExtraObjectsCache = [];
// Thanks: Drakos for the preset button and search bar code (https://github.com/0xDrMoe/TownofHost-Enhanced/pull/1115)
private static void SetupExtendedUI(GameSettingMenu __instance)
{
Transform parentLeftPanel = __instance.GamePresetsButton.transform.parent;
GameObject preset = ModGameOptionsMenu.Track(Object.Instantiate(GameObject.Find("ModeValue"), parentLeftPanel));
bool cached = ExtraObjectsCache.TryGetValue(0, out GameObject cache);
GameObject preset = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(GameObject.Find("ModeValue"), parentLeftPanel));
if (cached)
{
preset.transform.SetParent(parentLeftPanel, false);
preset.SetActive(true);
}
ExtraObjectsCache[0] = preset;
preset.transform.localPosition = new(-1.8f, 0f, -2f);
preset.transform.localScale = new(0.65f, 0.63f, 1f);
@@ -1244,7 +1108,10 @@ public static class GameSettingMenuPatch
GameObject tempMinus = GameObject.Find("MinusButton").gameObject;
GameObject gMinus = ModGameOptionsMenu.Track(Object.Instantiate(__instance.GamePresetsButton.gameObject, preset.transform));
cached = ExtraObjectsCache.TryGetValue(1, out cache);
GameObject gMinus = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(__instance.GamePresetsButton.gameObject, preset.transform));
if (cached) gMinus.transform.SetParent(preset.transform, false);
ExtraObjectsCache[1] = gMinus;
gMinus.gameObject.SetActive(true);
gMinus.transform.localScale = new(0.08f, 0.4f, 1f);
@@ -1252,7 +1119,7 @@ public static class GameSettingMenuPatch
mLabel.alignment = TextAlignmentOptions.Center;
mLabel.DestroyTranslator();
mLabel.SetText("-");
mLabel.transform.localPosition = new(mLabel.transform.localPosition.x, mLabel.transform.localPosition.y + 0.26f, mLabel.transform.localPosition.z);
if (!cached) mLabel.transform.localPosition = new(mLabel.transform.localPosition.x, mLabel.transform.localPosition.y + 0.26f, mLabel.transform.localPosition.z);
mLabel.color = Color.white;
mLabel.SetFaceColor(new Color(255f, 255f, 255f));
mLabel.transform.localScale = new(12f, 4f, 1f);
@@ -1262,11 +1129,12 @@ public static class GameSettingMenuPatch
minus.OnClick.AddListener((Action)(() =>
{
if (!PresetBehaviour)
__instance.ChangeTab(3, false);
LastPresetChange = Utils.TimeStamp;
PresetBehaviour.Decrease();
Options.Preset--;
ModSettingsTabs.Values.Do(GameOptionsMenuPatch.ReCreateSettings);
GameOptionsMenuPatch.RefreshSettingValues();
GameOptionsMenuPatch.RefreshTabButtons();
presetTmp.SetText(Translator.GetString($"Preset_{OptionItem.CurrentPreset + 1}"));
Logger.Info($"Current preset: {OptionItem.CurrentPreset + 1}", "GameOptionsMenuPatch");
}));
@@ -1286,13 +1154,20 @@ public static class GameSettingMenuPatch
selectedSprites.color = new Color32(0, 165, 255, 255);
GameObject plusFab = ModGameOptionsMenu.Track(Object.Instantiate(gMinus, preset.transform));
cached = ExtraObjectsCache.TryGetValue(2, out cache);
GameObject plusFab = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(gMinus, preset.transform));
if (cached)
{
plusFab.transform.SetParent(preset.transform, false);
plusFab.SetActive(true);
}
ExtraObjectsCache[2] = plusFab;
var plusLabel = plusFab.transform.Find("FontPlacer/Text_TMP").GetComponent<TextMeshPro>();
plusLabel.alignment = TextAlignmentOptions.Center;
plusLabel.DestroyTranslator();
plusLabel.SetText("+");
plusLabel.color = Color.white;
plusLabel.transform.localPosition = new(plusLabel.transform.localPosition.x, plusLabel.transform.localPosition.y + 0.26f, plusLabel.transform.localPosition.z);
if (!cached) plusLabel.transform.localPosition = new(plusLabel.transform.localPosition.x, plusLabel.transform.localPosition.y + 0.26f, plusLabel.transform.localPosition.z);
plusLabel.transform.localScale = new(18f, 4f, 1f);
var plus = plusFab.GetComponent<PassiveButton>();
@@ -1300,11 +1175,12 @@ public static class GameSettingMenuPatch
plus.OnClick.AddListener((Action)(() =>
{
if (!PresetBehaviour)
__instance.ChangeTab(3, false);
LastPresetChange = Utils.TimeStamp;
PresetBehaviour.Increase();
Options.Preset++;
ModSettingsTabs.Values.Do(GameOptionsMenuPatch.ReCreateSettings);
GameOptionsMenuPatch.RefreshSettingValues();
GameOptionsMenuPatch.RefreshTabButtons();
presetTmp.SetText(Translator.GetString($"Preset_{OptionItem.CurrentPreset + 1}"));
Logger.Info($"Current preset: {OptionItem.CurrentPreset + 1}", "GameOptionsMenuPatch");
}));
@@ -1350,9 +1226,14 @@ public static class GameSettingMenuPatch
{
CustomGameMode gm = gms[index];
var gmButton = ModGameOptionsMenu.Track(Object.Instantiate(gMinus, gameSettingsLabel.transform, true));
cached = GMButtons.TryGetValue(gm, out cache);
var gmButton = cached ? cache : ModGameOptionsMenu.Track(Object.Instantiate(gMinus, gameSettingsLabel.transform, true));
if (cached)
{
gmButton.transform.SetParent(gameSettingsLabel.transform, false);
gmButton.SetActive(true);
}
gmButton.transform.localPosition = new Vector3((((index / 8) - ((totalCols - 1) / 2f)) * 1.4f) + 0.86f, gameSettingsLabelPos.y - 1.9f - (0.22f * (index % 8)), -1f);
gmButton.transform.localScale = new(0.4f, 0.3f, 1f);
var gmButtonTmp = gmButton.transform.Find("FontPlacer/Text_TMP").GetComponent<TextMeshPro>();
gmButtonTmp.alignment = TextAlignmentOptions.Center;
@@ -1366,19 +1247,36 @@ public static class GameSettingMenuPatch
gmPassiveButton.OnClick.RemoveAllListeners();
gmPassiveButton.OnClick.AddListener((Action)(() =>
{
if (ModSettingsTabLoaded && !((TabGroup)(ModGameOptionsMenu.TabIndex - 3)).IsRelevant(gm))
GameSettingMenu.Instance.ChangeTab(4, false);
Options.GameMode.SetValue((int)gm - 1);
GameOptionsMenuPatch.ReloadUI();
GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.GameSettings]);
if (gm is CustomGameMode.Standard or CustomGameMode.HideAndSeek)
{
GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.ImpostorRoles]);
GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.CrewmateRoles]);
GameOptionsMenuPatch.ReCreateSettings(ModSettingsTabs[TabGroup.NeutralRoles]);
}
GameOptionsMenuPatch.RefreshTabButtons();
GameOptionsMenuPatch.RefreshCheckMarkColors();
gameSettingsLabel.SetText($"<size=50%>{Translator.GetString($"Mode{Options.CurrentGameMode}")}</size>\n");
}));
gmPassiveButton.activeTextColor = gmPassiveButton.inactiveTextColor = gmPassiveButton.disabledTextColor = gmPassiveButton.selectedTextColor = Main.GameModeColors[gm];
GMButtons.Add(gmButton);
GMButtons[gm] = gmButton;
}
if (!HudManager.InstanceExists) return;
FreeChatInputField freeChatField = HudManager.Instance.Chat.freeChatField;
FreeChatInputField field = ModGameOptionsMenu.Track(Object.Instantiate(freeChatField, parentLeftPanel.parent));
cached = InputField;
FreeChatInputField field = cached ? InputField : ModGameOptionsMenu.Track(Object.Instantiate(freeChatField, parentLeftPanel.parent));
if (cached)
{
field.transform.SetParent(parentLeftPanel.parent, false);
field.gameObject.SetActive(true);
}
field.transform.localScale = new(0.3f, 0.59f, 1);
field.transform.localPosition = new(-0.7f, -2.5f, -5f);
field.textArea.outputText.transform.localScale = new(3.5f, 2f, 1f);
@@ -1481,6 +1379,8 @@ public static class GameSettingMenuPatch
__instance.ControllerSelectable.Add(gameSettingButton);
}
private static bool ModSettingsTabLoaded;
[HarmonyPatch(nameof(GameSettingMenu.ChangeTab))]
[HarmonyPrefix]
public static bool ChangeTabPrefix(GameSettingMenu __instance, ref int tabNum, [HarmonyArgument(1)] bool previewOnly)
@@ -1523,15 +1423,14 @@ public static class GameSettingMenuPatch
if (!OnlinePresetsManager.PresetsLoaded && tabGroup == TabGroup.PresetExplorer)
{
var co = Main.Instance.StartCoroutine(
__instance.StartCoroutine(
OnlinePresetsManager.FetchPresetList(list =>
{
OnlinePresetsManager.CachedPresets = list;
OnlinePresetsManager.PresetsLoaded = true;
GameOptionsMenuPatch.ReloadUI();
})
OnlinePresetsManager.CreatePresetExplorerUI(ModSettingsTabs[tabGroup]);
}).WrapToIl2Cpp()
);
ModGameOptionsMenu.RunningMainCoroutines.Add(co);
}
if ((previewOnly && Controller.currentTouchType == Controller.TouchType.Joystick) || !previewOnly)
@@ -1561,7 +1460,11 @@ public static class GameSettingMenuPatch
__instance.ToggleLeftSideDarkener(true);
__instance.ToggleRightSideDarkener(false);
if (ModSettingsButtons.TryGetValue(tabGroup, out button) && button) button.SelectButton(true);
if (ModSettingsButtons.TryGetValue(tabGroup, out button) && button)
button.SelectButton(true);
if (tabGroup == TabGroup.GameSettings)
ModSettingsTabLoaded = true;
return false;
}
@@ -1593,36 +1496,34 @@ public static class GameSettingMenuPatch
return false;
}
private static Transform TempParent;
[HarmonyPatch(nameof(GameSettingMenu.Close))]
[HarmonyPrefix]
public static void Close_Prefix(GameSettingMenu __instance)
public static void Close_Prefix()
{
DestroySetting();
ModGameOptionsMenu.DestroyOption();
if (__instance.GameSettingsTab && __instance.GameSettingsTab.Children != null)
if (TempParent == null)
{
foreach (var opt in __instance.GameSettingsTab.Children)
{
if (!opt) continue;
if (opt.TryGetComponent<PassiveButton>(out var btn))
btn.OnClick.RemoveAllListeners();
ModGameOptionsMenu.Destroy(opt.gameObject);
}
var go = new GameObject("EHR Settings UI Cache Root");
Object.DontDestroyOnLoad(go);
go.SetActive(true);
TempParent = go.transform;
}
foreach (var x in ModSettingsTabs.Values) SetTempParent(x.gameObject);
foreach (var x in ModSettingsButtons.Values) SetTempParent(x.gameObject);
foreach (var x in ExtraObjectsCache.Values) SetTempParent(x);
foreach (var x in GMButtons.Values) SetTempParent(x);
SetTempParent(InputField.gameObject);
return;
try { __instance.StopAllCoroutines(); }
catch { }
Cleanup();
}
private static void Cleanup()
{
GC.Collect();
Resources.UnloadUnusedAssets();
void SetTempParent(GameObject go)
{
go.gameObject.transform.SetParent(TempParent, false);
go.gameObject.SetActive(false);
}
}
[HarmonyPatch(nameof(GameSettingMenu.Close))]
[HarmonyPostfix]
public static void Close_Postfix()
@@ -1630,12 +1531,12 @@ public static class GameSettingMenuPatch
try
{
int numImpostors = Main.NormalOptions.NumImpostors;
(OptionItem MinSetting, OptionItem MaxSetting) = Options.FactionMinMaxSettings[Team.Impostor];
(OptionItem minSetting, OptionItem maxSetting) = Options.FactionMinMaxSettings[Team.Impostor];
if (numImpostors != NumImpsOnOpen && MinImpsOnOpen == MinSetting.GetInt() && MaxImpsOnOpen == MaxSetting.GetInt())
if (numImpostors != NumImpsOnOpen && MinImpsOnOpen == minSetting.GetInt() && MaxImpsOnOpen == maxSetting.GetInt())
{
MinSetting.SetValue(numImpostors);
MaxSetting.SetValue(numImpostors);
minSetting.SetValue(numImpostors);
maxSetting.SetValue(numImpostors);
Logger.SendInGame(string.Format(Translator.GetString("MinMaxModdedImpCountsSettingsChangedAuto"), numImpostors));
}
@@ -1659,8 +1560,6 @@ public static class GameSettingMenuPatch
catch (Exception e) { Utils.ThrowException(e); }
Options.AutoSetFactionMinMaxSettings();
//Main.Instance.StartCoroutine(OptionShower.GetText());
}
}
@@ -1669,7 +1568,7 @@ public static class FixInputChatField
{
public static bool Prefix(FreeChatInputField __instance)
{
if (GameSettingMenuPatch.InputField && __instance == GameSettingMenuPatch.InputField)
if (GameSettingMenuPatch.InputField && __instance == GameSettingMenuPatch.InputField && __instance.gameObject.activeSelf)
{
Vector2 size = __instance.Background.size;
size.y = Math.Max(0.62f, __instance.textArea.TextHeight + 0.2f);
@@ -1690,7 +1589,7 @@ public static class FixDarkThemeForSearchBar
FreeChatInputField field = GameSettingMenuPatch.InputField;
if (field)
if (field && field.gameObject.activeSelf)
{
field.background.color = new Color32(40, 40, 40, byte.MaxValue);
field.textArea.compoText.Color(Color.white);
+3
View File
@@ -1065,6 +1065,9 @@ internal static class TaskPanelBehaviourPatch
internal static TaskPanelBehaviour CreateRoleTab(CustomRoles role)
{
TempPlayerData.Clear();
TempPointsData.Clear();
TaskPanel = HudManager.Instance.TaskStuff.transform.FindChild("TaskPanel").gameObject.GetComponent<TaskPanelBehaviour>();
GameObject clonePanel = Object.Instantiate(TaskPanel.gameObject, TaskPanel.transform.parent);
clonePanel.name = "RolePanel";
+1 -1
View File
@@ -1384,7 +1384,7 @@ internal static class MeetingHudOnDestroyPatch
[HarmonyPatch(typeof(MeetingHud), nameof(MeetingHud.CastVote))]
internal static class MeetingHudCastVotePatch
{
private static readonly Dictionary<byte, (MeetingHud MeetingHud, PlayerVoteArea SourcePVA, PlayerControl SourcePC)> ShouldCancelVoteList = [];
public static readonly Dictionary<byte, (MeetingHud MeetingHud, PlayerVoteArea SourcePVA, PlayerControl SourcePC)> ShouldCancelVoteList = [];
public static bool Prefix(MeetingHud __instance, [HarmonyArgument(0)] byte srcPlayerId, [HarmonyArgument(1)] byte suspectPlayerId)
{
+6 -19
View File
@@ -22,17 +22,19 @@ internal static class NotificationPopperPatch
public static void AddSettingsChangeMessage(OptionItem option, bool playSound = false)
{
if (Utils.TimeStamp == GameSettingMenuPatch.LastPresetChange) return;
string optValue = option.GetString();
if (optValue == "STRMISS") return;
SendRpc(0, option.Id, playSound: playSound);
string name = option.GetName();
if (name == "Accept") return;
string parentName = option.Parent?.GetName() ?? string.Empty;
if (parentName == "Accept") return;
SendRpc(option.Id, playSound);
string str = option.Parent != null
? TranslationController.Instance.GetString(StringNames.LobbyChangeSettingNotification, "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + parentName + "</font>: <font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + name + "</font>", "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + optValue + "</font>")
: TranslationController.Instance.GetString(StringNames.LobbyChangeSettingNotification, "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + name + "</font>", "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + optValue + "</font>");
@@ -40,19 +42,6 @@ internal static class NotificationPopperPatch
SettingsChangeMessageLogic(option, str, playSound);
}
public static void AddRoleSettingsChangeMessage(OptionItem option, CustomRoles customRole, bool playSound = false)
{
string optValue = option.GetString();
if (optValue == "STRMISS") return;
string name = option.GetName();
if (name == "Accept") return;
SendRpc(1, option.Id, customRole, playSound);
string str = TranslationController.Instance.GetString(StringNames.LobbyChangeSettingNotification, "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + name + "</font>", "<font=\"Barlow-Black SDF\" material=\"Barlow-Black Outline\">" + optValue + "</font>");
SettingsChangeMessageLogic(option, str, playSound);
}
private static void SettingsChangeMessageLogic(OptionItem option, string item, bool playSound)
{
if (Instance.lastMessageKey == option.Id && Instance.activeMessages.Count > 0)
@@ -70,13 +59,11 @@ internal static class NotificationPopperPatch
if (playSound) SoundManager.Instance.PlaySoundImmediate(Instance.settingsChangeSound, false);
}
private static void SendRpc(byte typeId, int optionId, CustomRoles customRole = CustomRoles.NotAssigned, bool playSound = true)
private static void SendRpc(int optionId, bool playSound = true)
{
if (Options.HideGameSettings.GetBool()) return;
if (!AmongUsClient.Instance.AmHost || Options.HideGameSettings.GetBool()) return;
var msg = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.NotificationPopper, Hazel.SendOption.None);
msg.Write(typeId);
msg.Write(optionId);
msg.Write((int)customRole);
msg.Write(playSound);
AmongUsClient.Instance.FinishRpcImmediately(msg);
}
+5 -110
View File
@@ -27,116 +27,6 @@ internal static class ChangeRoleSettings
{
public static bool BlockPopulateSkins;
public static bool Prefix(AmongUsClient __instance, ref IEnumerator __result)
{
if (!GameStates.IsLocalGame || !HudManager.InstanceExists) return true;
__result = CoStartGame().WrapToIl2Cpp();
return false;
IEnumerator<object> CoStartGame()
{
if (HudManager.Instance.GameMenu.IsOpen)
HudManager.Instance.GameMenu.Close();
UnityTelemetry.Instance.Init();
__instance.logger.Info("Received game start: " + __instance.AmHost);
yield return null;
while (!HudManager.InstanceExists)
yield return null;
while (!PlayerControl.LocalPlayer)
yield return null;
PlayerControl.LocalPlayer.moveable = false;
PlayerControl.LocalPlayer.MyPhysics.inputHandler.enabled = true;
var objectOfType1 = Object.FindObjectOfType<PlayerCustomizationMenu>();
if (objectOfType1)
objectOfType1.Close(false);
var objectOfType2 = Object.FindObjectOfType<GameSettingMenu>();
if (objectOfType2)
objectOfType2.Close();
if (GameStartManager.InstanceExists)
{
__instance.DisconnectHandlers.Remove(GameStartManager.Instance.CastFast<IDisconnectHandler>());
Object.Destroy(GameStartManager.Instance.gameObject);
}
if (LobbyInfoPane.InstanceExists)
Object.Destroy(LobbyInfoPane.Instance.gameObject);
if (DiscordManager.InstanceExists)
DiscordManager.Instance.SetPlayingGame();
if (!string.IsNullOrEmpty(DataManager.Player.Store.ActiveCosmicube))
AmongUsClient.Instance.SetActivePodType(CosmicubeManager.Instance.GetCubeDataByID(DataManager.Player.Store.ActiveCosmicube).podId);
else
{
PlayerStorageManager.CloudPlayerPrefs playerPrefs = PlayerStorageManager.Instance.PlayerPrefs;
AmongUsClient.Instance.SetActivePodType(playerPrefs.ActivePodType);
}
FriendsListManager.Instance.ConfirmationScreen.Cancel();
FriendsListManager.Instance.Ui.Close(true);
FriendsListManager.Instance.ReparentUI();
try { CosmeticsCache.ClearUnusedCosmetics(); }
catch (Exception e) { Utils.ThrowException(e); }
yield return HudManager.Instance.CoFadeFullScreen(Color.clear, Color.black);
++DataManager.Player.Ban.BanPoints;
DataManager.Player.Ban.PreviousGameStartDate = DateTime.UtcNow;
DataManager.Player.Save();
if (__instance.AmHost)
yield return __instance.CoStartGameHost();
else
{
yield return __instance.CoStartGameClient();
if (__instance.AmHost)
yield return __instance.CoStartGameHost();
}
for (var index = 0; index < GameData.Instance.PlayerCount; ++index)
{
PlayerControl player = GameData.Instance.AllPlayers[index].Object;
if (player)
{
player.moveable = true;
player.NetTransform.enabled = true;
player.MyPhysics.enabled = true;
player.MyPhysics.Awake();
player.MyPhysics.ResetMoveState();
player.Collider.enabled = true;
ShipStatus.Instance.SpawnPlayer(player, GameData.Instance.PlayerCount, true);
}
}
FriendsListManager.Instance.SetRecentlyPlayed(GameData.Instance.AllPlayers);
GameData.TimeGameStarted = Time.realtimeSinceStartup;
int map = Mathf.Clamp(GameOptionsManager.Instance.CurrentGameOptions.MapId, 0, Constants.MapNames.Length - 1);
string gameName = GameCode.IntToGameName(AmongUsClient.Instance.GameId);
DebugAnalytics.Instance.Analytics.StartGame(PlayerControl.LocalPlayer.Data, GameData.Instance.PlayerCount, GameOptionsManager.Instance.CurrentGameOptions.NumImpostors, AmongUsClient.Instance.NetworkMode, (MapNames)map, GameOptionsManager.Instance.CurrentGameOptions.GameMode, gameName, ServerManager.Instance.CurrentRegion.Name, GameOptionsManager.Instance.CurrentGameOptions, GameData.Instance.AllPlayers);
try
{
UnityTelemetry.Instance.StartGame(AmongUsClient.Instance.AmHost, GameData.Instance.PlayerCount, GameOptionsManager.Instance.CurrentGameOptions.NumImpostors, AmongUsClient.Instance.NetworkMode, DataManager.Player.Stats.GetStat(StatID.GamesAsImpostor), DataManager.Player.Stats.GetStat(StatID.GamesStarted), DataManager.Player.Stats.GetStat(StatID.CrewmateStreak));
NetworkedPlayerInfo.PlayerOutfit defaultOutfit = PlayerControl.LocalPlayer.Data.DefaultOutfit;
UnityTelemetry.Instance.StartGameCosmetics(defaultOutfit.ColorId, defaultOutfit.HatId, defaultOutfit.SkinId, defaultOutfit.PetId, defaultOutfit.VisorId, defaultOutfit.NamePlateId);
}
catch { }
GameDebugCommands.AddCommands();
}
}
public static void Postfix(AmongUsClient __instance)
{
try { LobbySharingAPI.NotifyLobbyStatusChanged(LobbyStatus.In_Game); }
@@ -309,6 +199,7 @@ internal static class ChangeRoleSettings
ChatCommands.MutedPlayers.Clear();
ExtendedPlayerControl.TempExiled.Clear();
Utils.CachedRoleSettings.Clear();
MeetingHudCastVotePatch.ShouldCancelVoteList.Clear();
MeetingTimeManager.Init();
Main.DefaultCrewmateVision = Main.RealOptionsData.GetFloat(FloatOptionNames.CrewLightMod);
@@ -330,6 +221,9 @@ internal static class ChangeRoleSettings
Camouflage.BlockCamouflage = false;
Camouflage.Init();
ReportDeadBodyPatch.CanReport.Clear();
ReportDeadBodyPatch.WaitReport.Clear();
RoleResult = [];
foreach (PlayerControl pc in Main.CachedAllPlayerControls())
@@ -434,6 +328,7 @@ internal static class ChangeRoleSettings
RoleBlockManager.Reset();
ChatManager.ResetHistory();
PerSecondUpdateScheduler.Reset();
Prompt.Reset();
}
catch (Exception e) { Utils.ThrowException(e); }
+1 -1
View File
@@ -101,7 +101,7 @@ internal static class EndGamePatch
HashSet<PlayerControl> winner = Main.EnumeratePlayerControls().Where(pc => CustomWinnerHolder.WinnerIds.Contains(pc.PlayerId)).ToHashSet();
foreach (CustomRoles team in CustomWinnerHolder.WinnerRoles)
winner.UnionWith(Main.EnumeratePlayerControls().Where(p => p.Is(team) && !winner.Contains(p)));
winner.UnionWith(Main.EnumeratePlayerControls().Where(p => p.Is(team)));
Main.WinnerNameList = [];
Main.WinnerList = [];
+1 -1
View File
@@ -23,7 +23,7 @@ public static class ShowHostMeetingPatch
Main.ForceRebuildCachesPlayerControls();
GameEndChecker.ForceCheckEnd();
if (GameStates.IsInGame && HostControl == null)
if (GameStates.IsInGame && !HostControl)
{
PlayerControl host = AmongUsClient.Instance.GetHost().Character;
NetworkedPlayerInfo.PlayerOutfit outfit = Main.PlayerStates[host.Data.PlayerId].NormalOutfit;
@@ -79,6 +79,9 @@ internal class Warlock : RoleBase
public override void Init()
{
On = false;
WarlockTimer = [];
CursedPlayers = [];
IsCurseAndKill = [];
}
public override void ApplyGameOptions(IGameOptions opt, byte playerId)
@@ -62,6 +62,11 @@ internal class Revolutionist : RoleBase
public override void Init()
{
On = false;
IsDraw = [];
RevolutionistTimer = [];
RevolutionistStart = [];
RevolutionistLastTime = [];
RevolutionistCountdown = [];
}
public override bool CanUseKillButton(PlayerControl pc)
+2
View File
@@ -67,6 +67,8 @@ internal class Arsonist : RoleBase
public override void Init()
{
On = false;
ArsonistTimer = [];
IsDoused = [];
}
public override bool CanUseKillButton(PlayerControl pc)
@@ -71,6 +71,7 @@ public class Infection : RoleBase
InfectInfos.Clear();
InfectActive = false;
ShadeColor = Utils.GetRoleColor(CustomRoles.Infection).ShadeColor(0.25f);
Updates.Clear();
}
public override void Add(byte playerId)
+3 -1
View File
@@ -27,7 +27,7 @@ internal class Sprayer : RoleBase
private static readonly Dictionary<byte, long> LastUpdate = [];
private static int Id => 643240;
private static PlayerControl SprayerPC => GetPlayerById(SprayerId);
private static PlayerControl SprayerPC;
public override bool IsEnable => SprayerId != byte.MaxValue;
@@ -73,6 +73,7 @@ internal class Sprayer : RoleBase
public override void Init()
{
SprayerId = byte.MaxValue;
SprayerPC = null;
Traps.Clear();
TrappedCount.Clear();
LowerVisionList.Clear();
@@ -82,6 +83,7 @@ internal class Sprayer : RoleBase
public override void Add(byte playerId)
{
SprayerId = playerId;
SprayerPC = playerId.GetPlayer();
playerId.SetAbilityUseLimit(UseLimitOpt.GetFloat());
foreach (PlayerControl pc in Main.CachedAlivePlayerControls()) TrappedCount[pc.PlayerId] = 0;