• Unfortunately, we have experienced significant hard drive damage that requires urgent maintenance and rebuilding. The forum will be a state of read only until we install our new drives and rebuild all the configurations needed. Please follow our Facebook page for updates, we will be back up shortly! (The forum could go offline at any given time due to the nature of the failed drives whilst awaiting the upgrades.) When you see an Incapsula error, you know we are in the process of migration.

Kealy's FpsLimiter

Status
Not open for further replies.
Newbie Spellweaver
Joined
Oct 20, 2007
Messages
28
Reaction score
2
Hey guys,
first of all i dont open this thread to get answers like: use madknight's dll or learn c++, i want make my own .dll's and not just download finished ones..
i learning by doing and i wanted to use Keays Source code but anything wrong...if i start my client it dont use the fpslimiter <.<
and no i dont copy paste, i changed few functions to miney like "Core to Memory,.." included too all i need for it but it still not work -.-
no one wanted to help me or tryed... so i hope anyone of you can explain me what i did wrong :S
(its not the fully source of my dll, just the one for fpslimiter)

dllmain.cpp:
PHP:
#include "FpsLimiter.h"

void IProtect::Boot(HMODULE hModule)
{
    CTweaks Tweaks;

    Tweaks.HookWorldRefresh();
}

FpsLimiter.h
PHP:
#include <iostream>
#include <Windows.h>

using namespace std;

class CTweaks
{
    public:
        CTweaks();                                                // Constructor
        void HookWorldRefresh();                                // World refreshing function hooker
    private:
        // This function has to be static, otherwise it wouldn't be possible to get a pointer to it.
        static WPARAM __thiscall WorldRefresh(void*);            // Engine World refreshing thread
        typedef int (__cdecl *WREngineFunc)(void);                // Unknown WorldRefresh function's prototype
        typedef int (__thiscall *RefreshEntities)(void*);    // Entity worldrefreshing function's prototype
        DWORD WREngineFuncPtr;                                    // Pointer to unknown worldrefreshing function
        DWORD RefreshEntitiesPtr;                                    // Pointer to entity worldrefreshing function
        BYTE *WREngineActive;                                    // Pointer to possible 'this' instance
        int MaxFPS;                                                // Maximum frames per second
        int MaxTime;                                            // Maximum milliseconds accepted to engage frame blocker
        DWORD SleepTime;                                        // Time to block the frame each round
};
extern CTweaks *Tweaks;

FpsLimiter.cpp
PHP:
#include "StdAfx.h"
#include "FpsLimiter.h"
#include "Memory.h"

// Only one single instance of this class is needed
// So there is no need to worry about where nor how we initialize it.
CTweaks *Tweaks = new CTweaks;
IMemory Memory;

CTweaks::CTweaks()
{
    // Engine addresses pointers
    this->WREngineFuncPtr = 0x004a73b0;
    this->RefreshEntitiesPtr = 0x00425960;
    this->WREngineActive = (BYTE*)0x006ddf58;
}
void CTweaks::HookWorldRefresh()
{
    this->MaxFPS = 30;
    // Right here it is possible to load the max fps from a configuration file, or what so ever.
    // Example : this->MaxFPS = Config->Engine.FPSLimit;

    // Two calls to our WorldRefresh function, only one of them is used, but the second one is just in case.
    this->MaxTime = (1000/this->MaxFPS);
    Memory.Intercept(Memory._I_CALL,(void*)0x00505869,(void*)this->WorldRefresh,5);
    Memory.Intercept(Memory._I_CALL,(void*)0x00505bfc,(void*)this->WorldRefresh,5);
    #ifndef SILENT_MODE
    cout << "FPS Limiter installed." << endl;
    #endif
}
WPARAM __thiscall CTweaks::WorldRefresh(void *thisPointer)
{
    // Since this function is running as a thread, InixSoft had to declare it as static (just as done here)
    // Therefore, since the 'this' instance can only be used with non-static member functions,
    // The calling convention is not __thiscall anymore but __fastcall, and the 'this' pointer is passed as argument.
    // EDIT: After some tests, I figured __thiscall is sometimes required, so try it like this.
    // If it doesn't work out, change it back to __fastcall

    // Default function vars
    void *that;
    char state;
    struct tagMSG Msg;
    HACCEL hAccel;

    // Our variables
    // We will be using high resolution timers
    // <3 precision
    int PerformanceTime;
    unsigned __int64 lpFrequency;
    unsigned __int64 lpPerformanceCount;
    unsigned __int64 lpPerformanceStep;

    // This > That. Ok ?
    that = thisPointer;

    // Checking for the CPU's frequency, unit is in Herz.
    QueryPerformanceFrequency((LARGE_INTEGER*)&lpFrequency);

    hAccel = LoadAcceleratorsA(NULL, (LPCSTR)0x71);
    Msg.message = 0;
    PeekMessageA(&Msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE);
    while (Msg.message != 0x12)
    {
        // EXTREMELY important!!
        // Since we call functions that weren't compiled with the same compiler (type, version, et cetera) as we use
        // There are high chances that those functions modify, either the stack or the registers in a way OUR compiler would never expect.
        // Such corruption is especially noticeable in loops, causing crashes in most cases.
        // This is why it is critical to save the stack before and after those functions are executed.
        __asm pushad
        if (*((BYTE*)that+0x9d)) state = (!!PeekMessageA(&Msg, NULL, WM_NULL, WM_NULL, PM_REMOVE));
        else state = (!!GetMessageA(&Msg, NULL, 0, 0));
        if (state)
        {
            if ((!hAccel) || (!(*(DWORD*)that+0x38)) || (!TranslateAcceleratorA(*((HWND*)that+0x38), hAccel, &Msg)))
            {
                TranslateMessage(&Msg);
                DispatchMessageA(&Msg);
            }
            // Not quite sure about what this function really does
            // I know it's executed when the mouse is moved.
            ((WREngineFunc)Tweaks->WREngineFuncPtr)();
        }
        else
        {
            if ((*((BYTE*)that+0x9d)) && (*(BYTE*)Tweaks->WREngineActive))
            {
                // Querying the performance count before and after world refreshing function
                QueryPerformanceCounter((LARGE_INTEGER*)&lpPerformanceCount);

                // This function refreshes the whole kal world, including object movements in time, daytime, et cetera, well, pretty much everything.
                // Could also be called rendering function.
                int tmpActive = ((RefreshEntities)Tweaks->RefreshEntitiesPtr)(that);

                QueryPerformanceCounter((LARGE_INTEGER*)&lpPerformanceStep);
                if (tmpActive < 0) SendMessageA(*((HWND*)that+0x38), WM_COMMAND, 0x9C46, 0);

                // From here on, we will calculate the difference between the two counters
                // And base the time we'll need to block the frames from being displayed for on that amount.
                PerformanceTime = (int)(lpFrequency / (lpPerformanceStep-lpPerformanceCount));
                if (PerformanceTime) PerformanceTime = 1000 / PerformanceTime;
                if (Tweaks->MaxTime > PerformanceTime)
                {
                    // This var could be used as local variable, but let's rather keep it global.
                    Tweaks->SleepTime = (Tweaks->MaxTime - PerformanceTime);
                    Sleep(Tweaks->SleepTime);
                }
            }
        }
        // Restoring the stack.
        __asm popad
    }
    if (hAccel) DestroyAcceleratorTable(hAccel);
    return Msg.wParam;
}

Memory.cpp (Just the Intercept Function):
PHP:
unsigned long IMemory::Intercept(unsigned char instruction, void* source, void* destination, size_t length)
{
    unsigned long realTarget;
    LPBYTE buffer = new BYTE[length];
    memset(buffer,0x90,length);
    if (instruction != IMemory::_I_NOP && length >= 5)
    {
        buffer[(length-5)] = instruction;
        unsigned long dwJMP = (unsigned long)destination - ((unsigned long)source + 5 + (length-5));
        memcpy(&realTarget,(void*)((unsigned long)source+1),4);
        realTarget = realTarget + (unsigned long)source + 5;
        memcpy(buffer + 1 + (length - 5),&dwJMP,4);
    }
    if (instruction == IMemory::_I_JE_SHORT)
    {
        buffer[0] = instruction;
        buffer[1] = (BYTE)destination;
    }
    if (instruction == 0x00)
        buffer[0] = (BYTE)destination;

    this->MemcpyExD(source, buffer, length);
    delete[] buffer;
    return realTarget;
}

Memory.h (Just the _I_Call & Intercept Function):
PHP:
_I_CALL = 0xe8,
virtual unsigned long Intercept(unsigned char instruction, void* source, void* destination, size_t length);

The Memory.cpp & Memory.h is from Cry.dll

so whats wrong, i dont understand lol... i looked now many times function for function but it should work oO or iam wrong?
pls help xD

greets dark
 
Elite Diviner
Joined
Feb 8, 2012
Messages
439
Reaction score
867
On the first view your code looks okay, but it is hard to say what is wrong wihout more testing and information. You should also go 100% sure, that your dll is really loaded clientside, maybe add a "Hello, World" as Console Output to your Clientside Addon, otherwise your DLL may work, but wasnt loaded : )

And maybe my adatpion of Kealys FPS Limiter Code can help you also:

MadFPS.h
Code:
#include "Ultilities.h"


typedef int (__cdecl *WREngineFunc)(void);                
typedef int (__thiscall *RefreshEntities)(void*);    
DWORD WREngineFuncPtr = 0x004a73b0;                                    
DWORD RefreshEntitiesPtr = 0x00425960;                                   
BYTE *WREngineActive = (BYTE*)0x006ddf58;                                
int MaxFPS = 60;                                                
int MaxTime = (1000/MaxFPS);                                         
DWORD SleepTime;                                    




WPARAM __fastcall WorldRefresh(void *thisPointer, void* _edx) 
{
    void *that; 
    char state; 
    struct tagMSG Msg; 
    HACCEL hAccel; 
    int PerformanceTime; 
    unsigned __int64 lpFrequency; 
    unsigned __int64 lpPerformanceCount; 
    unsigned __int64 lpPerformanceStep; 
    that = thisPointer; 
    QueryPerformanceFrequency((LARGE_INTEGER*)&lpFrequency);
    hAccel = LoadAcceleratorsA(NULL, (LPCSTR)0x71); 
    Msg.message = 0; 
    PeekMessageA(&Msg, NULL, WM_NULL, WM_NULL, PM_NOREMOVE); 
    while (Msg.message != 0x12) 
    {
        __asm pushad 
        if (*((BYTE*)that+0x9d)) state = (!!PeekMessageA(&Msg, NULL, WM_NULL, WM_NULL, PM_REMOVE)); 
        else state = (!!GetMessageA(&Msg, NULL, 0, 0)); 
        if (state) 
        { 
            if ((!hAccel) || (!(*(DWORD*)that+0x38)) || (!TranslateAcceleratorA(*((HWND*)that+0x38), hAccel, &Msg))) 
            { 
                TranslateMessage(&Msg); 
                DispatchMessageA(&Msg); 
            } 
            ((WREngineFunc)WREngineFuncPtr)(); 
        } 
        else 
        { 
            if ((*((BYTE*)that+0x9d)) && (*(BYTE*)WREngineActive)) 
            { 
                QueryPerformanceCounter((LARGE_INTEGER*)&lpPerformanceCount); 
                int tmpActive = ((RefreshEntities)RefreshEntitiesPtr)(that); 


                QueryPerformanceCounter((LARGE_INTEGER*)&lpPerformanceStep); 
                if (tmpActive < 0) SendMessageA(*((HWND*)that+0x38), WM_COMMAND, 0x9C46, 0); 


                PerformanceTime = (int)(lpFrequency / (lpPerformanceStep-lpPerformanceCount)); 
                if (PerformanceTime) PerformanceTime = 1000 / PerformanceTime; 
                if (MaxTime > PerformanceTime) 
                { 
                    SleepTime = (MaxTime - PerformanceTime); 
                    Sleep(SleepTime); 
                } 
            } 
        } 
        __asm popad 
    } 
    if (hAccel) DestroyAcceleratorTable(hAccel); 
    return Msg.wParam; 
}




void HookWorldRefresh()
{
    Intercept(INST_CALL,0x00505869,(DWORD)WorldRefresh,5); 
    Intercept(INST_CALL,0x00505bfc,(DWORD)WorldRefresh,5); 
}

Ultilities.h
Code:
#define INST_NOP  0x90
#define INST_CALL 0xE8
#define INST_JMP  0xE9
#define INST_BYTE 0x00
#define SHORT_JZ  0x74
#define STD_CALL_LEN 0x05
#define INST_JMPR  0xEB
#define INST_RET 0xC3
#define _DWORD DWORD
#define _WORD WORD
#define _BYTE BYTE


#include <windows.h> 


LPVOID MemoryCopy(DWORD destination, DWORD source, int length)
{
    DWORD oldSource      = 0;
    DWORD oldDestination = 0;


    VirtualProtect((LPVOID)source,length,PAGE_EXECUTE_READWRITE,&oldSource);
    VirtualProtect((LPVOID)destination,length,PAGE_EXECUTE_READWRITE,&oldDestination);


    memcpy((void*)destination,(void*)source,length);


    VirtualProtect((LPVOID)destination,length,oldDestination,&oldDestination);
    VirtualProtect((LPVOID)source,length,oldSource,&oldSource);


    return (LPVOID)destination;
};


void MemoryCopy(void *Destination, void *Source, size_t Size)
{
    unsigned long p1, p2;
    VirtualProtect(Destination, Size, PAGE_EXECUTE_READWRITE, &p1);
    VirtualProtect(Source, Size, PAGE_EXECUTE_READWRITE, &p2);
    CopyMemory(Destination, Source, Size);
    VirtualProtect(Destination, Size, p1, &p1);
    VirtualProtect(Source, Size, p1, &p2);
};


void *DetourFunction(BYTE *src, const BYTE *dst, const int len) // credits to gamedeception
{
    BYTE *jmp = (BYTE*)malloc(len+5);
    DWORD dwback;
    VirtualProtect(src, len, PAGE_READWRITE, &dwback);
    memcpy(jmp, src, len); jmp += len;
    jmp[0] = 0xE9;
    *(DWORD*)(jmp+1) = (DWORD)(src+len - jmp) - 5;
    src[0] = 0xE9;
    *(DWORD*)(src+1) = (DWORD)(dst - src) - 5;
    VirtualProtect(src, len, dwback, &dwback);
    return (jmp-len);
}




DWORD Intercept(int instruction, DWORD source, DWORD destination, int length)
{
    DWORD realTarget;
    LPBYTE buffer = new BYTE[length];


    memset(buffer,0x90,length); 


    if(instruction != INST_NOP && length >= 5)
    {
        buffer[(length-5)] = instruction;
        DWORD dwJMP = (DWORD)destination - (source + 5 + (length-5));
        memcpy(&realTarget,(void*)(source+1),4);
        realTarget = realTarget + source + 5;
        memcpy(buffer + 1 + (length - 5),&dwJMP,4);
    }


    if(instruction == SHORT_JZ)
    {
        buffer[0] = instruction;
        buffer[1] = (BYTE)destination;
    }


    if(instruction == INST_BYTE)
    {
        buffer[0] = (BYTE)destination;
    }


    MemoryCopy(source,(DWORD)buffer,length);
    delete[] buffer;


    return realTarget;
}

Code:
BOOL APIENTRY DllMain( HINSTANCE hModule, DWORD ul_reason_for_call, LPVOID lpReserved )
{
    switch (ul_reason_for_call)
    {
        
    case DLL_PROCESS_ATTACH:
        {
            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            hLThis = hModule;
                hL = LoadLibrary("KealyFPSLimiter.dll");
                if (!hL) return false;
                CreateConsole();
              printf("Hello Madknight, im KealyFPSLimiter.dll and im loaded");
            p[0] = GetProcAddress(hL,"InitCommonControls");
            HookWorldRefresh();
            DetourTransactionCommit();
            break;
        }
    case DLL_PROCESS_DETACH:
        {
            DetourTransactionBegin();
            DetourUpdateThread(GetCurrentThread());
            DetourTransactionCommit();
            break;
        }
    }
    return TRUE;
}
 
Upvote 0
Newbie Spellweaver
Joined
Oct 20, 2007
Messages
28
Reaction score
2
Thank you for your answer and ye iam 100% sure thats my dll loads with the engine :) because i have the disable function for "Version not matched" and its only disabled if i start with my .dll, but whatever its still dont work :/ btw your fps looks to 99% the same like kealys one, just some functions are written differently. :p i tryed now both and NWK ones... have you a next idea xD?
 
Upvote 0
Elite Diviner
Joined
Feb 8, 2012
Messages
439
Reaction score
867
have you a next idea xD?

Yes : )

There are two options here i think, the first one is, that something with your code is wrong, the second thing is that something general is wrong (every error/misstake wich is not related to your code).
So to find out where you have to seek the error try the following:

1. Try to use my Adpation and see if my 99% Kealy Code work for you

if (this->worksforyou)
{
// Then something must be wrong with your code and you should take deeper look into it, comparing, debug messaging
}
else
{
// So my code also not work for you wich means something must be wrong in General
}

2. Report here if you have an General or Code related misstake or you already found the solution and say "thread can be closed" ^^
 
Upvote 0
Newbie Spellweaver
Joined
Oct 20, 2007
Messages
28
Reaction score
2
Ok thanks to Darn & MadKnight ^^

Problem was this lines:
PHP:
    this->MaxFPS = 60;
    this->MaxTime = (1000/MaxFPS);
    this->SleepTime;

Old One:
PHP:
CTweaks::CTweaks()
{
    // Engine addresses pointers
    this->WREngineFuncPtr = 0x004a73b0;
    this->RefreshEntitiesPtr = 0x00425960;
    this->WREngineActive = (BYTE*)0x006ddf58;
}

void CTweaks::HookWorldRefresh()
{
    this->MaxFPS = 60;
    // Right here it is possible to load the max fps from a configuration file, or what so ever.
    // Example : this->MaxFPS = Config->Engine.FPSLimit;

    this->MaxTime = (1000/MaxFPS);
    // Two calls to our WorldRefresh function, only one of them is used, but the second one is just in case.
    Memory.Intercept(IMemory::_I_CALL, 0x00505869, (DWORD)WorldRefresh, 5);
    Memory.Intercept(IMemory::_I_CALL, 0x00505bfc, (DWORD)WorldRefresh, 5); 
}

New One:
PHP:
CTweaks::CTweaks()
{
    // Engine addresses pointers
    this->WREngineFuncPtr = 0x004a73b0;
    this->RefreshEntitiesPtr = 0x00425960;
    this->WREngineActive = (BYTE*)0x006ddf58;
    this->MaxFPS = 60;
    this->MaxTime = (1000/MaxFPS);
    this->SleepTime;
}

void CTweaks::HookWorldRefresh()
{
    // Right here it is possible to load the max fps from a configuration file, or what so ever.
    // Example : this->MaxFPS = Config->Engine.FPSLimit;

    // Two calls to our WorldRefresh function, only one of them is used, but the second one is just in case.
    Memory.Intercept(IMemory::_I_CALL, 0x00505869, (DWORD)WorldRefresh, 5);
    Memory.Intercept(IMemory::_I_CALL, 0x00505bfc, (DWORD)WorldRefresh, 5); 
}


thread can be closed :)
 
Upvote 0
Status
Not open for further replies.
Back
Top