mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-19 15:51:58 +00:00
FINALLY FIX MEMORY LEAK OMG (+ improved the lobby settings UI overall)
This commit is contained in:
1 parent
3bb0758e55
commit
bccb216e2d
29 files changed
+365
-557
No files matched your search
+1
-1
@@ -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" />
|
||||
|
||||
@@ -326,6 +326,8 @@ public static class CaptureTheFlag
|
||||
if (pc && outfit != null)
|
||||
Utils.RpcChangeSkin(pc, outfit);
|
||||
}
|
||||
|
||||
DefaultOutfits = [];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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))
|
||||
|
||||
@@ -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
|
||||
{
|
||||
|
||||
@@ -105,4 +105,11 @@ public static class Prompt
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
public static void Reset()
|
||||
{
|
||||
CurrentQuestion = string.Empty;
|
||||
ClearQueue();
|
||||
HidePromt();
|
||||
}
|
||||
}
|
||||
+1
-16
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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
@@ -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);
|
||||
|
||||
@@ -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";
|
||||
|
||||
@@ -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)
|
||||
{
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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); }
|
||||
|
||||
|
||||
@@ -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 = [];
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in new issue
Block a user