# Releases\r
| Among Us - Version| Mod Version | Link |\r
|----------|-------------|-----------------|\r
+| 2021.5.10s| v2.6.3| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.6.3/TheOtherRoles.zip)\r
| 2021.5.10s| v2.6.2| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.6.2/TheOtherRoles.zip)\r
| 2021.4.14s| v2.6.1| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.6.1/TheOtherRoles.zip)\r
| 2021.4.14s| v2.6.0| [Download](https://github.com/Eisbison/TheOtherRoles/releases/download/v2.6.0/TheOtherRoles.zip)\r
<details>\r
<summary>Click to show the Changelog</summary>\r
\r
+**Version 2.6.3**\r
+- Changed the role limits options to allow for minimum and maximum bounds\r
+- Changed the role assignment to be more random when assigning roles (previously assigned the neutral roles before assigning the crewmate roles)\r
+\r
**Version 2.6.2**\r
- The Other Roles now supports the new Among Us version **2021.5.10s**\r
- Added a chat command to kick players as the host of a lobby (/kick playerName)\r
The count you set will only be reached, if there are enough Crewmates/Impostors in the game and if enough roles are set to be in the game (i.e. they are set to > 0%). The roles are then being distributed as follows:\r
- First all roles that are set to 100% are being assigned to arbitrary players\r
- After that each role that has 10%-90% selected adds 1-9 tickets to a ticket pool (there exists a ticket pool for Crewmates, Neutrals and Impostors). Then the roles will be selected randomly from the pools as long it's possible (until the selected number is reached, until there are no more Crewmates/Impostors or until there are no more tickets). If a role is selected from the pool, obviously all the tickets of that role are being removed.\r
-- The Mafia, Lovers and Child are being selected independently (without using the ticket system) according to the spawn chance you selected. After that all Neutral roles are being selected, then all Crewmate roles and in the very end all Impostor roles.\r
+- The Mafia, Lovers and Child are being selected independently (without using the ticket system) according to the spawn chance you selected. After that the Crewmate, Neutral and Impostor roles are selected and assigned in a random order.\r
\r
**Example:**\\r
Settings: 2 special Crewmate roles, Snitch: 100%, Hacker: 10%, Tracker: 30%\\r
[HarmonyPatch]
public static class CredentialsPatch {
public static string fullCredentials =
-$@"<color=#FCCE03FF>TheOtherRoles</color> v{TheOtherRolesPlugin.Version.ToString()}:
-- Modded by <color=#FCCE03FF>Eisbison</color>,
- <color=#FFEB91FF>Thunderstorm584</color> and <color=#FFEB91FF>EndOfFile</color>
-- Balanced with <color=#FFEB91FF>Dhalucard</color>
-- Button design by <color=#FFEB91FF>Bavari</color>";
+$@"<size=130%><color=#ff351f>TheOtherRoles</color></size> v{TheOtherRolesPlugin.Version.ToString()}
+<size=80%>Modded by <color=#FCCE03FF>Eisbison</color>,
+<color=#FCCE03FF>Thunderstorm584</color> & <color=#FCCE03FF>EndOfFile</color>
+Balanced with <color=#FCCE03FF>Dhalucard</color>
+Button design by <color=#FCCE03FF>Bavari</color></size>";
+
+ public static string mainMenuCredentials =
+$@"Modded by <color=#FCCE03FF>Eisbison</color>, <color=#FCCE03FF>Thunderstorm584</color> & <color=#FCCE03FF>EndOfFile</color>
+Balanced with <color=#FCCE03FF>Dhalucard</color> Design by <color=#FCCE03FF>Bavari</color>";
[HarmonyPatch(typeof(VersionShower), nameof(VersionShower.Start))]
private static class VersionShowerPatch
{
static void Postfix(VersionShower __instance) {
- string spacer = new String('\n', 8);
+ var amongUsLogo = GameObject.Find("bannerLogo_AmongUs");
+ if (amongUsLogo == null) return;
+
+ var credentials = UnityEngine.Object.Instantiate<TMPro.TextMeshPro>(__instance.text);
+ credentials.transform.position = new Vector3(0, 0.1f, 0);
+ credentials.SetText(mainMenuCredentials);
+ credentials.alignment = TMPro.TextAlignmentOptions.Center;
+ credentials.fontSize *= 0.75f;
+
+ var version = UnityEngine.Object.Instantiate<TMPro.TextMeshPro>(credentials);
+ version.transform.position = new Vector3(0, -0.25f, 0);
+ version.SetText($"v{TheOtherRolesPlugin.Version.ToString()}");
- if (__instance.text.text.Contains(spacer))
- __instance.text.text = __instance.text.text + "\n" + fullCredentials;
- else
- __instance.text.text = __instance.text.text + spacer + fullCredentials;
- __instance.text.alignment = TMPro.TextAlignmentOptions.TopLeft;
+ credentials.transform.SetParent(amongUsLogo.transform);
+ version.transform.SetParent(amongUsLogo.transform);
}
}
[HarmonyPatch(typeof(PingTracker), nameof(PingTracker.Update))]
private static class PingTrackerPatch
{
- static void Postfix(PingTracker __instance)
- {
+ static void Postfix(PingTracker __instance){
+ __instance.text.alignment = TMPro.TextAlignmentOptions.TopRight;
if (AmongUsClient.Instance.GameState == InnerNet.InnerNetClient.GameStates.Started) {
- __instance.text.text = "<color=#FCCE03FF>TheOtherRoles</color>\nModded by <color=#FCCE03FF>Eisbison</color>\n" + __instance.text.text;
- __instance.transform.localPosition = new Vector3(2.583f, 2.675f, __instance.transform.localPosition.z);
+ __instance.text.text = $"<size=130%><color=#ff351f>TheOtherRoles</color></size> v{TheOtherRolesPlugin.Version.ToString()}\n" + __instance.text.text;
+ if (PlayerControl.LocalPlayer.Data.IsDead) {
+ __instance.transform.localPosition = new Vector3(3.45f, 2.675f, __instance.transform.localPosition.z);
+ } else {
+ __instance.transform.localPosition = new Vector3(4.2f, 2.675f, __instance.transform.localPosition.z);
+ }
} else {
__instance.text.text = $"{fullCredentials}\n{__instance.text.text}";
- __instance.transform.localPosition = new Vector3(1.25f, 2.675f, __instance.transform.localPosition.z);
+ __instance.transform.localPosition = new Vector3(3.5f, 2.675f, __instance.transform.localPosition.z);
}
}
}
+
+ [HarmonyPatch(typeof(MainMenuManager), nameof(MainMenuManager.Start))]
+ private static class LogoPatch
+ {
+ static void Postfix(PingTracker __instance) {
+ var amongUsLogo = GameObject.Find("bannerLogo_AmongUs");
+ if (amongUsLogo != null) {
+ amongUsLogo.transform.localScale *= 0.6f;
+ amongUsLogo.transform.position += Vector3.up * 0.25f;
+ }
+
+ var torLogo = new GameObject("bannerLogo_TOR");
+ torLogo.transform.position = Vector3.up;
+ var renderer = torLogo.AddComponent<SpriteRenderer>();
+ renderer.sprite = Helpers.loadSpriteFromResources("TheOtherRoles.Resources.Banner.png", 300f);
+ }
+ }
}
}
-extern alias Il2CppNewtonsoft;
using System;
using BepInEx;
using BepInEx.Configuration;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Security.Cryptography;
-using Il2CppNewtonsoft::Newtonsoft.Json.Linq;
-using Il2CppNewtonsoft::Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
namespace TheOtherRoles {
[HarmonyPatch]
public static Material hatShader;
public static Dictionary<string, HatExtension> CustomHatRegistry = new Dictionary<string, HatExtension>();
+ public static HatExtension TestExt = null;
public class HatExtension {
public string author { get; set;}
public string package { get; set;}
public string condition { get; set;}
+ public Sprite FlipImage { get; set;}
+ public Sprite BackFlipImage { get; set;}
public bool isUnlocked() {
if (condition == null || condition.ToLower() == "none")
public string condition { get; set;}
public string name { get; set;}
public string resource { get; set;}
+ public string flipresource { get; set;}
+ public string backflipresource { get; set;}
public string backresource { get; set;}
public string climbresource { get; set;}
public bool bounce { get; set;}
private static List<CustomHat> createCustomHatDetails(string[] hats, bool fromDisk = false) {
Dictionary<string, CustomHat> fronts = new Dictionary<string, CustomHat>();
Dictionary<string, string> backs = new Dictionary<string, string>();
+ Dictionary<string, string> flips = new Dictionary<string, string>();
+ Dictionary<string, string> backflips = new Dictionary<string, string>();
Dictionary<string, string> climbs = new Dictionary<string, string>();
for (int i = 0; i < hats.Length; i++) {
for (int j = 1; j < p.Length; j++)
options.Add(p[j]);
- if (options.Contains("climb"))
+ if (options.Contains("back") && options.Contains("flip"))
+ backflips.Add(p[0], hats[i]);
+ else if (options.Contains("climb"))
climbs.Add(p[0], hats[i]);
- if (options.Contains("back"))
+ else if (options.Contains("back"))
backs.Add(p[0], hats[i]);
- if (!options.Contains("back") && !options.Contains("climb")) {
+ else if (options.Contains("flip"))
+ flips.Add(p[0], hats[i]);
+ else {
CustomHat custom = new CustomHat { resource = hats[i] };
custom.name = p[0].Replace('-', ' ');
custom.bounce = options.Contains("bounce");
foreach (string k in fronts.Keys) {
CustomHat hat = fronts[k];
- string br, cr;
+ string br, cr, fr, bfr;
backs.TryGetValue(k, out br);
climbs.TryGetValue(k, out cr);
+ flips.TryGetValue(k, out fr);
+ backflips.TryGetValue(k, out bfr);
if (br != null)
hat.backresource = br;
if (cr != null)
hat.climbresource = cr;
+ if (fr != null)
+ hat.flipresource = fr;
+ if (bfr != null)
+ hat.backflipresource = bfr;
if (hat.backresource != null)
hat.behind = true;
if (ch.adaptive && hatShader != null)
hat.AltShader = hatShader;
- if (!testOnly) {
- HatExtension extend = new HatExtension();
- extend.author = ch.author != null ? ch.author : "Unknown";
- extend.package = ch.package != null ? ch.package : "Misc.";
- extend.condition = ch.condition != null ? ch.condition : "none";
+ HatExtension extend = new HatExtension();
+ extend.author = ch.author != null ? ch.author : "Unknown";
+ extend.package = ch.package != null ? ch.package : "Misc.";
+ extend.condition = ch.condition != null ? ch.condition : "none";
+ if (ch.flipresource != null)
+ extend.FlipImage = CreateHatSprite(ch.flipresource, fromDisk);
+ if (ch.backflipresource != null)
+ extend.BackFlipImage = CreateHatSprite(ch.backflipresource, fromDisk);
+
+ if (testOnly) {
+ TestExt = extend;
+ TestExt.condition = hat.name;
+ } else {
CustomHatRegistry.Add(hat.name, extend);
}
chd.backresource = filePath + chd.backresource;
if (chd.climbresource != null)
chd.climbresource = filePath + chd.climbresource;
+ if (chd.flipresource != null)
+ chd.flipresource = filePath + chd.flipresource;
+ if (chd.backflipresource != null)
+ chd.backflipresource = filePath + chd.backflipresource;
return CreateHatBehaviour(chd, true);
}
}
}
+ [HarmonyPatch(typeof(PlayerPhysics), nameof(PlayerPhysics.HandleAnimation))]
+ private static class PlayerPhysicsHandleAnimationPatch {
+ private static void Postfix(PlayerPhysics __instance) {
+ AnimationClip currentAnimation = __instance.Animator.GetCurrentAnimation();
+ if (currentAnimation == __instance.ClimbAnim || currentAnimation == __instance.ClimbDownAnim) return;
+ HatParent hp = __instance.myPlayer.HatRenderer;
+ if (hp.Hat == null) return;
+ HatExtension extend = hp.Hat.getHatExtension();
+ if (extend == null) return;
+ if (extend.FlipImage != null) {
+ if (__instance.rend.flipX) {
+ hp.FrontLayer.sprite = extend.FlipImage;
+ } else {
+ hp.FrontLayer.sprite = hp.Hat.MainImage;
+ }
+ }
+ if (extend.BackFlipImage != null) {
+ if (__instance.rend.flipX) {
+ hp.BackLayer.sprite = extend.BackFlipImage;
+ } else {
+ hp.BackLayer.sprite = hp.Hat.BackImage;
+ }
+ }
+ }
+ }
+
[HarmonyPatch(typeof(HatParent), nameof(HatParent.SetHat), new System.Type[] { typeof(uint), typeof(int) })]
private static class HatParentSetHatPatch {
static void Postfix(HatParent __instance, [HarmonyArgument(0)]uint hatId, [HarmonyArgument(1)]int color) {
List<System.Tuple<HatBehaviour, HatExtension>> value = packages[key];
YOffset = createHatPackage(value, key, YOffset, __instance);
}
- __instance.scroller.YBounds.max = YOffset * -0.875f; // probably needs to fix up the entire messed math to solve this correctly
+
+ // __instance.scroller.YBounds.max = -(__instance.YStart - (float)(unlockedHats.Length / this.NumPerRow) * this.YOffset) - 3f;
+ // __instance.scroller.YBounds.max = YOffset * -0.875f; // probably needs to fix up the entire messed math to solve this correctly
+ __instance.scroller.YBounds.max = -(YOffset + 4.1f);
return false;
}
}
info.reshashb = current["reshashb"]?.ToString();
info.climbresource = sanitizeResourcePath(current["climbresource"]?.ToString());
info.reshashc = current["reshashc"]?.ToString();
+ info.flipresource = sanitizeResourcePath(current["flipresource"]?.ToString());
+ info.reshashf = current["reshashf"]?.ToString();
+ info.backflipresource = sanitizeResourcePath(current["backflipresource"]?.ToString());
+ info.reshashbf = current["reshashbf"]?.ToString();
+
info.author = current["author"]?.ToString();
info.package = current["package"]?.ToString();
info.condition = current["condition"]?.ToString();
markedfordownload.Add(data.backresource);
if (data.climbresource != null && doesResourceRequireDownload(filePath + data.climbresource, data.reshashc, md5))
markedfordownload.Add(data.climbresource);
+ if (data.flipresource != null && doesResourceRequireDownload(filePath + data.flipresource, data.reshashf, md5))
+ markedfordownload.Add(data.flipresource);
+ if (data.backflipresource != null && doesResourceRequireDownload(filePath + data.backflipresource, data.reshashbf, md5))
+ markedfordownload.Add(data.backflipresource);
}
foreach(var file in markedfordownload) {
public string reshasha { get; set;}
public string reshashb { get; set;}
public string reshashc { get; set;}
+ public string reshashf { get; set;}
+ public string reshashbf { get; set;}
}
}
public static class CustomHatExtensions {
public static CustomHats.HatExtension getHatExtension(this HatBehaviour hat) {
CustomHats.HatExtension ret = null;
+ if (CustomHats.TestExt != null && CustomHats.TestExt.condition.Equals(hat.name)) {
+ return CustomHats.TestExt;
+ }
CustomHats.CustomHatRegistry.TryGetValue(hat.name, out ret);
return ret;
}
namespace TheOtherRoles {
public class CustomOptionHolder {
public static string[] rates = new string[]{"0%", "10%", "20%", "30%", "40%", "50%", "60%", "70%", "80%", "90%", "100%"};
- public static string[] crewmateAndNeutralRoleCaps = new string[]{"0", "0-1", "1", "1-2", "2", "2-3", "3", "3-4", "4", "4-5", "5", "5-6", "6", "6-7", "7", "7-8", "8", "8-9", "9", "9-10", "10", "10-11", "11", "11-12", "12", "12-13", "13", "13-14", "14", "14-15", "15"};
- public static string[] impostorRoleCaps = new string[]{"0", "0-1", "1", "1-2", "2", "2-3", "3"};
public static string[] presets = new string[]{"Preset 1", "Preset 2", "Preset 3", "Preset 4", "Preset 5"};
public static CustomOption presetSelection;
- public static CustomOption crewmateRolesCount;
- public static CustomOption neutralRolesCount;
- public static CustomOption impostorRolesCount;
+ public static CustomOption crewmateRolesCountMin;
+ public static CustomOption crewmateRolesCountMax;
+ public static CustomOption neutralRolesCountMin;
+ public static CustomOption neutralRolesCountMax;
+ public static CustomOption impostorRolesCountMin;
+ public static CustomOption impostorRolesCountMax;
public static CustomOption mafiaSpawnRate;
public static CustomOption janitorCooldown;
// Role Options
presetSelection = CustomOption.Create(0, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Preset"), presets, null, true);
- crewmateRolesCount = CustomOption.Create(1, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Number Of Crewmate Roles"), crewmateAndNeutralRoleCaps, null, true);
- neutralRolesCount = CustomOption.Create(7, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Number Of Neutral Roles"), crewmateAndNeutralRoleCaps);
- impostorRolesCount = CustomOption.Create(2, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Number Of Impostor Roles"), impostorRoleCaps);
+ // Using new id's for the options to not break compatibilty with older versions
+ crewmateRolesCountMin = CustomOption.Create(300, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Crewmate Roles"), 0f, 0f, 15f, 1f, null, true);
+ crewmateRolesCountMax = CustomOption.Create(301, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Crewmate Roles"), 0f, 0f, 15f, 1f);
+ neutralRolesCountMin = CustomOption.Create(302, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Neutral Roles"), 0f, 0f, 15f, 1f);
+ neutralRolesCountMax = CustomOption.Create(303, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Neutral Roles"), 0f, 0f, 15f, 1f);
+ impostorRolesCountMin = CustomOption.Create(304, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Minimum Impostor Roles"), 0f, 0f, 3f, 1f);
+ impostorRolesCountMax = CustomOption.Create(305, cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Maximum Impostor Roles"), 0f, 0f, 3f, 1f);
mafiaSpawnRate = CustomOption.Create(10, cs(Janitor.color, "Mafia"), rates, null, true);
janitorCooldown = CustomOption.Create(11, "Janitor Cooldown", 30f, 10f, 60f, 2.5f, mafiaSpawnRate);
private static void Postfix(ref string __result)
{
StringBuilder sb = new StringBuilder(__result);
- foreach (CustomOption option in CustomOption.options)
- if (option.parent == null)
- sb.AppendLine($"{option.name}: {option.selections[option.selection].ToString()}");
+ foreach (CustomOption option in CustomOption.options) {
+ if (option.parent == null) {
+ if (option == CustomOptionHolder.crewmateRolesCountMin) {
+ var optionName = CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Crewmate Roles");
+ var min = CustomOptionHolder.crewmateRolesCountMin.getSelection();
+ var max = CustomOptionHolder.crewmateRolesCountMax.getSelection();
+ if (min > max) min = max;
+ var optionValue = (min == max) ? $"{max}" : $"{min} - {max}";
+ sb.AppendLine($"{optionName}: {optionValue}");
+ } else if (option == CustomOptionHolder.neutralRolesCountMin) {
+ var optionName = CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Neutral Roles");
+ var min = CustomOptionHolder.neutralRolesCountMin.getSelection();
+ var max = CustomOptionHolder.neutralRolesCountMax.getSelection();
+ if (min > max) min = max;
+ var optionValue = (min == max) ? $"{max}" : $"{min} - {max}";
+ sb.AppendLine($"{optionName}: {optionValue}");
+ } else if (option == CustomOptionHolder.impostorRolesCountMin) {
+ var optionName = CustomOptionHolder.cs(new Color(204f / 255f, 204f / 255f, 0, 1f), "Impostor Roles");
+ var min = CustomOptionHolder.impostorRolesCountMin.getSelection();
+ var max = CustomOptionHolder.impostorRolesCountMax.getSelection();
+ if (min > max) min = max;
+ var optionValue = (min == max) ? $"{max}" : $"{min} - {max}";
+ sb.AppendLine($"{optionName}: {optionValue}");
+ } else if ((option == CustomOptionHolder.crewmateRolesCountMax) || (option == CustomOptionHolder.neutralRolesCountMax) || (option == CustomOptionHolder.impostorRolesCountMax)) {
+ continue;
+ } else {
+ sb.AppendLine($"{option.name}: {option.selections[option.selection].ToString()}");
+ }
+
+ }
+ }
CustomOption parent = null;
foreach (CustomOption option in CustomOption.options)
if (option.parent != null) {
public class TheOtherRolesPlugin : BasePlugin
{
public const string Id = "me.eisbison.theotherroles";
- public const string VersionString = "2.6.2";
+ public const string VersionString = "2.6.3";
public static System.Version Version = System.Version.Parse(VersionString);
public Harmony Harmony { get; } = new Harmony(Id);
-extern alias Il2CppNewtonsoft;
using System;
using BepInEx;
using BepInEx.Configuration;
using System.Runtime.InteropServices;
using System.Threading.Tasks;
using System.Security.Cryptography;
-using Il2CppNewtonsoft::Newtonsoft.Json.Linq;
-using Il2CppNewtonsoft::Newtonsoft.Json;
+using Newtonsoft.Json.Linq;
+using Newtonsoft.Json;
using Twitch;
namespace TheOtherRoles {
string roleNames = String.Join(", ", RoleInfo.getRoleInfoForPlayer(p).Select(x => Helpers.cs(x.color, x.name)).ToArray());
string taskInfo = tasksTotal > 0 ? $"<color=#FAD934FF>({tasksCompleted}/{tasksTotal})</color>" : "";
- string info = "";
+ string playerInfoText = "";
+ string meetingInfoText ="";
if (p == PlayerControl.LocalPlayer) {
- info = $"{roleNames}";
+ playerInfoText = $"{roleNames}";
if (DestroyableSingleton<TaskPanelBehaviour>.InstanceExists) {
TMPro.TextMeshPro tabText = DestroyableSingleton<TaskPanelBehaviour>.Instance.tab.transform.FindChild("TabText_TMP").GetComponent<TMPro.TextMeshPro>();
tabText.SetText($"Tasks {taskInfo}");
}
- } else if (MapOptions.ghostsSeeRoles && MapOptions.ghostsSeeTasks)
- info = $"{roleNames} {taskInfo}".Trim();
- else if (MapOptions.ghostsSeeTasks)
- info = $"{taskInfo}".Trim();
- else if (MapOptions.ghostsSeeRoles)
- info = $"{roleNames}";
-
- playerInfo.text = info;
+ meetingInfoText = $"{roleNames} {taskInfo}".Trim();
+ }
+ else if (MapOptions.ghostsSeeRoles && MapOptions.ghostsSeeTasks) {
+ playerInfoText = $"{roleNames} {taskInfo}".Trim();
+ meetingInfoText = playerInfoText;
+ }
+ else if (MapOptions.ghostsSeeTasks) {
+ playerInfoText = $"{taskInfo}".Trim();
+ meetingInfoText = playerInfoText;
+ }
+ else if (MapOptions.ghostsSeeRoles) {
+ playerInfoText = $"{roleNames}";
+ meetingInfoText = playerInfoText;
+ }
+
+ playerInfo.text = playerInfoText;
playerInfo.gameObject.SetActive(p.Visible);
- if (meetingInfo != null) meetingInfo.text = MeetingHud.Instance.state == MeetingHud.VoteStates.Results ? "" : info;
+ if (meetingInfo != null) meetingInfo.text = MeetingHud.Instance.state == MeetingHud.VoteStates.Results ? "" : meetingInfoText;
}
}
class SetInfectedPatch
{
- private static void setRoleToRandomPlayer(byte roleId, List<PlayerControl> playerList) {
- var index = rnd.Next(0, playerList.Count);
- byte playerId = playerList[index].PlayerId;
- playerList.RemoveAt(index);
-
- setRoleToPlayer(roleId, playerId);
- }
-
- private static void setRoleToPlayer(byte roleId, byte playerId) {
- MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRole, Hazel.SendOption.Reliable, -1);
- writer.Write(roleId);
- writer.Write(playerId);
- AmongUsClient.Instance.FinishRpcImmediately(writer);
- RPCProcedure.setRole(roleId, playerId);
- }
-
public static void Postfix([HarmonyArgument(0)]Il2CppReferenceArray<GameData.PlayerInfo> infected)
{
MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.ResetVaribles, Hazel.SendOption.Reliable, -1);
AmongUsClient.Instance.FinishRpcImmediately(writer);
RPCProcedure.resetVariables();
+ assignRoles();
+ }
+
+ private static void assignRoles() {
+ var data = getRoleAssignmentData();
+ assignSpecialRoles(data); // Assign special roles like mafia and lovers first as they assign a role to multiple players and the chances are independent of the ticket system
+ assignEnsuredRoles(data); // Assign roles that should always be in the game next
+ assignChanceRoles(data); // Assign roles that may or may not be in the game last
+ }
+
+ private static RoleAssignmentData getRoleAssignmentData() {
+ // Get the players that we want to assign the roles to. Crewmate and Neutral roles are assigned to natural crewmates. Impostor roles to impostors.
List<PlayerControl> crewmates = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList();
crewmates.RemoveAll(x => x.Data.IsImpostor);
List<PlayerControl> impostors = PlayerControl.AllPlayerControls.ToArray().ToList().OrderBy(x => Guid.NewGuid()).ToList();
impostors.RemoveAll(x => !x.Data.IsImpostor);
- float crewCountSettings = (float)CustomOptionHolder.crewmateRolesCount.getSelection() / 2;
- float neutralCountSettings = (float)CustomOptionHolder.neutralRolesCount.getSelection() / 2;
- float impCountSettings = (float)CustomOptionHolder.impostorRolesCount.getSelection() / 2;
+ var crewmateMin = CustomOptionHolder.crewmateRolesCountMin.getSelection();
+ var crewmateMax = CustomOptionHolder.crewmateRolesCountMax.getSelection();
+ var neutralMin = CustomOptionHolder.neutralRolesCountMin.getSelection();
+ var neutralMax = CustomOptionHolder.neutralRolesCountMax.getSelection();
+ var impostorMin = CustomOptionHolder.impostorRolesCountMin.getSelection();
+ var impostorMax = CustomOptionHolder.impostorRolesCountMax.getSelection();
+
+ // Make sure min is less or equal to max
+ if (crewmateMin > crewmateMax) crewmateMin = crewmateMax;
+ if (neutralMin > neutralMax) neutralMin = neutralMax;
+ if (impostorMin > impostorMax) impostorMin = impostorMax;
- if (crewCountSettings % 1 == 0.5f) crewCountSettings += 0.5f * (rnd.Next(2) * 2 - 1);
- if (neutralCountSettings % 1 == 0.5f) neutralCountSettings += 0.5f * (rnd.Next(2) * 2 - 1);
- if (impCountSettings % 1 == 0.5f) impCountSettings += 0.5f * (rnd.Next(2) * 2 - 1);
+ // Get the maximum allowed count of each role type based on the minimum and maximum option
+ int crewCountSettings = rnd.Next(crewmateMin, crewmateMax + 1);
+ int neutralCountSettings = rnd.Next(neutralMin, neutralMax + 1);
+ int impCountSettings = rnd.Next(impostorMin, impostorMax + 1);
- int maxCrewmateRoles = Mathf.Min(crewmates.Count, Mathf.RoundToInt(crewCountSettings));
- int maxNeutralRoles = Mathf.Min(crewmates.Count, Mathf.RoundToInt(neutralCountSettings));
- int maxImpostorRoles = Mathf.Min(impostors.Count, Mathf.RoundToInt(impCountSettings));
+ // Potentially lower the actual maximum to the assignable players
+ int maxCrewmateRoles = Mathf.Min(crewmates.Count, crewCountSettings);
+ int maxNeutralRoles = Mathf.Min(crewmates.Count, neutralCountSettings);
+ int maxImpostorRoles = Mathf.Min(impostors.Count, impCountSettings);
+ // Fill in the lists with the roles that should be assigned to players. Note that the special roles (like Mafia or Lovers) are NOT included in these lists
Dictionary<byte, int> impSettings = new Dictionary<byte, int>();
Dictionary<byte, int> neutralSettings = new Dictionary<byte, int>();
Dictionary<byte, int> crewSettings = new Dictionary<byte, int>();
crewSettings.Add((byte)RoleId.Hacker, CustomOptionHolder.hackerSpawnRate.getSelection());
crewSettings.Add((byte)RoleId.Tracker, CustomOptionHolder.trackerSpawnRate.getSelection());
crewSettings.Add((byte)RoleId.Snitch, CustomOptionHolder.snitchSpawnRate.getSelection());
- if (impostors.Count > 1) // Spy is useless with less than 2 Impostors
+ if (impostors.Count > 1) {
+ // Only add Spy if more than 1 impostor as the spy role is otherwise useless
crewSettings.Add((byte)RoleId.Spy, CustomOptionHolder.spySpawnRate.getSelection());
+ }
crewSettings.Add((byte)RoleId.SecurityGuard, CustomOptionHolder.securityGuardSpawnRate.getSelection());
- // Set special roles
- if (impostors.Count >= 3 && maxImpostorRoles >= 3 && (rnd.Next(1, 101) <= CustomOptionHolder.mafiaSpawnRate.getSelection() * 10)) {
- setRoleToRandomPlayer((byte)RoleId.Godfather, impostors);
- setRoleToRandomPlayer((byte)RoleId.Janitor, impostors);
- setRoleToRandomPlayer((byte)RoleId.Mafioso, impostors);
- maxImpostorRoles -= 3;
+ return new RoleAssignmentData {
+ crewmates = crewmates,
+ impostors = impostors,
+ crewSettings = crewSettings,
+ neutralSettings = neutralSettings,
+ impSettings = impSettings,
+ maxCrewmateRoles = maxCrewmateRoles,
+ maxNeutralRoles = maxNeutralRoles,
+ maxImpostorRoles = maxImpostorRoles
+ };
+ }
+
+ private static void assignSpecialRoles(RoleAssignmentData data) {
+ // Assign Mafia
+ if (data.impostors.Count >= 3 && data.maxImpostorRoles >= 3 && (rnd.Next(1, 101) <= CustomOptionHolder.mafiaSpawnRate.getSelection() * 10)) {
+ setRoleToRandomPlayer((byte)RoleId.Godfather, data.impostors);
+ setRoleToRandomPlayer((byte)RoleId.Janitor, data.impostors);
+ setRoleToRandomPlayer((byte)RoleId.Mafioso, data.impostors);
+ data.maxImpostorRoles -= 3;
}
+ // Assign Lovers
if (rnd.Next(1, 101) <= CustomOptionHolder.loversSpawnRate.getSelection() * 10) {
- if (impostors.Count > 0 && crewmates.Count > 0 && maxCrewmateRoles > 0 && maxImpostorRoles > 0 && rnd.Next(1, 101) <= CustomOptionHolder.loversImpLoverRate.getSelection() * 10) {
- setRoleToRandomPlayer((byte)RoleId.Lover1, impostors);
- setRoleToRandomPlayer((byte)RoleId.Lover2, crewmates);
- maxCrewmateRoles--;
- maxImpostorRoles--;
- } else if (crewmates.Count >= 2 && maxCrewmateRoles >= 2) {
- setRoleToRandomPlayer((byte)RoleId.Lover1, crewmates);
- setRoleToRandomPlayer((byte)RoleId.Lover2, crewmates);
- maxCrewmateRoles -= 2;
+ if (data.impostors.Count > 0 && data.crewmates.Count > 0 && data.maxCrewmateRoles > 0 && data.maxImpostorRoles > 0 && rnd.Next(1, 101) <= CustomOptionHolder.loversImpLoverRate.getSelection() * 10) {
+ setRoleToRandomPlayer((byte)RoleId.Lover1, data.impostors);
+ setRoleToRandomPlayer((byte)RoleId.Lover2, data.crewmates);
+ data.maxCrewmateRoles--;
+ data.maxImpostorRoles--;
+ } else if (data.crewmates.Count >= 2 && data.maxCrewmateRoles >= 2) {
+ setRoleToRandomPlayer((byte)RoleId.Lover1, data.crewmates);
+ setRoleToRandomPlayer((byte)RoleId.Lover2, data.crewmates);
+ data.maxCrewmateRoles -= 2;
}
}
+ // Assign Child
if (rnd.Next(1, 101) <= CustomOptionHolder.childSpawnRate.getSelection() * 10) {
- if (impostors.Count > 0 && maxImpostorRoles > 0 && rnd.Next(1, 101) <= 33) {
- setRoleToRandomPlayer((byte)RoleId.Child, impostors);
- maxImpostorRoles--;
- } else if (crewmates.Count > 0 && maxCrewmateRoles > 0) {
- setRoleToRandomPlayer((byte)RoleId.Child, crewmates);
- maxCrewmateRoles--;
+ if (data.impostors.Count > 0 && data.maxImpostorRoles > 0 && rnd.Next(1, 101) <= 33) {
+ setRoleToRandomPlayer((byte)RoleId.Child, data.impostors);
+ data.maxImpostorRoles--;
+ } else if (data.crewmates.Count > 0 && data.maxCrewmateRoles > 0) {
+ setRoleToRandomPlayer((byte)RoleId.Child, data.crewmates);
+ data.maxCrewmateRoles--;
}
}
+ }
- // Set tickets and always active roles
-
- List<byte> crewTickets = new List<byte>();
- List<byte> neutralTickets = new List<byte>();
- List<byte> impTickets = new List<byte>();
-
- for (int i = 0; i < neutralSettings.Count; i++) {
- var entry = neutralSettings.ElementAt(i);
- if (entry.Value == 0) { // Never
- } else if (entry.Value == 10) { // Always
- if (crewmates.Count > 0 && maxNeutralRoles > 0) {
- setRoleToRandomPlayer(entry.Key, crewmates);
- maxNeutralRoles--;
- if (CustomOptionHolder.blockedRolePairings.ContainsKey(entry.Key)) {
- foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[entry.Key]) {
- if(impSettings.ContainsKey(blockedRoleId)) impSettings[blockedRoleId] = 0;
- if (neutralSettings.ContainsKey(blockedRoleId)) neutralSettings[blockedRoleId] = 0;
- if(crewSettings.ContainsKey(blockedRoleId)) crewSettings[blockedRoleId] = 0;
- }
- }
- }
- } else { // Other
- for (int j = 0; j < entry.Value; j++) neutralTickets.Add(entry.Key);
- }
- }
+ private static void assignEnsuredRoles(RoleAssignmentData data) {
+ // Get all roles where the chance to occur is set to 100%
+ List<byte> ensuredCrewmateRoles = data.crewSettings.Where(x => x.Value == 10).Select(x => x.Key).ToList();
+ List<byte> ensuredNeutralRoles = data.neutralSettings.Where(x => x.Value == 10).Select(x => x.Key).ToList();
+ List<byte> ensuredImpostorRoles = data.impSettings.Where(x => x.Value == 10).Select(x => x.Key).ToList();
+
+ // Assign roles until we run out of either players we can assign roles to or run out of roles we can assign to players
+ while (
+ (data.impostors.Count > 0 && data.maxImpostorRoles > 0 && ensuredImpostorRoles.Count > 0) ||
+ (data.crewmates.Count > 0 && (
+ (data.maxCrewmateRoles > 0 && ensuredCrewmateRoles.Count > 0) ||
+ (data.maxNeutralRoles > 0 && ensuredNeutralRoles.Count > 0)
+ ))) {
+
+ Dictionary<RoleType, List<byte>> rolesToAssign = new Dictionary<RoleType, List<byte>>();
+ if (data.crewmates.Count > 0 && data.maxCrewmateRoles > 0 && ensuredCrewmateRoles.Count > 0) rolesToAssign.Add(RoleType.Crewmate, ensuredCrewmateRoles);
+ if (data.crewmates.Count > 0 && data.maxNeutralRoles > 0 && ensuredNeutralRoles.Count > 0) rolesToAssign.Add(RoleType.Neutral, ensuredNeutralRoles);
+ if (data.impostors.Count > 0 && data.maxImpostorRoles > 0 && ensuredImpostorRoles.Count > 0) rolesToAssign.Add(RoleType.Impostor, ensuredImpostorRoles);
+
+ // Randomly select a pool of roles to assign a role from next (Crewmate role, Neutral role or Impostor role)
+ // then select one of the roles from the selected pool to a player
+ // and remove the role (and any potentially blocked role pairings) from the pool(s)
+ var roleType = rolesToAssign.Keys.ElementAt(rnd.Next(0, rolesToAssign.Keys.Count()));
+ var players = roleType == RoleType.Crewmate || roleType == RoleType.Neutral ? data.crewmates : data.impostors;
+ var index = rnd.Next(0, rolesToAssign[roleType].Count);
+ var roleId = rolesToAssign[roleType][index];
+ setRoleToRandomPlayer(rolesToAssign[roleType][index], players);
+ rolesToAssign[roleType].RemoveAt(index);
- for (int i = 0; i < crewSettings.Count; i++) {
- var entry = crewSettings.ElementAt(i);
- if (entry.Value == 0) { // Never
- } else if (entry.Value == 10) { // Always
- if (crewmates.Count > 0 && maxCrewmateRoles > 0) {
- setRoleToRandomPlayer(entry.Key, crewmates);
- maxCrewmateRoles--;
- if(CustomOptionHolder.blockedRolePairings.ContainsKey(entry.Key)) {
- foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[entry.Key]) {
- if (impSettings.ContainsKey(blockedRoleId)) impSettings[blockedRoleId] = 0;
- if (neutralSettings.ContainsKey(blockedRoleId)) neutralSettings[blockedRoleId] = 0;
- if (crewSettings.ContainsKey(blockedRoleId)) crewSettings[blockedRoleId] = 0;
- }
+ if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) {
+ foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) {
+ // Set chance for the blocked roles to 0 for chances less than 100%
+ if (data.impSettings.ContainsKey(blockedRoleId)) data.impSettings[blockedRoleId] = 0;
+ if (data.neutralSettings.ContainsKey(blockedRoleId)) data.neutralSettings[blockedRoleId] = 0;
+ if (data.crewSettings.ContainsKey(blockedRoleId)) data.crewSettings[blockedRoleId] = 0;
+ // Remove blocked roles even if the chance was 100%
+ foreach(var ensuredRolesList in rolesToAssign.Values) {
+ ensuredRolesList.RemoveAll(x => x == blockedRoleId);
}
}
- } else { // Other
- for (int j = 0; j < entry.Value; j++) crewTickets.Add(entry.Key);
}
- }
- for (int i = 0; i < impSettings.Count; i++) {
- var entry = impSettings.ElementAt(i);
- if (entry.Value == 0) { // Never
- } else if (entry.Value == 10) { // Always
- if (impostors.Count > 0 && maxImpostorRoles > 0) {
- setRoleToRandomPlayer(entry.Key, impostors);
- if(CustomOptionHolder.blockedRolePairings.ContainsKey(entry.Key)) {
- foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[entry.Key]) {
- if (impSettings.ContainsKey(blockedRoleId)) impSettings[blockedRoleId] = 0;
- if (neutralSettings.ContainsKey(blockedRoleId)) neutralSettings[blockedRoleId] = 0;
- if (crewSettings.ContainsKey(blockedRoleId)) crewSettings[blockedRoleId] = 0;
- }
- }
- maxImpostorRoles--;
- }
- } else { // Other
- for (int j = 0; j < entry.Value; j++) impTickets.Add(entry.Key);
+ // Adjust the role limit
+ switch (roleType) {
+ case RoleType.Crewmate: data.maxCrewmateRoles--; break;
+ case RoleType.Neutral: data.maxNeutralRoles--;break;
+ case RoleType.Impostor: data.maxImpostorRoles--;break;
}
}
+ }
- // Set solo player roles
+
+ private static void assignChanceRoles(RoleAssignmentData data) {
+ // Get all roles where the chance to occur is set grater than 0% but not 100% and build a ticket pool based on their weight
+ List<byte> crewmateTickets = data.crewSettings.Where(x => x.Value > 0 && x.Value < 10).Select(x => Enumerable.Repeat(x.Key, x.Value)).SelectMany(x => x).ToList();
+ List<byte> neutralTickets = data.neutralSettings.Where(x => x.Value > 0 && x.Value < 10).Select(x => Enumerable.Repeat(x.Key, x.Value)).SelectMany(x => x).ToList();
+ List<byte> impostorTickets = data.impSettings.Where(x => x.Value > 0 && x.Value < 10).Select(x => Enumerable.Repeat(x.Key, x.Value)).SelectMany(x => x).ToList();
- for (int i = 0; i < maxNeutralRoles; i++) {
- if (neutralTickets.Count > 0 && crewmates.Count > 0) {
- var index = rnd.Next(0, neutralTickets.Count);
- byte roleId = neutralTickets[index];
- neutralTickets.RemoveAll(x => x == roleId);
- setRoleToRandomPlayer(roleId, crewmates);
+ // Assign roles until we run out of either players we can assign roles to or run out of roles we can assign to players
+ while (
+ (data.impostors.Count > 0 && data.maxImpostorRoles > 0 && impostorTickets.Count > 0) ||
+ (data.crewmates.Count > 0 && (
+ (data.maxCrewmateRoles > 0 && crewmateTickets.Count > 0) ||
+ (data.maxNeutralRoles > 0 && neutralTickets.Count > 0)
+ ))) {
+
+ Dictionary<RoleType, List<byte>> rolesToAssign = new Dictionary<RoleType, List<byte>>();
+ if (data.crewmates.Count > 0 && data.maxCrewmateRoles > 0 && crewmateTickets.Count > 0) rolesToAssign.Add(RoleType.Crewmate, crewmateTickets);
+ if (data.crewmates.Count > 0 && data.maxNeutralRoles > 0 && neutralTickets.Count > 0) rolesToAssign.Add(RoleType.Neutral, neutralTickets);
+ if (data.impostors.Count > 0 && data.maxImpostorRoles > 0 && impostorTickets.Count > 0) rolesToAssign.Add(RoleType.Impostor, impostorTickets);
+
+ // Randomly select a pool of role tickets to assign a role from next (Crewmate role, Neutral role or Impostor role)
+ // then select one of the roles from the selected pool to a player
+ // and remove all tickets of this role (and any potentially blocked role pairings) from the pool(s)
+ var roleType = rolesToAssign.Keys.ElementAt(rnd.Next(0, rolesToAssign.Keys.Count()));
+ var players = roleType == RoleType.Crewmate || roleType == RoleType.Neutral ? data.crewmates : data.impostors;
+ var index = rnd.Next(0, rolesToAssign[roleType].Count);
+ var roleId = rolesToAssign[roleType][index];
+ setRoleToRandomPlayer(rolesToAssign[roleType][index], players);
+ rolesToAssign[roleType].RemoveAll(x => x == roleId);
- if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) {
- foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) {
- crewTickets.RemoveAll(x => x == blockedRoleId);
- neutralTickets.RemoveAll(x => x == blockedRoleId);
- impTickets.RemoveAll(x => x == blockedRoleId);
- }
+ if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) {
+ foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) {
+ // Remove tickets of blocked roles from all pools
+ crewmateTickets.RemoveAll(x => x == blockedRoleId);
+ neutralTickets.RemoveAll(x => x == blockedRoleId);
+ impostorTickets.RemoveAll(x => x == blockedRoleId);
}
}
- }
- for (int i = 0; i < maxCrewmateRoles; i++) {
- if (crewTickets.Count > 0 && crewmates.Count > 0) {
- var index = rnd.Next(0, crewTickets.Count);
- byte roleId = crewTickets[index];
- crewTickets.RemoveAll(x => x == roleId);
- setRoleToRandomPlayer(roleId, crewmates);
-
- if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) {
- foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) {
- crewTickets.RemoveAll(x => x == blockedRoleId);
- neutralTickets.RemoveAll(x => x == blockedRoleId);
- impTickets.RemoveAll(x => x == blockedRoleId);
- }
- }
+ // Adjust the role limit
+ switch (roleType) {
+ case RoleType.Crewmate: data.maxCrewmateRoles--; break;
+ case RoleType.Neutral: data.maxNeutralRoles--;break;
+ case RoleType.Impostor: data.maxImpostorRoles--;break;
}
}
+ }
- for (int i = 0; i < maxImpostorRoles; i++) {
- if (impTickets.Count > 0 && impostors.Count > 0) {
- var index = rnd.Next(0, impTickets.Count);
- byte roleId = impTickets[index];
- impTickets.RemoveAll(x => x == roleId);
- setRoleToRandomPlayer(roleId, impostors);
-
- if (CustomOptionHolder.blockedRolePairings.ContainsKey(roleId)) {
- foreach(var blockedRoleId in CustomOptionHolder.blockedRolePairings[roleId]) {
- crewTickets.RemoveAll(x => x == blockedRoleId);
- neutralTickets.RemoveAll(x => x == blockedRoleId);
- impTickets.RemoveAll(x => x == blockedRoleId);
- }
- }
- }
- }
+ private static void setRoleToRandomPlayer(byte roleId, List<PlayerControl> playerList) {
+ var index = rnd.Next(0, playerList.Count);
+ byte playerId = playerList[index].PlayerId;
+ playerList.RemoveAt(index);
+
+ setRoleToPlayer(roleId, playerId);
}
+
+ private static void setRoleToPlayer(byte roleId, byte playerId) {
+ MessageWriter writer = AmongUsClient.Instance.StartRpcImmediately(PlayerControl.LocalPlayer.NetId, (byte)CustomRPC.SetRole, Hazel.SendOption.Reliable, -1);
+ writer.Write(roleId);
+ writer.Write(playerId);
+ AmongUsClient.Instance.FinishRpcImmediately(writer);
+ RPCProcedure.setRole(roleId, playerId);
+ }
+
+ private class RoleAssignmentData {
+ public List<PlayerControl> crewmates {get;set;}
+ public List<PlayerControl> impostors {get;set;}
+ public Dictionary<byte, int> impSettings = new Dictionary<byte, int>();
+ public Dictionary<byte, int> neutralSettings = new Dictionary<byte, int>();
+ public Dictionary<byte, int> crewSettings = new Dictionary<byte, int>();
+ public int maxCrewmateRoles {get;set;}
+ public int maxNeutralRoles {get;set;}
+ public int maxImpostorRoles {get;set;}
+ }
+
+ private enum RoleType {
+ Crewmate = 0,
+ Neutral = 1,
+ Impostor = 2
+ }
+
}
}
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>netstandard2.1</TargetFramework>
- <Version>2.6.2</Version>
+ <Version>2.6.3</Version>
<Description>TheOtherRoles</Description>
<Authors>Eisbison</Authors>
</PropertyGroup>
<Message Text="Second occurrence" />
<Copy SourceFiles="$(ProjectDir)\bin\$(Configuration)\netstandard2.1\TheOtherRoles.dll" DestinationFolder="$(AmongUs)/BepInEx/plugins/" />
</Target>
-
- <!-- il2cpp newtonsoft -->
- <ItemGroup>
- <Reference Include="Newtonsoft.Json, Version=3.7.1.6">
- <HintPath>$(AmongUs)\BepInEx\unhollowed\Newtonsoft.Json.dll</HintPath>
- <Aliases>Il2CppNewtonsoft</Aliases>
- </Reference>
- </ItemGroup>
- <PropertyGroup>
- <NoWarn>$(NoWarn);MSB3243</NoWarn>
- </PropertyGroup>
</Project>
\ No newline at end of file