refactor: split magic_numbers into per-module files

Extracted all doc-commented magic numbers into module-local magic_numbers.rs
files, co-located with the module that owns them. No logic changes.

- entities/shared_systems/magic_numbers: pathfinding + dig constants
- world/generation/terrain/magic_numbers: terrain + cave constants
- world/generation/forestry/magic_numbers: tree constants
- world/tiles/magic_numbers: A*, benchmark, memory constants
- entities/item/magic_numbers: item sprite z-offset
- Removed src/magic_numbers.rs (central file deleted)

Constants imported as `crate::{module}::magic_numbers::*` from each
consumer. src/constants.rs retains only structural constants (PIXEL_RATIO,
TILE_SIZE, SEED, pathfinding tier thresholds).
This commit is contained in:
2026-03-21 17:31:39 +00:00
parent 776d3caefc
commit 7fe33d4b2d
19 changed files with 159 additions and 45 deletions
+32 -13
View File
@@ -63,6 +63,11 @@ use crate::constants::{
ITILE_SIZE, PATHFINDER_HIERARCHICAL_THRESHOLD_CHUNKS, PATHFINDER_MAX_NODES,
PATHFINDER_PROVISIONAL_NODE_LIMIT, PIXEL_RATIO, TILE_SIZE,
};
use crate::entities::shared_systems::magic_numbers::{
CONVOY_DOT_THRESHOLD, ES_DIRECTION_THRESHOLD, HEAD_ON_DOT_THRESHOLD, OCCUPANCY_CROWD_THRESHOLD,
PATHFINDER_DIRTY_LOOKAHEAD, PATHFINDER_VALIDATE_STEPS, PATHFINDER_VALIDATION_COOLDOWN,
WALK_SPEED_DIVISOR,
};
use crate::entities::shared_systems::occupancy::{rebuild_tile_occupancy, TileOccupancy};
use crate::world::tiles::tile_changed::{PathfindingDirtyChunks, TileChangedEvent};
use crate::world::tiles::TileMap;
@@ -272,7 +277,7 @@ pub fn invalidate_paths_on_tile_change(
let Some(ref path) = ambulatory.current_path else {
continue;
};
let check_end = (ambulatory.path_index + 8).min(path.len());
let check_end = (ambulatory.path_index + PATHFINDER_DIRTY_LOOKAHEAD).min(path.len());
let affected = path[ambulatory.path_index..check_end]
.iter()
.any(|p| dirty.chunks.contains(&world_to_chunk(p.as_ivec3())));
@@ -629,17 +634,23 @@ pub fn movement(
if ambulatory.validation_cooldown > 0 {
ambulatory.validation_cooldown -= 1;
} else if let Some(path) = &ambulatory.current_path {
if !validate_next_steps(&tilemap, path, ambulatory.path_index, 3) {
if !validate_next_steps(
&tilemap,
path,
ambulatory.path_index,
PATHFINDER_VALIDATE_STEPS,
) {
ambulatory.current_path = None;
ambulatory.validation_cooldown = 10;
ambulatory.validation_cooldown = PATHFINDER_VALIDATION_COOLDOWN;
return;
}
ambulatory.validation_cooldown = 10;
ambulatory.validation_cooldown = PATHFINDER_VALIDATION_COOLDOWN;
}
if ambulatory.walk_speed > 0. {
let tile_weight = get_tile_weight(&tilemap, current_pos.as_ivec3());
let threshold = (ambulatory.walk_speed as i32 * tile_weight as i32 / 50) as u32;
let threshold =
(ambulatory.walk_speed as i32 * tile_weight as i32 / WALK_SPEED_DIVISOR) as u32;
if ambulatory.step_recovery <= threshold {
ambulatory.step_recovery += 1;
@@ -656,7 +667,7 @@ pub fn movement(
let current_count = occupancy.count_at(transform.translation);
let next_count = occupancy.count_at(next_point);
let current_crowded = current_count > 3;
let current_crowded = current_count > OCCUPANCY_CROWD_THRESHOLD;
let occupied = !current_crowded && next_count > current_count;
let actual_move: Vec3;
@@ -671,13 +682,16 @@ pub fn movement(
};
// Case 1: Convoy — same direction, treat as unoccupied
let convoy =
occupied && their_dir != Vec2::ZERO && their_dir.dot(our_dir) > 0.7;
let convoy = occupied
&& their_dir != Vec2::ZERO
&& their_dir.dot(our_dir) > CONVOY_DOT_THRESHOLD;
// Case 2: Head-on (directly opposite directions)
let head_on = their_dir != Vec2::ZERO && their_dir.dot(our_dir) < -0.7;
let head_on =
their_dir != Vec2::ZERO && their_dir.dot(our_dir) < HEAD_ON_DOT_THRESHOLD;
let we_are_es = our_dir.x > 0.3 || our_dir.y < -0.3;
let we_are_es =
our_dir.x > ES_DIRECTION_THRESHOLD || our_dir.y < -ES_DIRECTION_THRESHOLD;
if !occupied || convoy {
// Normal movement
@@ -743,7 +757,8 @@ pub fn movement(
let tile_weight =
get_tile_weight(&tilemap, transform.translation.as_ivec3());
let excuse_threshold = if ambulatory.walk_speed > 0. {
(ambulatory.walk_speed as i32 * tile_weight as i32 / 50) as u32
(ambulatory.walk_speed as i32 * tile_weight as i32
/ WALK_SPEED_DIVISOR) as u32
} else {
0
};
@@ -812,7 +827,8 @@ pub fn movement(
let tile_weight =
get_tile_weight(&tilemap, transform.translation.as_ivec3());
let excuse_threshold = if ambulatory.walk_speed > 0. {
(ambulatory.walk_speed as i32 * tile_weight as i32 / 50) as u32
(ambulatory.walk_speed as i32 * tile_weight as i32
/ WALK_SPEED_DIVISOR) as u32
} else {
0
};
@@ -827,7 +843,8 @@ pub fn movement(
let tile_weight =
get_tile_weight(&tilemap, transform.translation.as_ivec3());
let excuse_threshold = if ambulatory.walk_speed > 0. {
(ambulatory.walk_speed as i32 * tile_weight as i32 / 50) as u32
(ambulatory.walk_speed as i32 * tile_weight as i32 / WALK_SPEED_DIVISOR)
as u32
} else {
0
};
@@ -1056,6 +1073,8 @@ fn directional_chunk_waypoint(
// goal varies per entity (each has a different random wander target).
// Together they produce unique spread values for entities even when
// heading through the same chunk, without needing to pass entity ID.
// MAGIC Small primes spread entity starting positions across waypoint edge tiles.
// Different values per axis prevent aliasing when positions are on a regular grid.
let entropy = (cur_tile.x.unsigned_abs() as usize)
.wrapping_mul(1619)
.wrapping_add((cur_tile.y.unsigned_abs() as usize).wrapping_mul(31337))