Skip to content
This repository has been archived by the owner on Jul 1, 2024. It is now read-only.

Commit

Permalink
Optimization
Browse files Browse the repository at this point in the history
  • Loading branch information
Mubelotix committed Nov 13, 2023
1 parent f34d1f9 commit 9be1871
Showing 1 changed file with 58 additions and 65 deletions.
123 changes: 58 additions & 65 deletions minecraft-server/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,16 @@ mod entities;

use crate::prelude::*;


fn min(a: f32, b: f32, c: f32) -> f32 {
fn min2(a: f32, b: f32) -> f32 {
if a < b {
a
} else {
b
}
fn min2(a: f32, b: f32) -> f32 {
if a < b {
a
} else {
b
}
min2(min2(a, b), c)
}

fn min_options(a: Option<f32>, b: Option<f32>, c: Option<f32>) -> Option<f32> {
match (a, b, c) {
(Some(a), Some(b), Some(c)) => Some(min(a, b, c)),
(Some(a), Some(b), None) => Some(min(a, b, 1.0)),
(Some(a), None, Some(c)) => Some(min(a, 1.0, c)),
(None, Some(b), Some(c)) => Some(min(1.0, b, c)),
(Some(a), None, None) => Some(a),
(None, Some(b), None) => Some(b),
(None, None, Some(c)) => Some(c),
(None, None, None) => None,
}
fn min(a: f32, b: f32, c: f32) -> f32 {
min2(min2(a, b), c)
}

fn min_options2(a: Option<f32>, b: Option<f32>) -> Option<f32> {
Expand Down Expand Up @@ -128,95 +115,93 @@ fn is_inside(shape: &CollisionShape, point: Point) -> bool {
(shape.x1..=shape.x2).contains(&point.x) && (shape.y1..=shape.y2).contains(&point.y) && (shape.z1..=shape.z2).contains(&point.z)
}

fn translation_limit_y(shape: &CollisionShape, translation: &Translation, point: &Point) -> Option<f32> {
fn translation_limit_y(shape: &CollisionShape, translation: &Translation, point: &Point) -> f32 {
if translation.y == 0.0 {
return None;
return 1.0;
}
let y = if translation.y < 0.0 { shape.y1 } else { shape.y2 };
let translated_ratio = (point.y - y) / translation.y;
if translated_ratio >= 1.0 {
return None;
return 1.0;
} else if translated_ratio <= 0.0 {
return Some(0.0)
return 0.0;
}
let translated_x1 = shape.x1 + translation.x * translated_ratio;
let translated_x2 = shape.x2 + translation.x * translated_ratio;
let translated_z1 = shape.z1 + translation.z * translated_ratio;
let translated_z2 = shape.z2 + translation.z * translated_ratio;
if (translated_x1..=translated_x2).contains(&point.x) && (translated_z1..=translated_z2).contains(&point.z) {
Some(translated_ratio)
translated_ratio
} else {
None
1.0
}
}

fn translation_limit_x(shape: &CollisionShape, translation: &Translation, point: &Point) -> Option<f32> {
fn translation_limit_x(shape: &CollisionShape, translation: &Translation, point: &Point) -> f32 {
if translation.x == 0.0 {
return None;
return 1.0;
}
let x = if translation.x < 0.0 { shape.x1 } else { shape.x2 };
let translated_ratio = (point.x - x) / translation.x;
if translated_ratio >= 1.0 {
return None;
return 1.0;
} else if translated_ratio <= 0.0 {
return Some(0.0)
return 0.0;
}
let translated_y1 = shape.y1 + translation.y * translated_ratio;
let translated_y2 = shape.y2 + translation.y * translated_ratio;
let translated_z1 = shape.z1 + translation.z * translated_ratio;
let translated_z2 = shape.z2 + translation.z * translated_ratio;
if (translated_y1..=translated_y2).contains(&point.y) && (translated_z1..=translated_z2).contains(&point.z) {
Some(translated_ratio)
translated_ratio
} else {
None
1.0
}
}

fn translation_limit_z(shape: &CollisionShape, translation: &Translation, point: &Point) -> Option<f32> {
fn translation_limit_z(shape: &CollisionShape, translation: &Translation, point: &Point) -> f32 {
if translation.z == 0.0 {
return None;
return 1.0;
}
let z = if translation.z < 0.0 { shape.z1 } else { shape.z2 };
let translated_ratio = (point.z - z) / translation.z;
if translated_ratio >= 1.0 {
return None;
return 1.0;
} else if translated_ratio <= 0.0 {
return Some(0.0)
return 0.0;
}
let translated_x1 = shape.x1 + translation.x * translated_ratio;
let translated_x2 = shape.x2 + translation.x * translated_ratio;
let translated_y1 = shape.y1 + translation.y * translated_ratio;
let translated_y2 = shape.y2 + translation.y * translated_ratio;
if (translated_x1..=translated_x2).contains(&point.x) && (translated_y1..=translated_y2).contains(&point.y) {
Some(translated_ratio)
translated_ratio
} else {
None
1.0
}
}

fn translation_limit(shape: &CollisionShape, translation: &Translation, point: &Point) -> Option<f32> {
min_options(
fn translation_limit(shape: &CollisionShape, translation: &Translation, point: &Point) -> f32 {
min(
translation_limit_x(shape, translation, point),
translation_limit_y(shape, translation, point),
translation_limit_z(shape, translation, point)
)
}

fn collide(translating: &CollisionShape, translation: &Translation, obstacle: &CollisionShape) -> Option<Translation> {
let mut limit = None;
fn restrict(translating: &CollisionShape, translation: &mut Translation, obstacle: &CollisionShape) {
let mut limit = 1.0;

for point in obstacle.points() {
limit = min_options2(limit, translation_limit(translating, translation, &point));
if limit.map(|l| l==0.0).unwrap_or(false) {
limit = min2(limit, translation_limit(translating, translation, &point));
if limit == 0.0 {
break;
}
}

limit.map(|limit| Translation {
x: translation.x * limit,
y: translation.y * limit,
z: translation.z * limit,
})
translation.x *= limit;
translation.y *= limit;
translation.z *= limit;
}

#[test]
Expand All @@ -232,43 +217,51 @@ fn test() {

// Boxes are just next to each other and pushing against each other
let shape2 = shape1.clone() + Translation { x: 1.0, y: 0.0, z: 0.0 };
let translation = Translation { x: -1.0, y: 0.0, z: 0.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: 0.0, y: 0.0, z: 0.0 }));
let mut translation = Translation { x: -1.0, y: 0.0, z: 0.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: 0.0, y: 0.0, z: 0.0 });

// Boxes are one block away but one comes and pushes the other
let shape2 = shape1.clone() + Translation { x: 2.0, y: 0.0, z: 0.0 };
let translation = Translation { x: -2.0, y: 0.0, z: 0.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: -1.0, y: 0.0, z: 0.0 }));
let mut translation = Translation { x: -2.0, y: 0.0, z: 0.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: -1.0, y: 0.0, z: 0.0 });

// The other way around
let shape2 = shape1.clone() + Translation { x: -2.0, y: 0.0, z: 0.0 };
let translation = Translation { x: 2.0, y: 0.0, z: 0.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: 1.0, y: 0.0, z: 0.0 }));
let mut translation = Translation { x: 2.0, y: 0.0, z: 0.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: 1.0, y: 0.0, z: 0.0 });

// From top
let shape2 = shape1.clone() + Translation { x: 0.0, y: 2.0, z: 0.0 };
let translation = Translation { x: 0.0, y: -2.0, z: 0.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: 0.0, y: -1.0, z: 0.0 }));
let mut translation = Translation { x: 0.0, y: -2.0, z: 0.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: 0.0, y: -1.0, z: 0.0 });

// On last axis
let shape2 = shape1.clone() + Translation { x: 0.0, y: 0.0, z: 2.0 };
let translation = Translation { x: 0.0, y: 0.0, z: -2.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: 0.0, y: 0.0, z: -1.0 }));
let mut translation = Translation { x: 0.0, y: 0.0, z: -2.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: 0.0, y: 0.0, z: -1.0 });

// Colliding on corner
let shape2 = shape1.clone() + Translation { x: 2.0, y: 2.0, z: 2.0 };
let translation = Translation { x: -2.0, y: -2.0, z: -2.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: -1.0, y: -1.0, z: -1.0 }));
let mut translation = Translation { x: -2.0, y: -2.0, z: -2.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: -1.0, y: -1.0, z: -1.0 });

// Colliding with offset on other axis
let shape2 = shape1.clone() + Translation { x: 2.0, y: 0.5, z: 0.0 };
let translation = Translation { x: -2.0, y: 0.0, z: 0.0 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: -1.0, y: 0.0, z: 0.0 }));
let mut translation = Translation { x: -2.0, y: 0.0, z: 0.0 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: -1.0, y: 0.0, z: 0.0 });

// Colliding when already inside
let shape2 = shape1.clone() + Translation { x: 0.5, y: 0.5, z: 0.5 };
let translation = Translation { x: -0.5, y: -0.5, z: -0.5 };
assert_eq!(collide(&shape2, &translation, &shape1), Some(Translation { x: 0.0, y: 0.0, z: 0.0 }));
let mut translation = Translation { x: -0.5, y: -0.5, z: -0.5 };
restrict(&shape2, &mut translation, &shape1);
assert_eq!(translation, Translation { x: 0.0, y: 0.0, z: 0.0 });
}

fn ray_cast(position: (f32, f32, f32), movement: (f32, f32, f32)) -> Vec<(isize, isize, isize)> {
Expand Down

0 comments on commit 9be1871

Please sign in to comment.