about summary refs log tree commit diff
path: root/src/game/server
diff options
context:
space:
mode:
authorMagnus Auvinen <magnus.auvinen@gmail.com>2007-09-09 18:21:14 +0000
committerMagnus Auvinen <magnus.auvinen@gmail.com>2007-09-09 18:21:14 +0000
commit3f4587ede831760b2f6976960658d202c9d847ff (patch)
tree6c3a22251906673e5e7491dcd86faec23887691b /src/game/server
parent350e968f514a00d4a89395ed13e415103390b9d9 (diff)
downloadzcatch-3f4587ede831760b2f6976960658d202c9d847ff.tar.gz
zcatch-3f4587ede831760b2f6976960658d202c9d847ff.zip
a lot of changes. client side prediction added
Diffstat (limited to 'src/game/server')
-rw-r--r--src/game/server/game_server.cpp437
-rw-r--r--src/game/server/game_server.h29
2 files changed, 75 insertions, 391 deletions
diff --git a/src/game/server/game_server.cpp b/src/game/server/game_server.cpp
index ebb35cf1..7ad4ec09 100644
--- a/src/game/server/game_server.cpp
+++ b/src/game/server/game_server.cpp
@@ -9,26 +9,6 @@
 
 data_container *data = 0x0;
 
-// --------- DEBUG STUFF ---------
-const int debug_bots = 3;
-
-// --------- PHYSICS TWEAK! --------
-const float ground_control_speed = 7.0f;
-const float ground_control_accel = 2.0f;
-const float ground_friction = 0.5f;
-const float ground_jump_speed = 13.5f;
-const float air_control_speed = 3.5f;
-const float air_control_accel = 1.2f;
-const float air_friction = 0.95f;
-const float hook_length = 34*10.0f;
-const float hook_fire_speed = 45.0f;
-const float hook_drag_accel = 3.0f;
-const float hook_drag_speed = 15.0f;
-const float gravity = 0.5f;
-const float wall_friction = 0.80f;
-const float wall_jump_speed_up = ground_jump_speed*0.8f;
-const float wall_jump_speed_out = ground_jump_speed*0.8f;
-
 class player* get_player(int index);
 void create_damageind(vec2 p, float angle_mod, int amount);
 void create_explosion(vec2 p, int owner, int weapon, bool bnodamage);
@@ -39,134 +19,6 @@ void create_sound(vec2 pos, int sound, int loopflags = 0);
 void create_targetted_sound(vec2 pos, int sound, int target, int loopflags = 0);
 class player *intersect_player(vec2 pos0, vec2 pos1, vec2 &new_pos, class entity *notthis = 0);
 
-template<typename T>
-T saturated_add(T min, T max, T current, T modifier)
-{
-	if(modifier < 0)
-	{
-		if(current < min)
-			return current;
-		current += modifier;
-		if(current < min)
-			current = min;
-		return current;
-	}
-	else
-	{
-		if(current > max)
-			return current;
-		current += modifier;
-		if(current > max)
-			current = max;
-		return current;
-	}
-}
-
-// TODO: rewrite this smarter!
-void move_point(vec2 *inout_pos, vec2 *inout_vel, float elasticity, int *bounces)
-{
-	if(bounces)
-		*bounces = 0;
-	
-	vec2 pos = *inout_pos;
-	vec2 vel = *inout_vel;
-	if(col_check_point(pos + vel))
-	{
-		int affected = 0;
-		if(col_check_point(pos.x + vel.x, pos.y))
-		{
-			inout_vel->x *= -elasticity;
-			if(bounces)
-				(*bounces)++;			
-			affected++;
-		}
-
-		if(col_check_point(pos.x, pos.y + vel.y))
-		{
-			inout_vel->y *= -elasticity;
-			if(bounces)
-				(*bounces)++;			
-			affected++;
-		}
-		
-		if(affected == 0)
-		{
-			inout_vel->x *= -elasticity;
-			inout_vel->y *= -elasticity;
-		}
-	}
-	else
-	{
-		*inout_pos = pos + vel;
-	}
-}
-
-// TODO: rewrite this smarter!
-void move_box(vec2 *inout_pos, vec2 *inout_vel, vec2 size, float elasticity)
-{
-	// do the move
-	vec2 pos = *inout_pos;
-	vec2 vel = *inout_vel;
-	
-	float distance = length(vel);
-	int max = (int)distance;
-	
-	vec2 offsets[4] = {	vec2(-size.x/2, -size.y/2), vec2( size.x/2, -size.y/2),
-						vec2(-size.x/2,  size.y/2), vec2( size.x/2,  size.y/2)};
-	
-	if(distance > 0.00001f)
-	{
-		vec2 old_pos = pos;
-		for(int i = 0; i <= max; i++)
-		{
-			float amount = i/(float)max;
-			if(max == 0)
-				amount = 0;
-			
-			vec2 new_pos = pos + vel*amount; // TODO: this row is not nice
-
-			for(int p = 0; p < 4; p++)
-			{
-				vec2 np = new_pos+offsets[p];
-				vec2 op = old_pos+offsets[p];
-				if(col_check_point(np))
-				{
-					int affected = 0;
-					if(col_check_point(np.x, op.y))
-					{
-						vel.x = -vel.x*elasticity;
-						pos.x = old_pos.x;
-						new_pos.x = old_pos.x;
-						affected++;
-					}
-
-					if(col_check_point(op.x, np.y))
-					{
-						vel.y = -vel.y*elasticity;
-						pos.y = old_pos.y;
-						new_pos.y = old_pos.y;
-						affected++;
-					}
-					
-					if(!affected)
-					{
-						new_pos = old_pos;
-						pos = old_pos;
-						vel *= -elasticity;
-					}
-				}
-			}
-			
-			old_pos = new_pos;
-		}
-		
-		pos = old_pos;
-	}
-	
-	*inout_pos = pos;
-	*inout_vel = vel;
-}
-
 //////////////////////////////////////////////////
 // Event handler
 //////////////////////////////////////////////////
@@ -784,8 +636,8 @@ void player::reset()
 	release_hooks();
 	
 	pos = vec2(0.0f, 0.0f);
-	vel = vec2(0.0f, 0.0f);
-	direction = vec2(0.0f, 1.0f);
+	core.vel = vec2(0.0f, 0.0f);
+	//direction = vec2(0.0f, 1.0f);
 	score = 0;
 	dead = true;
 	spawning = false;
@@ -863,7 +715,9 @@ void player::try_respawn()
 	
 	spawning = false;
 	pos = spawnpos;
-	defered_pos = pos;
+	
+	core.pos = pos;
+	core.hooked_player = -1;
 	
 
 	health = 10;
@@ -873,8 +727,10 @@ void player::try_respawn()
 	set_flag(entity::FLAG_ALIVE);
 	state = STATE_PLAYING;
 	
+	core.hook_state = HOOK_IDLE;
+	
 	mem_zero(&input, sizeof(input));
-	vel = vec2(0.0f, 0.0f);
+	core.vel = vec2(0.0f, 0.0f);
 		
 	// init weapons
 	mem_zero(&weapons, sizeof(weapons));
@@ -905,13 +761,14 @@ bool player::is_grounded()
 // releases the hooked player
 void player::release_hooked()
 {
-	hook_state = HOOK_RETRACTED;
-	hooked_player = 0x0;
+	//hook_state = HOOK_RETRACTED;
+	//hooked_player = 0x0;
 }
 
 // release all hooks to this player	
 void player::release_hooks()
 {
+	/*
 	// TODO: loop thru players only
 	for(entity *ent = world.first_entity; ent; ent = ent->next_entity)
 	{
@@ -921,11 +778,13 @@ void player::release_hooks()
 			if(p->hooked_player == this)
 				p->release_hooked();
 		}
-	}
+	}*/
 }
 
 int player::handle_ninja()
 {
+	vec2 direction = normalize(vec2(input.target_x, input.target_y));
+	
 	if ((server_tick() - ninjaactivationtick) > (data->weapons[WEAPON_NINJA].duration * server_tickspeed() / 1000))
 	{
 		// time's up, return
@@ -956,18 +815,18 @@ int player::handle_ninja()
 	if (currentmovetime == 0)
 	{	
 		// reset player velocity
-		vel *= 0.2f;
+		core.vel *= 0.2f;
 		//return MODIFIER_RETURNFLAGS_OVERRIDEWEAPON;
 	}
 	
 	if (currentmovetime > 0)
 	{
 		// Set player velocity
-		vel = activationdir * data->weapons[WEAPON_NINJA].velocity;
+		core.vel = activationdir * data->weapons[WEAPON_NINJA].velocity;
 		vec2 oldpos = pos;
-		move_box(&defered_pos, &vel, vec2(phys_size, phys_size), 0.0f);
+		move_box(&core.pos, &core.vel, vec2(phys_size, phys_size), 0.0f);
 		// reset velocity so the client doesn't predict stuff
-		vel = vec2(0.0f,0.0f);
+		core.vel = vec2(0.0f,0.0f);
 		if ((currentmovetime % 2) == 0)
 		{
 			create_smoke(pos);
@@ -1015,6 +874,8 @@ int player::handle_ninja()
 
 int player::handle_weapons()
 {
+	vec2 direction = normalize(vec2(input.target_x, input.target_y));
+	
 	if(config.stress)
 	{
 		for(int i = 0; i < NUM_WEAPONS; i++)
@@ -1175,7 +1036,7 @@ int player::handle_weapons()
 				dir = normalize(target->pos - pos);
 			else
 				dir = vec2(0,-1);
-			target->vel += dir * 25.0f + vec2(0,-5.0f);
+			target->core.vel += dir * 25.0f + vec2(0,-5.0f);
 		}
 	}
 	if (data->weapons[active_weapon].ammoregentime)
@@ -1228,7 +1089,6 @@ void player::tick()
 		try_respawn();
 
 	// TODO: rework the input to be more robust
-	// TODO: remove this tick count, it feels weird
 	if(dead)
 	{
 		if(server_tick()-die_tick >= server_tickspeed()*5) // auto respawn after 3 sec
@@ -1238,205 +1098,30 @@ void player::tick()
 		return;
 	}
 	
-	// fetch some info
-	bool grounded = is_grounded();
-	int wall_sliding = 0;
-	direction = normalize(vec2(input.target_x, input.target_y));
+	//player_core core;
+	//core.pos = pos;
+	//core.jumped = jumped;
+	core.input = input;
+	core.tick();
 	
-	float max_speed = grounded ? ground_control_speed : air_control_speed;
-	float accel = grounded ? ground_control_accel : air_control_accel;
-	float friction = grounded ? ground_friction : air_friction;
-	
-	if(!grounded && vel.y > 0)
-	{
-		if(input.left && col_check_point((int)(pos.x-phys_size/2)-4, (int)(pos.y)))
-			wall_sliding = -1;
-		if(input.right && col_check_point((int)(pos.x+phys_size/2)+4, (int)(pos.y)))
-			wall_sliding = 1;
-	}
-
-	if(wall_sliding)
-		vel.y *= wall_friction;
-	
-	// handle movement
-	if(input.left)
-		vel.x = saturated_add(-max_speed, max_speed, vel.x, -accel);
-	if(input.right)
-		vel.x = saturated_add(-max_speed, max_speed, vel.x, accel);
-		
-	if(!input.left && !input.right)
-		vel.x *= friction;
-	
-	// handle jumping
-	if(input.jump)
-	{
-		if(!jumped && (grounded || wall_sliding))
-		{
-			create_sound(pos, SOUND_PLAYER_JUMP);
-			if(wall_sliding)
-			{
-				vel.y = -wall_jump_speed_up;
-				vel.x = -wall_jump_speed_out*wall_sliding;
-			}
-			else
-				vel.y = -ground_jump_speed;
-			jumped++;
-		}
-	}
-	else
-		jumped = 0;
-		
-	// do hook
-	if(input.hook)
-	{
-		if(hook_state == HOOK_IDLE)
-		{
-			hook_state = HOOK_FLYING;
-			hook_pos = pos;
-			hook_dir = direction;
-			hook_tick = -1;
-		}
-		else if(hook_state == HOOK_FLYING)
-		{
-			vec2 new_pos = hook_pos+hook_dir*hook_fire_speed;
-
-			// Check against other players first
-			for(entity *ent = world.first_entity; ent; ent = ent->next_entity)
-			{
-				if(ent && ent->objtype == OBJTYPE_PLAYER)
-				{
-					player *p = (player*)ent;
-					if(p != this && !p->dead && distance(p->pos, new_pos) < p->phys_size)
-					{
-						hook_state = HOOK_GRABBED;
-						hooked_player = p;
-						break;
-					}
-				}
-			}
-			
-			if(hook_state == HOOK_FLYING)
-			{
-				// check against ground
-				if(col_intersect_line(hook_pos, new_pos, &new_pos))
-				{
-					hook_state = HOOK_GRABBED;
-					hook_pos = new_pos;	
-				}
-				else if(distance(pos, new_pos) > hook_length)
-				{
-					hook_state = HOOK_RETRACTED;
-				}
-				else
-					hook_pos = new_pos;
-			}
-			
-			if(hook_state == HOOK_GRABBED)
-			{
-				create_sound(pos, SOUND_HOOK_ATTACH);
-				hook_tick = server_tick();
-			}
-		}
-	}
-	else
-	{
-		release_hooked();
-		hook_state = HOOK_IDLE;
-		hook_pos = pos;
-	}
-		
-	if(hook_state == HOOK_GRABBED)
-	{
-		if(hooked_player)
-		{
-			hook_pos = hooked_player->pos;
-			
-			// keep players hooked for a max of 1.5sec
-			if(server_tick() > hook_tick+(server_tickspeed()*3)/2)
-				release_hooked();
-		}
-			
-		/*if(hooked_player)
-			hook_pos = hooked_player->pos;
-
-		float d = distance(pos, hook_pos);
-		vec2 dir = normalize(pos - hook_pos);		
-		if(d > 10.0f) // TODO: fix tweakable variable
-		{
-			float accel = hook_drag_accel * (d/hook_length);
-			vel.x = saturated_add(-hook_drag_speed, hook_drag_speed, vel.x, -accel*dir.x*0.75f);
-			vel.y = saturated_add(-hook_drag_speed, hook_drag_speed, vel.y, -accel*dir.y);
-		}*/
-		
-		// Old version feels much better (to me atleast)
-		if(distance(hook_pos, pos) > 46.0f)
-		{
-			vec2 hookvel = normalize(hook_pos-pos)*hook_drag_accel;
-			// the hook as more power to drag you up then down.
-			// this makes it easier to get on top of an platform
-			if(hookvel.y > 0)
-				hookvel.y *= 0.3f;
-			
-			// the hook will boost it's power if the player wants to move
-			// in that direction. otherwise it will dampen everything abit
-			if((hookvel.x < 0 && input.left) || (hookvel.x > 0 && input.right)) 
-				hookvel.x *= 0.95f;
-			else
-				hookvel.x *= 0.75f;
-			
-			vec2 new_vel = vel+hookvel;
-			
-			// check if we are under the legal limit for the hook
-			if(length(new_vel) < hook_drag_speed || length(new_vel) < length(vel))
-				vel = new_vel; // no problem. apply
-		}
-	}
-		
-	// fix influence of other players, collision + hook
-	// TODO: loop thru players only
-	for(entity *ent = world.first_entity; ent; ent = ent->next_entity)
-	{
-		if(ent && ent->objtype == OBJTYPE_PLAYER)
-		{
-			player *p = (player*)ent;
-			if(p == this || !(p->flags&FLAG_ALIVE))
-				continue; // make sure that we don't nudge our self
-			
-			// handle player <-> player collision
-			float d = distance(pos, p->pos);
-			vec2 dir = normalize(pos - p->pos);
-			if(d < phys_size*1.25f)
-			{
-				float a = phys_size*1.25f - d;
-				vel = vel + dir*a;
-			}
-			
-			// handle hook influence
-			if(p->hooked_player == this)
-			{
-				if(d > phys_size*1.50f) // TODO: fix tweakable variable
-				{
-					float accel = hook_drag_accel * (d/hook_length);
-					vel.x = saturated_add(-hook_drag_speed, hook_drag_speed, vel.x, -accel*dir.x);
-					vel.y = saturated_add(-hook_drag_speed, hook_drag_speed, vel.y, -accel*dir.y);
-				}
-			}
-		}
-	}
 	
 	// handle weapons
 	int retflags = handle_weapons();
+	/*
 	if (!(retflags & (MODIFIER_RETURNFLAGS_OVERRIDEVELOCITY | MODIFIER_RETURNFLAGS_OVERRIDEPOSITION)))
 	{
 		// add gravity
-		if (!(retflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY))
-			vel.y += gravity;
+		//if (!(retflags & MODIFIER_RETURNFLAGS_OVERRIDEGRAVITY))
+			//vel.y += gravity;
 	
 		// do the move
 		defered_pos = pos;
-		move_box(&defered_pos, &vel, vec2(phys_size, phys_size), 0);
-	}
+		move_box(&core.pos, &vel, vec2(phys_size, phys_size), 0);
+	}*/
 
+	//defered_pos = core.pos;
+	//jumped = core.jumped;
+	
 	state = input.state;
 	
 	// Previnput
@@ -1446,8 +1131,12 @@ void player::tick()
 
 void player::tick_defered()
 {
+	core.move();
+	core.quantize();
+	pos = core.pos;
+	
 	// apply the new position
-	pos = defered_pos;
+	//pos = defered_pos;
 }
 
 void player::die(int killer, int weapon)
@@ -1478,13 +1167,14 @@ void player::die(int killer, int weapon)
 
 bool player::take_damage(vec2 force, int dmg, int from, int weapon)
 {
-	vel += force;
+	core.vel += force;
 
 	// player only inflicts half damage on self	
 	if(from == client_id)
 		dmg = max(1, dmg/2);
 
-	if (gameobj->gametype == GAMETYPE_TDM && from >= 0 && players[from].team == team)
+	// CTF and TDM,
+	if (gameobj->gametype != GAMETYPE_DM && from >= 0 && players[from].team == team)
 		return false;
 
 	damage_taken++;
@@ -1567,10 +1257,15 @@ void player::snap(int snaping_client)
 {
 	obj_player *player = (obj_player *)snap_new_item(OBJTYPE_PLAYER, client_id, sizeof(obj_player));
 
-	player->x = (int)pos.x;
-	player->y = (int)pos.y;
-	player->vx = (int)vel.x;
-	player->vy = (int)vel.y;
+	core.write(player);
+	
+	if(snaping_client != client_id)
+	{
+		player->vx = 0; // make sure that we don't send these to clients who don't need them
+		player->vy = 0;
+		player->hook_dx = 0;
+		player->hook_dy = 0;
+	}
 
 	if (emote_stop < server_tick())
 	{
@@ -1613,21 +1308,6 @@ void player::snap(int snaping_client)
 			player->emote = EMOTE_BLINK;
 	}
 	
-	player->hook_active = hook_state>0?1:0;
-	player->hook_x = (int)hook_pos.x;
-	player->hook_y = (int)hook_pos.y;
-
-	float a = 0;
-	if(input.target_x == 0)
-		a = atan((float)input.target_y);
-	else
-		a = atan((float)input.target_y/(float)input.target_x);
-		
-	if(input.target_x < 0)
-		a = a+pi;
-		
-	player->angle = (int)(a*256.0f);
-	
 	player->score = score;
 	player->team = team;
 
@@ -2011,7 +1691,7 @@ void mods_tick()
 	if(world.paused) // make sure that the game object always updates
 		gameobj->tick();
 
-	if(debug_bots)
+	if(config.dbg_bots)
 	{
 		static int count = 0;
 		if(count >= 0)
@@ -2019,13 +1699,14 @@ void mods_tick()
 			count++;
 			if(count == 10)
 			{
-				for(int i = 0; i < debug_bots ; i++)
+				for(int i = 0; i < config.dbg_bots ; i++)
 				{
 					mods_client_enter(MAX_CLIENTS-i-1);
 					strcpy(players[MAX_CLIENTS-i-1].name, "(bot)");
 					if(gameobj->gametype != GAMETYPE_DM)
-						players[MAX_CLIENTS-i-1].team = count&1;
+						players[MAX_CLIENTS-i-1].team = i&1;
 				}
+				
 				count = -1;
 			}
 		}
@@ -2187,7 +1868,15 @@ void mods_init()
 
 	players = new player[MAX_CLIENTS];
 	gameobj = new gameobject;
+	
+	// setup core world	
+	for(int i = 0; i < MAX_CLIENTS; i++)
+	{
+		players[i].core.world = &world.core;
+		world.core.players[i] = &players[i].core;
+	}
 
+	//
 	int start, num;
 	map_get_type(MAPRES_ITEM, &start, &num);
 	
diff --git a/src/game/server/game_server.h b/src/game/server/game_server.h
index b691e0de..56f668f6 100644
--- a/src/game/server/game_server.h
+++ b/src/game/server/game_server.h
@@ -85,6 +85,8 @@ public:
 	bool paused;
 	bool reset_requested;
 	
+	world_core core;
+	
 	game_world();
 	int find_entities(vec2 pos, float radius, entity **ents, int max);
 	int find_entities(vec2 pos, float radius, entity **ents, int max, const int* types, int maxtypes);
@@ -229,9 +231,9 @@ public:
 	int last_action;
 	
 	// we need a defered position so we can handle the physics correctly
-	vec2 defered_pos;
-	vec2 vel;
-	vec2 direction;
+	//vec2 defered_pos;
+	//vec2 vel;
+	//vec2 direction;
 
 	//
 	int client_id;
@@ -269,21 +271,14 @@ public:
 	int latency_avg;
 	int latency_min;
 	int latency_max;
-
-	// hooking stuff
-	enum
-	{
-		HOOK_RETRACTED=-1,
-		HOOK_IDLE=0,
-		HOOK_FLYING,
-		HOOK_GRABBED
-	};
 	
-	int hook_state;
-	int hook_tick;
-	player *hooked_player;
-	vec2 hook_pos;
-	vec2 hook_dir;
+	player_core core;
+	
+	//int hook_state;
+	//int hook_tick;
+	//player *hooked_player;
+	//vec2 hook_pos;
+	//vec2 hook_dir;
 
 	//
 	player();