mirror of
https://github.com/Gurge44/EndlessHostRoles.git
synced 2026-10-20 01:46:25 +00:00
just some casual bug fixing
This commit is contained in:
1 parent
83b74f66fc
commit
b2ea6d4745
34 files changed
+462
-255
No files matched your search
@@ -36,6 +36,7 @@
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=FPS/@EntryIndexedValue">FPS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GA/@EntryIndexedValue">GA</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=GM/@EntryIndexedValue">GM</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HNS/@EntryIndexedValue">HNS</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HP/@EntryIndexedValue">HP</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HQ/@EntryIndexedValue">HQ</s:String>
|
||||
<s:String x:Key="/Default/CodeStyle/Naming/CSharpNaming/Abbreviations/=HUD/@EntryIndexedValue">HUD</s:String>
|
||||
|
||||
@@ -1734,8 +1734,8 @@ public static class BedWars
|
||||
if (!vanillaServer)
|
||||
{
|
||||
if (lastSelected) finalSb.Append(baseColor);
|
||||
finalSb.Append("▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔");
|
||||
finalSb.AppendLine();
|
||||
finalSb.AppendLine("▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔▔");
|
||||
finalSb.Append(Utils.ColorString(Color.white, bottomText));
|
||||
finalSb.AppendLine("</color>");
|
||||
}
|
||||
|
||||
@@ -260,13 +260,14 @@ public class Main : BasePlugin
|
||||
|
||||
// ################# - WARNING!!! - #####################
|
||||
// Don't use Enumerate(Alive)PlayerControls if it updates every frame or every second
|
||||
// Better use CachedAll/AlivePlayerControls, but in Coroutines (Async) functions need use "for (...)" loop
|
||||
// Better use CachedAll/AlivePlayerControls, but in Coroutines (Async) functions, use "for (...)" loop
|
||||
public static IEnumerable<PlayerControl> EnumeratePlayerControls()
|
||||
{
|
||||
// foreach can throw System.InvalidOperationException: Collection was modified; enumeration operation may not execute.
|
||||
// if the code waits frames between iterations, so the safest way is to use a for loop backwards
|
||||
for (int index = PlayerControl.AllPlayerControls.Count - 1; index >= 0; index--)
|
||||
{
|
||||
if (PlayerControl.AllPlayerControls.Count <= index) continue;
|
||||
PlayerControl pc = PlayerControl.AllPlayerControls[index];
|
||||
if (!pc || pc.PlayerId >= 254) continue;
|
||||
yield return pc;
|
||||
@@ -276,6 +277,7 @@ public class Main : BasePlugin
|
||||
{
|
||||
for (int index = PlayerControl.AllPlayerControls.Count - 1; index >= 0; index--)
|
||||
{
|
||||
if (PlayerControl.AllPlayerControls.Count <= index) continue;
|
||||
PlayerControl pc = PlayerControl.AllPlayerControls[index];
|
||||
if (!pc.IsAliveWithConditions() || pc.PlayerId >= 254) continue;
|
||||
yield return pc;
|
||||
@@ -319,7 +321,7 @@ public class Main : BasePlugin
|
||||
}
|
||||
// ################# - WARNING!!! - #####################
|
||||
// Don't use CachedAll/AlivePlayerControls witch "foreach (...)" loop in Coroutines (Async) functions
|
||||
// In async functions use a "for (...)" loop or Enumerate(Alive)PlayerControls or CachedAll/AlivePlayerControls witch LINQ functions (Like: ToList() or ToArray())
|
||||
// In async functions use a "for (...)" loop or Enumerate(Alive)PlayerControls or CachedAll(Alive)PlayerControls with LINQ functions (Like: ToList() or ToArray())
|
||||
// ######################################
|
||||
public static List<PlayerControl> CachedAllPlayerControls()
|
||||
{
|
||||
|
||||
@@ -241,7 +241,8 @@ namespace EHR
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
if (SnapToSendFrameCount++ < 5) return;
|
||||
// max 30 calls per second in total
|
||||
if (++SnapToSendFrameCount < Math.Max(10, AllObjects.Count)) return;
|
||||
SnapToSendFrameCount = 0;
|
||||
|
||||
if (AmongUsClient.Instance.AmClient)
|
||||
|
||||
@@ -248,7 +248,7 @@ internal static class CustomRoleSelector
|
||||
|
||||
Dictionary<RoleAssignType, List<RoleAssignInfo>> allRoles = roles.ToDictionary(x => x.Key, x => x.Value.ToList());
|
||||
|
||||
roles.Keys.ToArray().Do(type => ApplySubCategoryLimits(type, subCategoryLimits));
|
||||
roles.Keys.Do(type => ApplySubCategoryLimits(type, subCategoryLimits));
|
||||
|
||||
Logger.Msg("===================================================", "PreSelectedRoles");
|
||||
Logger.Info(string.Join(", ", roles[RoleAssignType.Impostor].Select(x => x.Role.ToString())), "PreSelectedImpostorRoles");
|
||||
|
||||
+64
-31
@@ -36,12 +36,14 @@ public class CustomRpcSender
|
||||
private readonly OnSendDelegateType onSendDelegate;
|
||||
public readonly SendOption sendOption;
|
||||
|
||||
public bool checkLength;
|
||||
|
||||
// 0~: targetClientId (GameDataTo)
|
||||
// -1: All players (GameData)
|
||||
// -2: Not set
|
||||
private int currentRpcTarget;
|
||||
|
||||
private bool packed;
|
||||
public bool packed;
|
||||
|
||||
private State currentState/* = State.BeforeInit*/;
|
||||
public int messages;
|
||||
@@ -57,6 +59,7 @@ public class CustomRpcSender
|
||||
this.log = log;
|
||||
currentRpcTarget = -2;
|
||||
packed = false;
|
||||
checkLength = true;
|
||||
onSendDelegate = () => { };
|
||||
messages = 0;
|
||||
|
||||
@@ -177,7 +180,7 @@ public class CustomRpcSender
|
||||
return count;
|
||||
}
|
||||
|
||||
if (1 + GetPackedIntSize(AmongUsClient.Instance.GameId) >= stream.Length)
|
||||
if (3 + GetPackedIntSize(AmongUsClient.Instance.GameId) >= stream.Length)
|
||||
dispose = true;
|
||||
else
|
||||
EndMessage();
|
||||
@@ -271,7 +274,7 @@ public class CustomRpcSender
|
||||
throw new InvalidOperationException(errorMsg);
|
||||
}
|
||||
|
||||
if (stream.Length > 500)
|
||||
if (checkLength && stream.Length > 500)
|
||||
{
|
||||
if (currentState == State.InRootPackedMessage)
|
||||
{
|
||||
@@ -320,7 +323,7 @@ public class CustomRpcSender
|
||||
throw new InvalidOperationException(errorMsg);
|
||||
}
|
||||
|
||||
if (stream.Length > 500)
|
||||
if (checkLength && stream.Length > 500)
|
||||
{
|
||||
doneStreams.Add(stream);
|
||||
stream = MessageWriter.Get(sendOption);
|
||||
@@ -529,6 +532,63 @@ public class CustomRpcSender
|
||||
|
||||
public static class CustomRpcSenderExtensions
|
||||
{
|
||||
public static void RpcSetName(ref CustomRpcSender sender, PlayerControl player, string name, PlayerControl seer = null)
|
||||
{
|
||||
bool seerIsNull = !seer;
|
||||
int targetClientId = seerIsNull ? -1 : seer.OwnerId;
|
||||
|
||||
name = name.Replace("color=", string.Empty);
|
||||
|
||||
switch (seerIsNull)
|
||||
{
|
||||
case true when Main.LastNotifyNames.Where(x => x.Key.Item1 == player.PlayerId).All(x => x.Value == name):
|
||||
case false when Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] == name:
|
||||
return;
|
||||
case true:
|
||||
Main.EnumeratePlayerControls().Do(x => Main.LastNotifyNames[(player.PlayerId, x.PlayerId)] = name);
|
||||
break;
|
||||
default:
|
||||
Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name;
|
||||
break;
|
||||
}
|
||||
|
||||
sender.checkLength = false;
|
||||
|
||||
if (sender.stream.Length + GetSetNameRpcSize(player.NetId, name) > 1100)
|
||||
{
|
||||
bool packed = sender.packed;
|
||||
sender.SendMessage();
|
||||
sender = CustomRpcSender.Create(sender.name, sender.sendOption);
|
||||
if (packed) sender.StartPackedMessage();
|
||||
}
|
||||
|
||||
sender.AutoStartRpc(player.NetId, RpcCalls.SetName, targetClientId)
|
||||
.Write(player.Data.NetId)
|
||||
.Write(name)
|
||||
.Write(false)
|
||||
.EndRpc();
|
||||
|
||||
return;
|
||||
|
||||
static int GetSetNameRpcSize(uint netId, string playerName)
|
||||
{
|
||||
int byteCount = System.Text.Encoding.UTF8.GetByteCount(playerName);
|
||||
return 3 + PackedUIntSize(netId) + 1 + 4 + PackedUIntSize((uint)byteCount) + byteCount + 1;
|
||||
}
|
||||
|
||||
static int PackedUIntSize(uint value)
|
||||
{
|
||||
return value switch
|
||||
{
|
||||
< 0x80 => 1,
|
||||
< 0x4000 => 2,
|
||||
< 0x20_0000 => 3,
|
||||
< 0x1000_0000 => 4,
|
||||
_ => 5
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
extension(CustomRpcSender sender)
|
||||
{
|
||||
public bool RpcSetRole(PlayerControl player, RoleTypes role, int targetClientId = -1, bool noRpcForSelf = true, bool changeRoleMap = false)
|
||||
@@ -568,33 +628,6 @@ public static class CustomRpcSenderExtensions
|
||||
return true;
|
||||
}
|
||||
|
||||
public void RpcSetName(PlayerControl player, string name, PlayerControl seer = null)
|
||||
{
|
||||
bool seerIsNull = !seer;
|
||||
int targetClientId = seerIsNull ? -1 : seer.OwnerId;
|
||||
|
||||
name = name.Replace("color=", string.Empty);
|
||||
|
||||
switch (seerIsNull)
|
||||
{
|
||||
case true when Main.LastNotifyNames.Where(x => x.Key.Item1 == player.PlayerId).All(x => x.Value == name):
|
||||
case false when Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] == name:
|
||||
return;
|
||||
case true:
|
||||
Main.EnumeratePlayerControls().Do(x => Main.LastNotifyNames[(player.PlayerId, x.PlayerId)] = name);
|
||||
break;
|
||||
default:
|
||||
Main.LastNotifyNames[(player.PlayerId, seer.PlayerId)] = name;
|
||||
break;
|
||||
}
|
||||
|
||||
sender.AutoStartRpc(player.NetId, RpcCalls.SetName, targetClientId)
|
||||
.Write(player.Data.NetId)
|
||||
.Write(name)
|
||||
.Write(false)
|
||||
.EndRpc();
|
||||
}
|
||||
|
||||
public bool RpcGuardAndKill(PlayerControl killer, PlayerControl target = null, bool forObserver = false, bool fromSetKCD = false)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost)
|
||||
|
||||
+12
-2
@@ -12,18 +12,24 @@ public static class CustomSoundsManager
|
||||
{
|
||||
private static readonly string SoundsPath = $"{Environment.CurrentDirectory.Replace(@"\", "/")}/BepInEx/resources/";
|
||||
|
||||
public static long LastSoundRPCTS;
|
||||
|
||||
public static void RPCPlayCustomSound(this PlayerControl pc, string sound, float volume = 1f, float pitch = 1f, bool force = false)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!force && (!AmongUsClient.Instance.AmHost || !pc.IsModdedClient())) return;
|
||||
|
||||
if (!pc || pc.AmOwner)
|
||||
{
|
||||
Play(sound, volume, pitch);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!force && (!AmongUsClient.Instance.AmHost || !pc.IsModdedClient())) return;
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
if (now == LastSoundRPCTS) return;
|
||||
LastSoundRPCTS = now;
|
||||
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.PlayCustomSound, SendOption.None, pc.OwnerId);
|
||||
writer.Write(sound);
|
||||
writer.Write(volume);
|
||||
@@ -40,6 +46,10 @@ public static class CustomSoundsManager
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
Play(sound, volume, pitch);
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
if (now == LastSoundRPCTS) return;
|
||||
LastSoundRPCTS = now;
|
||||
|
||||
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.PlayCustomSound, SendOption.None);
|
||||
writer.Write(sound);
|
||||
|
||||
+114
-17
@@ -14,6 +14,7 @@ internal static class CustomTeamManager
|
||||
public static CustomTeam WinnerTeam;
|
||||
public static Dictionary<CustomTeam, HashSet<byte>> CustomTeamPlayerIds = [];
|
||||
public static List<CustomTeamOptionGroup> CustomTeamOptions = [];
|
||||
public static Dictionary<CustomTeam, List<bool>> CustomTeamOptionsCache = [];
|
||||
|
||||
public static void LoadCustomTeams()
|
||||
{
|
||||
@@ -72,7 +73,16 @@ internal static class CustomTeamManager
|
||||
|
||||
private static void UpdateEnabledTeams()
|
||||
{
|
||||
EnabledCustomTeams = CustomTeamOptions.Where(x => x.Enabled.GetBool()).Select(x => x.Team).ToHashSet();
|
||||
EnabledCustomTeams.Clear();
|
||||
CustomTeamOptionsCache.Clear();
|
||||
|
||||
foreach (CustomTeamOptionGroup customTeamOptionGroup in CustomTeamOptions)
|
||||
{
|
||||
if (customTeamOptionGroup.Enabled.GetBool())
|
||||
EnabledCustomTeams.Add(customTeamOptionGroup.Team);
|
||||
|
||||
CustomTeamOptionsCache[customTeamOptionGroup.Team] = customTeamOptionGroup.AllOptions.ConvertAll(x => x.GetBool());
|
||||
}
|
||||
}
|
||||
|
||||
public static void InitializeCustomTeamPlayers()
|
||||
@@ -127,6 +137,44 @@ internal static class CustomTeamManager
|
||||
});
|
||||
}
|
||||
|
||||
if (Utils.DoRPC)
|
||||
{
|
||||
var msg = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.CTA, SendOption.Reliable);
|
||||
msg.WritePacked(1);
|
||||
msg.WritePacked(EnabledCustomTeams.Count);
|
||||
EnabledCustomTeams.Do(x => x.Serialize(msg));
|
||||
AmongUsClient.Instance.FinishRpcImmediately(msg);
|
||||
msg.Recycle();
|
||||
|
||||
msg = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.CTA, SendOption.Reliable);
|
||||
msg.WritePacked(2);
|
||||
msg.WritePacked(CustomTeamPlayerIds.Count);
|
||||
|
||||
foreach ((CustomTeam customTeam, HashSet<byte> ids) in CustomTeamPlayerIds)
|
||||
{
|
||||
msg.WritePacked(ids.Count);
|
||||
ids.Do(x => msg.Write(x));
|
||||
msg.Write(customTeam.TeamName);
|
||||
}
|
||||
|
||||
AmongUsClient.Instance.FinishRpcImmediately(msg);
|
||||
msg.Recycle();
|
||||
|
||||
msg = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.CTA, SendOption.Reliable);
|
||||
msg.WritePacked(3);
|
||||
msg.WritePacked(CustomTeamOptionsCache.Count);
|
||||
|
||||
foreach ((CustomTeam customTeam, List<bool> bools) in CustomTeamOptionsCache)
|
||||
{
|
||||
msg.WritePacked(bools.Count);
|
||||
bools.ForEach(x => msg.Write(x));
|
||||
msg.Write(customTeam.TeamName);
|
||||
}
|
||||
|
||||
AmongUsClient.Instance.FinishRpcImmediately(msg);
|
||||
msg.Recycle();
|
||||
}
|
||||
|
||||
return;
|
||||
|
||||
static HashSet<byte> TakeAsManyAsSet(IEnumerable<byte> playerIds, CustomTeam customTeam)
|
||||
@@ -169,7 +217,44 @@ internal static class CustomTeamManager
|
||||
return CustomTeamPlayerIds[GetCustomTeam(seer.PlayerId)].Aggregate(string.Empty, (s, id) => s + Utils.ColorString(Main.PlayerColors.GetValueOrDefault(id, Color.white), TargetArrow.GetArrows(seer, id)));
|
||||
}
|
||||
|
||||
private static readonly Dictionary<CustomTeam, HashSet<byte>> AliveTeamPlayers = [];
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
switch (reader.ReadPackedInt32())
|
||||
{
|
||||
case 1:
|
||||
{
|
||||
EnabledCustomTeams.Clear();
|
||||
Loop.Times(reader.ReadPackedInt32(), _ => EnabledCustomTeams.Add(new CustomTeam(reader.ReadString())));
|
||||
break;
|
||||
}
|
||||
case 2:
|
||||
{
|
||||
CustomTeamPlayerIds.Clear();
|
||||
Loop.Times(reader.ReadPackedInt32(), _ =>
|
||||
{
|
||||
HashSet<byte> ids = [];
|
||||
Loop.Times(reader.ReadPackedInt32(), _ => ids.Add(reader.ReadByte()));
|
||||
string teamName = reader.ReadString();
|
||||
CustomTeamPlayerIds[EnabledCustomTeams.First(x => x.TeamName == teamName)] = ids;
|
||||
});
|
||||
break;
|
||||
}
|
||||
case 3:
|
||||
{
|
||||
CustomTeamOptionsCache.Clear();
|
||||
Loop.Times(reader.ReadPackedInt32(), _ =>
|
||||
{
|
||||
List<bool> bools = [];
|
||||
Loop.Times(reader.ReadPackedInt32(), _ => bools.Add(reader.ReadBoolean()));
|
||||
string teamName = reader.ReadString();
|
||||
CustomTeamOptionsCache[EnabledCustomTeams.First(x => x.TeamName == teamName)] = bools;
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static readonly List<CustomTeam> AliveTeamPlayers = [];
|
||||
private static readonly List<byte> ToRemove = [];
|
||||
public static bool CheckCustomTeamGameEnd()
|
||||
{
|
||||
@@ -210,27 +295,20 @@ internal static class CustomTeamManager
|
||||
AliveTeamPlayers.Clear();
|
||||
foreach ((CustomTeam teamKey, HashSet<byte> originalSet) in CustomTeamPlayerIds)
|
||||
{
|
||||
HashSet<byte> aliveSet = null;
|
||||
foreach (var id in originalSet)
|
||||
{
|
||||
var pc = Utils.GetPlayerById(id);
|
||||
if (pc.IsAlive())
|
||||
if (pc && pc.IsAlive())
|
||||
{
|
||||
aliveSet ??= [];
|
||||
aliveSet.Add(id);
|
||||
AliveTeamPlayers.Add(teamKey);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (aliveSet != null)
|
||||
AliveTeamPlayers[teamKey] = aliveSet;
|
||||
}
|
||||
|
||||
if (AliveTeamPlayers.Count == 1)
|
||||
{
|
||||
var aliveTeam = AliveTeamPlayers.GetEnumerator();
|
||||
aliveTeam.MoveNext();
|
||||
|
||||
var onlyTeam = aliveTeam.Current.Key;
|
||||
var winners = aliveTeam.Current.Value;
|
||||
var onlyTeam = AliveTeamPlayers[0];
|
||||
|
||||
for (int i = 0; i < aapc.Count; i++)
|
||||
{
|
||||
@@ -243,7 +321,7 @@ internal static class CustomTeamManager
|
||||
|
||||
WinnerTeam = onlyTeam;
|
||||
CustomWinnerHolder.SetWinnerOrAdditonalWinner(CustomWinner.CustomTeam);
|
||||
CustomWinnerHolder.WinnerIds = winners;
|
||||
CustomWinnerHolder.WinnerIds = CustomTeamPlayerIds[onlyTeam];
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -287,9 +365,7 @@ internal static class CustomTeamManager
|
||||
|
||||
public static bool IsSettingEnabledForTeam(CustomTeam team, CTAOption setting)
|
||||
{
|
||||
CustomTeamOptionGroup optionsGroup = CustomTeamOptions.First(x => x.Team.Equals(team));
|
||||
List<bool> values = optionsGroup.AllOptions.ConvertAll(x => x.GetBool());
|
||||
return values[(int)setting];
|
||||
return CustomTeamOptionsCache[team][(int)setting];
|
||||
}
|
||||
|
||||
internal class CustomTeam
|
||||
@@ -330,6 +406,27 @@ internal static class CustomTeamManager
|
||||
{
|
||||
return TeamName.GetHashCode();
|
||||
}
|
||||
|
||||
public void Serialize(MessageWriter writer)
|
||||
{
|
||||
StringBuilder sb = new();
|
||||
sb.Append(TeamName);
|
||||
sb.Append(';');
|
||||
sb.Append(RoleRevealScreenTitle);
|
||||
sb.Append(';');
|
||||
sb.Append(RoleRevealScreenSubtitle);
|
||||
sb.Append(';');
|
||||
sb.Append(RoleRevealScreenBackgroundColor);
|
||||
sb.Append(';');
|
||||
|
||||
for (var index = 0; index < TeamMembers.Count; index++)
|
||||
{
|
||||
sb.Append(TeamMembers[index].ToString());
|
||||
sb.Append(',');
|
||||
}
|
||||
|
||||
writer.Write(sb.ToString());
|
||||
}
|
||||
}
|
||||
|
||||
internal class CustomTeamOptionGroup
|
||||
|
||||
@@ -10,6 +10,7 @@ using EHR.Modules;
|
||||
using EHR.Modules.Extensions;
|
||||
using EHR.Roles;
|
||||
using Hazel;
|
||||
using Il2CppInterop.Runtime;
|
||||
using Il2CppInterop.Runtime.InteropTypes.Arrays;
|
||||
using InnerNet;
|
||||
using UnityEngine;
|
||||
@@ -509,9 +510,11 @@ internal static class ExtendedPlayerControl
|
||||
|
||||
public void RpcChangeRoleBasis(CustomRoles newCustomRole, bool loggerRoleMap = false, bool forced = false)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
if (!forced)
|
||||
{
|
||||
if (!AmongUsClient.Instance.AmHost || !GameStates.IsInGame || !player || !player.IsAlive()) return;
|
||||
if (!GameStates.IsInGame || !player || !player.IsAlive()) return;
|
||||
|
||||
if (AntiBlackout.SkipTasks || ExileController.Instance)
|
||||
{
|
||||
@@ -1299,12 +1302,16 @@ internal static class ExtendedPlayerControl
|
||||
{
|
||||
try
|
||||
{
|
||||
string name = isMeeting ? player.Data.PlayerName : player.name;
|
||||
return name.RemoveHtmlTags();
|
||||
return (isMeeting ? player.Data.PlayerName : player.name).RemoveHtmlTags();
|
||||
}
|
||||
catch (NullReferenceException nullReferenceException)
|
||||
{
|
||||
Logger.Error($"{nullReferenceException.Message} - player is null? {!player}", "GetRealName");
|
||||
Logger.Warn($"{nullReferenceException.Message} - player is null? {!player}", "GetRealName");
|
||||
return string.Empty;
|
||||
}
|
||||
catch (Il2CppException il2CppException)
|
||||
{
|
||||
Logger.Warn($"{il2CppException.Message} - player is null? {!player}", "GetRealName");
|
||||
return string.Empty;
|
||||
}
|
||||
catch (Exception exception)
|
||||
|
||||
@@ -34,6 +34,11 @@ public static class CollectionExtensions
|
||||
|
||||
return default(TKey);
|
||||
}
|
||||
|
||||
// foreach will only throw System.InvalidOperationException: collection was modified; enumeration operation may not execute.
|
||||
// if the number of elements inside the dictionary changes.
|
||||
// If Count stays the same for the entire iteration, it can be safely enumerated without ToList or ToArray.
|
||||
// Changing values does NOT modify the collection!
|
||||
|
||||
/// <summary>
|
||||
/// Sets the value for all existing keys in a dictionary to a specific value
|
||||
@@ -41,7 +46,7 @@ public static class CollectionExtensions
|
||||
/// <param name="value"></param>
|
||||
public void SetAllValues(TValue value)
|
||||
{
|
||||
foreach (TKey key in dictionary.Keys.ToArray())
|
||||
foreach (TKey key in dictionary.Keys)
|
||||
dictionary[key] = value;
|
||||
}
|
||||
|
||||
@@ -51,7 +56,7 @@ public static class CollectionExtensions
|
||||
/// <param name="adjust">The function to adjust the values with</param>
|
||||
public void AdjustAllValues(Func<TValue, TValue> adjust)
|
||||
{
|
||||
foreach (TKey key in dictionary.Keys.ToArray())
|
||||
foreach (TKey key in dictionary.Keys)
|
||||
dictionary[key] = adjust(dictionary[key]);
|
||||
}
|
||||
|
||||
|
||||
@@ -53,7 +53,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
}
|
||||
}
|
||||
|
||||
public static void SendAllImmediately()
|
||||
public static DataFlagRateLimiter.QueuedAction SendAllImmediately()
|
||||
{
|
||||
ForceWaitFrame = true;
|
||||
|
||||
@@ -83,20 +83,22 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
sender.IsDirty = false;
|
||||
}
|
||||
}
|
||||
|
||||
DataFlagRateLimiter.QueuedAction qa = null;
|
||||
|
||||
if (PackedWriter != null)
|
||||
{
|
||||
if (PackedWriterMessages > 0)
|
||||
{
|
||||
PackedWriter.EndMessage();
|
||||
Logger.Info($"PackedWriter flush queued - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendAllImmediately");
|
||||
var capturedWriter = PackedWriter;
|
||||
DataFlagRateLimiter.Enqueue(() =>
|
||||
qa = DataFlagRateLimiter.Enqueue(() =>
|
||||
{
|
||||
AmongUsClient.Instance.SendOrDisconnect(capturedWriter);
|
||||
capturedWriter.Recycle();
|
||||
Logger.Info("PackedWriter flush queue finished and sent", "SendAllImmediately");
|
||||
}, cleanup: capturedWriter.Recycle);
|
||||
Logger.Info($"PackedWriter flush queued - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendAllImmediately");
|
||||
}
|
||||
else
|
||||
{
|
||||
@@ -106,6 +108,8 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
|
||||
PackedWriter = null;
|
||||
PackedWriterMessages = 0;
|
||||
|
||||
return qa;
|
||||
}
|
||||
|
||||
public static void SetDirtyToAll()
|
||||
@@ -292,6 +296,7 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
if (PackedWriter.Length > 1000 || PackedWriterMessages >= AmongUsClient.Instance.GetMaxMessagePackingLimit())
|
||||
{
|
||||
PackedWriter.EndMessage();
|
||||
Logger.Info($"PackedWriter flush queued - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendOptionsArray");
|
||||
var capturedWriter = PackedWriter;
|
||||
DataFlagRateLimiter.Enqueue(() =>
|
||||
{
|
||||
@@ -299,7 +304,6 @@ public sealed class PlayerGameOptionsSender(PlayerControl player) : GameOptionsS
|
||||
capturedWriter.Recycle();
|
||||
Logger.Info("PackedWriter flush queue finished and sent", "SendOptionsArray");
|
||||
}, cleanup: capturedWriter.Recycle);
|
||||
Logger.Info($"PackedWriter flush queued - Length: {PackedWriter.Length}, Messages: {PackedWriterMessages}", "SendOptionsArray");
|
||||
PackedWriterMessages = 0;
|
||||
PackedWriter = MessageWriter.Get(SendOption.Reliable);
|
||||
PackedWriter.StartMessage(26);
|
||||
|
||||
@@ -161,6 +161,7 @@ internal static class ExitGamePatch
|
||||
Logger.Msg($"Exiting game - reason: {reason}", "ExitGamePatch.Prefix");
|
||||
|
||||
GameStates.InGame = false;
|
||||
GameEndChecker.LoadingEndScreen = false;
|
||||
Main.RealOptionsData?.Restore(GameOptionsManager.Instance.CurrentGameOptions);
|
||||
DataFlagRateLimiter.DropQueue();
|
||||
|
||||
|
||||
+16
-6
@@ -163,6 +163,7 @@ public enum CustomRPC
|
||||
Necronomicon,
|
||||
Stained,
|
||||
Entombed,
|
||||
CTA,
|
||||
|
||||
// Game Modes
|
||||
RoomRushDataSync,
|
||||
@@ -713,7 +714,7 @@ internal static class RPCHandlerPatch
|
||||
{
|
||||
byte bountyId = reader.ReadByte();
|
||||
byte targetId = reader.ReadByte();
|
||||
(Main.PlayerStates[bountyId].Role as BountyHunter)?.ReceiveRPC(targetId);
|
||||
(Main.PlayerStates[bountyId].Role as BountyHunter)?.ReceiveRPCTarget(targetId);
|
||||
break;
|
||||
}
|
||||
case CustomRPC.SyncBargainer:
|
||||
@@ -824,7 +825,7 @@ internal static class RPCHandlerPatch
|
||||
}
|
||||
case CustomRPC.SyncRabbit:
|
||||
{
|
||||
Rabbit.ReceiveRPC(reader);
|
||||
Rabbit.ReceiveRPCStatic(reader);
|
||||
break;
|
||||
}
|
||||
case CustomRPC.SyncYinYanger:
|
||||
@@ -961,12 +962,12 @@ internal static class RPCHandlerPatch
|
||||
if (operate == 1)
|
||||
{
|
||||
byte victim = reader.ReadByte();
|
||||
(Main.PlayerStates[id].Role as Penguin)?.ReceiveRPC(victim);
|
||||
(Main.PlayerStates[id].Role as Penguin)?.ReceiveRPCVictim(victim);
|
||||
}
|
||||
else
|
||||
{
|
||||
float timer = reader.ReadSingle();
|
||||
(Main.PlayerStates[id].Role as Penguin)?.ReceiveRPC(timer);
|
||||
bool reset = reader.ReadBoolean();
|
||||
(Main.PlayerStates[id].Role as Penguin)?.ReceiveRPCTimer(reset);
|
||||
}
|
||||
|
||||
break;
|
||||
@@ -1374,6 +1375,11 @@ internal static class RPCHandlerPatch
|
||||
LateTask.New(() => Stained.VioletNameList.Remove(id), 3f);
|
||||
break;
|
||||
}
|
||||
case CustomRPC.CTA:
|
||||
{
|
||||
CustomTeamManager.ReceiveRPC(reader);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
@@ -1390,7 +1396,7 @@ internal static class RPC
|
||||
if (targetId != -1)
|
||||
{
|
||||
ClientData client = Utils.GetClientById(targetId);
|
||||
if (client == null || client.Character == null || !Main.PlayerVersion.ContainsKey(client.Character.PlayerId)) return;
|
||||
if (client == null || !client.Character || !Main.PlayerVersion.ContainsKey(client.Character.PlayerId)) return;
|
||||
}
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost || PlayerControl.AllPlayerControls.Count <= 1) return;
|
||||
@@ -1417,6 +1423,10 @@ internal static class RPC
|
||||
public static void PlaySoundRPC(byte playerID, Sounds sound)
|
||||
{
|
||||
if (AmongUsClient.Instance.AmHost) PlaySound(playerID, sound);
|
||||
|
||||
long now = Utils.TimeStamp;
|
||||
if (now == CustomSoundsManager.LastSoundRPCTS) return;
|
||||
CustomSoundsManager.LastSoundRPCTS = now;
|
||||
|
||||
SendOption sendOption = SendOption.Reliable;
|
||||
|
||||
|
||||
+37
-38
@@ -169,11 +169,11 @@ public static class Utils
|
||||
|
||||
switch (Vector2.Distance(pc.Pos(), location))
|
||||
{
|
||||
// case < 0.3f:
|
||||
// {
|
||||
// if (log) Logger.Warn($"Target ({pc.GetNameWithRole().RemoveHtmlTags()}) is too close to the destination - Teleporting canceled", "TP");
|
||||
// return false;
|
||||
// }
|
||||
case < 0.3f:
|
||||
{
|
||||
if (log) Logger.Warn($"Target ({pc.GetNameWithRole().RemoveHtmlTags()}) is too close to the destination - Teleporting canceled", "TP");
|
||||
return false;
|
||||
}
|
||||
case < 1.5f when !GameStates.IsLobby:
|
||||
{
|
||||
if (log) Logger.Msg($"Target ({pc.GetNameWithRole().RemoveHtmlTags()}) is too close to the destination - Changed to SendOption.None", "TP");
|
||||
@@ -191,12 +191,18 @@ public static class Utils
|
||||
nt.SnapTo(location, (ushort)(nt.lastSequenceId + 328));
|
||||
nt.SetDirtyBit(uint.MaxValue);
|
||||
|
||||
if (NumSnapToCallsThisRound > 80)
|
||||
if (NumSnapToCallsThisRound >= 80)
|
||||
{
|
||||
if (log) Logger.Warn($"Too many SnapTo calls this round ({NumSnapToCallsThisRound}) - Changed to SendOption.None", "TP");
|
||||
if (log) Logger.Warn($"Too many Reliable SnapTo calls this round ({NumSnapToCallsThisRound}) - Changed to SendOption.None", "TP");
|
||||
sendOption = SendOption.None;
|
||||
}
|
||||
|
||||
if (NumSnapToCallsThisRound >= 100)
|
||||
{
|
||||
if (log) Logger.Warn($"Too many Total SnapTo calls this round and this second ({NumSnapToCallsThisRound}) - Canceled", "TP");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (GameStates.CurrentServerType != GameStates.ServerType.Vanilla)
|
||||
sendOption = SendOption.Reliable;
|
||||
|
||||
@@ -214,7 +220,7 @@ public static class Utils
|
||||
SubmergedCompatibility.CheckOutOfBoundsElevator(pc);
|
||||
}
|
||||
|
||||
if (sendOption == SendOption.Reliable) NumSnapToCallsThisRound++;
|
||||
NumSnapToCallsThisRound++;
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -2748,13 +2754,17 @@ public static class Utils
|
||||
if (!AmongUsClient.Instance.AmHost || GameStates.IsMeeting) yield break;
|
||||
|
||||
const int frameBudget = 3; // milliseconds per frame
|
||||
var stopwatch = new Stopwatch();
|
||||
var stopwatch = Stopwatch.StartNew();
|
||||
var aapc = Main.CachedAlivePlayerControls();
|
||||
var hasValue = false;
|
||||
var sender = CustomRpcSender.Create("NotifyRoles", sendOption, log: false);
|
||||
sender.StartPackedMessage();
|
||||
|
||||
for (int seerIndex = 0; seerIndex < aapc.Count; seerIndex++)
|
||||
{
|
||||
PlayerControl seer = aapc[seerIndex];
|
||||
NotifyRoles(SpecifySeer: seer, NoCache: noCache, SendOption: sendOption);
|
||||
hasValue |= WriteSetNameRpcsToSender(ref sender, false, noCache, false, false, false, false, seer, [seer], aapc, out bool senderWasCleared, sendOption);
|
||||
if (senderWasCleared) hasValue = false;
|
||||
|
||||
if (stopwatch.ElapsedMilliseconds >= frameBudget)
|
||||
{
|
||||
@@ -2764,6 +2774,8 @@ public static class Utils
|
||||
stopwatch.Start();
|
||||
}
|
||||
}
|
||||
|
||||
sender.SendMessage(!hasValue || sender.stream.Length <= 11);
|
||||
}
|
||||
|
||||
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||
@@ -2779,24 +2791,18 @@ public static class Utils
|
||||
SeerList = SpecifySeer ? [SpecifySeer] : apc;
|
||||
TargetList = SpecifyTarget ? [SpecifyTarget] : apc;
|
||||
|
||||
var sender = CustomRpcSender.Create("NotifyRoles", SendOption, log: false);
|
||||
var hasValue = false;
|
||||
var sender = CustomRpcSender.Create("NotifyRoles", SendOption, log: false);
|
||||
sender.StartPackedMessage();
|
||||
|
||||
for (byte seerIndex = 0; seerIndex < SeerList.Count; seerIndex++)
|
||||
{
|
||||
PlayerControl seer = SeerList[seerIndex];
|
||||
hasValue |= WriteSetNameRpcsToSender(ref sender, ForMeeting, NoCache, ForceLoop, CamouflageIsForMeeting, GuesserIsForMeeting, MushroomMixup, seer, SeerList, TargetList, out bool senderWasCleared, SendOption);
|
||||
if (senderWasCleared) hasValue = false;
|
||||
|
||||
if (sender.stream.Length > 500)
|
||||
{
|
||||
sender.SendMessage();
|
||||
sender = CustomRpcSender.Create("NotifyRoles", SendOption, log: false);
|
||||
hasValue = false;
|
||||
}
|
||||
}
|
||||
|
||||
sender.SendMessage(!hasValue || sender.stream.Length <= 3);
|
||||
sender.SendMessage(!hasValue || sender.stream.Length <= 11);
|
||||
|
||||
if (Options.CurrentGameMode != CustomGameMode.Standard) return;
|
||||
|
||||
@@ -2838,26 +2844,26 @@ public static class Utils
|
||||
var selfTeamName = $"<size=450%>{iconTextLeft} <font=\"VCR SDF\" material=\"VCR Black Outline\">{ColorString(seerTeam.GetColor(), $"{seerTeam}")}</font> {iconTextRight}</size><size=500%>\n \n</size>";
|
||||
selfName = $"{selfTeamName}\r\n<size=150%>{seerRole.ToColoredString()}</size>{roleNameUp}";
|
||||
|
||||
sender.RpcSetName(seer, selfName, seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, seer, selfName, seer);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (seer.Is(CustomRoles.Car) && !forMeeting && !GameStates.IsEnded)
|
||||
{
|
||||
sender.RpcSetName(seer, Car.Name);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, seer, Car.Name);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (Main.PlayerStates.TryGetValue(seer.PlayerId, out var seerState) && seerState.Role is Tree { TreeSpriteActive: true } && !forMeeting && !GameStates.IsEnded)
|
||||
{
|
||||
sender.RpcSetName(seer, Tree.Sprite);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, seer, Tree.Sprite);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (forMeeting && Magistrate.CallCourtNextMeeting)
|
||||
{
|
||||
selfName = seer.Is(CustomRoles.Magistrate) ? GetString("Magistrate.CourtName") : GetString("Magistrate.JuryName");
|
||||
sender.RpcSetName(seer, selfName);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, seer, selfName);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3183,7 +3189,7 @@ public static class Utils
|
||||
if (selfName.EndsWith("</size>")) selfName = selfName.Remove(selfName.Length - 7);
|
||||
if (selfName.EndsWith("</color>")) selfName = selfName.Remove(selfName.Length - 8);
|
||||
|
||||
sender.RpcSetName(seer, selfName, seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, seer, selfName, seer);
|
||||
hasValue = true;
|
||||
|
||||
bool onlySelfNameUpdateRequired = Options.CurrentGameMode switch
|
||||
@@ -3214,24 +3220,24 @@ public static class Utils
|
||||
if (target.PlayerId == seer.PlayerId) continue;
|
||||
|
||||
if ((IsActive(SystemTypes.MushroomMixupSabotage) || mushroomMixup) && !forMeeting && target.IsAlive() && !seer.Is(CustomRoleTypes.Impostor) && seer.HasDesyncRole())
|
||||
sender.RpcSetName(target, "<size=0%>", seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, target, "<size=0%>", seer);
|
||||
else
|
||||
{
|
||||
if (target.Is(CustomRoles.Car) && !forMeeting && !GameStates.IsEnded)
|
||||
{
|
||||
sender.RpcSetName(target, Car.Name, seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, target, Car.Name, seer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (Main.PlayerStates.TryGetValue(target.PlayerId, out var targetState) && targetState.Role is Tree { TreeSpriteActive: true } && !forMeeting && !GameStates.IsEnded)
|
||||
{
|
||||
sender.RpcSetName(target, Tree.Sprite, seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, target, Tree.Sprite, seer);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (forMeeting && Magistrate.CallCourtNextMeeting)
|
||||
{
|
||||
sender.RpcSetName(target, GetString(target.Is(CustomRoles.Magistrate) ? "Magistrate.CourtName" : "Magistrate.JuryName"), seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, target, GetString(target.Is(CustomRoles.Magistrate) ? "Magistrate.CourtName" : "Magistrate.JuryName"), seer);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -3500,17 +3506,9 @@ public static class Utils
|
||||
if (targetName.EndsWith("</size>")) targetName = targetName.Remove(targetName.Length - 7);
|
||||
if (targetName.EndsWith("</color>")) targetName = targetName.Remove(targetName.Length - 8);
|
||||
|
||||
sender.RpcSetName(target, targetName, seer);
|
||||
CustomRpcSenderExtensions.RpcSetName(ref sender, target, targetName, seer);
|
||||
hasValue = true;
|
||||
senderWasCleared = false;
|
||||
|
||||
if (sender.stream.Length > 500)
|
||||
{
|
||||
sender.SendMessage();
|
||||
sender = CustomRpcSender.Create(sender.name, sender.sendOption);
|
||||
hasValue = false;
|
||||
senderWasCleared = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
@@ -4153,7 +4151,7 @@ public static class Utils
|
||||
CustomRpcSender sender = CustomRpcSender.Create("Bloodlust fix", SendOption.Reliable);
|
||||
bool hasValue = false;
|
||||
hasValue |= sender.RpcSetRole(pc, RoleTypes.Impostor, pc.OwnerId);
|
||||
Main.EnumeratePlayerControls().DoIf(x => x.IsImpostor(), x => hasValue |= sender.RpcSetRole(x, RoleTypes.Crewmate, pc.OwnerId));
|
||||
Main.EnumerateAlivePlayerControls().DoIf(x => x.IsImpostor(), x => hasValue |= sender.RpcSetRole(x, RoleTypes.Crewmate, pc.OwnerId));
|
||||
sender.SendMessage(dispose: !hasValue);
|
||||
LateTask.New(() => pc.SetKillCooldown(), 0.2f, log: false);
|
||||
}
|
||||
@@ -5171,6 +5169,7 @@ public static class Utils
|
||||
|
||||
DataFlagRateLimiter.Enqueue(() =>
|
||||
{
|
||||
if (!deadBodyParent) return;
|
||||
CreateDeadBody(position, colorId, deadBodyParent);
|
||||
PlayerControl playerControl = Object.Instantiate(AmongUsClient.Instance.PlayerPrefab, Vector2.zero, Quaternion.identity);
|
||||
playerControl.PlayerId = deadBodyParent.PlayerId;
|
||||
|
||||
@@ -1252,28 +1252,29 @@ internal static class IntroCutsceneDestroyPatch
|
||||
{
|
||||
lp.Notify(GetString("GLHF"), 2f);
|
||||
|
||||
bool hasValue = false;
|
||||
var sender = CustomRpcSender.Create("Shapeshift After Pet Assign On Game Start", SendOption.Reliable);
|
||||
sender.StartPackedMessage();
|
||||
|
||||
foreach (PlayerControl pc in aapc)
|
||||
{
|
||||
if (pc.IsHost()) continue; // Skip the host
|
||||
if (pc.AmOwner) continue; // Skip the host
|
||||
|
||||
try
|
||||
{
|
||||
var sender = CustomRpcSender.Create("Shapeshift After Pet Assign On Game Start", SendOption.Reliable);
|
||||
|
||||
if (AmongUsClient.Instance.AmClient)
|
||||
pc.Shapeshift(pc, false);
|
||||
|
||||
sender.AutoStartRpc(pc.NetId, 46);
|
||||
sender.AutoStartRpc(pc.NetId, 46, pc.OwnerId);
|
||||
sender.WriteNetObject(pc);
|
||||
sender.Write(false);
|
||||
sender.EndRpc();
|
||||
|
||||
sender.Notify(pc, GetString("GLHF"), 2f);
|
||||
|
||||
sender.SendMessage();
|
||||
hasValue = true;
|
||||
}
|
||||
catch (Exception ex) { Logger.Fatal(ex.ToString(), "IntroPatch.RpcShapeshift"); }
|
||||
}
|
||||
|
||||
sender.SendMessage(dispose: !hasValue);
|
||||
}, 4f, "Show Pet For Everyone");
|
||||
|
||||
LateTask.New(() => Main.ProcessShapeshifts = true, 2f, "Enable SS Processing");
|
||||
|
||||
@@ -818,6 +818,7 @@ internal static class MeetingHudStartPatch
|
||||
{
|
||||
string playername = pc.GetRealName();
|
||||
if (Doppelganger.DoppelVictim.TryGetValue(pc.PlayerId, out string value)) playername = value;
|
||||
playername = Main.AllPlayerNames.GetValueOrDefault(pc.PlayerId, playername);
|
||||
|
||||
AddMsg(string.Format(GetString("SilencerDead"), playername, pc.PlayerId, CustomRoles.Silencer.ColoredTextByRole(GetString("SilencerKillTitle"))));
|
||||
}
|
||||
|
||||
@@ -377,6 +377,20 @@ internal static class ChangeRoleSettings
|
||||
{
|
||||
RPC.SyncCustomSettingsRPC();
|
||||
}
|
||||
else
|
||||
{
|
||||
CustomTeamManager.CustomTeams.Clear();
|
||||
CustomTeamManager.EnabledCustomTeams.Clear();
|
||||
CustomTeamManager.CustomTeamPlayerIds.Clear();
|
||||
CustomTeamManager.CustomTeamOptionsCache.Clear();
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Bloodlust] = [];
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Nimble] = [];
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Examiner] = [];
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Finder] = [];
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Physicist] = [];
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Noisy] = [];
|
||||
StartGameHostPatch.BasisChangingAddons[CustomRoles.Venom] = [];
|
||||
}
|
||||
|
||||
FallFromLadder.Reset();
|
||||
CustomSabotage.Reset();
|
||||
|
||||
@@ -32,12 +32,11 @@ internal static class LocalPetPatch
|
||||
|
||||
AFKDetector.SetNotAFK(__instance.PlayerId);
|
||||
|
||||
if (!LastProcess.ContainsKey(__instance.PlayerId)) LastProcess.TryAdd(__instance.PlayerId, Utils.TimeStamp - 2);
|
||||
LastProcess.TryAdd(__instance.PlayerId, Utils.TimeStamp - 2);
|
||||
if (LastProcess[__instance.PlayerId] + 1 >= Utils.TimeStamp) return true;
|
||||
|
||||
ExternalRpcPetPatch.Prefix(__instance.MyPhysics, (byte)RpcCalls.Pet);
|
||||
|
||||
LastProcess[__instance.PlayerId] = Utils.TimeStamp;
|
||||
return !Main.CancelPetAnimation.Value || !__instance.GetCustomRole().PetActivatedAbility();
|
||||
}
|
||||
|
||||
@@ -68,6 +67,10 @@ internal static class ExternalRpcPetPatch
|
||||
|
||||
AFKDetector.SetNotAFK(pc.PlayerId);
|
||||
|
||||
LastProcess.TryAdd(pc.PlayerId, Utils.TimeStamp - 2);
|
||||
if (LastProcess[pc.PlayerId] + 1 >= Utils.TimeStamp) return;
|
||||
LastProcess[pc.PlayerId] = Utils.TimeStamp;
|
||||
|
||||
if (!pc.inVent
|
||||
&& !pc.inMovingPlat
|
||||
&& !pc.walkingToVent
|
||||
@@ -89,11 +92,6 @@ internal static class ExternalRpcPetPatch
|
||||
}
|
||||
}
|
||||
|
||||
if (!LastProcess.ContainsKey(pc.PlayerId)) LastProcess.TryAdd(pc.PlayerId, Utils.TimeStamp - 2);
|
||||
if (LastProcess[pc.PlayerId] + 1 >= Utils.TimeStamp) return;
|
||||
|
||||
LastProcess[pc.PlayerId] = Utils.TimeStamp;
|
||||
|
||||
Logger.Info($"Player {pc.GetNameWithRole().RemoveHtmlTags()} petted their pet", "PetActionTrigger");
|
||||
|
||||
LateTask.New(() => OnPetUse(pc), 0.2f, $"OnPetUse: {pc.GetNameWithRole().RemoveHtmlTags()}", false);
|
||||
|
||||
@@ -1037,8 +1037,12 @@ internal static class ReportDeadBodyPatch
|
||||
|
||||
Logger.Info($"{__instance.GetNameWithRole().RemoveHtmlTags()} => {target?.Object?.GetNameWithRole() ?? "null"}", "ReportDeadBody");
|
||||
|
||||
foreach (KeyValuePair<byte, PlayerState> kvp in Main.PlayerStates)
|
||||
kvp.Value.LastRoom = GetPlayerById(kvp.Key).GetPlainShipRoom();
|
||||
try
|
||||
{
|
||||
foreach (KeyValuePair<byte, PlayerState> kvp in Main.PlayerStates)
|
||||
kvp.Value.LastRoom = GetPlayerById(kvp.Key)?.GetPlainShipRoom();
|
||||
}
|
||||
catch (Exception e) { ThrowException(e); }
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost) return true;
|
||||
|
||||
@@ -1639,6 +1643,9 @@ internal static class FixedUpdatePatch
|
||||
|
||||
if (self)
|
||||
{
|
||||
if (NumSnapToCallsThisRound > 80)
|
||||
NumSnapToCallsThisRound = 80;
|
||||
|
||||
Zoom.OnFixedUpdate();
|
||||
TextBoxPatch.CheckChatOpen();
|
||||
|
||||
@@ -2391,26 +2398,29 @@ internal static class GameDataCompleteTaskPatch
|
||||
|
||||
public static void Postfix(PlayerControl pc, uint taskId)
|
||||
{
|
||||
if (MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) return;
|
||||
|
||||
if (Options.CurrentGameMode == CustomGameMode.HideAndSeek && CustomHnS.PlayerRoles[pc.PlayerId].Interface.Team == Team.Crewmate && pc.IsAlive())
|
||||
{
|
||||
var task = pc.myTasks.Find((Il2CppSystem.Predicate<PlayerTask>)(x => taskId == x.Id));
|
||||
Hider.OnSpecificTaskComplete(pc, task);
|
||||
}
|
||||
|
||||
try
|
||||
{
|
||||
if (MeetingHud.Instance && MeetingHud.Instance.state != MeetingHud.VoteStates.Animating) return;
|
||||
|
||||
if (Options.CurrentGameMode == CustomGameMode.HideAndSeek && CustomHnS.PlayerRoles[pc.PlayerId].Interface.Team == Team.Crewmate && pc.IsAlive())
|
||||
{
|
||||
var task = pc.myTasks.Find((Il2CppSystem.Predicate<PlayerTask>)(x => taskId == x.Id));
|
||||
Hider.OnSpecificTaskComplete(pc, task);
|
||||
}
|
||||
|
||||
|
||||
if (pc.IsAlive())
|
||||
{
|
||||
var task = pc.myTasks.Find((Il2CppSystem.Predicate<PlayerTask>)(x => taskId == x.Id));
|
||||
Benefactor.OnTaskComplete(pc, task);
|
||||
}
|
||||
|
||||
Logger.Info($"TaskComplete: {pc.GetNameWithRole().RemoveHtmlTags()}", "CompleteTask");
|
||||
}
|
||||
catch (Exception e) { ThrowException(e); }
|
||||
|
||||
Logger.Info($"TaskComplete: {pc.GetNameWithRole().RemoveHtmlTags()}", "CompleteTask");
|
||||
|
||||
Main.PlayerStates[pc.PlayerId].UpdateTask(pc);
|
||||
|
||||
NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
GameEndChecker.SetDirtyCheckEnd();
|
||||
}
|
||||
|
||||
@@ -287,7 +287,7 @@ public static class ElectricTaskInitializePatch
|
||||
foreach (PlayerControl pc in Main.CachedAlivePlayerControls())
|
||||
{
|
||||
if (pc.GetCustomRole().NeedUpdateOnLights() || pc.Is(CustomRoles.Torch) || pc.Is(CustomRoles.Sleep) || Beacon.IsAffectedPlayer(pc.PlayerId))
|
||||
Utils.NotifyRoles(SpecifyTarget: pc, ForceLoop: true, SendOption: SendOption.None);
|
||||
Utils.NotifyRoles(SpecifyTarget: pc, SendOption: SendOption.None);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -313,7 +313,7 @@ public static class ElectricTaskCompletePatch
|
||||
CustomRoles role = pc.GetCustomRole();
|
||||
|
||||
if (role.NeedUpdateOnLights() || pc.Is(CustomRoles.Torch) || pc.Is(CustomRoles.Sleep) || Beacon.IsAffectedPlayer(pc.PlayerId))
|
||||
Utils.NotifyRoles(SpecifyTarget: pc, ForceLoop: true, SendOption: SendOption.None);
|
||||
Utils.NotifyRoles(SpecifyTarget: pc, SendOption: SendOption.None);
|
||||
|
||||
if (role == CustomRoles.Wiper)
|
||||
{
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using static EHR.Options;
|
||||
@@ -79,32 +80,30 @@ public class Workhorse : IAddon
|
||||
return canBeTarget;
|
||||
}
|
||||
|
||||
public static bool OnCompleteTask(PlayerControl pc)
|
||||
public static void OnCompleteTask(PlayerControl pc)
|
||||
{
|
||||
if (!CustomRoles.Workhorse.IsEnable() || PlayerIdList.Count >= CustomRoles.Workhorse.GetCount()) return false;
|
||||
|
||||
if (CurrentGameMode != CustomGameMode.Standard) return false;
|
||||
|
||||
if (pc.Is(CustomRoles.Snitch) && !OptionSnitchCanBeWorkhorse.GetBool()) return false;
|
||||
|
||||
if (!IsAssignTarget(pc)) return false;
|
||||
|
||||
if (IRandom.Instance.Next(100) >= SpawnChance.GetInt()) return false;
|
||||
|
||||
pc.RpcSetCustomRole(CustomRoles.Workhorse);
|
||||
TaskState taskState = pc.GetTaskState();
|
||||
taskState.AllTasksCount += NumLongTasks + NumShortTasks;
|
||||
taskState.CompletedTasksCount++;
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
try
|
||||
{
|
||||
Add(pc.PlayerId);
|
||||
pc.RpcResetTasks(false);
|
||||
pc.SyncSettings();
|
||||
Main.PlayerStates[pc.PlayerId].TaskState.AllTasksCount = pc.Data.Tasks.Count;
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
}
|
||||
if (!CustomRoles.Workhorse.IsEnable() || PlayerIdList.Count >= CustomRoles.Workhorse.GetCount()) return;
|
||||
if (CurrentGameMode != CustomGameMode.Standard) return;
|
||||
if (pc.Is(CustomRoles.Snitch) && !OptionSnitchCanBeWorkhorse.GetBool()) return;
|
||||
if (!IsAssignTarget(pc)) return;
|
||||
if (IRandom.Instance.Next(100) >= SpawnChance.GetInt()) return;
|
||||
|
||||
return true;
|
||||
pc.RpcSetCustomRole(CustomRoles.Workhorse);
|
||||
TaskState taskState = pc.GetTaskState();
|
||||
taskState.AllTasksCount += NumLongTasks + NumShortTasks;
|
||||
taskState.CompletedTasksCount++;
|
||||
|
||||
if (AmongUsClient.Instance.AmHost)
|
||||
{
|
||||
Add(pc.PlayerId);
|
||||
pc.RpcResetTasks(false);
|
||||
pc.SyncSettings();
|
||||
Main.PlayerStates[pc.PlayerId].TaskState.AllTasksCount = pc.Data.Tasks.Count;
|
||||
Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
}
|
||||
}
|
||||
catch (System.Exception e) { Utils.ThrowException(e); }
|
||||
}
|
||||
}
|
||||
@@ -40,7 +40,7 @@ internal class Rabbit : RoleBase
|
||||
RabbitStates.Remove(playerId);
|
||||
}
|
||||
|
||||
public static void ReceiveRPC(MessageReader reader)
|
||||
public static void ReceiveRPCStatic(MessageReader reader)
|
||||
{
|
||||
byte id = reader.ReadByte();
|
||||
bool hasArrow = reader.ReadBoolean();
|
||||
@@ -49,14 +49,14 @@ internal class Rabbit : RoleBase
|
||||
|
||||
public override void OnTaskComplete(PlayerControl pc, int completedTaskCount, int totalTaskCount)
|
||||
{
|
||||
if (pc == null || !RabbitStates.TryGetValue(pc.PlayerId, out RabbitState state)) return;
|
||||
if (!RabbitStates.TryGetValue(pc.PlayerId, out RabbitState state)) return;
|
||||
|
||||
state.OnTaskComplete();
|
||||
}
|
||||
|
||||
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
|
||||
{
|
||||
if (seer == null || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || !RabbitStates.TryGetValue(seer.PlayerId, out RabbitState state)) return string.Empty;
|
||||
if (seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || !RabbitStates.TryGetValue(seer.PlayerId, out RabbitState state)) return string.Empty;
|
||||
|
||||
string suffix = state.Suffix;
|
||||
return hud ? $"<size=200%>{suffix}</size>" : suffix;
|
||||
|
||||
@@ -58,7 +58,8 @@ public class Carrier : RoleBase
|
||||
|
||||
public override bool OnShapeshift(PlayerControl shapeshifter, PlayerControl target, bool shapeshifting)
|
||||
{
|
||||
if (!shapeshifting || !Location.HasValue) return true;
|
||||
if (!shapeshifting) return true;
|
||||
if (!Location.HasValue) return false;
|
||||
target.TP(Location.Value);
|
||||
target.Notify(Translator.GetString("Carrier.TargetNotify"));
|
||||
return false;
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using static EHR.Options;
|
||||
@@ -11,7 +10,6 @@ public class DonutDelivery : RoleBase
|
||||
{
|
||||
private const int Id = 642700;
|
||||
private static List<DonutDelivery> Instances = [];
|
||||
private static Dictionary<byte, float> StartingSpeed = [];
|
||||
|
||||
private static OptionItem CD;
|
||||
private static OptionItem UseLimit;
|
||||
@@ -66,7 +64,6 @@ public class DonutDelivery : RoleBase
|
||||
public override void Init()
|
||||
{
|
||||
Instances = [];
|
||||
StartingSpeed = Main.AllPlayerSpeed.ToDictionary(x => x.Key, x => x.Value);
|
||||
}
|
||||
|
||||
public override void Add(byte playerId)
|
||||
@@ -99,7 +96,7 @@ public class DonutDelivery : RoleBase
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (!IsEnable || killer == null || target == null || killer.GetAbilityUseLimit() <= 0) return false;
|
||||
if (!IsEnable) return false;
|
||||
|
||||
killer.RpcRemoveAbilityUse();
|
||||
|
||||
@@ -123,7 +120,7 @@ public class DonutDelivery : RoleBase
|
||||
|
||||
LateTask.New(() =>
|
||||
{
|
||||
Main.AllPlayerSpeed[target.PlayerId] = StartingSpeed[target.PlayerId];
|
||||
Main.AllPlayerSpeed[target.PlayerId] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
||||
target.MarkDirtySettings();
|
||||
}, SEDuration.GetFloat(), log: false);
|
||||
}, SEDelay.GetFloat(), log: false);
|
||||
|
||||
@@ -131,27 +131,31 @@ internal class TimeMaster : RoleBase
|
||||
|
||||
private static IEnumerator Rewind()
|
||||
{
|
||||
const float delay = 0.3f;
|
||||
long now = Utils.TimeStamp;
|
||||
int length = TimeMasterRewindTimeLength.GetInt();
|
||||
|
||||
Dictionary<byte, float> originalSpeeds = Main.AllPlayerSpeed.ToDictionary(x => x.Key, x => x.Value);
|
||||
Main.AllPlayerSpeed.SetAllValues(Main.MinSpeed);
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(false);
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
Rewinding = true;
|
||||
|
||||
const float delay = 0.3f;
|
||||
long now = Utils.TimeStamp;
|
||||
int length = TimeMasterRewindTimeLength.GetInt();
|
||||
float duration = length * delay + 0.55f;
|
||||
|
||||
Main.AllPlayerSpeed.SetAllValues(Main.MinSpeed);
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(false);
|
||||
|
||||
string notify = Utils.ColorString(Color.yellow, string.Format(Translator.GetString("TimeMasterRewindStart"), CustomRoles.TimeMaster.ToColoredString()));
|
||||
|
||||
foreach (PlayerControl player in Main.EnumeratePlayerControls())
|
||||
{
|
||||
if (player.inVent || player.MyPhysics?.Animations?.IsPlayingEnterVentAnimation() == true) player.MyPhysics?.RpcExitVent(player.GetClosestVent().Id);
|
||||
player.ReactorFlash(flashDuration: length * delay + 0.55f);
|
||||
player.Notify(notify, Math.Max((length * delay) + 0.55f, 4f));
|
||||
player.ReactorFlash(flashDuration: duration);
|
||||
player.Notify(notify, Math.Max(duration, 4f));
|
||||
player.MarkDirtySettings();
|
||||
}
|
||||
|
||||
yield return PlayerGameOptionsSender.SendAllImmediately().Wait();
|
||||
|
||||
yield return new WaitForSecondsRealtime(0.55f);
|
||||
|
||||
@@ -196,21 +200,29 @@ internal class TimeMaster : RoleBase
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
finally
|
||||
{
|
||||
Rewinding = false;
|
||||
Main.AllPlayerSpeed = originalSpeeds;
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
Main.AllPlayerSpeed.AddRange(originalSpeeds);
|
||||
Utils.MarkEveryoneDirtySettings();
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
AfterMeetingTasks();
|
||||
}
|
||||
|
||||
public override void AfterMeetingTasks()
|
||||
{
|
||||
Rewinding = false;
|
||||
if (Rewinding)
|
||||
{
|
||||
Rewinding = false;
|
||||
Main.AllPlayerSpeed.SetAllValues(Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod));
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnFixedUpdate(PlayerControl player)
|
||||
|
||||
@@ -82,7 +82,7 @@ internal class Bloodmoon : IGhostRole
|
||||
if (pc.RpcCheckAndMurder(player, true)) player.Suicide(PlayerState.DeathReason.LossOfBlood, pc);
|
||||
}
|
||||
|
||||
var alivePlayers = Main.CachedAlivePlayerControls();
|
||||
/*var alivePlayers = Main.CachedAlivePlayerControls();
|
||||
for (int index = 0; index < alivePlayers.Count; index++)
|
||||
{
|
||||
PlayerControl target = alivePlayers[index];
|
||||
@@ -90,7 +90,7 @@ internal class Bloodmoon : IGhostRole
|
||||
if (!FastVector2.DistanceWithinRange(target.Pos(), pc.Pos(), 4f)) continue;
|
||||
|
||||
target.Notify(string.Format(Translator.GetString("BloodmoonNearYou"), CustomRoles.Bloodmoon.ToColoredString()), sendOption: SendOption.None);
|
||||
}
|
||||
}*/
|
||||
}
|
||||
|
||||
public static void OnMeetingStart()
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
@@ -16,13 +17,12 @@ public class Penguin : RoleBase
|
||||
private static OptionItem OptionSpeedDuringDrag;
|
||||
private static OptionItem OptionVictimCanUseAbilities;
|
||||
|
||||
private float AbductTimer;
|
||||
private Stopwatch AbductTimer;
|
||||
private float AbductTimerLimit;
|
||||
|
||||
private PlayerControl AbductVictim;
|
||||
private float Cooldown;
|
||||
|
||||
private int Count;
|
||||
private float DefaultSpeed;
|
||||
|
||||
private bool IsGoose;
|
||||
@@ -33,7 +33,6 @@ public class Penguin : RoleBase
|
||||
private byte PenguinId = byte.MaxValue;
|
||||
private float SpeedDuringDrag;
|
||||
|
||||
private bool stopCount;
|
||||
private bool VictimCanUseAbilities;
|
||||
|
||||
public override bool IsEnable => PenguinId != byte.MaxValue;
|
||||
@@ -101,8 +100,7 @@ public class Penguin : RoleBase
|
||||
PenguinId = playerId;
|
||||
Penguin_ = Utils.GetPlayerById(playerId);
|
||||
|
||||
AbductTimer = 255f;
|
||||
stopCount = false;
|
||||
AbductTimer = null;
|
||||
LastNotify = 0;
|
||||
}
|
||||
|
||||
@@ -142,23 +140,25 @@ public class Penguin : RoleBase
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public void ReceiveRPC(byte victim)
|
||||
public void ReceiveRPCVictim(byte victim)
|
||||
{
|
||||
if (victim == 255)
|
||||
{
|
||||
AbductVictim = null;
|
||||
AbductTimer = 255f;
|
||||
AbductTimer = null;
|
||||
Utils.SendRPC(CustomRPC.PenguinSync, PenguinId, 2, true);
|
||||
}
|
||||
else
|
||||
{
|
||||
AbductVictim = Utils.GetPlayerById(victim);
|
||||
AbductTimer = AbductTimerLimit;
|
||||
AbductTimer = Stopwatch.StartNew();
|
||||
Utils.SendRPC(CustomRPC.PenguinSync, PenguinId, 2, false);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveRPC(float timer)
|
||||
public void ReceiveRPCTimer(bool reset)
|
||||
{
|
||||
AbductTimer = timer;
|
||||
AbductTimer = reset ? null : Stopwatch.StartNew();
|
||||
}
|
||||
|
||||
private void AddVictim(PlayerControl target)
|
||||
@@ -168,7 +168,8 @@ public class Penguin : RoleBase
|
||||
if (Thanos.IsImmune(target)) return;
|
||||
|
||||
AbductVictim = target;
|
||||
AbductTimer = AbductTimerLimit;
|
||||
AbductTimer = Stopwatch.StartNew();
|
||||
Utils.SendRPC(CustomRPC.PenguinSync, PenguinId, 2, false);
|
||||
Main.AllPlayerSpeed[PenguinId] = SpeedDuringDrag;
|
||||
Penguin_.MarkDirtySettings();
|
||||
LogSpeed();
|
||||
@@ -209,7 +210,8 @@ public class Penguin : RoleBase
|
||||
}, 1f, log: false);
|
||||
}
|
||||
|
||||
AbductTimer = 255f;
|
||||
AbductTimer = null;
|
||||
Utils.SendRPC(CustomRPC.PenguinSync, PenguinId, 2, true);
|
||||
Main.AllPlayerSpeed[PenguinId] = DefaultSpeed;
|
||||
Penguin_.MarkDirtySettings();
|
||||
LogSpeed();
|
||||
@@ -268,8 +270,6 @@ public class Penguin : RoleBase
|
||||
{
|
||||
if (!IsEnable) return;
|
||||
|
||||
stopCount = true;
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
if (!AbductVictim) return;
|
||||
|
||||
@@ -301,31 +301,12 @@ public class Penguin : RoleBase
|
||||
if (!IsEnable) return;
|
||||
|
||||
if (AbductVictim) Penguin_.MarkDirtySettings();
|
||||
|
||||
stopCount = false;
|
||||
}
|
||||
|
||||
public override void OnFixedUpdate(PlayerControl pc)
|
||||
{
|
||||
if (!IsEnable) return;
|
||||
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
|
||||
if (!GameStates.IsInTask) return;
|
||||
|
||||
if (!stopCount)
|
||||
{
|
||||
AbductTimer -= Time.fixedDeltaTime;
|
||||
|
||||
Count++;
|
||||
|
||||
if (Count >= 30)
|
||||
{
|
||||
Count = 0;
|
||||
Utils.SendRPC(CustomRPC.PenguinSync, PenguinId, 2, AbductTimer);
|
||||
}
|
||||
}
|
||||
|
||||
if (AbductVictim)
|
||||
{
|
||||
if (!Penguin_.IsAlive() || Pelican.IsEaten(PenguinId) || !AbductVictim.IsAlive())
|
||||
@@ -340,7 +321,7 @@ public class Penguin : RoleBase
|
||||
LastNotify = Utils.TimeStamp;
|
||||
}
|
||||
|
||||
if (AbductTimer <= 0f && !Penguin_.MyPhysics.Animations.IsPlayingAnyLadderAnimation() && !Penguin_.inMovingPlat && !Penguin_.onLadder)
|
||||
if (AbductTimer.Elapsed.TotalSeconds >= AbductTimerLimit && !Penguin_.MyPhysics.Animations.IsPlayingAnyLadderAnimation() && !Penguin_.inMovingPlat && !Penguin_.onLadder)
|
||||
{
|
||||
// Set IsDead to true first (prevents ladder chase)
|
||||
if (!IsGoose)
|
||||
@@ -395,17 +376,21 @@ public class Penguin : RoleBase
|
||||
{
|
||||
LateTask.New(() =>
|
||||
{
|
||||
if (AbductVictim != null) Utils.TP(AbductVictim.NetTransform, position, log: false);
|
||||
if (AbductVictim) Utils.TP(AbductVictim.NetTransform, position, log: false);
|
||||
}, 0.25f, log: false);
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (AbductTimer <= 100f) AbductTimer = 255f;
|
||||
else
|
||||
{
|
||||
AbductTimer = null;
|
||||
Utils.SendRPC(CustomRPC.PenguinSync, PenguinId, 2, true);
|
||||
}
|
||||
}
|
||||
|
||||
public override string GetSuffix(PlayerControl seer, PlayerControl target, bool hud = false, bool meeting = false)
|
||||
{
|
||||
if (seer == null || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || !Main.PlayerStates.TryGetValue(seer.PlayerId, out PlayerState state) || state.Role is not Penguin pg || pg.AbductVictim == null) return string.Empty;
|
||||
return $"\u21b9 {(int)(pg.AbductTimer + 1f)}s";
|
||||
if (seer.PlayerId != PenguinId || seer.PlayerId != target.PlayerId || (seer.IsModdedClient() && !hud) || AbductTimer == null) return string.Empty;
|
||||
return $"\u21b9 {(int)(AbductTimerLimit - AbductTimer.Elapsed.TotalSeconds + 1f)}s";
|
||||
}
|
||||
}
|
||||
@@ -128,7 +128,7 @@ public class Stasis : RoleBase
|
||||
}
|
||||
}
|
||||
|
||||
Utils.MarkEveryoneDirtySettings();
|
||||
Utils.SyncAllSettings();
|
||||
Main.Instance.StartCoroutine(Countdown());
|
||||
return;
|
||||
|
||||
@@ -150,11 +150,26 @@ public class Stasis : RoleBase
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
Main.AllPlayerSpeed = originalSpeeds;
|
||||
Main.AllPlayerSpeed.AddRange(originalSpeeds);
|
||||
Main.PlayerStates.Values.Do(x => x.IsBlackOut = false);
|
||||
Utils.MarkEveryoneDirtySettings();
|
||||
|
||||
pc.RpcResetAbilityCooldown();
|
||||
}
|
||||
}
|
||||
|
||||
public override void OnReportDeadBody()
|
||||
{
|
||||
if (UsingAbility)
|
||||
{
|
||||
UsingAbility = false;
|
||||
ReportDeadBodyPatch.CanReport.SetAllValues(true);
|
||||
Main.AllPlayerSpeed.SetAllValues(Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod));
|
||||
}
|
||||
}
|
||||
|
||||
public override void AfterMeetingTasks()
|
||||
{
|
||||
OnReportDeadBody();
|
||||
}
|
||||
}
|
||||
@@ -82,7 +82,7 @@ public class BountyHunter : RoleBase
|
||||
AmongUsClient.Instance.FinishRpcImmediately(writer);
|
||||
}
|
||||
|
||||
public void ReceiveRPC(byte targetId)
|
||||
public void ReceiveRPCTarget(byte targetId)
|
||||
{
|
||||
Target = targetId;
|
||||
}
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
|
||||
namespace EHR.Roles;
|
||||
|
||||
@@ -70,7 +71,6 @@ internal class Butcher : RoleBase
|
||||
RPCHandlerPatch.WhiteListFromRateLimitUntil(target.PlayerId, Utils.TimeStamp + 5);
|
||||
|
||||
Vector2 ops = target.Pos();
|
||||
Vector2 originPos = killer.Pos();
|
||||
var rd = IRandom.Instance;
|
||||
|
||||
Main.Instance.StartCoroutine(SpawnFakeDeadBodies());
|
||||
@@ -85,15 +85,12 @@ internal class Butcher : RoleBase
|
||||
|
||||
Utils.RpcCreateDeadBody(location, (byte)target.CurrentOutfit.ColorId, target, SendOption.None);
|
||||
|
||||
if (i % 4 == 0) yield return null;
|
||||
yield return new WaitForSecondsRealtime(0.2f);
|
||||
}
|
||||
|
||||
yield return null;
|
||||
killer.TP(originPos);
|
||||
}
|
||||
}, 0.05f, "Butcher Murder");
|
||||
}
|
||||
|
||||
return base.OnCheckMurder(killer, target);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using static EHR.Options;
|
||||
|
||||
namespace EHR.Roles;
|
||||
@@ -51,10 +52,11 @@ internal class Capitalist : RoleBase
|
||||
});
|
||||
}
|
||||
|
||||
public static bool AddTaskForPlayer(PlayerControl player)
|
||||
public static void AddTaskForPlayer(PlayerControl player)
|
||||
{
|
||||
if (CapitalistAddTask.TryGetValue(player.PlayerId, out int amount))
|
||||
try
|
||||
{
|
||||
if (!CapitalistAddTask.TryGetValue(player.PlayerId, out int amount)) return;
|
||||
TaskState taskState = player.GetTaskState();
|
||||
taskState.AllTasksCount += amount;
|
||||
CapitalistAddTask.Remove(player.PlayerId);
|
||||
@@ -63,9 +65,7 @@ internal class Capitalist : RoleBase
|
||||
player.SyncSettings();
|
||||
Main.PlayerStates[player.PlayerId].TaskState.AllTasksCount = player.Data.Tasks.Count;
|
||||
Utils.NotifyRoles(SpecifySeer: player, SpecifyTarget: player);
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
catch (Exception e) { Utils.ThrowException(e); }
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Linq;
|
||||
using AmongUs.GameOptions;
|
||||
using EHR.Modules;
|
||||
using Hazel;
|
||||
using UnityEngine;
|
||||
using static EHR.Options;
|
||||
|
||||
@@ -36,8 +37,9 @@ internal class Vector : RoleBase
|
||||
public override void Add(byte playerId)
|
||||
{
|
||||
On = true;
|
||||
VectorVentCount[playerId] = 0;
|
||||
VectorVentNumWin = MapWinCounts[SubmergedCompatibility.IsSubmerged() ? MapNames.Airship : Main.CurrentMap].GetInt();
|
||||
if (!AmongUsClient.Instance.AmHost) return;
|
||||
VectorVentNumWin = MapWinCounts[SubmergedCompatibility.IsSubmerged() || Main.LIMap ? MapNames.Airship : Main.CurrentMap].GetInt();
|
||||
LateTask.New(() => Utils.SendRPC(CustomRPC.SyncRoleData, playerId, VectorVentNumWin), 8f);
|
||||
}
|
||||
|
||||
public override void Init()
|
||||
@@ -71,7 +73,7 @@ internal class Vector : RoleBase
|
||||
{
|
||||
VectorVentCount.TryAdd(pc.PlayerId, 0);
|
||||
VectorVentCount[pc.PlayerId]++;
|
||||
if (!pc.IsModdedClient()) Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc);
|
||||
if (!pc.IsModdedClient()) Utils.NotifyRoles(SpecifySeer: pc, SpecifyTarget: pc, SendOption: SendOption.None);
|
||||
if (pc.AmOwner) CustomSoundsManager.Play("MarioJump");
|
||||
|
||||
if (AmongUsClient.Instance.AmHost && VectorVentCount[pc.PlayerId] >= VectorVentNumWin)
|
||||
@@ -81,4 +83,9 @@ internal class Vector : RoleBase
|
||||
CustomWinnerHolder.WinnerIds.Add(pc.PlayerId);
|
||||
}
|
||||
}
|
||||
|
||||
public void ReceiveRPC(MessageReader reader)
|
||||
{
|
||||
VectorVentNumWin = reader.ReadPackedInt32();
|
||||
}
|
||||
}
|
||||
@@ -69,13 +69,16 @@ internal class Workaholic : RoleBase
|
||||
Main.AllPlayerSpeed[playerId] = WorkaholicSpeed.GetFloat();
|
||||
}
|
||||
|
||||
public override void OnTaskComplete(PlayerControl player, int CompletedTasksCount, int AllTasksCount)
|
||||
public override void OnTaskComplete(PlayerControl player, int completedTasksCount, int allTasksCount)
|
||||
{
|
||||
if (CompletedTasksCount + 1 >= AllTasksCount && (!WorkaholicCannotWinAtDeath.GetBool() || player.IsAlive()))
|
||||
if (completedTasksCount + 1 >= allTasksCount && (!WorkaholicCannotWinAtDeath.GetBool() || player.IsAlive()))
|
||||
{
|
||||
Logger.Info("Workaholic Tasks Finished", "Workaholic");
|
||||
RPC.PlaySoundRPC(player.PlayerId, Sounds.KillSound);
|
||||
|
||||
GameEndChecker.ShouldNotCheck = true;
|
||||
LateTask.New(() => GameEndChecker.ShouldNotCheck = false, 0.2f);
|
||||
|
||||
foreach (PlayerControl pc in Main.EnumerateAlivePlayerControls())
|
||||
pc.Suicide(pc.PlayerId == player.PlayerId ? PlayerState.DeathReason.Overtired : PlayerState.DeathReason.Ashamed, player);
|
||||
|
||||
|
||||
@@ -121,12 +121,9 @@ public class Pelican : RoleBase
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool CanEat(PlayerControl pc, byte id)
|
||||
public static bool CanEat(PlayerControl target)
|
||||
{
|
||||
if (!pc.Is(CustomRoles.Pelican) || GameStates.IsMeeting) return false;
|
||||
|
||||
PlayerControl target = Utils.GetPlayerById(id);
|
||||
return target.IsAlive() && !target.inVent && !Medic.ProtectList.Contains(target.PlayerId) && !target.Is(CustomRoles.GM) && !target.Is(CustomRoles.Pestilence) && !IsEaten(pc, id) && !IsEaten(id);
|
||||
return !Medic.ProtectList.Contains(target.PlayerId) && !target.Is(CustomRoles.GM) && !target.Is(CustomRoles.Pestilence) && (!target.Is(CustomRoles.Guardian) || !target.AllTasksCompleted()) && !IsEaten(target.PlayerId);
|
||||
}
|
||||
|
||||
public static Vector2 GetBlackRoomPS()
|
||||
@@ -147,7 +144,7 @@ public class Pelican : RoleBase
|
||||
public override void GetProgressText(byte playerId, bool comms, StringBuilder resultText)
|
||||
{
|
||||
PlayerControl player = Utils.GetPlayerById(playerId);
|
||||
if (player == null)
|
||||
if (!player)
|
||||
{
|
||||
resultText.Append("Invalid");
|
||||
return;
|
||||
@@ -163,9 +160,9 @@ public class Pelican : RoleBase
|
||||
.Append(")</color>");
|
||||
}
|
||||
|
||||
public static void EatPlayer(PlayerControl pc, PlayerControl target)
|
||||
private static void EatPlayer(PlayerControl pc, PlayerControl target)
|
||||
{
|
||||
if (pc == null || target == null || !CanEat(pc, target.PlayerId)) return;
|
||||
if (!pc || !target) return;
|
||||
|
||||
if (!EatenList.ContainsKey(pc.PlayerId)) EatenList.Add(pc.PlayerId, []);
|
||||
|
||||
@@ -217,7 +214,7 @@ public class Pelican : RoleBase
|
||||
{
|
||||
PlayerControl target = Utils.GetPlayerById(tar);
|
||||
PlayerControl player = Utils.GetPlayerById(pc);
|
||||
if (player == null || target == null) continue;
|
||||
if (!player || !target) continue;
|
||||
|
||||
target.TP(player);
|
||||
Main.AllPlayerSpeed[tar] = Main.RealOptionsData.GetFloat(FloatOptionNames.PlayerSpeedMod);
|
||||
@@ -259,7 +256,7 @@ public class Pelican : RoleBase
|
||||
|
||||
public override bool OnCheckMurder(PlayerControl killer, PlayerControl target)
|
||||
{
|
||||
if (CanEat(killer, target.PlayerId))
|
||||
if (CanEat(target))
|
||||
{
|
||||
EatPlayer(killer, target);
|
||||
killer.SetKillCooldown();
|
||||
|
||||
Reference in new issue
Block a user