changelog

This commit is contained in:
Gurge44 committed 2026-04-09 09:55:06 +02:00
1 parent 6f9b77fc01
commit 778c8efbc1
7 files changed
+26 -76

No files matched your search

+12 -62
View File
@@ -1,67 +1,17 @@
# Thank you so much for finding and using EHR!
> [!INFO]
> Updated to Among Us v2026.3.31 (v17.3)
> [!CAUTION]
> **Due to an issue on InnerSloth's servers, players (even unmodded ones) get banned after completing a visual task. Please disable Visual Tasks to avoid this issue.** We've talked to InnerSloth about this, and they've said they're working on the fix.
> [!WARNING]
> **Use commands with a `/cmd ` prefix, otherwise your message gets leaked.** So if you were to type `/bt 4 snitch`, you would now type `/cmd bt 4 snitch`. The system will NOT spam the chat after command usage even if it would be required.
## Bug Fixes
- Fixed Custom Hide And Seek errors when the host uses /setrole with an unavailable role
- Fixed Mingle ending during killing process
- Fixed disasters spawning while some players still see the ejection screen in Natural Disasters
- Fixed sinkholes not being despawned properly in Natural Disasters when the disaster limit specified in settings is reached
- Fixed players getting stuck inside collapsed buildings in Natural Disasters
- Fixed Sprayer, Catcher CNOs not disappearing after meetings
- Fixed Skeld/Dleks Electrical bounds overlapping Storage's colliders
- Fixed after-death actions not being triggered after guesses if the game instantly ends due to it
- Fixed shapeshift-related issues (by TommyXL)
- Fixed april fools stuff (by TommyXL)
- Fixed host's messages not being logged (for chat spam & chat during game notifies)
- GM and Specators cannot be summoned by Summoner
- Fixed Hacker consuming ability uses when looking at physical admin map
- Fixed memory leak
- Medic's tasks don't reset if it uses the pet button as the kill button (by Hyper)
- Time Master & Stasis now reset player speeds to their original values instead of the global value
- Bloodmoon now always gives Loss Of Blood as the death reason
## Changes
- **More compatibility with Starlight** (should be stable at this point)
- Player points are counted individually in King Of The Zones (by Zypherus)
- Optimized Natural Disasters: Suffix cache & saved about 3/4 of all RPCs sent
- Reduced Snowdown vanish cooldown from 2s to 1s
- Reduced network pressure in Solo PVP
- Missing 'Notification' template no longer sends an error message
- Snowdown auto enables pet use, just like Bed Wars
- Many more small improvements
### Template System Overhaul (by Zypherus)
- `/t` with no args → lists all tags
- Supports real/visual line breaks (`\n` still works)
- Variables (`@Name = value`) usable anywhere
- Lines starting with `#` = comment (ignored)
#### Properties
Syntax: `tag[property=value]:` (chain with `|`)
- `weight=N` → weighted random (1–10)
- `delay=N` → send after N sec (1–30, always fires; others are weighted)
- `map=X|Y` → specific maps
- `role=X|Y` / `!X` → role filter / exclude
- `rank=X|Y` → Host/Admin/Mod/VIP only
- `players><>=<=!=N` → player count condition
- `preset=X|Y` → specific presets
- `hidden` → hides from `/t` list
#### New Placeholders
`{{HostName}} {{Players}} {{AlivePlayers}} {{DeadPlayers}} {{PlayerCount}} {{AlivePlayerCount}} {{DeadPlayerCount}} {{GameDuration}} {{MeetingCount}} {{PresetName}}`
## Additions
- Client Control GUI (by Zypherus)
- New setting for Capture The Flag: `Spawn Protection Time` (by Zypherus)
- New setting for Natural Disasters: `Disaster Spawn Mode` (`All On Players`/`All On Random Places`/`On Players & Random Places`)
- Death messages for others in Natural Disasters
- New client option: `Classic Mode` (by TommyXL)
- **Fixed HUGE (~ 400 MB) memory leak when opening the settings UI**
- Custom Net Objects should spawn more reliably, and not delayed/flickering for non-host modded clients
- Fixed Coven roles not getting the Necronomicon
- Drafting in Custom Hide And Seek now doesn't give disabled roles as choices and forcefully assigns 1 seeker if everyone drafted a non-seeker role
- Fixed King Of The Zones sometimes not registering zone domination
- Fixed Asthmatic not working after the host dies
- New client option: `Show Client Control GUI` (Enabled by default)
- Improved Client Control GUI (by Zypherus)
- Fixed Dleks button (by TommyXL)
- Other internal fixes and optimizations
---
+1 -1
View File
@@ -900,7 +900,7 @@ public static class KingOfTheZones
if (team != KOTZTeam.None)
{
Points[team]++;
zoneInfo[zone].Players.FindAll(x => x.Team == (int)team).ForEach(x => PlayerPoints[x.Id]++);
zoneInfo[zone].Players.DoIf(x => x.Team == (int)team, x => PlayerPoints[x.Id]++);
}
}
+1 -1
View File
@@ -288,7 +288,7 @@ public static class NaturalDisasters
}
case 1:
{
Disaster remove = PreferRemovingThunderstorm.GetBool() ? ActiveDisasters.Find(x => x is Thunderstorm) : ActiveDisasters.RandomElement();
Disaster remove = PreferRemovingThunderstorm.GetBool() && ActiveDisasters.FindFirst(x => x is Thunderstorm, out Disaster thunderstorm) ? thunderstorm : ActiveDisasters.RandomElement();
if (remove != null) remove.Duration = 0;
remove?.RemoveIfExpired();
break;
+2 -2
View File
@@ -41,8 +41,8 @@ public class Main : BasePlugin
private const string DebugKeyHash = "c0fd562955ba56af3ae20d7ec9e64c664f0facecef4b3e366e109306adeae29d";
private const string DebugKeySalt = "59687b";
public const string PluginGuid = "com.gurge44.endlesshostroles";
public const string PluginVersion = "7.4.0";
public const string PluginDisplayVersion = "7.4.0";
public const string PluginVersion = "7.4.1";
public const string PluginDisplayVersion = "7.4.1";
public const bool TestBuild = false;
public const string NeutralColor = "#ffab1b";
+8 -8
View File
@@ -404,7 +404,7 @@ namespace EHR
{
SpawnTimeStamp = Utils.TimeStamp;
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=67%><alpha=#00>\u2588<alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<br><#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<br><#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#636363>\u2588<#636363>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<br><#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#636363>\u2588<#636363>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<br><#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<br><alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#8c8c8c>\u2588<#8c8c8c>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<#bababa>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.7f);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.4f);
}
protected override void OnFixedUpdate()
@@ -439,7 +439,7 @@ namespace EHR
public PlayerDetector(Vector2 position, List<byte> visibleList, out int id)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=67%><alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#000000>\u2588<#000000>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#000000>\u2588<#000000>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<br><alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#33e6b0>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.7f);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.4f);
id = Id;
}
}
@@ -453,7 +453,7 @@ namespace EHR
Resource = resource;
(char Icon, Color Color) data = Adventurer.ResourceDisplayData[resource];
CreateNetObject($"<size=300%><font=\"VCR SDF\"><line-height=67%>{Utils.ColorString(data.Color, data.Icon.ToString())}</line-height></font></size>", position);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.7f);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.4f);
}
}
@@ -462,7 +462,7 @@ namespace EHR
internal Toilet(Vector2 position, IEnumerable<PlayerControl> hideList)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=67%><alpha=#00>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<alpha=#00>\u2588<br><#e6e6e6>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<br><#e6e6e6>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<br><alpha=#00>\u2588<#e6e6e6>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<#d3d4ce>\u2588<#dedede>\u2588<#dedede>\u2588<#d3d4ce>\u2588<#e6e6e6>\u2588<#e6e6e6>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#bfbfbf>\u2588<#454545>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#333333>\u2588<#bfbfbf>\u2588<br><alpha=#00>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#454545>\u2588<#bfbfbf>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<#bfbfbf>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#dedede>\u2588<#dedede>\u2588<#dedede>\u2588<#dedede>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<#dedede>\u2588<#dedede>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></color></line-height></font></size>", position);
LateTask.New(() => hideList.Do(Hide), 0.7f);
LateTask.New(() => hideList.Do(Hide), 0.4f);
}
}
@@ -485,7 +485,7 @@ namespace EHR
public SprayedArea(Vector2 position, IEnumerable<byte> visibleList)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=67%><alpha=#00>\u2588<alpha=#00>\u2588<#ffd000>\u2588<#ffd000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<alpha=#00>\u2588<br><#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<br><#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<br><alpha=#00>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<#ffd000>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#ffd000>\u2588<#ffd000>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>", position);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.7f);
LateTask.New(() => Main.EnumerateAlivePlayerControls().ExceptBy(visibleList, x => x.PlayerId).Do(Hide), 0.4f);
}
public override void OnMeeting()
@@ -499,7 +499,7 @@ namespace EHR
public CatcherTrap(Vector2 position, PlayerControl catcher)
{
CreateNetObject("<size=100%><font=\"VCR SDF\"><line-height=67%><alpha=#00>\u2588<alpha=#00>\u2588<#ccffda>\u2588<#ccffda>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<alpha=#00>\u2588<br><#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<br><#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<br><alpha=#00>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<#ccffda>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<alpha=#00>\u2588<#ccffda>\u2588<#ccffda>\u2588<alpha=#00>\u2588<alpha=#00>\u2588<br></line-height></size>", position);
LateTask.New(() => Main.EnumerateAlivePlayerControls().Without(catcher).Do(Hide), 0.7f);
LateTask.New(() => Main.EnumerateAlivePlayerControls().Without(catcher).Do(Hide), 0.4f);
}
public override void OnMeeting()
@@ -529,7 +529,7 @@ namespace EHR
public SoulObject(Vector2 position, PlayerControl whisperer)
{
CreateNetObject("<size=80%><font=\"VCR SDF\"><line-height=67%><alpha=#00>\u2588<alpha=#00>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<alpha=#00>\u2588<br><alpha=#00>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<br><#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#cfcfcf>\u2588<#cfcfcf>\u2588<br><#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<br><alpha=#00>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<br><alpha=#00>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<#fcfcfc>\u2588<alpha=#00>\u2588<#fcfcfc>\u2588<br></line-height></size>", position);
LateTask.New(() => Main.EnumerateAlivePlayerControls().Without(whisperer).Do(Hide), 0.7f);
LateTask.New(() => Main.EnumerateAlivePlayerControls().Without(whisperer).Do(Hide), 0.4f);
}
}
@@ -752,7 +752,7 @@ namespace EHR
public ShapeshiftMenuElement(byte visibleTo)
{
CreateNetObject(string.Empty, new Vector2(0f, 0f));
LateTask.New(() => Main.EnumeratePlayerControls().DoIf(x => x.PlayerId != visibleTo, Hide), 0.7f);
LateTask.New(() => Main.EnumeratePlayerControls().DoIf(x => x.PlayerId != visibleTo, Hide), 0.4f);
}
}
+1 -1
View File
@@ -947,7 +947,7 @@ internal static class StartGameHostPatch
foreach (PlayerState state in Main.PlayerStates.Values)
{
if (Main.NeverSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out Dictionary<CustomRoles, List<CustomRoles>> neverList) && neverList.TryGetValue(state.MainRole, out List<CustomRoles> bannedAddonList))
bannedAddonList.ForEach(x => state.RemoveSubRole(x));
bannedAddonList.ForEach(state.RemoveSubRole);
if (Main.AlwaysSpawnTogetherCombos.TryGetValue(OptionItem.CurrentPreset, out Dictionary<CustomRoles, List<CustomRoles>> alwaysList) && alwaysList.TryGetValue(state.MainRole, out List<CustomRoles> addonList))
addonList.ForEach(x => state.SetSubRole(x));
+1 -1
View File
@@ -1684,7 +1684,7 @@ internal static class FixedUpdatePatch
var state = Main.PlayerStates[playerId];
state.SubRoles
.FindAll(x => x is CustomRoles.Fragile or CustomRoles.Unbound or CustomRoles.Diseased or CustomRoles.Antidote or CustomRoles.Beartrap or CustomRoles.Youtuber or CustomRoles.Lucky or CustomRoles.Onbound or CustomRoles.Allergic or CustomRoles.Asthmatic or CustomRoles.Bewilder or CustomRoles.Compelled or CustomRoles.Unlucky or CustomRoles.Bait)
.ForEach(x => state.RemoveSubRole(x));
.ForEach(state.RemoveSubRole);
if (!PlagueBearer.PestilenceList.Contains(playerId))
PlagueBearer.PestilenceList.Add(playerId);