Skip to content

Commit

Permalink
Feature/SeeProtections (#358)
Browse files Browse the repository at this point in the history
* #258: [Feature] Show Protections

We can see which players are protected to avoid wasting kill chances.

* Fix NullPointerException in HudManager_Update
  • Loading branch information
cddjr committed May 1, 2022
1 parent 828c088 commit 46b2dc0
Show file tree
Hide file tree
Showing 11 changed files with 163 additions and 20 deletions.
7 changes: 6 additions & 1 deletion appdata/il2cpp-functions.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ DO_APP_FUNC(void, Camera_set_orthographicSize, (Camera* __this, float value, Met
DO_APP_FUNC(float, Camera_get_orthographicSize, (Camera* __this, MethodInfo* method), "UnityEngine.CoreModule, System.Single UnityEngine.Camera::get_orthographicSize()");
DO_APP_FUNC(Color, SpriteRenderer_get_color, (SpriteRenderer* __this, MethodInfo* method), "UnityEngine.CoreModule, UnityEngine.Color UnityEngine.SpriteRenderer::get_color()");
DO_APP_FUNC(float, Time_get_fixedDeltaTime, (MethodInfo* method), "UnityEngine.CoreModule, System.Single UnityEngine.Time::get_fixedDeltaTime()");
DO_APP_FUNC(float, Time_get_realtimeSinceStartup, (MethodInfo* method), "UnityEngine.CoreModule, System.Single UnityEngine.Time::get_realtimeSinceStartup()");
DO_APP_FUNC(float, Time_get_time, (MethodInfo* method), "UnityEngine.CoreModule, System.Single UnityEngine.Time::get_time()");

DO_APP_FUNC(int32_t, Screen_get_width, (MethodInfo* method), "UnityEngine.CoreModule, System.Int32 UnityEngine.Screen::get_width()");
DO_APP_FUNC(int32_t, Screen_get_height, (MethodInfo* method), "UnityEngine.CoreModule, System.Int32 UnityEngine.Screen::get_height()");
Expand Down Expand Up @@ -200,4 +202,7 @@ DO_APP_FUNC(void, InnerNetClient_EnqueueDisconnect, (InnerNetClient* __this, Dis

DO_APP_FUNC(void, PlayerPhysics_FixedUpdate, (PlayerPhysics* __this, MethodInfo* method), "Assembly-CSharp, System.Void PlayerPhysics::FixedUpdate()");

DO_APP_FUNC(bool, SaveManager_GetPurchase, (String* itemKey, String* bundleKey, MethodInfo* method), "Assembly-CSharp, System.Boolean SaveManager::GetPurchase(System.String, System.String)");
DO_APP_FUNC(bool, SaveManager_GetPurchase, (String* itemKey, String* bundleKey, MethodInfo* method), "Assembly-CSharp, System.Boolean SaveManager::GetPurchase(System.String, System.String)");

DO_APP_FUNC(void, PlayerControl_TurnOnProtection, (PlayerControl* __this, bool visible, int32_t colorId, MethodInfo* method), "Assembly-CSharp, System.Void PlayerControl::TurnOnProtection(System.Boolean, System.Int32)");
DO_APP_FUNC(void, PlayerControl_RemoveProtection, (PlayerControl* __this, MethodInfo* method), "Assembly-CSharp, System.Void PlayerControl::RemoveProtection()");
79 changes: 73 additions & 6 deletions appdata/il2cpp-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -2974,11 +2974,15 @@ namespace app
#pragma region Color32
struct Color32
{
int32_t rgba;
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
union {
int32_t rgba;
struct {
uint8_t r;
uint8_t g;
uint8_t b;
uint8_t a;
};
};
};
#pragma endregion

Expand Down Expand Up @@ -8106,6 +8110,69 @@ namespace app
};
#pragma endregion

#pragma region List_1_RoleEffectAnimation_
struct __declspec(align(4)) List_1_RoleEffectAnimation___Fields {
struct RoleEffectAnimation__Array *_items;
int32_t _size;
int32_t _version;
struct Object *_syncRoot;
};

struct List_1_RoleEffectAnimation_ {
void *klass;
MonitorData *monitor;
struct List_1_RoleEffectAnimation___Fields fields;
};

#if defined(_CPLUSPLUS_)
enum class RoleEffectAnimation_EffectType__Enum : int32_t {
Default = 0x00000000,
ProtectLoop = 0x00000001,
Shapeshift = 0x00000002,
};

#else
enum RoleEffectAnimation_EffectType__Enum {
RoleEffectAnimation_EffectType__Enum_Default = 0x00000000,
RoleEffectAnimation_EffectType__Enum_ProtectLoop = 0x00000001,
RoleEffectAnimation_EffectType__Enum_Shapeshift = 0x00000002,
};

#endif
#pragma endregion

#pragma region RoleEffectAnimation
struct RoleEffectAnimation__Fields {
struct MonoBehaviour__Fields _;
#if defined(_CPLUSPLUS_)
RoleEffectAnimation_EffectType__Enum effectType;
#else
int32_t effectType;
#endif
struct AnimationClip* Clip;
struct SpriteAnim* Animator;
struct Action* MidAnimCB;
struct SpriteRenderer* Renderer;
struct AudioClip* UseSound;
struct AudioSource* AudioSource;
struct PlayerControl* parent;
};

struct RoleEffectAnimation {
void* klass;
MonitorData* monitor;
struct RoleEffectAnimation__Fields fields;
};

struct RoleEffectAnimation__Array {
void* klass;
MonitorData* monitor;
Il2CppArrayBounds* bounds;
il2cpp_array_size_t max_length;
struct RoleEffectAnimation* vector[32];
};
#pragma endregion

#pragma region List_1_PlayerTask_
struct __declspec(align(4)) List_1_PlayerTask___Fields
{
Expand Down Expand Up @@ -8564,7 +8631,7 @@ namespace app
struct Vector3 defaultPlayerScale;
void* ScannerAnims;
void* ScannersImages;
void* currentRoleAnimations;
struct List_1_RoleEffectAnimation_* currentRoleAnimations;
void* closest;
bool isNew;
bool isDummy;
Expand Down
3 changes: 1 addition & 2 deletions gui/radar.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,7 @@ namespace Radar {
if (playerData->fields.IsDead)
return ImGui::ColorConvertFloat4ToU32(AmongUsColorToImVec4(app::Palette__TypeInfo->static_fields->HalfWhite));
else if (State.RevealRoles
&& playerData->fields.Role != nullptr
&& playerData->fields.Role->fields.TeamType == RoleTeamTypes__Enum::Impostor)
&& PlayerIsImpostor(playerData))
return ImGui::ColorConvertFloat4ToU32(AmongUsColorToImVec4(GetRoleColor(playerData->fields.Role)));
else
return ImGui::ColorConvertFloat4ToU32(ImVec4(0, 0, 0, 0));
Expand Down
46 changes: 46 additions & 0 deletions gui/tabs/self_tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,10 @@
#include "gui-helpers.hpp"
#include "utility.h"
#include "state.hpp"
#include "logger.h"

namespace SelfTab {
void _SeeProtect();
void Render() {
if (ImGui::BeginTabItem("Self")) {
ImGui::Dummy(ImVec2(4, 4) * State.dpiScale);
Expand Down Expand Up @@ -67,6 +69,13 @@ namespace SelfTab {
if (ImGui::Checkbox("See Ghosts", &State.ShowGhosts)) {
State.Save();
}

if (ImGui::Checkbox("See Protections", &State.ShowProtections))
{
State.Save();
_SeeProtect();
}

if (ImGui::Checkbox("Unlock Vents", &State.UnlockVents)) {
State.Save();
}
Expand Down Expand Up @@ -96,4 +105,41 @@ namespace SelfTab {
ImGui::EndTabItem();
}
}

void _SeeProtect() {
if (!IsInGame())
return;
auto self = GetPlayerData(*Game::pLocalPlayer);
if (self->fields.IsDead)
return;
if (PlayerIsImpostor(self)
&& (*Game::pGameOptionsData)->fields.RoleOptions->fields.ImpostorsCanSeeProtect)
return;
float& _Duration = (*Game::pGameOptionsData)->fields.RoleOptions->fields.ProtectionDurationSeconds;
const float ProtectionDurationSeconds = _Duration;
for (auto player : GetAllPlayerControl()) {
if (!player->fields.protectedByGuardian)
continue;
//if (GetPlayerData(player)->fields.IsDead)
// continue;
bool isPlaying = false;
for (auto anim : il2cpp::List(player->fields.currentRoleAnimations))
if (anim->fields.effectType == RoleEffectAnimation_EffectType__Enum::ProtectLoop) {
isPlaying = true;
break;
}
if (isPlaying == State.ShowProtections)
continue;
if (!State.ShowProtections)
app::PlayerControl_RemoveProtection(player, nullptr);
do {
std::lock_guard lock(State.protectMutex);
auto pair = State.protectMonitor[player->fields.PlayerId];
_Duration = ProtectionDurationSeconds - (app::Time_get_time(nullptr) - pair.second);
if (_Duration > 0.f)
app::PlayerControl_TurnOnProtection(player, State.ShowProtections, pair.first, nullptr);
_Duration = ProtectionDurationSeconds;
} while (0);
}
}
}
7 changes: 4 additions & 3 deletions hooks/HudManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,18 @@ void dHudManager_Update(HudManager* __this, MethodInfo* method) {

if (!State.InMeeting)
{
app::RoleBehaviour *playerRole = localData->fields.Role;
app::RoleBehaviour *playerRole = localData->fields.Role; // Nullable
app::RoleTypes__Enum role = playerRole != nullptr ? playerRole->fields.Role : app::RoleTypes__Enum::Crewmate;
GameObject* ImpostorVentButton = app::Component_get_gameObject((Component_1*)__this->fields.ImpostorVentButton, NULL);

if (playerRole->fields.Role == RoleTypes__Enum::Engineer && State.UnlockVents)
if (role == RoleTypes__Enum::Engineer && State.UnlockVents)
{
app::EngineerRole *engineerRole = (app::EngineerRole*)playerRole;
if (engineerRole->fields.cooldownSecondsRemaining > 0.0f)
engineerRole->fields.cooldownSecondsRemaining = 0.01f; //This will be deducted below zero on the next FixedUpdate call
engineerRole->fields.inVentTimeRemaining = 30.0f; //Can be anything as it will always be written
}
else if(playerRole->fields.Role == RoleTypes__Enum::GuardianAngel)
else if(role == RoleTypes__Enum::GuardianAngel)
{
app::GameObject_SetActive(ImpostorVentButton, false, nullptr);
}
Expand Down
24 changes: 18 additions & 6 deletions hooks/PlayerControl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -343,15 +343,27 @@ void dGameObject_SetActive(GameObject* __this, bool value, MethodInfo* method)
}

void dPlayerControl_Shapeshift(PlayerControl* __this, PlayerControl* target, bool animate, MethodInfo* method) {
std::lock_guard<std::mutex> replayLock(Replay::replayEventMutex);
State.rawEvents.push_back(std::make_unique<ShapeShiftEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
State.liveReplayEvents.push_back(std::make_unique<ShapeShiftEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
{
std::lock_guard<std::mutex> replayLock(Replay::replayEventMutex);
State.rawEvents.push_back(std::make_unique<ShapeShiftEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
State.liveReplayEvents.push_back(std::make_unique<ShapeShiftEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
}
PlayerControl_Shapeshift(__this, target, animate, method);
}

void dPlayerControl_ProtectPlayer(PlayerControl* __this, PlayerControl* target, int32_t colorId, MethodInfo* method) {
std::lock_guard<std::mutex> replayLock(Replay::replayEventMutex);
State.rawEvents.push_back(std::make_unique<ProtectPlayerEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
State.liveReplayEvents.push_back(std::make_unique<ProtectPlayerEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
{
std::lock_guard<std::mutex> replayLock(Replay::replayEventMutex);
State.rawEvents.push_back(std::make_unique<ProtectPlayerEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
State.liveReplayEvents.push_back(std::make_unique<ProtectPlayerEvent>(GetEventPlayerControl(__this).value(), GetEventPlayerControl(target).value()));
}
PlayerControl_ProtectPlayer(__this, target, colorId, method);
}

void dPlayerControl_TurnOnProtection(PlayerControl* __this, bool visible, int32_t colorId, MethodInfo* method) {
{
std::lock_guard lock(State.protectMutex);
app::PlayerControl_TurnOnProtection(__this, visible || State.ShowProtections, colorId, method);
State.protectMonitor[__this->fields.PlayerId] = { colorId, app::Time_get_time(nullptr) };
}
}
2 changes: 2 additions & 0 deletions hooks/_hooks.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ void DetourInitilization() {
HOOKFUNC(InnerNetClient_EnqueueDisconnect);
HOOKFUNC(PlayerPhysics_FixedUpdate);
HOOKFUNC(SaveManager_GetPurchase);
HOOKFUNC(PlayerControl_TurnOnProtection);


if (!HookFunction(&(PVOID&)oPresent, dPresent, "D3D_PRESENT_FUNCTION")) return;
Expand Down Expand Up @@ -234,6 +235,7 @@ void DetourUninitialization()
UNHOOKFUNC(EOSManager_IsFreechatAllowed);
UNHOOKFUNC(ChatController_Update);
UNHOOKFUNC(InnerNetClient_EnqueueDisconnect);
UNHOOKFUNC(PlayerControl_TurnOnProtection);

if (DetourDetach(&(PVOID&)oPresent, dPresent) != 0) return;

Expand Down
3 changes: 2 additions & 1 deletion hooks/_hooks.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,4 +70,5 @@ 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 dPlayerPhysics_FixedUpdate (PlayerPhysics* __this, MethodInfo* method);
bool dSaveManager_GetPurchase(String* itemKey, String* bundleKey, MethodInfo* method);
bool dSaveManager_GetPurchase(String* itemKey, String* bundleKey, MethodInfo* method);
void dPlayerControl_TurnOnProtection(PlayerControl* __this, bool visible, int32_t colorId, MethodInfo* method);
6 changes: 5 additions & 1 deletion used_types.txt
Original file line number Diff line number Diff line change
Expand Up @@ -207,4 +207,8 @@ List_1_HatData_
GameOptionsDataParent
StatsManager_Stats
SkinLayer
VoteSpreader__Fields
VoteSpreader__Fields
RoleOptionsData__Fields
RoleEffectAnimation_EffectType__Enum
RoleEffectAnimation__Fields
PlayerControl__Fields
2 changes: 2 additions & 0 deletions user/state.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ void Settings::Load() {
j.at("AdjustByDPI").get_to(this->AdjustByDPI);

j.at("RevealVotes").get_to(this->RevealVotes);
j.at("ShowProtections").get_to(this->ShowProtections);

j.at("ShowConsole").get_to(this->ShowConsole);
j.at("ShowUnityLogs").get_to(this->ShowUnityLogs);
Expand Down Expand Up @@ -130,6 +131,7 @@ void Settings::Save() {

{"RevealVotes", this->RevealVotes},
{"AdjustByDPI", this->AdjustByDPI},
{"ShowProtections", this->ShowProtections},

{"ShowConsole", this->ShowConsole},
{"ShowUnityLogs", this->ShowUnityLogs}
Expand Down
4 changes: 4 additions & 0 deletions user/state.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,10 @@ class Settings {
bool UnlockVents = false;
bool ShowGhosts = false;

bool ShowProtections = false;
std::map<uint8_t/*PlayerId*/, std::pair<int32_t/*ColorId*/, float/*Time*/>> protectMonitor;
std::mutex protectMutex;

bool RevealVotes = false;

bool RevealRoles = false;
Expand Down

0 comments on commit 46b2dc0

Please sign in to comment.