├── 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 | [![v0.4](https://img.youtube.com/vi/f-emyZ0ZKdo/0.jpg)](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 | --------------------------------------------------------------------------------