# Releases
| Among Us - Version| Mod Version | Link |
|----------|-------------|-----------------|
+| 2023.07.12s| v4.3.4| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.3.4/TheOtherRoles.zip)
| 2023.07.12s| v4.3.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.3.3/TheOtherRoles.zip)
| 2023.03.28s| v4.3.2| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v4.3.2/TheOtherRoles.zip)
<details>
<details>
<summary>Click to show the Changelog</summary>
+**Version 4.3.4**
+- Updated BepInEx dependency to 671
+- Fixed compatibility to Submerged (not thouroughly tested)
+- Fixed a bug where the death reason of a guessed shifter was incorrectly displayed as "shifted xy"
+- Make it possible to disable the Mod-Updater (see [details](#gcerror) ), to circumvent a crash at startup with a GC-Error
+- Fixed the hats in freeplay partially
+
**Version 4.3.3**
- Updated to Among Us version 2023.07.12
- Fixed an issue where the swap icon of a swapper guesser would be in front of the witch icon on a spelled player
| Enable Sabotages | -
| Time The Hunter Needs To Wait | -
+## GCERROR
+If the error message "Fatal Error in GC - Collecting from unknown thread" stops you from playing the game, you can now disable the mod-updater, which causes this error.
+In order to do this, create a file called `noupdater.txt` in your modded Among Us folder.
+
# License
TheOtherRolesAU/TheOtherRoles is licensed under the
public class TheOtherRolesPlugin : BasePlugin
{
public const string Id = "me.eisbison.theotherroles";
- public const string VersionString = "4.3.3";
+ public const string VersionString = "4.3.4";
public static uint betaDays = 0; // amount of days for the build to be usable (0 for infinite!)
public static Version Version = Version.Parse(VersionString);
SubmergedCompatibility.Initialize();
AddComponent<ModUpdateBehaviour>();
Modules.MainMenuPatch.addSceneChangeCallbacks();
+
+ TheOtherRolesPlugin.Logger.LogInfo("Loading TOR completed!");
}
public static Sprite GetModStamp() {
if (ModStamp) return ModStamp;
public class BepInExUpdater : MonoBehaviour
{
- public const string RequiredBepInExVersion = "6.0.0-be.670+42a6727370c2b9356fc043ea601410540a8b4042";
- public const string BepInExDownloadURL = "https://builds.bepinex.dev/projects/bepinex_be/670/BepInEx-Unity.IL2CPP-win-x86-6.0.0-be.670%2B42a6727.zip";
+ public const string RequiredBepInExVersion = "6.0.0-be.671+9caf61dca07043beae57b0771f6a5283aa02436b";
+ public const string BepInExDownloadURL = "https://builds.bepinex.dev/projects/bepinex_be/671/BepInEx-Unity.IL2CPP-win-x86-6.0.0-be.671%2B9caf61d.zip";
public static bool UpdateRequired => Paths.BepInExVersion.ToString() != RequiredBepInExVersion;
public void Awake()
} else {
CustomHatRegistry.Add(hat.name, extend);
}
- CustomHatViewDatas.Add(hat.name, viewdata);
+ CustomHatViewDatas.TryAdd(hat.name, viewdata);
var assetRef = new AssetReference(viewdata.Pointer);
hat.ViewDataRef = assetRef;
[HarmonyPatch]
private static class FreeplayHatTestingPatches
{
+ [HarmonyPriority(Priority.High)]
[HarmonyPatch(typeof(HatParent), nameof(HatParent.SetHat), typeof(int))]
private static class HatParentSetHatPatchColor {
static void Prefix(HatParent __instance) {
if (hats.Count > 0)
{
__instance.Hat = CreateHatBehaviour(hats[0], true, true);
- __instance.hatDataAsset = __instance.Hat.CreateAddressableAsset();
+ __instance.Hat.CreateAddressableAsset();
}
}
catch (System.Exception e)
[HarmonyPatch(typeof(HatParent), nameof(HatParent.SetHat), typeof(int))]
public class SetHatPatch {
public static bool Prefix(HatParent __instance, int color) {
- if (!CustomHatRegistry.ContainsKey(__instance.Hat.name)) return true;
+ if (!CustomHatViewDatas.ContainsKey(__instance.Hat.name)) return true;
__instance.hatDataAsset = null;
__instance.PopulateFromHatViewData();
__instance.SetMaterialColor(color);
}
}
+ [HarmonyPatch(typeof(HatParent), nameof(HatParent.LateUpdate))]
+ public static class HatParentLateUpdatePatch {
+ public static bool Prefix(HatParent __instance) {
+ return false;
+ if (__instance.Parent) {
+ HatViewData hatViewData;
+ try {
+ hatViewData = __instance.hatDataAsset.GetAsset();
+ return true;
+ } catch {
+ try {
+ hatViewData = CustomHatViewDatas[__instance.Hat.name];
+ } catch {
+ return false;
+ }
+ }
+ if (__instance.Hat && hatViewData != null) {
+ if (__instance.FrontLayer.sprite != hatViewData.ClimbImage && __instance.FrontLayer.sprite != hatViewData.FloorImage) {
+ if ((__instance.Hat.InFront || hatViewData.BackImage) && hatViewData.LeftMainImage) {
+ __instance.FrontLayer.sprite = (__instance.Parent.flipX ? hatViewData.LeftMainImage : hatViewData.MainImage);
+ }
+ if (hatViewData.BackImage && hatViewData.LeftBackImage) {
+ __instance.BackLayer.sprite = (__instance.Parent.flipX ? hatViewData.LeftBackImage : hatViewData.BackImage);
+ return false;
+ }
+ if (!hatViewData.BackImage && !__instance.Hat.InFront && hatViewData.LeftMainImage) {
+ __instance.BackLayer.sprite = (__instance.Parent.flipX ? hatViewData.LeftMainImage : hatViewData.MainImage);
+ return false;
+ }
+ } else if (__instance.FrontLayer.sprite == hatViewData.ClimbImage || __instance.FrontLayer.sprite == hatViewData.LeftClimbImage) {
+ SpriteAnimNodeSync spriteAnimNodeSync = __instance.SpriteSyncNode ?? __instance.GetComponent<SpriteAnimNodeSync>();
+ if (spriteAnimNodeSync) {
+ spriteAnimNodeSync.NodeId = 0;
+ }
+ }
+ }
+ }
+ return false;
+ }
+ }
+
[HarmonyPatch(typeof(HatParent), nameof(HatParent.SetFloorAnim))]
public class HatParentSetFloorAnimPatch {
public static bool Prefix(HatParent __instance) {
public class HatParentSetIdleAnimPatch {
public static bool Prefix(HatParent __instance, int colorId) {
if (!__instance.Hat) return false;
- if (!CustomHatRegistry.ContainsKey(__instance.Hat.name))
+ if (!CustomHatViewDatas.ContainsKey(__instance.Hat.name))
return true;
HatViewData hatViewData = CustomHatViewDatas[__instance.Hat.name];
__instance.hatDataAsset = null;
}
}
+ [HarmonyPatch(typeof(CosmeticsCache), nameof(CosmeticsCache.GetHat))]
+ public class CosmeticsCacheGetHatPatch {
+ public static bool Prefix(string id, ref HatViewData __result) {
+ TheOtherRolesPlugin.Logger.LogMessage($"trying to load hat {id} from cosmetics cache");
+ if (CustomHatViewDatas.ContainsKey(id)) {
+ __result = CustomHatViewDatas[id];
+ return false;
+ }
+ return true;
+ }
+ }
+
[HarmonyPatch(typeof(HatsTab), nameof(HatsTab.OnEnable))]
public class HatsTabOnEnablePatch {
public static string innerslothPackageName = "Innersloth Hats";
public string TimeString;
public JObject Request;
public Version Version => Version.Parse(Tag);
-
+
public UpdateData(JObject data)
{
Tag = data["tag_name"]?.ToString().TrimStart('v');
[HideFromIl2Cpp]
public static IEnumerator CoCheckUpdates()
{
+ // Since running the update check task causes a crash for some users, allow the user to disable the updater by creating a file called noupdater.txt
+ // in their Among Us folder (root)
+ if (Il2CppSystem.IO.File.Exists(System.IO.Directory.GetCurrentDirectory() + "\\noupdater.txt")) yield break;
var torUpdateCheck = Task.Run(() => Instance.GetGithubUpdate("Eisbison", "TheOtherRoles"));
while (!torUpdateCheck.IsCompleted) yield return null;
if (torUpdateCheck.Result != null && torUpdateCheck.Result.IsNewer(Version.Parse(TheOtherRolesPlugin.VersionString)))
if (submergedUpdateCheck.Result != null && (!SubmergedCompatibility.Loaded || submergedUpdateCheck.Result.IsNewer(SubmergedCompatibility.Version)))
{
Instance.SubmergedUpdate = submergedUpdateCheck.Result;
- if (Instance.SubmergedUpdate.Tag.Equals("2022.10.26")) Instance.SubmergedUpdate = null;
+ if (Instance.SubmergedUpdate.Tag.Equals("2022.10.26") || IL2CPPChainloader.Instance.Plugins.TryGetValue("com.DigiWorm.LevelImposter", out PluginInfo _)) Instance.SubmergedUpdate = null;
}
}
Instance.OnSceneLoaded(SceneManager.GetActiveScene(), LoadSceneMode.Single);
{
var client = new HttpClient();
client.DefaultRequestHeaders.Add("User-Agent", "TheOtherRoles Updater");
-
try {
var req = await client.GetAsync($"https://api.github.com/repos/{owner}/{repo}/releases/latest", HttpCompletionOption.ResponseContentRead);
-
if (!req.IsSuccessStatusCode) return null;
var dataString = await req.Content.ReadAsStringAsync();
__result = Mathf.Clamp(GameOptionsManager.Instance.CurrentGameOptions.NumImpostors, 1, 3);
}
}
- }
+ }
[HarmonyPatch(typeof(GameOptionsData), nameof(GameOptionsData.Validate))]
class GameOptionsDataValidatePatch {
Shifter.clearAndReload();
// Suicide (exile) when impostor or impostor variants
- if (player.Data.Role.IsImpostor || Helpers.isNeutral(player)) {
+ if ((player.Data.Role.IsImpostor || Helpers.isNeutral(player)) && !oldShifter.Data.IsDead) {
oldShifter.Exiled();
GameHistory.overrideDeathReasonAndKiller(oldShifter, DeadPlayer.CustomDeathReason.Shift, player);
if (oldShifter == Lawyer.target && AmongUsClient.Instance.AmHost && Lawyer.lawyer != null) {
public static class SoundEffectsManager
{
- private static Dictionary<string, AudioClip> soundEffects;
+ private static Dictionary<string, AudioClip> soundEffects = new();
public static void Load()
{
}
public static void stop(string path) {
- if (Constants.ShouldPlaySfx()) SoundManager.Instance.StopSound(get(path));
+ var soundToStop = get(path);
+ if (soundToStop != null)
+ if (Constants.ShouldPlaySfx()) SoundManager.Instance.StopSound(soundToStop);
}
public static void stopAll() {
public static bool IsSubmerged { get; private set; }
- public static bool DisableO2MaskCheckForEmergency
- {
- set
- {
- if (!Loaded) return;
- DisableO2MaskCheckField.SetValue(null, value);
- }
- }
public static void SetupMap(ShipStatus map)
{
}
private static Type SubmarineStatusType;
- private static MethodInfo CalculateLightRadiusMethod;
-
- private static Type TaskIsEmergencyPatchType;
- private static FieldInfo DisableO2MaskCheckField;
+ private static MethodInfo CalculateLightRadiusMethod;
private static MethodInfo RpcRequestChangeFloorMethod;
private static Type FloorHandlerType;
private static MethodInfo GetFloorHandlerMethod;
- private static Type Vent_MoveToVent_PatchType;
- private static FieldInfo InTransitionField;
+ private static Type VentPatchDataType;
+ private static PropertyInfo InTransitionField;
private static Type CustomTaskTypesType;
private static FieldInfo RetrieveOxigenMaskField;
InjectedTypes = (Dictionary<string, Type>) AccessTools.PropertyGetter(Types.FirstOrDefault(t => t.Name == "ComponentExtensions"), "RegisteredTypes")
.Invoke(null, Array.Empty<object>());
-
+
SubmarineStatusType = Types.First(t => t.Name == "SubmarineStatus");
CalculateLightRadiusMethod = AccessTools.Method(SubmarineStatusType, "CalculateLightRadius");
-
- TaskIsEmergencyPatchType = Types.First(t => t.Name == "PlayerTask_TaskIsEmergency_Patch");
- DisableO2MaskCheckField = AccessTools.Field(TaskIsEmergencyPatchType, "DisableO2MaskCheck");
FloorHandlerType = Types.First(t => t.Name == "FloorHandler");
GetFloorHandlerMethod = AccessTools.Method(FloorHandlerType, "GetFloorHandler", new Type[] {typeof(PlayerControl)});
RpcRequestChangeFloorMethod = AccessTools.Method(FloorHandlerType, "RpcRequestChangeFloor");
- Vent_MoveToVent_PatchType = Types.First(t => t.Name == "Vent_MoveToVent_Patch");
- InTransitionField = AccessTools.Field(Vent_MoveToVent_PatchType, "InTransition");
+ VentPatchDataType = Types.First(t => t.Name == "VentPatchData");
+
+ InTransitionField = AccessTools.Property(VentPatchDataType, "InTransition");
CustomTaskTypesType = Types.First(t => t.Name == "CustomTaskTypes");
RetrieveOxigenMaskField = AccessTools.Field(CustomTaskTypesType, "RetrieveOxygenMask");
- RetrieveOxygenMask = (TaskTypes)RetrieveOxigenMaskField.GetValue(null);
+ var RetrieveOxigenMaskTaskTypeField = AccessTools.Field(CustomTaskTypesType, "taskType");
+ object OxygenMaskCustomTaskType = RetrieveOxigenMaskField.GetValue(null);
+ RetrieveOxygenMask = (TaskTypes)RetrieveOxigenMaskTaskTypeField.GetValue(OxygenMaskCustomTaskType);
- SubmarineOxygenSystemType = Types.First(t => t.Name == "SubmarineOxygenSystem" && t.Namespace == "Submerged.Systems.CustomSystems.Oxygen");
+ SubmarineOxygenSystemType = Types.First(t => t.Name == "SubmarineOxygenSystem" && t.Namespace == "Submerged.Systems.Oxygen");
SubmarineOxygenSystemInstanceField = AccessTools.PropertyGetter(SubmarineOxygenSystemType, "Instance");
RepairDamageMethod = AccessTools.Method(SubmarineOxygenSystemType, "RepairDamage");
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
- <Version>4.3.3</Version>
+ <Version>4.3.4</Version>
<Description>TheOtherRoles</Description>
<Authors>Eisbison</Authors>
<LangVersion>latest</LangVersion>
<ItemGroup>
<PackageReference Include="AmongUs.GameLibs.Steam" Version="2023.7.11" />
- <PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.670" />
+ <PackageReference Include="BepInEx.Unity.IL2CPP" Version="6.0.0-be.671" />
<PackageReference Include="BepInEx.IL2CPP.MSBuild" Version="2.1.0-rc.1" />
- <PackageReference Include="Reactor" Version="2.2.0-ci.235" />
+ <PackageReference Include="Reactor" Version="2.2.0" />
</ItemGroup>
<Target Name="Date" BeforeTargets="BeforeBuild"> <!--Will make the compile time available s.t. we can let betas expire-->
},
"BepInEx.Unity.IL2CPP": {
"type": "Direct",
- "requested": "[6.0.0-be.670, )",
- "resolved": "6.0.0-be.670",
- "contentHash": "dhzCrem44oFxhOICCJ9eoSUbaKSsGGyBUfUQW9WFljCwIK8o4Cx5BiuXAkYoRjr2DhpzLpPDyPZDRImUqH0bwA==",
+ "requested": "[6.0.0-be.671, )",
+ "resolved": "6.0.0-be.671",
+ "contentHash": "XpmrBitEO7pe5YG9VHqn0nuelEF5Dp0Rpkxa2F7PFZF1a00KSsdCL809++HYnGzLumNOCIt7mO7yyDNP5k25mw==",
"dependencies": {
- "BepInEx.Core": "6.0.0-be.670",
- "BepInEx.Unity.Common": "6.0.0-be.670",
+ "BepInEx.Core": "6.0.0-be.671",
+ "BepInEx.Unity.Common": "6.0.0-be.671",
"HarmonyX": "2.10.1",
"Iced": "1.18.0",
- "Il2CppInterop.Generator": "1.4.6-ci.354",
- "Il2CppInterop.HarmonySupport": "1.4.6-ci.354",
- "Il2CppInterop.Runtime": "1.4.6-ci.354",
+ "Il2CppInterop.Generator": "1.4.6-ci.367",
+ "Il2CppInterop.HarmonySupport": "1.4.6-ci.367",
+ "Il2CppInterop.Runtime": "1.4.6-ci.367",
"MonoMod.RuntimeDetour": "22.5.1.1",
"Samboy063.Cpp2IL.Core": "2022.1.0-development.866"
}
},
"Reactor": {
"type": "Direct",
- "requested": "[2.2.0-ci.235, )",
- "resolved": "2.2.0-ci.235",
- "contentHash": "aa0VHgBs5QwuMHt7evQ/mldAHBqsWdLvnh7NS0RrVSwxi46KfTdALc1sebjzLrWs949USdwGXtFIePEMizGqrA==",
+ "requested": "[2.2.0, )",
+ "resolved": "2.2.0",
+ "contentHash": "foMHya01tmr//3tw+kO7FmY1ojnR0m+ShMU6sxogbnWeO85lmX3QM8aSIsYeAhtJSThf6Ben6iTM4O0KgVcmqw==",
"dependencies": {
"BepInEx.Unity.IL2CPP": "6.0.0-be.670"
}
},
"BepInEx.Core": {
"type": "Transitive",
- "resolved": "6.0.0-be.670",
- "contentHash": "7CbbMNZfb+1VHjFKh/ErFBOOEYrVCIkng/B3/HPcbNioySC7qdT1ztfYqs6YjQia4krEic+LV3ew86B/hTg+hw==",
+ "resolved": "6.0.0-be.671",
+ "contentHash": "Hp9QsgwtlGuNULFq5tF8YHrVD5R5WA5nMgFTJbcScWsGJDq7KPEhiLNGvKHAxcmMM8GA0CKM+jn8cJPtlMKvNQ==",
"dependencies": {
"HarmonyX": "2.10.1",
"MonoMod.Utils": "22.5.1.1",
},
"BepInEx.Unity.Common": {
"type": "Transitive",
- "resolved": "6.0.0-be.670",
- "contentHash": "FSzWILgwepZ7CpA34ew1WyO75lNjxkfX86uwo2172lbhmLkgoAdQbNun8dxKJCDlIevmTDga76yr/WPrTXELvA==",
+ "resolved": "6.0.0-be.671",
+ "contentHash": "05W7ERsHizZl0MacTAhiGkcihZl2b0DYBP0e6gA1Vzoay+teQ/mHy3zorGu1r8lLWlesH4LXl89HwFjrMA1ZKw==",
"dependencies": {
"AssetRipper.VersionUtilities": "1.2.1",
"MonoMod.Utils": "22.5.1.1"
},
"Il2CppInterop.Common": {
"type": "Transitive",
- "resolved": "1.4.6-ci.354",
- "contentHash": "aCP3kr39YQw5GVqE9Q8c5y7f9CEKdFxpUhIqYgQBtrEz5Z/KCbHhjuOf/lSuFrjl6Vub/BKk6k+UbMRdoSvC1w==",
+ "resolved": "1.4.6-ci.367",
+ "contentHash": "zviSAk0COGdxx1KLTJlSi6lyvfRjbPO4qhj9RvLAU5zP74hwAkjhim0WsSo9clkkyGS+KXDrjnUEHqfXuMMm9Q==",
"dependencies": {
"Iced": "1.17.0",
"Microsoft.Extensions.Logging.Abstractions": "6.0.1",
},
"Il2CppInterop.Generator": {
"type": "Transitive",
- "resolved": "1.4.6-ci.354",
- "contentHash": "y30sxc9mMv0bUzCPDr73xiI6fiu7ksmnEm6XULTGU/5JEGv2aw++/71bLOEYCscNbZTa2JT4yYrLCXCj3GSekg==",
+ "resolved": "1.4.6-ci.367",
+ "contentHash": "VP/1LX3wEy0/5BCrgggzIm9niyRGp/zjXaxFJip1D2bvM7oIXwK0LR0Rp8BE/uxKW8aQjVYxxwVwsdXPS/1KZw==",
"dependencies": {
- "Il2CppInterop.Common": "1.4.6-ci.354",
+ "Il2CppInterop.Common": "1.4.6-ci.367",
"Mono.Cecil": "0.11.3"
}
},
"Il2CppInterop.HarmonySupport": {
"type": "Transitive",
- "resolved": "1.4.6-ci.354",
- "contentHash": "mQV5A+B/qtI6kSXEGx/UswiqjFKw13/yyviawnStfRKbLMW+XFsdMgGSkOVZd/TiDtF9ZG4Xt7DbkbFu26WjyA==",
+ "resolved": "1.4.6-ci.367",
+ "contentHash": "rKb4Bt4cZQNWtI1L1/n/m5jJelP8pwAcQHwN/gaUAcobnapGZPJvRp8gyLQRvthGm3sxeleIQelEsv6L+21A2g==",
"dependencies": {
"HarmonyX": "2.10.0",
- "Il2CppInterop.Runtime": "1.4.6-ci.354"
+ "Il2CppInterop.Runtime": "1.4.6-ci.367"
}
},
"Il2CppInterop.Runtime": {
"type": "Transitive",
- "resolved": "1.4.6-ci.354",
- "contentHash": "Xe5md9z+KIthdEcjfUjmoOhvM3gTI3SPyocqvuzEHoov5jQ/HhIPv5hUZzTSm+2nzn3XplENNE8vlBPvQ1o6OA==",
+ "resolved": "1.4.6-ci.367",
+ "contentHash": "Wb4rj/ESlfiYljfVXskndbkYNSX1WxPcsylrYex39QnVzujk6tRQUbHLA7PZn509z6P5wYbqJvhodzJ+w9Kk4A==",
"dependencies": {
"Iced": "1.17.0",
- "Il2CppInterop.Common": "1.4.6-ci.354"
+ "Il2CppInterop.Common": "1.4.6-ci.367"
}
},
"js6pak.Gee.External.Capstone": {
<configuration>
<packageSources>
<add key="BepInEx" value="https://nuget.bepinex.dev/v3/index.json" />
- <add key="Reactor" value="https://nuget.reactor.gg/v3/index.json" />
- <add key="Samboy063" value="https://nuget.samboy.dev/v3/index.json" />
+ <add key="Reactor" value="https://nuget.reactor.gg/v3/index.json" />
+ <add key="Samboy063" value="https://nuget.samboy.dev/v3/index.json" />
</packageSources>
</configuration>