Fix areinvaild on official servers (#584)

* Add force clamp in options builder

* Add vaild check for options
This commit is contained in:
NikoCat233 authored and GitHub committed 2026-04-16 21:47:57 +02:00
1 parent 37faf3e02c
commit 3ae5fa5ab3
3 files changed
+151 -71

No files matched your search

+65 -11
View File
@@ -3,23 +3,24 @@ using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using AmongUs.GameOptions;
using Hazel;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using InnerNet;
using UnityEngine;
using Hazel;
using Il2CppInterop.Runtime.InteropTypes.Arrays;
using InnerNet;
using UnityEngine;
using static EHR.GameStates;
namespace EHR.Modules;
public abstract class GameOptionsSender
{
protected abstract bool IsDirty { get; set; }
protected abstract bool IsDirty { get; set; }
protected virtual int TargetClientId => -1;
private Il2CppStructArray<byte> BuildOptionArray()
{
IGameOptions opt = BuildGameOptions();
var currentGameMode = AprilFoolsMode.IsAprilFoolsModeToggledOn ? opt.AprilFoolsOnMode : opt.GameMode;
private Il2CppStructArray<byte> BuildOptionArray()
{
IGameOptions opt = BuildSendableGameOptions();
var currentGameMode = AprilFoolsMode.IsAprilFoolsModeToggledOn ? opt.AprilFoolsOnMode : opt.GameMode;
// option => byte[]
MessageWriter writer = MessageWriter.Get();
@@ -107,7 +108,60 @@ public abstract class GameOptionsSender
catch (Exception ex) { Logger.Fatal(ex.ToString(), "GameOptionsSender.SendOptionsArray"); }
}
public abstract IGameOptions BuildGameOptions();
public abstract IGameOptions BuildGameOptions();
protected IGameOptions BuildSendableGameOptions()
{
return SanitizeForOfficialServer(BuildGameOptions());
}
protected static IGameOptions SanitizeForOfficialServer(IGameOptions opt)
{
if (CurrentServerType != ServerType.Vanilla || opt == null || !opt.TryCast(out NormalGameOptionsV10 normalOpt))
return opt;
int originalMaxPlayers = normalOpt.MaxPlayers;
int originalImpostors = normalOpt.NumImpostors;
int originalKillDistance = normalOpt.KillDistance;
float originalPlayerSpeed = normalOpt.PlayerSpeedMod;
bool changed = false;
if (normalOpt.MaxPlayers > 15)
{
normalOpt.SetInt(Int32OptionNames.MaxPlayers, 15);
changed = true;
}
int impostors = Mathf.Clamp(normalOpt.NumImpostors, 1, 3);
if (impostors != normalOpt.NumImpostors)
{
normalOpt.SetInt(Int32OptionNames.NumImpostors, impostors);
changed = true;
}
int killDistance = Mathf.Clamp(normalOpt.KillDistance, 0, 2);
if (killDistance != normalOpt.KillDistance)
{
normalOpt.SetInt(Int32OptionNames.KillDistance, killDistance);
changed = true;
}
float playerSpeed = Mathf.Clamp(normalOpt.PlayerSpeedMod, Main.MinSpeed, 3f);
if (!Mathf.Approximately(playerSpeed, normalOpt.PlayerSpeedMod))
{
normalOpt.SetFloat(FloatOptionNames.PlayerSpeedMod, playerSpeed);
changed = true;
}
if (changed)
{
Logger.Warn(
$"Clamped outgoing official game options: MaxPlayers={originalMaxPlayers}->{normalOpt.MaxPlayers}, NumImpostors={originalImpostors}->{normalOpt.NumImpostors}, KillDistance={originalKillDistance}->{normalOpt.KillDistance}, PlayerSpeedMod={originalPlayerSpeed:0.###}->{normalOpt.PlayerSpeedMod:0.###}",
nameof(GameOptionsSender));
}
return normalOpt.CastFast<IGameOptions>();
}
protected virtual bool AmValid()
{
@@ -171,4 +225,4 @@ public abstract class GameOptionsSender
protected static bool ForceWaitFrame;
#endregion
}
}
@@ -106,11 +106,11 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
IsDirty = true;
}
protected override void SendGameOptions()
{
if (player.AmOwner)
{
IGameOptions opt = BuildGameOptions();
protected override void SendGameOptions()
{
if (player.AmOwner)
{
IGameOptions opt = BuildSendableGameOptions();
if (GameManager.Instance?.LogicComponents != null)
{
@@ -127,11 +127,11 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
base.SendGameOptions();
}
protected override IEnumerator SendGameOptionsAsync()
{
if (player.AmOwner)
{
IGameOptions opt = BuildGameOptions();
protected override IEnumerator SendGameOptionsAsync()
{
if (player.AmOwner)
{
IGameOptions opt = BuildSendableGameOptions();
if (GameManager.Instance?.LogicComponents != null)
{
+76 -50
View File
@@ -633,13 +633,15 @@ public static class ToggleOptionPatch
}
[HarmonyPatch(typeof(NumberOption))]
public static class NumberOptionPatch
{
private static int IncrementMultiplier
{
get
{
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) return 5;
public static class NumberOptionPatch
{
private static bool IsVanillaServer => GameStates.CurrentServerType == GameStates.ServerType.Vanilla;
private static int IncrementMultiplier
{
get
{
if (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift)) return 5;
if (Input.GetKey(KeyCode.LeftControl) || Input.GetKey(KeyCode.RightControl)) return 10;
return 1;
}
@@ -661,27 +663,34 @@ public static class NumberOptionPatch
__instance.ValidRange = new(0, 90);
__instance.Value = (float)Math.Round(__instance.Value, 2);
break;
case StringNames.GameKillCooldown:
__instance.ValidRange = new(0, 180);
__instance.Increment = 0.5f;
__instance.Value = (float)Math.Round(__instance.Value, 2);
break;
case StringNames.GamePlayerSpeed:
case StringNames.GameCrewLight:
case StringNames.GameImpostorLight:
__instance.Increment = 0.05f;
__instance.Value = (float)Math.Round(__instance.Value, 2);
break;
case StringNames.GameKillCooldown:
__instance.ValidRange = new(0, 180);
__instance.Increment = 0.5f;
__instance.Value = (float)Math.Round(__instance.Value, 2);
break;
case StringNames.GamePlayerSpeed:
if (IsVanillaServer)
__instance.ValidRange = new(Main.MinSpeed, 3f);
__instance.Increment = 0.05f;
__instance.Value = Mathf.Clamp((float)Math.Round(__instance.Value, 2), __instance.ValidRange.min, __instance.ValidRange.max);
break;
case StringNames.GameCrewLight:
case StringNames.GameImpostorLight:
__instance.Increment = 0.05f;
__instance.Value = (float)Math.Round(__instance.Value, 2);
break;
case StringNames.GameNumImpostors:
__instance.ValidRange = GameStates.CurrentServerType != GameStates.ServerType.Vanilla
? new(0, Crowded.MaxImpostors) : new(1, 3);
__instance.Value = (float)Math.Round(__instance.Value, 2);
if (DebugModeManager.AmDebugger) __instance.ValidRange.min = 0;
break;
case StringNames.CapacityLabel:
__instance.ValidRange = new(4, 127);
break;
}
__instance.ValidRange = GameStates.CurrentServerType != GameStates.ServerType.Vanilla
? new(0, Crowded.MaxImpostors) : new(1, 3);
__instance.Value = Mathf.Clamp((float)Math.Round(__instance.Value, 2), __instance.ValidRange.min, __instance.ValidRange.max);
if (DebugModeManager.AmDebugger) __instance.ValidRange.min = 0;
break;
case StringNames.CapacityLabel:
__instance.ValidRange = IsVanillaServer ? new(4, 15) : new(4, 127);
__instance.Value = Mathf.Clamp(__instance.Value, __instance.ValidRange.min, __instance.ValidRange.max);
break;
}
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index))
{
@@ -803,18 +812,33 @@ public static class NumberOptionPatch
}
[HarmonyPatch(typeof(StringOption))]
public static class StringOptionPatch
{
private static long HelpShowEndTS;
[HarmonyPatch(nameof(StringOption.Initialize))]
[HarmonyPrefix]
private static bool InitializePrefix(StringOption __instance)
{
if (__instance.name.StartsWith(nameof(OnlinePresetsManager))) return true;
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index))
{
public static class StringOptionPatch
{
private static long HelpShowEndTS;
private static bool IsVanillaServer => GameStates.CurrentServerType == GameStates.ServerType.Vanilla;
private static void ClampOfficialStringOption(StringOption option)
{
if (!IsVanillaServer) return;
switch (option.Title)
{
case StringNames.GameKillDistance:
option.Value = Mathf.Clamp(option.Value, 0, Math.Min(2, option.Values.Length - 1));
break;
}
}
[HarmonyPatch(nameof(StringOption.Initialize))]
[HarmonyPrefix]
private static bool InitializePrefix(StringOption __instance)
{
if (__instance.name.StartsWith(nameof(OnlinePresetsManager))) return true;
ClampOfficialStringOption(__instance);
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index))
{
OptionItem item = OptionItem.AllOptions[index];
string name = item.GetName();
item.OptionBehaviour = __instance;
@@ -1006,18 +1030,20 @@ public static class StringOptionPatch
return true;
}
[HarmonyPatch(nameof(StringOption.FixedUpdate))]
[HarmonyPrefix]
private static bool FixedUpdatePrefix(StringOption __instance)
{
if (__instance.name.StartsWith(nameof(OnlinePresetsManager)))
[HarmonyPatch(nameof(StringOption.FixedUpdate))]
[HarmonyPrefix]
private static bool FixedUpdatePrefix(StringOption __instance)
{
if (__instance.name.StartsWith(nameof(OnlinePresetsManager)))
{
__instance.TitleText.SetText(__instance.name.Split(';')[1]);
return false;
}
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index))
{
return false;
}
ClampOfficialStringOption(__instance);
if (ModGameOptionsMenu.OptionList.TryGetValue(__instance, out int index))
{
__instance.MinusBtn.SetInteractable(true);
__instance.PlusBtn.SetInteractable(true);
@@ -1700,4 +1726,4 @@ public static class RpcSyncSettingsPatch
{
OptionItem.SyncAllOptions();
}
}
}