Skip to content

Commit

Permalink
Simplify Dictionary/Array/List operations and optimize code (#350)
Browse files Browse the repository at this point in the history
* Simplify Dictionary/Array/List operations and optimize code

Now we can use for_each to iterate over il2cpp's Dictionary, Array and List objects

* use il2cpp_thread_attach to prevent fatal unmanaged exceptions
  • Loading branch information
cddjr committed Apr 15, 2022
1 parent 6767ed5 commit 9345ac1
Show file tree
Hide file tree
Showing 19 changed files with 242 additions and 324 deletions.
23 changes: 16 additions & 7 deletions appdata/il2cpp-types.h
Original file line number Diff line number Diff line change
Expand Up @@ -8967,27 +8967,27 @@ namespace app
};
#pragma endregion

#pragma region List_SpriteRenderer_
struct __declspec(align(4)) List_SpriteRenderer__Fields
#pragma region List_1_UnityEngine_SpriteRenderer_
struct __declspec(align(4)) List_1_UnityEngine_SpriteRenderer___Fields
{
struct SpriteRenderer__Array* _items;
int32_t _size;
int32_t _version;
struct Object* _syncRoot;
};

struct List_SpriteRenderer_
struct List_1_UnityEngine_SpriteRenderer_
{
void* klass;
void* monitor;
struct List_SpriteRenderer__Fields fields;
struct List_1_UnityEngine_SpriteRenderer___Fields fields;
};
#pragma endregion

#pragma region VoteSpreader
struct VoteSpreader__Fields {
struct MonoBehaviour__Fields _;
struct List_SpriteRenderer_* Votes;
struct List_1_UnityEngine_SpriteRenderer_* Votes;
void* VoteRange;
int32_t maxVotesBeforeSmoosh;
float CounterY;
Expand All @@ -8996,7 +8996,7 @@ namespace app

struct VoteSpreader {
struct VoteSpreader__Class* klass;
void* monitor;
MonitorData* monitor;
struct VoteSpreader__Fields fields;
};

Expand All @@ -9009,7 +9009,8 @@ namespace app

struct VoteSpreader__Class {
Il2CppClass_0 _0;
void* static_fields;
Il2CppRuntimeInterfaceOffsetPair* interfaceOffsets;
struct VoteSpreader__StaticFields* static_fields;
const Il2CppRGCTXData* rgctx_data;
Il2CppClass_1 _1;
struct VoteSpreader__VTable vtable;
Expand Down Expand Up @@ -10908,6 +10909,14 @@ namespace app
struct List_1_GameData_PlayerInfo___Fields fields;
};

struct GameData_PlayerInfo__Array {
struct GameData_PlayerInfo__Array__Class* klass;
MonitorData* monitor;
Il2CppArrayBounds* bounds;
il2cpp_array_size_t max_length;
struct GameData_PlayerInfo* vector[32];
};

struct List_1_GameData_PlayerInfo___VTable
{
VirtualInvokeData Equals;
Expand Down
9 changes: 4 additions & 5 deletions events/_events.h
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
#include <optional>
#include <chrono>
#include <format>
#include "il2cpp-helpers.h"

using namespace app;

Expand Down Expand Up @@ -52,19 +53,17 @@ struct EVENT_PLAYER {
playerId = playerInfo->fields.PlayerId;

// rolling GetPlayerOutfit into this func to avoid circular dependencies
GameData_PlayerOutfit* outfit = 0;
auto arr = playerInfo->fields.Outfits->fields.entries;
for (int i = 0; i < playerInfo->fields.Outfits->fields.count; i++)
GameData_PlayerOutfit* outfit = nullptr;
for (auto& kvp : il2cpp::Dictionary(playerInfo->fields.Outfits))
{
auto kvp = arr->vector[i];
if (kvp.key == PlayerOutfitType__Enum::Default)
{
outfit = kvp.value;
break;
}
}

if (outfit != 0)
if (outfit != nullptr)
{
colorId = outfit->fields.ColorId;
playerName = convert_from_string(outfit->fields._playerName);
Expand Down
60 changes: 30 additions & 30 deletions framework/il2cpp-helpers.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,46 +233,46 @@ void output_assembly_methods(const Il2CppAssembly* assembly) {
output_class_methods(const_cast<Il2CppClass*>(il2cpp_image_get_class(assembly->image, i)));
}
}

class ScopedThreadAttacher
{
public:
ScopedThreadAttacher() : m_AttachedThread(nullptr) {
m_AttachedThread = il2cpp_thread_attach(il2cpp_domain_get());
}
~ScopedThreadAttacher() {
if (m_AttachedThread)
il2cpp_thread_detach(m_AttachedThread);
}

private:
Il2CppThread* m_AttachedThread;
};

bool cctor_finished(Il2CppClass* klass)
{
STREAM_DEBUG("Class " << klass->name << " Has Static Constructor: " << (klass->has_cctor ? "true" : "false"));
// make sure we're attached before we call il2cpp_runtime_class_init
ScopedThreadAttacher managedThreadAttached;
if (!klass->initialized) {
// enforce to call 'Class::Init'
auto size = il2cpp_class_get_bitmap_size(klass);
std::vector<size_t> buffer(size / sizeof(size_t));
il2cpp_class_get_bitmap(klass, buffer.data());
if (!klass->initialized) {
STREAM_ERROR("Class " << klass->name << " il2cpp_class_get_bitmap() failure");
return false;
}
}

constexpr int CCTOR_TIMEOUT = 5000; //Time in milliseconds to wait for class to initialize
int timeout = CCTOR_TIMEOUT; //Five second timeout
STREAM_DEBUG("Class " << klass->name << " Has Static Constructor: " << (klass->has_cctor ? "true" : "false"));
//First we wait for the class itself to finish initializing
while (!(klass->initialized || klass->initialized_and_no_error) && (timeout >= 0)) //Bails on either initialization setting
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
timeout -= 10;
}

if (timeout <= 0)
{
STREAM_DEBUG("Class " << klass->name << " Timed out waiting for initialized || initialized_and_no_error");
return false;
}
//Then we wait for the static constructor to finish
timeout = CCTOR_TIMEOUT;

if (!klass->has_cctor) return true; //If we don't have a static constructor, no need to wait
//If we don't have a static constructor, no need to wait
if (!klass->has_cctor) return true;
if (!klass->cctor_finished) {
// enforce to call 'Runtime::ClassInit'
il2cpp_runtime_class_init(klass);
if (!klass->cctor_finished) {
STREAM_ERROR("Class " << klass->name << " il2cpp_runtime_class_init() failure");
return false;
}
}
while (!klass->cctor_finished && (timeout >= 0))
{
std::this_thread::sleep_for(std::chrono::milliseconds(10));
timeout -= 10;
}
if (timeout <= 0)
{
STREAM_DEBUG("Class " << klass->name << " Timed out waiting for cctor_finished");
}
return (timeout > 0);
return true;
}
53 changes: 52 additions & 1 deletion framework/il2cpp-helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,4 +11,55 @@ Il2CppClass* get_class(std::string classSignature);
std::string get_method_description(const MethodInfo* methodInfo);
void output_class_methods(Il2CppClass* klass);
void output_assembly_methods(const Il2CppAssembly* assembly);
bool cctor_finished(Il2CppClass* klass);
bool cctor_finished(Il2CppClass* klass);

namespace app {
namespace il2cpp {
template<typename E>
class Dictionary {
public:
Dictionary(E* dict) : _Ptr(dict) {}
size_t size() const {
auto pDict = (Dictionary_2_SystemTypes_ISystemType_*)_Ptr;
return ((size_t(*)(void*, const void*))(pDict->klass->vtable.get_Count.methodPtr))(pDict, pDict->klass->vtable.get_Count.method);
}
auto begin() { return _Ptr->fields.entries->vector; }
auto end() { return _Ptr->fields.entries->vector + size(); }
protected:
E* _Ptr;
};
template<typename E>
class Array {
public:
Array(E* arr) : _Ptr(arr) {}
size_t size() const {
if (_Ptr->bounds)
return _Ptr->bounds->length;
return _Ptr->max_length;
}
auto begin() { return _Ptr->vector; }
auto end() { return _Ptr->vector + size(); }
auto& operator[](const size_t _Pos) { return begin()[_Pos]; }
protected:
E* _Ptr;
};
template<typename E>
class List {
public:
List(E* list) : _Ptr(list) {}
size_t size() const {
auto pList = (List_1_PlayerTask_*)_Ptr;
return ((size_t(*)(void*, const void*))(pList->klass->vtable.get_Count.methodPtr))(pList, pList->klass->vtable.get_Count.method);
}
auto clear() {
auto pList = (List_1_PlayerTask_*)_Ptr;
((void(*)(void*, const void*))(pList->klass->vtable.Clear.methodPtr))(pList, pList->klass->vtable.get_Count.method);
}
auto begin() { return _Ptr->fields._items->vector; }
auto end() { return _Ptr->fields._items->vector + size(); }
auto& operator[](const size_t _Pos) { return begin()[_Pos]; }
protected:
E* _Ptr;
};
}
}
60 changes: 27 additions & 33 deletions gui/console.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,56 +57,50 @@ namespace ConsoleGui
ImGui::EndChild();
ImGui::Separator();
ImGui::BeginChild("console#scroll", ImVec2(511, 270) * State.dpiScale, true, ImGuiWindowFlags_AlwaysVerticalScrollbar);

// pre-processing of filters
bool isUsingEventFilter = false, isUsingPlayerFilter = false;
for (const auto& pair : ConsoleGui::event_filter) {
if (pair.second) {
isUsingEventFilter = true;
break;
}
}
for (auto& pair : ConsoleGui::player_filter) {
if (pair.second && pair.first.has_value()) {
isUsingPlayerFilter = true;
break;
}
}

std::lock_guard<std::mutex> replayLock(Replay::replayEventMutex);
size_t i = State.liveReplayEvents.size() - 1;
if (i >= 0) {
for (std::vector<std::unique_ptr<EventInterface>>::reverse_iterator rit = State.liveReplayEvents.rbegin(); rit != State.liveReplayEvents.rend(); ++rit, --i) {
for (auto rit = State.liveReplayEvents.rbegin(); rit != State.liveReplayEvents.rend(); ++rit, --i) {
EventInterface* evt = (*rit).get();
if (evt == NULL)
{
STREAM_ERROR("State.rawEvents[" << i << "] was NULL (rawEvents.size(): " << State.liveReplayEvents.size() << ")");
STREAM_ERROR("State.liveReplayEvents[" << i << "] was NULL (liveReplayEvents.size(): " << State.liveReplayEvents.size() << ")");
continue;
}
if (evt->getType() == EVENT_WALK)
continue;

bool typeFound = false, anyTypeFilterSelected = false;
for (size_t n = 0; n < ConsoleGui::event_filter.size(); n++) {
if (ConsoleGui::event_filter[n].second
&& (EVENT_TYPES)n == evt->getType()) {
typeFound = true;
anyTypeFilterSelected = true;
break;
}
else if (ConsoleGui::event_filter[n].second)
anyTypeFilterSelected = true;
}

if (!typeFound && anyTypeFilterSelected)
if (isUsingEventFilter && ConsoleGui::event_filter.at((size_t)evt->getType()).second == false)
continue;

bool playerFound = false, anyPlayerFilterSelected = false;
for (auto player : ConsoleGui::player_filter) {
if (player.second
&& player.first.has_value()
&& player.first.get_PlayerId() == evt->getSource().playerId)
{
playerFound = true;
anyPlayerFilterSelected = true;
break;
}
else if (player.second) // if no player was selected we want to make sure that any filter was set in the first place before we continue
anyPlayerFilterSelected = true;
if (isUsingPlayerFilter) {
if (evt->getSource().playerId < 0 || evt->getSource().playerId >= ConsoleGui::player_filter.size())
continue;
auto& p = ConsoleGui::player_filter.at(evt->getSource().playerId);
if (p.second == false)
continue;
if (!p.first.has_value())
continue;
}

if (!playerFound && anyPlayerFilterSelected)
continue;

evt->ColoredEventOutput();
ImGui::SameLine();
evt->Output();
}
}
ImGui::EndChild();
ImGui::End();
}
Expand Down
8 changes: 4 additions & 4 deletions gui/tabs/debug_tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ namespace DebugTab {

if (ImGui::CollapsingHeader("Colors##debug"))
{
app::Color32__Array* colArr = app::Palette__TypeInfo->static_fields->PlayerColors;
CorrectedColor32* colArr_raw = (CorrectedColor32*)app::Palette__TypeInfo->static_fields->PlayerColors->vector;
int length = colArr->max_length;
for (int i = 0; i < length; i++)
il2cpp::Array colArr = app::Palette__TypeInfo->static_fields->PlayerColors;
CorrectedColor32* colArr_raw = (CorrectedColor32*)colArr.begin();
size_t length = colArr.size();
for (size_t i = 0; i < length; i++)
{
CorrectedColor32 col = colArr_raw[i];
ImVec4 conv_col = AmongUsColorToImVec4(col);
Expand Down
31 changes: 13 additions & 18 deletions gui/tabs/host_tab.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,35 +44,30 @@ namespace HostTab {

if (!IsInGame())
{
auto roleRates = (*Game::pGameOptionsData)->fields.RoleOptions->fields.roleRates;
if(roleRates->fields.count != 0)
{
auto vectors = roleRates->fields.entries->vector;
for (size_t iVector = 0; iVector < roleRates->fields.entries->max_length; iVector++)
for (auto& kvp : il2cpp::Dictionary((*Game::pGameOptionsData)->fields.RoleOptions->fields.roleRates))
{
if (vectors[iVector].key == RoleTypes__Enum::Engineer)
if (kvp.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;
kvp.value.Chance = 100;
if(State.engineers_amount > kvp.value.MaxCount)
kvp.value.MaxCount = State.engineers_amount;
}
else if (vectors[iVector].key == RoleTypes__Enum::Scientist)
else if (kvp.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;
kvp.value.Chance = 100;
if(State.scientists_amount > kvp.value.MaxCount)
kvp.value.MaxCount = State.scientists_amount;
}
else if (vectors[iVector].key == RoleTypes__Enum::Shapeshifter)
else if (kvp.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;
kvp.value.Chance = 100;
if(State.shapeshifters_amount > kvp.value.MaxCount)
kvp.value.MaxCount = State.shapeshifters_amount;
}
}
}

if((*Game::pGameOptionsData)->fields._.numImpostors <= State.impostors_amount + State.shapeshifters_amount)
(*Game::pGameOptionsData)->fields._.numImpostors = State.impostors_amount + State.shapeshifters_amount;
Expand Down

0 comments on commit 9345ac1

Please sign in to comment.