Skip to content

Latest commit

 

History

History
201 lines (171 loc) · 7.88 KB

UsingTheSDK.md

File metadata and controls

201 lines (171 loc) · 7.88 KB

Using the SDK to create a simple DLL project

Visual Studio project setup

  1. Create a new empty C++ project
  2. Go to Project>Properties
  3. Set Configuration Type from Application (.exe) to Dynamic Library (.dll)
  4. In the same settings set the C++ Language Standard from Default (ISO C++14 Standard) to Preview - Latest...
  5. Hit Apply and close the settings
    image
  6. Switch your build configuration from x86 to x64
    image
  7. Add a file Main.cpp to your project
  8. Add a DllMain function and a MainThread function (See code here)

Including the SDK into the project

  1. Take the contents of your CppSDK folder (by default C:\\Dumper-7\\GameName-GameVersion\\CppSDK)
    image
  2. Drop the contents into your VS projects' directory
    image
  3. If you do not care about your projects' compilation time, add #include "SDK.hpp" at the top of your Main.cpp file
  4. If you do care, and you want faster compilation-times, directly include only the files you require.
    Adding #include "SDK/Engine_classes.hpp" is a good start in this case.
  5. Add Basic.cpp and CoreUObject_functions.cpp to your VS project
  6. If you call a function from the SDK you need to add the .cpp file, that contains the function-body, to your project.
    Example:
    Calling GetViewportSize() from APlayerController requires you to add Engine_functions.cpp to your project.
    image
  7. After attempting to build the SDK go to the "Error List" and make sure to select Build Only image
  8. If there are any static_asserts failing, or other errors occuring, during building, read the Issue part of the ReadMe

Using the SDK

1. Retrieving instances of classes/structs to manipulate them

  • FindObject, used to find an object by its' name
    SDK::UObject* Obj1 = SDK::UObject::FindObject("ClassName PackageName.Outer1.Outer2.ObjectName");
    SDK::UObject* Obj2 = SDK::UObject::FindObjectFast("ObjectName");
    
    SDK::UObject* Obj3 = SDK::UObject::FindObjectFast("StructName", EClassCastFlags::Struct); // Finds a UStruct
  • StaticFunctions / GlobalVariables, used to retreive class-instances from static variables
    /* UWorld::GetWorld() replaces GWorld, no offset required */
    SDK::UWorld* World = SDK::UWorld::GetWorld();
    SDK::APlayerController* MyController = World->OwningGameInstance->LocalPlayers[0]->PlayerController;

2. Calling functions

  • Non-Static functions
    SDK::APlayerController* MyController = MagicFuncToGetPlayerController();
    
    float OutX, OutY;
    MyController->GetMousePosition(&OutX, &OutY);
  • Static functions
    /* static functions do not require an instance, they are automatically called using their DefaultObject */
    SDK::FName MyNewName = SDK::UKismetStringLibrary::Conv_StringToName(L"DemoNetDriver");

3. Checking a UObject's type

  • With EClassCastFlags
    /* Limited to some few types, but fast */
    const bool bIsActor = Obj->IsA(EClassCastFlags::Actor);
  • With a UClass*
    /* For every class, but slower (faster than string-comparison) */
    const bool bIsSpecificActor = Obj->IsA(ASomeSpecificActor::StaticClass());

4. Casting

UnrealEngine heavily relies on inheritance and often uses pointers to a base class, which are later assigned addresses to
instances of child classes.

if (MyController->Pawn->IsA(SDK::AGameSpecificPawn::StaticClass()))
{
    SDK::AGameSpecificPawn* MyGamePawn = static_cast<SDK::AGameSpecificPawn*>(MyController->Pawn);
    MyGamePawn->GameSpecificVariable = 30; 
}

Code

DllMain and MainThread

#include <Windows.h>
#include <iostream>

DWORD MainThread(HMODULE Module)
{
        /* Code to open a console window */
        AllocConsole();
        FILE* Dummy;
        freopen_s(&Dummy, "CONOUT$", "w", stdout);
        freopen_s(&Dummy, "CONIN$", "r", stdin);

        // Your code here

        return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
        switch (reason)
        {
                case DLL_PROCESS_ATTACH:
                CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, hModule, 0, 0);
                break;
        }

        return TRUE;
}

Example program that enables the UnrealEngine console

#include <Windows.h>
#include <iostream>

#include "SDK/Engine_classes.hpp"

// Basic.cpp was added to the VS project
// Engine_functions.cpp was added to the VS project

DWORD MainThread(HMODULE Module)
{
    /* Code to open a console window */
    AllocConsole();
    FILE* Dummy;
    freopen_s(&Dummy, "CONOUT$", "w", stdout);
    freopen_s(&Dummy, "CONIN$", "r", stdin);

    /* Functions returning "static" instances */
    SDK::UEngine* Engine = SDK::UEngine::GetEngine();
    SDK::UWorld* World = SDK::UWorld::GetWorld();

    /* Getting the PlayerController, World, OwningGameInstance, ... should all be checked not to be nullptr! */
    SDK::APlayerController* MyController = World->OwningGameInstance->LocalPlayers[0]->PlayerController;

    /* Print the full-name of an object ("ClassName PackageName.OptionalOuter.ObjectName") */
    std::cout << Engine->ConsoleClass->GetFullName() << std::endl;

    /* Manually iterating GObjects and printing the FullName of every UObject that is a Pawn (not recommended) */
    for (int i = 0; i < SDK::UObject::GObjects->Num(); i++)
    {
        SDK::UObject* Obj = SDK::UObject::GObjects->GetByIndex(i);

        if (!Obj)
            continue;

        if (Obj->IsDefaultObject())
            continue;

        /* Only the 'IsA' check using the cast flags is required, the other 'IsA' is redundant */
        if (Obj->IsA(SDK::APawn::StaticClass()) || Obj->HasTypeFlag(SDK::EClassCastFlags::Pawn))
        {
            std::cout << Obj->GetFullName() << "\n";
        }
    }

    /* You might need to loop all levels in UWorld::Levels */
    SDK::ULevel* Level = World->PersistentLevel;
    SDK::TArray<SDK::AActor*>& Actors = Level->Actors;

    for (SDK::AActor* Actor : Actors)
    {
        /* The 2nd and 3rd checks are equal, prefer using EClassCastFlags if available for your class. */
        if (!Actor || !Actor->IsA(SDK::EClassCastFlags::Pawn) || !Actor->IsA(SDK::APawn::StaticClass()))
            continue;

        SDK::APawn* Pawn = static_cast<SDK::APawn*>(Actor);
        // Use Pawn here
    }

    /* 
    * Changes the keyboard-key that's used to open the UE console
    * 
    * This is a rare case of a DefaultObjects' member-variables being changed.
    * By default you do not want to use the DefaultObject, this is a rare exception.
    */
    SDK::UInputSettings::GetDefaultObj()->ConsoleKeys[0].KeyName = SDK::UKismetStringLibrary::Conv_StringToName(L"F2");

    /* Creates a new UObject of class-type specified by Engine->ConsoleClass */
    SDK::UObject* NewObject = SDK::UGameplayStatics::SpawnObject(Engine->ConsoleClass, Engine->GameViewport);

    /* The Object we created is a subclass of UConsole, so this cast is **safe**. */
    Engine->GameViewport->ViewportConsole = static_cast<SDK::UConsole*>(NewObject);

    return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, DWORD reason, LPVOID lpReserved)
{
    switch (reason)
    {
    case DLL_PROCESS_ATTACH:
        CreateThread(0, 0, (LPTHREAD_START_ROUTINE)MainThread, hModule, 0, 0);
        break;
    }

    return TRUE;
}