Encrypt and Client-side movement

Posted By: EpsiloN

Encrypt and Client-side movement - 11/28/13 18:29

From the manual :
Quote:
For preventing client hacking or cheating by injection of malicious data packets, always use encryption for MMOGs.

If I use dplay_encrypt , does this mean that I can move the client localy and send position to server , or I still have to use server authority over client? I mean , is it easy to cheat/hack with encription?

*EDIT* This can save a lot of traffic laugh
Posted By: WretchedSid

Re: Encrypt and Client-side movement - 11/28/13 18:47

Yes. Whatever the manual says, it's bullshit and it doesn't help you in any way to authenticate a client and the data they send. It may help against man in the middle attacks and people sniffing on the wire, although, since the manual makes no effort in telling you how the encryption works and what is used to authenticate and authorise clients, I wouldn't exactly trust the system.

Given Gamestudios track record with encryption, which basically boils down to security-through-obscurity and no one actually caring enough to break it since it's not worth the effort... Well, I don't know, use with care and don't trust a client. Ever.
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 11/28/13 18:50

How should this protect you from manipulating the position of your player in memory? Works even in World of Warcraft because the movement is clientsided. If everything would be client sided nobody would play this game because you could also change your health/mana etc in memory. Would be kind of shitty^^
But you should enable it because this way people have to reverse your game before they can do anything. Sending and faking packets is most of the times easier without any encryption and/or hash/crc check.
If you need an anti-cheat I could also provide one with my gui gwen laugh
Posted By: WretchedSid

Re: Encrypt and Client-side movement - 11/28/13 19:03

Originally Posted By: Ch40zzC0d3r
If you need an anti-cheat I could also provide one with my gui gwen laugh

Sounds familiar

By the way, I'm not sure what I should think of someone with a leetspeak username and no track record in cryptography (or anything, really), trying to sell an anti-cheat system with a GUI package. Is there a chance to peer-review it?

Edit: Error-whateverthenumberis pointed rightfully out that we don't know yet if you are selling it. But why would you build snakeoil if you don't want to sell it?
Posted By: Error014

Re: Encrypt and Client-side movement - 11/28/13 19:49

Quote:
Error-whateverthenumberis


I'm offended. There is no dash in my name.
Posted By: WretchedSid

Re: Encrypt and Client-side movement - 11/28/13 19:53

The dash is silent :\
Posted By: Error014

Re: Encrypt and Client-side movement - 11/28/13 19:54

You are silent!


EDIT: Come to think of it, you are not really silent, no.
Posted By: WretchedSid

Re: Encrypt and Client-side movement - 11/28/13 19:54

I know. I'm eating. Didn't your mom teach you manners and told you that you shouldn't talk while eating?
Posted By: Error014

Re: Encrypt and Client-side movement - 11/28/13 19:56

Well, I am not eating. I am just defending myself after you, in obvious malicious intent, misspell my name.

How could you.
Posted By: Superku

Re: Encrypt and Client-side movement - 11/28/13 19:56

Not this again.
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 11/28/13 20:13

I dont want to sell it -.-
Everything is free, if nobody does a thing I need to do something and upload so we have something we can work with. And NO the ac is not made in vb.
Its made in C++ compiled as dll. Ive got all the basics like scanning for windowtitle, process name, looping through all loaded dlls, scanning md5 and for known patterns and so on but these are easy to track so I did some special work on it. First of all Im hooking engine frame, present/endscene reset and dip (DrawIndexPrimitives) and checking for return address and modified memory (crc32) in these regions, not whole module because of the speed gain.
Im also doing maaany anti debugging tricks (wont post them here are up to 12 functions), Ive also encrypted all strings, added an own function to destroy the game if a hack or something was detected (No APIs used, Im writing directly 0xFF into the application memory). I also crypted it in runtime with Code Virtualizer and I packed it with UPX, but I will use a new packer soon something like Themida or VMProtect.
I also hooked 10 standard "hacking" APIs like LoadLibrary, OpenProcess, Write/ReadProcessMemory and so on. Always checking handles, names etc.
I will do these checks if commercial released here with a database so every user can add and review hacking tools etc.
Posted By: Uhrwerk

Re: Encrypt and Client-side movement - 11/28/13 22:36

Why would you want to do this?
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 11/28/13 22:43

To prevent people from cheating?
Or what do you mean? I dont get it lol
Posted By: Uhrwerk

Re: Encrypt and Client-side movement - 11/28/13 22:50

Cheating in which game?
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 11/28/13 23:04

In the game of the threadtarter for example. Many people create online games here and want a little bit security shocked
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 11/29/13 05:01

I never ment I'll make the char stats and inventory client-side. Thats something that needs updating once every minute, for example. But the position is constantly updating.
Nevermind the problem laugh I wont use it. I just tought from that statement from the manual, that I can use client-side movement now.

I have a prediction that is off by 20 quants, and I cant avoid it, because the engine moves things differently on high speeds. I'll try to make it a little more precise, but I doubt I'll get closer to the truth.

Client-side movement would be best, but I guess it'll never happen...

PS.: Anyone can think of a way to make the rendering 100ms late? Like in Counter-Strike Source.
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 11/29/13 06:10

You just need a good prediction formula I dont thin its the engines fault.
Im lerping my positions and doing ping/velocity prediction.
Works fine up to 200ms pings but keep in mind im coding a fps no rpg.
You dont even have to be too precise.
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 11/30/13 10:30

"the engines fault"
I once posted here for help because of a test I made that gave a very wrong position.

MMO btw. Dont smile like that :}

I used c_move with a speed X times greater than the speed per frame for Y frames (wich adds up to the total distance, on theory) and the two entities were off by 30 quants when gliding on a wall. I dont remember wich (the instant or actual moving entity) one got further right now.

I discarded that test and code.
Now I use the same principle , multiplying the distance that needs to be covered for certain number of frames.
But my prediction is (at best) off by 7-8 quants, wich is fine. But when it reaches 20 quants (more than half of the time) I move the entity towards the prediction, wich produces visible 'artefacts'. If I dont move it , it'll be more than 20 quants next time and the ent has to snap to place.

I see we're getting off topic on this one, but I hope its fine.
Could you give me some clues how you do it? Keep in mind I update 5 times/sec.

Here's my prediction (simple extrapolation really) code:
Code:
var temp_pos[3];
		vec_set(temp_pos[0],my.x);
		var temp_speed[3];
		var temp_trace[3];
		if(my.movement_input == 1) { temp_speed[0] = ((( 16 / time_step ) / 1000 ) * (my.movement_speed * time_step )) * latency_time; temp_speed[1] = 0; }
		if(my.movement_input == 2) { temp_speed[0] = ((( 16 / time_step ) / 1000 ) * ((my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; temp_speed[1] = ((( 16 / time_step ) / 1000 ) * (my.movement_speed * time_step )) * latency_time; }
		if(my.movement_input == 3) { temp_speed[0] = ((( 16 / time_step ) / 1000 ) * ((my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; temp_speed[1] = ((( 16 / time_step ) / 1000 ) * ((-my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; }
		if(my.movement_input == 4) { temp_speed[0] = ((( 16 / time_step ) / 1000 ) * (-my.movement_speed * time_step )) * latency_time; temp_speed[1] = 0; }
		if(my.movement_input == 5) { temp_speed[0] = ((( 16 / time_step ) / 1000 ) * ((-my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; temp_speed[1] = ((( 16 / time_step ) / 1000 ) * ((my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; }
		if(my.movement_input == 6) { temp_speed[0] = ((( 16 / time_step ) / 1000 ) * ((-my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; temp_speed[1] = ((( 16 / time_step ) / 1000 ) * ((-my.movement_speed * 0.7142857142857143) * time_step )) * latency_time; }
		if(my.movement_input == 7) { temp_speed[0] = 0; temp_speed[1] = ((( 16 / time_step ) / 1000 ) * (my.movement_speed * time_step )) * latency_time; }
		if(my.movement_input == 8) { temp_speed[0] = 0; temp_speed[1] = ((( 16 / time_step ) / 1000 ) * (-my.movement_speed * time_step )) * latency_time; }
		if(my.movement_input == 0) { temp_speed[0] = 0; temp_speed[1] = 0; }
		debug_var[1] = latency_time;
		debug_var[2] = temp_speed[0];
		debug_var[3] = temp_speed[1];
		temp_speed[2] = 0;
		c_move(me , vector(temp_speed[0],temp_speed[1],temp_speed[2]) , NULLVECTOR , GLIDE );

		vec_set( temp_speed , NULLVECTOR );
		vec_set( temp_trace , vector( my.x , my.y , my.z - 150 + my.foot_height ) );
		c_trace( my.x , temp_trace , IGNORE_PASSABLE | IGNORE_ME | USE_BOX );
		if( !trace_hit )
		{
			vec_set( target , temp_trace );
		}
		my.soil_height = target.z - my.foot_height;
		
		if(my.z > my.soil_height + ( 5 + 20 * my.soil_contact ) * time_step )
		{
			my.soil_contact = 0;
			temp_speed[2] = maxv( temp_speed[2] - 9 * time_step , -90 );
		}
		else
		{
			my.soil_contact = 1;
			temp_speed[2] = 0;
			my.z = my.soil_height;
		}

		if( temp_speed[2] ) { c_move( me , nullvector , vector( 0 , 0 , temp_speed[2] * time_step ) , IGNORE_PASSABLE ); }
		my.z = maxv( my.soil_height , my.z );

		vec_set(my.predicted_current_x,my.x);
		vec_set(my.x,temp_pos[0]);



The function takes "latency_time" as an argument, to use for duration of movement, like 200ms between 2 updates.

I tought about using the same prediction client-side to move the entity just a little bit toward the upcomming position, so that it doesnt snap or get corrected when the pos arrives. Thats the best I can think off...

PS.: The "(( 16 / time_step ) / 1000 )" is used to get the duration of one frame in ms(i think, cant remember anymore)
It gets multiplied by speed to get distance to be covered for 1 ms, and then multiplied by latency_time to give total distance for the requested time.
Maby thats what gives me errors, but it all added up on theory...
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 11/30/13 11:24

Well your code is rather long and I dont have too much time today.
However, are you doing c_move only clientsided or on server and client?
What Im doing:
Im doing my whole movement clientsided, gravity, jumping, etc etc.
Im sending my new position all time and the whole vector because it needs less overhead as if I would send every position as soon as it gets changed.
On the server Im lerping with a ping factor, means higher ping more smooth lerping.
Then Im calculating the velocity out of the movement multiply it with the ping and add it to the x and y coordinate:

Code:
vVelocity[pPlayer].x = speedX * ping/1000;
vVelocity[pPlayer].y = speedY * ping/1000;

...

newpos = receive(player.x);
newpos.x += vVelocity[pPlayer].x;
newpos.y += vVelocity[pPlayer].y;
vec_lerp(player, newpos, pingoffset);



I wont predict my z pos because the players would glide into the ground if they fall from high places grin
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/01/13 09:31

The important part is this :
Code:
if(my.movement_input == 1)
		{
			temp_speed[0] = ((( 16 / time_step ) / 1000 ) * (my.movement_speed * time_step )) * latency_time;
			temp_speed[1] = 0;
		}
		c_move(me , vector(temp_speed[0],temp_speed[1],temp_speed[2]) , NULLVECTOR , GLIDE );


This is the code that predicts where the entity should be based on "latency_time" given. It simply moves the entity forward to simulate latency_time passed.

I checked the math, although there is an easier way to get quants/ms, this works accurately. I dont understand where is the problem, because I even include the actual latency time to correct for lag. I'm testing everything on 7ms. (one comp.)
The client moves localy through C_Move , the Server moves the client with C_Move to catch up and use more accurate collision detection, and uses prediction to send the 'next' expected position.
So I'm thinking of including the prediction function on the client and to interp between the actual client position and the expected server future response.
This is all without changing pan angles or anything, simply moving the entity forward on client and server simultaneously and using this function to predict where the client should be on the next update sent. Also , will tune up the time_frame variable to get average frame time on time_step.

Maby even adding a 'speed-up' effect on the client could reduce the error given by the engine.

I dont know why it gives wrong results, cuz in theory it should be extremely accurate.

PLEASE , HELP! grin
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/01/13 11:23

After tweaking the script and setting time_smooth to 0.99 I get almost constant difference in position.
It looks like its not the engine thats causing the difference, but my script.


This is the update counter for each player (separately)
Code:
if(my.movement_input != 0 || vec_dist( my.x , my.last_sent_position_x ) > 32)
		{
			if(my.update_time_passed >= 20)
			{
				predict_position( 200 );
				send_skill( my.predicted_current_x, SEND_VEC | SEND_ALL );
				vec_set( my.last_sent_position_x , my.predicted_current_x );
				my.update_time_passed = 0;
			}
			my.update_time_passed += time_step;
		}




And this is the update I send immediately after the player changes input (because first update will come after 200ms.)
Code:
if(my.old_movement_input != my.movement_input)
		{
			my.old_movement_input = my.movement_input;
			predict_position( my.latency );
			send_skill( my.predicted_current_x, SEND_VEC | SEND_ALL );
		}


my.latency is stored and send on each client to the server upon connecting.


Any toughts what is causing the constant difference?
The first update I send with event is off by 8.x quants. The others are 18.8x quants. (I think its ahead of my actual player,btw. Cant see that fast)
Posted By: Ch40zzC0d3r

Re: Encrypt and Client-side movement - 12/01/13 11:26

Man, are you updating your ping?
I hope you know that your ping right after connecting is much higher.
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/01/13 19:06

Yes , I am updating the ping constantly.

After testing a few times , the first time after I posted I got, again, variable result, but now its stable again. No reason, no change.

Just tested 2 times , fixed error between current and predicted position.

I'll try to see if the predicted is further then the current position and I'll try sending a prediction with different combinations of 200ms and latency time / 2 added or substracted and I'll post again.





EDIT: Unstable again, gives variable results. I have no idea what is wrong. Latency is fixed at 7ms.
I gave some tought on this one
Code:
if(my.update_time_passed >= 20)
{
	my.update_time_passed += time_step;
}


time_step times 75 frames (on 60fps) gives 20. I'm not updating very often laugh

Any idea how to make it count in ms? This ticks stuff is extremely confusing...
Posted By: Superku

Re: Encrypt and Client-side movement - 12/01/13 20:24

16 ticks equal 1 second, that means when you write

d += time_step; // or better time_frame
if(d >= 16) error("hello");

the error message pops up after 1 second.
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/01/13 21:02

Yes, but I wanned to turn that into ms. , eg:

d += time_var; // add duration of frame in ms
if(d >= 200) error("hello"); // 200ms.

Nevermind that, I ended up with this:
Code:
if(my.update_time_passed >= ((16 / time_step) / 5) )
{
	my.update_time_passed += 1;
}


5 = how many times/sec.

The other problem still stands. I just ran the client for 30 mins. At first, the error was almost constant (depending on direction, I mean movement_input being different, it gave different errors, but they almost remained constant). I just checked the client and the error now was adding up with 0.5 quants per update, corrected at 20 quants to 16 or 17, then adding up again.

I almost have a correct prediction method, but I'm truly lost now!

I dont have any ideas what could be wrong to give 18 quants difference even when updating 5 times/sec instead of 0.8 times/sec.
In theory the error should have been reduced down to 3 quants, due to often updating, but it remains around 18.


The even stranger part is that I was updating once every 1.2 sec. with my previous wrong counter, and I was predicting for 200ms. in the future, but the position was still almost correct, like it was ment for 1200ms silence, not 200 ms.


I have a ghost in my laptop that is joking with me! frown
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/02/13 11:04

I deleted all my client-server code and downloaded Superku's Multiplayer script. Adapted it to my GUI and added rotation, but I just noticed its client authority.

I'll start from scratch again :| Without prediction, to see if the latency produced error in position will be smaller than 18 or even 8 quants (it should be with 7ms lag, at 160 quants/sec.)...
Posted By: Superku

Re: Encrypt and Client-side movement - 12/02/13 17:43

Quote:
Adapted it to my GUI and added rotation, but I just noticed its client authority.

What does that mean and why is it bad?
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/02/13 21:53

It means the client controls his position , not the server.

Its bad because it makes cheating easy. Someone can make 'speed' or 'teleport' hacks.

The only way this could work is to make the server force the client to move at a certain position if the client moved too far during the last update, exceeding the predefined maximum client speed, for example. laugh

But this way you must have a reasonable fixed speed for all entities. Otherwise if you're making a game with a slow warrior and a fast rogue, the cheat comes into play, making the warrior as fast as the rogue, but twice tougher...
Posted By: Superku

Re: Encrypt and Client-side movement - 12/02/13 22:11

How do you plan to make a normal multiplayer game without client side movement? AFAIK all games (including for example CoD) do it this way, the server simply checks the movement for hacks (for instance flying, too fast, ...), approves it and sends it to the other clients.
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/03/13 05:37

You make the client send only input. The server moves the player and sends back the result.

With high latency, this becomes a problem, because the client seems unresponsive. You have to noticeably wait a fraction of a second to start moving after a key is pressed. To deal with that, you make local movement, but as soon as an update arrives, you correct the local position with the updated server position.


Thats where my problem comes from, my client and server are out of sync by 18 quants constant, and I cant pinpoint where this comes from. I'll try today without any prediction, starting from scratch, to see how much the difference will be between the client and server positions for 7ms latency. It should be just a few quants, no more...

Thats how a lot of games do it, btw, but they've learned their lessons laugh I remember Counter-Strike being the most noticeable. Everybody got speed hacks back in the original. But, if you've noticed for example WoW, if you lag, you suddenly appear somewhere else. It doesnt matter that you just ran half a mile...
Posted By: EpsiloN

Re: Encrypt and Client-side movement - 12/03/13 19:53

Starting from scratch , I tried the built in sync of Acknex and I failed. The engine sends updates and it isnt that inaccurate, but I couldnt make the Ghost entity follow the actual player entity smoothly, because the Server is just a little out of sync.

However , I started blank again and tested a simple function to predict position.
If I use 120 c_move calls, including gravity(to simulate a second passed on 60fps) the function ends up exactly where my player will be in 60 frames. The problem is that, I think, I cannot use that many c_move calls just for one client in one frame. If I have 1000 clients, this becomes 120 000 in one frame. If I use it at different frames(best scenario) it ends up at 2000, wich is still a lot. Not counting the 2 actual c_move calls per client to move the client every frame.

So I instead use one c_move call with 16 times the speed per tick to get the movement per second.

I send move instruction from the client and after one second I send stop instruction. I also send Pan with the move instruction, and the result is exact XYZ position on both client and server.
But the prediction is off by 0.1 to 2.0 quants.
I guess its all right for such small numbers, but I still have to script it to test and see what the result is.
I guess the 18 quants difference in my previous attemp was comming from the conversion from ticks to ms and using quants per ms to calculate the distance, but I dont intend to spend time figuring out why it didnt work.
I'm using ticks now (16/sec.)

Here are the codes so far:

Superku's gravity
Code:
function apply_gravity()
{
	var move_direction[3];
	var temp_trace[3];

	vec_set( temp_trace , vector( my.x , my.y , my.z - 150 + my.foot_height ) );
	c_trace( my.x , temp_trace , IGNORE_PASSABLE | IGNORE_ME | USE_BOX );
	if( !trace_hit )
	{
		vec_set( target , temp_trace );
	}
	my.soil_height = target.z - my.foot_height;
		
	if(my.z > my.soil_height + ( 5 + 20 * my.soil_contact ) * time_step )
	{
		my.soil_contact = 0;
		move_direction[2] = maxv( move_direction[2] - 9 * time_step , -90 );
	}
	else
	{
		my.soil_contact = 1;
		move_direction[2] = 0;
		my.z = my.soil_height;
	}

	if( move_direction[2] ) { c_move( me , nullvector , vector( 0 , 0 , move_direction[2] * time_step ) , IGNORE_PASSABLE ); }
	my.z = maxv( my.soil_height , my.z );
}



Client trigger and movement:
Code:
if(key_space == 1)
		{
			while(key_space == 1) { wait(1); }
			
			my.movement_input = 1;
			send_skill( my.movement_input , 0 );
			send_skill( my.pan , 0 );
// Prediction
////////////////
			var tmpvar1[3];
			vec_set( tmpvar1 , my.x );

			c_move( me , vector( 160 , 0 , 0 ) , NULLVECTOR , GLIDE );

			apply_gravity();

			vec_set( my.x , tmpvar1 );
// Actual movement
/////////////////////
			counter1 = 0;
			while(counter1 < 16)
			{
				counter1 += time_step;
				c_move( me , vector( 10 * time_step , 0 , 0 ) , NULLVECTOR , GLIDE );
				apply_gravity();
				wait(1);
			}

			my.movement_input = 0;
			send_skill( my.movement_input , 0 );
		}



Server movement:
Code:
if(my.movement_input == 1) { move_direction[0] = 10 * time_step; move_direction[1] = 0; }
		if(my.movement_input == 2) { move_direction[0] = (10 * 0.7142857142857143) * time_step; move_direction[1] = (10 * 0.7142857142857143) * time_step; }
		if(my.movement_input == 3) { move_direction[0] = (10 * 0.7142857142857143) * time_step; move_direction[1] = -(10 * 0.7142857142857143) * time_step; }
		if(my.movement_input == 4) { move_direction[0] = -10 * time_step; move_direction[1] = 0; }
		if(my.movement_input == 5) { move_direction[0] = -(10 * 0.7142857142857143) * time_step; move_direction[1] = (10 * 0.7142857142857143) * time_step; }
		if(my.movement_input == 6) { move_direction[0] = -(10 * 0.7142857142857143) * time_step; move_direction[1] = -(10 * 0.7142857142857143) * time_step; }
		if(my.movement_input == 7) { move_direction[0] = 0; move_direction[1] = 10 * time_step; }
		if(my.movement_input == 8) { move_direction[0] = 0; move_direction[1] = -10 * time_step; }
		if(my.movement_input == 0) { move_direction[0] = 0; move_direction[1] = 0; }
		c_move( me , move_direction , NULLVECTOR , GLIDE );
		
		apply_gravity();


I'll try next to add the prediction to the server code and use it just to eliminate Latency, then move the client every frame to get correct results from collision and correct frame-rate movement. This will limit the error to just the quant that I described above.
Next, I'll try to include a code to correct the server movement if the server receives a change in Pan between 2 updates (wich would desync the client-server ents) by moving the server back in time at a previous position, correcting Pan angle, predicting how far the client went during the latency and continuing with the normal frame-rate movement to keep both entities in sync. The server will send the updated position once each second with a floating start point depending on client behaviour. This deals with the problem of a global update clock sending 1000's of packets at once, by making the update clock local for each entity.
The back-in-time part will also be used to check if a client hit another client with a projectile X ms ago...


If I shape this into a working script, everyone wins laugh so , Please , drop in any opinions and ideas , because this works not only for MMOs, but for FPS and other styles.

So , any Ideas?



PS.: My main concern is the prediction, I need to figure out a way to make it as perfect as normal movement without using 1000's of c_move calls every frame (Oh, forgot the 1000's of c_trace calls for gravity.)
© 2024 lite-C Forums