From aeb05632d3fc15b1c7ce94c2e60a0c0954691e3f Mon Sep 17 00:00:00 2001 From: DarkPenguin <96709220+DarkPenguin24@users.noreply.github.com> Date: Sun, 27 Feb 2022 03:00:36 +0100 Subject: [PATCH] #302: Fix getting banned on shapeshifting / killing (#303) --- AmongUsMenu.vcxproj | 1 + AmongUsMenu.vcxproj.filters | 3 ++ appdata/il2cpp-functions.h | 1 + gui/tabs/host_tab.cpp | 40 ++++++++++++------- hooks/GameOptionsData.cpp | 2 - hooks/RoleManager.cpp | 77 +++++++++++++++++++++++++++++++++++-- hooks/RoleManager.hpp | 5 +++ hooks/_hooks.cpp | 4 ++ hooks/_hooks.h | 5 +-- user/state.hpp | 3 +- user/utility.cpp | 29 +++++++++++++- user/utility.h | 13 +++++++ 12 files changed, 158 insertions(+), 25 deletions(-) create mode 100644 hooks/RoleManager.hpp diff --git a/AmongUsMenu.vcxproj b/AmongUsMenu.vcxproj index e86617cc..1d618050 100644 --- a/AmongUsMenu.vcxproj +++ b/AmongUsMenu.vcxproj @@ -342,6 +342,7 @@ + diff --git a/AmongUsMenu.vcxproj.filters b/AmongUsMenu.vcxproj.filters index 755b031b..c5479e27 100644 --- a/AmongUsMenu.vcxproj.filters +++ b/AmongUsMenu.vcxproj.filters @@ -268,6 +268,9 @@ events + + hooks + hooks diff --git a/appdata/il2cpp-functions.h b/appdata/il2cpp-functions.h index e377d413..4fa1cfac 100644 --- a/appdata/il2cpp-functions.h +++ b/appdata/il2cpp-functions.h @@ -184,6 +184,7 @@ DO_APP_FUNC(void, TextMeshPro_SetOutlineColor, (TextMeshPro* __this, Color32 col DO_APP_FUNC(void, TMP_Text_set_text, (TMP_Text* __this, String* value, MethodInfo* method), "Unity.TextMeshPro, System.Void TMPro.TMP_Text::set_text(System.String)"); DO_APP_FUNC(Color32, Color32_op_Implicit, (Color c, MethodInfo* method), "UnityEngine.CoreModule, UnityEngine.Color32 UnityEngine.Color32::op_Implicit(UnityEngine.Color)"); +DO_APP_FUNC(void, RoleManager_SelectRoles, (RoleManager* __this, MethodInfo* method), "Assembly-CSharp, System.Void RoleManager::SelectRoles()"); DO_APP_FUNC(void, RoleManager_AssignRolesForTeam, (List_1_GameData_PlayerInfo_* players, RoleOptionsData* opts, RoleTeamTypes__Enum team, int32_t teamMax, Nullable_1_RoleTypes_ defaultRole, MethodInfo* method), "Assembly-CSharp, System.Void RoleManager::AssignRolesForTeam(System.Collections.Generic.List, RoleOptionsData, RoleTeamTypes, System.Int32, System.Nullable)"); DO_APP_FUNC(void, RoleManager_AssignRolesFromList, (List_1_GameData_PlayerInfo_* players, int32_t teamMax, List_1_RoleTypes_* roleList, int32_t* rolesAssigned, MethodInfo* method), "Assembly-CSharp, System.Void RoleManager::AssignRolesFromList(System.Collections.Generic.List, System.Int32, System.Collections.Generic.List, System.Int32&)"); DO_APP_FUNC(void, InnerNetClient_EnqueueDisconnect, (InnerNetClient* __this, DisconnectReasons__Enum reason, String* stringReason, MethodInfo* method), "Assembly-CSharp, System.Void InnerNet.InnerNetClient::EnqueueDisconnect(DisconnectReasons, System.String)"); diff --git a/gui/tabs/host_tab.cpp b/gui/tabs/host_tab.cpp index 6f3a52cb..fef7d2a4 100644 --- a/gui/tabs/host_tab.cpp +++ b/gui/tabs/host_tab.cpp @@ -32,14 +32,13 @@ namespace HostTab { State.impostors_amount = GetRoleCount((int)RoleType::Impostor); if (State.impostors_amount + State.shapeshifters_amount > maxImposterAmount) { - State.assignedRoles[index] = (int)RoleType::Crewmate; - State.impostors_amount--; - } - else if (State.shapeshifters_amount + State.impostors_amount > maxImposterAmount) - { - State.assignedRoles[index] = (int)RoleType::Engineer; - State.shapeshifters_amount--; + if(State.assignedRoles[index] == (int)RoleType::Shapeshifter) + State.assignedRoles[index] = (int)RoleType::Engineer; + else if(State.assignedRoles[index] == (int)RoleType::Impostor) + State.assignedRoles[index] = (int)RoleType::Random; } + State.shapeshifters_amount = GetRoleCount((int)RoleType::Shapeshifter); + State.impostors_amount = GetRoleCount((int)RoleType::Impostor); if (!IsInGame()) { @@ -49,12 +48,27 @@ namespace HostTab { auto vectors = roleRates->fields.entries[0].vector; for (auto iVector = 0; iVector < 32; iVector++) { - if (vectors[iVector].key == RoleTypes__Enum::Engineer && State.engineers_amount > vectors[iVector].value.MaxCount) - vectors[iVector].value.MaxCount = State.engineers_amount; - else if (vectors[iVector].key == RoleTypes__Enum::Scientist && State.scientists_amount > vectors[iVector].value.MaxCount) - vectors[iVector].value.MaxCount = State.scientists_amount; - else if (vectors[iVector].key == RoleTypes__Enum::Shapeshifter && State.shapeshifters_amount > vectors[iVector].value.MaxCount) - vectors[iVector].value.MaxCount = State.shapeshifters_amount; + if (vectors[iVector].key == RoleTypes__Enum::Engineer) + { + if(State.engineers_amount > 0) + vectors[iVector].value.Chance = 100; + if(State.engineers_amount > vectors[iVector].value.MaxCount) + vectors[iVector].value.MaxCount = State.engineers_amount; + } + else if (vectors[iVector].key == RoleTypes__Enum::Scientist) + { + if(State.scientists_amount > 0) + vectors[iVector].value.Chance = 100; + if(State.scientists_amount > vectors[iVector].value.MaxCount) + vectors[iVector].value.MaxCount = State.scientists_amount; + } + else if (vectors[iVector].key == RoleTypes__Enum::Shapeshifter) + { + if(State.shapeshifters_amount > 0) + vectors[iVector].value.Chance = 100; + if(State.shapeshifters_amount > vectors[iVector].value.MaxCount) + vectors[iVector].value.MaxCount = State.shapeshifters_amount; + } } } diff --git a/hooks/GameOptionsData.cpp b/hooks/GameOptionsData.cpp index c83e639f..0877a3ed 100644 --- a/hooks/GameOptionsData.cpp +++ b/hooks/GameOptionsData.cpp @@ -13,7 +13,6 @@ GameOptionsData* dGameOptionsData_Deserialize(BinaryReader* reader, MethodInfo* State.TaskBarUpdates = (int)gameOptions->fields.TaskBarMode; State.mapHostChoice = gameOptions->fields.MapId; State.impostors_amount = gameOptions->fields.NumImpostors; - State.RoleOptions = gameOptions->fields.RoleOptions; return gameOptions; } @@ -29,7 +28,6 @@ GameOptionsData* dGameOptionsData_Deserialize_1(MessageReader* reader, MethodInf State.TaskBarUpdates = (int)gameOptions->fields.TaskBarMode; State.mapHostChoice = gameOptions->fields.MapId; State.impostors_amount = gameOptions->fields.NumImpostors; - State.RoleOptions = gameOptions->fields.RoleOptions; return gameOptions; } \ No newline at end of file diff --git a/hooks/RoleManager.cpp b/hooks/RoleManager.cpp index e1bd1915..b7210641 100644 --- a/hooks/RoleManager.cpp +++ b/hooks/RoleManager.cpp @@ -1,4 +1,5 @@ #include "pch-il2cpp.h" +#include "RoleManager.hpp" #include "_hooks.h" #include "state.hpp" #include "logger.h" @@ -7,25 +8,95 @@ #include #include +void dRoleManager_SelectRoles(RoleManager* __this, MethodInfo* method) { + std::vector assignedPlayers; + auto allPlayers = GetAllPlayerControl(); + auto roleRates = RoleRates((*Game::pGameOptionsData)->fields.RoleOptions); + + AssignPreChosenRoles(roleRates, assignedPlayers); + AssignRoles(roleRates.ShapeshifterCount, roleRates.ShapeshifterChance, RoleTypes__Enum::Shapeshifter, allPlayers, assignedPlayers); + AssignRoles(roleRates.ImposterCount, 100, RoleTypes__Enum::Impostor, allPlayers, assignedPlayers); + AssignRoles(roleRates.ScientistCount, roleRates.ScientistChance, RoleTypes__Enum::Scientist, allPlayers, assignedPlayers); + AssignRoles(roleRates.EngineerCount, roleRates.EngineerChance, RoleTypes__Enum::Engineer, allPlayers, assignedPlayers); + AssignRoles(roleRates.MaxCrewmates, 100, RoleTypes__Enum::Crewmate, allPlayers, assignedPlayers); +} + void dRoleManager_AssignRolesForTeam(List_1_GameData_PlayerInfo_* players, RoleOptionsData* opts, RoleTeamTypes__Enum team, int32_t teamMax, Nullable_1_RoleTypes_ defaultRole, MethodInfo* method) { return RoleManager_AssignRolesForTeam(players, opts, team, teamMax, defaultRole, method); } void dRoleManager_AssignRolesFromList(List_1_GameData_PlayerInfo_* players, int32_t teamMax, List_1_RoleTypes_* roleList, int32_t* rolesAssigned, MethodInfo* method) { - dRoleManager_AssignPreChosenRoles(rolesAssigned); return RoleManager_AssignRolesFromList(players, teamMax, roleList, rolesAssigned, method); } -void dRoleManager_AssignPreChosenRoles(int32_t*& rolesAssigned) +void AssignPreChosenRoles(RoleRates& roleRates, std::vector& assignedPlayers) { for (int i = 0; i < State.assignedRolesPlayer.size(); i++) { auto role = State.assignedRoles[i]; auto player = State.assignedRolesPlayer[i]; + if (player == nullptr) + break; if (role == (int)RoleType::Random) continue; auto trueRole = GetRoleTypesEnum((RoleType)role); + if (trueRole == RoleTypes__Enum::Shapeshifter) + { + if (roleRates.ShapeshifterCount == 0) + continue; + roleRates.ShapeshifterCount--; + } + else if (trueRole == RoleTypes__Enum::Impostor) + { + if (roleRates.ImposterCount == 0) + continue; + roleRates.ImposterCount--; + } + else if (trueRole == RoleTypes__Enum::Scientist) + { + if (roleRates.ScientistCount == 0) + continue; + roleRates.ScientistCount--; + } + else if (trueRole == RoleTypes__Enum::Engineer) + { + if (roleRates.EngineerCount == 0) + continue; + roleRates.EngineerCount--; + } + PlayerControl_RpcSetRole(player, trueRole, NULL); - (*rolesAssigned)++; + assignedPlayers.push_back(player->fields.PlayerId); } } + +void AssignRoles(int& roleCount, int roleChance, RoleTypes__Enum role, std::vector& allPlayers, std::vector& assignedPlayers) +{ + if (roleCount == 0) + return; + + std::vector randomEngineers; + std::sample(allPlayers.begin(), allPlayers.end(), std::back_inserter(randomEngineers), roleCount, std::mt19937{ std::random_device{}() }); + for (auto player : randomEngineers) { + if (player == nullptr) { + break; + } + if (std::find(assignedPlayers.begin(), assignedPlayers.end(), player->fields.PlayerId) != assignedPlayers.end()) { + continue; + } + + if (roleChance < 100) + { + std::random_device dev; + std::mt19937 rng(dev()); + std::uniform_int_distribution dist100(1, 100); + auto chance = 100 - dist100(rng); + + if (chance <= roleChance) + continue; + } + + PlayerControl_RpcSetRole(player, role, NULL); + assignedPlayers.push_back(player->fields.PlayerId); + } +} \ No newline at end of file diff --git a/hooks/RoleManager.hpp b/hooks/RoleManager.hpp new file mode 100644 index 00000000..b13ae683 --- /dev/null +++ b/hooks/RoleManager.hpp @@ -0,0 +1,5 @@ +#pragma once +#include "utility.h" + +void AssignPreChosenRoles(RoleRates& roleRates, std::vector& assignedPlayers); +void AssignRoles(int& roleCount, int roleChance, RoleTypes__Enum role, std::vector& allPlayers, std::vector& assignedPlayers); \ No newline at end of file diff --git a/hooks/_hooks.cpp b/hooks/_hooks.cpp index 105bb9f7..2162f89b 100644 --- a/hooks/_hooks.cpp +++ b/hooks/_hooks.cpp @@ -95,6 +95,8 @@ void DetourInitilization() { HOOKFUNC(PlayerControl_CompleteTask); HOOKFUNC(PlayerControl_CmdReportDeadBody); HOOKFUNC(PlayerControl_ReportDeadBody); + HOOKFUNC(RoleManager_SelectRoles); + HOOKFUNC(RoleManager_AssignRolesForTeam); HOOKFUNC(RoleManager_AssignRolesFromList); HOOKFUNC(PlayerControl_HandleRpc); HOOKFUNC(Renderer_set_enabled); @@ -176,6 +178,8 @@ void DetourUninitialization() UNHOOKFUNC(PlayerControl_CompleteTask); UNHOOKFUNC(PlayerControl_CmdReportDeadBody); UNHOOKFUNC(PlayerControl_ReportDeadBody); + UNHOOKFUNC(RoleManager_SelectRoles); + UNHOOKFUNC(RoleManager_AssignRolesForTeam); UNHOOKFUNC(RoleManager_AssignRolesFromList); UNHOOKFUNC(PlayerControl_HandleRpc); UNHOOKFUNC(Renderer_set_enabled); diff --git a/hooks/_hooks.h b/hooks/_hooks.h index 1cf96e8f..a6dd9362 100644 --- a/hooks/_hooks.h +++ b/hooks/_hooks.h @@ -35,8 +35,6 @@ void dPlayerControl_FixedUpdate(PlayerControl* __this, MethodInfo* method); void dPlayerControl_MurderPlayer(PlayerControl* __this, PlayerControl* target, MethodInfo* method); void dPlayerControl_CmdReportDeadBody(PlayerControl* __this, GameData_PlayerInfo* target, MethodInfo* method); void dPlayerControl_ReportDeadBody(PlayerControl*__this, GameData_PlayerInfo* target, MethodInfo *method); -//void dPlayerControl_RpcSetRole(PlayerControl* __this, RoleTypes__Enum roleType, MethodInfo* method); -void dRoleManager_AssignRolesForTeam(List_1_GameData_PlayerInfo_* players, RoleOptionsData* opts, RoleTeamTypes__Enum team, int32_t teamMax, Nullable_1_RoleTypes_ defaultRole, MethodInfo* method); void dPlayerControl_RpcSyncSettings(PlayerControl* __this, GameOptionsData* gameOptions, MethodInfo* method); void dPlayerControl_HandleRpc(PlayerControl* __this, uint8_t callId, MessageReader* reader, MethodInfo* method); void dPlayerControl_Shapeshift(PlayerControl* __this, PlayerControl* target, bool animate, MethodInfo* method); @@ -69,8 +67,9 @@ void dEOSManager_ReallyBeginFlow(EOSManager* __this, MethodInfo* method); bool dEOSManager_IsFreechatAllowed(EOSManager* __this, MethodInfo* method); void dChatController_Update(ChatController* __this, MethodInfo* method); void dInnerNetClient_EnqueueDisconnect(InnerNetClient* __this, DisconnectReasons__Enum reason, String* stringReason, MethodInfo* method); +void dRoleManager_SelectRoles(RoleManager* __this, MethodInfo * method); +void dRoleManager_AssignRolesForTeam(List_1_GameData_PlayerInfo_* players, RoleOptionsData* opts, RoleTeamTypes__Enum team, int32_t teamMax, Nullable_1_RoleTypes_ defaultRole, MethodInfo* method); void dRoleManager_AssignRolesFromList(List_1_GameData_PlayerInfo_* players, int32_t teamMax, List_1_RoleTypes_* roleList, int32_t* rolesAssigned, MethodInfo* method); -void dRoleManager_AssignPreChosenRoles(int32_t*& rolesAssigned); void dPlayerPhysics_FixedUpdate (PlayerPhysics* __this, MethodInfo* method); // 55 8B EC 80 3D ? ? ? ? ? 75 14 68 ? ? ? ? E8 ? ? ? ? 83 C4 04 C6 05 ? ? ? ? ? 8B 45 0C 85 C0 74 3F 80 78 50 00 diff --git a/user/state.hpp b/user/state.hpp index e9be3144..41e1a07c 100644 --- a/user/state.hpp +++ b/user/state.hpp @@ -113,7 +113,6 @@ class Settings { int shapeshifters_amount = 0; int engineers_amount = 0; int scientists_amount = 0; - RoleOptionsData* RoleOptions = nullptr; bool Wallhack = false; bool FreeCam = false; @@ -150,7 +149,7 @@ class Settings { bool ShowUnityLogs = true; int LobbyTimer = -1; - + std::string userName = ""; enum MapType : uint8_t diff --git a/user/utility.cpp b/user/utility.cpp index d51f5c44..03e87273 100644 --- a/user/utility.cpp +++ b/user/utility.cpp @@ -15,6 +15,31 @@ int randi(int lo, int hi) { return lo + i; } +RoleRates::RoleRates(RoleOptionsData* roleOptions) { + auto roleRates = roleOptions->fields.roleRates; + if (roleRates->fields.count != 0) { + auto vectors = roleRates->fields.entries[0].vector; + for (auto iVector = 0; iVector < 32; iVector++) + { + if (vectors[iVector].key == RoleTypes__Enum::Engineer) + { + this->EngineerChance = vectors[iVector].value.Chance; + this->EngineerCount = vectors[iVector].value.MaxCount; + } + else if (vectors[iVector].key == RoleTypes__Enum::Scientist) + { + this->ScientistChance = vectors[iVector].value.Chance; + this->ScientistCount = vectors[iVector].value.MaxCount; + } + else if (vectors[iVector].key == RoleTypes__Enum::Shapeshifter) + { + this->ShapeshifterChance = vectors[iVector].value.Chance; + this->ShapeshifterCount = vectors[iVector].value.MaxCount; + } + } + } +} + PlayerSelection::PlayerSelection() { this->hasValue = false; @@ -377,7 +402,7 @@ const char* TranslateTaskTypes(TaskTypes__Enum taskType) { "Inspect Sample", "Empty Chute", "Empty Garbage", "Align Engine Output", "Fix Wiring", "Calibrate Distributor", "Divert Power", "Unlock Manifolds", "Reset Reactor", "Fix Lights", "Clean O2 Filter", "Fix Communications", "Restore Oxygen", "Stabilize Steering", "Assemble Artifact", "Sort Samples", "Measure Weather", "Enter ID Code", "Buy Beverage", "Process Data", "Run Diagnostics", "Water Plants", "Monitor Oxygen", "Store Artifacts", "Fill Canisters", "Activate Weather Nodes", "Insert Keys", - "Reset Seismic Stabilizers", "Scan Boarding Pass", "Open Waterways", "Replace Water Jug", "Repair Drill", "Align Telecopse", "Record Temperature", "Reboot Wifi", + "Reset Seismic Stabilizers", "Scan Boarding Pass", "Open Waterways", "Replace Water Jug", "Repair Drill", "Align Telecopse", "Record Temperature", "Reboot Wifi", "Polish Ruby", "Reset Breakers", "Decontaminate", "Make Burger", "Unlock Safe", "Sort Records", "Put Away Pistols", "Fix Shower", "Clean Toilet", "Dress Mannequin", "Pick Up Towels", "Rewind Tapes", "Start Fans", "Develop Photos", "Get Biggol Sword", "Put Away Rifles", "Stop Charles", "Vent Cleaning"}; return TASK_TRANSLATIONS[(uint8_t)taskType]; @@ -387,7 +412,7 @@ const char* TranslateTaskTypes(TaskTypes__Enum taskType) { const char* TranslateSystemTypes(SystemTypes__Enum systemType) { static const char* const SYSTEM_TRANSLATIONS[] = { "Hallway", "Storage", "Cafeteria", "Reactor", "Upper Engine", "Navigation", "Admin", "Electrical", "Oxygen", "Shields", "MedBay", "Security", "Weapons", "Lower Engine", "Communications", "Ship Tasks", "Doors", "Sabotage", "Decontamination", "Launchpad", "Locker Room", "Laboratory", - "Balcony", "Office", "Greenhouse", "Dropship", "Decontamination", "Outside", "Specimen Room", "Boiler Room", "Vault Room", "Cockpit", "Armory", "Kitchen", "Viewing Deck", + "Balcony", "Office", "Greenhouse", "Dropship", "Decontamination", "Outside", "Specimen Room", "Boiler Room", "Vault Room", "Cockpit", "Armory", "Kitchen", "Viewing Deck", "Hall Of Portraits", "Cargo Bay", "Ventilation", "Showers", "Engine Room", "The Brig", "Meeting Room", "Records Room", "Lounge Room", "Gap Room", "Main Hall", "Medical" }; return SYSTEM_TRANSLATIONS[(uint8_t)systemType]; } diff --git a/user/utility.h b/user/utility.h index 1235aaf2..ab3e1839 100644 --- a/user/utility.h +++ b/user/utility.h @@ -28,6 +28,19 @@ enum RoleType Shapeshifter = 5, }; +class RoleRates { +public: + int ImposterCount = 0; + int ShapeshifterCount = 0; + int ShapeshifterChance = 0; + int ScientistCount = 0; + int ScientistChance = 0; + int EngineerCount = 0; + int EngineerChance = 0; + int MaxCrewmates = 15; + RoleRates(RoleOptionsData* roleOptions); +}; + class PlayerSelection { bool hasValue; int32_t clientId;