Welcome!

Join our community of MMO enthusiasts and game developers! By registering, you'll gain access to discussions on the latest developments in MMO server files and collaborate with like-minded individuals. Join us today and unlock the potential of MMO server development!

Join Today!

FPS Limiter

Status
Not open for further replies.
Newbie Spellweaver
Joined
Jun 18, 2010
Messages
86
Reaction score
147
Hai.
I wish to introduce a little tweak for engine.exe that hasn't been done in the whole KalOnline scene yet. (Haven't seen any.)

Little parenthesis : in case this is the wrong section, I demand your pardon and beg of you to correct my mistake.

Now, back to the topic.
Before hurrying to the code and copy/pasting the poop in 'kthxbye' mode, you should know that I have been playing with the good ol' p-server engine.exe for quite a while now, for nearly two years.
Roaming in it with no real aim, discovering stuff, remembering those, reusing them later, creating tweaks, cheats, workarounds, et cetera.
Most of it is nothing that could be released on a server development forum, since some of them are real cheats, others are just cookie-like mods.
(cf. accelerating the in-game daytime, having 3 days pass by in 3 seconds (sweet effect, for real.))
So yeah, I've kinda been looking forward to releasing something useful to the server dev community (so far I've been doing only very bad things /evil_laugh).

Guess the time has come now ┐( ̄ー ̄)┌
A bit of history before that :
A few years ago, as I was still discovering server maps and kal files on my local server,
I noticed that the FPS counter was quite irregular (even back on my Pentium IV, 2.0GHz).
I went to the edge of the map, where no ground is drawn anymore, and looked up the sky.
2500 frames per second.
Now I don't know whether these korean people have forwarded themselves so far in the future they were already expecting Sony's new hyper-mega-epic 2500Hz display monitor, or just engineered their code like mentally disturbed camels. (Looking forward to this)
Anywho, now that I got a sweet new computer, quad core 3.0Ghz, 285gtx, quite a beast (well, at least it was a year ago. /emo)
It happens that the CPU usage engine.exe sucks is just exaggerated.
No matter what environment it runs in, engine.exe will use ALL the power it has at hand, causing overheating at laptops, overall slowdowns and, omg.. wait, I think my CPU just got baked! ( ゜Д゜ )

Now what really shocked me (YA IT HURT MY FEELINGS~!), is that after so many years, none has even thought of making this, nor has inixsoft (or have they ? don't have client, so can't know either way.)
But uhm, well, whatever.
Let's get straight to the point (finally).

In the first place, this is an add-on for C++ projects, and NOT a complete project on its own.
If you want to use it, you will have to create a proxy dll project yourself.

Now about the rights, if you use my code, I DEMAND credits.
Besides, since this is the very first and only fps limiter, I will know whenever someone uses it or not.
Beware.

About the code :
The code is commented. Not everything, but enough to get the idea, I hope.
I redirect the 2 calls to that WorldRefreshing function to mine, and hold the whole loop inside it.
This allows me to easily add/modify/remove anything, at any time.
To install the FPS Limiter, you have to call CTweaks::HookWorldRefresh().
And this HAS to be done before engine.exe code is executed. (In theory it's possible to to do before the 3d environment is loaded, but it's quite risky.)

Here it goes.

PHP:
/* Tweaks.h */

#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;
PHP:
/* Tweaks.cpp */

#include "Tweaks.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;

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);
	Core->Intercept(INST_CALL,0x00505869,(DWORD)this->WorldRefresh,5);
	Core->Intercept(INST_CALL,0x00505bfc,(DWORD)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;
}

Seriously, this game doesn't need to run at any higher than 30fps.
Using this FPS limiter, I managed to drop the CPU usage by nearly 60%, whilst having the game still completely playable.

PS: If I ever find another tweak that could be useful here, I will update this thread only and ask a moderator to change its title.

Edit: Added namespace use and includes. Oh and I forgot to mention I compile every of my projects with VisualC++ 2010 Express SP1.
Edit2: Moved namespace and includes to the correct file and fixed a critical error in the code.
 
Last edited:
Junior Spellweaver
Joined
Apr 10, 2007
Messages
185
Reaction score
42
hi and thnx for the nice release
realy usefull hope allot wil do something with it

keep up the good work

greetz
 
Custom Title Activated
Loyal Member
Joined
Apr 5, 2008
Messages
1,325
Reaction score
133
tnx kealy its nice to see you help on development forum too ;)
 

Xca

Experienced Elementalist
Joined
Apr 1, 2011
Messages
206
Reaction score
93
Thanks for the release. I can't believe in all this time no one has thought of this until now.
 
Newbie Spellweaver
Joined
Jun 18, 2010
Messages
86
Reaction score
147
Sweet.

I edited the code, moved the inclues and namespace in Tweaks.h and fixed a serious error.
I was actually using the wrong calling convention for RefreshEntities(), and passed an argument too much, which was causing a stack corruption after several minutes of gaming.
I am even myself surprised it could actually run like this.
 
Joined
Oct 11, 2007
Messages
1,706
Reaction score
517
Sweet.

I edited the code, moved the inclues and namespace in Tweaks.h and fixed a serious error.
I was actually using the wrong calling convention for RefreshEntities(), and passed an argument too much, which was causing a stack corruption after several minutes of gaming.
I am even myself surprised it could actually run like this.

Updating sticky thread :) thanks for contributing. (And heard u were the first to bypass elmo, gz ;P FINALLY I might say, incredible no1 has wont u say? Oh well...)
 
Newbie Spellweaver
Joined
Jun 18, 2010
Messages
86
Reaction score
147
Nope I haven't.
I didn't get to try out KalMax, and I don't think I will unless its population becomes interesting.
On the other hand, I have other things in mind, for the time being. =]
 
Elite Diviner
Joined
Feb 8, 2012
Messages
439
Reaction score
867
I know this Thread is old, but i saw that nearly no Server use this FPS Limiter!
Today its a must have, you can see it on the following Screenshot:


Kealy - FPS Limiter - RaGEZONE Forums

I think many people dont use it, because they dont know how to compile and inject it, so here it is. The DLL is named KealyFPSLimiter.dll and all credits goes to him, i only compiled it and proxied another dll for injection, just read the Readme.txt.
 

Attachments

You must be registered for see attachments list

ASN

Please STAHP!
Joined
Dec 21, 2010
Messages
919
Reaction score
729
I know this Thread is old, but i saw that nearly no Server use this FPS Limiter!
Today its a must have, you can see it on the following Screenshot:


Kealy - FPS Limiter - RaGEZONE Forums

I think many people dont use it, because they dont know how to compile and inject it, so here it is. The DLL is named KealyFPSLimiter.dll and all credits goes to him, i only compiled it and proxied another dll for injection, just read the Readme.txt.

I thought you won't use backdoored sirix stuff and now you proxied this dll to cskill.dll?:p
 
Elite Diviner
Joined
Feb 8, 2012
Messages
439
Reaction score
867
cskill have no virus in it and it is clientside, i never would use sirix code on serverside : )

But feel free to compile Kealys code and proxy an other DLL. But dont use Colorizer.dll its even from him ^^
 
Junior Spellweaver
Joined
Apr 10, 2007
Messages
185
Reaction score
42
but they are stil around
they never leave 100 % ^^

thnx kealy for the code and thnx madknight for the release
wil help some people maybe

greetz
 
Status
Not open for further replies.
Back
Top