├── plague-scpsl.vcxproj.user
├── pointer.h
├── utils.h
├── offsets.h
├── utils.cpp
├── memory.h
├── math.h
├── plague-scpsl.vcxproj.filters
├── plague-scpsl.sln
├── readme.md
├── veh.h
├── il2cpp.h
├── il2cpp.cpp
├── main.cpp
└── plague-scpsl.vcxproj
/plague-scpsl.vcxproj.user:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
--------------------------------------------------------------------------------
/pointer.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | // x86 support
3 | #ifndef POINTER
4 | #ifdef _WIN64
5 | typedef unsigned long long pointer;
6 | #else
7 | typedef unsigned int pointer;
8 | #endif
9 | #define POINTER 1
10 | #endif
--------------------------------------------------------------------------------
/utils.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "math.h"
3 | #include
4 | #include
5 |
6 | float GetDistance(vec3 p1, vec3 p2);
7 | bool WorldToScreen(Matrix &matrix, vec3 &from, vec2 &to, int ScreenCenterX, int ScreenCenterY);
8 | template T Read(uint64_t addr)
9 | {
10 | T Novalue = {};
11 | if (!IsBadReadPtr((const void*)addr, sizeof(T)))
12 | {
13 | return *(T*)(addr);
14 | }
15 | else
16 | {
17 | return Novalue;
18 | }
19 | };
20 |
--------------------------------------------------------------------------------
/offsets.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include "pointer.h"
3 |
4 | namespace offset {
5 |
6 | // il2cpp
7 | constexpr pointer create_text = 0x1052040;
8 | constexpr pointer draw_text = 0x10669A0;
9 | constexpr pointer none_style = 0x1060210;
10 |
11 | // camera
12 | constexpr pointer camera = 0x10;
13 | constexpr pointer matrix = 0xDC;
14 | constexpr pointer camera_position = 0x42C;
15 |
16 | // unit3d
17 | constexpr pointer unity_list_len = 0x18;
18 | constexpr pointer unity_list_start = 0x20;
19 | constexpr pointer unity_list_offset = 0x8;
20 |
21 | // PlayerStats
22 | constexpr pointer PlayerStats_Update = 0x15D5900;
23 | constexpr pointer PlayerStats_ccm = 0x70;
24 | constexpr pointer ccm_team = 0x158;
25 |
26 | // render
27 | constexpr pointer GUI = 0x3A3330;
28 | }
29 |
--------------------------------------------------------------------------------
/utils.cpp:
--------------------------------------------------------------------------------
1 | #include "utils.h"
2 |
3 |
4 | float GetDistance(vec3 p1, vec3 p2)
5 | {
6 | float diffY = p1.Y - p2.Y;
7 | float diffX = p1.X - p2.X;
8 | float diffZ = p1.Z - p2.Z;
9 | return sqrtf((diffY * diffY) + (diffX * diffX) + (diffZ * diffZ));
10 | }
11 |
12 | bool WorldToScreen(Matrix &matrix, vec3 &from, vec2 &to, int ScreenCenterX, int ScreenCenterY)
13 | {
14 | float ViewW = matrix._14 * from.X + matrix._24 * from.Y + matrix._34 * from.Z + matrix._44;
15 |
16 | if (ViewW > 0.01f)
17 | {
18 | ViewW = 1.0f / ViewW;
19 |
20 | to.X = ScreenCenterX + (matrix._11 * from.X + matrix._21 * from.Y + matrix._31 * from.Z + matrix._41) * ViewW * ScreenCenterX;
21 | to.Y = ScreenCenterY - (matrix._12 * from.X + matrix._22 * from.Y + matrix._32 * from.Z + matrix._42) * ViewW * ScreenCenterY;
22 | return true;
23 | }
24 | return false;
25 | }
26 |
27 |
--------------------------------------------------------------------------------
/memory.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include "pointer.h"
4 |
5 | struct Entity {
6 | pointer address;
7 | vec3 position;
8 | char name[50];
9 | pointer ccm;
10 | int team;
11 | };
12 |
13 | // setup some global to work in different threads
14 | vec3 cameraPosition;
15 | Matrix matrix;
16 | pointer camera;
17 | std::vector entityList;
18 | std::vector locationList;
19 | char TeamName[18][50] = { "SCP-173", "Class-D Personnel", "Spectator", "SCP-106", "Nine-Tailed Fox Scientist", "SCP-049", "Scientist", "SCP-079", "Chaos Insurgency", "SCP-096", "SCP-049-2", "Nine-Tailed Fox Lieutenant", "Nine-Tailed Fox Commander", "Nine-Tailed Fox Cadet", "TUTORIAL", "Facility Guard", "SCP-939-53", "SCP-939-89", };
20 | char TeamColor[18][50] = { "#ff1900", "#ffece6", "white", "#cc0000", "#4d4dff", "red", "yellow", "#ff3333", "#33cc33", "red", "#ff6666", "#3333ff", "#1a1aff", "6666ff", "white", "lightblue", "#ff3364", "#ff3364", };
21 |
--------------------------------------------------------------------------------
/math.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 |
4 | struct Matrix
5 | {
6 | float _11, _12, _13, _14;
7 | float _21, _22, _23, _24;
8 | float _31, _32, _33, _34;
9 | float _41, _42, _43, _44;
10 | };
11 |
12 | struct vec3 {
13 | float X;
14 | float Y;
15 | float Z;
16 |
17 | vec3 operator * (float other)
18 | {
19 | vec3 buf;
20 | buf.X *= other;
21 | buf.Y *= other;
22 | buf.Z *= other;
23 | return buf;
24 | }
25 | vec3 operator + (float other)
26 | {
27 | vec3 buf;
28 | buf.X += other;
29 | buf.Y += other;
30 | buf.Z += other;
31 | return buf;
32 | }
33 | vec3 operator + (vec3 other)
34 | {
35 | vec3 buf;
36 | buf.X = X + other.X;
37 | buf.Y = Y + other.Y;
38 | buf.Z = Z + other.Z;
39 | return buf;
40 | }
41 | vec3 operator / (float other)
42 | {
43 | vec3 buf;
44 | buf.X /= other;
45 | buf.Y /= other;
46 | buf.Z /= other;
47 | return buf;
48 | }
49 | vec3& operator *= (float other)
50 | {
51 | X *= other;
52 | Y *= other;
53 | Z *= other;
54 | return *this;
55 | }
56 | float get_length_sqr(void) const
57 | {
58 | float buf;
59 | buf += (X * X);
60 | buf += (Y * Y);
61 | buf += (Z * Z);
62 |
63 | return buf;
64 | }
65 | };
66 |
67 | struct vec2 {
68 | float X;
69 | float Y;
70 | };
71 |
--------------------------------------------------------------------------------
/plague-scpsl.vcxproj.filters:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | {9b47fd4b-6f36-42dc-bee2-81cada66576f}
6 |
7 |
8 | {41bfae6c-83b9-49d7-8ace-1243a58ecf90}
9 |
10 |
11 |
12 |
13 | source
14 |
15 |
16 | source
17 |
18 |
19 | source
20 |
21 |
22 |
23 |
24 | h
25 |
26 |
27 | h
28 |
29 |
30 | h
31 |
32 |
33 | h
34 |
35 |
36 | h
37 |
38 |
39 | h
40 |
41 |
42 | h
43 |
44 |
45 |
--------------------------------------------------------------------------------
/plague-scpsl.sln:
--------------------------------------------------------------------------------
1 |
2 | Microsoft Visual Studio Solution File, Format Version 12.00
3 | # Visual Studio 15
4 | VisualStudioVersion = 15.0.28307.329
5 | MinimumVisualStudioVersion = 10.0.40219.1
6 | Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "plague-scpsl", "plague-scpsl.vcxproj", "{7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}"
7 | EndProject
8 | Global
9 | GlobalSection(SolutionConfigurationPlatforms) = preSolution
10 | Debug|x64 = Debug|x64
11 | Debug|x86 = Debug|x86
12 | Release|x64 = Release|x64
13 | Release|x86 = Release|x86
14 | EndGlobalSection
15 | GlobalSection(ProjectConfigurationPlatforms) = postSolution
16 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Debug|x64.ActiveCfg = Debug|x64
17 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Debug|x64.Build.0 = Debug|x64
18 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Debug|x86.ActiveCfg = Debug|Win32
19 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Debug|x86.Build.0 = Debug|Win32
20 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Release|x64.ActiveCfg = Release|x64
21 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Release|x64.Build.0 = Release|x64
22 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Release|x86.ActiveCfg = Release|Win32
23 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}.Release|x86.Build.0 = Release|Win32
24 | EndGlobalSection
25 | GlobalSection(SolutionProperties) = preSolution
26 | HideSolutionNode = FALSE
27 | EndGlobalSection
28 | GlobalSection(ExtensibilityGlobals) = postSolution
29 | SolutionGuid = {4AE5BC57-F4B3-408C-9A4F-91226580E10B}
30 | EndGlobalSection
31 | EndGlobal
32 |
--------------------------------------------------------------------------------
/readme.md:
--------------------------------------------------------------------------------
1 | The code looks pretty simple and nice.
2 |
3 | # how to update offsets
4 |
5 | https://github.com/t1f7/scp-internal-il2cpp/wiki
6 |
7 | # friendly reminder
8 |
9 | SL-AC.dll hooks next functions to detect this base
10 |
11 | ```
12 | GetProcAddress
13 | LoadLibraryA
14 | LoadLibraryW
15 | GetModuleHandleA
16 | GetModuleHandleW
17 | GetAsyncKeyState
18 | NtOpenFile
19 | CreateThread
20 | Sleep
21 | il2cpp_string_new
22 | il2cpp_resolve_icall
23 | UnityPlayer.dll + 0x937480 (gettable with il2cpp_resolve_icall("UnityEngine.GameObject::FindGameObjectsWithTag(System.String)")), in other words "il2cpp::unity_find_objects" is detected also.
24 | ```
25 |
26 | # il2cpp
27 |
28 | I have found time to learn megapatch2 changes in SCPSL game.
29 |
30 | Old repo is read-only from now.
31 |
32 | # Preview
33 |
34 | [](https://www.youtube.com/watch?v=f-emyZ0ZKdo)
35 |
36 | This project is a base for il2cpp game hack. You can make a couple changes to make it work with any other game, not SCPSL only.
37 |
38 | # Updates
39 |
40 | v0.4: hooking game thread to bypass GC detection.
41 |
42 | v0.5: fetching component data example.
43 |
44 | v0.6: engine rendering, removed old GUI
45 |
46 | v0.7: scopophobia update, AC bypass
47 |
48 | v0.8: auto screen resolution change support
49 |
50 | v0.9: better transform handling & more interesting il2cpp class
51 |
52 | # Credits
53 |
54 | * [Foxye](https://github.com/EquiFox) for his public hack that gave me inspiration to continue.
55 | * Allan for great w2s code and cool c++ snippets.
56 |
--------------------------------------------------------------------------------
/veh.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #include
3 | #include
4 | #include "pointer.h"
5 |
6 | typedef void func(PEXCEPTION_POINTERS debug_context);
7 |
8 | struct VEHUnit {
9 | bool exists = false;
10 | pointer address;
11 | void* callback;
12 | byte oldByte;
13 | bool post_call = false;
14 | void enable()
15 | {
16 | *(byte*)address = 0xCC;
17 | }
18 | void disable()
19 | {
20 | *(byte*)address = oldByte;
21 | }
22 | };
23 | struct VEHStruct {
24 | std::vector list;
25 | VEHUnit Find(pointer address) {
26 |
27 | for (int i = 0; i < list.size(); i++) {
28 | auto tpl = list[i];
29 | if (tpl.address == address || (tpl.address > address - 0x16 && tpl.address < address)) {
30 | return tpl;
31 | }
32 | }
33 |
34 | VEHUnit pl;
35 | return pl;
36 | };
37 | void Append(pointer address, void* callback, bool postcall = false) {
38 | DWORD dwOld;
39 | VirtualProtect((void*)address, 1, PAGE_EXECUTE_READWRITE, &dwOld);
40 |
41 | VEHUnit h = {
42 | true,
43 | address,
44 | callback,
45 | *(byte*)address,
46 | postcall
47 | };
48 | list.push_back(h);
49 |
50 | h.enable();
51 | }
52 | };
53 | VEHStruct VEH;
54 |
55 | LONG WINAPI CorruptionHandler(PEXCEPTION_POINTERS ExceptionInfo) {
56 |
57 | if (!ExceptionInfo || !ExceptionInfo->ExceptionRecord || !ExceptionInfo->ContextRecord)
58 | {
59 | return EXCEPTION_CONTINUE_SEARCH;
60 | }
61 | auto code = ExceptionInfo->ExceptionRecord->ExceptionCode;
62 | if (code != EXCEPTION_BREAKPOINT && code != EXCEPTION_SINGLE_STEP)
63 | {
64 | return EXCEPTION_CONTINUE_SEARCH;
65 | }
66 |
67 | auto h = VEH.Find((pointer)ExceptionInfo->ContextRecord->Rip);
68 | if (h.exists) {
69 | if (code == EXCEPTION_BREAKPOINT) {
70 | h.disable();
71 | ExceptionInfo->ContextRecord->EFlags |= 0x100;
72 | if (!h.post_call) ((func*)h.callback)(ExceptionInfo);
73 | ExceptionInfo->ContextRecord->Rip = h.address;
74 |
75 | return EXCEPTION_CONTINUE_EXECUTION;
76 | }
77 | else {
78 | h.enable();
79 | ExceptionInfo->ContextRecord->EFlags &= ~(0x100);
80 | if (h.post_call) ((func*)h.callback)(ExceptionInfo);
81 | return EXCEPTION_CONTINUE_EXECUTION;
82 | }
83 | }
84 | else {
85 | return EXCEPTION_CONTINUE_EXECUTION;
86 | }
87 | return EXCEPTION_CONTINUE_EXECUTION;
88 |
89 | }
--------------------------------------------------------------------------------
/il2cpp.h:
--------------------------------------------------------------------------------
1 | #pragma once
2 | #pragma warning(disable : 4244 4996 )
3 | #include
4 | #include "offsets.h"
5 | #include "math.h"
6 | #include "utils.h"
7 |
8 | struct Rect {
9 | float x, y, width, heigh;
10 | };
11 |
12 | struct Il2CppString;
13 | struct GUIContent;
14 | struct GUIStyle;
15 |
16 | typedef void* (__cdecl *il2cpp_resolve_icall)(const char*);
17 | typedef Il2CppString* (__cdecl *il2cpp_string_new)(const char*);
18 |
19 | typedef pointer (__cdecl *t_unity_get_main_camera)();
20 | typedef pointer* (__cdecl *t_unity_find_objects)(Il2CppString*);
21 |
22 | typedef pointer* (__cdecl *t_unity_get_transform)(pointer);
23 | typedef pointer* (__cdecl *t_unity_transform_get_vector)(pointer*, vec3*);
24 | typedef pointer (__cdecl *t_unity_get_gameobject)(pointer);
25 |
26 | typedef GUIContent* (__cdecl *t_unity_create_gui_text)(Il2CppString*);
27 | typedef void (__cdecl *t_unity_label)(Rect position, GUIContent* content, GUIStyle* style);
28 | typedef GUIStyle* (__cdecl *t_unity_no_style)();
29 | typedef int(__cdecl *t_unity_get_screen_data)();
30 |
31 | namespace il2cpp
32 | {
33 |
34 | // strings
35 | constexpr const char* assemblyName = "GameAssembly.dll";
36 | constexpr const char* moduleName = "SCPSL.exe";
37 | constexpr const char* fname_find_gameobjects = "UnityEngine.GameObject::FindGameObjectsWithTag(System.String)";
38 | constexpr const char* fname_get_transform = "UnityEngine.GameObject::get_transform(System.IntPtr)";
39 | constexpr const char* fname_get_transform_vector = "UnityEngine.Transform::get_position_Injected(UnityEngine.Vector3&)";
40 | constexpr const char* fname_get_current_camera = "UnityEngine.Camera::get_main()";
41 | constexpr const char* fname_get_gameobject = "UnityEngine.Component::get_gameObject()";
42 | constexpr const char* fname_screen_width = "UnityEngine.Screen::get_width()";
43 | constexpr const char* fname_screen_height = "UnityEngine.Screen::get_height()";
44 |
45 |
46 | // functions
47 | pointer GetModuleBase();
48 | void Init();
49 |
50 | // usefull functions
51 | int get_screen_width();
52 | int get_screen_height();
53 | pointer get_current_camera();
54 | pointer* find_entities(const char* tag);
55 | pointer get_gameobject(pointer component);
56 | vec3 get_camera_position(pointer camera);
57 | void get_transform(pointer entity, vec3* pos);
58 | Matrix get_viewmatrix();
59 | Matrix get_viewmatrix(pointer);
60 |
61 | // rendering
62 | void draw_text(Rect position, const char* text);
63 | }
--------------------------------------------------------------------------------
/il2cpp.cpp:
--------------------------------------------------------------------------------
1 | #include "il2cpp.h"
2 |
3 | namespace il2cpp
4 | {
5 | // variables
6 | pointer moduleBase;
7 | pointer assemblyBase;
8 |
9 | // api
10 | il2cpp_string_new unity_string_new;
11 | il2cpp_resolve_icall unity_resolve_icall;
12 | t_unity_find_objects unity_find_objects;
13 | t_unity_get_transform unity_get_transform;
14 | t_unity_transform_get_vector unity_transform_get_vector;
15 | t_unity_get_main_camera unity_get_main_camera;
16 | t_unity_get_gameobject unity_get_gameobject;
17 | t_unity_create_gui_text unity_create_text;
18 | t_unity_label unity_draw_text;
19 | t_unity_no_style unity_none_style;
20 | t_unity_get_screen_data unity_get_screen_width;
21 | t_unity_get_screen_data unity_get_screen_height;
22 |
23 | pointer GetModuleBase()
24 | {
25 | if (assemblyBase == 0)
26 | {
27 | assemblyBase = (pointer)GetModuleHandleA(assemblyName);
28 | }
29 | return assemblyBase;
30 | }
31 |
32 | void Init() {
33 |
34 | // grab data
35 | unity_string_new = (il2cpp_string_new)GetProcAddress((HMODULE)assemblyBase, "il2cpp_string_new");
36 | unity_resolve_icall = (il2cpp_resolve_icall)GetProcAddress((HMODULE)assemblyBase, "il2cpp_resolve_icall");
37 | unity_find_objects = (t_unity_find_objects)unity_resolve_icall(fname_find_gameobjects);
38 | unity_get_transform = (t_unity_get_transform)unity_resolve_icall(fname_get_transform);
39 | unity_transform_get_vector = (t_unity_transform_get_vector)unity_resolve_icall(fname_get_transform_vector);
40 | unity_get_main_camera = (t_unity_get_main_camera)unity_resolve_icall(fname_get_current_camera);
41 | unity_get_gameobject = (t_unity_get_gameobject)unity_resolve_icall(fname_get_gameobject);
42 | unity_get_screen_width = (t_unity_get_screen_data)unity_resolve_icall(fname_screen_width);
43 | unity_get_screen_height = (t_unity_get_screen_data)unity_resolve_icall(fname_screen_height);
44 |
45 | // unity3D rendering
46 | unity_create_text = (t_unity_create_gui_text)(assemblyBase + offset::create_text);
47 | unity_draw_text = (t_unity_label)(assemblyBase + offset::draw_text);
48 | unity_none_style = (t_unity_no_style)(assemblyBase + offset::none_style);
49 |
50 | }
51 |
52 | int get_screen_width() {
53 | return unity_get_screen_width();
54 | }
55 |
56 | int get_screen_height() {
57 | return unity_get_screen_height();
58 | }
59 |
60 | void draw_text(Rect position, const char* text) {
61 | auto il2cpp_string = unity_string_new(text);
62 | auto content = unity_create_text(il2cpp_string);
63 | auto style = unity_none_style();
64 | unity_draw_text(position, content, style);
65 | }
66 |
67 | pointer get_current_camera() {
68 | return unity_get_main_camera();
69 | }
70 |
71 | pointer* find_entities(const char* tag) {
72 | auto il2cpp_string = unity_string_new(tag);
73 | return unity_find_objects(il2cpp_string);
74 | }
75 |
76 | void get_transform(pointer entity, vec3* pos) {
77 | auto transform = (pointer*)unity_get_transform(entity);
78 | unity_transform_get_vector(transform, pos);
79 | }
80 |
81 | pointer get_gameobject(pointer component) {
82 | auto go = unity_get_gameobject(component);
83 | return go;
84 | }
85 |
86 | vec3 get_camera_position(pointer camera) {
87 | if (camera != NULL) {
88 | camera = Read((pointer)camera + offset::camera);
89 | return Read(camera + offset::camera_position);
90 | }
91 | return vec3{};
92 | }
93 |
94 | Matrix get_viewmatrix() {
95 | auto camera = get_current_camera();
96 | return get_viewmatrix(camera);
97 | }
98 | Matrix get_viewmatrix(pointer camera) {
99 | if (camera != NULL) {
100 | camera = Read((pointer)camera + offset::camera);
101 | return Read(camera + offset::matrix);
102 | }
103 | return Matrix{};
104 | }
105 |
106 | }
107 |
--------------------------------------------------------------------------------
/main.cpp:
--------------------------------------------------------------------------------
1 | #include "il2cpp.h"
2 | #include "utils.h"
3 | #include "memory.h"
4 | #include "veh.h"
5 |
6 |
7 | void OnGUI(PEXCEPTION_POINTERS ExceptionInfo) {
8 |
9 | il2cpp::draw_text(Rect{ 5, 30, 100.0f, 100.0f }, "il2cpp plague : v0.9");
10 |
11 | camera = il2cpp::get_current_camera();
12 | if (!camera) return;
13 | matrix = il2cpp::get_viewmatrix(camera);
14 | cameraPosition = il2cpp::get_camera_position(camera);
15 |
16 | if (!camera) {
17 | entityList.clear();
18 | return;
19 | }
20 |
21 | auto screenCenterX = il2cpp::get_screen_width() * 0.5;
22 | auto screenCenterY = il2cpp::get_screen_height() * 0.5;
23 |
24 | char buf[100];
25 | sprintf(buf, "players: %i", entityList.size());
26 | il2cpp::draw_text(Rect{ 5, 45, 100.0f, 100.0f }, buf);
27 |
28 | // draw players
29 | for (int i = 0; i < entityList.size(); i++) {
30 | vec2 out;
31 |
32 | if (WorldToScreen(matrix, entityList[i].position, out, screenCenterX, screenCenterY)) {
33 |
34 | float dist = GetDistance(cameraPosition, entityList[i].position);
35 | //auto color = "white";
36 |
37 | sprintf(buf, "%s - %.2f", TeamColor[entityList[i].team], TeamName[entityList[i].team], dist);
38 | il2cpp::draw_text(Rect{ out.X, out.Y, 100.0f, 100.0f }, buf);
39 | }
40 | }
41 |
42 | // find scp-914
43 | std::vector tmp;
44 | auto location = il2cpp::find_entities("914_use");
45 | int objects_num = Read((pointer)location + offset::unity_list_len);
46 | if (objects_num) {
47 | auto object = Read((pointer)location + offset::unity_list_start);
48 |
49 | vec3 position;
50 | il2cpp::get_transform(object, &position);
51 | tmp.push_back({
52 | object,
53 | position,
54 | "SCP-914"
55 | });
56 | }
57 |
58 | locationList = tmp;
59 |
60 | // draw locations
61 | for (int i = 0; i < locationList.size(); i++) {
62 | vec2 out;
63 |
64 | if (WorldToScreen(matrix, locationList[i].position, out, screenCenterX, screenCenterY)) {
65 |
66 | float dist = GetDistance(cameraPosition, locationList[i].position);
67 | auto color = "yellow";
68 |
69 | sprintf(buf, "%s - %.2f", color, locationList[i].name, dist);
70 | il2cpp::draw_text(Rect{ out.X, out.Y, 100.0f, 100.0f }, buf);
71 | }
72 | }
73 | }
74 |
75 | void PlayerStats_Update(PEXCEPTION_POINTERS ExceptionInfo) {
76 |
77 | // components are at Rcx
78 | auto PlayerStats_Component = ExceptionInfo->ContextRecord->Rcx;
79 | pointer ccm = Read(PlayerStats_Component + offset::PlayerStats_ccm);
80 | auto team = Read(ccm + offset::ccm_team);
81 |
82 | // this is how to combine player gameobject with component data
83 | // it's ok to call il2cpp api here as we're inside game thread inside any VEH hook
84 | auto player = il2cpp::get_gameobject(PlayerStats_Component);
85 |
86 | // why don't we collect other data here
87 | vec3 position;
88 | il2cpp::get_transform(player, &position);
89 |
90 | // different thread forces us to recreate a list
91 | // it looks as a bad design but it works so I don't care actually if it's bad
92 | std::vector tmp;
93 | bool found = false;
94 |
95 | for (int i = 0; i < entityList.size(); i++) {
96 | if (entityList[i].address == player) {
97 | found = true;
98 | // override position for cached entity
99 | entityList[i].position = position;
100 | entityList[i].ccm = ccm;
101 | entityList[i].team = team;
102 | }
103 | tmp.push_back(entityList[i]);
104 | }
105 | entityList = tmp;
106 | tmp.clear();
107 |
108 | if (!found) {
109 | entityList.push_back(Entity{
110 | player,
111 | position,
112 | "unnamed", // add nickname here after
113 | ccm,
114 | team
115 | });
116 | }
117 |
118 | }
119 |
120 | BOOL WINAPI DllMain(HINSTANCE hinstDll, DWORD fdwReason, LPVOID lpvReserved) {
121 | if (fdwReason == DLL_PROCESS_ATTACH) {
122 |
123 | auto base = il2cpp::GetModuleBase();
124 | il2cpp::Init();
125 |
126 | // hooking with VEH example
127 | AddVectoredExceptionHandler(1, CorruptionHandler);
128 | VEH.Append(base + offset::PlayerStats_Update, &PlayerStats_Update);
129 | VEH.Append(base + offset::GUI, &OnGUI);
130 |
131 | }
132 | return true;
133 | }
134 |
--------------------------------------------------------------------------------
/plague-scpsl.vcxproj:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Debug
6 | Win32
7 |
8 |
9 | Release
10 | Win32
11 |
12 |
13 | Debug
14 | x64
15 |
16 |
17 | Release
18 | x64
19 |
20 |
21 |
22 | 15.0
23 | {7A3B0089-3F7B-4E2C-9DF0-46F217C189D4}
24 | plaguescpsl
25 | 10.0.17763.0
26 |
27 |
28 |
29 | Application
30 | true
31 | v141
32 | MultiByte
33 |
34 |
35 | Application
36 | false
37 | v141
38 | true
39 | MultiByte
40 |
41 |
42 | DynamicLibrary
43 | true
44 | v141
45 | MultiByte
46 |
47 |
48 | DynamicLibrary
49 | false
50 | v141
51 | true
52 | MultiByte
53 | false
54 |
55 |
56 |
57 |
58 |
59 |
60 |
61 |
62 |
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 |
73 |
74 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(DXSDK_DIR)Include;
75 | $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(DXSDK_DIR)Lib\x64
76 |
77 |
78 | $(VC_LibraryPath_x64);$(WindowsSDK_LibraryPath_x64);$(DXSDK_DIR)Lib\x64
79 | $(VC_IncludePath);$(WindowsSDK_IncludePath);$(DXSDK_DIR)Include;
80 |
81 |
82 |
83 | Level3
84 | Disabled
85 | true
86 | true
87 |
88 |
89 |
90 |
91 | Level3
92 | Disabled
93 | true
94 | true
95 | stdcpp17
96 |
97 |
98 |
99 |
100 | Level3
101 | MaxSpeed
102 | true
103 | true
104 | true
105 | true
106 |
107 |
108 | true
109 | true
110 |
111 |
112 |
113 |
114 | Level3
115 | MaxSpeed
116 | true
117 | true
118 | true
119 | true
120 | stdcpp17
121 |
122 |
123 | true
124 | true
125 |
126 |
127 |
128 |
129 |
130 |
131 |
132 |
133 |
134 |
135 |
136 |
137 |
138 |
139 |
140 |
141 |
142 |
143 |
144 |
--------------------------------------------------------------------------------