diff --git a/hero_0.gd b/hero_0.gd
new file mode 100644
index 0000000..be28406
--- /dev/null
+++ b/hero_0.gd
@@ -0,0 +1,28 @@
+extends "res://player.gd"
+
+const wallride_speed = 2
+
+master func _integrate_forces(state):
+	._integrate_forces(state)
+	wallride(state)
+
+func wallride(state):
+	var ray = get_node("Ray")
+	# If our feet aren't touching, but we are colliding, we are wall-riding
+	if !ray.is_colliding() and get_colliding_bodies():
+		print("riding")
+		var aim = get_node("Yaw").get_global_transform().basis
+		var direction = Vector3()
+		if Input.is_action_pressed("move_forwards"):
+			direction -= aim[2]
+		if Input.is_action_pressed("move_backwards"):
+			direction += aim[2]
+		#var n = -1 * (state.get_transform() * state.get_contact_local_normal(0))
+		#direction = n.slide(direction) * wallride_speed
+		direction *= 0.1
+		set_gravity_scale(-0.1)
+		apply_impulse(Vector3(), direction)
+		state.integrate_forces()
+	else:
+		# We need to return to falling (we aren't riding anymore)
+		set_gravity_scale(1)
diff --git a/scenes/heroes/0.tscn b/scenes/heroes/0.tscn
index 4e4fbd3..9af2b42 100644
--- a/scenes/heroes/0.tscn
+++ b/scenes/heroes/0.tscn
@@ -20,19 +20,33 @@ radial_segments = 64
 rings = 8
 _sections_unfolded = [ "Resource" ]
 
-[node name="RigidBody" type="KinematicBody"]
+[node name="RigidBody" type="RigidBody" index="0"]
 
 input_ray_pickable = true
 input_capture_on_drag = false
 collision_layer = 1
 collision_mask = 1
+mode = 2
+mass = 1.0
+friction = 0.0
+bounce = 0.0
+gravity_scale = 1.0
+custom_integrator = true
+continuous_cd = true
+contacts_reported = 8
+contact_monitor = true
+sleeping = false
+can_sleep = false
 axis_lock_linear_x = false
 axis_lock_linear_y = false
 axis_lock_linear_z = false
 axis_lock_angular_x = false
 axis_lock_angular_y = false
 axis_lock_angular_z = false
-collision/safe_margin = 0.001
+linear_velocity = Vector3( 0, 0, 0 )
+linear_damp = -1.0
+angular_velocity = Vector3( 0, 0, 0 )
+angular_damp = -1.0
 script = ExtResource( 1 )
 _sections_unfolded = [ "Angular", "Collision", "Linear", "Transform", "Visibility" ]
 
diff --git a/scenes/player.tscn b/scenes/player.tscn
index 334797c..0881952 100644
--- a/scenes/player.tscn
+++ b/scenes/player.tscn
@@ -20,21 +20,33 @@ radial_segments = 64
 rings = 8
 _sections_unfolded = [ "Resource" ]
 
-[node name="RigidBody" type="KinematicBody" index="0" groups=[
-"player",
-]]
+[node name="RigidBody" type="RigidBody" index="0"]
 
 input_ray_pickable = true
 input_capture_on_drag = false
 collision_layer = 1
 collision_mask = 1
+mode = 2
+mass = 1.0
+friction = 0.0
+bounce = 0.0
+gravity_scale = 1.0
+custom_integrator = true
+continuous_cd = true
+contacts_reported = 8
+contact_monitor = true
+sleeping = false
+can_sleep = false
 axis_lock_linear_x = false
 axis_lock_linear_y = false
 axis_lock_linear_z = false
 axis_lock_angular_x = false
 axis_lock_angular_y = false
 axis_lock_angular_z = false
-collision/safe_margin = 0.001
+linear_velocity = Vector3( 0, 0, 0 )
+linear_damp = -1.0
+angular_velocity = Vector3( 0, 0, 0 )
+angular_damp = -1.0
 script = ExtResource( 1 )
 _sections_unfolded = [ "Angular", "Axis Lock", "Collision", "Linear", "Pause", "Transform", "Visibility", "collision" ]
 
diff --git a/scripts/heroes/0.gd b/scripts/heroes/0.gd
index 6567e8c..3d20698 100644
--- a/scripts/heroes/0.gd
+++ b/scripts/heroes/0.gd
@@ -9,22 +9,32 @@ var since_on_wall = 0
 var last_wall_normal = Vector3()
 var wallride_forgiveness = .150
 
-func control_player(delta):
-	wallride(delta)
-	.control_player(delta)
+func control_player(state):
+	.control_player(state)
+	wallride(state)
+
+func wallride(state):
+
+	var ray = get_node("Ray")
+	var vel = get_linear_velocity()
 
-func wallride(delta):
 	# If our feet aren't touching, but we are colliding, we are wall-riding
-	if is_on_wall() and not is_on_floor() and velocity.length() > wallride_speed_necessary:
+	if !ray.is_colliding() and get_colliding_bodies() and vel.length() > wallride_speed_necessary:
 		since_on_wall = 0
-		last_wall_normal = get_slide_collision(0).normal
+		last_wall_normal = state.get_contact_local_normal()
 	else:
 		since_on_wall += delta
+
 	if since_on_wall < wallride_forgiveness:
 		var aim = get_node("Yaw").get_global_transform().basis
 		# Add zero gravity
-		velocity.y = -gravity # So it's undone in super
+		set_gravity_scale(0)
 		# Allow jumping (for wall hopping!)
 		if Input.is_action_just_pressed("jump"):
-			velocity.y += wallride_leap_height
-			velocity += wallride_leap_side * last_wall_normal
+			var jump_impulse = -wallride_leap_side * last_wall_normal
+			jump_impulse.y += wallride_leap_height
+			state.apply_impulse(Vector3(), jump_impulse)
+	else:
+		# We need to return to falling (we aren't riding anymore)
+		set_gravity_scale(1)
+
diff --git a/scripts/player.gd b/scripts/player.gd
index 126a165..a0990cd 100644
--- a/scripts/player.gd
+++ b/scripts/player.gd
@@ -2,17 +2,12 @@
 # This source code form is governed by the MIT license.
 # Original: https://raw.githubusercontent.com/Calinou/fps-test/master/scripts/player.gd
 
-extends KinematicBody
+extends RigidBody
 
 var view_sensitivity = 0.25
 var yaw = 0
 var pitch = 0
 
-var gravity = -.8
-var velocity = Vector3()
-slave var slave_tf = Basis()
-slave var slave_vel = Vector3()
-
 var timer = 0
 
 # Walking speed and jumping height are defined later.
@@ -26,6 +21,9 @@ var ray_length = 10
 
 var debug_node
 
+slave var slave_transform = Basis()
+slave var slave_lin_v = Vector3()
+slave var slave_ang_v = Vector3()
 
 func _ready():
 	set_process_input(true)
@@ -61,16 +59,21 @@ func _input(event):
 			quit()
 
 
-func _physics_process(delta):
-	if is_network_master():
-		control_player(delta)
-		rset_unreliable("slave_tf", get_transform())
-		rset_unreliable("slave_vel", velocity)
-	else:
-		set_transform(slave_tf)
-		move_and_slide(slave_vel)
+master func _integrate_forces(state):
+	control_player(state)
+	rpc_unreliable("set_status", get_transform(), get_linear_velocity(), get_angular_velocity())
 
-func control_player(delta):
+slave func set_status(tf, lv, av):
+	set_transform(tf)
+	set_linear_velocity(lv)
+	set_angular_velocity(av)
+
+func control_player(state):
+	
+	# Default walk speed:
+	walk_speed = 5
+	# Default jump height:
+	jump_speed = 3
 
 	var aim = get_node("Yaw").get_global_transform().basis
 
@@ -86,30 +89,57 @@ func control_player(delta):
 		direction += aim[0]
 
 	direction = direction.normalized()
+	var ray = get_node("Ray")
+	
+	#print("---")
+
+	if ray.is_colliding():
+		var up = state.get_total_gravity().normalized()
+		var normal = ray.get_collision_normal()
+		var floor_velocity = Vector3()
+		var object = ray.get_collider()
+
+		if object is RigidBody or object is StaticBody:
+			var point = ray.get_collision_point() - object.get_translation()
+			var floor_angular_vel = Vector3()
+			if object is RigidBody:
+				floor_velocity = object.get_linear_velocity()
+				floor_angular_vel = object.get_angular_velocity()
+			elif object is StaticBody:
+				floor_velocity = object.get_constant_linear_velocity()
+				floor_angular_vel = object.get_constant_angular_velocity()
+			# Surely there should be a function to convert Euler angles to a 3x3 matrix
+			var tf = Basis(Vector3(1, 0, 0), floor_angular_vel.x)
+			tf = tf.rotated(Vector3(0, 1, 0), floor_angular_vel.y)
+			tf = tf.rotated(Vector3(0, 0, 1), floor_angular_vel.z)
+			floor_velocity += tf.xform_inv(point) - point
+			yaw = fmod(yaw + rad2deg(floor_angular_vel.y) * state.get_step(), 360)
+			get_node("Yaw").set_rotation(Vector3(0, deg2rad(yaw), 0))
+			print("isRB||isSB")
 
-	var friction
-
-	if is_on_floor():
+		var diff = floor_velocity + direction * walk_speed - state.get_linear_velocity()
+		var vertdiff = aim[1] * diff.dot(aim[1])
+		print("VD: " + str(vertdiff))
+		diff -= vertdiff
+		diff = diff.normalized() * clamp(diff.length(), 0, max_accel / state.get_step())
+		diff += vertdiff
 
-		friction = 1 - 0.16
-		velocity.x *= friction
-		velocity.z *= friction
-		velocity.y = 0
-		velocity += direction * walk_speed
+		print("D: " + str(diff))
+		apply_impulse(Vector3(), diff * get_mass())
 
 		if Input.is_action_pressed("jump"):
-			velocity.y += jump_speed
+			apply_impulse(Vector3(), normal * jump_speed * get_mass())
 
 	else:
-		friction = 1 - 0.01
-		velocity.x *= friction
-		velocity.z *= friction
-		velocity.y += gravity
-		velocity += direction * air_accel
+		apply_impulse(Vector3(), direction * air_accel * get_mass())
+	
+	print(get_translation())
+	print(state.get_linear_velocity())
 
-	debug_node.set_text("%8.f,%8.f,%8.f" % [velocity.x, velocity.y, velocity.z])
+	var vel = get_linear_velocity()
+	debug_node.set_text("%8.f,%8.f,%8.f" % [vel.x, vel.y, vel.z])
 
-	velocity = move_and_slide(velocity, Vector3(0, 1, 0))
+	state.integrate_forces()
 
 func _exit_scene():
 	Input.set_mouse_mode(Input.MOUSE_MODE_VISIBLE)